@xom11/whiteboard 0.25.0 → 0.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/{ExcalidrawWithMenus-WENZRYYE.mjs → ExcalidrawWithMenus-2QPPTXJM.mjs} +3 -2
  2. package/dist/ExcalidrawWithMenus-2QPPTXJM.mjs.map +1 -0
  3. package/dist/ai.d.mts +3035 -108
  4. package/dist/ai.d.ts +3035 -108
  5. package/dist/ai.js +6780 -788
  6. package/dist/ai.js.map +1 -1
  7. package/dist/ai.mjs +5140 -577
  8. package/dist/ai.mjs.map +1 -1
  9. package/dist/catalog.json +5 -5
  10. package/dist/{chunk-NDEZJKNY.mjs → chunk-5JM35CXV.mjs} +4 -4
  11. package/dist/{chunk-NDEZJKNY.mjs.map → chunk-5JM35CXV.mjs.map} +1 -1
  12. package/dist/{chunk-VNCCIV6O.mjs → chunk-AJAHD35N.mjs} +779 -9
  13. package/dist/chunk-AJAHD35N.mjs.map +1 -0
  14. package/dist/{chunk-M42TGYT6.mjs → chunk-BNBOIDO5.mjs} +3 -3
  15. package/dist/{chunk-M42TGYT6.mjs.map → chunk-BNBOIDO5.mjs.map} +1 -1
  16. package/dist/{chunk-ONBCUWVI.mjs → chunk-BU5KLO3P.mjs} +3 -3
  17. package/dist/{chunk-ONBCUWVI.mjs.map → chunk-BU5KLO3P.mjs.map} +1 -1
  18. package/dist/{chunk-CJBLJUWG.mjs → chunk-CXHNVYMD.mjs} +4 -4
  19. package/dist/{chunk-CJBLJUWG.mjs.map → chunk-CXHNVYMD.mjs.map} +1 -1
  20. package/dist/chunk-H22OZYTW.mjs +265 -0
  21. package/dist/chunk-H22OZYTW.mjs.map +1 -0
  22. package/dist/chunk-J5LGTIGS.mjs +10 -0
  23. package/dist/chunk-J5LGTIGS.mjs.map +1 -0
  24. package/dist/{chunk-TB4CL25L.mjs → chunk-OQIQNKPQ.mjs} +206 -66
  25. package/dist/chunk-OQIQNKPQ.mjs.map +1 -0
  26. package/dist/{chunk-SGFJLHHG.mjs → chunk-PPKHCRRE.mjs} +3 -3
  27. package/dist/{chunk-SGFJLHHG.mjs.map → chunk-PPKHCRRE.mjs.map} +1 -1
  28. package/dist/{chunk-YSJOVBCD.mjs → chunk-QCZVFEN4.mjs} +4 -4
  29. package/dist/{chunk-YSJOVBCD.mjs.map → chunk-QCZVFEN4.mjs.map} +1 -1
  30. package/dist/{chunk-ESVPQWHX.mjs → chunk-QRUAEXLR.mjs} +5 -5
  31. package/dist/{chunk-ESVPQWHX.mjs.map → chunk-QRUAEXLR.mjs.map} +1 -1
  32. package/dist/{chunk-AYSFWUPK.mjs → chunk-SZDAS7LK.mjs} +79 -2
  33. package/dist/chunk-SZDAS7LK.mjs.map +1 -0
  34. package/dist/chunk-T3SOHYB2.mjs +851 -0
  35. package/dist/chunk-T3SOHYB2.mjs.map +1 -0
  36. package/dist/{chunk-I24QOHPU.mjs → chunk-V3YJ6JFL.mjs} +3 -3
  37. package/dist/{chunk-I24QOHPU.mjs.map → chunk-V3YJ6JFL.mjs.map} +1 -1
  38. package/dist/{chunk-REIJZDVZ.mjs → chunk-ZTQBUKLJ.mjs} +960 -196
  39. package/dist/chunk-ZTQBUKLJ.mjs.map +1 -0
  40. package/dist/geometry-2d.d.mts +1 -1
  41. package/dist/geometry-2d.d.ts +1 -1
  42. package/dist/geometry-2d.js +5521 -1384
  43. package/dist/geometry-2d.js.map +1 -1
  44. package/dist/geometry-2d.mjs +5 -4
  45. package/dist/geometry-3d.d.mts +1 -1
  46. package/dist/geometry-3d.d.ts +1 -1
  47. package/dist/geometry-3d.js +1351 -252
  48. package/dist/geometry-3d.js.map +1 -1
  49. package/dist/geometry-3d.mjs +4 -3
  50. package/dist/graph-2d.d.mts +1 -1
  51. package/dist/graph-2d.d.ts +1 -1
  52. package/dist/graph-2d.js +1517 -341
  53. package/dist/graph-2d.js.map +1 -1
  54. package/dist/graph-2d.mjs +7 -6
  55. package/dist/handleExtractProblem-C-U5KluK.d.mts +158 -0
  56. package/dist/handleExtractProblem-C-U5KluK.d.ts +158 -0
  57. package/dist/{host-A64ITWVX.mjs → host-2ISGVO7O.mjs} +6 -5
  58. package/dist/host-2ISGVO7O.mjs.map +1 -0
  59. package/dist/{host-L7FMFZUW.mjs → host-4P766V4J.mjs} +1363 -463
  60. package/dist/host-4P766V4J.mjs.map +1 -0
  61. package/dist/{host-QK53UYMD.mjs → host-HOSJHQ5H.mjs} +10 -9
  62. package/dist/host-HOSJHQ5H.mjs.map +1 -0
  63. package/dist/{host-QS2EOTRJ.mjs → host-ZQCDAT6O.mjs} +3 -2
  64. package/dist/host-ZQCDAT6O.mjs.map +1 -0
  65. package/dist/index.d.mts +10 -4
  66. package/dist/index.d.ts +10 -4
  67. package/dist/index.js +5746 -1603
  68. package/dist/index.js.map +1 -1
  69. package/dist/index.mjs +26 -22
  70. package/dist/index.mjs.map +1 -1
  71. package/dist/latex.d.mts +1 -1
  72. package/dist/latex.d.ts +1 -1
  73. package/dist/latex.mjs +2 -1
  74. package/dist/render-ZX2O2IK7.mjs +10 -0
  75. package/dist/{render-3WTY7NZB.mjs.map → render-ZX2O2IK7.mjs.map} +1 -1
  76. package/dist/serialize-N4G6RFBB.mjs +9 -0
  77. package/dist/{serialize-SRJVKYUG.mjs.map → serialize-N4G6RFBB.mjs.map} +1 -1
  78. package/dist/{types-DWRyCa2m.d.ts → types-BHYC2Fiw.d.mts} +130 -1
  79. package/dist/{types-DWRyCa2m.d.mts → types-BHYC2Fiw.d.ts} +130 -1
  80. package/package.json +10 -1
  81. package/dist/ExcalidrawWithMenus-WENZRYYE.mjs.map +0 -1
  82. package/dist/chunk-AYSFWUPK.mjs.map +0 -1
  83. package/dist/chunk-REIJZDVZ.mjs.map +0 -1
  84. package/dist/chunk-TB4CL25L.mjs.map +0 -1
  85. package/dist/chunk-VNCCIV6O.mjs.map +0 -1
  86. package/dist/chunk-VRHWDZ66.mjs +0 -96
  87. package/dist/chunk-VRHWDZ66.mjs.map +0 -1
  88. package/dist/host-A64ITWVX.mjs.map +0 -1
  89. package/dist/host-L7FMFZUW.mjs.map +0 -1
  90. package/dist/host-QK53UYMD.mjs.map +0 -1
  91. package/dist/host-QS2EOTRJ.mjs.map +0 -1
  92. package/dist/render-3WTY7NZB.mjs +0 -9
  93. package/dist/serialize-SRJVKYUG.mjs +0 -8
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/stamps/geometry-2d/ai/providers/anthropic.ts","../src/stamps/geometry-2d/ai/providers/ollama.ts","../src/stamps/geometry-2d/ai/providers/claude-agent-sdk.ts","../src/stamps/geometry-2d/ai/providers/claude-cli.ts","../src/stamps/geometry-2d/ai/providers/index.ts","../src/stamps/geometry-2d/ai/vision/envelope.ts","../src/stamps/geometry-2d/ai/vision/prompt.ts","../src/stamps/geometry-2d/ai/vision/tesseract.ts","../src/stamps/geometry-2d/ai/vision/extractProblem.ts","../src/stamps/geometry-2d/ai/handleExtractProblem.ts"],"names":["DEFAULT_MODEL","toUsage","readEnv"],"mappings":"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","file":"chunk-T3SOHYB2.mjs","sourcesContent":["// src/stamps/geometry-2d/ai/providers/anthropic.ts\n//\n// AIProvider impl cho Anthropic Claude. Internal: dùng tool_use với single\n// tool \"emit_figure_envelope\" input_schema = envelope JSON Schema → ép Claude\n// emit JSON đúng shape. Map response → ProviderOutput envelope.\n//\n// Khác bản trước (provider.ts): bỏ dual-tool (build_figure + refuse) — Claude\n// hoàn toàn xử lý được decision/refuse trong cùng 1 envelope.\n\nimport Anthropic from '@anthropic-ai/sdk';\nimport type {\n AIProvider,\n ImagePart,\n ProviderOutput,\n ProviderRequest,\n ProviderTokenUsage,\n VisionRequest,\n} from './types';\n\nconst TOOL_NAME = 'emit_figure_envelope';\nconst VISION_TOOL_NAME = 'extract_problem_envelope';\n\nexport interface AnthropicProviderOptions {\n apiKey: string;\n /** Cache system prompt qua Anthropic prompt-caching (mặc định bật). */\n enableCaching?: boolean;\n}\n\nexport class AnthropicProvider implements AIProvider {\n readonly name = 'anthropic';\n readonly defaultModel = 'claude-opus-4-7';\n\n constructor(private readonly opts: AnthropicProviderOptions) {\n if (!opts.apiKey) throw new Error('AnthropicProvider: apiKey bắt buộc');\n }\n\n async call(req: ProviderRequest): Promise<ProviderOutput> {\n const enableCaching = this.opts.enableCaching !== false;\n const systemBlock = enableCaching\n ? { type: 'text' as const, text: req.systemPrompt, cache_control: { type: 'ephemeral' as const } }\n : { type: 'text' as const, text: req.systemPrompt };\n\n const tool = {\n name: TOOL_NAME,\n description:\n 'Emit envelope JSON cho phép vẽ hình hoặc từ chối. ' +\n 'decision=\"build\" kèm figure (DSL hình học); decision=\"refuse\" kèm reason.',\n input_schema: req.schema,\n };\n\n const client = new Anthropic({ apiKey: this.opts.apiKey });\n let resp: Anthropic.Messages.Message;\n try {\n resp = await client.messages.create(\n {\n model: req.model,\n max_tokens: req.maxTokens,\n system: [systemBlock],\n tools: [tool as never],\n tool_choice: { type: 'tool', name: TOOL_NAME },\n messages: [{ role: 'user', content: req.userPrompt }],\n },\n req.signal ? { signal: req.signal } : undefined,\n );\n } catch (e) {\n const err = e as { message?: string; status?: number };\n return {\n kind: 'error',\n message: err.message ?? 'Lỗi gọi Anthropic API',\n ...(err.status !== undefined ? { status: err.status } : {}),\n };\n }\n\n const usage = toUsage(resp.usage);\n const toolUse = resp.content.find((c) => c.type === 'tool_use');\n if (!toolUse || toolUse.type !== 'tool_use') {\n return {\n kind: 'error',\n message: 'Claude không gọi tool. stop_reason=' + resp.stop_reason,\n };\n }\n if (toolUse.name !== TOOL_NAME) {\n return {\n kind: 'error',\n message: `Tool không xác định: \"${toolUse.name}\"`,\n };\n }\n return { kind: 'json', data: toolUse.input, usage };\n }\n\n async extractText(req: VisionRequest): Promise<ProviderOutput> {\n const model = req.model ?? this.defaultModel;\n const enableCaching = this.opts.enableCaching !== false;\n const systemBlock = enableCaching\n ? { type: 'text' as const, text: req.systemPrompt, cache_control: { type: 'ephemeral' as const } }\n : { type: 'text' as const, text: req.systemPrompt };\n\n const tool = {\n name: VISION_TOOL_NAME,\n description: 'Trích đề bài hình học từ ảnh, hoặc từ chối nếu không phải đề toán.',\n input_schema: req.schema,\n };\n\n const imageBlocks = req.images.map((img: ImagePart) => ({\n type: 'image' as const,\n source: {\n type: 'base64' as const,\n media_type: img.mediaType,\n data: img.base64,\n },\n }));\n\n const client = new Anthropic({ apiKey: this.opts.apiKey });\n let resp: Anthropic.Messages.Message;\n try {\n resp = await client.messages.create(\n {\n model,\n max_tokens: req.maxTokens,\n system: [systemBlock],\n tools: [tool as never],\n tool_choice: { type: 'tool', name: VISION_TOOL_NAME },\n messages: [\n {\n role: 'user',\n content: [...imageBlocks, { type: 'text', text: req.userPrompt }],\n },\n ],\n },\n req.signal ? { signal: req.signal } : undefined,\n );\n } catch (e) {\n const err = e as { message?: string; status?: number };\n return {\n kind: 'error',\n message: err.message ?? 'Lỗi gọi Anthropic Vision API',\n ...(err.status !== undefined ? { status: err.status } : {}),\n };\n }\n\n const usage = toUsage(resp.usage);\n const toolUse = resp.content.find((c) => c.type === 'tool_use');\n if (!toolUse || toolUse.type !== 'tool_use') {\n return { kind: 'error', message: 'Claude không gọi vision tool. stop_reason=' + resp.stop_reason };\n }\n if (toolUse.name !== VISION_TOOL_NAME) {\n return { kind: 'error', message: `Claude gọi sai tool: ${toolUse.name}` };\n }\n return { kind: 'json', data: toolUse.input, usage };\n }\n}\n\nfunction toUsage(u: Anthropic.Messages.Usage): ProviderTokenUsage {\n return {\n inputTokens: u.input_tokens,\n outputTokens: u.output_tokens,\n cacheReadTokens: u.cache_read_input_tokens ?? 0,\n cacheCreationTokens: u.cache_creation_input_tokens ?? 0,\n };\n}\n","// src/stamps/geometry-2d/ai/providers/ollama.ts\n//\n// AIProvider impl cho Ollama local. Dùng /api/chat với `format: <jsonSchema>`\n// (Ollama v0.5+ — structured outputs). Model emit JSON đúng schema, parse +\n// trả về envelope.\n//\n// Setup local:\n// $ ollama pull gemma3:4b # ~3.3GB Q4\n// $ ollama serve # mặc định port 11434\n//\n// Override base URL qua env `OLLAMA_BASE_URL` (test env / remote ollama).\n\nimport type {\n AIProvider,\n ProviderOutput,\n ProviderRequest,\n ProviderTokenUsage,\n VisionRequest,\n} from './types';\n\nconst DEFAULT_BASE_URL = 'http://localhost:11434';\nconst DEFAULT_MODEL = 'gemma3:4b';\n\nexport interface OllamaProviderOptions {\n /** Endpoint base URL, default http://localhost:11434. */\n baseUrl?: string;\n /** Default model id nếu request không truyền. */\n defaultModel?: string;\n /** Custom fetch impl (dùng cho test mock). */\n fetchImpl?: typeof fetch;\n}\n\ninterface OllamaChatResponse {\n model: string;\n message: { role: 'assistant'; content: string };\n done: boolean;\n prompt_eval_count?: number;\n eval_count?: number;\n total_duration?: number;\n}\n\nexport class OllamaProvider implements AIProvider {\n readonly name = 'ollama';\n readonly defaultModel: string;\n private readonly baseUrl: string;\n private readonly fetchImpl: typeof fetch | null;\n\n constructor(opts: OllamaProviderOptions = {}) {\n this.baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.defaultModel = opts.defaultModel ?? DEFAULT_MODEL;\n // Lazy resolve: jsdom test env không có global fetch; consumer chỉ cần\n // fetch ở runtime khi gọi .call(). Custom impl ưu tiên (test mock).\n this.fetchImpl = opts.fetchImpl ?? null;\n }\n\n private resolveFetch(): typeof fetch {\n if (this.fetchImpl) return this.fetchImpl;\n if (typeof fetch === 'undefined') {\n throw new Error(\n 'OllamaProvider: global `fetch` không khả dụng. Truyền `fetchImpl` qua constructor hoặc chạy ở Node 18+ / browser.',\n );\n }\n return fetch;\n }\n\n async call(req: ProviderRequest): Promise<ProviderOutput> {\n const body = {\n model: req.model,\n messages: [\n { role: 'system', content: req.systemPrompt },\n { role: 'user', content: req.userPrompt },\n ],\n format: req.schema,\n stream: true,\n options: { num_predict: req.maxTokens, temperature: 0.2 },\n };\n\n let doFetch: typeof fetch;\n try {\n doFetch = this.resolveFetch();\n } catch (e) {\n const err = e as { message?: string };\n return { kind: 'error', message: err.message ?? 'fetch không khả dụng' };\n }\n\n let resp: Response;\n try {\n resp = await doFetch(`${this.baseUrl}/api/chat`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal: req.signal,\n });\n } catch (e) {\n const err = e as { message?: string };\n return {\n kind: 'error',\n message: err.message ?? `Không kết nối được Ollama ở ${this.baseUrl}`,\n };\n }\n\n if (!resp.ok || !resp.body) {\n let detail = '';\n try { detail = await resp.text(); } catch { /* ignore */ }\n return {\n kind: 'error',\n message: `Ollama HTTP ${resp.status}: ${detail || resp.statusText}`,\n status: resp.status,\n };\n }\n\n const reader = resp.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let content = '';\n let promptEvalCount = 0;\n let evalCount = 0;\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n let nl;\n while ((nl = buffer.indexOf('\\n')) !== -1) {\n const line = buffer.slice(0, nl).trim();\n buffer = buffer.slice(nl + 1);\n if (!line) continue;\n try {\n const chunk = JSON.parse(line) as {\n message?: { content?: string };\n done?: boolean;\n prompt_eval_count?: number;\n eval_count?: number;\n };\n if (chunk.message?.content) {\n content += chunk.message.content;\n if (req.onToken) {\n try { req.onToken(chunk.message.content); } catch { /* swallow */ }\n }\n }\n if (chunk.done) {\n promptEvalCount = chunk.prompt_eval_count ?? promptEvalCount;\n evalCount = chunk.eval_count ?? evalCount;\n }\n } catch { /* skip malformed line */ }\n }\n }\n\n const trimmed = content.trim();\n if (!trimmed) return { kind: 'error', message: 'Ollama trả message.content rỗng' };\n\n let data: unknown;\n try {\n data = JSON.parse(trimmed);\n } catch (e) {\n const err = e as { message?: string };\n return {\n kind: 'error',\n message: 'Ollama content không parse được JSON: ' + (err.message ?? '?'),\n };\n }\n\n return {\n kind: 'json',\n data,\n usage: {\n inputTokens: promptEvalCount,\n outputTokens: evalCount,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n },\n };\n }\n\n // Vision: gửi ảnh qua images[] field trong message (Ollama multimodal API).\n // Model cần hỗ trợ vision (gemma3, llava, ...). Output vẫn là JSON envelope.\n async extractText(req: VisionRequest): Promise<ProviderOutput> {\n const model = req.model ?? this.defaultModel;\n const body = {\n model,\n messages: [\n { role: 'system', content: req.systemPrompt },\n {\n role: 'user',\n content: req.userPrompt,\n images: req.images.map((i) => i.base64),\n },\n ],\n format: req.schema,\n stream: false,\n options: { num_predict: req.maxTokens, temperature: 0.2 },\n };\n\n let doFetch: typeof fetch;\n try {\n doFetch = this.resolveFetch();\n } catch (e) {\n return { kind: 'error', message: (e as { message?: string }).message ?? 'fetch không khả dụng' };\n }\n\n let resp: Response;\n try {\n resp = await doFetch(`${this.baseUrl}/api/chat`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal: req.signal,\n });\n } catch (e) {\n return {\n kind: 'error',\n message: (e as { message?: string }).message ?? `Không kết nối được Ollama ở ${this.baseUrl}`,\n };\n }\n\n if (!resp.ok) {\n let detail = '';\n try { detail = await resp.text(); } catch { /* ignore */ }\n return {\n kind: 'error',\n message: `Ollama Vision HTTP ${resp.status}: ${detail || resp.statusText}`,\n status: resp.status,\n };\n }\n\n let json: OllamaChatResponse;\n try {\n json = (await resp.json()) as OllamaChatResponse;\n } catch (e) {\n return { kind: 'error', message: 'Ollama vision response không phải JSON: ' + ((e as { message?: string }).message ?? '?') };\n }\n\n const content = json.message?.content?.trim();\n if (!content) return { kind: 'error', message: 'Ollama vision trả content rỗng' };\n\n let data: unknown;\n try {\n data = JSON.parse(content);\n } catch (e) {\n return { kind: 'error', message: 'Ollama vision content không parse JSON: ' + ((e as { message?: string }).message ?? '?') };\n }\n\n const usage: ProviderTokenUsage = {\n inputTokens: json.prompt_eval_count ?? 0,\n outputTokens: json.eval_count ?? 0,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n };\n return { kind: 'json', data, usage };\n }\n}\n","// src/stamps/geometry-2d/ai/providers/claude-agent-sdk.ts\n//\n// AIProvider impl dùng @anthropic-ai/claude-agent-sdk (official Anthropic SDK\n// wrap Claude Code binary). OAuth subscription path — bill vào Pro/Max/Team\n// thay vì API key console. KHÔNG vi phạm ToS (SDK chính chủ).\n//\n// Setup:\n// $ npm install -g @anthropic-ai/claude-code\n// $ claude setup-token # browser auth → sk-ant-oat01-...\n// $ export CLAUDE_CODE_OAUTH_TOKEN=sk-ant-oat01-...\n// $ unset ANTHROPIC_API_KEY # nếu đã set ở project khác (sẽ shadow OAuth)\n//\n// So với ClaudeCliProvider (spawn `claude -p` subprocess):\n// - Latency thấp hơn nhiều (~10-30s vs 1-2 phút) — không boot full Claude Code context\n// - Streaming-first (in-process async iterator)\n// - Cùng subscription billing path\n\nimport type { AIProvider, ProviderOutput, ProviderRequest } from './types';\n\nconst DEFAULT_MODEL = 'claude-sonnet-4-6';\n\nconst SCHEMA_CACHE = new WeakMap<object, string>();\n\nfunction memoSchemaJson(schema: object): string {\n let s = SCHEMA_CACHE.get(schema);\n if (s) return s;\n s = JSON.stringify(schema, null, 2);\n SCHEMA_CACHE.set(schema, s);\n return s;\n}\n\nexport interface ClaudeAgentSdkProviderOptions {\n /** OAuth token. Fallback: env CLAUDE_CODE_OAUTH_TOKEN. */\n oauthToken?: string;\n defaultModel?: string;\n /** Inject custom query impl cho test mock. */\n queryImpl?: ClaudeAgentSdkQueryFn;\n}\n\n/** Shape của `query` từ @anthropic-ai/claude-agent-sdk — cho test mock. */\nexport type ClaudeAgentSdkQueryFn = (args: {\n prompt: string;\n options: {\n systemPrompt?: string;\n allowedTools?: string[];\n model?: string;\n abortSignal?: AbortSignal;\n };\n}) => AsyncIterable<ClaudeAgentSdkMessage>;\n\nexport type ClaudeAgentSdkMessage =\n | {\n type: 'assistant';\n message: { content: Array<{ type: 'text'; text: string } | { type: string }> };\n }\n | {\n type: 'result';\n subtype: 'success' | 'error_during_execution' | string;\n duration_ms?: number;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n }\n | { type: 'system'; [k: string]: unknown }\n | { type: string; [k: string]: unknown };\n\nexport class ClaudeAgentSdkProvider implements AIProvider {\n readonly name = 'claude-agent-sdk';\n readonly defaultModel: string;\n private readonly oauthToken: string | undefined;\n private readonly queryImpl: ClaudeAgentSdkQueryFn | null;\n\n constructor(opts: ClaudeAgentSdkProviderOptions = {}) {\n this.defaultModel = opts.defaultModel ?? DEFAULT_MODEL;\n this.oauthToken = opts.oauthToken;\n this.queryImpl = opts.queryImpl ?? null;\n }\n\n private async resolveQuery(): Promise<ClaudeAgentSdkQueryFn> {\n if (this.queryImpl) return this.queryImpl;\n // Lazy import: chỉ load SDK khi thực sự cần. SDK requires Node (spawn).\n const mod = (await import('@anthropic-ai/claude-agent-sdk')) as {\n query: ClaudeAgentSdkQueryFn;\n };\n return mod.query;\n }\n\n async call(req: ProviderRequest): Promise<ProviderOutput> {\n // Inject OAuth token vào env nếu provider có. SDK đọc CLAUDE_CODE_OAUTH_TOKEN.\n if (this.oauthToken) {\n process.env.CLAUDE_CODE_OAUTH_TOKEN = this.oauthToken;\n }\n\n let query: ClaudeAgentSdkQueryFn;\n try {\n query = await this.resolveQuery();\n } catch (e) {\n return {\n kind: 'error',\n message:\n 'ClaudeAgentSdkProvider: SDK không khả dụng. ' +\n ((e as { message?: string }).message ?? ''),\n };\n }\n\n // Constraint output qua system prompt — Agent SDK không có --json-schema flag,\n // dùng prompt-instruct + parse JSON post-hoc. Sonnet 4.6 follow format tốt.\n const schemaText = memoSchemaJson(req.schema as object);\n const constrainedSystem = `${req.systemPrompt}\n\nQUAN TRỌNG: Output PHẢI là valid JSON đúng schema sau. KHÔNG markdown wrapper, KHÔNG prose giải thích, CHỈ raw JSON:\n\n${schemaText}`;\n\n let assistantText = '';\n let usageInput = 0;\n let usageOutput = 0;\n let cacheRead = 0;\n let cacheCreation = 0;\n\n try {\n for await (const msg of query({\n prompt: req.userPrompt,\n options: {\n systemPrompt: constrainedSystem,\n allowedTools: [],\n model: req.model ?? this.defaultModel,\n ...(req.signal ? { abortSignal: req.signal } : {}),\n },\n })) {\n if (msg.type === 'assistant') {\n const message = (msg as { message: { content: Array<unknown> } }).message;\n for (const block of message.content) {\n const b = block as { type?: string; text?: string };\n if (b.type === 'text' && typeof b.text === 'string') {\n assistantText += b.text;\n if (req.onToken) {\n try { req.onToken(b.text); } catch { /* swallow */ }\n }\n }\n }\n } else if (msg.type === 'result') {\n const r = msg as {\n subtype?: string;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n };\n if (r.subtype && r.subtype !== 'success') {\n return {\n kind: 'error',\n message: `ClaudeAgentSdkProvider: result subtype=${r.subtype}`,\n };\n }\n if (r.usage) {\n usageInput = r.usage.input_tokens ?? 0;\n usageOutput = r.usage.output_tokens ?? 0;\n cacheRead = r.usage.cache_read_input_tokens ?? 0;\n cacheCreation = r.usage.cache_creation_input_tokens ?? 0;\n }\n }\n }\n } catch (e) {\n return {\n kind: 'error',\n message:\n 'ClaudeAgentSdkProvider: query() throw: ' +\n ((e as { message?: string }).message ?? '?'),\n };\n }\n\n if (!assistantText.trim()) {\n return {\n kind: 'error',\n message: 'ClaudeAgentSdkProvider: assistant trả response rỗng.',\n };\n }\n\n // Strip markdown fence nếu Sonnet vẫn add (defensive).\n let cleaned = assistantText.trim();\n cleaned = cleaned.replace(/^```(?:json)?\\s*\\n?/i, '').replace(/\\n?\\s*```\\s*$/, '');\n\n let data: unknown;\n try {\n data = JSON.parse(cleaned);\n } catch (e) {\n return {\n kind: 'error',\n message:\n 'ClaudeAgentSdkProvider: output không parse JSON: ' +\n ((e as { message?: string }).message ?? '?') +\n '. Output preview: ' +\n cleaned.slice(0, 200),\n };\n }\n\n return {\n kind: 'json',\n data,\n usage: {\n inputTokens: usageInput,\n outputTokens: usageOutput,\n cacheReadTokens: cacheRead,\n cacheCreationTokens: cacheCreation,\n },\n };\n }\n}\n","// src/stamps/geometry-2d/ai/providers/claude-cli.ts\n//\n// AIProvider impl qua `claude` CLI subprocess (Claude Code) — dev/eval only.\n// Tận dụng OAuth subscription Claude Pro/Max/Team đã đăng nhập sẵn ở máy,\n// charge vào quota subscription thay vì API console credits.\n//\n// LƯU Ý: Theo Anthropic ToS (cập nhật 02/2026), OAuth token từ subscription\n// chỉ legal cho Claude Code CLI / claude.ai. KHÔNG dùng provider này trong\n// production third-party app — chỉ dùng cho dev/eval local. Production phải\n// dùng AnthropicProvider với API key từ console.anthropic.com.\n//\n// CLI flags dùng:\n// --print batch mode (stdin → stdout)\n// --output-format json single-result JSON envelope\n// --json-schema <schema> structured-output constraint\n// --tools \"\" disable built-in Bash/Read/Write/Edit/...\n// --append-system-prompt inject DSL system prompt\n// --model <id> model id (alias 'sonnet'/'opus' hoặc full)\n// --max-budget-usd <usd> cost cap per call (safety)\n//\n// Parse `structured_output` field từ stdout JSON (không phải `result` —\n// `result` empty khi có --json-schema).\n\nimport type {\n AIProvider,\n ProviderOutput,\n ProviderRequest,\n ProviderTokenUsage,\n} from './types';\n\n// Lazy node:child_process — tránh bundle vào browser build (provider này\n// chỉ chạy ở Node env dev/eval).\ntype SpawnFn = typeof import('node:child_process').spawn;\n\nexport interface ClaudeCliProviderOptions {\n /** Binary path. Default 'claude'. Override qua env CLAUDE_CLI_BIN. */\n bin?: string;\n /** Default model id khi request không truyền. Default 'claude-sonnet-4-6'. */\n defaultModel?: string;\n /** Cost cap per call (USD). Default 0.50. */\n maxBudgetUsd?: number;\n /** Custom spawn impl (test mock). */\n spawnImpl?: SpawnFn;\n}\n\ninterface ClaudeCliResultEnvelope {\n type: 'result';\n subtype: 'success' | 'error_during_execution' | 'error_max_turns' | string;\n is_error: boolean;\n api_error_status?: string | null;\n result?: string;\n structured_output?: unknown;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n total_cost_usd?: number;\n}\n\nconst DEFAULT_BIN = 'claude';\nconst DEFAULT_MODEL = 'claude-sonnet-4-6';\nconst DEFAULT_MAX_BUDGET_USD = 0.5;\n\nexport class ClaudeCliProvider implements AIProvider {\n readonly name = 'claude-cli';\n readonly defaultModel: string;\n private readonly bin: string;\n private readonly maxBudgetUsd: number;\n private readonly spawnImpl: SpawnFn | null;\n\n constructor(opts: ClaudeCliProviderOptions = {}) {\n this.bin = opts.bin ?? DEFAULT_BIN;\n this.defaultModel = opts.defaultModel ?? DEFAULT_MODEL;\n this.maxBudgetUsd = opts.maxBudgetUsd ?? DEFAULT_MAX_BUDGET_USD;\n this.spawnImpl = opts.spawnImpl ?? null;\n }\n\n private async resolveSpawn(): Promise<SpawnFn> {\n if (this.spawnImpl) return this.spawnImpl;\n const mod = await import('node:child_process');\n return mod.spawn;\n }\n\n async call(req: ProviderRequest): Promise<ProviderOutput> {\n let spawn: SpawnFn;\n try {\n spawn = await this.resolveSpawn();\n } catch (e) {\n return {\n kind: 'error',\n message:\n 'ClaudeCliProvider: node:child_process không khả dụng (chỉ chạy được ở Node env). ' +\n ((e as { message?: string }).message ?? ''),\n };\n }\n\n const args = [\n '--print',\n '--output-format', 'json',\n '--json-schema', JSON.stringify(req.schema),\n '--append-system-prompt', req.systemPrompt,\n '--tools', '',\n '--model', req.model,\n '--max-budget-usd', String(this.maxBudgetUsd),\n ];\n\n return new Promise<ProviderOutput>((resolve) => {\n let child;\n try {\n child = spawn(this.bin, args, { stdio: ['pipe', 'pipe', 'pipe'] });\n } catch (e) {\n resolve({\n kind: 'error',\n message:\n `ClaudeCliProvider: spawn '${this.bin}' thất bại. ` +\n ((e as { message?: string }).message ?? 'Kiểm tra claude CLI đã cài chưa.'),\n });\n return;\n }\n\n let stdout = '';\n let stderr = '';\n let settled = false;\n const settle = (out: ProviderOutput) => {\n if (settled) return;\n settled = true;\n resolve(out);\n };\n\n const onAbort = () => {\n child.kill('SIGTERM');\n settle({ kind: 'error', message: 'ClaudeCliProvider: aborted' });\n };\n if (req.signal) {\n if (req.signal.aborted) {\n onAbort();\n return;\n }\n req.signal.addEventListener('abort', onAbort, { once: true });\n }\n\n child.stdout?.on('data', (chunk: Buffer) => {\n stdout += chunk.toString('utf8');\n });\n child.stderr?.on('data', (chunk: Buffer) => {\n stderr += chunk.toString('utf8');\n });\n\n child.on('error', (e: Error) => {\n settle({\n kind: 'error',\n message: `ClaudeCliProvider: subprocess error: ${e.message}`,\n });\n });\n\n child.on('close', (code: number | null) => {\n if (settled) return;\n if (code !== 0) {\n settle({\n kind: 'error',\n message:\n `ClaudeCliProvider: exit code ${code}. stderr: ${stderr.trim() || '(empty)'}`,\n ...(typeof code === 'number' ? { status: code } : {}),\n });\n return;\n }\n\n let env: ClaudeCliResultEnvelope;\n try {\n env = JSON.parse(stdout.trim()) as ClaudeCliResultEnvelope;\n } catch (e) {\n settle({\n kind: 'error',\n message:\n 'ClaudeCliProvider: stdout không parse được JSON: ' +\n ((e as { message?: string }).message ?? '?'),\n });\n return;\n }\n\n if (env.is_error) {\n settle({\n kind: 'error',\n message:\n `ClaudeCliProvider: CLI báo lỗi (subtype=${env.subtype}, api_status=${env.api_error_status ?? 'n/a'})`,\n });\n return;\n }\n\n if (env.structured_output === undefined || env.structured_output === null) {\n settle({\n kind: 'error',\n message:\n 'ClaudeCliProvider: thiếu structured_output trong response. ' +\n `result=\"${(env.result ?? '').slice(0, 200)}\"`,\n });\n return;\n }\n\n const usage = toUsage(env.usage);\n settle({ kind: 'json', data: env.structured_output, usage });\n });\n\n // User prompt qua stdin (cleaner than arg cho prompt dài + escape).\n try {\n child.stdin?.write(req.userPrompt);\n child.stdin?.end();\n } catch (e) {\n settle({\n kind: 'error',\n message:\n 'ClaudeCliProvider: ghi stdin thất bại: ' +\n ((e as { message?: string }).message ?? '?'),\n });\n }\n });\n }\n}\n\nfunction toUsage(u: ClaudeCliResultEnvelope['usage']): ProviderTokenUsage {\n return {\n inputTokens: u?.input_tokens ?? 0,\n outputTokens: u?.output_tokens ?? 0,\n cacheReadTokens: u?.cache_read_input_tokens ?? 0,\n cacheCreationTokens: u?.cache_creation_input_tokens ?? 0,\n };\n}\n","// src/stamps/geometry-2d/ai/providers/index.ts\n//\n// Public exports + selectProvider() factory dựa trên env hoặc explicit opts.\n//\n// Quy tắc chọn provider (high → low priority):\n// 1. opts.provider — instance đã build sẵn (test/custom)\n// 2. opts.apiKey — auto-route Anthropic (backward-compat caller cũ)\n// 3. env WHITEBOARD_AI_PROVIDER\n// - \"claude-agent-sdk\" (default): @anthropic-ai/claude-agent-sdk + OAuth subscription Pro/Max/Team\n// - \"anthropic\": cần env ANTHROPIC_API_KEY (pay-per-token console)\n// - \"claude-cli\": spawn `claude -p` subprocess (legacy, chậm hơn)\n// - \"ollama\": local, không cần key, đọc OLLAMA_BASE_URL tùy chọn\n\nimport { AnthropicProvider } from './anthropic';\nimport { ClaudeAgentSdkProvider } from './claude-agent-sdk';\nimport { ClaudeCliProvider } from './claude-cli';\nimport { OllamaProvider } from './ollama';\nimport type { AIProvider } from './types';\n\nexport type { AIProvider, ProviderOutput, ProviderRequest, ProviderTokenUsage } from './types';\nexport { AnthropicProvider } from './anthropic';\nexport { ClaudeAgentSdkProvider } from './claude-agent-sdk';\nexport { ClaudeCliProvider } from './claude-cli';\nexport { OllamaProvider } from './ollama';\n\nexport interface SelectProviderOptions {\n /** Provider instance dùng trực tiếp (override mọi env). */\n provider?: AIProvider;\n /** Anthropic API key. Khi truyền → auto chọn AnthropicProvider. */\n apiKey?: string;\n /** Anthropic prompt-caching, default true (chỉ áp dụng provider Anthropic). */\n enableCaching?: boolean;\n /** Ollama endpoint override. */\n ollamaBaseUrl?: string;\n /** Ollama model override (vd \"gemma3:1b\"). */\n ollamaDefaultModel?: string;\n /** Claude CLI binary path override (default 'claude'). */\n claudeCliBin?: string;\n /** Claude CLI default model override. */\n claudeCliDefaultModel?: string;\n /** Claude CLI max budget USD per call override. */\n claudeCliMaxBudgetUsd?: number;\n /** Claude Agent SDK OAuth token (subscription path). Fallback env CLAUDE_CODE_OAUTH_TOKEN. */\n claudeAgentSdkOauthToken?: string;\n /** Claude Agent SDK default model. */\n claudeAgentSdkDefaultModel?: string;\n /** Test env: env vars getter (default process.env). */\n env?: Record<string, string | undefined>;\n}\n\nexport function selectProvider(opts: SelectProviderOptions = {}): AIProvider {\n if (opts.provider) return opts.provider;\n if (opts.apiKey) {\n return new AnthropicProvider({\n apiKey: opts.apiKey,\n enableCaching: opts.enableCaching,\n });\n }\n\n const env = opts.env ?? readEnv();\n const wanted = (env.WHITEBOARD_AI_PROVIDER ?? 'claude-agent-sdk').toLowerCase();\n\n if (wanted === 'anthropic') {\n const key = env.ANTHROPIC_API_KEY;\n if (!key) {\n throw new Error(\n 'selectProvider: WHITEBOARD_AI_PROVIDER=anthropic nhưng thiếu env ANTHROPIC_API_KEY',\n );\n }\n return new AnthropicProvider({ apiKey: key, enableCaching: opts.enableCaching });\n }\n\n if (wanted === 'claude-cli') {\n const budgetEnv = env.CLAUDE_CLI_MAX_BUDGET_USD;\n const budgetNum = budgetEnv !== undefined ? Number(budgetEnv) : undefined;\n return new ClaudeCliProvider({\n bin: opts.claudeCliBin ?? env.CLAUDE_CLI_BIN,\n defaultModel: opts.claudeCliDefaultModel ?? env.CLAUDE_CLI_MODEL,\n maxBudgetUsd:\n opts.claudeCliMaxBudgetUsd ??\n (budgetNum !== undefined && Number.isFinite(budgetNum) ? budgetNum : undefined),\n });\n }\n\n if (wanted === 'claude-agent-sdk') {\n return new ClaudeAgentSdkProvider({\n oauthToken: opts.claudeAgentSdkOauthToken ?? env.CLAUDE_CODE_OAUTH_TOKEN,\n defaultModel:\n opts.claudeAgentSdkDefaultModel ?? env.CLAUDE_AGENT_SDK_MODEL,\n });\n }\n\n if (wanted === 'ollama') {\n return new OllamaProvider({\n baseUrl: opts.ollamaBaseUrl ?? env.OLLAMA_BASE_URL,\n defaultModel: opts.ollamaDefaultModel ?? env.OLLAMA_DEFAULT_MODEL,\n });\n }\n\n throw new Error(\n `selectProvider: WHITEBOARD_AI_PROVIDER=\"${wanted}\" không hợp lệ (anthropic|claude-cli|claude-agent-sdk|ollama)`,\n );\n}\n\nfunction readEnv(): Record<string, string | undefined> {\n // process.env không tồn tại ở pure browser; ở Node/Next.js server route thì OK.\n if (typeof process !== 'undefined' && process.env) {\n return process.env as Record<string, string | undefined>;\n }\n return {};\n}\n","// src/stamps/geometry-2d/ai/vision/envelope.ts\n//\n// Envelope schema cho OCR output. AI vision luôn emit:\n// { decision: 'extract', text: '...', confidence?: 'high'|'low' }\n// { decision: 'refuse', reason: '...' }\n//\n// Schema flatten được pass cho cả Anthropic tool input_schema + Ollama format.\n\nimport { z } from 'zod';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\n\nexport const VisionEnvelopeZ = z\n .object({\n decision: z.enum(['extract', 'refuse']),\n text: z.string().optional(),\n confidence: z.enum(['high', 'low']).optional(),\n reason: z.string().optional(),\n })\n .refine(\n (e) =>\n e.decision === 'extract'\n ? e.text != null && e.text.length > 0\n : e.reason != null && e.reason.length > 0,\n { message: 'extract cần text không rỗng; refuse cần reason không rỗng' },\n );\n\nexport type VisionEnvelopeT = z.infer<typeof VisionEnvelopeZ>;\n\nexport function visionEnvelopeJsonSchema(): Record<string, unknown> {\n return zodToJsonSchema(VisionEnvelopeZ, {\n $refStrategy: 'none',\n target: 'jsonSchema7',\n }) as Record<string, unknown>;\n}\n","// src/stamps/geometry-2d/ai/vision/prompt.ts\n//\n// Prompt OCR chuyên đề toán hình học tiếng Việt. Giữ ký hiệu Unicode toán.\n\nexport function buildVisionSystemPrompt(): string {\n return [\n 'Bạn là OCR chuyên đọc đề toán hình học tiếng Việt từ ảnh.',\n '',\n 'NHIỆM VỤ:',\n '1. Đọc text trong ảnh, trả về phần ĐỀ BÀI (lời văn + công thức inline).',\n '2. GIỮ NGUYÊN các ký hiệu toán Unicode: Δ ⊥ ∥ ° ⊙ π → ≤ ≥ ∈ ∉ ∩ ∪.',\n '3. BỎ QUA hình vẽ minh hoạ — chỉ trả phần text.',\n '4. Nếu ảnh KHÔNG phải đề toán hình học (vd: văn học, ảnh đời thường, code, công thức không liên quan): decision=\"refuse\" với reason cụ thể bằng tiếng Việt.',\n '5. Đánh giá confidence:',\n ' - \"high\": ≥ 80% ký tự đọc rõ ràng, không nghi ngờ.',\n ' - \"low\": ảnh mờ, có chữ không chắc chắn, hoặc < 80% ký tự confident.',\n '',\n 'OUTPUT: JSON theo schema sau, không markdown, không giải thích thêm.',\n ' { \"decision\": \"extract\", \"text\": \"...\", \"confidence\": \"high\"|\"low\" }',\n ' { \"decision\": \"refuse\", \"reason\": \"...\" }',\n '',\n 'VÍ DỤ extract success:',\n ' { \"decision\": \"extract\", \"text\": \"Cho tam giác ABC vuông tại A. Kẻ đường cao AH ⊥ BC. Chứng minh AH² = BH · CH.\", \"confidence\": \"high\" }',\n '',\n 'VÍ DỤ refuse:',\n ' { \"decision\": \"refuse\", \"reason\": \"Ảnh không phải đề toán — đây là một đoạn văn về Truyện Kiều.\" }',\n ].join('\\n');\n}\n\nexport const VISION_USER_PROMPT = 'Đọc đề bài hình học trong ảnh sau.';\n","// src/stamps/geometry-2d/ai/vision/tesseract.ts\n//\n// Tesseract.js wrapper cho client-side OCR đề toán. Default vie+eng, terminate\n// worker sau mỗi call (không cache v1). Lazy import giữ bundle slim.\n\nimport type { ImagePart } from '../providers/types';\n\nexport interface TesseractOcrOptions {\n /** Tesseract language code. Default 'vie+eng' cho đề toán VN. */\n lang?: string;\n signal?: AbortSignal;\n}\n\nexport interface TesseractOcrResult {\n text: string;\n /** Confidence 0–100 (Tesseract scale). */\n confidence: number;\n}\n\nconst DEFAULT_LANG = 'vie+eng';\n\nexport async function runTesseractOcr(\n image: ImagePart,\n opts: TesseractOcrOptions = {},\n): Promise<TesseractOcrResult> {\n if (opts.signal?.aborted) {\n const err = new Error('Tesseract OCR aborted');\n err.name = 'AbortError';\n throw err;\n }\n\n const { createWorker } = await import('tesseract.js');\n const lang = opts.lang ?? DEFAULT_LANG;\n const worker = await createWorker(lang);\n\n try {\n const dataUrl = `data:${image.mediaType};base64,${image.base64}`;\n const { data } = await worker.recognize(dataUrl);\n return { text: data.text, confidence: data.confidence };\n } finally {\n await worker.terminate();\n }\n}\n","// src/stamps/geometry-2d/ai/vision/extractProblem.ts\n//\n// Orchestrator vision → text. Hỗ trợ 2 engine:\n// - 'tesseract' (default): client-side OCR, offline, không cần Ollama/API key.\n// - 'llm': Vision LLM qua AIProvider.extractText() (Ollama/Anthropic) — fallback\n// cho handwriting / math symbols.\n\nimport { selectProvider, type SelectProviderOptions } from '../providers';\nimport type { AIProvider, ImagePart, VisionRequest } from '../providers/types';\nimport { VisionEnvelopeZ, visionEnvelopeJsonSchema } from './envelope';\nimport { buildVisionSystemPrompt, VISION_USER_PROMPT } from './prompt';\nimport { runTesseractOcr } from './tesseract';\n\n// Ngưỡng: text ngắn hơn thì force confidence=low bất kể engine report gì.\nconst MIN_HIGH_CONFIDENCE_CHARS = 10;\nconst MAX_TEXT_CHARS = 2000;\n// Tesseract confidence (0-100): ≥ ngưỡng này coi như high.\nconst TESSERACT_HIGH_CONFIDENCE_THRESHOLD = 70;\n\nexport type VisionEngine = 'tesseract' | 'llm';\n\nexport interface ExtractProblemOptions extends SelectProviderOptions {\n /** OCR engine. Default 'tesseract' (client-side, không cần network). */\n engine?: VisionEngine;\n /** Tesseract language (chỉ áp dụng khi engine='tesseract'). Default 'vie+eng'. */\n tesseractLang?: string;\n /** Override model OCR cho LLM path. Priority cao hơn env. */\n visionModel?: string;\n /** Max tokens cho LLM response. Default 1024. */\n maxTokens?: number;\n /** Env getter override (cho test). */\n env?: Record<string, string | undefined>;\n signal?: AbortSignal;\n}\n\nexport interface ExtractProblemSuccess {\n ok: true;\n text: string;\n confidence: 'high' | 'low';\n usage: { inputTokens: number; outputTokens: number };\n}\n\nexport interface ExtractProblemFailure {\n ok: false;\n reason: 'not-math' | 'unreadable' | 'empty' | 'unsupported';\n message: string;\n}\n\nexport type ExtractProblemOutcome = ExtractProblemSuccess | ExtractProblemFailure;\n\n/** Pick vision model theo priority: opts → env → provider.defaultModel. */\nexport function pickVisionModel(\n providerDefault: string,\n opts: { visionModel?: string },\n env: Record<string, string | undefined>,\n): string {\n return opts.visionModel ?? env.WHITEBOARD_AI_VISION_MODEL ?? providerDefault;\n}\n\nexport async function extractProblemFromImage(\n image: ImagePart,\n opts: ExtractProblemOptions = {},\n): Promise<ExtractProblemOutcome> {\n const engine: VisionEngine = opts.engine ?? 'tesseract';\n if (engine === 'tesseract') {\n return extractViaTesseract(image, opts);\n }\n return extractViaLlm(image, opts);\n}\n\nasync function extractViaTesseract(\n image: ImagePart,\n opts: ExtractProblemOptions,\n): Promise<ExtractProblemOutcome> {\n let raw: { text: string; confidence: number };\n try {\n raw = await runTesseractOcr(image, {\n ...(opts.tesseractLang ? { lang: opts.tesseractLang } : {}),\n ...(opts.signal ? { signal: opts.signal } : {}),\n });\n } catch (e) {\n const err = e as { message?: string };\n return {\n ok: false,\n reason: 'unreadable',\n message: 'Tesseract OCR fail: ' + (err.message ?? '?'),\n };\n }\n\n const text = postProcess(raw.text);\n if (text.length === 0) {\n return { ok: false, reason: 'empty', message: 'Tesseract không trích được text.' };\n }\n\n const tooShort = text.length < MIN_HIGH_CONFIDENCE_CHARS;\n const lowConf = raw.confidence < TESSERACT_HIGH_CONFIDENCE_THRESHOLD;\n const confidence: 'high' | 'low' = tooShort || lowConf ? 'low' : 'high';\n\n return {\n ok: true,\n text,\n confidence,\n usage: { inputTokens: 0, outputTokens: 0 },\n };\n}\n\nasync function extractViaLlm(\n image: ImagePart,\n opts: ExtractProblemOptions,\n): Promise<ExtractProblemOutcome> {\n const provider: AIProvider = opts.provider ?? selectProvider(opts);\n if (!provider.extractText) {\n return {\n ok: false,\n reason: 'unsupported',\n message: `Provider \"${provider.name}\" không hỗ trợ đọc ảnh.`,\n };\n }\n\n const env = opts.env ?? readEnv();\n const model = pickVisionModel(provider.defaultModel, opts, env);\n const req: VisionRequest = {\n systemPrompt: buildVisionSystemPrompt(),\n userPrompt: VISION_USER_PROMPT,\n schema: visionEnvelopeJsonSchema(),\n images: [image],\n model,\n maxTokens: opts.maxTokens ?? 1024,\n ...(opts.signal ? { signal: opts.signal } : {}),\n };\n\n const out = await provider.extractText(req);\n if (out.kind === 'error') {\n return { ok: false, reason: 'unreadable', message: out.message };\n }\n\n const parsed = VisionEnvelopeZ.safeParse(out.data);\n if (!parsed.success) {\n return {\n ok: false,\n reason: 'empty',\n message: 'Không parse được output OCR: ' + parsed.error.message,\n };\n }\n\n const env_ = parsed.data;\n if (env_.decision === 'refuse') {\n return {\n ok: false,\n reason: 'not-math',\n message: env_.reason ?? 'Ảnh không phải đề toán.',\n };\n }\n\n const rawText = env_.text ?? '';\n const text = postProcess(rawText);\n if (text.length === 0) {\n return { ok: false, reason: 'empty', message: 'OCR không trích được text.' };\n }\n\n const tooShort = text.length < MIN_HIGH_CONFIDENCE_CHARS;\n const confidence: 'high' | 'low' =\n env_.confidence === 'low' || tooShort ? 'low' : 'high';\n\n const usage = out.usage ?? { inputTokens: 0, outputTokens: 0 };\n return {\n ok: true,\n text,\n confidence,\n usage: { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens },\n };\n}\n\nfunction postProcess(raw: string): string {\n let t = raw.trim();\n t = t.replace(/\\*\\*(.+?)\\*\\*/g, '$1');\n t = t.replace(/\\*(.+?)\\*/g, '$1');\n t = t.replace(/_(.+?)_/g, '$1');\n t = t.replace(/```[\\s\\S]*?```/g, '').replace(/`([^`]+)`/g, '$1');\n t = t.replace(/\\s+/g, ' ').trim();\n t = t.normalize('NFC');\n if (t.length > MAX_TEXT_CHARS) t = t.slice(0, MAX_TEXT_CHARS);\n return t;\n}\n\nfunction readEnv(): Record<string, string | undefined> {\n if (typeof process !== 'undefined' && process.env) {\n return process.env as Record<string, string | undefined>;\n }\n return {};\n}\n","// src/stamps/geometry-2d/ai/handleExtractProblem.ts\n//\n// Façade UI-friendly cho extractProblemFromImage. Map outcome → UI result kind.\n\nimport {\n extractProblemFromImage,\n type ExtractProblemOptions,\n} from './vision/extractProblem';\nimport type { ImagePart } from './providers/types';\n\nexport interface HandleExtractProblemOptions extends ExtractProblemOptions {}\n\nexport type ExtractUiResult =\n | {\n kind: 'success';\n text: string;\n usage: { inputTokens: number; outputTokens: number };\n }\n | {\n kind: 'low-confidence';\n text: string;\n warning: string;\n usage: { inputTokens: number; outputTokens: number };\n }\n | {\n kind: 'refused';\n reason: 'not-math';\n message: string;\n }\n | {\n kind: 'error';\n code: 'network' | 'unsupported' | 'unexpected' | 'empty';\n message: string;\n };\n\nexport async function handleExtractProblem(\n image: ImagePart,\n opts: HandleExtractProblemOptions = {},\n): Promise<ExtractUiResult> {\n try {\n const r = await extractProblemFromImage(image, opts);\n if (r.ok) {\n if (r.confidence === 'low') {\n return {\n kind: 'low-confidence',\n text: r.text,\n warning: 'OCR có thể không chính xác, kiểm tra trước khi vẽ.',\n usage: r.usage,\n };\n }\n return { kind: 'success', text: r.text, usage: r.usage };\n }\n if (r.reason === 'not-math') {\n return { kind: 'refused', reason: 'not-math', message: r.message };\n }\n if (r.reason === 'unsupported') {\n return { kind: 'error', code: 'unsupported', message: r.message };\n }\n if (r.reason === 'unreadable') {\n return { kind: 'error', code: 'network', message: r.message };\n }\n return { kind: 'error', code: 'empty', message: r.message };\n } catch (e) {\n return {\n kind: 'error',\n code: 'unexpected',\n message: e instanceof Error ? e.message : String(e),\n };\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { serializeScene } from './chunk-REIJZDVZ.mjs';
2
+ import { serializeScene } from './chunk-ZTQBUKLJ.mjs';
3
3
 
