@intentface/latch-core 0.9.1 → 0.11.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/agent.d.ts +17 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js.map +1 -1
- package/dist/extensions/compose.d.ts +117 -0
- package/dist/extensions/compose.d.ts.map +1 -0
- package/dist/extensions/compose.js +249 -0
- package/dist/extensions/compose.js.map +1 -0
- package/dist/extensions/extension.d.ts +322 -0
- package/dist/extensions/extension.d.ts.map +1 -0
- package/dist/extensions/extension.js +171 -0
- package/dist/extensions/extension.js.map +1 -0
- package/dist/extensions/index.d.ts +11 -0
- package/dist/extensions/index.d.ts.map +1 -0
- package/dist/extensions/index.js +11 -0
- package/dist/extensions/index.js.map +1 -0
- package/dist/extensions/tools.d.ts +60 -0
- package/dist/extensions/tools.d.ts.map +1 -0
- package/dist/extensions/tools.js +229 -0
- package/dist/extensions/tools.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime.d.ts +10 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +400 -44
- package/dist/runtime.js.map +1 -1
- package/dist/storage.d.ts +19 -0
- package/dist/storage.d.ts.map +1 -1
- package/dist/telemetry.d.ts +6 -0
- package/dist/telemetry.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/extensions.d.ts +0 -333
- package/dist/extensions.d.ts.map +0 -1
- package/dist/extensions.js +0 -569
- package/dist/extensions.js.map +0 -1
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extension.ts — the extension model.
|
|
3
|
+
*
|
|
4
|
+
* An extension attaches handlers to MOMENTS of a turn. A handler returns an
|
|
5
|
+
* EFFECT, never a rewritten world; `undefined` means no effect. The effect type
|
|
6
|
+
* for each moment says exactly what is possible there, so you cannot do
|
|
7
|
+
* everything everywhere, and several extensions on one moment compose by a
|
|
8
|
+
* rule declared once per moment (see `compose.ts`).
|
|
9
|
+
*
|
|
10
|
+
* WHAT PERSISTS. The stored `UIMessage[]` is the only durable thing; everything
|
|
11
|
+
* else is recomputed each step. Three moments change it:
|
|
12
|
+
*
|
|
13
|
+
* before_agent_start injects or replaces messages
|
|
14
|
+
* step_end appends parts (append-only; never rewrites)
|
|
15
|
+
* tool_result the override IS the stored result, and what the model reads
|
|
16
|
+
*
|
|
17
|
+
* The rest are lenses and vanish after the step:
|
|
18
|
+
*
|
|
19
|
+
* instructions, context what the MODEL sees
|
|
20
|
+
* render what the CUSTOMER sees, live AND on load
|
|
21
|
+
*
|
|
22
|
+
* So: mask a secret in `tool_result` and it is gone everywhere (usually right).
|
|
23
|
+
* Use `render` only for the rarer case where the model should keep the truth
|
|
24
|
+
* and the person should not see it.
|
|
25
|
+
*
|
|
26
|
+
* Ported from `experiment/agents-sdk`, where the same model ran 118/119 of its
|
|
27
|
+
* suite over a plain `streamText` loop — the moments do not depend on who owns
|
|
28
|
+
* the loop, which is why they can sit over `ToolLoopAgent` here.
|
|
29
|
+
*/
|
|
30
|
+
import type { Instructions, LanguageModel, ModelMessage, ToolSet, UIMessage, UIMessagePart } from "ai";
|
|
31
|
+
/**
|
|
32
|
+
* Who a run is for, as an extension sees it. EMPTY on purpose, and augmented by
|
|
33
|
+
* the application:
|
|
34
|
+
*
|
|
35
|
+
* declare module "@intentface/latch-core" {
|
|
36
|
+
* interface Principal { orgId: string; userId: string }
|
|
37
|
+
* }
|
|
38
|
+
*
|
|
39
|
+
* Augmentation rather than a `<P>` type parameter, because a parameter has to
|
|
40
|
+
* be repeated at every declaration that touches it — the runtime's own `<P>`
|
|
41
|
+
* already rides on twenty-odd exported symbols, and every moment type would
|
|
42
|
+
* inherit the noise. One `declare module` gives the same type safety with no
|
|
43
|
+
* generics in any handler signature. The trade is one principal shape per
|
|
44
|
+
* process, which is what an application has anyway. The runtime hands its `P`
|
|
45
|
+
* through as this type; the two describe the same object.
|
|
46
|
+
*
|
|
47
|
+
* The framework never reads a field of this. Isolation is enforced wherever
|
|
48
|
+
* the principal is USED — the storage owner key, a connection lookup.
|
|
49
|
+
*
|
|
50
|
+
* CONTRACT: principals are persisted with a run and replayed on resume or a
|
|
51
|
+
* scheduled fire, possibly months later. Durable identifiers only: no secrets
|
|
52
|
+
* or tokens, no PII beyond ids, nothing volatile like roles or flags.
|
|
53
|
+
*/
|
|
54
|
+
export interface Principal {
|
|
55
|
+
}
|
|
56
|
+
/** What is known before the first step: no step number yet, no messages of its own. */
|
|
57
|
+
export interface RunContext {
|
|
58
|
+
runId: string;
|
|
59
|
+
principal: Principal;
|
|
60
|
+
}
|
|
61
|
+
export interface StepContext extends RunContext {
|
|
62
|
+
stepNumber: number;
|
|
63
|
+
/** The stored messages at this step. */
|
|
64
|
+
messages: UIMessage[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Token counts for one step. The cache split is carried separately because
|
|
68
|
+
* cached input is billed at a fraction of the normal rate, so a cost extension
|
|
69
|
+
* that only sees `inputTokens` overcharges every cached turn.
|
|
70
|
+
*/
|
|
71
|
+
export interface StepUsage {
|
|
72
|
+
inputTokens?: number;
|
|
73
|
+
outputTokens?: number;
|
|
74
|
+
totalTokens?: number;
|
|
75
|
+
/** Cached input tokens read. Billed at a discount by most providers. */
|
|
76
|
+
cacheReadTokens?: number;
|
|
77
|
+
/** Input tokens written to the cache. Usually billed at a premium. */
|
|
78
|
+
cacheWriteTokens?: number;
|
|
79
|
+
reasoningTokens?: number;
|
|
80
|
+
}
|
|
81
|
+
/** What a completed step cost and how it ended. The basis for evals and budgets. */
|
|
82
|
+
export interface StepInfo extends StepContext {
|
|
83
|
+
usage: StepUsage;
|
|
84
|
+
finishReason: string;
|
|
85
|
+
model: {
|
|
86
|
+
provider: string;
|
|
87
|
+
modelId: string;
|
|
88
|
+
};
|
|
89
|
+
durationMs: number;
|
|
90
|
+
toolCalls: Array<{
|
|
91
|
+
toolName: string;
|
|
92
|
+
toolCallId: string;
|
|
93
|
+
}>;
|
|
94
|
+
}
|
|
95
|
+
export type Part = UIMessagePart<any, any>;
|
|
96
|
+
/**
|
|
97
|
+
* `replace` is how a store says "ignore what the client sent, this is the
|
|
98
|
+
* truth". `inject` adds a message WITHOUT disturbing the response anchor: it
|
|
99
|
+
* lands immediately before the final message, so a synthetic message can never
|
|
100
|
+
* become the assistant message the run streams into. See `compose.messagesIn`.
|
|
101
|
+
*/
|
|
102
|
+
export type StartEffect = {
|
|
103
|
+
inject?: UIMessage;
|
|
104
|
+
} | {
|
|
105
|
+
replace?: UIMessage[];
|
|
106
|
+
} | undefined | void;
|
|
107
|
+
/** Append-only: nothing can rewrite the past. History only grows. */
|
|
108
|
+
export type StepEffect = {
|
|
109
|
+
append?: Part[];
|
|
110
|
+
} | undefined | void;
|
|
111
|
+
/**
|
|
112
|
+
* `append` adds a paragraph of text. `replace` hands over the whole
|
|
113
|
+
* `Instructions` value, which may be a `SystemModelMessage[]` carrying
|
|
114
|
+
* `providerOptions` — that is how prompt-cache breakpoints are set on the
|
|
115
|
+
* system prompt, so this deliberately is NOT narrowed to `string`.
|
|
116
|
+
*/
|
|
117
|
+
export type InstructionsEffect = {
|
|
118
|
+
append?: string;
|
|
119
|
+
} | {
|
|
120
|
+
replace?: Instructions;
|
|
121
|
+
} | undefined | void;
|
|
122
|
+
export type ContextEffect = {
|
|
123
|
+
messages?: ModelMessage[];
|
|
124
|
+
} | undefined | void;
|
|
125
|
+
/** One rule over a part, applied to the live stream AND to stored messages on load. */
|
|
126
|
+
export type ViewEffect = {
|
|
127
|
+
hide?: true;
|
|
128
|
+
} | {
|
|
129
|
+
replace?: Part;
|
|
130
|
+
} | undefined | void;
|
|
131
|
+
export type ToolCallEffect = {
|
|
132
|
+
block?: true;
|
|
133
|
+
reason?: string;
|
|
134
|
+
} | undefined | void;
|
|
135
|
+
export type ToolResultEffect = {
|
|
136
|
+
output?: unknown;
|
|
137
|
+
isError?: boolean;
|
|
138
|
+
} | undefined | void;
|
|
139
|
+
/**
|
|
140
|
+
* `transform` rewrites the text before the run starts. `handled` skips the
|
|
141
|
+
* model entirely — `reply` becomes the assistant's answer, so the conversation
|
|
142
|
+
* still reads normally.
|
|
143
|
+
*
|
|
144
|
+
* `replace` exists because a command that answers directly may also need to
|
|
145
|
+
* rewrite what came before (`/compact` is the case); deciding the reply and
|
|
146
|
+
* the rewrite in one place keeps them from disagreeing about whether anything
|
|
147
|
+
* happened.
|
|
148
|
+
*/
|
|
149
|
+
export type InputEffect = {
|
|
150
|
+
transform?: string;
|
|
151
|
+
} | {
|
|
152
|
+
handled: true;
|
|
153
|
+
reply?: string | Part[];
|
|
154
|
+
replace?: UIMessage[];
|
|
155
|
+
} | undefined | void;
|
|
156
|
+
/**
|
|
157
|
+
* Before each model call. `stop` ends the run before this step; `model` and
|
|
158
|
+
* `activeTools` apply to this step only.
|
|
159
|
+
*/
|
|
160
|
+
export type StepControlEffect = {
|
|
161
|
+
stop?: true;
|
|
162
|
+
model?: LanguageModel;
|
|
163
|
+
activeTools?: string[];
|
|
164
|
+
} | undefined | void;
|
|
165
|
+
/**
|
|
166
|
+
* EVERY moment receives identity. That is the point of carrying the principal
|
|
167
|
+
* on the turn rather than letting each extension close over one: a per-tenant
|
|
168
|
+
* toolset, a per-tenant veto, a per-tenant redaction rule and per-tenant error
|
|
169
|
+
* reporting all read the SAME principal, so two extensions cannot disagree
|
|
170
|
+
* about who a run is for.
|
|
171
|
+
*
|
|
172
|
+
* It arrives as a trailing `run` argument, which existing handlers may ignore:
|
|
173
|
+
* a function with fewer parameters stays assignable.
|
|
174
|
+
*/
|
|
175
|
+
export interface Hooks {
|
|
176
|
+
/** User text arrived, before anything runs. Earliest per-message moment. */
|
|
177
|
+
input?: Array<(info: {
|
|
178
|
+
text: string;
|
|
179
|
+
source: "user" | "extension";
|
|
180
|
+
messages: UIMessage[];
|
|
181
|
+
}, run: RunContext) => InputEffect | Promise<InputEffect>>;
|
|
182
|
+
/** First run of a conversation (no assistant message yet). Before before_agent_start. */
|
|
183
|
+
session_start?: Array<(messages: UIMessage[], run: RunContext) => StartEffect | Promise<StartEffect>>;
|
|
184
|
+
/**
|
|
185
|
+
* Every run, before the first step. Receives identity as well as messages: a
|
|
186
|
+
* store has to know who a chat belongs to at CLAIM time, not at the first
|
|
187
|
+
* step, or a scheduled run has nothing to rebuild the principal from.
|
|
188
|
+
*/
|
|
189
|
+
before_agent_start?: Array<(messages: UIMessage[], run: RunContext) => StartEffect | Promise<StartEffect>>;
|
|
190
|
+
step_end?: Array<(messages: UIMessage[], info: StepInfo) => StepEffect | Promise<StepEffect>>;
|
|
191
|
+
instructions?: Array<(current: Instructions | undefined, ctx: StepContext) => InstructionsEffect | Promise<InstructionsEffect>>;
|
|
192
|
+
context?: Array<(messages: ModelMessage[], ctx: StepContext) => ContextEffect | Promise<ContextEffect>>;
|
|
193
|
+
/**
|
|
194
|
+
* Identity is OPTIONAL here alone, because `renderTranscript` runs on a load
|
|
195
|
+
* route where no run exists. Pass it when the caller knows it, which an
|
|
196
|
+
* authenticated route does.
|
|
197
|
+
*/
|
|
198
|
+
render?: Array<(part: Part, ctx: {
|
|
199
|
+
stored: boolean;
|
|
200
|
+
} & Partial<RunContext>) => ViewEffect>;
|
|
201
|
+
register_tools?: Array<(tools: ToolSet, run: RunContext) => ToolSet>;
|
|
202
|
+
tool_call?: Array<(info: {
|
|
203
|
+
toolName: string;
|
|
204
|
+
toolCallId: string;
|
|
205
|
+
input: unknown;
|
|
206
|
+
}, run: RunContext) => ToolCallEffect | Promise<ToolCallEffect>>;
|
|
207
|
+
tool_result?: Array<(info: {
|
|
208
|
+
toolName: string;
|
|
209
|
+
toolCallId: string;
|
|
210
|
+
input: unknown;
|
|
211
|
+
output: unknown;
|
|
212
|
+
isError: boolean;
|
|
213
|
+
source: "server" | "client";
|
|
214
|
+
}, run: RunContext) => ToolResultEffect | Promise<ToolResultEffect>>;
|
|
215
|
+
step_start?: Array<(ctx: StepContext) => StepControlEffect | Promise<StepControlEffect>>;
|
|
216
|
+
/** The run failed. Fires before agent_end, which still fires. */
|
|
217
|
+
error?: Array<(info: {
|
|
218
|
+
error: unknown;
|
|
219
|
+
stepNumber: number;
|
|
220
|
+
messages: UIMessage[];
|
|
221
|
+
}, run: RunContext) => void | Promise<void>>;
|
|
222
|
+
agent_end?: Array<(info: {
|
|
223
|
+
runId: string;
|
|
224
|
+
principal: Principal;
|
|
225
|
+
messages: UIMessage[];
|
|
226
|
+
stepCount: number;
|
|
227
|
+
isAborted: boolean;
|
|
228
|
+
error?: unknown;
|
|
229
|
+
usage: StepUsage;
|
|
230
|
+
}) => void | Promise<void>>;
|
|
231
|
+
}
|
|
232
|
+
export type Moment = keyof Hooks;
|
|
233
|
+
/** What a command answers with: text, parts, or parts plus a rewritten history. */
|
|
234
|
+
export type CommandReply = string | Part[] | {
|
|
235
|
+
reply?: string | Part[];
|
|
236
|
+
replace?: UIMessage[];
|
|
237
|
+
};
|
|
238
|
+
export interface CommandOptions {
|
|
239
|
+
description: string;
|
|
240
|
+
/**
|
|
241
|
+
* Answer directly, no model call.
|
|
242
|
+
*
|
|
243
|
+
* `ctx.messages` is the FULL stored conversation, because commands run after
|
|
244
|
+
* the start moments — a client that posts only its newest turn does not
|
|
245
|
+
* shrink what a command can see.
|
|
246
|
+
*/
|
|
247
|
+
handler?: (args: string, ctx: {
|
|
248
|
+
messages: UIMessage[];
|
|
249
|
+
}) => CommandReply | Promise<CommandReply>;
|
|
250
|
+
/** Or rewrite the user's text and let the run proceed. */
|
|
251
|
+
expand?: (args: string) => string | Promise<string>;
|
|
252
|
+
}
|
|
253
|
+
export interface RegisteredCommand extends CommandOptions {
|
|
254
|
+
name: string;
|
|
255
|
+
extension: string;
|
|
256
|
+
}
|
|
257
|
+
export interface Extension {
|
|
258
|
+
name: string;
|
|
259
|
+
hooks: Hooks;
|
|
260
|
+
commands: RegisteredCommand[];
|
|
261
|
+
/**
|
|
262
|
+
* Fail CLOSED. A throwing handler on a critical extension fails the run
|
|
263
|
+
* instead of being reported and skipped.
|
|
264
|
+
*
|
|
265
|
+
* Default is false, because one broken feature must never break the loop.
|
|
266
|
+
* But that rule is wrong for anything the run's correctness depends on: a
|
|
267
|
+
* persistence extension whose database is down has NOT "produced no effect",
|
|
268
|
+
* it has lost the step. Mark those critical.
|
|
269
|
+
*/
|
|
270
|
+
critical?: boolean;
|
|
271
|
+
}
|
|
272
|
+
/** What the client needs to render a command palette. */
|
|
273
|
+
export declare const listCommands: (extensions: Extension[]) => Array<{
|
|
274
|
+
name: string;
|
|
275
|
+
description: string;
|
|
276
|
+
extension: string;
|
|
277
|
+
}>;
|
|
278
|
+
export interface ContextOptions {
|
|
279
|
+
/** 'step' every call · 'run' once per request (default) · 'session' once per conversation, stored */
|
|
280
|
+
scope?: "step" | "run" | "session";
|
|
281
|
+
/** 'before-user' (default) prepends to the latest user message · 'system' appends to instructions */
|
|
282
|
+
position?: "before-user" | "system";
|
|
283
|
+
}
|
|
284
|
+
type Handler<K extends Moment> = NonNullable<Hooks[K]>[number];
|
|
285
|
+
export interface ExtensionAPI {
|
|
286
|
+
/** Attach a handler to a moment. Several handlers on one moment run in order. */
|
|
287
|
+
on<K extends Moment>(moment: K, handler: Handler<K>): void;
|
|
288
|
+
/** Add a tool the model can call. */
|
|
289
|
+
registerTool(name: string, definition: ToolSet[string]): void;
|
|
290
|
+
/**
|
|
291
|
+
* A slash command. Sugar over `on('input', …)`: matches `/name …` and passes
|
|
292
|
+
* the rest as args. Return text from `handler` to answer without calling the
|
|
293
|
+
* model, or a string from `expand` to rewrite the prompt and let it run.
|
|
294
|
+
*/
|
|
295
|
+
registerCommand(name: string, options: CommandOptions): void;
|
|
296
|
+
/**
|
|
297
|
+
* Change what the CUSTOMER sees, live and on load, without touching storage
|
|
298
|
+
* or the model's view. To hide a value from everyone, use `tool_result`.
|
|
299
|
+
*/
|
|
300
|
+
registerRenderer(fn: Handler<"render">): void;
|
|
301
|
+
/**
|
|
302
|
+
* Intent: give the model information. Assembles the moments for you. The
|
|
303
|
+
* provider sees the transcript and the run — `run.principal` is how a
|
|
304
|
+
* per-tenant context is derived.
|
|
305
|
+
*/
|
|
306
|
+
context(provider: (ctx: {
|
|
307
|
+
messages: UIMessage[];
|
|
308
|
+
run: RunContext;
|
|
309
|
+
}) => string | undefined | Promise<string | undefined>, options?: ContextOptions): void;
|
|
310
|
+
/** Intent: tell the customer something. The model never sees it. */
|
|
311
|
+
notify(provider: (info: StepInfo) => string | undefined | Promise<string | undefined>): void;
|
|
312
|
+
}
|
|
313
|
+
/** A conversation has not started while nothing has been said back. */
|
|
314
|
+
export declare const isNewSession: (messages: UIMessage[]) => boolean;
|
|
315
|
+
export interface DefineExtensionOptions {
|
|
316
|
+
/** See `Extension.critical`. */
|
|
317
|
+
critical?: boolean;
|
|
318
|
+
}
|
|
319
|
+
export declare function defineExtension(name: string, setup: (ext: ExtensionAPI) => void, options?: DefineExtensionOptions): Extension;
|
|
320
|
+
export declare function defineExtension(name: string, setup: (ext: ExtensionAPI) => Promise<void>, options?: DefineExtensionOptions): Promise<Extension>;
|
|
321
|
+
export {};
|
|
322
|
+
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../../src/extensions/extension.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extension.ts — the extension model.
|
|
3
|
+
*
|
|
4
|
+
* An extension attaches handlers to MOMENTS of a turn. A handler returns an
|
|
5
|
+
* EFFECT, never a rewritten world; `undefined` means no effect. The effect type
|
|
6
|
+
* for each moment says exactly what is possible there, so you cannot do
|
|
7
|
+
* everything everywhere, and several extensions on one moment compose by a
|
|
8
|
+
* rule declared once per moment (see `compose.ts`).
|
|
9
|
+
*
|
|
10
|
+
* WHAT PERSISTS. The stored `UIMessage[]` is the only durable thing; everything
|
|
11
|
+
* else is recomputed each step. Three moments change it:
|
|
12
|
+
*
|
|
13
|
+
* before_agent_start injects or replaces messages
|
|
14
|
+
* step_end appends parts (append-only; never rewrites)
|
|
15
|
+
* tool_result the override IS the stored result, and what the model reads
|
|
16
|
+
*
|
|
17
|
+
* The rest are lenses and vanish after the step:
|
|
18
|
+
*
|
|
19
|
+
* instructions, context what the MODEL sees
|
|
20
|
+
* render what the CUSTOMER sees, live AND on load
|
|
21
|
+
*
|
|
22
|
+
* So: mask a secret in `tool_result` and it is gone everywhere (usually right).
|
|
23
|
+
* Use `render` only for the rarer case where the model should keep the truth
|
|
24
|
+
* and the person should not see it.
|
|
25
|
+
*
|
|
26
|
+
* Ported from `experiment/agents-sdk`, where the same model ran 118/119 of its
|
|
27
|
+
* suite over a plain `streamText` loop — the moments do not depend on who owns
|
|
28
|
+
* the loop, which is why they can sit over `ToolLoopAgent` here.
|
|
29
|
+
*/
|
|
30
|
+
/** What the client needs to render a command palette. */
|
|
31
|
+
export const listCommands = (extensions) => extensions.flatMap((e) => e.commands.map((c) => ({ name: c.name, description: c.description, extension: c.extension })));
|
|
32
|
+
/** A conversation has not started while nothing has been said back. */
|
|
33
|
+
export const isNewSession = (messages) => !messages.some((m) => m.role === "assistant");
|
|
34
|
+
export function defineExtension(name, setup, options = {}) {
|
|
35
|
+
const hooks = {};
|
|
36
|
+
const on = (k, fn) => {
|
|
37
|
+
(hooks[k] ??= []).push(fn);
|
|
38
|
+
};
|
|
39
|
+
const registered = {};
|
|
40
|
+
const commands = [];
|
|
41
|
+
const api = {
|
|
42
|
+
on,
|
|
43
|
+
registerTool: (n, d) => {
|
|
44
|
+
registered[n] = d;
|
|
45
|
+
},
|
|
46
|
+
registerCommand: (cmdName, opts) => {
|
|
47
|
+
// Caught here, at registration, rather than as a throw the moment a user
|
|
48
|
+
// types the command — which a non-critical extension would swallow,
|
|
49
|
+
// sending the raw `/name` to the model as if nothing had matched.
|
|
50
|
+
if (!opts.handler && !opts.expand)
|
|
51
|
+
throw new Error(`Command "/${cmdName}" on extension "${name}" needs a handler or an expand.`);
|
|
52
|
+
commands.push({ ...opts, name: cmdName, extension: name });
|
|
53
|
+
on("input", async ({ text, messages }) => {
|
|
54
|
+
if (text !== `/${cmdName}` && !text.startsWith(`/${cmdName} `))
|
|
55
|
+
return;
|
|
56
|
+
const args = text.slice(cmdName.length + 1).trim();
|
|
57
|
+
if (opts.expand)
|
|
58
|
+
return { transform: await opts.expand(args) };
|
|
59
|
+
const answer = await opts.handler(args, { messages });
|
|
60
|
+
if (typeof answer === "string" || Array.isArray(answer))
|
|
61
|
+
return { handled: true, reply: answer };
|
|
62
|
+
return { handled: true, reply: answer.reply, replace: answer.replace };
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
registerRenderer: (fn) => on("render", fn),
|
|
66
|
+
context(provider, { scope = "run", position = "before-user" } = {}) {
|
|
67
|
+
const type = `data-ctx-${name}`;
|
|
68
|
+
const place = (m, text) => {
|
|
69
|
+
const i = m.map((x) => x.role).lastIndexOf("user");
|
|
70
|
+
if (i < 0)
|
|
71
|
+
return;
|
|
72
|
+
const u = m[i];
|
|
73
|
+
const content = typeof u.content === "string" ? [{ type: "text", text: u.content }] : u.content;
|
|
74
|
+
return {
|
|
75
|
+
messages: [
|
|
76
|
+
...m.slice(0, i),
|
|
77
|
+
{ ...u, content: [{ type: "text", text }, ...content] },
|
|
78
|
+
...m.slice(i + 1),
|
|
79
|
+
],
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
const find = (msgs) => {
|
|
83
|
+
for (const m of msgs)
|
|
84
|
+
for (const p of m.parts)
|
|
85
|
+
if (p.type === type)
|
|
86
|
+
return String(p.data);
|
|
87
|
+
return undefined;
|
|
88
|
+
};
|
|
89
|
+
if (scope === "session") {
|
|
90
|
+
on("before_agent_start", async (msgs, run) => {
|
|
91
|
+
if (find(msgs))
|
|
92
|
+
return;
|
|
93
|
+
const text = await provider({ messages: msgs, run });
|
|
94
|
+
if (text == null)
|
|
95
|
+
return;
|
|
96
|
+
// Injected BEFORE the final message by `compose.messagesIn`, so this
|
|
97
|
+
// never becomes the assistant message the run streams into.
|
|
98
|
+
return {
|
|
99
|
+
inject: {
|
|
100
|
+
id: crypto.randomUUID(),
|
|
101
|
+
role: "assistant",
|
|
102
|
+
parts: [{ type, data: text }],
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
});
|
|
106
|
+
on("render", (p) => (p.type === type ? { hide: true } : undefined));
|
|
107
|
+
if (position === "system")
|
|
108
|
+
on("instructions", (_, ctx) => {
|
|
109
|
+
const t = find(ctx.messages);
|
|
110
|
+
return t ? { append: t } : undefined;
|
|
111
|
+
});
|
|
112
|
+
else
|
|
113
|
+
on("context", (m, ctx) => {
|
|
114
|
+
const t = find(ctx.messages);
|
|
115
|
+
return t ? place(m, t) : undefined;
|
|
116
|
+
});
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// One extension object serves every turn of a runtime, concurrently. A
|
|
120
|
+
// run-scoped value is therefore keyed by run id — a single variable would
|
|
121
|
+
// let an overlapping turn's context reach the wrong model call. Populated
|
|
122
|
+
// at the start moment when there is one; a continuation (resume, decision)
|
|
123
|
+
// skips those and fills its entry on first use. Released at the end.
|
|
124
|
+
const perRun = new Map();
|
|
125
|
+
const valueFor = (msgs, run) => {
|
|
126
|
+
let p = perRun.get(run.runId);
|
|
127
|
+
if (!p) {
|
|
128
|
+
p = Promise.resolve(provider({ messages: msgs, run }));
|
|
129
|
+
perRun.set(run.runId, p);
|
|
130
|
+
}
|
|
131
|
+
return p;
|
|
132
|
+
};
|
|
133
|
+
if (scope === "run") {
|
|
134
|
+
on("before_agent_start", (msgs, run) => {
|
|
135
|
+
perRun.set(run.runId, Promise.resolve(provider({ messages: msgs, run })));
|
|
136
|
+
});
|
|
137
|
+
on("agent_end", ({ runId }) => {
|
|
138
|
+
perRun.delete(runId);
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const get = (msgs, run) => scope === "run" ? valueFor(msgs, run) : provider({ messages: msgs, run });
|
|
142
|
+
if (position === "system")
|
|
143
|
+
on("instructions", async (_, ctx) => {
|
|
144
|
+
const t = await get(ctx.messages, ctx);
|
|
145
|
+
return t ? { append: t } : undefined;
|
|
146
|
+
});
|
|
147
|
+
else
|
|
148
|
+
on("context", async (m, ctx) => {
|
|
149
|
+
const t = await get(ctx.messages, ctx);
|
|
150
|
+
return t ? place(m, t) : undefined;
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
notify(provider) {
|
|
154
|
+
const type = `data-notice-${name}`;
|
|
155
|
+
on("step_end", async (_msgs, info) => {
|
|
156
|
+
const text = await provider(info);
|
|
157
|
+
return text == null ? undefined : { append: [{ type, data: text }] };
|
|
158
|
+
});
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
const finish = () => {
|
|
162
|
+
if (Object.keys(registered).length)
|
|
163
|
+
on("register_tools", (t) => ({ ...t, ...registered }));
|
|
164
|
+
return { name, hooks, commands, critical: options.critical ?? false };
|
|
165
|
+
};
|
|
166
|
+
// An async factory is awaited once, before anything runs — the pattern for
|
|
167
|
+
// one-time startup work (load config, open a client, discover models).
|
|
168
|
+
const result = setup(api);
|
|
169
|
+
return result instanceof Promise ? result.then(finish) : finish();
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../../src/extensions/extension.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AA2QH,yDAAyD;AACzD,MAAM,CAAC,MAAM,YAAY,GAAG,CAC1B,UAAuB,EAC0C,EAAE,CACnE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CACvB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAC9F,CAAC;AA0CJ,uEAAuE;AACvE,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAqB,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC;AAiBrG,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,KAAkD,EAClD,UAAkC,EAAE;IAEpC,MAAM,KAAK,GAAU,EAAE,CAAC;IACxB,MAAM,EAAE,GAAG,CAAmB,CAAI,EAAE,EAAc,EAAE,EAAE;QACpD,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,EAAoC,CAAC,CAAC,IAAI,CAAC,EAAW,CAAC,CAAC;IACxE,CAAC,CAAC;IACF,MAAM,UAAU,GAAoC,EAAE,CAAC;IACvD,MAAM,QAAQ,GAAwB,EAAE,CAAC;IAEzC,MAAM,GAAG,GAAiB;QACxB,EAAE;QACF,YAAY,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACrB,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;QACD,eAAe,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE;YACjC,yEAAyE;YACzE,oEAAoE;YACpE,kEAAkE;YAClE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM;gBAC/B,MAAM,IAAI,KAAK,CAAC,aAAa,OAAO,mBAAmB,IAAI,iCAAiC,CAAC,CAAC;YAChG,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3D,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;gBACvC,IAAI,IAAI,KAAK,IAAI,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,OAAO,GAAG,CAAC;oBAAE,OAAO;gBACvE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBACnD,IAAI,IAAI,CAAC,MAAM;oBAAE,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC/D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACvD,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;oBACrD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;gBAC1C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;YACzE,CAAC,CAAC,CAAC;QACL,CAAC;QACD,gBAAgB,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;QAE1C,OAAO,CAAC,QAAQ,EAAE,EAAE,KAAK,GAAG,KAAK,EAAE,QAAQ,GAAG,aAAa,EAAE,GAAG,EAAE;YAChE,MAAM,IAAI,GAAG,YAAY,IAAI,EAAW,CAAC;YACzC,MAAM,KAAK,GAAG,CAAC,CAAiB,EAAE,IAAY,EAAiB,EAAE;gBAC/D,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;gBACnD,IAAI,CAAC,GAAG,CAAC;oBAAE,OAAO;gBAClB,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;gBAChB,MAAM,OAAO,GACX,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC3F,OAAO;oBACL,QAAQ,EAAE;wBACR,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;wBAChB,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,EAAkB;wBAChF,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;qBAClB;iBACF,CAAC;YACJ,CAAC,CAAC;YACF,MAAM,IAAI,GAAG,CAAC,IAAiB,EAAE,EAAE;gBACjC,KAAK,MAAM,CAAC,IAAI,IAAI;oBAAE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK;wBAAE,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI;4BAAE,OAAO,MAAM,CAAE,CAAuB,CAAC,IAAI,CAAC,CAAC;gBACjH,OAAO,SAAS,CAAC;YACnB,CAAC,CAAC;YAEF,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,EAAE,CAAC,oBAAoB,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;oBAC3C,IAAI,IAAI,CAAC,IAAI,CAAC;wBAAE,OAAO;oBACvB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;oBACrD,IAAI,IAAI,IAAI,IAAI;wBAAE,OAAO;oBACzB,qEAAqE;oBACrE,4DAA4D;oBAC5D,OAAO;wBACL,MAAM,EAAE;4BACN,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;4BACvB,IAAI,EAAE,WAAW;4BACjB,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAU,CAAC;yBACzB;qBACf,CAAC;gBACJ,CAAC,CAAC,CAAC;gBACH,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;gBACpE,IAAI,QAAQ,KAAK,QAAQ;oBACvB,EAAE,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;wBAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;wBAC7B,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;oBACvC,CAAC,CAAC,CAAC;;oBAEH,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;wBACvB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;wBAC7B,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;oBACrC,CAAC,CAAC,CAAC;gBACL,OAAO;YACT,CAAC;YAED,uEAAuE;YACvE,0EAA0E;YAC1E,0EAA0E;YAC1E,2EAA2E;YAC3E,qEAAqE;YACrE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuC,CAAC;YAC9D,MAAM,QAAQ,GAAG,CAAC,IAAiB,EAAE,GAAe,EAAE,EAAE;gBACtD,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC9B,IAAI,CAAC,CAAC,EAAE,CAAC;oBACP,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;oBACvD,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;gBAC3B,CAAC;gBACD,OAAO,CAAC,CAAC;YACX,CAAC,CAAC;YACF,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;gBACpB,EAAE,CAAC,oBAAoB,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;oBACrC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;gBAC5E,CAAC,CAAC,CAAC;gBACH,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE;oBAC5B,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvB,CAAC,CAAC,CAAC;YACL,CAAC;YACD,MAAM,GAAG,GAAG,CAAC,IAAiB,EAAE,GAAe,EAAE,EAAE,CACjD,KAAK,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;YAC5E,IAAI,QAAQ,KAAK,QAAQ;gBACvB,EAAE,CAAC,cAAc,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE;oBAClC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;oBACvC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;gBACvC,CAAC,CAAC,CAAC;;gBAEH,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE;oBAC7B,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;oBACvC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBACrC,CAAC,CAAC,CAAC;QACP,CAAC;QAED,MAAM,CAAC,QAAQ;YACb,MAAM,IAAI,GAAG,eAAe,IAAI,EAAW,CAAC;YAC5C,EAAE,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;gBACnC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,CAAC;gBAClC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAU,CAAC,EAAE,CAAC;YAC/E,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;IAEF,MAAM,MAAM,GAAG,GAAc,EAAE;QAC7B,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM;YAChC,EAAE,CAAC,gBAAgB,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC;QACzD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,KAAK,EAAE,CAAC;IACxE,CAAC,CAAC;IAEF,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1B,OAAO,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;AACpE,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The extension seam: moments, effects, the composer, and the tool wiring.
|
|
3
|
+
*
|
|
4
|
+
* `RuntimeConfig.extensions` and `AgentConfig.extensions` take `Extension[]`.
|
|
5
|
+
* Omit both and the runtime behaves exactly as before — every moment is a
|
|
6
|
+
* no-op with no handlers attached.
|
|
7
|
+
*/
|
|
8
|
+
export * from "./extension.js";
|
|
9
|
+
export * from "./compose.js";
|
|
10
|
+
export * from "./tools.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The extension seam: moments, effects, the composer, and the tool wiring.
|
|
3
|
+
*
|
|
4
|
+
* `RuntimeConfig.extensions` and `AgentConfig.extensions` take `Extension[]`.
|
|
5
|
+
* Omit both and the runtime behaves exactly as before — every moment is a
|
|
6
|
+
* no-op with no handlers attached.
|
|
7
|
+
*/
|
|
8
|
+
export * from "./extension.js";
|
|
9
|
+
export * from "./compose.js";
|
|
10
|
+
export * from "./tools.js";
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/extensions/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools.ts — the tool-side wiring: `tool_call` vetoes and `tool_result`
|
|
3
|
+
* rewrites over a toolset, plus the small transcript helpers the runtime uses
|
|
4
|
+
* to apply start-moment and step-end effects.
|
|
5
|
+
*/
|
|
6
|
+
import type { ToolSet, UIMessage } from "ai";
|
|
7
|
+
import type { Composed } from "./compose.js";
|
|
8
|
+
import type { Part, RunContext } from "./extension.js";
|
|
9
|
+
/** What a blocked tool call returns to the model. A result, not a throw, so the reason survives. */
|
|
10
|
+
export interface BlockedToolOutput {
|
|
11
|
+
blocked: true;
|
|
12
|
+
reason: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Wrap every executable tool so `tool_call` can veto and `tool_result` can
|
|
16
|
+
* rewrite what gets stored. With no listener on either moment the toolset is
|
|
17
|
+
* returned untouched — the identity of every tool object is preserved.
|
|
18
|
+
*
|
|
19
|
+
* The AI SDK's `executeTool` sniffs synchronously for `Symbol.asyncIterator`,
|
|
20
|
+
* so a wrapper that returns a promise turns a streaming tool into a
|
|
21
|
+
* non-streaming one: no progress chunks, and a generator object as the output.
|
|
22
|
+
* Two paths follow from that, chosen once per run:
|
|
23
|
+
*
|
|
24
|
+
* no `tool_call` listener call `execute` synchronously, pass the iterable
|
|
25
|
+
* through, hold one value back so the FINAL yield
|
|
26
|
+
* is the hooked one. Streaming preserved.
|
|
27
|
+
* a `tool_call` listener the veto is async and must resolve before
|
|
28
|
+
* `execute` runs, so the result is a promise and
|
|
29
|
+
* progress chunks are collapsed. A gated tool
|
|
30
|
+
* cannot also stream; that is the trade.
|
|
31
|
+
*/
|
|
32
|
+
export declare function wrapTools(tools: ToolSet, hooks: Composed, run: RunContext): ToolSet;
|
|
33
|
+
/**
|
|
34
|
+
* Fire `tool_result` for outputs a CLIENT produced.
|
|
35
|
+
*
|
|
36
|
+
* A client tool has no server `execute`, so the wrapper above never sees it:
|
|
37
|
+
* its output arrives in a later request, already in the transcript. Without
|
|
38
|
+
* this, an extension that inspects or redacts tool results silently covers
|
|
39
|
+
* server tools only, while the type promises both.
|
|
40
|
+
*
|
|
41
|
+
* Only parts after the last `step-start` are considered — the same slice the
|
|
42
|
+
* SDK's own auto-resubmit uses — so outputs an earlier run already handled are
|
|
43
|
+
* not fired again.
|
|
44
|
+
*/
|
|
45
|
+
export declare function fireClientToolResults(messages: UIMessage[], tools: ToolSet, hooks: Composed, run: RunContext): Promise<UIMessage[]>;
|
|
46
|
+
/** Append parts onto the run's assistant message (or start one). */
|
|
47
|
+
export declare function appendParts(messages: UIMessage[], parts: Part[]): UIMessage[];
|
|
48
|
+
/**
|
|
49
|
+
* Fold `step_end` parts into an assistant message the SDK assembled without
|
|
50
|
+
* them: each step's appended parts go before the NEXT `step-start`, the last
|
|
51
|
+
* step's at the end — exactly where an append at that step boundary would have
|
|
52
|
+
* landed. `priorSteps` skips step-start parts the message already carried
|
|
53
|
+
* before this run (a continuation reuses the assistant message).
|
|
54
|
+
*/
|
|
55
|
+
export declare function insertStepParts(message: UIMessage, appendedByStep: Map<number, Part[]>, priorSteps?: number): UIMessage;
|
|
56
|
+
/** The text of the newest user message, if any. */
|
|
57
|
+
export declare const lastUserTextOf: (messages: UIMessage[]) => string | undefined;
|
|
58
|
+
/** Rewrite the first text part of the newest user message (an `input` transform). */
|
|
59
|
+
export declare const replaceLastUserText: (messages: UIMessage[], text: string) => UIMessage[];
|
|
60
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../../src/extensions/tools.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC7C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAMvD,oGAAoG;AACpG,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,IAAI,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,GAAG,OAAO,CAuFnF;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CACzC,QAAQ,EAAE,SAAS,EAAE,EACrB,KAAK,EAAE,OAAO,EACd,KAAK,EAAE,QAAQ,EACf,GAAG,EAAE,UAAU,GACd,OAAO,CAAC,SAAS,EAAE,CAAC,CA+CtB;AAED,oEAAoE;AACpE,wBAAgB,WAAW,CAAC,QAAQ,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,SAAS,EAAE,CAO7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,SAAS,EAClB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,EACnC,UAAU,SAAI,GACb,SAAS,CAiBX;AAED,mDAAmD;AACnD,eAAO,MAAM,cAAc,GAAI,UAAU,SAAS,EAAE,KAAG,MAAM,GAAG,SAQ/D,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,mBAAmB,GAAI,UAAU,SAAS,EAAE,EAAE,MAAM,MAAM,KAAG,SAAS,EAalF,CAAC"}
|