@neutrome/lilsdk 0.4.4 → 0.4.6
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 +2 -6
- package/etc/api/index.api.md +103 -0
- package/etc/api/loops.api.md +108 -0
- package/etc/api/managed.api.md +102 -0
- package/etc/api/primitives.api.md +39 -0
- package/etc/api/stream.api.md +55 -0
- package/etc/api/synthetic.api.md +46 -0
- package/etc/api/tools.api.md +103 -0
- package/etc/api/types.api.md +103 -0
- package/package.json +4 -3
- package/src/managed/capabilities.ts +27 -7
- package/src/managed/index.ts +0 -14
- package/src/tools-support.ts +52 -27
- package/src/tools.ts +1 -1
- package/test/lilsdk-ts.test.ts +29 -301
- package/test/tools.test.ts +55 -9
- package/src/managed/two-pass-request.ts +0 -164
- package/src/managed/two-pass.ts +0 -171
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
appendInstructions,
|
|
3
|
-
contentText,
|
|
4
|
-
insertBefore,
|
|
5
|
-
messageText,
|
|
6
|
-
messages,
|
|
7
|
-
removeRange,
|
|
8
|
-
type Program,
|
|
9
|
-
} from "@neutrome/lil-engine";
|
|
10
|
-
import { Opcode } from "@neutrome/lil-engine";
|
|
11
|
-
import {
|
|
12
|
-
appendToolInteraction,
|
|
13
|
-
makeMessage,
|
|
14
|
-
prependSystemPrompt,
|
|
15
|
-
} from "../synthetic/index.ts";
|
|
16
|
-
import type { ExecutorContext } from "../types.ts";
|
|
17
|
-
|
|
18
|
-
export const INTERNAL_DRAFT_TOOL_NAME = "knowledge";
|
|
19
|
-
export const INTERNAL_DRAFT_CALL_ID = "knowledge_0";
|
|
20
|
-
|
|
21
|
-
export type InternalDraft =
|
|
22
|
-
| string
|
|
23
|
-
| readonly string[]
|
|
24
|
-
| readonly { text: string }[];
|
|
25
|
-
|
|
26
|
-
export type TwoPassSettings = {
|
|
27
|
-
reasoningLevel?: string;
|
|
28
|
-
systemPrompt?: string;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export type TwoPassSettingsResolver = (
|
|
32
|
-
request: Program,
|
|
33
|
-
ctx: ExecutorContext,
|
|
34
|
-
) => TwoPassSettings | null | Promise<TwoPassSettings | null>;
|
|
35
|
-
|
|
36
|
-
export type TwoPassRequestOptions = {
|
|
37
|
-
maxTotalContextLength?: number;
|
|
38
|
-
buildFinalRequest?: (request: Program, draft: string) => Program;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export function appendInternalDraft(
|
|
42
|
-
request: Program,
|
|
43
|
-
draft: InternalDraft,
|
|
44
|
-
options: { callId?: string } = {},
|
|
45
|
-
): Program {
|
|
46
|
-
const callId = options.callId ?? INTERNAL_DRAFT_CALL_ID;
|
|
47
|
-
const drafts = normalizeDrafts(draft);
|
|
48
|
-
if (drafts.length === 0) return request;
|
|
49
|
-
return drafts.reduce(
|
|
50
|
-
(program, text, index) =>
|
|
51
|
-
appendToolInteraction(program, {
|
|
52
|
-
callId: drafts.length === 1 ? callId : `${callId}_${index}`,
|
|
53
|
-
name: INTERNAL_DRAFT_TOOL_NAME,
|
|
54
|
-
args: {},
|
|
55
|
-
result: text,
|
|
56
|
-
}),
|
|
57
|
-
request,
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
export function buildDraftRequest(
|
|
62
|
-
request: Program,
|
|
63
|
-
settings: TwoPassSettings,
|
|
64
|
-
): Program {
|
|
65
|
-
const withPrompt = settings.systemPrompt
|
|
66
|
-
? replaceSystemPrompt(request, settings.systemPrompt)
|
|
67
|
-
: request;
|
|
68
|
-
return applySettings(withPrompt, settings);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export function buildFinalRequest(
|
|
72
|
-
options: TwoPassRequestOptions,
|
|
73
|
-
request: Program,
|
|
74
|
-
settings: TwoPassSettings,
|
|
75
|
-
draft: string,
|
|
76
|
-
): Program {
|
|
77
|
-
const limitedDraft = limitDraft(options, request, settings, draft);
|
|
78
|
-
const withDraft = options.buildFinalRequest
|
|
79
|
-
? options.buildFinalRequest(request, limitedDraft)
|
|
80
|
-
: appendInternalDraft(request, limitedDraft);
|
|
81
|
-
const withPrompt = settings.systemPrompt
|
|
82
|
-
? prependSystemPrompt(withDraft, settings.systemPrompt)
|
|
83
|
-
: withDraft;
|
|
84
|
-
return applySettings(withPrompt, settings);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function validateMaxContextLength(value: number | undefined): void {
|
|
88
|
-
if (value !== undefined && (!Number.isSafeInteger(value) || value < 0)) {
|
|
89
|
-
throw new Error("maxTotalContextLength must be a non-negative integer");
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function replaceSystemPrompt(request: Program, systemPrompt: string): Program {
|
|
94
|
-
const systemSpans = messages(request).filter(
|
|
95
|
-
(span) => span.role === "system",
|
|
96
|
-
);
|
|
97
|
-
const previousSystemPrompt = systemSpans
|
|
98
|
-
.map((span) => messageText(request, span).trim())
|
|
99
|
-
.filter(Boolean)
|
|
100
|
-
.join("\n\n");
|
|
101
|
-
let draft = request;
|
|
102
|
-
for (const span of systemSpans.slice().reverse()) {
|
|
103
|
-
draft = removeRange(draft, span.start, span.end);
|
|
104
|
-
}
|
|
105
|
-
draft = prependSystemPrompt(draft, systemPrompt);
|
|
106
|
-
if (!previousSystemPrompt) return draft;
|
|
107
|
-
const firstNonSystem = messages(draft).find((span) => span.role !== "system");
|
|
108
|
-
return insertBefore(
|
|
109
|
-
draft,
|
|
110
|
-
firstNonSystem?.start ?? draft.code.length,
|
|
111
|
-
makeMessage("user", previousSystemPrompt).code,
|
|
112
|
-
);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function applySettings(request: Program, settings: TwoPassSettings): Program {
|
|
116
|
-
if (!settings.reasoningLevel) return request;
|
|
117
|
-
return appendInstructions(
|
|
118
|
-
{
|
|
119
|
-
...request,
|
|
120
|
-
code: request.code.filter(
|
|
121
|
-
(instruction) => instruction.opcode !== Opcode.SET_REASON_EFFORT,
|
|
122
|
-
),
|
|
123
|
-
},
|
|
124
|
-
[
|
|
125
|
-
{
|
|
126
|
-
opcode: Opcode.SET_REASON_EFFORT,
|
|
127
|
-
value: { kind: "string", value: settings.reasoningLevel },
|
|
128
|
-
},
|
|
129
|
-
],
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function limitDraft(
|
|
134
|
-
options: TwoPassRequestOptions,
|
|
135
|
-
request: Program,
|
|
136
|
-
settings: TwoPassSettings,
|
|
137
|
-
draft: string,
|
|
138
|
-
): string {
|
|
139
|
-
if (options.maxTotalContextLength === undefined) return draft;
|
|
140
|
-
const base = buildFinalRequestWithoutDraft(options, request, settings);
|
|
141
|
-
const available = options.maxTotalContextLength - contentText(base).length;
|
|
142
|
-
return available > 0 ? draft.slice(0, available) : "";
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function buildFinalRequestWithoutDraft(
|
|
146
|
-
options: TwoPassRequestOptions,
|
|
147
|
-
request: Program,
|
|
148
|
-
settings: TwoPassSettings,
|
|
149
|
-
): Program {
|
|
150
|
-
const withDraft = options.buildFinalRequest
|
|
151
|
-
? options.buildFinalRequest(request, "")
|
|
152
|
-
: request;
|
|
153
|
-
const withPrompt = settings.systemPrompt
|
|
154
|
-
? prependSystemPrompt(withDraft, settings.systemPrompt)
|
|
155
|
-
: withDraft;
|
|
156
|
-
return applySettings(withPrompt, settings);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function normalizeDrafts(draft: InternalDraft): string[] {
|
|
160
|
-
const drafts = Array.isArray(draft)
|
|
161
|
-
? draft.map((item) => (typeof item === "string" ? item : item.text))
|
|
162
|
-
: [draft];
|
|
163
|
-
return drafts.map((text) => text.trim()).filter((text) => text.length > 0);
|
|
164
|
-
}
|
package/src/managed/two-pass.ts
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
callData,
|
|
3
|
-
contentText,
|
|
4
|
-
createProgram,
|
|
5
|
-
deltaText,
|
|
6
|
-
finishReason,
|
|
7
|
-
hasToolDelta,
|
|
8
|
-
lastMessageRole,
|
|
9
|
-
type Program,
|
|
10
|
-
} from "@neutrome/lil-engine";
|
|
11
|
-
import { streamReasoningDelta } from "../output.ts";
|
|
12
|
-
import { completeStream, streamStage } from "../stream/stages.ts";
|
|
13
|
-
import type { Executor, ExecutorContext, ExecutorInput } from "../types.ts";
|
|
14
|
-
import {
|
|
15
|
-
appendInternalDraft,
|
|
16
|
-
buildDraftRequest,
|
|
17
|
-
buildFinalRequest,
|
|
18
|
-
INTERNAL_DRAFT_CALL_ID,
|
|
19
|
-
INTERNAL_DRAFT_TOOL_NAME,
|
|
20
|
-
validateMaxContextLength,
|
|
21
|
-
type InternalDraft,
|
|
22
|
-
type TwoPassRequestOptions,
|
|
23
|
-
type TwoPassSettings,
|
|
24
|
-
type TwoPassSettingsResolver,
|
|
25
|
-
} from "./two-pass-request.ts";
|
|
26
|
-
|
|
27
|
-
export type {
|
|
28
|
-
InternalDraft,
|
|
29
|
-
TwoPassSettings,
|
|
30
|
-
TwoPassSettingsResolver,
|
|
31
|
-
} from "./two-pass-request.ts";
|
|
32
|
-
export {
|
|
33
|
-
appendInternalDraft,
|
|
34
|
-
INTERNAL_DRAFT_CALL_ID,
|
|
35
|
-
INTERNAL_DRAFT_TOOL_NAME,
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export type TwoPassExecutorOptions = TwoPassRequestOptions & {
|
|
39
|
-
draft: ExecutorInput;
|
|
40
|
-
final: ExecutorInput;
|
|
41
|
-
resolveDraftSettings?: TwoPassSettingsResolver;
|
|
42
|
-
resolveFinalSettings?: TwoPassSettingsResolver;
|
|
43
|
-
reasoningIntro?: string;
|
|
44
|
-
reasoningSeparator?: string;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
export function createTwoPassExecutor(
|
|
48
|
-
options: TwoPassExecutorOptions,
|
|
49
|
-
): Executor {
|
|
50
|
-
const reasoningIntro = options.reasoningIntro ?? "Let me think...\n\n";
|
|
51
|
-
const reasoningSeparator = options.reasoningSeparator ?? "\n\n";
|
|
52
|
-
validateMaxContextLength(options.maxTotalContextLength);
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
async execute(request, ctx) {
|
|
56
|
-
const settings = await resolveSettings(options, request, ctx);
|
|
57
|
-
if (!settings.draft) {
|
|
58
|
-
return invokeFinal(options, request, ctx, settings.final!);
|
|
59
|
-
}
|
|
60
|
-
const draftRequest = buildDraftRequest(request, settings.draft);
|
|
61
|
-
if (!settings.final || lastMessageRole(request) === "tool") {
|
|
62
|
-
return ctx.invoke(options.draft, draftRequest);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const draftResponse = await ctx.invoke(options.draft, draftRequest);
|
|
66
|
-
if (callData(draftResponse).length > 0) return draftResponse;
|
|
67
|
-
|
|
68
|
-
return invokeFinal(
|
|
69
|
-
options,
|
|
70
|
-
request,
|
|
71
|
-
ctx,
|
|
72
|
-
settings.final,
|
|
73
|
-
contentText(draftResponse),
|
|
74
|
-
);
|
|
75
|
-
},
|
|
76
|
-
|
|
77
|
-
async *stream(request, ctx) {
|
|
78
|
-
const settings = await resolveSettings(options, request, ctx);
|
|
79
|
-
if (!settings.draft) {
|
|
80
|
-
yield* streamFinal(options, request, ctx, settings.final!);
|
|
81
|
-
return;
|
|
82
|
-
}
|
|
83
|
-
const draftRequest = buildDraftRequest(request, settings.draft);
|
|
84
|
-
if (!settings.final || lastMessageRole(request) === "tool") {
|
|
85
|
-
yield* ctx.invokeStream(options.draft, draftRequest);
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
let transcript = "";
|
|
90
|
-
let emittedReasoning = false;
|
|
91
|
-
let toolMode = false;
|
|
92
|
-
for await (const chunk of streamStage(
|
|
93
|
-
ctx.invokeStream(options.draft, draftRequest),
|
|
94
|
-
)) {
|
|
95
|
-
if (ctx.signal.aborted) return;
|
|
96
|
-
if (toolMode) {
|
|
97
|
-
yield chunk;
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
if (hasToolDelta(chunk) || finishReason(chunk) === "tool_calls") {
|
|
101
|
-
toolMode = true;
|
|
102
|
-
yield chunk;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
const text = deltaText(chunk);
|
|
106
|
-
if (!text) continue;
|
|
107
|
-
transcript += text;
|
|
108
|
-
if (!emittedReasoning) {
|
|
109
|
-
emittedReasoning = true;
|
|
110
|
-
yield streamReasoningDelta(reasoningIntro);
|
|
111
|
-
}
|
|
112
|
-
yield streamReasoningDelta(text);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (ctx.signal.aborted) return;
|
|
116
|
-
if (toolMode) {
|
|
117
|
-
yield completeStream("tool_calls");
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
if (emittedReasoning && reasoningSeparator) {
|
|
121
|
-
yield streamReasoningDelta(reasoningSeparator);
|
|
122
|
-
}
|
|
123
|
-
yield* streamFinal(options, request, ctx, settings.final, transcript);
|
|
124
|
-
},
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function resolveSettings(
|
|
129
|
-
options: TwoPassExecutorOptions,
|
|
130
|
-
request: Program,
|
|
131
|
-
ctx: ExecutorContext,
|
|
132
|
-
): Promise<{ draft: TwoPassSettings | null; final: TwoPassSettings | null }> {
|
|
133
|
-
const [draft, final] = await Promise.all([
|
|
134
|
-
options.resolveDraftSettings
|
|
135
|
-
? options.resolveDraftSettings(request, ctx)
|
|
136
|
-
: {},
|
|
137
|
-
options.resolveFinalSettings
|
|
138
|
-
? options.resolveFinalSettings(request, ctx)
|
|
139
|
-
: {},
|
|
140
|
-
]);
|
|
141
|
-
if (!draft && !final) {
|
|
142
|
-
throw new Error("Two-pass executor requires at least one enabled pass");
|
|
143
|
-
}
|
|
144
|
-
return { draft, final };
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function invokeFinal(
|
|
148
|
-
options: TwoPassExecutorOptions,
|
|
149
|
-
request: Program,
|
|
150
|
-
ctx: ExecutorContext,
|
|
151
|
-
settings: TwoPassSettings,
|
|
152
|
-
draft = "",
|
|
153
|
-
): Promise<Program> {
|
|
154
|
-
return ctx.invoke(
|
|
155
|
-
options.final,
|
|
156
|
-
buildFinalRequest(options, request, settings, draft),
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
async function* streamFinal(
|
|
161
|
-
options: TwoPassExecutorOptions,
|
|
162
|
-
request: Program,
|
|
163
|
-
ctx: ExecutorContext,
|
|
164
|
-
settings: TwoPassSettings,
|
|
165
|
-
draft = "",
|
|
166
|
-
): AsyncIterable<Program> {
|
|
167
|
-
yield* ctx.invokeStream(
|
|
168
|
-
options.final,
|
|
169
|
-
buildFinalRequest(options, request, settings, draft),
|
|
170
|
-
);
|
|
171
|
-
}
|