From 070f3988a2511de23a28e46052bbaf4aaed3a6eb Mon Sep 17 00:00:00 2001
From: hywznn
Date: Tue, 4 Aug 2026 10:54:18 +0900
Subject: [PATCH 1/4] =?UTF-8?q?feat(agent):=20=EC=9E=90=EC=97=B0=EC=96=B4?=
=?UTF-8?q?=20=EB=B6=84=EC=84=9D=EA=B3=BC=20=EC=B6=94=EA=B0=80=20=EC=A7=88?=
=?UTF-8?q?=EB=AC=B8=20=ED=99=94=EB=A9=B4=20=EC=97=B0=EA=B2=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/api/aiRuns.ts | 61 +++++
src/pages/CreateWorkPage/CreateWorkPage.tsx | 30 ++-
src/pages/CreateWorkPage/createWorkData.ts | 14 +-
src/pages/ReviewWorkPage/AiRunReview.tsx | 221 ++++++++++++++++++
.../ReviewWorkPage/ReviewWorkPage.module.css | 73 ++++++
src/pages/ReviewWorkPage/ReviewWorkPage.tsx | 10 +-
vite.config.ts | 5 +
7 files changed, 407 insertions(+), 7 deletions(-)
create mode 100644 src/api/aiRuns.ts
create mode 100644 src/pages/ReviewWorkPage/AiRunReview.tsx
diff --git a/src/api/aiRuns.ts b/src/api/aiRuns.ts
new file mode 100644
index 0000000..a560e8a
--- /dev/null
+++ b/src/api/aiRuns.ts
@@ -0,0 +1,61 @@
+import { apiFetch } from './client'
+
+export type AiRunStatus = 'QUEUED' | 'RUNNING' | 'SUCCEEDED' | 'FAILED'
+export type AiAnalysisOutcome = 'CONTEXT_REQUIRED' | 'NEEDS_INFO' | 'REVIEW_REQUIRED'
+
+export interface AiRunQuestion {
+ slot_key: string
+ label: string
+ input_type: string
+ required: boolean
+ answer: string | null
+}
+
+export interface AiRunCandidate {
+ candidate_id: string
+ candidate_ref: string
+ worker_id: string | null
+ workflow_id: string
+ extracted_slots: Record
+ missing_slots: string[]
+ confidence: number | null
+}
+
+export interface AiRunResponse {
+ ai_run_id: string
+ request_id: string
+ instruction: string
+ status: AiRunStatus
+ analysis_outcome: AiAnalysisOutcome | null
+ detected_intent: string | null
+ error_code: string | null
+ attempt_count: number
+ version: number
+ questions: AiRunQuestion[]
+ candidates: AiRunCandidate[]
+ created_at: string
+ updated_at: string
+}
+
+export function createAiRun(instruction: string, idempotencyKey: string): Promise {
+ return apiFetch('/ai-runs', {
+ method: 'POST',
+ headers: { 'Idempotency-Key': idempotencyKey },
+ body: JSON.stringify({ instruction }),
+ })
+}
+
+export function fetchAiRun(aiRunId: string): Promise {
+ return apiFetch(`/ai-runs/${encodeURIComponent(aiRunId)}`)
+}
+
+export function submitAiRunAnswers(
+ aiRunId: string,
+ expectedVersion: number,
+ answers: Record,
+): Promise {
+ return apiFetch(`/ai-runs/${encodeURIComponent(aiRunId)}/answers`, {
+ method: 'POST',
+ body: JSON.stringify({ expected_version: expectedVersion, answers }),
+ })
+}
diff --git a/src/pages/CreateWorkPage/CreateWorkPage.tsx b/src/pages/CreateWorkPage/CreateWorkPage.tsx
index eee80ef..6d11895 100644
--- a/src/pages/CreateWorkPage/CreateWorkPage.tsx
+++ b/src/pages/CreateWorkPage/CreateWorkPage.tsx
@@ -1,6 +1,7 @@
import { useCallback, useMemo, useState } from 'react'
import { Link, useLocation, useNavigate } from 'react-router-dom'
import { ApiError, getErrorMessage } from '../../api/errors'
+import { createAiRun } from '../../api/aiRuns'
import { createTask, type TaskType } from '../../api/tasks'
import { fetchWorkers } from '../../api/workers'
import { fetchWorkflowCatalog } from '../../api/workflows'
@@ -12,9 +13,11 @@ import { TASK_TYPE_LABEL } from '../../utils/taskStatus'
import styles from './CreateWorkPage.module.css'
import {
AGENT_TRACE_PREVIEW,
+ EXAMPLE_PROMPT_INTENTS,
EXAMPLE_PROMPTS,
INPUT_MODES,
MAX_LENGTH,
+ instructionWithHint,
type InputModeId,
} from './createWorkData'
import { ImportWizardModal } from './importWizard/ImportWizardModal'
@@ -34,6 +37,7 @@ export function CreateWorkPage() {
const prefill = (location.state as { prefill?: string } | null)?.prefill
const [mode, setMode] = useState('nl')
const [request, setRequest] = useState(prefill ?? '')
+ const [intentHint, setIntentHint] = useState(null)
const [importWizardOpen, setImportWizardOpen] = useState(false)
const showToast = useToastStore((state) => state.showToast)
@@ -50,6 +54,8 @@ export function CreateWorkPage() {
const [dueDate, setDueDate] = useState('')
const [slotValues, setSlotValues] = useState>({})
const [submitting, setSubmitting] = useState(false)
+ const [analyzing, setAnalyzing] = useState(false)
+ const [analysisError, setAnalysisError] = useState(null)
const [formError, setFormError] = useState(null)
const workerOptions = useMemo(
@@ -109,13 +115,25 @@ export function CreateWorkPage() {
}
}
- function handleExampleClick(example: string) {
+ function handleExampleClick(example: (typeof EXAMPLE_PROMPTS)[number]) {
setRequest(example)
+ setIntentHint(EXAMPLE_PROMPT_INTENTS[example])
}
- function handleAnalyze() {
- // TODO(backend): POST /api/work-items/analyze { mode, request } -> 분류·필수정보 확인 결과 반영
- navigate('/tasks/new/review')
+ async function handleAnalyze() {
+ if (request.trim() === '' || analyzing) return
+ setAnalyzing(true)
+ setAnalysisError(null)
+ try {
+ const instruction = instructionWithHint(request, intentHint)
+ const idempotencyKey = globalThis.crypto.randomUUID()
+ const aiRun = await createAiRun(instruction, idempotencyKey)
+ navigate('/tasks/new/review', { state: { aiRun } })
+ } catch (error) {
+ setAnalysisError(error instanceof ApiError ? getErrorMessage(error) : '요청을 분석하지 못했습니다.')
+ } finally {
+ setAnalyzing(false)
+ }
}
function handleSaveDraft() {
@@ -235,11 +253,13 @@ export function CreateWorkPage() {
취소
-
} />
,
)
@@ -94,6 +111,22 @@ describe('CreateWorkPage', () => {
expect(screen.getByLabelText('업무 요청 내용')).toHaveValue('체류연장 준비')
})
+ it('sends the natural-language request with an intent hint and opens the review page', async () => {
+ const user = userEvent.setup()
+ renderPage()
+
+ await user.click(screen.getByRole('button', { name: '체류연장 준비' }))
+ await user.click(screen.getByRole('button', { name: '요청 분석하기 →' }))
+
+ expect(await screen.findByText('Agent 추가 질문')).toBeInTheDocument()
+ const analyzeCall = vi.mocked(fetch).mock.calls.find(([url]) => String(url).endsWith('/ai-runs'))
+ expect(analyzeCall).toBeDefined()
+ expect(JSON.parse((analyzeCall![1] as RequestInit).body as string)).toEqual({
+ instruction: '체류연장 준비, EXPIRY_RENEWAL',
+ })
+ expect(new Headers((analyzeCall![1] as RequestInit).headers).get('Idempotency-Key')).toBeTruthy()
+ })
+
it('switches the active input mode', async () => {
const user = userEvent.setup()
renderPage()
diff --git a/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx b/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx
index 1ae4321..21197fb 100644
--- a/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx
+++ b/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx
@@ -1,7 +1,8 @@
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { MemoryRouter } from 'react-router-dom'
-import { beforeEach, describe, expect, it } from 'vitest'
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
+import type { AiRunResponse } from '../../api/aiRuns'
import { ToastViewport } from '../../components/ui/ToastViewport/ToastViewport'
import { useToastStore } from '../../store/toastStore'
import { ReviewWorkPage } from './ReviewWorkPage'
@@ -14,13 +15,26 @@ import {
UNDERSTOOD_REQUEST,
} from './reviewWorkData'
+function jsonResponse(body: unknown, init: ResponseInit = {}) {
+ return new Response(JSON.stringify(body), {
+ status: 200,
+ headers: { 'Content-Type': 'application/json' },
+ ...init,
+ })
+}
+
beforeEach(() => {
useToastStore.setState({ toasts: [] })
+ vi.stubGlobal('fetch', vi.fn())
})
-function renderPage() {
+afterEach(() => {
+ vi.unstubAllGlobals()
+})
+
+function renderPage(aiRun?: AiRunResponse) {
render(
-
+
,
@@ -82,4 +96,56 @@ describe('ReviewWorkPage', () => {
expect(screen.getByText('분석 근거 보기는 준비 중입니다.')).toBeInTheDocument()
})
+
+ it('submits missing information and renders the returned candidate', async () => {
+ const initialRun: AiRunResponse = {
+ ai_run_id: 'A-1',
+ request_id: 'R-1',
+ instruction: '응웬반A 체류연장 준비해줘, EXPIRY_RENEWAL',
+ status: 'SUCCEEDED',
+ analysis_outcome: 'NEEDS_INFO',
+ detected_intent: 'EXPIRY_RENEWAL',
+ error_code: null,
+ attempt_count: 2,
+ version: 2,
+ questions: [
+ { slot_key: 'due_at', label: '신청 목표일을 입력해 주세요.', input_type: 'DATE', required: true, answer: null },
+ ],
+ candidates: [],
+ created_at: '2026-08-04T00:00:00Z',
+ updated_at: '2026-08-04T00:00:01Z',
+ }
+ const completedRun: AiRunResponse = {
+ ...initialRun,
+ analysis_outcome: 'REVIEW_REQUIRED',
+ attempt_count: 3,
+ version: 3,
+ questions: [],
+ candidates: [
+ {
+ candidate_id: 'C-1',
+ candidate_ref: 'candidate-1',
+ worker_id: 'W-1',
+ workflow_id: 'WF-STY-001',
+ extracted_slots: { due_at: '2026-08-31' },
+ missing_slots: [],
+ confidence: 0.96,
+ },
+ ],
+ }
+ vi.mocked(fetch).mockResolvedValue(jsonResponse(completedRun, { status: 202 }))
+ const user = userEvent.setup()
+ renderPage(initialRun)
+
+ await user.type(screen.getByLabelText('신청 목표일을 입력해 주세요. *'), '2026-08-31')
+ await user.click(screen.getByRole('button', { name: '답변하고 다시 분석' }))
+
+ expect(await screen.findByText('WF-STY-001')).toBeInTheDocument()
+ const answerCall = vi.mocked(fetch).mock.calls[0]
+ expect(String(answerCall[0])).toContain('/ai-runs/A-1/answers')
+ expect(JSON.parse((answerCall[1] as RequestInit).body as string)).toEqual({
+ expected_version: 2,
+ answers: { due_at: '2026-08-31' },
+ })
+ })
})
From f3b242a86b628b65d1ca39ef6e3693ccbb7e5e86 Mon Sep 17 00:00:00 2001
From: hywznn
Date: Tue, 4 Aug 2026 11:22:02 +0900
Subject: [PATCH 3/4] =?UTF-8?q?fix(agent):=20=EC=83=88=EB=A1=9C=EA=B3=A0?=
=?UTF-8?q?=EC=B9=A8=20=EC=8B=9C=20AiRun=20=EA=B2=80=ED=86=A0=20=EC=83=81?=
=?UTF-8?q?=ED=83=9C=20=EB=B3=B5=EA=B5=AC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
검토 URL에 aiRunId를 남기고, 화면 이동 상태가 사라진 경우 서버에서 최신 실행 결과를 다시 조회합니다.
---
src/pages/CreateWorkPage/CreateWorkPage.tsx | 2 +-
.../ReviewWorkPage/ReviewWorkPage.test.tsx | 31 +++++++++-
src/pages/ReviewWorkPage/ReviewWorkPage.tsx | 56 ++++++++++++++++++-
3 files changed, 83 insertions(+), 6 deletions(-)
diff --git a/src/pages/CreateWorkPage/CreateWorkPage.tsx b/src/pages/CreateWorkPage/CreateWorkPage.tsx
index 6d11895..3df7fd0 100644
--- a/src/pages/CreateWorkPage/CreateWorkPage.tsx
+++ b/src/pages/CreateWorkPage/CreateWorkPage.tsx
@@ -128,7 +128,7 @@ export function CreateWorkPage() {
const instruction = instructionWithHint(request, intentHint)
const idempotencyKey = globalThis.crypto.randomUUID()
const aiRun = await createAiRun(instruction, idempotencyKey)
- navigate('/tasks/new/review', { state: { aiRun } })
+ navigate(`/tasks/new/review?aiRunId=${encodeURIComponent(aiRun.ai_run_id)}`, { state: { aiRun } })
} catch (error) {
setAnalysisError(error instanceof ApiError ? getErrorMessage(error) : '요청을 분석하지 못했습니다.')
} finally {
diff --git a/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx b/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx
index 21197fb..e9e64fe 100644
--- a/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx
+++ b/src/pages/ReviewWorkPage/ReviewWorkPage.test.tsx
@@ -32,9 +32,9 @@ afterEach(() => {
vi.unstubAllGlobals()
})
-function renderPage(aiRun?: AiRunResponse) {
+function renderPage(aiRun?: AiRunResponse, path = '/tasks/new/review') {
render(
-
+
,
@@ -148,4 +148,31 @@ describe('ReviewWorkPage', () => {
answers: { due_at: '2026-08-31' },
})
})
+
+ it('restores the AI run from the URL after a refresh', async () => {
+ const savedRun: AiRunResponse = {
+ ai_run_id: 'A-RESTORED',
+ request_id: 'R-RESTORED',
+ instruction: '응웬반A 체류연장 준비해줘, EXPIRY_RENEWAL',
+ status: 'SUCCEEDED',
+ analysis_outcome: 'NEEDS_INFO',
+ detected_intent: 'EXPIRY_RENEWAL',
+ error_code: null,
+ attempt_count: 1,
+ version: 1,
+ questions: [
+ { slot_key: 'due_at', label: '신청 목표일을 입력해 주세요.', input_type: 'DATE', required: true, answer: null },
+ ],
+ candidates: [],
+ created_at: '2026-08-04T00:00:00Z',
+ updated_at: '2026-08-04T00:00:01Z',
+ }
+ vi.mocked(fetch).mockResolvedValue(jsonResponse(savedRun))
+
+ renderPage(undefined, '/tasks/new/review?aiRunId=A-RESTORED')
+
+ expect(screen.getByText('Agent 분석 결과를 불러오고 있습니다.')).toBeInTheDocument()
+ expect(await screen.findByText(savedRun.instruction)).toBeInTheDocument()
+ expect(String(vi.mocked(fetch).mock.calls[0][0])).toContain('/ai-runs/A-RESTORED')
+ })
})
diff --git a/src/pages/ReviewWorkPage/ReviewWorkPage.tsx b/src/pages/ReviewWorkPage/ReviewWorkPage.tsx
index f014743..ccaec03 100644
--- a/src/pages/ReviewWorkPage/ReviewWorkPage.tsx
+++ b/src/pages/ReviewWorkPage/ReviewWorkPage.tsx
@@ -1,6 +1,7 @@
-import { useState } from 'react'
+import { useEffect, useState } from 'react'
import { Link, useLocation, useNavigate } from 'react-router-dom'
-import type { AiRunResponse } from '../../api/aiRuns'
+import { ApiError, getErrorMessage } from '../../api/errors'
+import { fetchAiRun, type AiRunResponse } from '../../api/aiRuns'
import { Button } from '../../components/ui/Button/Button'
import { DetailRow } from '../../components/ui/DetailRow/DetailRow'
import { Dropdown } from '../../components/ui/Dropdown/Dropdown'
@@ -27,14 +28,63 @@ export function ReviewWorkPage() {
const navigate = useNavigate()
const location = useLocation()
const [institution, setInstitution] = useState('')
+ const navigationRun = (location.state as { aiRun?: AiRunResponse } | null)?.aiRun
+ const aiRunId = new URLSearchParams(location.search).get('aiRunId')
+ const [recoveredRun, setRecoveredRun] = useState(null)
+ const [recovering, setRecovering] = useState(Boolean(aiRunId && !navigationRun))
+ const [recoveryError, setRecoveryError] = useState(null)
const canCreate = institution !== ''
const showToast = useToastStore((state) => state.showToast)
- const aiRun = (location.state as { aiRun?: AiRunResponse } | null)?.aiRun
+ const aiRun = navigationRun ?? recoveredRun
+
+ useEffect(() => {
+ if (!aiRunId || navigationRun) return
+
+ let cancelled = false
+ setRecovering(true)
+ setRecoveryError(null)
+ fetchAiRun(aiRunId)
+ .then((run) => {
+ if (!cancelled) setRecoveredRun(run)
+ })
+ .catch((error) => {
+ if (!cancelled) {
+ setRecoveryError(error instanceof ApiError ? getErrorMessage(error) : '분석 결과를 불러오지 못했습니다.')
+ }
+ })
+ .finally(() => {
+ if (!cancelled) setRecovering(false)
+ })
+
+ return () => {
+ cancelled = true
+ }
+ }, [aiRunId, navigationRun])
if (aiRun) {
return
}
+ if (recovering || recoveryError) {
+ return (
+
+
+ ← 요청 수정
+
+
+
+
+ {recovering ? 'Agent 분석 결과를 불러오고 있습니다.' : 'Agent 분석 결과를 불러오지 못했습니다.'}
+
+
+ {recoveryError ?? '저장된 실행 번호로 최신 상태를 확인합니다.'}
+
+
+
+
+ )
+ }
+
function handleCreate() {
// TODO(backend): POST /api/work-items { ...UNDERSTOOD_REQUEST, institution } -> 생성 후 WORK-001로 이동
navigate('/tasks')
From 32181320a52cf94c2a8450abbfb8ff63b24a64a0 Mon Sep 17 00:00:00 2001
From: hywznn
Date: Wed, 5 Aug 2026 19:26:47 +0900
Subject: [PATCH 4/4] =?UTF-8?q?fix(agent):=20=EB=B9=A0=EB=A5=B8=20?=
=?UTF-8?q?=EC=84=A0=ED=83=9D=20intent=20=ED=9E=8C=ED=8A=B8=20=EC=A0=9C?=
=?UTF-8?q?=EA=B1=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../CreateWorkPage/CreateWorkPage.test.tsx | 23 ++++++++++++++++---
src/pages/CreateWorkPage/CreateWorkPage.tsx | 6 +----
src/pages/CreateWorkPage/createWorkData.ts | 12 ----------
3 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/src/pages/CreateWorkPage/CreateWorkPage.test.tsx b/src/pages/CreateWorkPage/CreateWorkPage.test.tsx
index ae1084d..5884d79 100644
--- a/src/pages/CreateWorkPage/CreateWorkPage.test.tsx
+++ b/src/pages/CreateWorkPage/CreateWorkPage.test.tsx
@@ -41,7 +41,7 @@ const CATALOG = {
const AI_RUN = {
ai_run_id: 'A-1',
request_id: 'R-1',
- instruction: '체류연장 준비, EXPIRY_RENEWAL',
+ instruction: '체류연장 준비',
status: 'SUCCEEDED',
analysis_outcome: 'NEEDS_INFO',
detected_intent: 'EXPIRY_RENEWAL',
@@ -111,7 +111,7 @@ describe('CreateWorkPage', () => {
expect(screen.getByLabelText('업무 요청 내용')).toHaveValue('체류연장 준비')
})
- it('sends the natural-language request with an intent hint and opens the review page', async () => {
+ it('sends the selected example as written and opens the review page', async () => {
const user = userEvent.setup()
renderPage()
@@ -122,11 +122,28 @@ describe('CreateWorkPage', () => {
const analyzeCall = vi.mocked(fetch).mock.calls.find(([url]) => String(url).endsWith('/ai-runs'))
expect(analyzeCall).toBeDefined()
expect(JSON.parse((analyzeCall![1] as RequestInit).body as string)).toEqual({
- instruction: '체류연장 준비, EXPIRY_RENEWAL',
+ instruction: '체류연장 준비',
})
expect(new Headers((analyzeCall![1] as RequestInit).headers).get('Idempotency-Key')).toBeTruthy()
})
+ it('sends an edited request without retaining the previously selected intent', async () => {
+ const user = userEvent.setup()
+ renderPage()
+
+ await user.click(screen.getByRole('button', { name: '체류연장 준비' }))
+ const request = screen.getByLabelText('업무 요청 내용')
+ await user.clear(request)
+ await user.type(request, '이번 주 근태자료 차이를 설명해 주세요')
+ await user.click(screen.getByRole('button', { name: '요청 분석하기 →' }))
+
+ const analyzeCall = vi.mocked(fetch).mock.calls.find(([url]) => String(url).endsWith('/ai-runs'))
+ expect(analyzeCall).toBeDefined()
+ expect(JSON.parse((analyzeCall![1] as RequestInit).body as string)).toEqual({
+ instruction: '이번 주 근태자료 차이를 설명해 주세요',
+ })
+ })
+
it('switches the active input mode', async () => {
const user = userEvent.setup()
renderPage()
diff --git a/src/pages/CreateWorkPage/CreateWorkPage.tsx b/src/pages/CreateWorkPage/CreateWorkPage.tsx
index 3df7fd0..948a2d0 100644
--- a/src/pages/CreateWorkPage/CreateWorkPage.tsx
+++ b/src/pages/CreateWorkPage/CreateWorkPage.tsx
@@ -13,11 +13,9 @@ import { TASK_TYPE_LABEL } from '../../utils/taskStatus'
import styles from './CreateWorkPage.module.css'
import {
AGENT_TRACE_PREVIEW,
- EXAMPLE_PROMPT_INTENTS,
EXAMPLE_PROMPTS,
INPUT_MODES,
MAX_LENGTH,
- instructionWithHint,
type InputModeId,
} from './createWorkData'
import { ImportWizardModal } from './importWizard/ImportWizardModal'
@@ -37,7 +35,6 @@ export function CreateWorkPage() {
const prefill = (location.state as { prefill?: string } | null)?.prefill
const [mode, setMode] = useState('nl')
const [request, setRequest] = useState(prefill ?? '')
- const [intentHint, setIntentHint] = useState(null)
const [importWizardOpen, setImportWizardOpen] = useState(false)
const showToast = useToastStore((state) => state.showToast)
@@ -117,7 +114,6 @@ export function CreateWorkPage() {
function handleExampleClick(example: (typeof EXAMPLE_PROMPTS)[number]) {
setRequest(example)
- setIntentHint(EXAMPLE_PROMPT_INTENTS[example])
}
async function handleAnalyze() {
@@ -125,7 +121,7 @@ export function CreateWorkPage() {
setAnalyzing(true)
setAnalysisError(null)
try {
- const instruction = instructionWithHint(request, intentHint)
+ const instruction = request.trim()
const idempotencyKey = globalThis.crypto.randomUUID()
const aiRun = await createAiRun(instruction, idempotencyKey)
navigate(`/tasks/new/review?aiRunId=${encodeURIComponent(aiRun.ai_run_id)}`, { state: { aiRun } })
diff --git a/src/pages/CreateWorkPage/createWorkData.ts b/src/pages/CreateWorkPage/createWorkData.ts
index 287189f..50a2aaf 100644
--- a/src/pages/CreateWorkPage/createWorkData.ts
+++ b/src/pages/CreateWorkPage/createWorkData.ts
@@ -12,18 +12,6 @@ export type InputModeId = (typeof INPUT_MODES)[number]['id']
export const EXAMPLE_PROMPTS = ['체류연장 준비', '입사자료 취합', '외부기관 제출', '근태자료 설명'] as const
-export const EXAMPLE_PROMPT_INTENTS: Record<(typeof EXAMPLE_PROMPTS)[number], string> = {
- '체류연장 준비': 'EXPIRY_RENEWAL',
- '입사자료 취합': 'WORKER_ONBOARDING',
- '외부기관 제출': 'DOCUMENT_REQUEST',
- '근태자료 설명': 'WORK_INSTRUCTION',
-}
-
-export function instructionWithHint(instruction: string, intentHint: string | null) {
- const normalized = instruction.trim()
- return intentHint ? `${normalized}, ${intentHint}` : normalized
-}
-
export const MAX_LENGTH = 2000
export const AGENT_TRACE_PREVIEW = {