@kubuild/ai 0.4.0 → 0.5.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.
- package/dist/{chunk-T72YWBJS.js → chunk-K7CBTQCY.js} +30 -1
- package/dist/chunk-K7CBTQCY.js.map +1 -0
- package/dist/client/ai-client.d.ts +8 -1
- package/dist/client/ai-client.d.ts.map +1 -1
- package/dist/client/index.cjs +29 -0
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/react/index.cjs +60 -0
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js +32 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/use-ai-generator.d.ts +2 -1
- package/dist/react/use-ai-generator.d.ts.map +1 -1
- package/dist/server/engine.d.ts +5 -1
- package/dist/server/engine.d.ts.map +1 -1
- package/dist/server/handler.d.ts +8 -1
- package/dist/server/handler.d.ts.map +1 -1
- package/dist/server/index.cjs +152 -41
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.js +152 -41
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +32 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/dist/chunk-T72YWBJS.js.map +0 -1
package/dist/react/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createAiClient
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-K7CBTQCY.js";
|
|
4
4
|
|
|
5
5
|
// src/react/use-ai-generator.ts
|
|
6
6
|
import { useState, useCallback, useRef } from "react";
|
|
@@ -168,8 +168,39 @@ function useAiGenerator(options) {
|
|
|
168
168
|
},
|
|
169
169
|
[cancel, options]
|
|
170
170
|
);
|
|
171
|
+
const planPage = useCallback(
|
|
172
|
+
async (params) => {
|
|
173
|
+
cancel();
|
|
174
|
+
const ac = new AbortController();
|
|
175
|
+
abortControllerRef.current = ac;
|
|
176
|
+
setIsGenerating(true);
|
|
177
|
+
setIsStreaming(false);
|
|
178
|
+
setError(null);
|
|
179
|
+
setCurrentStep("Planning page structure...");
|
|
180
|
+
try {
|
|
181
|
+
const plan = await clientRef.current.planPage(params, {
|
|
182
|
+
signal: ac.signal
|
|
183
|
+
});
|
|
184
|
+
return plan;
|
|
185
|
+
} catch (err) {
|
|
186
|
+
if (ac.signal.aborted) return null;
|
|
187
|
+
const e = err instanceof Error ? err : new Error(String(err));
|
|
188
|
+
setError(e);
|
|
189
|
+
options.onError?.(e);
|
|
190
|
+
return null;
|
|
191
|
+
} finally {
|
|
192
|
+
if (abortControllerRef.current === ac) {
|
|
193
|
+
setIsGenerating(false);
|
|
194
|
+
setCurrentStep("");
|
|
195
|
+
abortControllerRef.current = null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
[cancel, options]
|
|
200
|
+
);
|
|
171
201
|
return {
|
|
172
202
|
generatePage,
|
|
203
|
+
planPage,
|
|
173
204
|
streamPage,
|
|
174
205
|
generateSection,
|
|
175
206
|
refactorNode,
|
package/dist/react/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/react/use-ai-generator.ts","../../src/react/use-ai-chat.ts","../../src/react/use-ai-agent.ts"],"sourcesContent":["import { useState, useCallback, useRef } from 'react';\nimport type { PageDocument, Node } from '@kubuild/schema';\nimport type {\n AiGeneratePageRequest,\n AiGenerateSectionRequest,\n AiRefactorNodeRequest,\n AiStreamCallbacks,\n} from '../types';\nimport { createAiClient, type AiClientOptions, KubuildAiClient } from '../client/ai-client';\n\nexport interface UseAiGeneratorOptions extends AiClientOptions {\n onSuccess?: (data: PageDocument | Node) => void;\n onError?: (error: Error) => void;\n}\n\nexport function useAiGenerator(options: UseAiGeneratorOptions) {\n const [isGenerating, setIsGenerating] = useState(false);\n const [isStreaming, setIsStreaming] = useState(false);\n const [currentStep, setCurrentStep] = useState<string>('');\n const [error, setError] = useState<Error | null>(null);\n\n const abortControllerRef = useRef<AbortController | null>(null);\n const clientRef = useRef<KubuildAiClient>(createAiClient(options));\n\n // Cancel any in-flight request\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n setIsGenerating(false);\n setIsStreaming(false);\n setCurrentStep('');\n }\n }, []);\n\n /**\n * Standard full page generator (non-streaming).\n */\n const generatePage = useCallback(\n async (params: AiGeneratePageRequest): Promise<PageDocument | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(false);\n setError(null);\n setCurrentStep('Generating full page...');\n\n try {\n const doc = await clientRef.current.generatePage(params, {\n signal: ac.signal,\n });\n options.onSuccess?.(doc);\n return doc;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n /**\n * Progressive section streamer (SSE).\n * Calls callbacks on each step (onStatus, onMetadata, onSection, onComplete).\n */\n const streamPage = useCallback(\n async (\n params: AiGeneratePageRequest,\n streamCallbacks?: AiStreamCallbacks,\n ): Promise<PageDocument | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(true);\n setError(null);\n setCurrentStep('Connecting to AI stream...');\n\n try {\n const doc = await clientRef.current.streamPage(\n params,\n {\n onStatus: (msg) => {\n setCurrentStep(msg);\n streamCallbacks?.onStatus?.(msg);\n },\n onMetadata: (metadata, rootPage) => {\n streamCallbacks?.onMetadata?.(metadata, rootPage);\n },\n onSection: (section, index, total) => {\n setCurrentStep(`Section ${index + 1}/${total} rendered`);\n streamCallbacks?.onSection?.(section, index, total);\n },\n onComplete: (completedDoc) => {\n setCurrentStep('Completed');\n streamCallbacks?.onComplete?.(completedDoc);\n options.onSuccess?.(completedDoc);\n },\n onError: (err) => {\n setError(err);\n streamCallbacks?.onError?.(err);\n options.onError?.(err);\n },\n },\n { signal: ac.signal },\n );\n\n return doc;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setIsStreaming(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n const generateSection = useCallback(\n async (params: AiGenerateSectionRequest): Promise<Node | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(false);\n setError(null);\n setCurrentStep('Generating section...');\n\n try {\n const node = await clientRef.current.generateSection(params, {\n signal: ac.signal,\n });\n options.onSuccess?.(node);\n return node;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n const refactorNode = useCallback(\n async (params: AiRefactorNodeRequest): Promise<Node | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(false);\n setError(null);\n setCurrentStep('Refactoring node...');\n\n try {\n const node = await clientRef.current.refactorNode(params, {\n signal: ac.signal,\n });\n options.onSuccess?.(node);\n return node;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n return {\n generatePage,\n streamPage,\n generateSection,\n refactorNode,\n isGenerating,\n isStreaming,\n currentStep,\n error,\n cancel,\n };\n}\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport type { PageDocument } from '@kubuild/schema';\nimport type { AiChatMessage, AiChatResponse } from '../types';\nimport { createAiClient, type AiClientOptions, KubuildAiClient } from '../client/ai-client';\n\n/**\n * Optional, host-implemented chat history persistence (STORA-520). `@kubuild/ai` stays\n * storage-agnostic — it never imports `localStorage` or any concrete storage mechanism\n * itself; the host supplies an adapter backed by whatever it wants (browser\n * `localStorage`, IndexedDB, a Stora.page backend call, etc.).\n */\nexport interface AiChatHistoryStorageAdapter {\n /** Called once on mount to seed `messages` before the user sends anything. */\n loadHistory(): Promise<AiChatMessage[]> | AiChatMessage[];\n /**\n * Called at completed-message boundaries (a user message just sent, or an assistant\n * reply that just finished/streamed to completion) — never on every mid-stream token,\n * see `useAiChat`'s persistence notes.\n */\n saveHistory(messages: AiChatMessage[]): Promise<void> | void;\n}\n\nexport interface UseAiChatOptions extends AiClientOptions {\n initialMessages?: AiChatMessage[];\n onMessage?: (message: AiChatMessage) => void;\n onError?: (error: Error) => void;\n /**\n * Fired for every partial token/chunk of a streaming chat response (STORA-516),\n * mirroring `useAiGenerator`'s `AiStreamCallbacks` naming convention. Optional — the\n * `messages` array already updates incrementally on its own, this is only for hosts\n * that want a side-channel (e.g. custom rendering, telemetry) into the raw chunks.\n */\n onChunk?: (delta: string, content: string) => void;\n /**\n * Optional storage adapter (STORA-520) used to persist/restore chat history across\n * reloads. Without it, behavior is exactly as before: pure in-memory React state, lost\n * on reload/unmount. `loadHistory()` is called once on mount to hydrate `messages`\n * (only overriding `initialMessages` when it resolves a non-empty array);\n * `saveHistory()` is called at completed-message boundaries — after a user message is\n * appended, and after an assistant reply finishes (streamed or not) — intentionally\n * *not* on every streaming chunk, to avoid hammering the adapter mid-stream.\n */\n historyStorage?: AiChatHistoryStorageAdapter;\n}\n\nexport interface SendMessageOptions {\n currentDocument?: PageDocument;\n selectedNodeId?: string;\n systemPrompt?: string;\n /**\n * Opt out of token-level streaming for this call (STORA-515/516 default to `true`).\n * When `false`, behaves exactly like the pre-streaming single request/response call.\n */\n stream?: boolean;\n}\n\nexport function useAiChat(options: UseAiChatOptions) {\n const [messages, setMessages] = useState<AiChatMessage[]>(options.initialMessages || []);\n const [isLoading, setIsLoading] = useState(false);\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const abortControllerRef = useRef<AbortController | null>(null);\n const clientRef = useRef<KubuildAiClient>(createAiClient(options));\n const historyStorageRef = useRef(options.historyStorage);\n historyStorageRef.current = options.historyStorage;\n\n /**\n * STORA-520 — best-effort persistence: a storage failure (quota exceeded, network\n * error on a remote adapter, etc.) must never break the chat itself, so errors are\n * swallowed here rather than surfaced through `setError`/`onError` (those are reserved\n * for the actual chat request failing).\n */\n const persistHistory = useCallback((history: AiChatMessage[]) => {\n const adapter = historyStorageRef.current;\n if (!adapter) return;\n try {\n void Promise.resolve(adapter.saveHistory(history)).catch(() => undefined);\n } catch {\n // Synchronous throw from a non-Promise-returning adapter — ignore, same reasoning.\n }\n }, []);\n\n // STORA-520 — hydrate from storage once on mount. Only overrides `initialMessages`\n // when the adapter actually resolves a non-empty history, so a fresh/empty adapter\n // (e.g. first-ever visit) doesn't clobber a host-provided `initialMessages` seed.\n useEffect(() => {\n const adapter = historyStorageRef.current;\n if (!adapter) return;\n let cancelled = false;\n Promise.resolve(adapter.loadHistory())\n .then((loaded) => {\n if (!cancelled && Array.isArray(loaded) && loaded.length > 0) {\n setMessages(loaded);\n }\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n const e = err instanceof Error ? err : new Error(String(err));\n options.onError?.(e);\n });\n return () => {\n cancelled = true;\n };\n // Deliberately empty deps: `historyStorage`/`onError` are read via refs/closures at\n // call time and this must run exactly once per mount, not whenever the caller passes\n // a fresh options object.\n }, []);\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n // Aborts the underlying fetch (and, for a streaming request, the in-flight\n // ReadableStream read) — not just local UI state (STORA-516 AC).\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n setIsLoading(false);\n setIsStreaming(false);\n }\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n setError(null);\n persistHistory([]);\n }, [persistHistory]);\n\n const sendMessage = useCallback(\n async (content: string, sendOptions?: SendMessageOptions): Promise<AiChatMessage | null> => {\n if (!content.trim()) return null;\n\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n const userMessage: AiChatMessage = {\n role: 'user',\n content: content.trim(),\n timestamp: Date.now(),\n };\n\n const updatedHistory = [...messages, userMessage];\n setMessages(updatedHistory);\n setIsLoading(true);\n setError(null);\n // Completed-message boundary #1 (STORA-520): the user's message is final the\n // instant it's sent — persist it now rather than waiting for the assistant reply,\n // so a reload mid-request doesn't lose it.\n persistHistory(updatedHistory);\n\n const useStream = sendOptions?.stream !== false;\n\n try {\n if (useStream) {\n setIsStreaming(true);\n\n // Placeholder assistant message, filled in incrementally as chunks arrive.\n let assistantIndex = -1;\n setMessages((prev) => {\n assistantIndex = prev.length;\n return [...prev, { role: 'assistant', content: '', timestamp: Date.now() }];\n });\n\n const finalMessage = await clientRef.current.chatStream(\n {\n messages: updatedHistory,\n currentDocument: sendOptions?.currentDocument,\n selectedNodeId: sendOptions?.selectedNodeId,\n systemPrompt: sendOptions?.systemPrompt,\n },\n {\n onChatChunk: (delta, contentSoFar) => {\n options.onChunk?.(delta, contentSoFar);\n setMessages((prev) => {\n if (assistantIndex < 0 || assistantIndex >= prev.length) return prev;\n const next = prev.slice();\n next[assistantIndex] = { ...next[assistantIndex], content: contentSoFar };\n return next;\n });\n },\n onChatComplete: (message) => {\n setMessages((prev) => {\n if (assistantIndex < 0 || assistantIndex >= prev.length) return prev;\n const next = prev.slice();\n next[assistantIndex] = message;\n return next;\n });\n },\n },\n { signal: ac.signal },\n );\n\n // Completed-message boundary #2 (STORA-520): the stream finished — persist the\n // fully assembled assistant message, never the intermediate per-chunk content\n // (`onChatChunk` above deliberately does not call `persistHistory`).\n persistHistory([...updatedHistory, finalMessage]);\n options.onMessage?.(finalMessage);\n return finalMessage;\n }\n\n const response: AiChatResponse = await clientRef.current.chat(\n {\n messages: updatedHistory,\n currentDocument: sendOptions?.currentDocument,\n selectedNodeId: sendOptions?.selectedNodeId,\n systemPrompt: sendOptions?.systemPrompt,\n },\n { signal: ac.signal },\n );\n\n const assistantMsg = response.message;\n setMessages((prev) => [...prev, assistantMsg]);\n // Completed-message boundary #2 (non-streaming variant): a single request/response\n // call has no intermediate chunks at all, so this is simply \"after the reply\".\n persistHistory([...updatedHistory, assistantMsg]);\n options.onMessage?.(assistantMsg);\n return assistantMsg;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsLoading(false);\n setIsStreaming(false);\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, messages, options, persistHistory],\n );\n\n return {\n messages,\n sendMessage,\n isLoading,\n /** Whether the in-flight `sendMessage` call is a token-level stream (STORA-516). */\n isStreaming,\n error,\n cancel,\n clearMessages,\n setMessages,\n };\n}\n","import { useCallback, useRef, useState } from 'react';\nimport type { PageDocument } from '@kubuild/schema';\nimport type { AgentOpRecord, AiAgentRunResult, AiChatMessage } from '../types';\nimport { createAiClient, type AiClientOptions, KubuildAiClient } from '../client/ai-client';\n\n/** One entry in the live run timeline the panel renders while the agent works. */\nexport interface AgentTimelineEntry {\n id: string;\n name: string;\n input: Record<string, unknown>;\n status: 'running' | 'ok' | 'failed';\n summary?: string;\n}\n\nexport interface UseAiAgentOptions extends AiClientOptions {\n onComplete?: (result: AiAgentRunResult) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface RunAgentParams {\n /** The instruction for this turn. Appended to `history` as the last user message. */\n instruction: string;\n document: PageDocument;\n selectedNodeId?: string;\n /** Prior turns of the same conversation, so follow-ups like \"tambahkan juga…\" work. */\n history?: AiChatMessage[];\n stylePreference?: string;\n maxSteps?: number;\n}\n\n/**\n * React binding for agent mode (STORA-530).\n *\n * Owns only the transport and the live run state — it deliberately does NOT apply anything\n * to a document. The resulting `ops` are handed to the caller (the editor's AI panel),\n * which reviews them with the user and then replays them through the editor store, so the\n * whole run lands as a single undoable edit.\n */\nexport function useAiAgent(options: UseAiAgentOptions) {\n const [isRunning, setIsRunning] = useState(false);\n const [step, setStep] = useState(0);\n const [maxSteps, setMaxSteps] = useState(0);\n const [timeline, setTimeline] = useState<AgentTimelineEntry[]>([]);\n const [ops, setOps] = useState<AgentOpRecord[]>([]);\n const [summary, setSummary] = useState<string>('');\n const [result, setResult] = useState<AiAgentRunResult | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const abortControllerRef = useRef<AbortController | null>(null);\n const clientRef = useRef<KubuildAiClient>(createAiClient(options));\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const reset = useCallback(() => {\n setTimeline([]);\n setOps([]);\n setSummary('');\n setResult(null);\n setError(null);\n setStep(0);\n setMaxSteps(0);\n }, []);\n\n const abort = useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setIsRunning(false);\n }, []);\n\n const run = useCallback(\n async (params: RunAgentParams): Promise<AiAgentRunResult | null> => {\n // A second run while one is in flight would interleave timeline entries from two\n // different conversations — cancel the old one first.\n abortControllerRef.current?.abort();\n const controller = new AbortController();\n abortControllerRef.current = controller;\n\n reset();\n setIsRunning(true);\n\n const messages: AiChatMessage[] = [\n ...(params.history ?? []),\n { role: 'user', content: params.instruction, timestamp: Date.now() },\n ];\n\n try {\n const runResult = await clientRef.current.runAgent(\n {\n messages,\n document: params.document,\n selectedNodeId: params.selectedNodeId,\n stylePreference: params.stylePreference,\n maxSteps: params.maxSteps,\n },\n {\n onAgentStep: (currentStep, limit) => {\n setStep(currentStep);\n setMaxSteps(limit);\n },\n onToolCall: (call) => {\n setTimeline((prev) => [\n ...prev,\n { id: call.id, name: call.name, input: call.input, status: 'running' },\n ]);\n },\n onToolResult: (toolResult) => {\n setTimeline((prev) =>\n prev.map((entry) =>\n entry.id === toolResult.id\n ? { ...entry, status: toolResult.ok ? 'ok' : 'failed', summary: toolResult.summary }\n : entry,\n ),\n );\n },\n onAgentComplete: (completed) => {\n setOps(completed.ops);\n setSummary(completed.summary);\n setResult(completed);\n optionsRef.current.onComplete?.(completed);\n },\n onError: (err) => {\n setError(err);\n optionsRef.current.onError?.(err);\n },\n },\n { signal: controller.signal },\n );\n\n return runResult;\n } catch (err) {\n const normalized = err instanceof Error ? err : new Error(String(err));\n // An abort is a user action, not a failure to report.\n if (normalized.name !== 'AbortError') {\n setError(normalized);\n optionsRef.current.onError?.(normalized);\n }\n return null;\n } finally {\n setIsRunning(false);\n abortControllerRef.current = null;\n }\n },\n [reset],\n );\n\n return {\n run,\n abort,\n reset,\n isRunning,\n step,\n maxSteps,\n timeline,\n ops,\n summary,\n result,\n error,\n };\n}\n"],"mappings":"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","names":["useState","useCallback","useRef","useState","useRef","useCallback","useCallback","useRef","useState","useState","useRef","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../../src/react/use-ai-generator.ts","../../src/react/use-ai-chat.ts","../../src/react/use-ai-agent.ts"],"sourcesContent":["import { useState, useCallback, useRef } from 'react';\nimport type { PageDocument, Node } from '@kubuild/schema';\nimport type {\n AiGeneratePageRequest,\n AiGenerateSectionRequest,\n AiRefactorNodeRequest,\n AiStreamCallbacks,\n PagePlan,\n AiPlanPageRequest,\n} from '../types';\nimport { createAiClient, type AiClientOptions, KubuildAiClient } from '../client/ai-client';\n\nexport interface UseAiGeneratorOptions extends AiClientOptions {\n onSuccess?: (data: PageDocument | Node) => void;\n onError?: (error: Error) => void;\n}\n\nexport function useAiGenerator(options: UseAiGeneratorOptions) {\n const [isGenerating, setIsGenerating] = useState(false);\n const [isStreaming, setIsStreaming] = useState(false);\n const [currentStep, setCurrentStep] = useState<string>('');\n const [error, setError] = useState<Error | null>(null);\n\n const abortControllerRef = useRef<AbortController | null>(null);\n const clientRef = useRef<KubuildAiClient>(createAiClient(options));\n\n // Cancel any in-flight request\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n setIsGenerating(false);\n setIsStreaming(false);\n setCurrentStep('');\n }\n }, []);\n\n /**\n * Standard full page generator (non-streaming).\n */\n const generatePage = useCallback(\n async (params: AiGeneratePageRequest): Promise<PageDocument | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(false);\n setError(null);\n setCurrentStep('Generating full page...');\n\n try {\n const doc = await clientRef.current.generatePage(params, {\n signal: ac.signal,\n });\n options.onSuccess?.(doc);\n return doc;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n /**\n * Progressive section streamer (SSE).\n * Calls callbacks on each step (onStatus, onMetadata, onSection, onComplete).\n */\n const streamPage = useCallback(\n async (\n params: AiGeneratePageRequest,\n streamCallbacks?: AiStreamCallbacks,\n ): Promise<PageDocument | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(true);\n setError(null);\n setCurrentStep('Connecting to AI stream...');\n\n try {\n const doc = await clientRef.current.streamPage(\n params,\n {\n onStatus: (msg) => {\n setCurrentStep(msg);\n streamCallbacks?.onStatus?.(msg);\n },\n onMetadata: (metadata, rootPage) => {\n streamCallbacks?.onMetadata?.(metadata, rootPage);\n },\n onSection: (section, index, total) => {\n setCurrentStep(`Section ${index + 1}/${total} rendered`);\n streamCallbacks?.onSection?.(section, index, total);\n },\n onComplete: (completedDoc) => {\n setCurrentStep('Completed');\n streamCallbacks?.onComplete?.(completedDoc);\n options.onSuccess?.(completedDoc);\n },\n onError: (err) => {\n setError(err);\n streamCallbacks?.onError?.(err);\n options.onError?.(err);\n },\n },\n { signal: ac.signal },\n );\n\n return doc;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setIsStreaming(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n const generateSection = useCallback(\n async (params: AiGenerateSectionRequest): Promise<Node | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(false);\n setError(null);\n setCurrentStep('Generating section...');\n\n try {\n const node = await clientRef.current.generateSection(params, {\n signal: ac.signal,\n });\n options.onSuccess?.(node);\n return node;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n const refactorNode = useCallback(\n async (params: AiRefactorNodeRequest): Promise<Node | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(false);\n setError(null);\n setCurrentStep('Refactoring node...');\n\n try {\n const node = await clientRef.current.refactorNode(params, {\n signal: ac.signal,\n });\n options.onSuccess?.(node);\n return node;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n /**\n * Plans website structure (sections overview) before generating.\n */\n const planPage = useCallback(\n async (params: AiPlanPageRequest): Promise<PagePlan | null> => {\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n setIsGenerating(true);\n setIsStreaming(false);\n setError(null);\n setCurrentStep('Planning page structure...');\n\n try {\n const plan = await clientRef.current.planPage(params, {\n signal: ac.signal,\n });\n return plan;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsGenerating(false);\n setCurrentStep('');\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, options],\n );\n\n return {\n generatePage,\n planPage,\n streamPage,\n generateSection,\n refactorNode,\n isGenerating,\n isStreaming,\n currentStep,\n error,\n cancel,\n };\n}\n","import { useState, useCallback, useRef, useEffect } from 'react';\nimport type { PageDocument } from '@kubuild/schema';\nimport type { AiChatMessage, AiChatResponse } from '../types';\nimport { createAiClient, type AiClientOptions, KubuildAiClient } from '../client/ai-client';\n\n/**\n * Optional, host-implemented chat history persistence (STORA-520). `@kubuild/ai` stays\n * storage-agnostic — it never imports `localStorage` or any concrete storage mechanism\n * itself; the host supplies an adapter backed by whatever it wants (browser\n * `localStorage`, IndexedDB, a Stora.page backend call, etc.).\n */\nexport interface AiChatHistoryStorageAdapter {\n /** Called once on mount to seed `messages` before the user sends anything. */\n loadHistory(): Promise<AiChatMessage[]> | AiChatMessage[];\n /**\n * Called at completed-message boundaries (a user message just sent, or an assistant\n * reply that just finished/streamed to completion) — never on every mid-stream token,\n * see `useAiChat`'s persistence notes.\n */\n saveHistory(messages: AiChatMessage[]): Promise<void> | void;\n}\n\nexport interface UseAiChatOptions extends AiClientOptions {\n initialMessages?: AiChatMessage[];\n onMessage?: (message: AiChatMessage) => void;\n onError?: (error: Error) => void;\n /**\n * Fired for every partial token/chunk of a streaming chat response (STORA-516),\n * mirroring `useAiGenerator`'s `AiStreamCallbacks` naming convention. Optional — the\n * `messages` array already updates incrementally on its own, this is only for hosts\n * that want a side-channel (e.g. custom rendering, telemetry) into the raw chunks.\n */\n onChunk?: (delta: string, content: string) => void;\n /**\n * Optional storage adapter (STORA-520) used to persist/restore chat history across\n * reloads. Without it, behavior is exactly as before: pure in-memory React state, lost\n * on reload/unmount. `loadHistory()` is called once on mount to hydrate `messages`\n * (only overriding `initialMessages` when it resolves a non-empty array);\n * `saveHistory()` is called at completed-message boundaries — after a user message is\n * appended, and after an assistant reply finishes (streamed or not) — intentionally\n * *not* on every streaming chunk, to avoid hammering the adapter mid-stream.\n */\n historyStorage?: AiChatHistoryStorageAdapter;\n}\n\nexport interface SendMessageOptions {\n currentDocument?: PageDocument;\n selectedNodeId?: string;\n systemPrompt?: string;\n /**\n * Opt out of token-level streaming for this call (STORA-515/516 default to `true`).\n * When `false`, behaves exactly like the pre-streaming single request/response call.\n */\n stream?: boolean;\n}\n\nexport function useAiChat(options: UseAiChatOptions) {\n const [messages, setMessages] = useState<AiChatMessage[]>(options.initialMessages || []);\n const [isLoading, setIsLoading] = useState(false);\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const abortControllerRef = useRef<AbortController | null>(null);\n const clientRef = useRef<KubuildAiClient>(createAiClient(options));\n const historyStorageRef = useRef(options.historyStorage);\n historyStorageRef.current = options.historyStorage;\n\n /**\n * STORA-520 — best-effort persistence: a storage failure (quota exceeded, network\n * error on a remote adapter, etc.) must never break the chat itself, so errors are\n * swallowed here rather than surfaced through `setError`/`onError` (those are reserved\n * for the actual chat request failing).\n */\n const persistHistory = useCallback((history: AiChatMessage[]) => {\n const adapter = historyStorageRef.current;\n if (!adapter) return;\n try {\n void Promise.resolve(adapter.saveHistory(history)).catch(() => undefined);\n } catch {\n // Synchronous throw from a non-Promise-returning adapter — ignore, same reasoning.\n }\n }, []);\n\n // STORA-520 — hydrate from storage once on mount. Only overrides `initialMessages`\n // when the adapter actually resolves a non-empty history, so a fresh/empty adapter\n // (e.g. first-ever visit) doesn't clobber a host-provided `initialMessages` seed.\n useEffect(() => {\n const adapter = historyStorageRef.current;\n if (!adapter) return;\n let cancelled = false;\n Promise.resolve(adapter.loadHistory())\n .then((loaded) => {\n if (!cancelled && Array.isArray(loaded) && loaded.length > 0) {\n setMessages(loaded);\n }\n })\n .catch((err: unknown) => {\n if (cancelled) return;\n const e = err instanceof Error ? err : new Error(String(err));\n options.onError?.(e);\n });\n return () => {\n cancelled = true;\n };\n // Deliberately empty deps: `historyStorage`/`onError` are read via refs/closures at\n // call time and this must run exactly once per mount, not whenever the caller passes\n // a fresh options object.\n }, []);\n\n const cancel = useCallback(() => {\n if (abortControllerRef.current) {\n // Aborts the underlying fetch (and, for a streaming request, the in-flight\n // ReadableStream read) — not just local UI state (STORA-516 AC).\n abortControllerRef.current.abort();\n abortControllerRef.current = null;\n setIsLoading(false);\n setIsStreaming(false);\n }\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n setError(null);\n persistHistory([]);\n }, [persistHistory]);\n\n const sendMessage = useCallback(\n async (content: string, sendOptions?: SendMessageOptions): Promise<AiChatMessage | null> => {\n if (!content.trim()) return null;\n\n cancel();\n const ac = new AbortController();\n abortControllerRef.current = ac;\n\n const userMessage: AiChatMessage = {\n role: 'user',\n content: content.trim(),\n timestamp: Date.now(),\n };\n\n const updatedHistory = [...messages, userMessage];\n setMessages(updatedHistory);\n setIsLoading(true);\n setError(null);\n // Completed-message boundary #1 (STORA-520): the user's message is final the\n // instant it's sent — persist it now rather than waiting for the assistant reply,\n // so a reload mid-request doesn't lose it.\n persistHistory(updatedHistory);\n\n const useStream = sendOptions?.stream !== false;\n\n try {\n if (useStream) {\n setIsStreaming(true);\n\n // Placeholder assistant message, filled in incrementally as chunks arrive.\n let assistantIndex = -1;\n setMessages((prev) => {\n assistantIndex = prev.length;\n return [...prev, { role: 'assistant', content: '', timestamp: Date.now() }];\n });\n\n const finalMessage = await clientRef.current.chatStream(\n {\n messages: updatedHistory,\n currentDocument: sendOptions?.currentDocument,\n selectedNodeId: sendOptions?.selectedNodeId,\n systemPrompt: sendOptions?.systemPrompt,\n },\n {\n onChatChunk: (delta, contentSoFar) => {\n options.onChunk?.(delta, contentSoFar);\n setMessages((prev) => {\n if (assistantIndex < 0 || assistantIndex >= prev.length) return prev;\n const next = prev.slice();\n next[assistantIndex] = { ...next[assistantIndex], content: contentSoFar };\n return next;\n });\n },\n onChatComplete: (message) => {\n setMessages((prev) => {\n if (assistantIndex < 0 || assistantIndex >= prev.length) return prev;\n const next = prev.slice();\n next[assistantIndex] = message;\n return next;\n });\n },\n },\n { signal: ac.signal },\n );\n\n // Completed-message boundary #2 (STORA-520): the stream finished — persist the\n // fully assembled assistant message, never the intermediate per-chunk content\n // (`onChatChunk` above deliberately does not call `persistHistory`).\n persistHistory([...updatedHistory, finalMessage]);\n options.onMessage?.(finalMessage);\n return finalMessage;\n }\n\n const response: AiChatResponse = await clientRef.current.chat(\n {\n messages: updatedHistory,\n currentDocument: sendOptions?.currentDocument,\n selectedNodeId: sendOptions?.selectedNodeId,\n systemPrompt: sendOptions?.systemPrompt,\n },\n { signal: ac.signal },\n );\n\n const assistantMsg = response.message;\n setMessages((prev) => [...prev, assistantMsg]);\n // Completed-message boundary #2 (non-streaming variant): a single request/response\n // call has no intermediate chunks at all, so this is simply \"after the reply\".\n persistHistory([...updatedHistory, assistantMsg]);\n options.onMessage?.(assistantMsg);\n return assistantMsg;\n } catch (err: unknown) {\n if (ac.signal.aborted) return null;\n const e = err instanceof Error ? err : new Error(String(err));\n setError(e);\n options.onError?.(e);\n return null;\n } finally {\n if (abortControllerRef.current === ac) {\n setIsLoading(false);\n setIsStreaming(false);\n abortControllerRef.current = null;\n }\n }\n },\n [cancel, messages, options, persistHistory],\n );\n\n return {\n messages,\n sendMessage,\n isLoading,\n /** Whether the in-flight `sendMessage` call is a token-level stream (STORA-516). */\n isStreaming,\n error,\n cancel,\n clearMessages,\n setMessages,\n };\n}\n","import { useCallback, useRef, useState } from 'react';\nimport type { PageDocument } from '@kubuild/schema';\nimport type { AgentOpRecord, AiAgentRunResult, AiChatMessage } from '../types';\nimport { createAiClient, type AiClientOptions, KubuildAiClient } from '../client/ai-client';\n\n/** One entry in the live run timeline the panel renders while the agent works. */\nexport interface AgentTimelineEntry {\n id: string;\n name: string;\n input: Record<string, unknown>;\n status: 'running' | 'ok' | 'failed';\n summary?: string;\n}\n\nexport interface UseAiAgentOptions extends AiClientOptions {\n onComplete?: (result: AiAgentRunResult) => void;\n onError?: (error: Error) => void;\n}\n\nexport interface RunAgentParams {\n /** The instruction for this turn. Appended to `history` as the last user message. */\n instruction: string;\n document: PageDocument;\n selectedNodeId?: string;\n /** Prior turns of the same conversation, so follow-ups like \"tambahkan juga…\" work. */\n history?: AiChatMessage[];\n stylePreference?: string;\n maxSteps?: number;\n}\n\n/**\n * React binding for agent mode (STORA-530).\n *\n * Owns only the transport and the live run state — it deliberately does NOT apply anything\n * to a document. The resulting `ops` are handed to the caller (the editor's AI panel),\n * which reviews them with the user and then replays them through the editor store, so the\n * whole run lands as a single undoable edit.\n */\nexport function useAiAgent(options: UseAiAgentOptions) {\n const [isRunning, setIsRunning] = useState(false);\n const [step, setStep] = useState(0);\n const [maxSteps, setMaxSteps] = useState(0);\n const [timeline, setTimeline] = useState<AgentTimelineEntry[]>([]);\n const [ops, setOps] = useState<AgentOpRecord[]>([]);\n const [summary, setSummary] = useState<string>('');\n const [result, setResult] = useState<AiAgentRunResult | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const abortControllerRef = useRef<AbortController | null>(null);\n const clientRef = useRef<KubuildAiClient>(createAiClient(options));\n const optionsRef = useRef(options);\n optionsRef.current = options;\n\n const reset = useCallback(() => {\n setTimeline([]);\n setOps([]);\n setSummary('');\n setResult(null);\n setError(null);\n setStep(0);\n setMaxSteps(0);\n }, []);\n\n const abort = useCallback(() => {\n abortControllerRef.current?.abort();\n abortControllerRef.current = null;\n setIsRunning(false);\n }, []);\n\n const run = useCallback(\n async (params: RunAgentParams): Promise<AiAgentRunResult | null> => {\n // A second run while one is in flight would interleave timeline entries from two\n // different conversations — cancel the old one first.\n abortControllerRef.current?.abort();\n const controller = new AbortController();\n abortControllerRef.current = controller;\n\n reset();\n setIsRunning(true);\n\n const messages: AiChatMessage[] = [\n ...(params.history ?? []),\n { role: 'user', content: params.instruction, timestamp: Date.now() },\n ];\n\n try {\n const runResult = await clientRef.current.runAgent(\n {\n messages,\n document: params.document,\n selectedNodeId: params.selectedNodeId,\n stylePreference: params.stylePreference,\n maxSteps: params.maxSteps,\n },\n {\n onAgentStep: (currentStep, limit) => {\n setStep(currentStep);\n setMaxSteps(limit);\n },\n onToolCall: (call) => {\n setTimeline((prev) => [\n ...prev,\n { id: call.id, name: call.name, input: call.input, status: 'running' },\n ]);\n },\n onToolResult: (toolResult) => {\n setTimeline((prev) =>\n prev.map((entry) =>\n entry.id === toolResult.id\n ? { ...entry, status: toolResult.ok ? 'ok' : 'failed', summary: toolResult.summary }\n : entry,\n ),\n );\n },\n onAgentComplete: (completed) => {\n setOps(completed.ops);\n setSummary(completed.summary);\n setResult(completed);\n optionsRef.current.onComplete?.(completed);\n },\n onError: (err) => {\n setError(err);\n optionsRef.current.onError?.(err);\n },\n },\n { signal: controller.signal },\n );\n\n return runResult;\n } catch (err) {\n const normalized = err instanceof Error ? err : new Error(String(err));\n // An abort is a user action, not a failure to report.\n if (normalized.name !== 'AbortError') {\n setError(normalized);\n optionsRef.current.onError?.(normalized);\n }\n return null;\n } finally {\n setIsRunning(false);\n abortControllerRef.current = null;\n }\n },\n [reset],\n );\n\n return {\n run,\n abort,\n reset,\n isRunning,\n step,\n maxSteps,\n timeline,\n ops,\n summary,\n result,\n error,\n };\n}\n"],"mappings":"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","names":["useState","useCallback","useRef","useState","useRef","useCallback","useCallback","useRef","useState","useState","useRef","useCallback"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PageDocument, Node } from '@kubuild/schema';
|
|
2
|
-
import type { AiGeneratePageRequest, AiGenerateSectionRequest, AiRefactorNodeRequest, AiStreamCallbacks } from '../types';
|
|
2
|
+
import type { AiGeneratePageRequest, AiGenerateSectionRequest, AiRefactorNodeRequest, AiStreamCallbacks, PagePlan, AiPlanPageRequest } from '../types';
|
|
3
3
|
import { type AiClientOptions } from '../client/ai-client';
|
|
4
4
|
export interface UseAiGeneratorOptions extends AiClientOptions {
|
|
5
5
|
onSuccess?: (data: PageDocument | Node) => void;
|
|
@@ -7,6 +7,7 @@ export interface UseAiGeneratorOptions extends AiClientOptions {
|
|
|
7
7
|
}
|
|
8
8
|
export declare function useAiGenerator(options: UseAiGeneratorOptions): {
|
|
9
9
|
generatePage: (params: AiGeneratePageRequest) => Promise<PageDocument | null>;
|
|
10
|
+
planPage: (params: AiPlanPageRequest) => Promise<PagePlan | null>;
|
|
10
11
|
streamPage: (params: AiGeneratePageRequest, streamCallbacks?: AiStreamCallbacks) => Promise<PageDocument | null>;
|
|
11
12
|
generateSection: (params: AiGenerateSectionRequest) => Promise<Node | null>;
|
|
12
13
|
refactorNode: (params: AiRefactorNodeRequest) => Promise<Node | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-ai-generator.d.ts","sourceRoot":"","sources":["../../src/react/use-ai-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAkB,KAAK,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAE5F,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB;2BAwB1C,qBAAqB,KAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"use-ai-generator.d.ts","sourceRoot":"","sources":["../../src/react/use-ai-generator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,QAAQ,EACR,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAkB,KAAK,eAAe,EAAmB,MAAM,qBAAqB,CAAC;AAE5F,MAAM,WAAW,qBAAsB,SAAQ,eAAe;IAC5D,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI,KAAK,IAAI,CAAC;IAChD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CAClC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB;2BAwB1C,qBAAqB,KAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;uBA2KpD,iBAAiB,KAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;yBApIjD,qBAAqB,oBACX,iBAAiB,KAClC,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;8BA2DhB,wBAAwB,KAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;2BAkC/C,qBAAqB,KAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;;;;;;EAiF9D"}
|
package/dist/server/engine.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PageDocument, Node } from '@kubuild/schema';
|
|
2
|
-
import type { KubuildAiEngineOptions, AiGeneratePageRequest, AiGenerateSectionRequest, AiRefactorNodeRequest, AiChatRequest, AiChatResponse, AiGenerateResponse, AiStreamEvent } from '../types';
|
|
2
|
+
import type { KubuildAiEngineOptions, AiGeneratePageRequest, AiGenerateSectionRequest, AiRefactorNodeRequest, AiChatRequest, AiChatResponse, AiGenerateResponse, AiStreamEvent, PagePlan, AiPlanPageRequest } from '../types';
|
|
3
3
|
export declare class KubuildAiEngine {
|
|
4
4
|
private options;
|
|
5
5
|
private catalog;
|
|
@@ -16,6 +16,10 @@ export declare class KubuildAiEngine {
|
|
|
16
16
|
refactorNode(request: AiRefactorNodeRequest, context?: {
|
|
17
17
|
signal?: AbortSignal;
|
|
18
18
|
}): Promise<AiGenerateResponse<Node>>;
|
|
19
|
+
private buildPlanPrompts;
|
|
20
|
+
planPage(request: AiPlanPageRequest, context?: {
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}): Promise<AiGenerateResponse<PagePlan>>;
|
|
19
23
|
/**
|
|
20
24
|
* Progressive Section Streaming Generator.
|
|
21
25
|
* Emits structured SSE events: status -> metadata -> section (one by one) -> complete.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/server/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,IAAI,EAA4C,MAAM,iBAAiB,CAAC;AAC/F,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,cAAc,EAEd,kBAAkB,EAElB,aAAa,
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../src/server/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,IAAI,EAA4C,MAAM,iBAAiB,CAAC;AAC/F,OAAO,KAAK,EACV,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,cAAc,EAEd,kBAAkB,EAElB,aAAa,EACb,QAAQ,EAER,iBAAiB,EAClB,MAAM,UAAU,CAAC;AAclB,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,OAAO,CAA4B;gBAE/B,OAAO,EAAE,sBAAsB;IAQ3C,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,cAAc,IAAI,IAAI;IAItB,OAAO,CAAC,GAAG;IASL,YAAY,CAChB,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC;IAwEtC,eAAe,CACnB,OAAO,EAAE,wBAAwB,EACjC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IAuD9B,YAAY,CAChB,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;IA+CpC,OAAO,CAAC,gBAAgB;IAsDlB,QAAQ,CACZ,OAAO,EAAE,iBAAiB,EAC1B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IA2CxC;;;OAGG;IACI,UAAU,CACf,OAAO,EAAE,qBAAqB,EAC9B,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,aAAa,CAAC,aAAa,CAAC;IA6L/B;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA4CvB;;;;;;;OAOG;IACG,IAAI,CACR,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,OAAO,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;IAsD9C;;;;;;;;;;;OAWG;IACI,UAAU,CACf,OAAO,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GACjC,aAAa,CAAC,aAAa,CAAC;CA4EhC"}
|
package/dist/server/handler.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { KubuildAiEngine } from './engine';
|
|
2
2
|
import type { KubuildAiAgent } from './agent';
|
|
3
3
|
import type { PageDocument } from '@kubuild/schema';
|
|
4
|
-
import type { AiGeneratePageRequest, AiRefactorNodeRequest, AiChatMessage, AiGenerateResponse, AiGenerationMode } from '../types';
|
|
4
|
+
import type { AiGeneratePageRequest, AiRefactorNodeRequest, AiChatMessage, AiGenerateResponse, AiGenerationMode, PagePlan } from '../types';
|
|
5
5
|
export interface AiApiRequestBody {
|
|
6
6
|
mode?: AiGenerationMode;
|
|
7
7
|
prompt?: string;
|
|
@@ -17,6 +17,13 @@ export interface AiApiRequestBody {
|
|
|
17
17
|
messages?: AiChatMessage[];
|
|
18
18
|
currentDocument?: PageDocument;
|
|
19
19
|
selectedNodeId?: string;
|
|
20
|
+
/** Prior conversation history from chat mode so generator keeps full context. */
|
|
21
|
+
conversationHistory?: AiChatMessage[];
|
|
22
|
+
sectionCount?: number | {
|
|
23
|
+
min?: number;
|
|
24
|
+
max?: number;
|
|
25
|
+
};
|
|
26
|
+
plan?: PagePlan;
|
|
20
27
|
/** Agent mode (STORA-530) — the snapshot the agent reads and patches. */
|
|
21
28
|
document?: PageDocument;
|
|
22
29
|
maxSteps?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/server/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EACV,qBAAqB,EAErB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/server/handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EACV,qBAAqB,EAErB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAEhB,QAAQ,EACT,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,gBAAgB,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC7C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;IAC3B,eAAe,CAAC,EAAE,YAAY,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iFAAiF;IACjF,mBAAmB,CAAC,EAAE,aAAa,EAAE,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD,IAAI,CAAC,EAAE,QAAQ,CAAC;IAChB,yEAAyE;IACzE,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,WAAW,EACpB,KAAK,CAAC,EAAE,cAAc,GACrB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAA;CAAE,CAAC,CAkMpE;AAsDD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IAEvB;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,GAAG,QAAQ,GAAG,IAAI,CAAC;CAClF;AA8CD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,sBAAsB,IACzE,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA+JnD"}
|
package/dist/server/index.cjs
CHANGED
|
@@ -735,6 +735,13 @@ var KubuildAiEngine = class {
|
|
|
735
735
|
Tone: ${request.tone}`;
|
|
736
736
|
if (request.locale) userPrompt += `
|
|
737
737
|
Language/Locale: ${request.locale}`;
|
|
738
|
+
if (request.conversationHistory && request.conversationHistory.length > 0) {
|
|
739
|
+
const chatContext = request.conversationHistory.map((m) => `${m.role.toUpperCase()}: ${getMessageText(m)}`).join("\n");
|
|
740
|
+
userPrompt += `
|
|
741
|
+
|
|
742
|
+
Prior Conversation Discussion Context:
|
|
743
|
+
${chatContext}`;
|
|
744
|
+
}
|
|
738
745
|
const jsonSchema = buildJsonSchemaForMode("full-page");
|
|
739
746
|
const result = await this.options.adapter.generate({
|
|
740
747
|
systemPrompt,
|
|
@@ -873,18 +880,18 @@ ${JSON.stringify(request.node, null, 2)}`;
|
|
|
873
880
|
};
|
|
874
881
|
}
|
|
875
882
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
883
|
+
buildPlanPrompts(request) {
|
|
884
|
+
let sectionGuidance = "Plan between 4 to 6 cohesive, essential sections (e.g., hero, features, testimonials, pricing, cta, footer) that fulfill the request thoroughly.";
|
|
885
|
+
if (typeof request.sectionCount === "number") {
|
|
886
|
+
sectionGuidance = `Plan exactly ${request.sectionCount} cohesive sections that fulfill the request.`;
|
|
887
|
+
} else if (request.sectionCount?.min || request.sectionCount?.max) {
|
|
888
|
+
const min = request.sectionCount.min ?? 3;
|
|
889
|
+
const max = request.sectionCount.max ?? 8;
|
|
890
|
+
sectionGuidance = `Plan between ${min} and ${max} cohesive sections that fulfill the request.`;
|
|
891
|
+
} else {
|
|
892
|
+
sectionGuidance += " If the user request mentions a specific number or list of sections, respect the user request.";
|
|
893
|
+
}
|
|
894
|
+
const planSystemPrompt = `
|
|
888
895
|
You are a web architect for the KUBUILD page builder.
|
|
889
896
|
Given the user's prompt, plan the website structure. Output pure JSON (no markdown fences, no explanatory text):
|
|
890
897
|
{
|
|
@@ -906,44 +913,113 @@ Given the user's prompt, plan the website structure. Output pure JSON (no markdo
|
|
|
906
913
|
}
|
|
907
914
|
]
|
|
908
915
|
}
|
|
909
|
-
|
|
916
|
+
${sectionGuidance}
|
|
910
917
|
`;
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
918
|
+
let planUserPrompt = `User Request: ${request.prompt}`;
|
|
919
|
+
if (request.stylePreference) {
|
|
920
|
+
planUserPrompt += `
|
|
914
921
|
Style Preference: ${request.stylePreference}`;
|
|
915
|
-
|
|
916
|
-
|
|
922
|
+
}
|
|
923
|
+
if (request.tone) planUserPrompt += `
|
|
917
924
|
Tone: ${request.tone}`;
|
|
918
|
-
|
|
925
|
+
if (request.locale) planUserPrompt += `
|
|
919
926
|
Locale: ${request.locale}`;
|
|
920
|
-
|
|
927
|
+
if (request.conversationHistory && request.conversationHistory.length > 0) {
|
|
928
|
+
const chatContext = request.conversationHistory.map((m) => `${m.role.toUpperCase()}: ${getMessageText(m)}`).join("\n");
|
|
929
|
+
planUserPrompt += `
|
|
930
|
+
|
|
931
|
+
Prior Conversation Discussion Context:
|
|
932
|
+
${chatContext}`;
|
|
933
|
+
}
|
|
934
|
+
return { systemPrompt: planSystemPrompt, userPrompt: planUserPrompt };
|
|
935
|
+
}
|
|
936
|
+
async planPage(request, context) {
|
|
937
|
+
let rawText = "";
|
|
938
|
+
try {
|
|
939
|
+
const { systemPrompt, userPrompt } = this.buildPlanPrompts(request);
|
|
940
|
+
this.log("info", `Planning website layout for: "${request.prompt}"`);
|
|
921
941
|
const planResult = await this.options.adapter.generate({
|
|
922
|
-
systemPrompt
|
|
923
|
-
userPrompt
|
|
942
|
+
systemPrompt,
|
|
943
|
+
userPrompt,
|
|
924
944
|
signal: context?.signal
|
|
925
945
|
});
|
|
926
|
-
|
|
946
|
+
rawText = planResult.text;
|
|
947
|
+
const plan = extractJsonFromResponse(rawText);
|
|
948
|
+
return {
|
|
949
|
+
success: true,
|
|
950
|
+
data: plan,
|
|
951
|
+
usage: planResult.usage,
|
|
952
|
+
rawModelResponse: rawText
|
|
953
|
+
};
|
|
954
|
+
} catch (err) {
|
|
955
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
956
|
+
this.log("warn", "Failed to generate plan JSON, using fallback plan", message);
|
|
957
|
+
const fallbackPlan = {
|
|
958
|
+
title: "AI Generated Page",
|
|
959
|
+
description: "Generated by KUBUILD AI",
|
|
960
|
+
sections: [
|
|
961
|
+
{ type: "hero", title: "Hero Banner", prompt: `Hero section for: ${request.prompt}` },
|
|
962
|
+
{ type: "features", title: "Key Features", prompt: `Features grid for: ${request.prompt}` },
|
|
963
|
+
{ type: "testimonials", title: "Testimonials", prompt: `Social proof and customer reviews for: ${request.prompt}` },
|
|
964
|
+
{ type: "cta", title: "Call To Action", prompt: `Call to action section for: ${request.prompt}` },
|
|
965
|
+
{ type: "footer", title: "Footer", prompt: `Footer navigation and copyright for: ${request.prompt}` }
|
|
966
|
+
]
|
|
967
|
+
};
|
|
968
|
+
return {
|
|
969
|
+
success: true,
|
|
970
|
+
data: fallbackPlan,
|
|
971
|
+
rawModelResponse: rawText || void 0
|
|
972
|
+
};
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Progressive Section Streaming Generator.
|
|
977
|
+
* Emits structured SSE events: status -> metadata -> section (one by one) -> complete.
|
|
978
|
+
*/
|
|
979
|
+
async *streamPage(request, context) {
|
|
980
|
+
try {
|
|
981
|
+
this.log("info", `[SSE] Starting streamPage for prompt: "${request.prompt}"`);
|
|
982
|
+
yield {
|
|
983
|
+
type: "status",
|
|
984
|
+
message: "Analyzing requirements and planning page sections..."
|
|
985
|
+
};
|
|
927
986
|
let plan;
|
|
928
|
-
|
|
929
|
-
plan =
|
|
930
|
-
this.log("
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
987
|
+
if (request.plan && Array.isArray(request.plan.sections) && request.plan.sections.length > 0) {
|
|
988
|
+
plan = request.plan;
|
|
989
|
+
this.log("info", `[SSE] Using approved pre-planned structure with ${plan.sections?.length ?? 0} sections`);
|
|
990
|
+
} else {
|
|
991
|
+
const { systemPrompt: planSystemPrompt, userPrompt: planUserPrompt } = this.buildPlanPrompts(request);
|
|
992
|
+
this.log("info", "[SSE] Generating website layout plan...");
|
|
993
|
+
const planResult = await this.options.adapter.generate({
|
|
994
|
+
systemPrompt: planSystemPrompt,
|
|
995
|
+
userPrompt: planUserPrompt,
|
|
996
|
+
signal: context?.signal
|
|
997
|
+
});
|
|
998
|
+
this.log("debug", "[SSE] Raw plan response from model", planResult.text);
|
|
999
|
+
try {
|
|
1000
|
+
plan = extractJsonFromResponse(planResult.text);
|
|
1001
|
+
this.log("debug", "[SSE] Parsed plan successfully", plan);
|
|
1002
|
+
} catch (parseErr) {
|
|
1003
|
+
this.log("warn", "[SSE] Failed to parse plan JSON, using fallback plan", parseErr);
|
|
1004
|
+
plan = {
|
|
1005
|
+
title: "AI Generated Page",
|
|
1006
|
+
description: "Generated by KUBUILD AI",
|
|
1007
|
+
sections: [
|
|
1008
|
+
{ type: "hero", title: "Hero Banner", prompt: `Hero section for: ${request.prompt}` },
|
|
1009
|
+
{ type: "features", title: "Key Features", prompt: `Features grid for: ${request.prompt}` },
|
|
1010
|
+
{ type: "testimonials", title: "Testimonials", prompt: `Social proof for: ${request.prompt}` },
|
|
1011
|
+
{ type: "cta", title: "Call To Action", prompt: `Call to action section for: ${request.prompt}` },
|
|
1012
|
+
{ type: "footer", title: "Footer", prompt: `Footer for: ${request.prompt}` }
|
|
1013
|
+
]
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
942
1016
|
}
|
|
943
1017
|
const sectionsToGenerate = Array.isArray(plan.sections) && plan.sections.length > 0 ? plan.sections : [
|
|
944
1018
|
{ type: "hero", title: "Hero Section", prompt: `Hero banner for: ${request.prompt}` },
|
|
945
1019
|
{ type: "features", title: "Features", prompt: `Features grid for: ${request.prompt}` },
|
|
946
|
-
{ type: "
|
|
1020
|
+
{ type: "testimonials", title: "Testimonials", prompt: `Social proof for: ${request.prompt}` },
|
|
1021
|
+
{ type: "cta", title: "Call To Action", prompt: `CTA section for: ${request.prompt}` },
|
|
1022
|
+
{ type: "footer", title: "Footer", prompt: `Footer section for: ${request.prompt}` }
|
|
947
1023
|
];
|
|
948
1024
|
const metadata = import_schema2.DocumentMetadataSchema.parse({
|
|
949
1025
|
title: plan.title || "AI Generated Page",
|
|
@@ -2325,7 +2401,10 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
2325
2401
|
stylePreference: payload.stylePreference,
|
|
2326
2402
|
tone: payload.tone,
|
|
2327
2403
|
locale: payload.locale,
|
|
2328
|
-
metadata: payload.metadata
|
|
2404
|
+
metadata: payload.metadata,
|
|
2405
|
+
conversationHistory: payload.conversationHistory ?? payload.messages,
|
|
2406
|
+
sectionCount: payload.sectionCount,
|
|
2407
|
+
plan: payload.plan
|
|
2329
2408
|
},
|
|
2330
2409
|
{ signal }
|
|
2331
2410
|
);
|
|
@@ -2433,13 +2512,42 @@ async function processAiRequest(engine, body, signal, agent) {
|
|
|
2433
2512
|
response: { success: result.stoppedBy !== "error", data: result }
|
|
2434
2513
|
};
|
|
2435
2514
|
}
|
|
2515
|
+
if (mode === "plan") {
|
|
2516
|
+
if (!payload.prompt || typeof payload.prompt !== "string") {
|
|
2517
|
+
return {
|
|
2518
|
+
status: 400,
|
|
2519
|
+
response: {
|
|
2520
|
+
success: false,
|
|
2521
|
+
error: {
|
|
2522
|
+
code: "INVALID_PROMPT",
|
|
2523
|
+
message: '"prompt" is required for planning mode'
|
|
2524
|
+
}
|
|
2525
|
+
}
|
|
2526
|
+
};
|
|
2527
|
+
}
|
|
2528
|
+
const result = await engine.planPage(
|
|
2529
|
+
{
|
|
2530
|
+
prompt: payload.prompt,
|
|
2531
|
+
stylePreference: payload.stylePreference,
|
|
2532
|
+
tone: payload.tone,
|
|
2533
|
+
locale: payload.locale,
|
|
2534
|
+
sectionCount: payload.sectionCount,
|
|
2535
|
+
conversationHistory: payload.conversationHistory ?? payload.messages
|
|
2536
|
+
},
|
|
2537
|
+
{ signal }
|
|
2538
|
+
);
|
|
2539
|
+
return {
|
|
2540
|
+
status: result.success ? 200 : 500,
|
|
2541
|
+
response: result
|
|
2542
|
+
};
|
|
2543
|
+
}
|
|
2436
2544
|
return {
|
|
2437
2545
|
status: 400,
|
|
2438
2546
|
response: {
|
|
2439
2547
|
success: false,
|
|
2440
2548
|
error: {
|
|
2441
2549
|
code: "UNKNOWN_MODE",
|
|
2442
|
-
message: `Unsupported mode: ${String(mode)}. Supported modes: 'full-page', 'section', 'refactor', 'chat', 'agent'`
|
|
2550
|
+
message: `Unsupported mode: ${String(mode)}. Supported modes: 'full-page', 'section', 'refactor', 'chat', 'agent', 'plan'`
|
|
2443
2551
|
}
|
|
2444
2552
|
}
|
|
2445
2553
|
};
|
|
@@ -2622,7 +2730,10 @@ function createAiHandler(engine, options) {
|
|
|
2622
2730
|
stylePreference: body.stylePreference,
|
|
2623
2731
|
tone: body.tone,
|
|
2624
2732
|
locale: body.locale,
|
|
2625
|
-
metadata: body.metadata
|
|
2733
|
+
metadata: body.metadata,
|
|
2734
|
+
conversationHistory: body.conversationHistory ?? body.messages,
|
|
2735
|
+
sectionCount: body.sectionCount,
|
|
2736
|
+
plan: body.plan
|
|
2626
2737
|
},
|
|
2627
2738
|
{ signal: request.signal }
|
|
2628
2739
|
),
|