@neutrome/lilsdk-ts 0.2.5 → 0.3.1
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/README.md +7 -4
- package/package.json +2 -2
- package/src/index.ts +3 -3
- package/src/loops/index.ts +50 -19
- package/src/managed/index.ts +1 -1
- package/src/managed/target-executor.ts +12 -0
- package/src/managed/twoPassExecutor.ts +18 -6
- package/src/observe.ts +2 -1
- package/src/output.ts +8 -2
- package/src/primitives/index.ts +45 -11
- package/src/stream/index.ts +5 -1
- package/src/synthetic/index.ts +22 -39
- package/src/tools-support.ts +108 -0
- package/src/tools.ts +144 -228
- package/src/types.ts +15 -7
- package/test/lilsdk-ts.test.ts +266 -102
- package/test/tools.test.ts +287 -94
- package/src/managed/wrap.ts +0 -17
package/src/tools.ts
CHANGED
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callData,
|
|
3
3
|
createProgram,
|
|
4
|
+
decodeStreamToolDelta,
|
|
4
5
|
isStreaming,
|
|
5
6
|
Opcode,
|
|
6
7
|
setStreaming,
|
|
7
8
|
type Instruction,
|
|
8
9
|
type Program,
|
|
10
|
+
type StreamToolDelta,
|
|
9
11
|
} from "@neutrome/lil-engine";
|
|
12
|
+
import { appendToolInteraction } from "./synthetic/index.ts";
|
|
13
|
+
import { type Executor, type ExecutorContext, type Tool } from "./types.ts";
|
|
10
14
|
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
type ExecutorContext,
|
|
20
|
-
type Tool,
|
|
21
|
-
} from "./types.ts";
|
|
15
|
+
buildCallExecutor,
|
|
16
|
+
buildToolAugmenter,
|
|
17
|
+
parseToolArguments,
|
|
18
|
+
type ToolCall,
|
|
19
|
+
type ToolExecution,
|
|
20
|
+
} from "./tools-support.ts";
|
|
21
|
+
|
|
22
|
+
export { ToolArgumentsError } from "./tools-support.ts";
|
|
22
23
|
|
|
23
24
|
export type WithToolsOptions = {
|
|
24
25
|
maxIterations?: number;
|
|
@@ -26,108 +27,34 @@ export type WithToolsOptions = {
|
|
|
26
27
|
|
|
27
28
|
const DEFAULT_MAX_ITERATIONS = 10;
|
|
28
29
|
|
|
29
|
-
function buildAugmenter(tools: Tool[]) {
|
|
30
|
-
const encoder = new TextEncoder();
|
|
31
|
-
const fragments = tools
|
|
32
|
-
.map((t) => t.systemPromptFragment)
|
|
33
|
-
.filter((f): f is string => !!f);
|
|
34
|
-
|
|
35
|
-
return function augmentRequest(request: Program): Program {
|
|
36
|
-
let augmented = request;
|
|
37
|
-
if (fragments.length > 0) {
|
|
38
|
-
augmented = prependSystemPrompt(augmented, fragments.join("\n\n"));
|
|
39
|
-
}
|
|
40
|
-
for (const tool of tools) {
|
|
41
|
-
augmented = addTool(
|
|
42
|
-
augmented,
|
|
43
|
-
tool.name,
|
|
44
|
-
tool.description,
|
|
45
|
-
encoder.encode(JSON.stringify(tool.schema)),
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
return augmented;
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function buildToolTrace(call: { id: string; name: string; args: string }, result: string): string {
|
|
53
|
-
return [
|
|
54
|
-
`CALL_START ${JSON.stringify(call.id)}`,
|
|
55
|
-
`CALL_NAME ${JSON.stringify(call.name)}`,
|
|
56
|
-
`CALL_ARGS ${call.args}`,
|
|
57
|
-
"CALL_END",
|
|
58
|
-
"RESULT_START",
|
|
59
|
-
`RESULT_DATA ${JSON.stringify(result)}`,
|
|
60
|
-
"RESULT_END",
|
|
61
|
-
].join("\n");
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function buildCallExecutor(toolMap: Map<string, Tool>) {
|
|
65
|
-
return function executeConnectedCalls(
|
|
66
|
-
calls: Array<{ id: string; name: string; args: string }>,
|
|
67
|
-
ctx: ExecutorContext,
|
|
68
|
-
): Promise<Array<{ id: string; name: string; args: string; result: string }>> {
|
|
69
|
-
return Promise.all(
|
|
70
|
-
calls.map(async (call) => {
|
|
71
|
-
const tool = toolMap.get(call.name)!;
|
|
72
|
-
let parsed: Record<string, unknown>;
|
|
73
|
-
try {
|
|
74
|
-
parsed = JSON.parse(call.args);
|
|
75
|
-
} catch {
|
|
76
|
-
parsed = {};
|
|
77
|
-
}
|
|
78
|
-
const startedMs = Date.now();
|
|
79
|
-
const startedAt = new Date(startedMs).toISOString();
|
|
80
|
-
const result = await tool.execute(parsed, ctx);
|
|
81
|
-
const finishedMs = Date.now();
|
|
82
|
-
ctx.observe(createSdkEvent({
|
|
83
|
-
kind: "tool.executed",
|
|
84
|
-
requestId: ctx.requestId,
|
|
85
|
-
executionId: `tool_${call.id || crypto.randomUUID()}`,
|
|
86
|
-
parentExecutionId: ctx.executionId,
|
|
87
|
-
data: {
|
|
88
|
-
toolName: call.name,
|
|
89
|
-
toolCallId: call.id,
|
|
90
|
-
startedAt,
|
|
91
|
-
finishedAt: new Date(finishedMs).toISOString(),
|
|
92
|
-
durationMs: finishedMs - startedMs,
|
|
93
|
-
lilText: buildToolTrace(call, result),
|
|
94
|
-
},
|
|
95
|
-
}));
|
|
96
|
-
return { ...call, result };
|
|
97
|
-
}),
|
|
98
|
-
);
|
|
99
|
-
};
|
|
100
|
-
}
|
|
101
|
-
|
|
102
30
|
type ToolDeltaAcc = { index: number; id: string; name: string; args: string };
|
|
31
|
+
type DecodedToolDelta = { instruction: Instruction; delta: StreamToolDelta };
|
|
103
32
|
|
|
104
33
|
function collectToolDeltasFromChunk(
|
|
105
34
|
chunk: Program,
|
|
106
35
|
acc: Map<number, ToolDeltaAcc>,
|
|
107
|
-
) {
|
|
36
|
+
): DecodedToolDelta[] {
|
|
37
|
+
const deltas: DecodedToolDelta[] = [];
|
|
108
38
|
for (const instr of chunk.code) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
}
|
|
39
|
+
const delta = decodeStreamToolDelta(instr);
|
|
40
|
+
if (!delta) continue;
|
|
41
|
+
deltas.push({ instruction: instr, delta });
|
|
42
|
+
const current = acc.get(delta.index) ?? {
|
|
43
|
+
index: delta.index,
|
|
44
|
+
id: "",
|
|
45
|
+
name: "",
|
|
46
|
+
args: "",
|
|
47
|
+
};
|
|
48
|
+
if (delta.id) current.id = delta.id;
|
|
49
|
+
if (delta.name) current.name = delta.name;
|
|
50
|
+
if (delta.arguments) current.args += delta.arguments;
|
|
51
|
+
acc.set(delta.index, current);
|
|
124
52
|
}
|
|
53
|
+
return deltas;
|
|
125
54
|
}
|
|
126
55
|
|
|
127
56
|
function filterChunkForClient(
|
|
128
57
|
chunk: Program,
|
|
129
|
-
connectedNames: Set<string>,
|
|
130
|
-
toolAcc: Map<number, ToolDeltaAcc>,
|
|
131
58
|
isIntermediate: boolean,
|
|
132
59
|
): Program | null {
|
|
133
60
|
const kept: Instruction[] = [];
|
|
@@ -135,16 +62,7 @@ function filterChunkForClient(
|
|
|
135
62
|
for (const instr of chunk.code) {
|
|
136
63
|
switch (instr.opcode) {
|
|
137
64
|
case Opcode.STREAM_TOOL_DELTA:
|
|
138
|
-
//
|
|
139
|
-
if (instr.value.kind === "json") {
|
|
140
|
-
const parsed = JSON.parse(new TextDecoder().decode(instr.value.value)) as Record<string, unknown>;
|
|
141
|
-
const index = typeof parsed.index === "number" ? parsed.index : 0;
|
|
142
|
-
const tool = toolAcc.get(index);
|
|
143
|
-
if (tool && connectedNames.has(tool.name)) {
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
kept.push(instr);
|
|
65
|
+
// Tool ownership can be revealed by a later fragment, so defer all deltas.
|
|
148
66
|
break;
|
|
149
67
|
case Opcode.RESP_DONE:
|
|
150
68
|
if (isIntermediate) continue;
|
|
@@ -173,21 +91,25 @@ async function* streamToolLoop(
|
|
|
173
91
|
ctx: ExecutorContext,
|
|
174
92
|
invokeStream: (req: Program) => AsyncIterable<Program>,
|
|
175
93
|
): AsyncGenerator<Program> {
|
|
176
|
-
|
|
177
|
-
let current = augmentRequest(request);
|
|
94
|
+
let state = createToolLoopState(augmentRequest(request));
|
|
178
95
|
let yieldedStart = false;
|
|
179
96
|
|
|
180
|
-
|
|
97
|
+
while (canRunToolLoop(state, maxIterations)) {
|
|
181
98
|
const toolAcc = new Map<number, ToolDeltaAcc>();
|
|
99
|
+
const toolDeltas: DecodedToolDelta[] = [];
|
|
182
100
|
const isIntermediate = true; // assume intermediate; we'll yield end markers later if final
|
|
183
101
|
|
|
184
|
-
for await (const chunk of invokeStream(
|
|
185
|
-
collectToolDeltasFromChunk(chunk, toolAcc);
|
|
102
|
+
for await (const chunk of invokeStream(state.request)) {
|
|
103
|
+
toolDeltas.push(...collectToolDeltasFromChunk(chunk, toolAcc));
|
|
186
104
|
|
|
187
|
-
const filtered = filterChunkForClient(chunk,
|
|
105
|
+
const filtered = filterChunkForClient(chunk, isIntermediate);
|
|
188
106
|
if (filtered) {
|
|
189
107
|
// Skip STREAM_START on iterations after the first (client already got it)
|
|
190
|
-
if (
|
|
108
|
+
if (
|
|
109
|
+
yieldedStart &&
|
|
110
|
+
filtered.code.length === 1 &&
|
|
111
|
+
filtered.code[0]?.opcode === Opcode.STREAM_START
|
|
112
|
+
) {
|
|
191
113
|
continue;
|
|
192
114
|
}
|
|
193
115
|
yield filtered;
|
|
@@ -202,82 +124,88 @@ async function* streamToolLoop(
|
|
|
202
124
|
.filter((t) => t.name)
|
|
203
125
|
.map((t) => ({ id: t.id, name: t.name, args: t.args }));
|
|
204
126
|
|
|
205
|
-
const
|
|
206
|
-
const outer = calls.filter((c) => !toolMap.has(c.name));
|
|
127
|
+
const decision = decideToolLoop(calls, toolMap);
|
|
207
128
|
|
|
208
|
-
if (
|
|
129
|
+
if (decision.kind !== "continue") {
|
|
209
130
|
// Final iteration — emit suppressed end markers
|
|
210
131
|
const endInstructions: Instruction[] = [];
|
|
211
|
-
if (
|
|
212
|
-
|
|
132
|
+
if (decision.kind === "external") {
|
|
133
|
+
const outerNames = new Set(decision.calls.map((call) => call.name));
|
|
134
|
+
const outerDeltas = toolDeltas
|
|
135
|
+
.filter(({ delta }) => {
|
|
136
|
+
const call = toolAcc.get(delta.index);
|
|
137
|
+
return call !== undefined && outerNames.has(call.name);
|
|
138
|
+
})
|
|
139
|
+
.map(({ instruction }) => instruction);
|
|
140
|
+
if (outerDeltas.length > 0) yield createProgram({ code: outerDeltas });
|
|
141
|
+
endInstructions.push({
|
|
142
|
+
opcode: Opcode.RESP_DONE,
|
|
143
|
+
value: { kind: "string", value: "tool_calls" },
|
|
144
|
+
});
|
|
213
145
|
} else if (calls.length === 0) {
|
|
214
|
-
endInstructions.push({
|
|
146
|
+
endInstructions.push({
|
|
147
|
+
opcode: Opcode.RESP_DONE,
|
|
148
|
+
value: { kind: "string", value: "stop" },
|
|
149
|
+
});
|
|
215
150
|
}
|
|
216
|
-
endInstructions.push({
|
|
151
|
+
endInstructions.push({
|
|
152
|
+
opcode: Opcode.STREAM_END,
|
|
153
|
+
value: { kind: "none" },
|
|
154
|
+
});
|
|
217
155
|
yield createProgram({ code: endInstructions });
|
|
218
156
|
return;
|
|
219
157
|
}
|
|
220
158
|
|
|
221
159
|
// Execute connected tools and loop
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
args: parseToolArgs(r.args),
|
|
229
|
-
result: r.result,
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
current = next;
|
|
160
|
+
state = await advanceToolLoopState(
|
|
161
|
+
state,
|
|
162
|
+
decision.calls,
|
|
163
|
+
ctx,
|
|
164
|
+
executeConnectedCalls,
|
|
165
|
+
);
|
|
233
166
|
}
|
|
234
167
|
|
|
235
168
|
// Max iterations reached — emit end
|
|
236
|
-
yield createProgram({
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
169
|
+
yield createProgram({
|
|
170
|
+
code: [
|
|
171
|
+
{ opcode: Opcode.RESP_DONE, value: { kind: "string", value: "stop" } },
|
|
172
|
+
{ opcode: Opcode.STREAM_END, value: { kind: "none" } },
|
|
173
|
+
],
|
|
174
|
+
});
|
|
240
175
|
}
|
|
241
176
|
|
|
242
|
-
export function
|
|
177
|
+
export function connectTools(
|
|
243
178
|
tools: Tool[],
|
|
244
|
-
|
|
179
|
+
inner: Executor,
|
|
245
180
|
options: WithToolsOptions = {},
|
|
246
181
|
): Executor {
|
|
247
182
|
const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
248
183
|
const toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
249
|
-
const augmentRequest =
|
|
184
|
+
const augmentRequest = buildToolAugmenter(tools);
|
|
250
185
|
const executeConnectedCalls = buildCallExecutor(toolMap);
|
|
251
186
|
|
|
252
187
|
return {
|
|
253
188
|
async execute(request, ctx) {
|
|
254
189
|
const augmented = augmentRequest(request);
|
|
255
|
-
let
|
|
190
|
+
let state = createToolLoopState(
|
|
191
|
+
isStreaming(augmented) ? setStreaming(augmented, false) : augmented,
|
|
192
|
+
);
|
|
256
193
|
|
|
257
|
-
|
|
258
|
-
const response = await
|
|
194
|
+
while (canRunToolLoop(state, maxIterations)) {
|
|
195
|
+
const response = await inner.execute(state.request, ctx);
|
|
259
196
|
const calls = callData(response);
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
callId: r.id,
|
|
270
|
-
name: r.name,
|
|
271
|
-
args: parseToolArgs(r.args),
|
|
272
|
-
result: r.result,
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (outer.length > 0) return response;
|
|
277
|
-
current = next;
|
|
197
|
+
const decision = decideToolLoop(calls, toolMap);
|
|
198
|
+
if (decision.kind !== "continue") return response;
|
|
199
|
+
|
|
200
|
+
state = await advanceToolLoopState(
|
|
201
|
+
state,
|
|
202
|
+
decision.calls,
|
|
203
|
+
ctx,
|
|
204
|
+
executeConnectedCalls,
|
|
205
|
+
);
|
|
278
206
|
}
|
|
279
207
|
|
|
280
|
-
return
|
|
208
|
+
return inner.execute(state.request, ctx);
|
|
281
209
|
},
|
|
282
210
|
|
|
283
211
|
async *stream(request, ctx) {
|
|
@@ -288,76 +216,64 @@ export function withTools(
|
|
|
288
216
|
executeConnectedCalls,
|
|
289
217
|
request,
|
|
290
218
|
ctx,
|
|
291
|
-
(req) =>
|
|
219
|
+
(req) => inner.stream(req, ctx),
|
|
292
220
|
);
|
|
293
221
|
},
|
|
294
222
|
};
|
|
295
223
|
}
|
|
296
224
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
):
|
|
307
|
-
const
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return {
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
for (let iteration = 0; iteration < maxIterations; iteration += 1) {
|
|
318
|
-
const response = await inner.execute(current, ctx);
|
|
319
|
-
const calls = callData(response);
|
|
320
|
-
const connected = calls.filter((c) => toolMap.has(c.name));
|
|
321
|
-
const outer = calls.filter((c) => !toolMap.has(c.name));
|
|
322
|
-
|
|
323
|
-
if (connected.length === 0) return response;
|
|
324
|
-
|
|
325
|
-
const results = await executeConnectedCalls(connected, ctx);
|
|
326
|
-
let next = current;
|
|
327
|
-
for (const r of results) {
|
|
328
|
-
next = appendToolInteraction(next, {
|
|
329
|
-
callId: r.id,
|
|
330
|
-
name: r.name,
|
|
331
|
-
args: parseToolArgs(r.args),
|
|
332
|
-
result: r.result,
|
|
333
|
-
});
|
|
334
|
-
}
|
|
225
|
+
type ToolLoopState = { request: Program; iteration: number };
|
|
226
|
+
type ToolLoopDecision =
|
|
227
|
+
| { kind: "complete" }
|
|
228
|
+
| { kind: "external"; calls: ToolCall[] }
|
|
229
|
+
| { kind: "continue"; calls: ToolCall[] };
|
|
230
|
+
|
|
231
|
+
function decideToolLoop(
|
|
232
|
+
calls: ToolCall[],
|
|
233
|
+
toolMap: ReadonlyMap<string, Tool>,
|
|
234
|
+
): ToolLoopDecision {
|
|
235
|
+
const connected: ToolCall[] = [];
|
|
236
|
+
const outer: ToolCall[] = [];
|
|
237
|
+
for (const call of calls) {
|
|
238
|
+
(toolMap.has(call.name) ? connected : outer).push(call);
|
|
239
|
+
}
|
|
240
|
+
if (outer.length > 0) return { kind: "external", calls: outer };
|
|
241
|
+
if (connected.length === 0) return { kind: "complete" };
|
|
242
|
+
return { kind: "continue", calls: connected };
|
|
243
|
+
}
|
|
335
244
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
245
|
+
function createToolLoopState(request: Program): ToolLoopState {
|
|
246
|
+
return { request, iteration: 0 };
|
|
247
|
+
}
|
|
339
248
|
|
|
340
|
-
|
|
341
|
-
|
|
249
|
+
function canRunToolLoop(state: ToolLoopState, maxIterations: number): boolean {
|
|
250
|
+
return state.iteration < maxIterations;
|
|
251
|
+
}
|
|
342
252
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
253
|
+
function appendToolResults(
|
|
254
|
+
request: Program,
|
|
255
|
+
results: readonly ToolExecution[],
|
|
256
|
+
): Program {
|
|
257
|
+
return results.reduce(
|
|
258
|
+
(next, result) =>
|
|
259
|
+
appendToolInteraction(next, {
|
|
260
|
+
callId: result.id,
|
|
261
|
+
name: result.name,
|
|
262
|
+
args: parseToolArguments(result.name, result.args),
|
|
263
|
+
result: result.result,
|
|
264
|
+
}),
|
|
265
|
+
request,
|
|
266
|
+
);
|
|
355
267
|
}
|
|
356
268
|
|
|
357
|
-
function
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
269
|
+
async function advanceToolLoopState(
|
|
270
|
+
state: ToolLoopState,
|
|
271
|
+
calls: readonly ToolCall[],
|
|
272
|
+
ctx: ExecutorContext,
|
|
273
|
+
executeCalls: ReturnType<typeof buildCallExecutor>,
|
|
274
|
+
): Promise<ToolLoopState> {
|
|
275
|
+
return {
|
|
276
|
+
request: appendToolResults(state.request, await executeCalls(calls, ctx)),
|
|
277
|
+
iteration: state.iteration + 1,
|
|
278
|
+
};
|
|
363
279
|
}
|
package/src/types.ts
CHANGED
|
@@ -22,7 +22,7 @@ export type ExecutionTarget =
|
|
|
22
22
|
transforms?: string[];
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
export type
|
|
25
|
+
export type ExecutionEvent = {
|
|
26
26
|
kind: string;
|
|
27
27
|
requestId: string;
|
|
28
28
|
executionId: string;
|
|
@@ -33,7 +33,7 @@ export type SdkEvent = {
|
|
|
33
33
|
data?: Record<string, unknown>;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
|
-
export type
|
|
36
|
+
export type ExecutionEventInput = Omit<ExecutionEvent, "timestamp"> & {
|
|
37
37
|
timestamp?: string;
|
|
38
38
|
};
|
|
39
39
|
|
|
@@ -46,8 +46,11 @@ export type InvokeOptions = {
|
|
|
46
46
|
|
|
47
47
|
export type TransformContext = {
|
|
48
48
|
invoke(request: Program, options?: InvokeOptions): Promise<Program>;
|
|
49
|
-
invokeStream(
|
|
50
|
-
|
|
49
|
+
invokeStream(
|
|
50
|
+
request: Program,
|
|
51
|
+
options?: InvokeOptions,
|
|
52
|
+
): AsyncIterable<Program>;
|
|
53
|
+
observe(event: ExecutionEvent): void;
|
|
51
54
|
signal: AbortSignal;
|
|
52
55
|
};
|
|
53
56
|
|
|
@@ -62,8 +65,11 @@ export type ExecutorContext = {
|
|
|
62
65
|
executionId: string;
|
|
63
66
|
parentExecutionId?: string;
|
|
64
67
|
invoke(request: Program, options?: InvokeOptions): Promise<Program>;
|
|
65
|
-
invokeStream(
|
|
66
|
-
|
|
68
|
+
invokeStream(
|
|
69
|
+
request: Program,
|
|
70
|
+
options?: InvokeOptions,
|
|
71
|
+
): AsyncIterable<Program>;
|
|
72
|
+
observe(event: ExecutionEvent): void;
|
|
67
73
|
signal: AbortSignal;
|
|
68
74
|
};
|
|
69
75
|
|
|
@@ -85,7 +91,9 @@ export type OutputSink = {
|
|
|
85
91
|
close(): void | Promise<void>;
|
|
86
92
|
};
|
|
87
93
|
|
|
88
|
-
export function
|
|
94
|
+
export function createExecutionEvent(
|
|
95
|
+
input: ExecutionEventInput,
|
|
96
|
+
): ExecutionEvent {
|
|
89
97
|
return {
|
|
90
98
|
...input,
|
|
91
99
|
timestamp: input.timestamp ?? new Date().toISOString(),
|