4
4
  // src/stamps/graph-2d/serialize.ts
5
5
  function stringifySceneState(state) {
@@ -24,5 +24,5 @@ function parseSceneState(json) {
24
24
  }
25
25
 
26
26
  export { parseSceneState, stringifySceneState };
27
- //# sourceMappingURL=chunk-I24QOHPU.mjs.map
28
- //# sourceMappingURL=chunk-I24QOHPU.mjs.map
27
+ //# sourceMappingURL=chunk-V3YJ6JFL.mjs.map
28
+ //# sourceMappingURL=chunk-V3YJ6JFL.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stamps/graph-2d/serialize.ts"],"names":[],"mappings":";;;AASO,SAAS,oBAAoB,KAAA,EAAsB;AACxD,EAAA,OAAO,eAAe,KAAK,CAAA;AAC7B;AAEO,SAAS,gBAAgB,IAAA,EAA4B;AAC1D,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,IAAA;AAC5C,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,IAAI,CAAA,CAAE,IAAA,EAAM,MAAA,KAAW,SAAA,EAAW,OAAO,IAAA;AACzC,EAAA,IAAI,CAAC,EAAE,IAAA,EAAM,IAAA,IAAQ,OAAO,CAAA,CAAE,IAAA,CAAK,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AAC7D,EAAA,IAAI,OAAO,CAAA,CAAE,OAAA,KAAY,QAAA,EAAU,OAAO,IAAA;AAC1C,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,KAAK,GAAG,OAAO,IAAA;AACpC,EAAA,IAAI,CAAC,CAAA,CAAE,OAAA,IAAW,OAAO,CAAA,CAAE,OAAA,KAAY,UAAU,OAAO,IAAA;AACxD,EAAA,OAAO,GAAA;AACT","file":"chunk-I24QOHPU.mjs","sourcesContent":["// src/stamps/graph-2d/serialize.ts\n//\n// graph-2d đã dùng plain State (không envelope) ngay từ đầu. Sau Tier D PR 3,\n// thin wrapper qua shared helper cho serialize. parseSceneState giữ behavior\n// null-on-invalid để host/index.tsx có thể discriminate \"customData hỏng\".\n\nimport { serializeScene } from '../shared/serializeScene';\nimport type { State } from '../../core/scene/types';\n\nexport function stringifySceneState(state: State): string {\n return serializeScene(state);\n}\n\nexport function parseSceneState(json: string): State | null {\n if (!json) return null;\n let raw: unknown;\n try {\n raw = JSON.parse(json);\n } catch {\n return null;\n }\n if (!raw || typeof raw !== 'object') return null;\n const v = raw as Partial<State>;\n if (v.meta?.domain !== 'graph2d') return null;\n if (!v.meta?.view || typeof v.meta.view !== 'object') return null;\n if (typeof v.counter !== 'number') return null;\n if (!Array.isArray(v.order)) return null;\n if (!v.objects || typeof v.objects !== 'object') return null;\n return raw as State;\n}\n"]}
1
+ {"version":3,"sources":["../src/stamps/graph-2d/serialize.ts"],"names":[],"mappings":";;;AASO,SAAS,oBAAoB,KAAA,EAAsB;AACxD,EAAA,OAAO,eAAe,KAAK,CAAA;AAC7B;AAEO,SAAS,gBAAgB,IAAA,EAA4B;AAC1D,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,IAAI,GAAA;AACJ,EAAA,IAAI;AACF,IAAA,GAAA,GAAM,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACvB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACA,EAAA,IAAI,CAAC,GAAA,IAAO,OAAO,GAAA,KAAQ,UAAU,OAAO,IAAA;AAC5C,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,IAAI,CAAA,CAAE,IAAA,EAAM,MAAA,KAAW,SAAA,EAAW,OAAO,IAAA;AACzC,EAAA,IAAI,CAAC,EAAE,IAAA,EAAM,IAAA,IAAQ,OAAO,CAAA,CAAE,IAAA,CAAK,IAAA,KAAS,QAAA,EAAU,OAAO,IAAA;AAC7D,EAAA,IAAI,OAAO,CAAA,CAAE,OAAA,KAAY,QAAA,EAAU,OAAO,IAAA;AAC1C,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,KAAK,GAAG,OAAO,IAAA;AACpC,EAAA,IAAI,CAAC,CAAA,CAAE,OAAA,IAAW,OAAO,CAAA,CAAE,OAAA,KAAY,UAAU,OAAO,IAAA;AACxD,EAAA,OAAO,GAAA;AACT","file":"chunk-V3YJ6JFL.mjs","sourcesContent":["// src/stamps/graph-2d/serialize.ts\n//\n// graph-2d đã dùng plain State (không envelope) ngay từ đầu. Sau Tier D PR 3,\n// thin wrapper qua shared helper cho serialize. parseSceneState giữ behavior\n// null-on-invalid để host/index.tsx có thể discriminate \"customData hỏng\".\n\nimport { serializeScene } from '../shared/serializeScene';\nimport type { State } from '../../core/scene/types';\n\nexport function stringifySceneState(state: State): string {\n return serializeScene(state);\n}\n\nexport function parseSceneState(json: string): State | null {\n if (!json) return null;\n let raw: unknown;\n try {\n raw = JSON.parse(json);\n } catch {\n return null;\n }\n if (!raw || typeof raw !== 'object') return null;\n const v = raw as Partial<State>;\n if (v.meta?.domain !== 'graph2d') return null;\n if (!v.meta?.view || typeof v.meta.view !== 'object') return null;\n if (typeof v.counter !== 'number') return null;\n if (!Array.isArray(v.order)) return null;\n if (!v.objects || typeof v.objects !== 'object') return null;\n return raw as State;\n}\n"]}