@miraiclip/assistant 0.1.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/LICENSE +21 -0
- package/README.md +21 -0
- package/dist/index.cjs +784 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +358 -0
- package/dist/index.d.ts +358 -0
- package/dist/index.js +774 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/openai.ts","../src/http.ts","../src/tools.ts","../src/fork.ts","../src/run.ts","../src/testing.ts"],"sourcesContent":["/**\n * The vendor-neutral model contract. An adapter turns these neutral messages\n * and tools into one vendor's API and back; nothing else in the package knows\n * which vendor is on the other end.\n */\n\n/** A tool call the model made. `arguments` is already parsed JSON. */\nexport interface ToolCall {\n id: string;\n name: string;\n arguments: Record<string, unknown>;\n}\n\nexport type ChatMessage =\n | { role: \"system\"; content: string }\n | { role: \"user\"; content: string }\n | { role: \"assistant\"; content: string; toolCalls?: ToolCall[] }\n | { role: \"tool\"; toolCallId: string; name: string; content: string };\n\n/** A tool as the model sees it: name, description and a JSON Schema for its input. */\nexport interface ToolSpec {\n name: string;\n description: string;\n inputSchema: Record<string, unknown>;\n}\n\nexport interface ChatRequest {\n messages: ChatMessage[];\n tools?: ToolSpec[];\n /** Model id, when the adapter serves several. */\n model?: string;\n maxOutputTokens?: number;\n /** Vendor-specific request fields, passed through untouched (e.g. `{ reasoning_effort: \"low\" }`). */\n params?: Record<string, unknown>;\n}\n\nexport interface ChatUsage {\n inputTokens?: number;\n outputTokens?: number;\n}\n\nexport interface ChatResponse {\n content: string;\n toolCalls: ToolCall[];\n /** Why the model stopped. */\n finish: \"stop\" | \"tool_calls\" | \"length\" | \"content_filter\" | \"other\";\n model?: string;\n usage?: ChatUsage;\n}\n\nexport interface ChatOptions {\n signal?: AbortSignal;\n /** Streaming text, as it arrives (adapters that can't stream call it once). */\n onText?: (delta: string) => void;\n}\n\nexport interface ChatModelInfo {\n /** Adapter id, e.g. \"openai\". Alphanumeric with - or _. */\n id: string;\n label: string;\n /** Models this adapter serves; the first is the default. */\n models?: { id: string; label?: string }[];\n}\n\nexport interface ChatModel extends ChatModelInfo {\n complete(request: ChatRequest, options?: ChatOptions): Promise<ChatResponse>;\n}\n\n/** An error from a model vendor, carrying its HTTP status when there was one. */\nexport class ChatModelError extends Error {\n constructor(\n readonly provider: string,\n message: string,\n readonly status?: number,\n ) {\n super(`${provider}: ${message}`);\n this.name = \"ChatModelError\";\n }\n}\n\nexport type FetchLike = (url: string, init?: RequestInit) => Promise<Response>;\n\nexport function defaultFetch(): FetchLike {\n if (typeof fetch !== \"function\") throw new Error(\"No global fetch: pass `fetch` explicitly\");\n return (url, init) => fetch(url, init);\n}\n\n/** Check an adapter's shape once, at registration. */\nexport function defineChatModel<M extends ChatModel>(model: M): M {\n if (!model.id || !/^[a-z0-9][a-z0-9_-]*$/i.test(model.id)) {\n throw new Error(`Chat model id must be alphanumeric with - or _ (got \"${model.id}\")`);\n }\n if (typeof model.complete !== \"function\") throw new Error(`Chat model \"${model.id}\" has no complete()`);\n return model;\n}\n","/**\n * OpenAI adapter, over the Chat Completions API with function calling.\n *\n * Chat Completions is also what most other servers speak (Azure OpenAI,\n * OpenRouter, Groq, Together, vLLM, Ollama, LM Studio…), so `baseUrl` points\n * this one adapter at any of them.\n */\nimport {\n ChatModelError,\n defaultFetch,\n defineChatModel,\n type ChatMessage,\n type ChatModel,\n type ChatRequest,\n type ChatResponse,\n type FetchLike,\n type ToolCall,\n} from \"./types.js\";\n\nexport interface OpenAIChatModelOptions {\n /** Model id, e.g. \"gpt-5.4-mini\". Required: model names change faster than this package. */\n model: string;\n /** Other models the app may pick per request (`ChatRequest.model`). */\n models?: { id: string; label?: string }[];\n /** API key. Omit for local servers that don't need one. Keep it server-side (see `createChatHandler`). */\n apiKey?: string;\n /** Default https://api.openai.com/v1. Any OpenAI-compatible base URL works. */\n baseUrl?: string;\n organization?: string;\n project?: string;\n headers?: Record<string, string>;\n /** Default request fields merged into every call (e.g. `{ reasoning_effort: \"low\" }`). */\n params?: Record<string, unknown>;\n /** Stream responses (default true). */\n stream?: boolean;\n /** Adapter id / label (default \"openai\" / \"OpenAI\"), e.g. \"ollama\" when pointing elsewhere. */\n id?: string;\n label?: string;\n fetch?: FetchLike;\n}\n\ntype OpenAIMessage =\n | { role: \"system\" | \"user\"; content: string }\n | { role: \"assistant\"; content: string | null; tool_calls?: { id: string; type: \"function\"; function: { name: string; arguments: string } }[] }\n | { role: \"tool\"; tool_call_id: string; content: string };\n\n/** Neutral messages → Chat Completions messages. */\nexport function toOpenAIMessages(messages: readonly ChatMessage[]): OpenAIMessage[] {\n return messages.map((m): OpenAIMessage => {\n if (m.role === \"assistant\") {\n const out: OpenAIMessage = { role: \"assistant\", content: m.content || null };\n if (m.toolCalls?.length) {\n out.tool_calls = m.toolCalls.map((c) => ({ id: c.id, type: \"function\", function: { name: c.name, arguments: JSON.stringify(c.arguments) } }));\n }\n return out;\n }\n if (m.role === \"tool\") return { role: \"tool\", tool_call_id: m.toolCallId, content: m.content };\n return { role: m.role, content: m.content };\n });\n}\n\n/** Parse a tool call's JSON arguments; unparseable JSON is reported to the model as a tool error. */\nexport function parseToolArguments(raw: string): Record<string, unknown> {\n if (!raw.trim()) return {};\n try {\n const value = JSON.parse(raw) as unknown;\n return value && typeof value === \"object\" && !Array.isArray(value) ? (value as Record<string, unknown>) : { __invalidArguments: raw };\n } catch {\n return { __invalidArguments: raw };\n }\n}\n\nconst FINISH: Record<string, ChatResponse[\"finish\"]> = {\n stop: \"stop\",\n tool_calls: \"tool_calls\",\n function_call: \"tool_calls\",\n length: \"length\",\n content_filter: \"content_filter\",\n};\n\nexport function openAIChatModel(options: OpenAIChatModelOptions): ChatModel {\n const base = (options.baseUrl ?? \"https://api.openai.com/v1\").replace(/\\/+$/, \"\");\n const id = options.id ?? \"openai\";\n const doFetch = options.fetch ?? defaultFetch();\n const stream = options.stream ?? true;\n const models = [{ id: options.model }, ...(options.models ?? []).filter((m) => m.id !== options.model)];\n\n return defineChatModel({\n id,\n label: options.label ?? \"OpenAI\",\n models,\n async complete(request: ChatRequest, opts = {}): Promise<ChatResponse> {\n const body: Record<string, unknown> = {\n model: request.model ?? options.model,\n messages: toOpenAIMessages(request.messages),\n ...(request.tools?.length\n ? { tools: request.tools.map((t) => ({ type: \"function\", function: { name: t.name, description: t.description, parameters: t.inputSchema } })) }\n : {}),\n ...(request.maxOutputTokens ? { max_completion_tokens: request.maxOutputTokens } : {}),\n ...(stream ? { stream: true, stream_options: { include_usage: true } } : {}),\n ...options.params,\n ...request.params,\n };\n const headers: Record<string, string> = { \"Content-Type\": \"application/json\", ...options.headers };\n if (options.apiKey) headers[\"Authorization\"] = `Bearer ${options.apiKey}`;\n if (options.organization) headers[\"OpenAI-Organization\"] = options.organization;\n if (options.project) headers[\"OpenAI-Project\"] = options.project;\n\n const res = await doFetch(`${base}/chat/completions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n ...(opts.signal ? { signal: opts.signal } : {}),\n });\n if (!res.ok) {\n const err = (await res.json().catch(() => null)) as { error?: { message?: string } } | null;\n throw new ChatModelError(id, err?.error?.message ?? `HTTP ${res.status}`, res.status);\n }\n if (!stream || !res.body || !(res.headers.get(\"content-type\") ?? \"\").includes(\"event-stream\")) {\n return fromCompletion(await res.json(), opts.onText);\n }\n return readStream(res.body, opts.onText);\n },\n });\n}\n\ninterface CompletionJson {\n model?: string;\n choices?: { message?: { content?: string | null; tool_calls?: { id: string; function: { name: string; arguments: string } }[] }; finish_reason?: string }[];\n usage?: { prompt_tokens?: number; completion_tokens?: number };\n}\n\nfunction fromCompletion(json: CompletionJson, onText?: (delta: string) => void): ChatResponse {\n const choice = json.choices?.[0];\n const content = choice?.message?.content ?? \"\";\n if (content) onText?.(content);\n const out: ChatResponse = {\n content,\n toolCalls: (choice?.message?.tool_calls ?? []).map((c) => ({ id: c.id, name: c.function.name, arguments: parseToolArguments(c.function.arguments) })),\n finish: FINISH[choice?.finish_reason ?? \"\"] ?? \"other\",\n };\n if (json.model) out.model = json.model;\n if (json.usage) out.usage = usage(json.usage);\n return out;\n}\n\nconst usage = (u: { prompt_tokens?: number; completion_tokens?: number }) => ({\n ...(u.prompt_tokens !== undefined ? { inputTokens: u.prompt_tokens } : {}),\n ...(u.completion_tokens !== undefined ? { outputTokens: u.completion_tokens } : {}),\n});\n\ninterface ChunkJson {\n model?: string;\n choices?: {\n delta?: { content?: string | null; tool_calls?: { index: number; id?: string; function?: { name?: string; arguments?: string } }[] };\n finish_reason?: string | null;\n }[];\n usage?: { prompt_tokens?: number; completion_tokens?: number } | null;\n}\n\n/** Server-sent events → one response; text deltas stream to `onText`, tool-call fragments are joined by index. */\nasync function readStream(body: ReadableStream<Uint8Array>, onText?: (delta: string) => void): Promise<ChatResponse> {\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let content = \"\";\n let finish: ChatResponse[\"finish\"] = \"other\";\n let model: string | undefined;\n let use: ChatResponse[\"usage\"];\n const calls = new Map<number, { id: string; name: string; args: string }>();\n\n const handle = (data: string) => {\n if (data === \"[DONE]\") return;\n let chunk: ChunkJson;\n try {\n chunk = JSON.parse(data) as ChunkJson;\n } catch {\n return;\n }\n if (chunk.model) model = chunk.model;\n if (chunk.usage) use = usage(chunk.usage);\n for (const choice of chunk.choices ?? []) {\n const delta = choice.delta;\n if (delta?.content) {\n content += delta.content;\n onText?.(delta.content);\n }\n for (const tc of delta?.tool_calls ?? []) {\n const call = calls.get(tc.index) ?? { id: \"\", name: \"\", args: \"\" };\n if (tc.id) call.id = tc.id;\n if (tc.function?.name) call.name += tc.function.name;\n if (tc.function?.arguments) call.args += tc.function.arguments;\n calls.set(tc.index, call);\n }\n if (choice.finish_reason) finish = FINISH[choice.finish_reason] ?? \"other\";\n }\n };\n\n for (;;) {\n const { done, value } = await reader.read();\n if (value) buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) >= 0) {\n const line = buffer.slice(0, nl).replace(/\\r$/, \"\");\n buffer = buffer.slice(nl + 1);\n if (line.startsWith(\"data:\")) handle(line.slice(5).trim());\n }\n if (done) break;\n }\n if (buffer.startsWith(\"data:\")) handle(buffer.slice(5).trim());\n\n const toolCalls: ToolCall[] = [...calls.entries()]\n .sort(([a], [b]) => a - b)\n .map(([index, c]) => ({ id: c.id || `call_${index}`, name: c.name, arguments: parseToolArguments(c.args) }));\n const out: ChatResponse = { content, toolCalls, finish };\n if (model) out.model = model;\n if (use) out.usage = use;\n return out;\n}\n","/**\n * Keys stay on the server: run the real model adapter in your backend behind\n * `createChatHandler`, and give the browser `remoteChatModel(endpoint)` — a\n * proxy with the same `ChatModel` shape. The agent loop and the tools run in\n * the browser, next to the project; only model calls cross the network.\n *\n * GET {base}/ → { id, label, models }\n * POST {base}/chat { request: ChatRequest } →\n * application/x-ndjson, one JSON object per line:\n * { \"type\": \"text\", \"delta\": \"…\" } (as it streams)\n * { \"type\": \"done\", \"response\": ChatResponse }\n * { \"type\": \"error\", \"error\": \"…\", \"status\": 401 }\n * errors before streaming → { error } with 400 / 404 / 413, or the vendor's status\n *\n * Fetch-API handler (`Request` → `Response`): mounts in Node 18+, edge\n * runtimes, Next, Hono, Express (via an adapter).\n */\nimport { ChatModelError, defaultFetch, type ChatModel, type ChatRequest, type ChatResponse, type FetchLike } from \"./types.js\";\n\nexport interface ChatHandlerOptions {\n /** Path prefix the handler is mounted at, e.g. \"/api/assistant\". */\n basePath?: string;\n /** Reject request bodies larger than this (default 2 MB). */\n maxBodyBytes?: number;\n /** Return a Response to refuse a request (auth, rate limits); undefined to allow. */\n authorize?: (request: Request) => Promise<Response | undefined> | Response | undefined;\n /** Adjust each request server-side (pin a model, cap tokens, add instructions). */\n prepare?: (request: ChatRequest) => ChatRequest;\n}\n\nexport function createChatHandler(model: ChatModel, options: ChatHandlerOptions = {}) {\n const base = (options.basePath ?? \"\").replace(/\\/+$/, \"\");\n const maxBody = options.maxBodyBytes ?? 2_000_000;\n\n return async function handle(request: Request): Promise<Response | null> {\n const path = new URL(request.url).pathname;\n if (base && path !== base && !path.startsWith(`${base}/`)) return null;\n const rest = path.slice(base.length).replace(/\\/+$/, \"\");\n\n const refused = await options.authorize?.(request);\n if (refused) return refused;\n\n if (rest === \"\" && request.method === \"GET\") {\n return json(200, { id: model.id, label: model.label, models: model.models ?? [] });\n }\n if (rest !== \"/chat\" || request.method !== \"POST\") return json(404, { error: \"not found\" });\n\n const text = await request.text();\n if (text.length > maxBody) return json(413, { error: \"request too large\" });\n let chat: ChatRequest;\n try {\n chat = (JSON.parse(text) as { request: ChatRequest }).request;\n } catch {\n return json(400, { error: \"body must be JSON { request }\" });\n }\n if (!chat || !Array.isArray(chat.messages)) return json(400, { error: \"request.messages is required\" });\n if (options.prepare) chat = options.prepare(chat);\n\n const encoder = new TextEncoder();\n const body = new ReadableStream<Uint8Array>({\n async start(controller) {\n const send = (value: unknown) => controller.enqueue(encoder.encode(`${JSON.stringify(value)}\\n`));\n try {\n const response = await model.complete(chat, { signal: request.signal, onText: (delta) => send({ type: \"text\", delta }) });\n send({ type: \"done\", response });\n } catch (err) {\n const status = (err as { status?: number })?.status;\n send({ type: \"error\", error: (err as Error)?.message ?? String(err), ...(status ? { status } : {}) });\n } finally {\n controller.close();\n }\n },\n });\n return new Response(body, { status: 200, headers: { \"content-type\": \"application/x-ndjson\", \"cache-control\": \"no-store\" } });\n };\n}\n\nconst json = (status: number, body: unknown) => new Response(JSON.stringify(body), { status, headers: { \"content-type\": \"application/json\" } });\n\nexport interface RemoteChatModelOptions {\n fetch?: FetchLike;\n headers?: Record<string, string>;\n /** Skip the GET for model info (id/label/models default to \"remote\"). */\n info?: { id: string; label: string; models?: { id: string; label?: string }[] };\n}\n\n/** The model a backend serves, as a browser-side `ChatModel`. */\nexport async function remoteChatModel(endpoint: string, options: RemoteChatModelOptions = {}): Promise<ChatModel> {\n const doFetch = options.fetch ?? defaultFetch();\n const root = endpoint.replace(/\\/+$/, \"\");\n let info = options.info;\n if (!info) {\n const res = await doFetch(`${root}/`, { headers: { Accept: \"application/json\", ...options.headers } });\n if (!res.ok) throw new ChatModelError(\"remote\", `HTTP ${res.status}`, res.status);\n info = (await res.json()) as NonNullable<RemoteChatModelOptions[\"info\"]>;\n }\n const { id, label, models } = info;\n\n return {\n id,\n label,\n ...(models ? { models } : {}),\n async complete(request, opts = {}): Promise<ChatResponse> {\n const res = await doFetch(`${root}/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", Accept: \"application/x-ndjson\", ...options.headers },\n body: JSON.stringify({ request }),\n ...(opts.signal ? { signal: opts.signal } : {}),\n });\n if (!res.ok || !res.body) {\n const err = (await res.json().catch(() => null)) as { error?: string } | null;\n throw new ChatModelError(id, err?.error ?? `HTTP ${res.status}`, res.status);\n }\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n let final: ChatResponse | undefined;\n const handle = (line: string) => {\n if (!line.trim()) return;\n const event = JSON.parse(line) as { type: string; delta?: string; response?: ChatResponse; error?: string; status?: number };\n if (event.type === \"text\" && event.delta) opts.onText?.(event.delta);\n else if (event.type === \"done\") final = event.response;\n else if (event.type === \"error\") throw new ChatModelError(id, event.error ?? \"failed\", event.status);\n };\n for (;;) {\n const { done, value } = await reader.read();\n if (value) buffer += decoder.decode(value, { stream: true });\n let nl: number;\n while ((nl = buffer.indexOf(\"\\n\")) >= 0) {\n handle(buffer.slice(0, nl));\n buffer = buffer.slice(nl + 1);\n }\n if (done) break;\n }\n handle(buffer);\n if (!final) throw new ChatModelError(id, \"the server closed the stream without a response\");\n return final;\n },\n };\n}\n","import {\n ANIMATION_EASINGS,\n ANIMATION_PRESETS,\n animationCommands,\n applyCommands,\n commandCatalog,\n builtinTransitionParamSchemas,\n describeAnimation,\n describeProject,\n findCuts,\n fitAnimation,\n readAnimation,\n toToolDefinitions,\n type AnimationEasing,\n type AnimationRecipe,\n type AnimationSlot,\n type Command,\n type Cut,\n type Project,\n} from \"@miraiclip/core\";\nimport type { ToolSpec } from \"./types.js\";\n\n/** What a tool's `run` gets. `project` is the turn's working copy. */\nexport interface ToolContext {\n project: Project;\n signal?: AbortSignal;\n}\n\n/** A tool's answer. `changes` are human-readable lines for the app's \"what changed\" list. */\nexport type ToolOutput =\n | { ok: true; result?: unknown; changes?: string[] }\n | { ok: false; error: unknown };\n\nexport interface AssistantTool extends ToolSpec {\n run(input: Record<string, unknown>, ctx: ToolContext): Promise<ToolOutput> | ToolOutput;\n}\n\nexport function defineTool(tool: AssistantTool): AssistantTool {\n if (!/^[a-zA-Z0-9_-]{1,64}$/.test(tool.name)) throw new Error(`Tool name must match ^[a-zA-Z0-9_-]{1,64}$ (got \"${tool.name}\")`);\n return tool;\n}\n\n/**\n * Adopt tools that come as definitions plus one runner — e.g.\n * `@miraiclip/audio-sources`' `audioToolDefinitions` + `runAudioTool`.\n * Accepts `{ name, description, input_schema }` or OpenAI function tools.\n */\nexport function toolsFromDefinitions(\n definitions: readonly unknown[],\n run: (name: string, input: Record<string, unknown>, ctx: ToolContext) => Promise<{ ok: boolean; result?: unknown; error?: unknown }>,\n options: { changes?: (name: string, input: Record<string, unknown>, result: unknown) => string[] | undefined } = {},\n): AssistantTool[] {\n return definitions.map((d) => {\n const def = d as { name?: string; description?: string; input_schema?: Record<string, unknown>; function?: { name: string; description?: string; parameters?: Record<string, unknown> } };\n const name = def.function?.name ?? def.name!;\n return defineTool({\n name,\n description: def.function?.description ?? def.description ?? \"\",\n inputSchema: def.function?.parameters ?? def.input_schema ?? { type: \"object\", properties: {} },\n async run(input, ctx) {\n const out = await run(name, input, ctx);\n if (!out.ok) return { ok: false, error: out.error ?? \"failed\" };\n const changes = options.changes?.(name, input, out.result);\n return { ok: true, result: out.result, ...(changes?.length ? { changes } : {}) };\n },\n });\n });\n}\n\nconst S = 1_000_000;\nconst seconds = (us: number) => `${Math.round(us / 100_000) / 10}s`;\nconst toUs = (s: unknown) => (typeof s === \"number\" && Number.isFinite(s) ? Math.round(s * S) : undefined);\n\n/* ---------- describing commands for people ---------- */\n\nconst PHRASES: Record<string, (p: Record<string, unknown>) => string> = {\n \"clip/add\": (p) =>\n p.kind === \"text\" ? `Added text \"${String(p.text ?? \"\").slice(0, 40)}\" at ${seconds(Number(p.startUs))}` : `Added a ${p.kind} clip at ${seconds(Number(p.startUs))}`,\n \"clip/remove\": (p) => `Removed clip ${p.clipId}`,\n \"clip/move\": (p) => `Moved clip ${p.clipId}${p.startUs !== undefined ? ` to ${seconds(Number(p.startUs))}` : \"\"}`,\n \"clip/trim\": (p) => `Trimmed clip ${p.clipId}`,\n \"clip/split\": (p) => `Split clip ${p.clipId} at ${seconds(Number(p.atUs))}`,\n \"clip/duplicate\": (p) => `Duplicated clip ${p.clipId}`,\n \"clip/set-property\": (p) => `Changed ${Object.keys(p).filter((k) => k !== \"clipId\").join(\", \")} of clip ${p.clipId}`,\n \"track/add\": (p) => `Added a ${p.kind} track`,\n \"track/remove\": (p) => `Removed track ${p.id}`,\n \"track/set-property\": (p) => `Changed track ${p.trackId}: ${Object.keys(p).filter((k) => k !== \"trackId\").join(\", \")}`,\n \"effect/add\": (p) => `Added ${p.kind} to clip ${p.clipId}`,\n \"effect/update\": (p) => `Adjusted an effect on clip ${p.clipId}`,\n \"effect/remove\": (p) => `Removed an effect from clip ${p.clipId}`,\n \"transition/add\": (p) => `Added a ${p.kind} transition`,\n \"transition/remove\": () => \"Removed a transition\",\n \"project/set-settings\": () => \"Changed the project settings\",\n};\n\n/** One line per command, for a \"what changed\" list (keyframe edits fold into one line per clip). */\nexport function describeCommands(commands: readonly Command[]): string[] {\n const lines: string[] = [];\n const keyframed = new Set<string>();\n for (const c of commands) {\n const p = (c.payload ?? {}) as Record<string, unknown>;\n if (c.type.startsWith(\"keyframe/\")) {\n const id = String(p.clipId);\n if (!keyframed.has(id)) lines.push(`Changed the animation of clip ${id}`);\n keyframed.add(id);\n continue;\n }\n const phrase = PHRASES[c.type];\n lines.push(phrase ? phrase(p) : `${c.type}`);\n }\n return lines;\n}\n\n/* ---------- the editor tools ---------- */\n\nconst US_NOTE = \"Times in commands are integer MICROSECONDS (1 s = 1000000).\";\n\nexport interface EditorToolsOptions {\n /** Transition kinds to offer (default: the built-ins). Add your registered custom kinds. */\n transitionKinds?: string[];\n /** The command catalog to offer in apply_commands (default: the built-ins). Pass `project.commandCatalog()` when you register custom commands. */\n commandCatalog?: Record<string, unknown>;\n}\n\n/**\n * The tools that edit a Miraiclip project: read state, look up a command's\n * schema, apply command batches, and two high-level tools (transitions,\n * animation presets) that use the same logic as the editor's panels.\n */\nexport function editorTools(options: EditorToolsOptions = {}): AssistantTool[] {\n const transitionKinds = options.transitionKinds ?? Object.keys(builtinTransitionParamSchemas);\n const presetIds = (slot: AnimationSlot) => ANIMATION_PRESETS.filter((p) => p.slot === slot).map((p) => p.id.split(\":\")[1]!);\n\n return [\n defineTool({\n name: \"get_state\",\n description: `The project as it is now (after your edits so far): settings, assets, tracks with clips (ids, kinds, time ranges), transitions. ${US_NOTE}`,\n inputSchema: {\n type: \"object\",\n properties: { includeJson: { type: \"boolean\", description: \"Also return the full document JSON (verbose; only for exact field values).\" } },\n additionalProperties: false,\n },\n run(input, { project }) {\n const summary = describeProject(project.toJSON());\n return { ok: true, result: input.includeJson ? { summary, document: project.toJSON() } : summary };\n },\n }),\n\n defineTool({\n name: \"get_command_schema\",\n description: \"The JSON Schema of one editing command's payload. Look it up before using a command in apply_commands for the first time.\",\n inputSchema: {\n type: \"object\",\n properties: { type: { type: \"string\", description: 'Command type, e.g. \"clip/add\".' } },\n required: [\"type\"],\n additionalProperties: false,\n },\n run(input, { project }) {\n const catalog = project.commandCatalog();\n const schema = catalog[String(input.type)];\n return schema ? { ok: true, result: schema } : { ok: false, error: { error: `unknown command \"${input.type}\"`, validTypes: Object.keys(catalog).sort() } };\n },\n }),\n\n defineTool({\n name: \"apply_commands\",\n description:\n \"Apply editing commands as one all-or-nothing batch. On failure nothing changes and the error names the failing index and why (invalid payload issues, or the engine's rejection reason) — fix it and retry. \" +\n `Give new clips, tracks and assets your own readable ids. ${US_NOTE}`,\n inputSchema: applyCommandsSchema(options.commandCatalog ?? commandCatalog()),\n run(input, { project }) {\n const commands = input.commands as Command[] | undefined;\n if (!Array.isArray(commands) || commands.length === 0) return { ok: false, error: \"commands must be a non-empty array of { type, payload }\" };\n const result = applyCommands(project, commands);\n if (!result.ok) return { ok: false, error: result };\n return { ok: true, result: { applied: result.applied }, changes: describeCommands(commands) };\n },\n }),\n\n defineTool({\n name: \"add_transition\",\n description:\n \"Add (or replace, or remove) a transition on cuts — where one clip ends exactly where the next starts on the same video track. Pick the cut by its two clip ids, by a time near it, or all cuts. \" +\n \"A transition overlaps both clips around the cut, so its length is capped by the spare footage there; cuts with none are skipped and reported.\",\n inputSchema: {\n type: \"object\",\n properties: {\n kind: { type: \"string\", enum: [...transitionKinds, \"none\"], description: '\"none\" removes the transition.' },\n fromClipId: { type: \"string\", description: \"The clip ending at the cut.\" },\n toClipId: { type: \"string\", description: \"The clip starting at the cut.\" },\n nearSeconds: { type: \"number\", description: \"Pick the cut closest to this time instead.\" },\n allCuts: { type: \"boolean\", description: \"Apply to every cut.\" },\n durationSeconds: { type: \"number\", minimum: 0.1, maximum: 3, description: \"Default 0.6.\" },\n direction: { type: \"string\", enum: [\"left\", \"right\", \"up\", \"down\"], description: \"wipe / slide only.\" },\n },\n required: [\"kind\"],\n additionalProperties: false,\n },\n run(input, { project }) {\n const cuts = findCuts(project.getState().doc);\n if (cuts.length === 0) return { ok: false, error: \"There are no cuts: transitions need two clips touching on the same video track.\" };\n let targets: Cut[];\n if (input.allCuts === true) targets = cuts;\n else if (typeof input.fromClipId === \"string\" || typeof input.toClipId === \"string\") {\n targets = cuts.filter((c) => (!input.fromClipId || c.fromClipId === input.fromClipId) && (!input.toClipId || c.toClipId === input.toClipId));\n } else {\n const at = toUs(input.nearSeconds) ?? project.getState().playheadUs;\n targets = [cuts.reduce((a, b) => (Math.abs(b.atUs - at) < Math.abs(a.atUs - at) ? b : a))];\n }\n if (targets.length === 0) return { ok: false, error: { error: \"no cut matches\", cuts: cuts.map(cutInfo) } };\n const kind = String(input.kind);\n const wanted = toUs(input.durationSeconds) ?? 600_000;\n const commands: Command[] = [];\n const changes: string[] = [];\n const skipped: unknown[] = [];\n for (const cut of targets) {\n if (cut.transition) commands.push({ type: \"transition/remove\", payload: { transitionId: cut.transition.id } });\n if (kind === \"none\") {\n if (cut.transition) changes.push(`Removed the transition at ${seconds(cut.atUs)}`);\n continue;\n }\n const durationUs = Math.min(wanted, cut.maxTransitionUs);\n if (durationUs < 100_000) {\n skipped.push({ ...cutInfo(cut), reason: `no spare footage (${cut.short === \"from\" ? \"the first clip ends where its media ends\" : cut.short === \"to\" ? \"the second clip starts at its media's start\" : \"both clips use all their media\"})` });\n if (cut.transition) commands.pop();\n continue;\n }\n const params = input.direction && (kind === \"wipe\" || kind === \"slide\") ? { direction: input.direction } : undefined;\n commands.push({ type: \"transition/add\", payload: { kind, fromClipId: cut.fromClipId, toClipId: cut.toClipId, durationUs, ...(params ? { params } : {}) } });\n changes.push(`${cut.transition ? \"Replaced the transition with\" : \"Added\"} ${kind} at ${seconds(cut.atUs)} (${seconds(durationUs)})`);\n }\n if (commands.length) {\n const result = applyCommands(project, commands);\n if (!result.ok) return { ok: false, error: result };\n }\n return { ok: true, result: { changed: changes.length, skipped }, changes };\n },\n }),\n\n defineTool({\n name: \"animate_clip\",\n description:\n \"Give a visual clip (video, image, text) an entrance (in), a loop while on screen, and/or an exit (out), as keyframes. Slots you leave out keep their current animation; \\\"none\\\" removes one; reset:true removes all. \" +\n `In/out presets: ${presetIds(\"in\").join(\", \")}. Loops: ${presetIds(\"loop\").join(\", \")}. Exits stay on the clip's end through trims.`,\n inputSchema: {\n type: \"object\",\n properties: {\n clipId: { type: \"string\" },\n in: { type: \"string\", enum: [...presetIds(\"in\"), \"none\"] },\n loop: { type: \"string\", enum: [...presetIds(\"loop\"), \"none\"] },\n out: { type: \"string\", enum: [...presetIds(\"out\"), \"none\"] },\n inSeconds: { type: \"number\", minimum: 0.2, maximum: 3, description: \"Default 0.6.\" },\n outSeconds: { type: \"number\", minimum: 0.2, maximum: 3, description: \"Default 0.6.\" },\n easing: { type: \"string\", enum: ANIMATION_EASINGS.map((e) => e.id), description: \"Default smooth.\" },\n reset: { type: \"boolean\" },\n },\n required: [\"clipId\"],\n additionalProperties: false,\n },\n run(input, { project }) {\n const clip = project.getState().doc.clips[String(input.clipId)];\n if (!clip) return { ok: false, error: `no clip \"${input.clipId}\"` };\n if (clip.kind === \"audio\") return { ok: false, error: \"audio clips have no picture to animate (use volume or fades)\" };\n const current = input.reset === true ? {} : readAnimation(clip).recipe;\n const next: AnimationRecipe = { ...current };\n const easing = (typeof input.easing === \"string\" ? input.easing : \"smooth\") as AnimationEasing;\n for (const slot of [\"in\", \"loop\", \"out\"] as const) {\n const name = input[slot];\n if (name === undefined) continue;\n if (name === \"none\") {\n delete next[slot];\n continue;\n }\n const durationUs = slot === \"loop\" ? 0 : toUs(input[slot === \"in\" ? \"inSeconds\" : \"outSeconds\"]) ?? current[slot]?.durationUs ?? 600_000;\n next[slot] = { preset: `${slot}:${name}`, durationUs, easing: slot === \"loop\" ? \"linear\" : easing };\n }\n const recipe = fitAnimation(next, clip.durationUs);\n const result = applyCommands(project, animationCommands(clip, recipe));\n if (!result.ok) return { ok: false, error: result };\n const summary = describeAnimation(recipe) || \"no animation\";\n return { ok: true, result: { clipId: clip.id, animation: summary }, changes: [`${clip.id}: ${summary}`] };\n },\n }),\n ];\n}\n\nfunction cutInfo(c: Cut) {\n return { fromClipId: c.fromClipId, toClipId: c.toClipId, atSeconds: c.atUs / S, maxSeconds: c.maxTransitionUs / S, ...(c.transition ? { transition: c.transition.kind } : {}) };\n}\n\n/** apply_commands' input schema: `type` is an enum of the catalog's commands. */\nexport function applyCommandsSchema(catalog: Record<string, unknown>): Record<string, unknown> {\n const [dispatch] = toToolDefinitions(catalog, { mode: \"dispatch\" }) as { input_schema: Record<string, unknown> }[];\n return {\n type: \"object\",\n properties: {\n commands: { type: \"array\", minItems: 1, items: dispatch!.input_schema, description: \"Commands applied in order, as one batch.\" },\n },\n required: [\"commands\"],\n additionalProperties: false,\n };\n}\n","import { createProject, type Command, type Project } from \"@miraiclip/core\";\n\n/**\n * A working copy of a project that records every command that sticks.\n *\n * The assistant edits the copy while the model thinks (async, many steps);\n * the real project only changes when the turn commits, by replaying the\n * recorded commands in one transaction — one undo step, and nothing half-done\n * if the request fails. Commands inside a transaction that rolls back are\n * dropped, exactly as the copy drops their effects.\n *\n * Replay must produce the same ids the model saw, so commands whose ids are\n * optional get explicit ones before they run.\n */\nexport interface RecordingProject extends Project {\n /** Commands that changed the copy, in order. */\n readonly recorded: readonly Command[];\n}\n\nexport interface ForkOptions {\n /** Build the copy (default: `createProject(doc)`). Register custom commands here. */\n createFork?: (doc: ReturnType<Project[\"toJSON\"]>) => Project;\n /** Give commands explicit ids (default handles the built-ins with optional ids). */\n ensureIds?: (command: Command) => Command;\n}\n\nlet seq = 0;\nconst genId = (prefix: string) => `${prefix}-${Date.now().toString(36)}${(++seq).toString(36)}${Math.random().toString(36).slice(2, 6)}`;\n\n/** Built-in commands that would otherwise get a random id inside the engine. */\nexport function withExplicitIds(command: Command): Command {\n const p = (command.payload ?? {}) as Record<string, unknown>;\n const set = (field: string, prefix: string) =>\n p[field] === undefined ? { ...command, payload: { ...p, [field]: genId(prefix) } } : command;\n switch (command.type) {\n case \"clip/split\":\n case \"clip/duplicate\":\n return set(\"newClipId\", \"clip\");\n case \"effect/add\":\n return set(\"effectId\", \"fx\");\n case \"transition/add\":\n return set(\"id\", \"tr\");\n default:\n return command;\n }\n}\n\nexport function forkProject(project: Project, options: ForkOptions = {}): RecordingProject {\n const fork = (options.createFork ?? ((doc) => createProject(doc)))(project.toJSON());\n const state = project.getState();\n fork.setPlayhead(state.playheadUs);\n fork.setSelection([...state.selection]);\n const ensure = options.ensureIds ?? withExplicitIds;\n const recorded: Command[] = [];\n let depth = 0;\n let buffer: Command[] = [];\n\n return {\n ...fork,\n get recorded() {\n return recorded;\n },\n dispatch(command) {\n const explicit = ensure(command as Command);\n const before = fork.getState().doc;\n fork.dispatch(explicit);\n if (fork.getState().doc === before) return; // no-op: nothing to replay\n if (depth > 0) buffer.push(explicit);\n else recorded.push(explicit);\n },\n transaction(fn, label) {\n if (depth > 0) {\n fn();\n return;\n }\n depth = 1;\n buffer = [];\n try {\n fork.transaction(fn, label);\n recorded.push(...buffer);\n } finally {\n depth = 0;\n buffer = [];\n }\n },\n };\n}\n\nexport type CommitResult = { ok: true; applied: number } | { ok: false; error: string };\n\n/** Replay a fork's commands onto the real project as one undoable step. */\nexport function commitFork(project: Project, fork: RecordingProject, label?: string): CommitResult {\n if (fork.recorded.length === 0) return { ok: true, applied: 0 };\n try {\n project.transaction(() => {\n for (const command of fork.recorded) project.dispatch(command);\n }, label);\n return { ok: true, applied: fork.recorded.length };\n } catch (err) {\n return {\n ok: false,\n error: `The project changed while the assistant was working, so its edit no longer applies (${(err as Error)?.message ?? err}). Ask again.`,\n };\n }\n}\n","import { describeProject, type Command, type Project, type ProjectDocument } from \"@miraiclip/core\";\nimport { commitFork, forkProject, type CommitResult, type ForkOptions } from \"./fork.js\";\nimport { editorTools, type AssistantTool } from \"./tools.js\";\nimport type { ChatMessage, ChatModel, ChatUsage, ToolCall } from \"./types.js\";\n\nexport interface AssistantOptions {\n model: ChatModel;\n /** Default `editorTools()`. Add your own (audio, captions, stock media…). */\n tools?: AssistantTool[];\n /** Extra system instructions (brand voice, house rules). */\n instructions?: string;\n /** Model round-trips per request (default 12). */\n maxSteps?: number;\n /** Model id when the adapter serves several. */\n modelId?: string;\n maxOutputTokens?: number;\n /** Vendor request fields, passed through. */\n params?: Record<string, unknown>;\n fork?: ForkOptions;\n}\n\nexport type AssistantEvent =\n | { type: \"text\"; delta: string }\n | { type: \"tool-start\"; call: ToolCall }\n | { type: \"tool-end\"; call: ToolCall; ok: boolean; changes?: string[]; error?: string }\n | { type: \"step\"; index: number };\n\nexport interface TurnOptions {\n /** Earlier messages of this conversation (`turn.messages` from the last turn). */\n history?: readonly ChatMessage[];\n /** What the user is looking at, e.g. \"Selected: clip t-1. Playhead: 4.2s.\" */\n context?: string;\n /** \"auto\" (default) commits when the request finishes; \"review\" waits for `turn.apply()`. */\n apply?: \"auto\" | \"review\";\n signal?: AbortSignal;\n onEvent?: (event: AssistantEvent) => void;\n /** History label for the undo step (default \"Assistant: <request>\"). */\n label?: string;\n}\n\nexport interface AssistantTurn {\n /** The model's final answer to the user. */\n reply: string;\n /** Human-readable list of what the turn changed (empty when nothing). */\n changes: string[];\n /** The commands the turn makes, in order (replayed onto the project on apply). */\n commands: readonly Command[];\n /**\n * applied: committed as one undo step. review: waiting for apply()/discard().\n * no-changes: nothing to apply. failed / canceled: the project wasn't touched.\n */\n status: \"applied\" | \"review\" | \"no-changes\" | \"failed\" | \"canceled\";\n error?: string;\n /** The project as the turn left it (for previews in review mode). */\n preview: ProjectDocument;\n /** The conversation so far, without the system prompt: pass back as `history`. */\n messages: ChatMessage[];\n usage: Required<ChatUsage>;\n /** Commit a reviewed turn (no-op once applied). */\n apply(): CommitResult;\n discard(): void;\n}\n\nexport interface Assistant {\n readonly tools: readonly AssistantTool[];\n run(project: Project, request: string, options?: TurnOptions): Promise<AssistantTurn>;\n}\n\nconst MAX_TOOL_RESULT = 20_000;\nconst MAX_OLD_TOOL_RESULT = 2_000;\n\nexport const DEFAULT_INSTRUCTIONS = `You are the editing assistant inside a video editor. You change the user's project by calling tools; every change you make lands as ONE undo step when you finish, so act confidently.\n\nHow to work:\n- The current project is summarized below. Clip, track and asset ids there are what tools expect. Call get_state to re-read it after big changes.\n- Prefer the high-level tools when they fit (add_transition, animate_clip, and any audio or media tools). Use apply_commands for everything else, batching related commands; look up a command's payload with get_command_schema the first time you use it.\n- Commands use integer microseconds (1 second = 1000000). High-level tools take seconds.\n- Positions (transform x, y) are fractions of the frame: 0.5, 0.5 is the center.\n- Only reference media that exists in the project or that a tool returned. Never invent file URLs.\n- If a tool fails, read the error, fix the input and retry. If something can't be done, say why.\n- If the request is ambiguous in a way that matters, ask one short question instead of guessing.\n\nWhen you're done, reply in one to three short sentences: what you changed, in plain words (times in seconds, names over ids). No markdown headings.`;\n\nexport function createAssistant(options: AssistantOptions): Assistant {\n const tools = options.tools ?? editorTools();\n const byName = new Map(tools.map((t) => [t.name, t]));\n const specs = tools.map(({ name, description, inputSchema }) => ({ name, description, inputSchema }));\n const maxSteps = options.maxSteps ?? 12;\n\n return {\n tools,\n async run(project, request, turn = {}) {\n const fork = forkProject(project, options.fork);\n const emit = turn.onEvent ?? (() => {});\n const usage = { inputTokens: 0, outputTokens: 0 };\n const changes: string[] = [];\n const history = trimHistory(turn.history ?? []);\n const added: ChatMessage[] = [{ role: \"user\", content: request }];\n const system = [\n DEFAULT_INSTRUCTIONS,\n options.instructions?.trim(),\n `Current project:\\n${describeProject(fork.toJSON())}`,\n turn.context?.trim() ? `What the user is looking at: ${turn.context.trim()}` : undefined,\n ]\n .filter(Boolean)\n .join(\"\\n\\n\");\n\n let reply = \"\";\n let status: AssistantTurn[\"status\"] = \"no-changes\";\n let error: string | undefined;\n\n try {\n for (let step = 0; ; step++) {\n if (step >= maxSteps) {\n reply = (reply ? `${reply}\\n\\n` : \"\") + `I stopped after ${maxSteps} steps; what I finished is applied. Ask me to continue if there's more.`;\n break;\n }\n emit({ type: \"step\", index: step });\n const response = await options.model.complete(\n {\n messages: [{ role: \"system\", content: system }, ...history, ...added],\n tools: specs,\n ...(options.modelId ? { model: options.modelId } : {}),\n ...(options.maxOutputTokens ? { maxOutputTokens: options.maxOutputTokens } : {}),\n ...(options.params ? { params: options.params } : {}),\n },\n { ...(turn.signal ? { signal: turn.signal } : {}), onText: (delta) => emit({ type: \"text\", delta }) },\n );\n usage.inputTokens += response.usage?.inputTokens ?? 0;\n usage.outputTokens += response.usage?.outputTokens ?? 0;\n added.push({ role: \"assistant\", content: response.content, ...(response.toolCalls.length ? { toolCalls: response.toolCalls } : {}) });\n if (response.toolCalls.length === 0) {\n reply = response.content.trim();\n break;\n }\n for (const call of response.toolCalls) {\n if (turn.signal?.aborted) throw abortError();\n emit({ type: \"tool-start\", call });\n const out = await runTool(byName.get(call.name), call, fork, turn.signal);\n if (out.ok && out.changes?.length) changes.push(...out.changes);\n emit({\n type: \"tool-end\",\n call,\n ok: out.ok,\n ...(out.ok && out.changes?.length ? { changes: out.changes } : {}),\n ...(!out.ok ? { error: short(out.error) } : {}),\n });\n added.push({ role: \"tool\", toolCallId: call.id, name: call.name, content: cap(out.ok ? out.result ?? { ok: true } : { ok: false, error: out.error }, MAX_TOOL_RESULT) });\n }\n }\n status = fork.recorded.length === 0 ? \"no-changes\" : turn.apply === \"review\" ? \"review\" : \"applied\";\n } catch (err) {\n status = turn.signal?.aborted || (err as Error)?.name === \"AbortError\" ? \"canceled\" : \"failed\";\n error = (err as Error)?.message ?? String(err);\n }\n\n let committed = false;\n let discarded = false;\n const label = turn.label ?? `Assistant: ${request.length > 40 ? `${request.slice(0, 39)}…` : request}`;\n const apply = (): CommitResult => {\n if (committed) return { ok: true, applied: 0 };\n if (discarded) return { ok: false, error: \"This edit was discarded.\" };\n if (status === \"failed\" || status === \"canceled\") return { ok: false, error: error ?? status };\n const result = commitFork(project, fork, label);\n if (result.ok) committed = true;\n return result;\n };\n if (status === \"applied\") {\n const result = apply();\n if (!result.ok) {\n status = \"failed\";\n error = result.error;\n }\n }\n\n return {\n reply,\n changes,\n commands: fork.recorded,\n status,\n ...(error !== undefined ? { error } : {}),\n preview: fork.toJSON(),\n messages: [...history, ...added],\n usage,\n apply,\n discard() {\n if (!committed) discarded = true;\n },\n };\n },\n };\n}\n\nasync function runTool(tool: AssistantTool | undefined, call: ToolCall, project: Project, signal?: AbortSignal) {\n if (!tool) return { ok: false as const, error: `unknown tool \"${call.name}\"` };\n if (\"__invalidArguments\" in call.arguments) return { ok: false as const, error: \"the tool arguments weren't valid JSON; send a JSON object\" };\n try {\n return await tool.run(call.arguments, { project, ...(signal ? { signal } : {}) });\n } catch (err) {\n if ((err as Error)?.name === \"AbortError\") throw err;\n return { ok: false as const, error: (err as Error)?.message ?? String(err) };\n }\n}\n\nfunction cap(value: unknown, max: number): string {\n const text = typeof value === \"string\" ? value : JSON.stringify(value);\n return text.length > max ? `${text.slice(0, max)}… [truncated ${text.length - max} chars]` : text;\n}\n\nconst short = (e: unknown) => {\n const text = typeof e === \"string\" ? e : JSON.stringify(e);\n return text.length > 300 ? `${text.slice(0, 299)}…` : text;\n};\n\n/**\n * Earlier turns keep their shape but not their bulky tool output. A turn cut\n * short (canceled, failed) can leave tool calls without results, which\n * vendors reject: those get a \"not run\" result.\n */\nfunction trimHistory(history: readonly ChatMessage[]): ChatMessage[] {\n const answered = new Set(history.flatMap((m) => (m.role === \"tool\" ? [m.toolCallId] : [])));\n const out: ChatMessage[] = [];\n for (const m of history) {\n if (m.role === \"system\") continue;\n if (m.role === \"tool\") {\n out.push(m.content.length > MAX_OLD_TOOL_RESULT ? { ...m, content: `${m.content.slice(0, MAX_OLD_TOOL_RESULT)}… [truncated]` } : m);\n continue;\n }\n out.push(m);\n if (m.role === \"assistant\") {\n for (const call of m.toolCalls ?? []) {\n if (!answered.has(call.id)) out.push({ role: \"tool\", toolCallId: call.id, name: call.name, content: '{\"ok\":false,\"error\":\"not run: the request was interrupted\"}' });\n }\n }\n }\n return out;\n}\n\nfunction abortError() {\n const err = new Error(\"canceled\");\n err.name = \"AbortError\";\n return err;\n}\n","import { defineChatModel, type ChatModel, type ChatRequest, type ChatResponse, type ToolCall } from \"./types.js\";\n\nexport type ScriptStep =\n | string\n | { text?: string; toolCalls?: (Omit<ToolCall, \"id\"> & { id?: string })[] }\n | ((request: ChatRequest, index: number) => ScriptStep);\n\n/**\n * A model that answers from a script: for tests, demos and offline\n * development. Each `complete` call takes the next step; a string is a final\n * text answer, an object can call tools. Requests are kept in `requests`.\n */\nexport function scriptedChatModel(steps: ScriptStep[], options: { id?: string } = {}): ChatModel & { requests: ChatRequest[] } {\n const requests: ChatRequest[] = [];\n let i = 0;\n const model = defineChatModel({\n id: options.id ?? \"scripted\",\n label: \"Scripted model\",\n async complete(request: ChatRequest, opts: { onText?: (delta: string) => void } = {}): Promise<ChatResponse> {\n requests.push(structuredClone(request));\n let step: ScriptStep = steps[Math.min(i, steps.length - 1)] ?? \"Done.\";\n while (typeof step === \"function\") step = step(request, i);\n i++;\n const s = typeof step === \"string\" ? { text: step } : step;\n if (s.text) opts.onText?.(s.text);\n const toolCalls = (s.toolCalls ?? []).map((c, n) => ({ id: c.id ?? `call_${i}_${n}`, name: c.name, arguments: c.arguments }));\n return { content: s.text ?? \"\", toolCalls, finish: toolCalls.length ? \"tool_calls\" : \"stop\", usage: { inputTokens: 10, outputTokens: 5 } };\n },\n });\n return Object.assign(model, { requests });\n}\n"],"mappings":"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","names":["json","describeProject","usage","describeProject"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@miraiclip/assistant",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "An AI editing assistant for Miraiclip: a vendor-neutral ChatModel contract (OpenAI first; any OpenAI-compatible server works), an agent loop that edits a forked project and lands each request as one undo step, high-level editing tools, and a server handler that keeps API keys off the browser.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/comaniacs/miraiclip.git",
|
|
9
|
+
"directory": "packages/assistant"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://comaniacs.github.io/miraiclip/",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/comaniacs/miraiclip/issues"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./dist/index.d.cts",
|
|
27
|
+
"default": "./dist/index.cjs"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"@miraiclip/core": "^0.5.5"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsup": "^8.5.1",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"vitest": "^3.2.4",
|
|
45
|
+
"@miraiclip/core": "0.5.5"
|
|
46
|
+
},
|
|
47
|
+
"keywords": [
|
|
48
|
+
"video",
|
|
49
|
+
"video-editor",
|
|
50
|
+
"ai",
|
|
51
|
+
"assistant",
|
|
52
|
+
"agent",
|
|
53
|
+
"llm",
|
|
54
|
+
"openai",
|
|
55
|
+
"tool-calling",
|
|
56
|
+
"function-calling"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "tsup",
|
|
60
|
+
"test": "vitest run",
|
|
61
|
+
"typecheck": "tsc --noEmit"
|
|
62
|
+
}
|
|
63
|
+
}
|