@code-yeongyu/senpi-ai 2026.9.12 → 2026.9.13
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 +39 -4
- package/dist/api/anthropic-messages.d.ts.map +1 -1
- package/dist/api/anthropic-messages.js +8 -1
- package/dist/api/anthropic-messages.js.map +1 -1
- package/dist/api/cloudflare-ai-binding.d.ts +77 -0
- package/dist/api/cloudflare-ai-binding.d.ts.map +1 -0
- package/dist/api/cloudflare-ai-binding.js +72 -0
- package/dist/api/cloudflare-ai-binding.js.map +1 -0
- package/dist/api/cursor-agent/measure.d.ts +11 -0
- package/dist/api/cursor-agent/measure.d.ts.map +1 -1
- package/dist/api/cursor-agent/measure.js +18 -0
- package/dist/api/cursor-agent/measure.js.map +1 -1
- package/dist/api/cursor-agent.d.ts +1 -1
- package/dist/api/cursor-agent.d.ts.map +1 -1
- package/dist/api/cursor-agent.js +5 -1
- package/dist/api/cursor-agent.js.map +1 -1
- package/dist/api/mistral-conversations.js +4 -1
- package/dist/api/mistral-conversations.js.map +1 -1
- package/dist/api/openai-codex-responses.d.ts.map +1 -1
- package/dist/api/openai-codex-responses.js +6 -3
- package/dist/api/openai-codex-responses.js.map +1 -1
- package/dist/api/openai-responses-shared.d.ts.map +1 -1
- package/dist/api/openai-responses-shared.js +4 -1
- package/dist/api/openai-responses-shared.js.map +1 -1
- package/dist/api/openai-responses.d.ts.map +1 -1
- package/dist/api/openai-responses.js +13 -3
- package/dist/api/openai-responses.js.map +1 -1
- package/dist/cursor/context-limit-store.d.ts +32 -0
- package/dist/cursor/context-limit-store.d.ts.map +1 -0
- package/dist/cursor/context-limit-store.js +62 -0
- package/dist/cursor/context-limit-store.js.map +1 -0
- package/dist/cursor/store-migration.d.ts.map +1 -1
- package/dist/cursor/store-migration.js +2 -1
- package/dist/cursor/store-migration.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/models.d.ts +1 -0
- package/dist/models.d.ts.map +1 -1
- package/dist/models.js +5 -2
- package/dist/models.js.map +1 -1
- package/dist/openai-responses-compat.d.ts +1 -1
- package/dist/openai-responses-compat.d.ts.map +1 -1
- package/dist/openai-responses-compat.js.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.d.ts.map +1 -1
- package/dist/providers/cloudflare-ai-gateway.js +4 -0
- package/dist/providers/cloudflare-ai-gateway.js.map +1 -1
- package/dist/providers/cursor.d.ts.map +1 -1
- package/dist/providers/cursor.js +2 -1
- package/dist/providers/cursor.js.map +1 -1
- package/dist/providers/data/.manifest.json +1 -1
- package/dist/providers/data/azure-openai-responses.json +1 -1
- package/dist/providers/data/baseten.json +1 -1
- package/dist/providers/data/deepseek.json +1 -1
- package/dist/providers/data/fireworks.json +1 -1
- package/dist/providers/data/github-copilot.json +1 -1
- package/dist/providers/data/openai-codex.json +1 -1
- package/dist/providers/data/openrouter.json +1 -1
- package/dist/providers/data/qwen-token-plan-cn.json +1 -1
- package/dist/providers/data/qwen-token-plan-individual.json +1 -1
- package/dist/providers/data/qwen-token-plan.json +1 -1
- package/dist/providers/data/vercel-ai-gateway.json +1 -1
- package/dist/providers/data/xai.json +1 -1
- package/dist/providers/faux.js +5 -5
- package/dist/providers/faux.js.map +1 -1
- package/dist/providers/opencode-go.d.ts.map +1 -1
- package/dist/providers/opencode-go.js +4 -3
- package/dist/providers/opencode-go.js.map +1 -1
- package/dist/providers/opencode-headers.d.ts +4 -0
- package/dist/providers/opencode-headers.d.ts.map +1 -0
- package/dist/providers/opencode-headers.js +22 -0
- package/dist/providers/opencode-headers.js.map +1 -0
- package/dist/providers/opencode.d.ts.map +1 -1
- package/dist/providers/opencode.js +5 -4
- package/dist/providers/opencode.js.map +1 -1
- package/dist/types.d.ts +16 -6
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/assistant-message-frame.d.ts +77 -0
- package/dist/utils/assistant-message-frame.d.ts.map +1 -0
- package/dist/utils/assistant-message-frame.js +427 -0
- package/dist/utils/assistant-message-frame.js.map +1 -0
- package/dist/utils/cursor-context-limit.d.ts +12 -0
- package/dist/utils/cursor-context-limit.d.ts.map +1 -0
- package/dist/utils/cursor-context-limit.js +93 -0
- package/dist/utils/cursor-context-limit.js.map +1 -0
- package/dist/utils/event-stream.d.ts.map +1 -1
- package/dist/utils/event-stream.js +25 -5
- package/dist/utils/event-stream.js.map +1 -1
- package/dist/utils/prompt-cache-ttl.d.ts +1 -1
- package/dist/utils/prompt-cache-ttl.d.ts.map +1 -1
- package/dist/utils/prompt-cache-ttl.js +5 -1
- package/dist/utils/prompt-cache-ttl.js.map +1 -1
- package/dist/utils/retry-profile/types.d.ts +10 -1
- package/dist/utils/retry-profile/types.d.ts.map +1 -1
- package/dist/utils/retry-profile/types.js.map +1 -1
- package/dist/utils/retry.d.ts +13 -2
- package/dist/utils/retry.d.ts.map +1 -1
- package/dist/utils/retry.js +18 -7
- package/dist/utils/retry.js.map +1 -1
- package/dist/utils/uuid.d.ts +2 -2
- package/dist/utils/uuid.d.ts.map +1 -1
- package/dist/utils/uuid.js +36 -31
- package/dist/utils/uuid.js.map +1 -1
- package/package.json +6 -6
- package/dist/api/cloudflare-gateway-binding.d.ts +0 -69
- package/dist/api/cloudflare-gateway-binding.d.ts.map +0 -1
- package/dist/api/cloudflare-gateway-binding.js +0 -159
- package/dist/api/cloudflare-gateway-binding.js.map +0 -1
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { parseStreamingJson } from "./json-parse.js";
|
|
2
|
+
function cloneTextContent(content) {
|
|
3
|
+
return {
|
|
4
|
+
type: "text",
|
|
5
|
+
text: content.text,
|
|
6
|
+
...(content.textSignature === undefined ? {} : { textSignature: content.textSignature }),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function cloneThinkingContent(content) {
|
|
10
|
+
return {
|
|
11
|
+
type: "thinking",
|
|
12
|
+
thinking: content.thinking,
|
|
13
|
+
...(content.thinkingSignature === undefined ? {} : { thinkingSignature: content.thinkingSignature }),
|
|
14
|
+
...(content.redacted === undefined ? {} : { redacted: content.redacted }),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function cloneToolCall(toolCall) {
|
|
18
|
+
return {
|
|
19
|
+
type: "toolCall",
|
|
20
|
+
id: toolCall.id,
|
|
21
|
+
name: toolCall.name,
|
|
22
|
+
arguments: structuredClone(toolCall.arguments),
|
|
23
|
+
...(toolCall.thoughtSignature === undefined ? {} : { thoughtSignature: toolCall.thoughtSignature }),
|
|
24
|
+
...(toolCall.namespace === undefined ? {} : { namespace: toolCall.namespace }),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function cloneStartMessage(message) {
|
|
28
|
+
return {
|
|
29
|
+
role: "assistant",
|
|
30
|
+
content: [],
|
|
31
|
+
api: message.api,
|
|
32
|
+
provider: message.provider,
|
|
33
|
+
model: message.model,
|
|
34
|
+
...(message.responseModel === undefined ? {} : { responseModel: message.responseModel }),
|
|
35
|
+
...(message.responseId === undefined ? {} : { responseId: message.responseId }),
|
|
36
|
+
...(message.providerThinkingLevel === undefined ? {} : { providerThinkingLevel: message.providerThinkingLevel }),
|
|
37
|
+
...(message.diagnostics === undefined ? {} : { diagnostics: structuredClone(message.diagnostics) }),
|
|
38
|
+
usage: structuredClone(message.usage),
|
|
39
|
+
stopReason: "pending",
|
|
40
|
+
timestamp: message.timestamp,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function assertContentIndex(contentIndex) {
|
|
44
|
+
if (!Number.isSafeInteger(contentIndex) || contentIndex < 0) {
|
|
45
|
+
throw new Error(`Invalid assistant message frame contentIndex: ${contentIndex}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function eventBlock(event) {
|
|
49
|
+
assertContentIndex(event.contentIndex);
|
|
50
|
+
const block = event.partial.content[event.contentIndex];
|
|
51
|
+
if (!block) {
|
|
52
|
+
throw new Error(`${event.type} event has no content block at index ${event.contentIndex}`);
|
|
53
|
+
}
|
|
54
|
+
return block;
|
|
55
|
+
}
|
|
56
|
+
function serializedArguments(argumentsValue) {
|
|
57
|
+
const serialized = JSON.stringify(argumentsValue);
|
|
58
|
+
if (serialized === undefined)
|
|
59
|
+
throw new Error("Tool-call arguments are not JSON-serializable");
|
|
60
|
+
return serialized;
|
|
61
|
+
}
|
|
62
|
+
const EMPTY_PARSED_TOOL_ARGUMENTS = serializedArguments(parseStreamingJson(""));
|
|
63
|
+
function isJsonPrefix(snapshot, current) {
|
|
64
|
+
if (typeof snapshot === "string")
|
|
65
|
+
return typeof current === "string" && current.startsWith(snapshot);
|
|
66
|
+
if (Array.isArray(snapshot)) {
|
|
67
|
+
return (Array.isArray(current) &&
|
|
68
|
+
snapshot.length <= current.length &&
|
|
69
|
+
snapshot.every((value, index) => isJsonPrefix(value, current[index])));
|
|
70
|
+
}
|
|
71
|
+
if (typeof snapshot !== "object" || snapshot === null)
|
|
72
|
+
return Object.is(snapshot, current);
|
|
73
|
+
if (typeof current !== "object" || current === null || Array.isArray(current))
|
|
74
|
+
return false;
|
|
75
|
+
const currentRecord = current;
|
|
76
|
+
return Object.entries(snapshot).every(([key, value]) => Object.hasOwn(currentRecord, key) && isJsonPrefix(value, currentRecord[key]));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Encodes one assistant stream. `partial` remains a shared live accumulator;
|
|
80
|
+
* the encoder uses per-block offsets to avoid replaying deltas already visible
|
|
81
|
+
* when an older queued event is consumed.
|
|
82
|
+
*/
|
|
83
|
+
export class AssistantMessageFrameEncoder {
|
|
84
|
+
constructor() {
|
|
85
|
+
this.started = false;
|
|
86
|
+
this.terminal = false;
|
|
87
|
+
this.blocks = new Map();
|
|
88
|
+
}
|
|
89
|
+
encode(event) {
|
|
90
|
+
if (this.terminal)
|
|
91
|
+
throw new Error(`Assistant message event ${event.type} follows a terminal event`);
|
|
92
|
+
switch (event.type) {
|
|
93
|
+
case "start":
|
|
94
|
+
if (this.started)
|
|
95
|
+
throw new Error("Assistant message stream contains more than one start event");
|
|
96
|
+
this.started = true;
|
|
97
|
+
return { type: "start", partial: cloneStartMessage(event.partial) };
|
|
98
|
+
case "done":
|
|
99
|
+
if (!this.started)
|
|
100
|
+
throw new Error("Assistant message done event appears before start");
|
|
101
|
+
this.terminal = true;
|
|
102
|
+
return undefined;
|
|
103
|
+
case "error":
|
|
104
|
+
this.terminal = true;
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
if (!this.started)
|
|
108
|
+
throw new Error(`Assistant message ${event.type} event appears before start`);
|
|
109
|
+
switch (event.type) {
|
|
110
|
+
case "text_start": {
|
|
111
|
+
const content = eventBlock(event);
|
|
112
|
+
if (content.type !== "text") {
|
|
113
|
+
throw new Error(`text_start event points to ${content.type} block at index ${event.contentIndex}`);
|
|
114
|
+
}
|
|
115
|
+
this.startBlock(event.contentIndex, {
|
|
116
|
+
kind: "text",
|
|
117
|
+
coveredChars: content.text.length,
|
|
118
|
+
deltaChars: 0,
|
|
119
|
+
});
|
|
120
|
+
return { type: "text_start", contentIndex: event.contentIndex, content: cloneTextContent(content) };
|
|
121
|
+
}
|
|
122
|
+
case "text_delta":
|
|
123
|
+
return this.encodeTextDelta(event.contentIndex, event.delta, "text");
|
|
124
|
+
case "text_end": {
|
|
125
|
+
const content = eventBlock(event);
|
|
126
|
+
if (content.type !== "text") {
|
|
127
|
+
throw new Error(`text_end event points to ${content.type} block at index ${event.contentIndex}`);
|
|
128
|
+
}
|
|
129
|
+
this.endBlock(event.contentIndex, "text");
|
|
130
|
+
return {
|
|
131
|
+
type: "text_end",
|
|
132
|
+
contentIndex: event.contentIndex,
|
|
133
|
+
content: event.content,
|
|
134
|
+
...(content.textSignature === undefined ? {} : { textSignature: content.textSignature }),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case "thinking_start": {
|
|
138
|
+
const content = eventBlock(event);
|
|
139
|
+
if (content.type !== "thinking") {
|
|
140
|
+
throw new Error(`thinking_start event points to ${content.type} block at index ${event.contentIndex}`);
|
|
141
|
+
}
|
|
142
|
+
this.startBlock(event.contentIndex, {
|
|
143
|
+
kind: "thinking",
|
|
144
|
+
coveredChars: content.thinking.length,
|
|
145
|
+
deltaChars: 0,
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
type: "thinking_start",
|
|
149
|
+
contentIndex: event.contentIndex,
|
|
150
|
+
content: cloneThinkingContent(content),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
case "thinking_delta":
|
|
154
|
+
return this.encodeTextDelta(event.contentIndex, event.delta, "thinking");
|
|
155
|
+
case "thinking_end": {
|
|
156
|
+
const content = eventBlock(event);
|
|
157
|
+
if (content.type !== "thinking") {
|
|
158
|
+
throw new Error(`thinking_end event points to ${content.type} block at index ${event.contentIndex}`);
|
|
159
|
+
}
|
|
160
|
+
this.endBlock(event.contentIndex, "thinking");
|
|
161
|
+
return {
|
|
162
|
+
type: "thinking_end",
|
|
163
|
+
contentIndex: event.contentIndex,
|
|
164
|
+
content: event.content,
|
|
165
|
+
...(content.thinkingSignature === undefined ? {} : { thinkingSignature: content.thinkingSignature }),
|
|
166
|
+
...(content.redacted === undefined ? {} : { redacted: content.redacted }),
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
case "toolcall_start": {
|
|
170
|
+
const content = eventBlock(event);
|
|
171
|
+
if (content.type !== "toolCall") {
|
|
172
|
+
throw new Error(`toolcall_start event points to ${content.type} block at index ${event.contentIndex}`);
|
|
173
|
+
}
|
|
174
|
+
const snapshotArguments = serializedArguments(content.arguments);
|
|
175
|
+
const caughtUp = snapshotArguments === EMPTY_PARSED_TOOL_ARGUMENTS;
|
|
176
|
+
this.startBlock(event.contentIndex, {
|
|
177
|
+
kind: "toolCall",
|
|
178
|
+
caughtUp,
|
|
179
|
+
catchupJson: "",
|
|
180
|
+
snapshotArguments: caughtUp ? "" : snapshotArguments,
|
|
181
|
+
});
|
|
182
|
+
return { type: "toolcall_start", contentIndex: event.contentIndex, toolCall: cloneToolCall(content) };
|
|
183
|
+
}
|
|
184
|
+
case "toolcall_delta": {
|
|
185
|
+
const state = this.block(event.contentIndex, "toolCall");
|
|
186
|
+
if (state.kind !== "toolCall")
|
|
187
|
+
throw new Error("Unreachable tool-call encoder state");
|
|
188
|
+
if (state.caughtUp) {
|
|
189
|
+
return event.delta.length === 0
|
|
190
|
+
? undefined
|
|
191
|
+
: { type: "toolcall_delta", contentIndex: event.contentIndex, delta: event.delta };
|
|
192
|
+
}
|
|
193
|
+
state.catchupJson += event.delta;
|
|
194
|
+
const argumentsValue = parseStreamingJson(state.catchupJson);
|
|
195
|
+
if (serializedArguments(argumentsValue) !== state.snapshotArguments) {
|
|
196
|
+
// Legacy grammar calls include the initial input in toolcall_start, but their
|
|
197
|
+
// JSON delta stream still begins at an empty input. Its parsed arguments can
|
|
198
|
+
// therefore extend, rather than exactly reproduce, the start snapshot.
|
|
199
|
+
const snapshotArguments = parseStreamingJson(state.snapshotArguments);
|
|
200
|
+
if (!isJsonPrefix(snapshotArguments, argumentsValue))
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
state.caughtUp = true;
|
|
204
|
+
state.snapshotArguments = "";
|
|
205
|
+
const json = state.catchupJson;
|
|
206
|
+
state.catchupJson = "";
|
|
207
|
+
return json.length === 0
|
|
208
|
+
? undefined
|
|
209
|
+
: { type: "toolcall_checkpoint", contentIndex: event.contentIndex, json };
|
|
210
|
+
}
|
|
211
|
+
case "toolcall_end": {
|
|
212
|
+
const content = eventBlock(event);
|
|
213
|
+
if (content.type !== "toolCall") {
|
|
214
|
+
throw new Error(`toolcall_end event points to ${content.type} block at index ${event.contentIndex}`);
|
|
215
|
+
}
|
|
216
|
+
if (event.toolCall.type !== "toolCall") {
|
|
217
|
+
throw new Error(`toolcall_end event has invalid tool call at index ${event.contentIndex}`);
|
|
218
|
+
}
|
|
219
|
+
this.endBlock(event.contentIndex, "toolCall");
|
|
220
|
+
return {
|
|
221
|
+
type: "toolcall_end",
|
|
222
|
+
contentIndex: event.contentIndex,
|
|
223
|
+
id: event.toolCall.id,
|
|
224
|
+
name: event.toolCall.name,
|
|
225
|
+
arguments: structuredClone(event.toolCall.arguments),
|
|
226
|
+
...(event.toolCall.thoughtSignature === undefined
|
|
227
|
+
? {}
|
|
228
|
+
: { thoughtSignature: event.toolCall.thoughtSignature }),
|
|
229
|
+
...(event.toolCall.namespace === undefined ? {} : { namespace: event.toolCall.namespace }),
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
startBlock(contentIndex, state) {
|
|
235
|
+
assertContentIndex(contentIndex);
|
|
236
|
+
if (this.blocks.has(contentIndex)) {
|
|
237
|
+
throw new Error(`Assistant message block ${contentIndex} starts more than once`);
|
|
238
|
+
}
|
|
239
|
+
this.blocks.set(contentIndex, state);
|
|
240
|
+
}
|
|
241
|
+
block(contentIndex, kind) {
|
|
242
|
+
assertContentIndex(contentIndex);
|
|
243
|
+
const state = this.blocks.get(contentIndex);
|
|
244
|
+
if (state === undefined)
|
|
245
|
+
throw new Error(`Assistant message ${kind} block ${contentIndex} has not started`);
|
|
246
|
+
if (state.kind !== kind) {
|
|
247
|
+
throw new Error(`Assistant message block ${contentIndex} is ${state.kind}, not ${kind}`);
|
|
248
|
+
}
|
|
249
|
+
return state;
|
|
250
|
+
}
|
|
251
|
+
endBlock(contentIndex, kind) {
|
|
252
|
+
this.block(contentIndex, kind);
|
|
253
|
+
this.blocks.delete(contentIndex);
|
|
254
|
+
}
|
|
255
|
+
encodeTextDelta(contentIndex, delta, kind) {
|
|
256
|
+
const state = this.block(contentIndex, kind);
|
|
257
|
+
if (state.kind === "toolCall")
|
|
258
|
+
throw new Error("Unreachable text encoder state");
|
|
259
|
+
const deltaStart = state.deltaChars;
|
|
260
|
+
state.deltaChars += delta.length;
|
|
261
|
+
const covered = Math.max(0, state.coveredChars - deltaStart);
|
|
262
|
+
if (covered >= delta.length)
|
|
263
|
+
return undefined;
|
|
264
|
+
const uncovered = covered === 0 ? delta : delta.slice(covered);
|
|
265
|
+
return kind === "text"
|
|
266
|
+
? { type: "text_delta", contentIndex, delta: uncovered }
|
|
267
|
+
: { type: "thinking_delta", contentIndex, delta: uncovered };
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
function appendBlock(message, states, contentIndex, block, state) {
|
|
271
|
+
assertContentIndex(contentIndex);
|
|
272
|
+
if (contentIndex !== message.content.length) {
|
|
273
|
+
const reason = contentIndex < message.content.length ? "already exists" : "would leave a gap";
|
|
274
|
+
throw new Error(`Cannot start assistant message block at index ${contentIndex}: ${reason}`);
|
|
275
|
+
}
|
|
276
|
+
message.content.push(structuredClone(block));
|
|
277
|
+
states.set(contentIndex, state);
|
|
278
|
+
}
|
|
279
|
+
function activeBlock(message, states, contentIndex, expectedKind, frameType) {
|
|
280
|
+
assertContentIndex(contentIndex);
|
|
281
|
+
const state = states.get(contentIndex);
|
|
282
|
+
const block = message.content[contentIndex];
|
|
283
|
+
if (!state || !block) {
|
|
284
|
+
throw new Error(`${frameType} frame has no started block at index ${contentIndex}`);
|
|
285
|
+
}
|
|
286
|
+
if (state.kind !== expectedKind || block.type !== expectedKind) {
|
|
287
|
+
throw new Error(`${frameType} frame expected ${expectedKind} block at index ${contentIndex}, found ${block.type}`);
|
|
288
|
+
}
|
|
289
|
+
if (state.ended) {
|
|
290
|
+
throw new Error(`${frameType} frame follows the end of block at index ${contentIndex}`);
|
|
291
|
+
}
|
|
292
|
+
return { block, state };
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Replay compact frames without mutating them. Returns `undefined` when the
|
|
296
|
+
* iterable contains no start frame.
|
|
297
|
+
*/
|
|
298
|
+
export function reduceAssistantMessageFrames(frames) {
|
|
299
|
+
let message;
|
|
300
|
+
let frameBeforeStart;
|
|
301
|
+
const states = new Map();
|
|
302
|
+
for (const frame of frames) {
|
|
303
|
+
if (frame.type === "start") {
|
|
304
|
+
if (message)
|
|
305
|
+
throw new Error("Assistant message frame sequence contains more than one start frame");
|
|
306
|
+
if (frameBeforeStart !== undefined)
|
|
307
|
+
throw new Error(`${frameBeforeStart} frame appears before the start frame`);
|
|
308
|
+
message = structuredClone(frame.partial);
|
|
309
|
+
continue;
|
|
310
|
+
}
|
|
311
|
+
if (!message) {
|
|
312
|
+
frameBeforeStart ??= frame.type;
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
switch (frame.type) {
|
|
316
|
+
case "text_start":
|
|
317
|
+
if (frame.content.type !== "text") {
|
|
318
|
+
throw new Error(`text_start frame contains ${frame.content.type} content`);
|
|
319
|
+
}
|
|
320
|
+
appendBlock(message, states, frame.contentIndex, frame.content, { kind: "text", ended: false });
|
|
321
|
+
break;
|
|
322
|
+
case "text_delta": {
|
|
323
|
+
const { block } = activeBlock(message, states, frame.contentIndex, "text", frame.type);
|
|
324
|
+
if (block.type !== "text")
|
|
325
|
+
throw new Error("Unreachable text frame state");
|
|
326
|
+
block.text += frame.delta;
|
|
327
|
+
break;
|
|
328
|
+
}
|
|
329
|
+
case "text_end": {
|
|
330
|
+
const { block, state } = activeBlock(message, states, frame.contentIndex, "text", frame.type);
|
|
331
|
+
if (block.type !== "text")
|
|
332
|
+
throw new Error("Unreachable text frame state");
|
|
333
|
+
block.text = frame.content;
|
|
334
|
+
delete block.textSignature;
|
|
335
|
+
if (frame.textSignature !== undefined)
|
|
336
|
+
block.textSignature = frame.textSignature;
|
|
337
|
+
state.ended = true;
|
|
338
|
+
break;
|
|
339
|
+
}
|
|
340
|
+
case "thinking_start":
|
|
341
|
+
if (frame.content.type !== "thinking") {
|
|
342
|
+
throw new Error(`thinking_start frame contains ${frame.content.type} content`);
|
|
343
|
+
}
|
|
344
|
+
appendBlock(message, states, frame.contentIndex, frame.content, {
|
|
345
|
+
kind: "thinking",
|
|
346
|
+
ended: false,
|
|
347
|
+
});
|
|
348
|
+
break;
|
|
349
|
+
case "thinking_delta": {
|
|
350
|
+
const { block } = activeBlock(message, states, frame.contentIndex, "thinking", frame.type);
|
|
351
|
+
if (block.type !== "thinking")
|
|
352
|
+
throw new Error("Unreachable thinking frame state");
|
|
353
|
+
block.thinking += frame.delta;
|
|
354
|
+
break;
|
|
355
|
+
}
|
|
356
|
+
case "thinking_end": {
|
|
357
|
+
const { block, state } = activeBlock(message, states, frame.contentIndex, "thinking", frame.type);
|
|
358
|
+
if (block.type !== "thinking")
|
|
359
|
+
throw new Error("Unreachable thinking frame state");
|
|
360
|
+
block.thinking = frame.content;
|
|
361
|
+
delete block.thinkingSignature;
|
|
362
|
+
delete block.redacted;
|
|
363
|
+
if (frame.thinkingSignature !== undefined)
|
|
364
|
+
block.thinkingSignature = frame.thinkingSignature;
|
|
365
|
+
if (frame.redacted !== undefined)
|
|
366
|
+
block.redacted = frame.redacted;
|
|
367
|
+
state.ended = true;
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
case "toolcall_start":
|
|
371
|
+
if (frame.toolCall.type !== "toolCall") {
|
|
372
|
+
throw new Error(`toolcall_start frame contains ${frame.toolCall.type} content`);
|
|
373
|
+
}
|
|
374
|
+
appendBlock(message, states, frame.contentIndex, frame.toolCall, {
|
|
375
|
+
kind: "toolCall",
|
|
376
|
+
ended: false,
|
|
377
|
+
json: "",
|
|
378
|
+
});
|
|
379
|
+
break;
|
|
380
|
+
case "toolcall_checkpoint": {
|
|
381
|
+
const { block, state } = activeBlock(message, states, frame.contentIndex, "toolCall", frame.type);
|
|
382
|
+
if (block.type !== "toolCall" || state.kind !== "toolCall") {
|
|
383
|
+
throw new Error("Unreachable tool-call checkpoint state");
|
|
384
|
+
}
|
|
385
|
+
state.json = frame.json;
|
|
386
|
+
block.arguments = parseStreamingJson(frame.json);
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
case "toolcall_delta": {
|
|
390
|
+
const { block, state } = activeBlock(message, states, frame.contentIndex, "toolCall", frame.type);
|
|
391
|
+
if (block.type !== "toolCall" || state.kind !== "toolCall") {
|
|
392
|
+
throw new Error("Unreachable tool-call frame state");
|
|
393
|
+
}
|
|
394
|
+
state.json += frame.delta;
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
397
|
+
case "toolcall_end": {
|
|
398
|
+
const { block, state } = activeBlock(message, states, frame.contentIndex, "toolCall", frame.type);
|
|
399
|
+
if (block.type !== "toolCall")
|
|
400
|
+
throw new Error("Unreachable tool-call frame state");
|
|
401
|
+
block.id = frame.id;
|
|
402
|
+
block.name = frame.name;
|
|
403
|
+
block.arguments = structuredClone(frame.arguments);
|
|
404
|
+
delete block.thoughtSignature;
|
|
405
|
+
delete block.namespace;
|
|
406
|
+
if (frame.thoughtSignature !== undefined)
|
|
407
|
+
block.thoughtSignature = frame.thoughtSignature;
|
|
408
|
+
if (frame.namespace !== undefined)
|
|
409
|
+
block.namespace = frame.namespace;
|
|
410
|
+
state.ended = true;
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
if (!message)
|
|
416
|
+
return undefined;
|
|
417
|
+
for (const [contentIndex, state] of states) {
|
|
418
|
+
if (state.kind !== "toolCall" || state.ended || state.json.length === 0)
|
|
419
|
+
continue;
|
|
420
|
+
const block = message.content[contentIndex];
|
|
421
|
+
if (block?.type !== "toolCall")
|
|
422
|
+
throw new Error("Unreachable tool-call frame state");
|
|
423
|
+
block.arguments = parseStreamingJson(state.json);
|
|
424
|
+
}
|
|
425
|
+
return message;
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=assistant-message-frame.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assistant-message-frame.js","sourceRoot":"","sources":["../../src/utils/assistant-message-frame.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AssistantMessage, AssistantMessageEvent, TextContent, ThinkingContent, ToolCall } from \"../types.ts\";\nimport { parseStreamingJson } from \"./json-parse.ts\";\n\n/**\n * Compact, replayable assistant-message progress. Terminal settlement is\n * intentionally excluded and must be persisted separately.\n */\nexport type AssistantMessageFrame =\n\t| { type: \"start\"; partial: AssistantMessage }\n\t| { type: \"text_start\"; contentIndex: number; content: TextContent }\n\t| { type: \"text_delta\"; contentIndex: number; delta: string }\n\t| { type: \"text_end\"; contentIndex: number; content: string; textSignature?: string }\n\t| { type: \"thinking_start\"; contentIndex: number; content: ThinkingContent }\n\t| { type: \"thinking_delta\"; contentIndex: number; delta: string }\n\t| {\n\t\t\ttype: \"thinking_end\";\n\t\t\tcontentIndex: number;\n\t\t\tcontent: string;\n\t\t\tthinkingSignature?: string;\n\t\t\tredacted?: boolean;\n\t }\n\t| { type: \"toolcall_start\"; contentIndex: number; toolCall: ToolCall }\n\t| { type: \"toolcall_checkpoint\"; contentIndex: number; json: string }\n\t| { type: \"toolcall_delta\"; contentIndex: number; delta: string }\n\t| {\n\t\t\ttype: \"toolcall_end\";\n\t\t\tcontentIndex: number;\n\t\t\tid: string;\n\t\t\tname: string;\n\t\t\targuments: ToolCall[\"arguments\"];\n\t\t\tthoughtSignature?: string;\n\t\t\tnamespace?: string;\n\t };\n\ntype EncoderBlockState =\n\t| { kind: \"text\" | \"thinking\"; coveredChars: number; deltaChars: number }\n\t| {\n\t\t\tkind: \"toolCall\";\n\t\t\tcaughtUp: boolean;\n\t\t\tcatchupJson: string;\n\t\t\tsnapshotArguments: string;\n\t };\n\ntype ReducerBlockState =\n\t| { kind: \"text\"; ended: boolean }\n\t| { kind: \"thinking\"; ended: boolean }\n\t| { kind: \"toolCall\"; ended: boolean; json: string };\n\nfunction cloneTextContent(content: TextContent): TextContent {\n\treturn {\n\t\ttype: \"text\",\n\t\ttext: content.text,\n\t\t...(content.textSignature === undefined ? {} : { textSignature: content.textSignature }),\n\t};\n}\n\nfunction cloneThinkingContent(content: ThinkingContent): ThinkingContent {\n\treturn {\n\t\ttype: \"thinking\",\n\t\tthinking: content.thinking,\n\t\t...(content.thinkingSignature === undefined ? {} : { thinkingSignature: content.thinkingSignature }),\n\t\t...(content.redacted === undefined ? {} : { redacted: content.redacted }),\n\t};\n}\n\nfunction cloneToolCall(toolCall: ToolCall): ToolCall {\n\treturn {\n\t\ttype: \"toolCall\",\n\t\tid: toolCall.id,\n\t\tname: toolCall.name,\n\t\targuments: structuredClone(toolCall.arguments),\n\t\t...(toolCall.thoughtSignature === undefined ? {} : { thoughtSignature: toolCall.thoughtSignature }),\n\t\t...(toolCall.namespace === undefined ? {} : { namespace: toolCall.namespace }),\n\t};\n}\n\nfunction cloneStartMessage(message: AssistantMessage): AssistantMessage {\n\treturn {\n\t\trole: \"assistant\",\n\t\tcontent: [],\n\t\tapi: message.api,\n\t\tprovider: message.provider,\n\t\tmodel: message.model,\n\t\t...(message.responseModel === undefined ? {} : { responseModel: message.responseModel }),\n\t\t...(message.responseId === undefined ? {} : { responseId: message.responseId }),\n\t\t...(message.providerThinkingLevel === undefined ? {} : { providerThinkingLevel: message.providerThinkingLevel }),\n\t\t...(message.diagnostics === undefined ? {} : { diagnostics: structuredClone(message.diagnostics) }),\n\t\tusage: structuredClone(message.usage),\n\t\tstopReason: \"pending\",\n\t\ttimestamp: message.timestamp,\n\t};\n}\n\nfunction assertContentIndex(contentIndex: number): void {\n\tif (!Number.isSafeInteger(contentIndex) || contentIndex < 0) {\n\t\tthrow new Error(`Invalid assistant message frame contentIndex: ${contentIndex}`);\n\t}\n}\n\nfunction eventBlock(event: Exclude<AssistantMessageEvent, { type: \"start\" | \"done\" | \"error\" }>) {\n\tassertContentIndex(event.contentIndex);\n\tconst block = event.partial.content[event.contentIndex];\n\tif (!block) {\n\t\tthrow new Error(`${event.type} event has no content block at index ${event.contentIndex}`);\n\t}\n\treturn block;\n}\n\nfunction serializedArguments(argumentsValue: ToolCall[\"arguments\"]): string {\n\tconst serialized = JSON.stringify(argumentsValue);\n\tif (serialized === undefined) throw new Error(\"Tool-call arguments are not JSON-serializable\");\n\treturn serialized;\n}\n\nconst EMPTY_PARSED_TOOL_ARGUMENTS = serializedArguments(parseStreamingJson<ToolCall[\"arguments\"]>(\"\"));\n\nfunction isJsonPrefix(snapshot: unknown, current: unknown): boolean {\n\tif (typeof snapshot === \"string\") return typeof current === \"string\" && current.startsWith(snapshot);\n\tif (Array.isArray(snapshot)) {\n\t\treturn (\n\t\t\tArray.isArray(current) &&\n\t\t\tsnapshot.length <= current.length &&\n\t\t\tsnapshot.every((value, index) => isJsonPrefix(value, current[index]))\n\t\t);\n\t}\n\tif (typeof snapshot !== \"object\" || snapshot === null) return Object.is(snapshot, current);\n\tif (typeof current !== \"object\" || current === null || Array.isArray(current)) return false;\n\tconst currentRecord = current as Record<string, unknown>;\n\treturn Object.entries(snapshot).every(\n\t\t([key, value]) => Object.hasOwn(currentRecord, key) && isJsonPrefix(value, currentRecord[key]),\n\t);\n}\n\n/**\n * Encodes one assistant stream. `partial` remains a shared live accumulator;\n * the encoder uses per-block offsets to avoid replaying deltas already visible\n * when an older queued event is consumed.\n */\nexport class AssistantMessageFrameEncoder {\n\tprivate started = false;\n\tprivate terminal = false;\n\tprivate readonly blocks = new Map<number, EncoderBlockState>();\n\n\tencode(event: AssistantMessageEvent): AssistantMessageFrame | undefined {\n\t\tif (this.terminal) throw new Error(`Assistant message event ${event.type} follows a terminal event`);\n\n\t\tswitch (event.type) {\n\t\t\tcase \"start\":\n\t\t\t\tif (this.started) throw new Error(\"Assistant message stream contains more than one start event\");\n\t\t\t\tthis.started = true;\n\t\t\t\treturn { type: \"start\", partial: cloneStartMessage(event.partial) };\n\t\t\tcase \"done\":\n\t\t\t\tif (!this.started) throw new Error(\"Assistant message done event appears before start\");\n\t\t\t\tthis.terminal = true;\n\t\t\t\treturn undefined;\n\t\t\tcase \"error\":\n\t\t\t\tthis.terminal = true;\n\t\t\t\treturn undefined;\n\t\t}\n\n\t\tif (!this.started) throw new Error(`Assistant message ${event.type} event appears before start`);\n\n\t\tswitch (event.type) {\n\t\t\tcase \"text_start\": {\n\t\t\t\tconst content = eventBlock(event);\n\t\t\t\tif (content.type !== \"text\") {\n\t\t\t\t\tthrow new Error(`text_start event points to ${content.type} block at index ${event.contentIndex}`);\n\t\t\t\t}\n\t\t\t\tthis.startBlock(event.contentIndex, {\n\t\t\t\t\tkind: \"text\",\n\t\t\t\t\tcoveredChars: content.text.length,\n\t\t\t\t\tdeltaChars: 0,\n\t\t\t\t});\n\t\t\t\treturn { type: \"text_start\", contentIndex: event.contentIndex, content: cloneTextContent(content) };\n\t\t\t}\n\t\t\tcase \"text_delta\":\n\t\t\t\treturn this.encodeTextDelta(event.contentIndex, event.delta, \"text\");\n\t\t\tcase \"text_end\": {\n\t\t\t\tconst content = eventBlock(event);\n\t\t\t\tif (content.type !== \"text\") {\n\t\t\t\t\tthrow new Error(`text_end event points to ${content.type} block at index ${event.contentIndex}`);\n\t\t\t\t}\n\t\t\t\tthis.endBlock(event.contentIndex, \"text\");\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\t\tcontent: event.content,\n\t\t\t\t\t...(content.textSignature === undefined ? {} : { textSignature: content.textSignature }),\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"thinking_start\": {\n\t\t\t\tconst content = eventBlock(event);\n\t\t\t\tif (content.type !== \"thinking\") {\n\t\t\t\t\tthrow new Error(`thinking_start event points to ${content.type} block at index ${event.contentIndex}`);\n\t\t\t\t}\n\t\t\t\tthis.startBlock(event.contentIndex, {\n\t\t\t\t\tkind: \"thinking\",\n\t\t\t\t\tcoveredChars: content.thinking.length,\n\t\t\t\t\tdeltaChars: 0,\n\t\t\t\t});\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_start\",\n\t\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\t\tcontent: cloneThinkingContent(content),\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"thinking_delta\":\n\t\t\t\treturn this.encodeTextDelta(event.contentIndex, event.delta, \"thinking\");\n\t\t\tcase \"thinking_end\": {\n\t\t\t\tconst content = eventBlock(event);\n\t\t\t\tif (content.type !== \"thinking\") {\n\t\t\t\t\tthrow new Error(`thinking_end event points to ${content.type} block at index ${event.contentIndex}`);\n\t\t\t\t}\n\t\t\t\tthis.endBlock(event.contentIndex, \"thinking\");\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\t\tcontent: event.content,\n\t\t\t\t\t...(content.thinkingSignature === undefined ? {} : { thinkingSignature: content.thinkingSignature }),\n\t\t\t\t\t...(content.redacted === undefined ? {} : { redacted: content.redacted }),\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"toolcall_start\": {\n\t\t\t\tconst content = eventBlock(event);\n\t\t\t\tif (content.type !== \"toolCall\") {\n\t\t\t\t\tthrow new Error(`toolcall_start event points to ${content.type} block at index ${event.contentIndex}`);\n\t\t\t\t}\n\t\t\t\tconst snapshotArguments = serializedArguments(content.arguments);\n\t\t\t\tconst caughtUp = snapshotArguments === EMPTY_PARSED_TOOL_ARGUMENTS;\n\t\t\t\tthis.startBlock(event.contentIndex, {\n\t\t\t\t\tkind: \"toolCall\",\n\t\t\t\t\tcaughtUp,\n\t\t\t\t\tcatchupJson: \"\",\n\t\t\t\t\tsnapshotArguments: caughtUp ? \"\" : snapshotArguments,\n\t\t\t\t});\n\t\t\t\treturn { type: \"toolcall_start\", contentIndex: event.contentIndex, toolCall: cloneToolCall(content) };\n\t\t\t}\n\t\t\tcase \"toolcall_delta\": {\n\t\t\t\tconst state = this.block(event.contentIndex, \"toolCall\");\n\t\t\t\tif (state.kind !== \"toolCall\") throw new Error(\"Unreachable tool-call encoder state\");\n\t\t\t\tif (state.caughtUp) {\n\t\t\t\t\treturn event.delta.length === 0\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: { type: \"toolcall_delta\", contentIndex: event.contentIndex, delta: event.delta };\n\t\t\t\t}\n\t\t\t\tstate.catchupJson += event.delta;\n\t\t\t\tconst argumentsValue = parseStreamingJson<ToolCall[\"arguments\"]>(state.catchupJson);\n\t\t\t\tif (serializedArguments(argumentsValue) !== state.snapshotArguments) {\n\t\t\t\t\t// Legacy grammar calls include the initial input in toolcall_start, but their\n\t\t\t\t\t// JSON delta stream still begins at an empty input. Its parsed arguments can\n\t\t\t\t\t// therefore extend, rather than exactly reproduce, the start snapshot.\n\t\t\t\t\tconst snapshotArguments = parseStreamingJson<ToolCall[\"arguments\"]>(state.snapshotArguments);\n\t\t\t\t\tif (!isJsonPrefix(snapshotArguments, argumentsValue)) return undefined;\n\t\t\t\t}\n\t\t\t\tstate.caughtUp = true;\n\t\t\t\tstate.snapshotArguments = \"\";\n\t\t\t\tconst json = state.catchupJson;\n\t\t\t\tstate.catchupJson = \"\";\n\t\t\t\treturn json.length === 0\n\t\t\t\t\t? undefined\n\t\t\t\t\t: { type: \"toolcall_checkpoint\", contentIndex: event.contentIndex, json };\n\t\t\t}\n\t\t\tcase \"toolcall_end\": {\n\t\t\t\tconst content = eventBlock(event);\n\t\t\t\tif (content.type !== \"toolCall\") {\n\t\t\t\t\tthrow new Error(`toolcall_end event points to ${content.type} block at index ${event.contentIndex}`);\n\t\t\t\t}\n\t\t\t\tif (event.toolCall.type !== \"toolCall\") {\n\t\t\t\t\tthrow new Error(`toolcall_end event has invalid tool call at index ${event.contentIndex}`);\n\t\t\t\t}\n\t\t\t\tthis.endBlock(event.contentIndex, \"toolCall\");\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"toolcall_end\",\n\t\t\t\t\tcontentIndex: event.contentIndex,\n\t\t\t\t\tid: event.toolCall.id,\n\t\t\t\t\tname: event.toolCall.name,\n\t\t\t\t\targuments: structuredClone(event.toolCall.arguments),\n\t\t\t\t\t...(event.toolCall.thoughtSignature === undefined\n\t\t\t\t\t\t? {}\n\t\t\t\t\t\t: { thoughtSignature: event.toolCall.thoughtSignature }),\n\t\t\t\t\t...(event.toolCall.namespace === undefined ? {} : { namespace: event.toolCall.namespace }),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate startBlock(contentIndex: number, state: EncoderBlockState): void {\n\t\tassertContentIndex(contentIndex);\n\t\tif (this.blocks.has(contentIndex)) {\n\t\t\tthrow new Error(`Assistant message block ${contentIndex} starts more than once`);\n\t\t}\n\t\tthis.blocks.set(contentIndex, state);\n\t}\n\n\tprivate block(contentIndex: number, kind: EncoderBlockState[\"kind\"]): EncoderBlockState {\n\t\tassertContentIndex(contentIndex);\n\t\tconst state = this.blocks.get(contentIndex);\n\t\tif (state === undefined) throw new Error(`Assistant message ${kind} block ${contentIndex} has not started`);\n\t\tif (state.kind !== kind) {\n\t\t\tthrow new Error(`Assistant message block ${contentIndex} is ${state.kind}, not ${kind}`);\n\t\t}\n\t\treturn state;\n\t}\n\n\tprivate endBlock(contentIndex: number, kind: EncoderBlockState[\"kind\"]): void {\n\t\tthis.block(contentIndex, kind);\n\t\tthis.blocks.delete(contentIndex);\n\t}\n\n\tprivate encodeTextDelta(\n\t\tcontentIndex: number,\n\t\tdelta: string,\n\t\tkind: \"text\" | \"thinking\",\n\t): AssistantMessageFrame | undefined {\n\t\tconst state = this.block(contentIndex, kind);\n\t\tif (state.kind === \"toolCall\") throw new Error(\"Unreachable text encoder state\");\n\t\tconst deltaStart = state.deltaChars;\n\t\tstate.deltaChars += delta.length;\n\t\tconst covered = Math.max(0, state.coveredChars - deltaStart);\n\t\tif (covered >= delta.length) return undefined;\n\t\tconst uncovered = covered === 0 ? delta : delta.slice(covered);\n\t\treturn kind === \"text\"\n\t\t\t? { type: \"text_delta\", contentIndex, delta: uncovered }\n\t\t\t: { type: \"thinking_delta\", contentIndex, delta: uncovered };\n\t}\n}\n\nfunction appendBlock(\n\tmessage: AssistantMessage,\n\tstates: Map<number, ReducerBlockState>,\n\tcontentIndex: number,\n\tblock: TextContent | ThinkingContent | ToolCall,\n\tstate: ReducerBlockState,\n): void {\n\tassertContentIndex(contentIndex);\n\tif (contentIndex !== message.content.length) {\n\t\tconst reason = contentIndex < message.content.length ? \"already exists\" : \"would leave a gap\";\n\t\tthrow new Error(`Cannot start assistant message block at index ${contentIndex}: ${reason}`);\n\t}\n\tmessage.content.push(structuredClone(block));\n\tstates.set(contentIndex, state);\n}\n\nfunction activeBlock(\n\tmessage: AssistantMessage,\n\tstates: Map<number, ReducerBlockState>,\n\tcontentIndex: number,\n\texpectedKind: ReducerBlockState[\"kind\"],\n\tframeType: AssistantMessageFrame[\"type\"],\n): { block: TextContent | ThinkingContent | ToolCall; state: ReducerBlockState } {\n\tassertContentIndex(contentIndex);\n\tconst state = states.get(contentIndex);\n\tconst block = message.content[contentIndex];\n\tif (!state || !block) {\n\t\tthrow new Error(`${frameType} frame has no started block at index ${contentIndex}`);\n\t}\n\tif (state.kind !== expectedKind || block.type !== expectedKind) {\n\t\tthrow new Error(\n\t\t\t`${frameType} frame expected ${expectedKind} block at index ${contentIndex}, found ${block.type}`,\n\t\t);\n\t}\n\tif (state.ended) {\n\t\tthrow new Error(`${frameType} frame follows the end of block at index ${contentIndex}`);\n\t}\n\treturn { block, state };\n}\n\n/**\n * Replay compact frames without mutating them. Returns `undefined` when the\n * iterable contains no start frame.\n */\nexport function reduceAssistantMessageFrames(frames: Iterable<AssistantMessageFrame>): AssistantMessage | undefined {\n\tlet message: AssistantMessage | undefined;\n\tlet frameBeforeStart: AssistantMessageFrame[\"type\"] | undefined;\n\tconst states = new Map<number, ReducerBlockState>();\n\n\tfor (const frame of frames) {\n\t\tif (frame.type === \"start\") {\n\t\t\tif (message) throw new Error(\"Assistant message frame sequence contains more than one start frame\");\n\t\t\tif (frameBeforeStart !== undefined)\n\t\t\t\tthrow new Error(`${frameBeforeStart} frame appears before the start frame`);\n\t\t\tmessage = structuredClone(frame.partial);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!message) {\n\t\t\tframeBeforeStart ??= frame.type;\n\t\t\tcontinue;\n\t\t}\n\n\t\tswitch (frame.type) {\n\t\t\tcase \"text_start\":\n\t\t\t\tif (frame.content.type !== \"text\") {\n\t\t\t\t\tthrow new Error(`text_start frame contains ${frame.content.type} content`);\n\t\t\t\t}\n\t\t\t\tappendBlock(message, states, frame.contentIndex, frame.content, { kind: \"text\", ended: false });\n\t\t\t\tbreak;\n\t\t\tcase \"text_delta\": {\n\t\t\t\tconst { block } = activeBlock(message, states, frame.contentIndex, \"text\", frame.type);\n\t\t\t\tif (block.type !== \"text\") throw new Error(\"Unreachable text frame state\");\n\t\t\t\tblock.text += frame.delta;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"text_end\": {\n\t\t\t\tconst { block, state } = activeBlock(message, states, frame.contentIndex, \"text\", frame.type);\n\t\t\t\tif (block.type !== \"text\") throw new Error(\"Unreachable text frame state\");\n\t\t\t\tblock.text = frame.content;\n\t\t\t\tdelete block.textSignature;\n\t\t\t\tif (frame.textSignature !== undefined) block.textSignature = frame.textSignature;\n\t\t\t\tstate.ended = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"thinking_start\":\n\t\t\t\tif (frame.content.type !== \"thinking\") {\n\t\t\t\t\tthrow new Error(`thinking_start frame contains ${frame.content.type} content`);\n\t\t\t\t}\n\t\t\t\tappendBlock(message, states, frame.contentIndex, frame.content, {\n\t\t\t\t\tkind: \"thinking\",\n\t\t\t\t\tended: false,\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"thinking_delta\": {\n\t\t\t\tconst { block } = activeBlock(message, states, frame.contentIndex, \"thinking\", frame.type);\n\t\t\t\tif (block.type !== \"thinking\") throw new Error(\"Unreachable thinking frame state\");\n\t\t\t\tblock.thinking += frame.delta;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"thinking_end\": {\n\t\t\t\tconst { block, state } = activeBlock(message, states, frame.contentIndex, \"thinking\", frame.type);\n\t\t\t\tif (block.type !== \"thinking\") throw new Error(\"Unreachable thinking frame state\");\n\t\t\t\tblock.thinking = frame.content;\n\t\t\t\tdelete block.thinkingSignature;\n\t\t\t\tdelete block.redacted;\n\t\t\t\tif (frame.thinkingSignature !== undefined) block.thinkingSignature = frame.thinkingSignature;\n\t\t\t\tif (frame.redacted !== undefined) block.redacted = frame.redacted;\n\t\t\t\tstate.ended = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolcall_start\":\n\t\t\t\tif (frame.toolCall.type !== \"toolCall\") {\n\t\t\t\t\tthrow new Error(`toolcall_start frame contains ${frame.toolCall.type} content`);\n\t\t\t\t}\n\t\t\t\tappendBlock(message, states, frame.contentIndex, frame.toolCall, {\n\t\t\t\t\tkind: \"toolCall\",\n\t\t\t\t\tended: false,\n\t\t\t\t\tjson: \"\",\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"toolcall_checkpoint\": {\n\t\t\t\tconst { block, state } = activeBlock(message, states, frame.contentIndex, \"toolCall\", frame.type);\n\t\t\t\tif (block.type !== \"toolCall\" || state.kind !== \"toolCall\") {\n\t\t\t\t\tthrow new Error(\"Unreachable tool-call checkpoint state\");\n\t\t\t\t}\n\t\t\t\tstate.json = frame.json;\n\t\t\t\tblock.arguments = parseStreamingJson<ToolCall[\"arguments\"]>(frame.json);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolcall_delta\": {\n\t\t\t\tconst { block, state } = activeBlock(message, states, frame.contentIndex, \"toolCall\", frame.type);\n\t\t\t\tif (block.type !== \"toolCall\" || state.kind !== \"toolCall\") {\n\t\t\t\t\tthrow new Error(\"Unreachable tool-call frame state\");\n\t\t\t\t}\n\t\t\t\tstate.json += frame.delta;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"toolcall_end\": {\n\t\t\t\tconst { block, state } = activeBlock(message, states, frame.contentIndex, \"toolCall\", frame.type);\n\t\t\t\tif (block.type !== \"toolCall\") throw new Error(\"Unreachable tool-call frame state\");\n\t\t\t\tblock.id = frame.id;\n\t\t\t\tblock.name = frame.name;\n\t\t\t\tblock.arguments = structuredClone(frame.arguments);\n\t\t\t\tdelete block.thoughtSignature;\n\t\t\t\tdelete block.namespace;\n\t\t\t\tif (frame.thoughtSignature !== undefined) block.thoughtSignature = frame.thoughtSignature;\n\t\t\t\tif (frame.namespace !== undefined) block.namespace = frame.namespace;\n\t\t\t\tstate.ended = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!message) return undefined;\n\tfor (const [contentIndex, state] of states) {\n\t\tif (state.kind !== \"toolCall\" || state.ended || state.json.length === 0) continue;\n\t\tconst block = message.content[contentIndex];\n\t\tif (block?.type !== \"toolCall\") throw new Error(\"Unreachable tool-call frame state\");\n\t\tblock.arguments = parseStreamingJson<ToolCall[\"arguments\"]>(state.json);\n\t}\n\n\treturn message;\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Same resolution as the conversation rotation store: an explicit override
|
|
3
|
+
* first, then the agent directory the host configured, then the default one.
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveCursorContextLimitStorePath(env?: NodeJS.ProcessEnv): string;
|
|
6
|
+
/** Records the ceiling Cursor reported for `modelId`; ignores non-positive values. */
|
|
7
|
+
export declare function recordCursorContextLimit(modelId: string, maxTokens: number | undefined): void;
|
|
8
|
+
export declare function getCursorContextLimit(modelId: string): number | undefined;
|
|
9
|
+
/** The window to trust for `modelId`: what the server reported, else the catalog. */
|
|
10
|
+
export declare function resolveCursorContextWindow(modelId: string, catalogWindow: number): number;
|
|
11
|
+
export declare function resetCursorContextLimitStoreForTest(): void;
|
|
12
|
+
//# sourceMappingURL=cursor-context-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-context-limit.d.ts","sourceRoot":"","sources":["../../src/utils/cursor-context-limit.ts"],"names":[],"mappings":"AAqBA;;;GAGG;AACH,wBAAgB,kCAAkC,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAO/F;AAgDD,sFAAsF;AACtF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAG7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGzE;AAED,qFAAqF;AACrF,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAGzF;AAED,wBAAgB,mCAAmC,IAAI,IAAI,CAG1D"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node entry point for the observed Cursor context limits.
|
|
3
|
+
*
|
|
4
|
+
* The store itself (`cursor/context-limit-store.ts`) is browser-safe because the
|
|
5
|
+
* catalog builders that read it are bundled for the browser. Persistence needs
|
|
6
|
+
* `node:fs`, so it lives here and is installed on first use rather than as an
|
|
7
|
+
* import side effect, which a bundler is free to drop for a package declared
|
|
8
|
+
* side-effect-free. Node callers - the `cursor-agent` stream and the coding
|
|
9
|
+
* agent - use this module; browser-facing code uses the store directly.
|
|
10
|
+
*/
|
|
11
|
+
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
12
|
+
import { dirname } from "node:path";
|
|
13
|
+
import { installCursorContextLimitPersistence, getCursorContextLimit as readObservedLimit, recordCursorContextLimit as recordObservedLimit, resetCursorContextLimitStoreForTest as resetObservedLimits, resolveCursorContextWindow as resolveObservedWindow, } from "../cursor/context-limit-store.js";
|
|
14
|
+
/**
|
|
15
|
+
* Same resolution as the conversation rotation store: an explicit override
|
|
16
|
+
* first, then the agent directory the host configured, then the default one.
|
|
17
|
+
*/
|
|
18
|
+
export function resolveCursorContextLimitStorePath(env = process.env) {
|
|
19
|
+
if (env.CURSOR_CONTEXT_LIMIT_STORE) {
|
|
20
|
+
return env.CURSOR_CONTEXT_LIMIT_STORE;
|
|
21
|
+
}
|
|
22
|
+
const agentDir = env.SENPI_CODING_AGENT_DIR ?? env.CODING_AGENT_DIR ?? `${(env.HOME ?? ".").replace(/\/$/, "")}/.senpi/agent`;
|
|
23
|
+
return `${agentDir.replace(/\/$/, "")}/cursor-context-limits.json`;
|
|
24
|
+
}
|
|
25
|
+
let savingEnabled = true;
|
|
26
|
+
const filePersistence = {
|
|
27
|
+
load: () => {
|
|
28
|
+
const limits = new Map();
|
|
29
|
+
let parsed;
|
|
30
|
+
try {
|
|
31
|
+
parsed = JSON.parse(readFileSync(resolveCursorContextLimitStorePath(), "utf8"));
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
// No file on first run, and a truncated or hand-edited one is the same
|
|
35
|
+
// situation for a cache: the catalog window is the documented fallback.
|
|
36
|
+
if (error instanceof Error)
|
|
37
|
+
return limits;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
41
|
+
return limits;
|
|
42
|
+
for (const [modelId, maxTokens] of Object.entries(parsed)) {
|
|
43
|
+
if (typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0) {
|
|
44
|
+
limits.set(modelId, maxTokens);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return limits;
|
|
48
|
+
},
|
|
49
|
+
save: (limits) => {
|
|
50
|
+
if (!savingEnabled)
|
|
51
|
+
return;
|
|
52
|
+
const path = resolveCursorContextLimitStorePath();
|
|
53
|
+
const record = {};
|
|
54
|
+
for (const [modelId, maxTokens] of limits)
|
|
55
|
+
record[modelId] = maxTokens;
|
|
56
|
+
try {
|
|
57
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
58
|
+
const temporaryPath = `${path}.${process.pid}.tmp`;
|
|
59
|
+
writeFileSync(temporaryPath, `${JSON.stringify(record, null, 2)}\n`);
|
|
60
|
+
renameSync(temporaryPath, path);
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
// This file is a cache for the next process. A read-only agent directory
|
|
64
|
+
// must not fail the live turn that observed the limit, and one failure
|
|
65
|
+
// disables saving so a broken path cannot cost a write per checkpoint.
|
|
66
|
+
if (!(error instanceof Error))
|
|
67
|
+
throw error;
|
|
68
|
+
savingEnabled = false;
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
function ensurePersistenceInstalled() {
|
|
73
|
+
installCursorContextLimitPersistence(filePersistence);
|
|
74
|
+
}
|
|
75
|
+
/** Records the ceiling Cursor reported for `modelId`; ignores non-positive values. */
|
|
76
|
+
export function recordCursorContextLimit(modelId, maxTokens) {
|
|
77
|
+
ensurePersistenceInstalled();
|
|
78
|
+
recordObservedLimit(modelId, maxTokens);
|
|
79
|
+
}
|
|
80
|
+
export function getCursorContextLimit(modelId) {
|
|
81
|
+
ensurePersistenceInstalled();
|
|
82
|
+
return readObservedLimit(modelId);
|
|
83
|
+
}
|
|
84
|
+
/** The window to trust for `modelId`: what the server reported, else the catalog. */
|
|
85
|
+
export function resolveCursorContextWindow(modelId, catalogWindow) {
|
|
86
|
+
ensurePersistenceInstalled();
|
|
87
|
+
return resolveObservedWindow(modelId, catalogWindow);
|
|
88
|
+
}
|
|
89
|
+
export function resetCursorContextLimitStoreForTest() {
|
|
90
|
+
savingEnabled = true;
|
|
91
|
+
resetObservedLimits();
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=cursor-context-limit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cursor-context-limit.js","sourceRoot":"","sources":["../../src/utils/cursor-context-limit.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Node entry point for the observed Cursor context limits.\n *\n * The store itself (`cursor/context-limit-store.ts`) is browser-safe because the\n * catalog builders that read it are bundled for the browser. Persistence needs\n * `node:fs`, so it lives here and is installed on first use rather than as an\n * import side effect, which a bundler is free to drop for a package declared\n * side-effect-free. Node callers - the `cursor-agent` stream and the coding\n * agent - use this module; browser-facing code uses the store directly.\n */\nimport { mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport {\n\ttype CursorContextLimitPersistence,\n\tinstallCursorContextLimitPersistence,\n\tgetCursorContextLimit as readObservedLimit,\n\trecordCursorContextLimit as recordObservedLimit,\n\tresetCursorContextLimitStoreForTest as resetObservedLimits,\n\tresolveCursorContextWindow as resolveObservedWindow,\n} from \"../cursor/context-limit-store.ts\";\n\n/**\n * Same resolution as the conversation rotation store: an explicit override\n * first, then the agent directory the host configured, then the default one.\n */\nexport function resolveCursorContextLimitStorePath(env: NodeJS.ProcessEnv = process.env): string {\n\tif (env.CURSOR_CONTEXT_LIMIT_STORE) {\n\t\treturn env.CURSOR_CONTEXT_LIMIT_STORE;\n\t}\n\tconst agentDir =\n\t\tenv.SENPI_CODING_AGENT_DIR ?? env.CODING_AGENT_DIR ?? `${(env.HOME ?? \".\").replace(/\\/$/, \"\")}/.senpi/agent`;\n\treturn `${agentDir.replace(/\\/$/, \"\")}/cursor-context-limits.json`;\n}\n\nlet savingEnabled = true;\n\nconst filePersistence: CursorContextLimitPersistence = {\n\tload: () => {\n\t\tconst limits = new Map<string, number>();\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(readFileSync(resolveCursorContextLimitStorePath(), \"utf8\"));\n\t\t} catch (error) {\n\t\t\t// No file on first run, and a truncated or hand-edited one is the same\n\t\t\t// situation for a cache: the catalog window is the documented fallback.\n\t\t\tif (error instanceof Error) return limits;\n\t\t\tthrow error;\n\t\t}\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return limits;\n\t\tfor (const [modelId, maxTokens] of Object.entries(parsed)) {\n\t\t\tif (typeof maxTokens === \"number\" && Number.isFinite(maxTokens) && maxTokens > 0) {\n\t\t\t\tlimits.set(modelId, maxTokens);\n\t\t\t}\n\t\t}\n\t\treturn limits;\n\t},\n\tsave: (limits) => {\n\t\tif (!savingEnabled) return;\n\t\tconst path = resolveCursorContextLimitStorePath();\n\t\tconst record: Record<string, number> = {};\n\t\tfor (const [modelId, maxTokens] of limits) record[modelId] = maxTokens;\n\t\ttry {\n\t\t\tmkdirSync(dirname(path), { recursive: true });\n\t\t\tconst temporaryPath = `${path}.${process.pid}.tmp`;\n\t\t\twriteFileSync(temporaryPath, `${JSON.stringify(record, null, 2)}\\n`);\n\t\t\trenameSync(temporaryPath, path);\n\t\t} catch (error) {\n\t\t\t// This file is a cache for the next process. A read-only agent directory\n\t\t\t// must not fail the live turn that observed the limit, and one failure\n\t\t\t// disables saving so a broken path cannot cost a write per checkpoint.\n\t\t\tif (!(error instanceof Error)) throw error;\n\t\t\tsavingEnabled = false;\n\t\t}\n\t},\n};\n\nfunction ensurePersistenceInstalled(): void {\n\tinstallCursorContextLimitPersistence(filePersistence);\n}\n\n/** Records the ceiling Cursor reported for `modelId`; ignores non-positive values. */\nexport function recordCursorContextLimit(modelId: string, maxTokens: number | undefined): void {\n\tensurePersistenceInstalled();\n\trecordObservedLimit(modelId, maxTokens);\n}\n\nexport function getCursorContextLimit(modelId: string): number | undefined {\n\tensurePersistenceInstalled();\n\treturn readObservedLimit(modelId);\n}\n\n/** The window to trust for `modelId`: what the server reported, else the catalog. */\nexport function resolveCursorContextWindow(modelId: string, catalogWindow: number): number {\n\tensurePersistenceInstalled();\n\treturn resolveObservedWindow(modelId, catalogWindow);\n}\n\nexport function resetCursorContextLimitStoreForTest(): void {\n\tsavingEnabled = true;\n\tresetObservedLimits();\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-stream.d.ts","sourceRoot":"","sources":["../../src/utils/event-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"event-stream.d.ts","sourceRoot":"","sources":["../../src/utils/event-stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAyB3E,qBAAa,WAAW,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAE,YAAW,aAAa,CAAC,CAAC,CAAC;;IAG7D,OAAO,CAAC,OAAO,CAAsG;IACrH,OAAO,CAAC,IAAI,CAAS;IAIrB,OAAO,CAAC,kBAAkB,CAAa;IACvC,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,UAAU,CAAwB;IAC1C,OAAO,CAAC,aAAa,CAAkB;IAEvC,YAAY,UAAU,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,EAAE,aAAa,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,EAQ5E;IAED,IAAI,KAAK,IAAI,CAAC,EAAE,CAEf;IAmBD,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAenB;IAED,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,GAAG,IAAI,CAUpB;IAED,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAUzB;IAED,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,CAezC;IAED,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,CAEnB;IAED;;;;;;OAMG;IACG,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAOhE;IAED,2EAA2E;IAC3E,mBAAmB,IAAI,OAAO,CAE7B;CACD;AAED,qBAAa,2BAA4B,SAAQ,WAAW,CAAC,qBAAqB,EAAE,gBAAgB,CAAC;IACpG,cAYC;CACD;AAED,+EAA+E;AAC/E,wBAAgB,iCAAiC,IAAI,2BAA2B,CAE/E"}
|