@neutrome/lilsdk 0.4.6 → 0.5.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 +24 -17
- package/etc/api/index.api.md +96 -103
- package/etc/api/loops.api.md +108 -108
- package/etc/api/managed.api.md +102 -102
- package/etc/api/primitives.api.md +39 -39
- package/etc/api/stream.api.md +46 -55
- package/etc/api/tools.api.md +103 -103
- package/neutrome-lilsdk-0.5.0.tgz +0 -0
- package/package.json +2 -4
- package/src/index.ts +41 -15
- package/src/loops/goal.ts +111 -0
- package/src/loops/index.ts +41 -110
- package/src/loops/shared.ts +27 -0
- package/src/managed/attachment-to-text.ts +35 -11
- package/src/managed/capabilities.ts +42 -22
- package/src/observe.ts +21 -6
- package/src/output.ts +13 -25
- package/src/primitives/index.ts +69 -0
- package/src/stream/index.ts +2 -6
- package/src/stream/stages.ts +15 -11
- package/src/tools-support.ts +9 -3
- package/src/tools.ts +36 -19
- package/src/types.ts +129 -4
- package/test/lilsdk-ts.test.ts +47 -45
- package/test/tools.test.ts +22 -20
- package/etc/api/synthetic.api.md +0 -46
- package/etc/api/types.api.md +0 -103
- package/src/synthetic/index.ts +0 -134
package/src/output.ts
CHANGED
|
@@ -1,31 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createProgram,
|
|
3
|
-
Opcode,
|
|
4
|
-
streamEnd,
|
|
5
|
-
streamStart,
|
|
6
|
-
streamTextDelta,
|
|
7
|
-
type Program,
|
|
8
|
-
} from "@neutrome/lil-engine";
|
|
1
|
+
import { delta } from "@neutrome/lil-engine";
|
|
9
2
|
import type { OutputSink } from "./types.ts";
|
|
10
3
|
|
|
11
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Writes a model-reasoning chunk to a sink.
|
|
6
|
+
*
|
|
7
|
+
* @param sink - Sink to write to.
|
|
8
|
+
* @param text - Reasoning text to emit.
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* await writeThinking(sink, "Checking the attachment first.");
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export async function writeThinking(
|
|
12
15
|
sink: OutputSink,
|
|
13
16
|
text: string,
|
|
14
17
|
): Promise<void> {
|
|
15
|
-
await sink.write(
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export function streamTextResponse(text: string): Program[] {
|
|
19
|
-
return [streamStart(), streamTextDelta(text), streamEnd()];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function streamReasoningDelta(text: string): Program {
|
|
23
|
-
return createProgram({
|
|
24
|
-
code: [
|
|
25
|
-
{
|
|
26
|
-
opcode: Opcode.STREAM_THINK_DELTA,
|
|
27
|
-
value: { kind: "string", value: text },
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
});
|
|
18
|
+
await sink.write(delta.thinking(text));
|
|
31
19
|
}
|
package/src/primitives/index.ts
CHANGED
|
@@ -4,16 +4,37 @@ import {
|
|
|
4
4
|
type Program,
|
|
5
5
|
} from "@neutrome/lil-engine";
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Finds the position of an instruction by value.
|
|
9
|
+
*
|
|
10
|
+
* @param program - Program to search.
|
|
11
|
+
* @param needle - Instruction to match, compared by opcode and payload.
|
|
12
|
+
* @returns The index, or `-1` when absent.
|
|
13
|
+
*/
|
|
7
14
|
export function indexOf(program: Program, needle: Instruction): number {
|
|
8
15
|
return program.code.findIndex((instruction) =>
|
|
9
16
|
instructionEquals(instruction, needle),
|
|
10
17
|
);
|
|
11
18
|
}
|
|
12
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Reports whether a program contains an instruction by value.
|
|
22
|
+
*
|
|
23
|
+
* @param program - Program to search.
|
|
24
|
+
* @param needle - Instruction to match.
|
|
25
|
+
* @returns `true` when a matching instruction exists.
|
|
26
|
+
*/
|
|
13
27
|
export function has(program: Program, needle: Instruction): boolean {
|
|
14
28
|
return indexOf(program, needle) >= 0;
|
|
15
29
|
}
|
|
16
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Reads the first instruction matching a value.
|
|
33
|
+
*
|
|
34
|
+
* @param program - Program to search.
|
|
35
|
+
* @param needle - Instruction to match.
|
|
36
|
+
* @returns A copy of the match, or `undefined` when absent.
|
|
37
|
+
*/
|
|
17
38
|
export function find(
|
|
18
39
|
program: Program,
|
|
19
40
|
needle: Instruction,
|
|
@@ -22,6 +43,12 @@ export function find(
|
|
|
22
43
|
return i >= 0 ? cloneInstruction(program.code[i]!) : undefined;
|
|
23
44
|
}
|
|
24
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Visits every instruction in order.
|
|
48
|
+
*
|
|
49
|
+
* @param program - Program to walk.
|
|
50
|
+
* @param callback - Called with each instruction, its index and the program.
|
|
51
|
+
*/
|
|
25
52
|
export function walk(
|
|
26
53
|
program: Program,
|
|
27
54
|
callback: (instruction: Instruction, index: number, program: Program) => void,
|
|
@@ -31,6 +58,19 @@ export function walk(
|
|
|
31
58
|
);
|
|
32
59
|
}
|
|
33
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Rewrites every instruction.
|
|
63
|
+
*
|
|
64
|
+
* @param program - Program to map.
|
|
65
|
+
* @param callback - Returns the replacement for each instruction.
|
|
66
|
+
* @returns A new program; the input is left untouched.
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* const redacted = map(program, (instruction) =>
|
|
70
|
+
* instruction.opcode === Opcode.TXT_CHUNK ? redact(instruction) : instruction,
|
|
71
|
+
* );
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
34
74
|
export function map(
|
|
35
75
|
program: Program,
|
|
36
76
|
callback: (
|
|
@@ -47,6 +87,13 @@ export function map(
|
|
|
47
87
|
};
|
|
48
88
|
}
|
|
49
89
|
|
|
90
|
+
/**
|
|
91
|
+
* Keeps only the instructions a predicate accepts.
|
|
92
|
+
*
|
|
93
|
+
* @param program - Program to filter.
|
|
94
|
+
* @param callback - Returns `true` for instructions to keep.
|
|
95
|
+
* @returns A new program; the input is left untouched.
|
|
96
|
+
*/
|
|
50
97
|
export function filter(
|
|
51
98
|
program: Program,
|
|
52
99
|
callback: (
|
|
@@ -63,6 +110,14 @@ export function filter(
|
|
|
63
110
|
};
|
|
64
111
|
}
|
|
65
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Folds the instruction list into a single value.
|
|
115
|
+
*
|
|
116
|
+
* @param program - Program to fold.
|
|
117
|
+
* @param callback - Combines the accumulator with each instruction.
|
|
118
|
+
* @param initialValue - Starting accumulator.
|
|
119
|
+
* @returns The final accumulator.
|
|
120
|
+
*/
|
|
66
121
|
export function reduce<T>(
|
|
67
122
|
program: Program,
|
|
68
123
|
callback: (
|
|
@@ -80,6 +135,13 @@ export function reduce<T>(
|
|
|
80
135
|
return accumulator;
|
|
81
136
|
}
|
|
82
137
|
|
|
138
|
+
/**
|
|
139
|
+
* Reports whether every instruction satisfies a predicate.
|
|
140
|
+
*
|
|
141
|
+
* @param program - Program to test.
|
|
142
|
+
* @param callback - Predicate applied to each instruction.
|
|
143
|
+
* @returns `true` when all instructions pass, including for empty programs.
|
|
144
|
+
*/
|
|
83
145
|
export function all(
|
|
84
146
|
program: Program,
|
|
85
147
|
callback: (
|
|
@@ -94,6 +156,13 @@ export function all(
|
|
|
94
156
|
return true;
|
|
95
157
|
}
|
|
96
158
|
|
|
159
|
+
/**
|
|
160
|
+
* Reports whether any instruction satisfies a predicate.
|
|
161
|
+
*
|
|
162
|
+
* @param program - Program to test.
|
|
163
|
+
* @param callback - Predicate applied to each instruction.
|
|
164
|
+
* @returns `true` when at least one instruction passes.
|
|
165
|
+
*/
|
|
97
166
|
export function any(
|
|
98
167
|
program: Program,
|
|
99
168
|
callback: (
|
package/src/stream/index.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export type { ObservedExecution, StreamObservationHooks } from "../observe.ts";
|
|
2
2
|
|
|
3
3
|
export { observeExecutionStream } from "../observe.ts";
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
streamReasoningDelta,
|
|
7
|
-
streamTextResponse,
|
|
8
|
-
writeReasoning,
|
|
9
|
-
} from "../output.ts";
|
|
4
|
+
export { streamStage } from "./stages.ts";
|
|
5
|
+
export { writeThinking } from "../output.ts";
|
package/src/stream/stages.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Opcode, type Program } from "@neutrome/lil-engine";
|
|
2
2
|
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Forwards one stage of a stream without letting it close the outer stream.
|
|
5
|
+
*
|
|
6
|
+
* Drops the `RESP_DONE` and `STREAM_END` instructions, so several executors can
|
|
7
|
+
* stream into one response and only the last one finishes it.
|
|
8
|
+
*
|
|
9
|
+
* @param source - Chunks to forward.
|
|
10
|
+
* @returns The chunks, minus any terminal instructions.
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* for await (const chunk of streamStage(ctx.invokeStream(draft, request))) yield chunk;
|
|
14
|
+
* yield delta.end();
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
4
17
|
export async function* streamStage(
|
|
5
18
|
source: AsyncIterable<Program>,
|
|
6
19
|
): AsyncGenerator<Program> {
|
|
@@ -14,12 +27,3 @@ export async function* streamStage(
|
|
|
14
27
|
yield code.length === chunk.code.length ? chunk : { ...chunk, code };
|
|
15
28
|
}
|
|
16
29
|
}
|
|
17
|
-
|
|
18
|
-
export function completeStream(reason = "stop"): Program {
|
|
19
|
-
return createProgram({
|
|
20
|
-
code: [
|
|
21
|
-
{ opcode: Opcode.RESP_DONE, value: { kind: "string", value: reason } },
|
|
22
|
-
{ opcode: Opcode.STREAM_END, value: { kind: "none" } },
|
|
23
|
-
],
|
|
24
|
-
});
|
|
25
|
-
}
|
package/src/tools-support.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
appendTool,
|
|
3
|
+
prependSystemPrompt,
|
|
4
|
+
type Program,
|
|
5
|
+
} from "@neutrome/lil-engine";
|
|
3
6
|
import {
|
|
4
7
|
createExecutionEvent,
|
|
5
8
|
type ExecutorContext,
|
|
@@ -14,6 +17,9 @@ export type ToolExecution = {
|
|
|
14
17
|
result: string;
|
|
15
18
|
};
|
|
16
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Thrown when a model calls a tool with arguments that are not valid JSON.
|
|
22
|
+
*/
|
|
17
23
|
export class ToolArgumentsError extends Error {
|
|
18
24
|
constructor(
|
|
19
25
|
readonly toolName: string,
|
|
@@ -36,7 +42,7 @@ export function buildToolAugmenter(tools: readonly Tool[]) {
|
|
|
36
42
|
augmented = prependSystemPrompt(augmented, fragments.join("\n\n"));
|
|
37
43
|
}
|
|
38
44
|
for (const tool of tools) {
|
|
39
|
-
augmented =
|
|
45
|
+
augmented = appendTool(
|
|
40
46
|
augmented,
|
|
41
47
|
tool.name,
|
|
42
48
|
tool.description,
|
package/src/tools.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
2
|
+
appendToolInteraction,
|
|
3
3
|
createProgram,
|
|
4
|
-
|
|
4
|
+
delta,
|
|
5
|
+
extractToolCalls,
|
|
5
6
|
isStreaming,
|
|
6
7
|
Opcode,
|
|
7
8
|
setStreaming,
|
|
8
9
|
type Instruction,
|
|
9
10
|
type Program,
|
|
10
|
-
type StreamToolDelta,
|
|
11
11
|
} from "@neutrome/lil-engine";
|
|
12
|
-
import { appendToolInteraction } from "./synthetic/index.ts";
|
|
13
12
|
import {
|
|
14
13
|
type Executor,
|
|
15
14
|
type ExecutorContext,
|
|
@@ -26,14 +25,16 @@ import {
|
|
|
26
25
|
|
|
27
26
|
export { ToolArgumentsError } from "./tools-support.ts";
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
/** Options accepted by {@link createToolsExecutor}. */
|
|
29
|
+
export type ToolsExecutorOptions = {
|
|
30
|
+
/** Maximum tool round trips before the loop gives up. Defaults to 10. */
|
|
30
31
|
maxIterations?: number;
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
const DEFAULT_MAX_ITERATIONS = 10;
|
|
34
35
|
|
|
35
36
|
type ToolDeltaAcc = { index: number; id: string; name: string; args: string };
|
|
36
|
-
type DecodedToolDelta = { instruction: Instruction; delta:
|
|
37
|
+
type DecodedToolDelta = { instruction: Instruction; delta: delta.ToolCall };
|
|
37
38
|
|
|
38
39
|
function collectToolDeltasFromChunk(
|
|
39
40
|
chunk: Program,
|
|
@@ -41,19 +42,19 @@ function collectToolDeltasFromChunk(
|
|
|
41
42
|
): DecodedToolDelta[] {
|
|
42
43
|
const deltas: DecodedToolDelta[] = [];
|
|
43
44
|
for (const instr of chunk.code) {
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
46
|
-
deltas.push({ instruction: instr, delta });
|
|
47
|
-
const current = acc.get(
|
|
48
|
-
index:
|
|
45
|
+
const toolCall = delta.decodeToolCall(instr);
|
|
46
|
+
if (!toolCall) continue;
|
|
47
|
+
deltas.push({ instruction: instr, delta: toolCall });
|
|
48
|
+
const current = acc.get(toolCall.index) ?? {
|
|
49
|
+
index: toolCall.index,
|
|
49
50
|
id: "",
|
|
50
51
|
name: "",
|
|
51
52
|
args: "",
|
|
52
53
|
};
|
|
53
|
-
if (
|
|
54
|
-
if (
|
|
55
|
-
if (
|
|
56
|
-
acc.set(
|
|
54
|
+
if (toolCall.id) current.id = toolCall.id;
|
|
55
|
+
if (toolCall.name) current.name = toolCall.name;
|
|
56
|
+
if (toolCall.arguments) current.args += toolCall.arguments;
|
|
57
|
+
acc.set(toolCall.index, current);
|
|
57
58
|
}
|
|
58
59
|
return deltas;
|
|
59
60
|
}
|
|
@@ -179,10 +180,26 @@ async function* streamToolLoop(
|
|
|
179
180
|
});
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
|
|
183
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Wraps an executor in a tool loop.
|
|
185
|
+
*
|
|
186
|
+
* The returned executor declares `tools` to the model, runs any it owns, feeds
|
|
187
|
+
* the results back and repeats. Calls to tools it does not own are passed
|
|
188
|
+
* through to the caller untouched, so an outer loop can handle them.
|
|
189
|
+
*
|
|
190
|
+
* @param inner - Executor or model id that does the generating.
|
|
191
|
+
* @param tools - Tools this loop owns and executes.
|
|
192
|
+
* @param options - Loop limits.
|
|
193
|
+
* @returns An executor that resolves tool calls before answering.
|
|
194
|
+
* @example
|
|
195
|
+
* ```ts
|
|
196
|
+
* export default createToolsExecutor("core/turn-1", [searchTool, calculatorTool]);
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export function createToolsExecutor(
|
|
184
200
|
inner: ExecutorInput,
|
|
185
|
-
|
|
201
|
+
tools: Tool[],
|
|
202
|
+
options: ToolsExecutorOptions = {},
|
|
186
203
|
): Executor {
|
|
187
204
|
const maxIterations = options.maxIterations ?? DEFAULT_MAX_ITERATIONS;
|
|
188
205
|
const toolMap = new Map(tools.map((t) => [t.name, t]));
|
|
@@ -198,7 +215,7 @@ export function connectTools(
|
|
|
198
215
|
|
|
199
216
|
while (canRunToolLoop(state, maxIterations)) {
|
|
200
217
|
const response = await ctx.invoke(inner, state.request);
|
|
201
|
-
const calls =
|
|
218
|
+
const calls = extractToolCalls(response);
|
|
202
219
|
const decision = decideToolLoop(calls, toolMap);
|
|
203
220
|
if (decision.kind !== "continue") return response;
|
|
204
221
|
|
package/src/types.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Program } from "@neutrome/lil-engine";
|
|
2
2
|
|
|
3
|
+
/** A capability a {@link ProgramTransform} declares before it may be applied. */
|
|
3
4
|
export type TransformCapability =
|
|
4
5
|
| "read_messages"
|
|
5
6
|
| "write_messages"
|
|
@@ -8,77 +9,201 @@ export type TransformCapability =
|
|
|
8
9
|
| "drop_content"
|
|
9
10
|
| "provider_extension";
|
|
10
11
|
|
|
12
|
+
/** One audit record emitted while a request is being served. */
|
|
11
13
|
export type ExecutionEvent = {
|
|
14
|
+
/** Event name, such as `"executor.start"`. */
|
|
12
15
|
kind: string;
|
|
16
|
+
/** Id shared by every event of one inbound request. */
|
|
13
17
|
requestId: string;
|
|
18
|
+
/** Id of the execution that emitted the event. */
|
|
14
19
|
executionId: string;
|
|
20
|
+
/** ISO timestamp of the event. */
|
|
15
21
|
timestamp: string;
|
|
22
|
+
/** Id of the enclosing execution, when nested. */
|
|
16
23
|
parentExecutionId?: string;
|
|
24
|
+
/** What the execution was talking to. */
|
|
17
25
|
target?: { kind: "provider" | "executor"; id: string };
|
|
26
|
+
/** Error class, for failure events. */
|
|
18
27
|
errorKind?: string;
|
|
28
|
+
/** Free-form payload. */
|
|
19
29
|
data?: Record<string, unknown>;
|
|
20
30
|
};
|
|
21
31
|
|
|
32
|
+
/** {@link ExecutionEvent} before a timestamp is stamped on it. */
|
|
22
33
|
export type ExecutionEventInput = Omit<ExecutionEvent, "timestamp"> & {
|
|
23
34
|
timestamp?: string;
|
|
24
35
|
};
|
|
25
36
|
|
|
37
|
+
/** Expiry options accepted by {@link Cache.put}. */
|
|
26
38
|
export type CachePutOptions = {
|
|
39
|
+
/** Absolute expiry, as a Unix timestamp in seconds. */
|
|
27
40
|
expiration?: number;
|
|
41
|
+
/** Relative expiry, in seconds from now. */
|
|
28
42
|
expirationTtl?: number;
|
|
29
43
|
};
|
|
30
44
|
|
|
45
|
+
/** Key-value store handed to executors through {@link RuntimeContext.cache}. */
|
|
31
46
|
export type Cache = {
|
|
47
|
+
/** Reads a value, or `null` when the key is unset. */
|
|
32
48
|
get(key: string): Promise<string | null>;
|
|
49
|
+
/** Writes a value, optionally with an expiry. */
|
|
33
50
|
put(key: string, value: string, options?: CachePutOptions): Promise<void>;
|
|
51
|
+
/** Removes a key. */
|
|
34
52
|
delete(key: string): Promise<void>;
|
|
35
53
|
};
|
|
36
54
|
|
|
37
|
-
|
|
55
|
+
/**
|
|
56
|
+
* The runtime services available while a request is being served.
|
|
57
|
+
*
|
|
58
|
+
* Executors and transforms never talk to providers directly: they call
|
|
59
|
+
* {@link RuntimeContext.invoke}, which lets the runtime handle routing,
|
|
60
|
+
* auditing and cancellation.
|
|
61
|
+
*/
|
|
62
|
+
export type RuntimeContext = {
|
|
63
|
+
/** Request-scoped cache. */
|
|
38
64
|
cache: Cache;
|
|
65
|
+
/**
|
|
66
|
+
* Runs another executor, or a model id, to completion.
|
|
67
|
+
*
|
|
68
|
+
* @param executor - Executor value or model id to run.
|
|
69
|
+
* @param request - Program to send.
|
|
70
|
+
* @returns The response program.
|
|
71
|
+
*/
|
|
39
72
|
invoke(executor: ExecutorInput, request: Program): Promise<Program>;
|
|
73
|
+
/**
|
|
74
|
+
* Runs another executor, or a model id, and streams its chunks.
|
|
75
|
+
*
|
|
76
|
+
* @param executor - Executor value or model id to run.
|
|
77
|
+
* @param request - Program to send.
|
|
78
|
+
* @returns The response chunks.
|
|
79
|
+
*/
|
|
40
80
|
invokeStream(
|
|
41
81
|
executor: ExecutorInput,
|
|
42
82
|
request: Program,
|
|
43
83
|
): AsyncIterable<Program>;
|
|
84
|
+
/**
|
|
85
|
+
* Records an audit event.
|
|
86
|
+
*
|
|
87
|
+
* @param event - Event to record.
|
|
88
|
+
*/
|
|
44
89
|
observe(event: ExecutionEvent): void;
|
|
90
|
+
/** Aborts when the client goes away or the request times out. */
|
|
45
91
|
signal: AbortSignal;
|
|
46
92
|
};
|
|
47
93
|
|
|
48
|
-
|
|
49
|
-
|
|
94
|
+
/** A named, capability-scoped edit applied to every program passing through. */
|
|
50
95
|
export type ProgramTransform = {
|
|
96
|
+
/** Transform name, used in audit events. */
|
|
51
97
|
name: string;
|
|
98
|
+
/** Everything this transform is allowed to do. */
|
|
52
99
|
capabilities: TransformCapability[];
|
|
53
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Applies the transform.
|
|
102
|
+
*
|
|
103
|
+
* @param program - Program to edit.
|
|
104
|
+
* @param ctx - Runtime services.
|
|
105
|
+
* @returns The edited program.
|
|
106
|
+
*/
|
|
107
|
+
apply(program: Program, ctx: RuntimeContext): Program | Promise<Program>;
|
|
54
108
|
};
|
|
55
109
|
|
|
110
|
+
/** {@link RuntimeContext} plus the identity of the running execution. */
|
|
56
111
|
export type ExecutorContext = RuntimeContext & {
|
|
112
|
+
/** Id shared by every execution of one inbound request. */
|
|
57
113
|
requestId: string;
|
|
114
|
+
/** Id of this execution. */
|
|
58
115
|
executionId: string;
|
|
116
|
+
/** Id of the enclosing execution, when nested. */
|
|
59
117
|
parentExecutionId?: string;
|
|
60
118
|
};
|
|
61
119
|
|
|
120
|
+
/**
|
|
121
|
+
* The unit of composition: something that answers a program.
|
|
122
|
+
*
|
|
123
|
+
* Both methods must be implemented, so an executor can be used in a streaming
|
|
124
|
+
* and a non-streaming request alike.
|
|
125
|
+
*
|
|
126
|
+
* @example
|
|
127
|
+
* ```ts
|
|
128
|
+
* const executor: Executor = {
|
|
129
|
+
* async execute(request, ctx) {
|
|
130
|
+
* return ctx.invoke(upstream, prependSystemPrompt(request, system()));
|
|
131
|
+
* },
|
|
132
|
+
* async *stream(request, ctx) {
|
|
133
|
+
* yield* ctx.invokeStream(upstream, prependSystemPrompt(request, system()));
|
|
134
|
+
* },
|
|
135
|
+
* };
|
|
136
|
+
* ```
|
|
137
|
+
*/
|
|
62
138
|
export type Executor = {
|
|
139
|
+
/**
|
|
140
|
+
* Answers a request in one shot.
|
|
141
|
+
*
|
|
142
|
+
* @param request - Program to answer.
|
|
143
|
+
* @param ctx - Runtime services and execution identity.
|
|
144
|
+
* @returns The response program.
|
|
145
|
+
*/
|
|
63
146
|
execute(request: Program, ctx: ExecutorContext): Promise<Program>;
|
|
147
|
+
/**
|
|
148
|
+
* Answers a request as a chunk stream.
|
|
149
|
+
*
|
|
150
|
+
* @param request - Program to answer.
|
|
151
|
+
* @param ctx - Runtime services and execution identity.
|
|
152
|
+
* @returns The response chunks.
|
|
153
|
+
*/
|
|
64
154
|
stream(request: Program, ctx: ExecutorContext): AsyncIterable<Program>;
|
|
65
155
|
};
|
|
66
156
|
|
|
157
|
+
/**
|
|
158
|
+
* An executor, or the id of a model to run.
|
|
159
|
+
*
|
|
160
|
+
* Every combinator in this package accepts either, so `retry("fast/gemma-4-31b")`
|
|
161
|
+
* and `retry(myExecutor)` are both valid.
|
|
162
|
+
*/
|
|
67
163
|
export type ExecutorInput = string | Executor;
|
|
68
164
|
|
|
165
|
+
/** A tool the model may call during a tool loop. */
|
|
69
166
|
export type Tool = {
|
|
167
|
+
/** Tool name the model must use when calling it. */
|
|
70
168
|
name: string;
|
|
169
|
+
/** Natural-language description shown to the model. */
|
|
71
170
|
description: string;
|
|
171
|
+
/** JSON Schema describing the arguments. */
|
|
72
172
|
schema: Record<string, unknown>;
|
|
173
|
+
/** Extra instructions appended to the system prompt when this tool is enabled. */
|
|
73
174
|
systemPromptFragment?: string;
|
|
175
|
+
/**
|
|
176
|
+
* Runs the tool.
|
|
177
|
+
*
|
|
178
|
+
* @param args - Arguments the model supplied, already parsed.
|
|
179
|
+
* @param ctx - Runtime services and execution identity.
|
|
180
|
+
* @returns The result, rendered as text for the model.
|
|
181
|
+
*/
|
|
74
182
|
execute(args: Record<string, unknown>, ctx: ExecutorContext): Promise<string>;
|
|
75
183
|
};
|
|
76
184
|
|
|
185
|
+
/** Where streamed chunks are written. */
|
|
77
186
|
export type OutputSink = {
|
|
187
|
+
/** Writes one chunk. */
|
|
78
188
|
write(chunk: Program): void | Promise<void>;
|
|
189
|
+
/** Closes the stream. */
|
|
79
190
|
close(): void | Promise<void>;
|
|
80
191
|
};
|
|
81
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Stamps an audit event with the current time.
|
|
195
|
+
*
|
|
196
|
+
* @param input - Event details, without a timestamp.
|
|
197
|
+
* @returns A complete event, ready to pass to {@link RuntimeContext.observe}.
|
|
198
|
+
* @example
|
|
199
|
+
* ```ts
|
|
200
|
+
* ctx.observe(createExecutionEvent({
|
|
201
|
+
* kind: "executor.start",
|
|
202
|
+
* requestId: ctx.requestId,
|
|
203
|
+
* executionId: ctx.executionId,
|
|
204
|
+
* }));
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
82
207
|
export function createExecutionEvent(
|
|
83
208
|
input: ExecutionEventInput,
|
|
84
209
|
): ExecutionEvent {
|