@miraiclip/assistant 0.1.0 → 0.1.2

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/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { Project, Command, ProjectDocument } from '@miraiclip/core';
1
+ import { ProjectDocument, Project, Command } from '@miraiclip/core';
2
2
 
3
3
  /**
4
4
  * The vendor-neutral model contract. An adapter turns these neutral messages
@@ -109,6 +109,12 @@ interface OpenAIChatModelOptions {
109
109
  params?: Record<string, unknown>;
110
110
  /** Stream responses (default true). */
111
111
  stream?: boolean;
112
+ /**
113
+ * Retries on rate limits (429) and server errors (500/502/503/504), waiting
114
+ * as long as the server asks (Retry-After, or "try again in 1.2s"), else
115
+ * backing off 1 s, 2 s, 4 s… (capped at 30 s). Default 4; 0 disables.
116
+ */
117
+ maxRetries?: number;
112
118
  /** Adapter id / label (default "openai" / "OpenAI"), e.g. "ollama" when pointing elsewhere. */
113
119
  id?: string;
114
120
  label?: string;
@@ -137,6 +143,8 @@ type OpenAIMessage = {
137
143
  declare function toOpenAIMessages(messages: readonly ChatMessage[]): OpenAIMessage[];
138
144
  /** Parse a tool call's JSON arguments; unparseable JSON is reported to the model as a tool error. */
139
145
  declare function parseToolArguments(raw: string): Record<string, unknown>;
146
+ /** How long the server asked us to wait (Retry-After header, or "try again in 1.2s / 350ms"), else exponential backoff. */
147
+ declare function retryDelayMs(res: Pick<Response, "headers">, message: string, attempt: number): number;
140
148
  declare function openAIChatModel(options: OpenAIChatModelOptions): ChatModel;
141
149
 
142
150
  /**
@@ -184,6 +192,38 @@ interface RemoteChatModelOptions {
184
192
  /** The model a backend serves, as a browser-side `ChatModel`. */
185
193
  declare function remoteChatModel(endpoint: string, options?: RemoteChatModelOptions): Promise<ChatModel>;
186
194
 
195
+ interface RateLimitOptions {
196
+ /** Tokens per rolling minute across every caller of this model (input + output). */
197
+ tokensPerMinute?: number;
198
+ /** Requests per rolling minute. */
199
+ requestsPerMinute?: number;
200
+ /** Token estimate for a request before it's sent (default: JSON length ÷ 4, plus room for the reply). */
201
+ estimate?: (request: ChatRequest) => number;
202
+ }
203
+ /**
204
+ * Wrap a model so calls wait for room under your provider's per-minute
205
+ * limits instead of failing with 429s — for batch jobs (evals, bulk edits)
206
+ * and for a server sharing one key. Each call reserves an estimate, which is
207
+ * replaced by the real usage when the response reports it.
208
+ */
209
+ declare function rateLimitedChatModel(model: ChatModel, options: RateLimitOptions): ChatModel;
210
+
211
+ /**
212
+ * The project as the model sees it: core's `describeProject`, plus what a
213
+ * model needs to make RELATIVE edits ("bigger", "louder", "keep the
214
+ * entrance") — track names, every clip's position, size and opacity, text
215
+ * styling, volume, effects and its animation recipe.
216
+ */
217
+ declare function describeForAssistant(doc: ProjectDocument): string;
218
+
219
+ interface UnknownFields {
220
+ unknown: string[];
221
+ /** The fields the command does take (for the error message). */
222
+ allowed: string[];
223
+ }
224
+ /** Unknown payload fields for a command, judged against the best-matching schema branch. */
225
+ declare function unknownFields(schema: unknown, payload: unknown): UnknownFields | null;
226
+
187
227
  /** What a tool's `run` gets. `project` is the turn's working copy. */
188
228
  interface ToolContext {
189
229
  project: Project;
@@ -214,6 +254,8 @@ declare function toolsFromDefinitions(definitions: readonly unknown[], run: (nam
214
254
  }>, options?: {
215
255
  changes?: (name: string, input: Record<string, unknown>, result: unknown) => string[] | undefined;
216
256
  }): AssistantTool[];
257
+ /** The html template set_background uses: one `{{color}}` fill. */
258
+ declare const BACKGROUND_TEMPLATE = "<div style=\"width:100%;height:100%;background:{{color}}\"></div>";
217
259
  /** One line per command, for a "what changed" list (keyframe edits fold into one line per clip). */
218
260
  declare function describeCommands(commands: readonly Command[]): string[];
219
261
  interface EditorToolsOptions {
@@ -228,6 +270,13 @@ interface EditorToolsOptions {
228
270
  * animation presets) that use the same logic as the editor's panels.
229
271
  */
230
272
  declare function editorTools(options?: EditorToolsOptions): AssistantTool[];
273
+ /**
274
+ * Apply a batch as one all-or-nothing step, with two checks core doesn't do:
275
+ * fields a command would silently ignore are errors, and commands that
276
+ * changed nothing are reported, so the model never claims an edit that didn't
277
+ * happen.
278
+ */
279
+ declare function applyChecked(project: Project, commands: Command[]): ToolOutput;
231
280
  /** apply_commands' input schema: `type` is an enum of the catalog's commands. */
232
281
  declare function applyCommandsSchema(catalog: Record<string, unknown>): Record<string, unknown>;
233
282
 
@@ -335,7 +384,7 @@ interface Assistant {
335
384
  readonly tools: readonly AssistantTool[];
336
385
  run(project: Project, request: string, options?: TurnOptions): Promise<AssistantTurn>;
337
386
  }
338
- declare 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.";
387
+ declare 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, add_effect, set_effects_enabled, set_background, trim_clip, set_keyframes, close_gaps, and any audio or media tools). Call tools directly; apply_commands takes only editing commands like \"clip/add\", never tool names. 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, and use only the fields it lists.\n- Fading a picture (text, image, logo, video) in or out is animate_clip (in / out: fade). fadeInUs / fadeOutUs are audio fades. \"Fade the video in at the start / out at the end\" means the first clip's entrance and the last clip's exit.\n- Constant values are set directly with clip/set-property: rotation (\"rotate 45\u00B0\", \"tilt\"), volume (\"lower to 30%\", \"louder\"), position, size, opacity. Only values that CHANGE over a time range (\"duck the music between 10 and 15 s\", \"fade to silence between 18 and 20 s\", \"spin one full turn\", \"pan across\") are keyframes: set_keyframes, with times in timeline seconds. Remove an animation with keyframe/clear.\n- \"Cuts\" are the ones listed in the project summary; use their times (e.g. one sound per cut).\n- \"Add N more seconds of footage\" adds a new clip (clip/add with trimStartUs for the source point) after the last one; it does not stretch an existing clip.\n- Caption looks (box behind the text, outline, shadow, colors, word preset) are the caption clip's style (clip/set-property { style }).\n- \"The whole video\" means from 0 to the composition length (trim_clip startSeconds / endSeconds).\n- A solid color background behind everything is set_background (add, recolor, remove). Other html clips are recolored through the params their template uses (shown in the clip details). A new track goes on top unless track/add gets index 0 (the bottom).\n- \"Replace X with Y\" removes X and adds Y in the same turn, whichever tool adds Y (audio tools take replaceClipId, which does both).\n- Solo / mute / lock / hide a track with track/set-property (solo, muted, locked, hidden). \"Solo X\" is solo: true on X, not muting the others.\n- Relative requests (\"bigger\", \"louder\", \"a bit brighter\", \"twice as big\") start from the current values in the clip details below: make a visible change in the asked direction (about 25% for \"bigger\"/\"smaller\", \u00D72 for \"twice\").\n- When something is selected, \"this\", \"it\", \"the clip\" and any request that names no target mean ONLY the selection, even with words like \"at the end\" (the end of that clip). Edit nothing else. \"Here\" / \"now\" / \"this point\" mean the playhead. \"Clips\" without a kind mean the video clips on the main video track.\n- \"Again\" / \"also\" / \"another\" mean keep the original and add a copy (clip/duplicate, or clip/add with the same asset); never move the original. \"Instead\" means move or replace.\n- Removing a clip leaves a gap; when asked to close it, also run close_gaps (or trim_clip with ripple).\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. A failed apply_commands batch applied NONE of its commands: resend all of them, corrected. 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). Describe only edits your tools reported as applied; if a tool says something changed nothing or failed, fix it or say so. No markdown headings.";
339
388
  declare function createAssistant(options: AssistantOptions): Assistant;
340
389
 
341
390
  type ScriptStep = string | {
@@ -355,4 +404,4 @@ declare function scriptedChatModel(steps: ScriptStep[], options?: {
355
404
  requests: ChatRequest[];
356
405
  };
357
406
 
358
- export { type Assistant, type AssistantEvent, type AssistantOptions, type AssistantTool, type AssistantTurn, type ChatHandlerOptions, type ChatMessage, type ChatModel, ChatModelError, type ChatModelInfo, type ChatOptions, type ChatRequest, type ChatResponse, type ChatUsage, type CommitResult, DEFAULT_INSTRUCTIONS, type EditorToolsOptions, type FetchLike, type ForkOptions, type OpenAIChatModelOptions, type RecordingProject, type RemoteChatModelOptions, type ScriptStep, type ToolCall, type ToolContext, type ToolOutput, type ToolSpec, type TurnOptions, applyCommandsSchema, commitFork, createAssistant, createChatHandler, defineChatModel, defineTool, describeCommands, editorTools, forkProject, openAIChatModel, parseToolArguments, remoteChatModel, scriptedChatModel, toOpenAIMessages, toolsFromDefinitions, withExplicitIds };
407
+ export { type Assistant, type AssistantEvent, type AssistantOptions, type AssistantTool, type AssistantTurn, BACKGROUND_TEMPLATE, type ChatHandlerOptions, type ChatMessage, type ChatModel, ChatModelError, type ChatModelInfo, type ChatOptions, type ChatRequest, type ChatResponse, type ChatUsage, type CommitResult, DEFAULT_INSTRUCTIONS, type EditorToolsOptions, type FetchLike, type ForkOptions, type OpenAIChatModelOptions, type RateLimitOptions, type RecordingProject, type RemoteChatModelOptions, type ScriptStep, type ToolCall, type ToolContext, type ToolOutput, type ToolSpec, type TurnOptions, type UnknownFields, applyChecked, applyCommandsSchema, commitFork, createAssistant, createChatHandler, defineChatModel, defineTool, describeCommands, describeForAssistant, editorTools, forkProject, openAIChatModel, parseToolArguments, rateLimitedChatModel, remoteChatModel, retryDelayMs, scriptedChatModel, toOpenAIMessages, toolsFromDefinitions, unknownFields, withExplicitIds };
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Project, Command, ProjectDocument } from '@miraiclip/core';
1
+ import { ProjectDocument, Project, Command } from '@miraiclip/core';
2
2
 
3
3
  /**
4
4
  * The vendor-neutral model contract. An adapter turns these neutral messages
@@ -109,6 +109,12 @@ interface OpenAIChatModelOptions {
109
109
  params?: Record<string, unknown>;
110
110
  /** Stream responses (default true). */
111
111
  stream?: boolean;
112
+ /**
113
+ * Retries on rate limits (429) and server errors (500/502/503/504), waiting
114
+ * as long as the server asks (Retry-After, or "try again in 1.2s"), else
115
+ * backing off 1 s, 2 s, 4 s… (capped at 30 s). Default 4; 0 disables.
116
+ */
117
+ maxRetries?: number;
112
118
  /** Adapter id / label (default "openai" / "OpenAI"), e.g. "ollama" when pointing elsewhere. */
113
119
  id?: string;
114
120
  label?: string;
@@ -137,6 +143,8 @@ type OpenAIMessage = {
137
143
  declare function toOpenAIMessages(messages: readonly ChatMessage[]): OpenAIMessage[];
138
144
  /** Parse a tool call's JSON arguments; unparseable JSON is reported to the model as a tool error. */
139
145
  declare function parseToolArguments(raw: string): Record<string, unknown>;
146
+ /** How long the server asked us to wait (Retry-After header, or "try again in 1.2s / 350ms"), else exponential backoff. */
147
+ declare function retryDelayMs(res: Pick<Response, "headers">, message: string, attempt: number): number;
140
148
  declare function openAIChatModel(options: OpenAIChatModelOptions): ChatModel;
141
149
 
142
150
  /**
@@ -184,6 +192,38 @@ interface RemoteChatModelOptions {
184
192
  /** The model a backend serves, as a browser-side `ChatModel`. */
185
193
  declare function remoteChatModel(endpoint: string, options?: RemoteChatModelOptions): Promise<ChatModel>;
186
194
 
195
+ interface RateLimitOptions {
196
+ /** Tokens per rolling minute across every caller of this model (input + output). */
197
+ tokensPerMinute?: number;
198
+ /** Requests per rolling minute. */
199
+ requestsPerMinute?: number;
200
+ /** Token estimate for a request before it's sent (default: JSON length ÷ 4, plus room for the reply). */
201
+ estimate?: (request: ChatRequest) => number;
202
+ }
203
+ /**
204
+ * Wrap a model so calls wait for room under your provider's per-minute
205
+ * limits instead of failing with 429s — for batch jobs (evals, bulk edits)
206
+ * and for a server sharing one key. Each call reserves an estimate, which is
207
+ * replaced by the real usage when the response reports it.
208
+ */
209
+ declare function rateLimitedChatModel(model: ChatModel, options: RateLimitOptions): ChatModel;
210
+
211
+ /**
212
+ * The project as the model sees it: core's `describeProject`, plus what a
213
+ * model needs to make RELATIVE edits ("bigger", "louder", "keep the
214
+ * entrance") — track names, every clip's position, size and opacity, text
215
+ * styling, volume, effects and its animation recipe.
216
+ */
217
+ declare function describeForAssistant(doc: ProjectDocument): string;
218
+
219
+ interface UnknownFields {
220
+ unknown: string[];
221
+ /** The fields the command does take (for the error message). */
222
+ allowed: string[];
223
+ }
224
+ /** Unknown payload fields for a command, judged against the best-matching schema branch. */
225
+ declare function unknownFields(schema: unknown, payload: unknown): UnknownFields | null;
226
+
187
227
  /** What a tool's `run` gets. `project` is the turn's working copy. */
188
228
  interface ToolContext {
189
229
  project: Project;
@@ -214,6 +254,8 @@ declare function toolsFromDefinitions(definitions: readonly unknown[], run: (nam
214
254
  }>, options?: {
215
255
  changes?: (name: string, input: Record<string, unknown>, result: unknown) => string[] | undefined;
216
256
  }): AssistantTool[];
257
+ /** The html template set_background uses: one `{{color}}` fill. */
258
+ declare const BACKGROUND_TEMPLATE = "<div style=\"width:100%;height:100%;background:{{color}}\"></div>";
217
259
  /** One line per command, for a "what changed" list (keyframe edits fold into one line per clip). */
218
260
  declare function describeCommands(commands: readonly Command[]): string[];
219
261
  interface EditorToolsOptions {
@@ -228,6 +270,13 @@ interface EditorToolsOptions {
228
270
  * animation presets) that use the same logic as the editor's panels.
229
271
  */
230
272
  declare function editorTools(options?: EditorToolsOptions): AssistantTool[];
273
+ /**
274
+ * Apply a batch as one all-or-nothing step, with two checks core doesn't do:
275
+ * fields a command would silently ignore are errors, and commands that
276
+ * changed nothing are reported, so the model never claims an edit that didn't
277
+ * happen.
278
+ */
279
+ declare function applyChecked(project: Project, commands: Command[]): ToolOutput;
231
280
  /** apply_commands' input schema: `type` is an enum of the catalog's commands. */
232
281
  declare function applyCommandsSchema(catalog: Record<string, unknown>): Record<string, unknown>;
233
282
 
@@ -335,7 +384,7 @@ interface Assistant {
335
384
  readonly tools: readonly AssistantTool[];
336
385
  run(project: Project, request: string, options?: TurnOptions): Promise<AssistantTurn>;
337
386
  }
338
- declare 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.";
387
+ declare 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, add_effect, set_effects_enabled, set_background, trim_clip, set_keyframes, close_gaps, and any audio or media tools). Call tools directly; apply_commands takes only editing commands like \"clip/add\", never tool names. 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, and use only the fields it lists.\n- Fading a picture (text, image, logo, video) in or out is animate_clip (in / out: fade). fadeInUs / fadeOutUs are audio fades. \"Fade the video in at the start / out at the end\" means the first clip's entrance and the last clip's exit.\n- Constant values are set directly with clip/set-property: rotation (\"rotate 45\u00B0\", \"tilt\"), volume (\"lower to 30%\", \"louder\"), position, size, opacity. Only values that CHANGE over a time range (\"duck the music between 10 and 15 s\", \"fade to silence between 18 and 20 s\", \"spin one full turn\", \"pan across\") are keyframes: set_keyframes, with times in timeline seconds. Remove an animation with keyframe/clear.\n- \"Cuts\" are the ones listed in the project summary; use their times (e.g. one sound per cut).\n- \"Add N more seconds of footage\" adds a new clip (clip/add with trimStartUs for the source point) after the last one; it does not stretch an existing clip.\n- Caption looks (box behind the text, outline, shadow, colors, word preset) are the caption clip's style (clip/set-property { style }).\n- \"The whole video\" means from 0 to the composition length (trim_clip startSeconds / endSeconds).\n- A solid color background behind everything is set_background (add, recolor, remove). Other html clips are recolored through the params their template uses (shown in the clip details). A new track goes on top unless track/add gets index 0 (the bottom).\n- \"Replace X with Y\" removes X and adds Y in the same turn, whichever tool adds Y (audio tools take replaceClipId, which does both).\n- Solo / mute / lock / hide a track with track/set-property (solo, muted, locked, hidden). \"Solo X\" is solo: true on X, not muting the others.\n- Relative requests (\"bigger\", \"louder\", \"a bit brighter\", \"twice as big\") start from the current values in the clip details below: make a visible change in the asked direction (about 25% for \"bigger\"/\"smaller\", \u00D72 for \"twice\").\n- When something is selected, \"this\", \"it\", \"the clip\" and any request that names no target mean ONLY the selection, even with words like \"at the end\" (the end of that clip). Edit nothing else. \"Here\" / \"now\" / \"this point\" mean the playhead. \"Clips\" without a kind mean the video clips on the main video track.\n- \"Again\" / \"also\" / \"another\" mean keep the original and add a copy (clip/duplicate, or clip/add with the same asset); never move the original. \"Instead\" means move or replace.\n- Removing a clip leaves a gap; when asked to close it, also run close_gaps (or trim_clip with ripple).\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. A failed apply_commands batch applied NONE of its commands: resend all of them, corrected. 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). Describe only edits your tools reported as applied; if a tool says something changed nothing or failed, fix it or say so. No markdown headings.";
339
388
  declare function createAssistant(options: AssistantOptions): Assistant;
340
389
 
341
390
  type ScriptStep = string | {
@@ -355,4 +404,4 @@ declare function scriptedChatModel(steps: ScriptStep[], options?: {
355
404
  requests: ChatRequest[];
356
405
  };
357
406
 
358
- export { type Assistant, type AssistantEvent, type AssistantOptions, type AssistantTool, type AssistantTurn, type ChatHandlerOptions, type ChatMessage, type ChatModel, ChatModelError, type ChatModelInfo, type ChatOptions, type ChatRequest, type ChatResponse, type ChatUsage, type CommitResult, DEFAULT_INSTRUCTIONS, type EditorToolsOptions, type FetchLike, type ForkOptions, type OpenAIChatModelOptions, type RecordingProject, type RemoteChatModelOptions, type ScriptStep, type ToolCall, type ToolContext, type ToolOutput, type ToolSpec, type TurnOptions, applyCommandsSchema, commitFork, createAssistant, createChatHandler, defineChatModel, defineTool, describeCommands, editorTools, forkProject, openAIChatModel, parseToolArguments, remoteChatModel, scriptedChatModel, toOpenAIMessages, toolsFromDefinitions, withExplicitIds };
407
+ export { type Assistant, type AssistantEvent, type AssistantOptions, type AssistantTool, type AssistantTurn, BACKGROUND_TEMPLATE, type ChatHandlerOptions, type ChatMessage, type ChatModel, ChatModelError, type ChatModelInfo, type ChatOptions, type ChatRequest, type ChatResponse, type ChatUsage, type CommitResult, DEFAULT_INSTRUCTIONS, type EditorToolsOptions, type FetchLike, type ForkOptions, type OpenAIChatModelOptions, type RateLimitOptions, type RecordingProject, type RemoteChatModelOptions, type ScriptStep, type ToolCall, type ToolContext, type ToolOutput, type ToolSpec, type TurnOptions, type UnknownFields, applyChecked, applyCommandsSchema, commitFork, createAssistant, createChatHandler, defineChatModel, defineTool, describeCommands, describeForAssistant, editorTools, forkProject, openAIChatModel, parseToolArguments, rateLimitedChatModel, remoteChatModel, retryDelayMs, scriptedChatModel, toOpenAIMessages, toolsFromDefinitions, unknownFields, withExplicitIds };