@archships/dim-agent-sdk 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,4820 @@
1
+ // src/providers/core/create-provider-factory.ts
2
+ function createProviderFactory(definition) {
3
+ return function createConfiguredAdapter(options) {
4
+ const provider = options.provider ?? definition.defaultProvider;
5
+ const defaultModel = {
6
+ provider,
7
+ modelId: options.defaultModel
8
+ };
9
+ return {
10
+ provider,
11
+ defaultModel,
12
+ async* stream(request) {
13
+ const requestId = request.requestId ?? crypto.randomUUID();
14
+ const model = request.model ?? defaultModel;
15
+ yield { type: "response_start", requestId, model };
16
+ const context = {
17
+ options,
18
+ provider,
19
+ defaultModel,
20
+ request: {
21
+ ...request,
22
+ model
23
+ }
24
+ };
25
+ let result;
26
+ try {
27
+ result = await definition.driver.generate(context);
28
+ } catch (error) {
29
+ const payload = definition.driver.normalizeError ? await definition.driver.normalizeError(error, context) : createFallbackErrorPayload(provider, error);
30
+ yield {
31
+ type: "error",
32
+ requestId,
33
+ error: payload,
34
+ terminal: true
35
+ };
36
+ return;
37
+ }
38
+ for (const segment of result.content) {
39
+ if (segment.type === "text") {
40
+ if (segment.text.length > 0)
41
+ yield { type: "text_delta", requestId, delta: segment.text };
42
+ continue;
43
+ }
44
+ if (segment.type === "thinking") {
45
+ if (segment.text.length > 0)
46
+ yield { type: "thinking_delta", requestId, delta: segment.text };
47
+ continue;
48
+ }
49
+ yield {
50
+ type: "tool_call_start",
51
+ requestId,
52
+ callId: segment.callId,
53
+ toolName: segment.toolName
54
+ };
55
+ yield {
56
+ type: "tool_call_args_delta",
57
+ requestId,
58
+ callId: segment.callId,
59
+ delta: segment.argsText
60
+ };
61
+ yield {
62
+ type: "tool_call_end",
63
+ requestId,
64
+ callId: segment.callId
65
+ };
66
+ }
67
+ yield {
68
+ type: "response_end",
69
+ requestId,
70
+ stopReason: result.stopReason,
71
+ usage: result.usage,
72
+ assistantMetadata: result.assistantMetadata
73
+ };
74
+ }
75
+ };
76
+ };
77
+ }
78
+ function createFallbackErrorPayload(provider, error) {
79
+ if (error instanceof Error) {
80
+ return {
81
+ code: `${provider}_request_error`,
82
+ message: error.message
83
+ };
84
+ }
85
+ return {
86
+ code: `${provider}_request_error`,
87
+ message: String(error)
88
+ };
89
+ }
90
+
91
+ // src/providers/aihubmix/driver.ts
92
+ import { APICallError } from "@ai-sdk/provider";
93
+ import { createAihubmix } from "@aihubmix/ai-sdk-provider";
94
+
95
+ // src/providers/shared/usage.ts
96
+ function normalizeLanguageModelUsage(raw) {
97
+ if (!raw)
98
+ return;
99
+ const promptTokens = raw.inputTokens.total ?? 0;
100
+ const completionTokens = raw.outputTokens.total ?? 0;
101
+ const totalTokens = promptTokens + completionTokens;
102
+ if (promptTokens === 0 && completionTokens === 0 && totalTokens === 0)
103
+ return;
104
+ return {
105
+ promptTokens,
106
+ completionTokens,
107
+ totalTokens
108
+ };
109
+ }
110
+ function mapLanguageModelFinishReason(reason) {
111
+ const raw = reason.raw?.toLowerCase();
112
+ if (raw === "cancelled" || raw === "canceled")
113
+ return "cancelled";
114
+ switch (reason.unified) {
115
+ case "tool-calls":
116
+ return "tool_call";
117
+ case "length":
118
+ return "length";
119
+ case "content-filter":
120
+ case "error":
121
+ return "error";
122
+ case "other":
123
+ return raw === "cancelled" || raw === "canceled" ? "cancelled" : "final";
124
+ case "stop":
125
+ default:
126
+ return "final";
127
+ }
128
+ }
129
+
130
+ // src/providers/shared/ai-sdk-driver.ts
131
+ async function generateWithAiSdk(input) {
132
+ const result = await input.model.doGenerate(input.callOptions);
133
+ const content = [];
134
+ for (const part of result.content) {
135
+ if (part.type === "text") {
136
+ if (part.text.length > 0)
137
+ content.push({ type: "text", text: part.text });
138
+ continue;
139
+ }
140
+ if (part.type === "reasoning") {
141
+ if (part.text.length > 0)
142
+ content.push({ type: "thinking", text: part.text });
143
+ continue;
144
+ }
145
+ if (part.type === "tool-call") {
146
+ content.push({
147
+ type: "tool_call",
148
+ callId: part.toolCallId,
149
+ toolName: part.toolName,
150
+ argsText: part.input
151
+ });
152
+ }
153
+ }
154
+ return {
155
+ content,
156
+ stopReason: mapLanguageModelFinishReason(result.finishReason),
157
+ usage: normalizeLanguageModelUsage(result.usage),
158
+ assistantMetadata: input.createAssistantMetadata?.(result)
159
+ };
160
+ }
161
+
162
+ // src/providers/shared/auth-warning.ts
163
+ var warnedProviders = new Set;
164
+ function warnIfPlaceholderApiKey(input) {
165
+ if (!input.shouldWarn)
166
+ return;
167
+ if (false)
168
+ ;
169
+ if (warnedProviders.has(input.provider))
170
+ return;
171
+ warnedProviders.add(input.provider);
172
+ const suffix = input.hint ? ` ${input.hint}` : "";
173
+ console.warn(`[dim-agent-sdk] ${input.provider} is using a placeholder API key because no apiKey or provider-native auth configuration was provided. ` + `If you rely on external authentication, ensure your custom fetch or provider-native headers add real credentials before the request is sent upstream.${suffix}`);
174
+ }
175
+
176
+ // src/providers/shared/fetch.ts
177
+ function createProviderFetch(input) {
178
+ const fetchImpl = input.fetch ?? globalThis.fetch;
179
+ if (!input.stripWhen || !input.stripHeaders || input.stripHeaders.length === 0)
180
+ return fetchImpl;
181
+ const headersToStrip = new Set(input.stripHeaders.map((header) => header.toLowerCase()));
182
+ const wrappedFetch = Object.assign((resource, init) => {
183
+ if (typeof resource === "string" || resource instanceof URL) {
184
+ const headers = new Headers(init?.headers);
185
+ for (const header of headersToStrip)
186
+ headers.delete(header);
187
+ return fetchImpl(resource, { ...init, headers });
188
+ }
189
+ const request = new Request(resource, init);
190
+ for (const header of headersToStrip)
191
+ request.headers.delete(header);
192
+ return fetchImpl(request);
193
+ }, {
194
+ preconnect: typeof fetchImpl.preconnect === "function" ? fetchImpl.preconnect.bind(fetchImpl) : (_url, _options) => {}
195
+ });
196
+ return wrappedFetch;
197
+ }
198
+ function hasHeader(headers, target) {
199
+ if (!headers)
200
+ return false;
201
+ const normalized = target.toLowerCase();
202
+ return Object.keys(headers).some((key) => key.toLowerCase() === normalized);
203
+ }
204
+
205
+ // src/providers/shared/http-error.ts
206
+ import { STATUS_CODES } from "node:http";
207
+ var MAX_TEXT_CHARS = 4000;
208
+ var MAX_JSON_DEPTH = 4;
209
+ var MAX_JSON_ARRAY_ITEMS = 20;
210
+ var MAX_JSON_OBJECT_KEYS = 40;
211
+ var TRUNCATED_SUFFIX = "...[truncated]";
212
+ function createApiCallErrorPayload(input) {
213
+ const responseBody = input.error.responseBody ? parseErrorBody(input.error.responseBody) : limitJsonValue(input.error.data);
214
+ return {
215
+ code: input.code,
216
+ message: `${input.provider} request failed${input.error.statusCode ? ` with status ${input.error.statusCode}` : ""}`,
217
+ status: input.error.statusCode,
218
+ retryable: input.error.isRetryable,
219
+ details: {
220
+ provider: input.provider,
221
+ endpoint: input.error.url,
222
+ ...input.error.statusCode ? { statusText: STATUS_CODES[input.error.statusCode] ?? undefined } : {},
223
+ ...responseBody === undefined ? {} : { responseBody }
224
+ }
225
+ };
226
+ }
227
+ function createRequestErrorPayload(input) {
228
+ if (input.error instanceof Error) {
229
+ return {
230
+ code: input.code,
231
+ message: input.error.message
232
+ };
233
+ }
234
+ return {
235
+ code: input.code,
236
+ message: String(input.error)
237
+ };
238
+ }
239
+ function parseErrorBody(value) {
240
+ const normalized = value.trim();
241
+ if (!normalized)
242
+ return;
243
+ try {
244
+ return limitJsonValue(JSON.parse(normalized));
245
+ } catch {
246
+ return truncateText(normalized);
247
+ }
248
+ }
249
+ function limitJsonValue(value, depth = 0) {
250
+ if (value === undefined)
251
+ return;
252
+ if (value === null || typeof value === "boolean" || typeof value === "number")
253
+ return value;
254
+ if (typeof value === "string")
255
+ return truncateText(value);
256
+ if (Array.isArray(value))
257
+ return value.slice(0, MAX_JSON_ARRAY_ITEMS).map((item) => limitJsonValue(item, depth + 1));
258
+ if (typeof value === "object") {
259
+ if (depth >= MAX_JSON_DEPTH)
260
+ return truncateText(JSON.stringify(value));
261
+ const limited = {};
262
+ for (const [key, child] of Object.entries(value).slice(0, MAX_JSON_OBJECT_KEYS))
263
+ limited[key] = limitJsonValue(child, depth + 1);
264
+ return limited;
265
+ }
266
+ return truncateText(String(value));
267
+ }
268
+ function truncateText(value) {
269
+ if (value.length <= MAX_TEXT_CHARS)
270
+ return value;
271
+ return `${value.slice(0, MAX_TEXT_CHARS)}${TRUNCATED_SUFFIX}`;
272
+ }
273
+
274
+ // src/utils/guards.ts
275
+ function isRecord(value) {
276
+ return typeof value === "object" && value !== null && !Array.isArray(value);
277
+ }
278
+ function isStringArray(value) {
279
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
280
+ }
281
+
282
+ // src/contracts/content-normalize.ts
283
+ function isTextContent(value) {
284
+ return isRecord(value) && value.type === "text" && typeof value.text === "string" && (value.annotations === undefined || isRecord(value.annotations)) && (value._meta === undefined || isRecord(value._meta));
285
+ }
286
+ function isImageContent(value) {
287
+ return isRecord(value) && value.type === "image" && typeof value.data === "string" && typeof value.mimeType === "string" && (value.annotations === undefined || isRecord(value.annotations)) && (value._meta === undefined || isRecord(value._meta));
288
+ }
289
+ function isContentBlock(value) {
290
+ return isTextContent(value) || isImageContent(value);
291
+ }
292
+ function normalizeContent(input) {
293
+ if (typeof input === "string") {
294
+ return [{ type: "text", text: input }];
295
+ }
296
+ if (Array.isArray(input)) {
297
+ const blocks = input.filter((item) => item != null);
298
+ if (!blocks.every(isContentBlock))
299
+ throw new TypeError("Content array must contain only text or image blocks");
300
+ return blocks.map((block) => ({ ...block }));
301
+ }
302
+ if (!isContentBlock(input))
303
+ throw new TypeError("Content must be a string, content block, or content block array");
304
+ return [{ ...input }];
305
+ }
306
+ function contentToText(content) {
307
+ return content.filter((block) => block.type === "text").map((block) => block.text).join("");
308
+ }
309
+
310
+ // src/utils/json.ts
311
+ function isJsonSafeValue(value) {
312
+ if (value === null)
313
+ return true;
314
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
315
+ return true;
316
+ if (Array.isArray(value))
317
+ return value.every(isJsonSafeValue);
318
+ if (isRecord(value))
319
+ return Object.values(value).every(isJsonSafeValue);
320
+ return false;
321
+ }
322
+ function assertJsonSafeObject(value, label) {
323
+ if (!isRecord(value) || !isJsonSafeValue(value))
324
+ throw new TypeError(`${label} must be a JSON-safe object`);
325
+ }
326
+ function parseJsonObject(value, label) {
327
+ let parsed;
328
+ try {
329
+ parsed = JSON.parse(value);
330
+ } catch (error) {
331
+ const message = error instanceof Error ? error.message : String(error);
332
+ throw new Error(`${label} must be valid JSON: ${message}`);
333
+ }
334
+ if (!isRecord(parsed))
335
+ throw new Error(`${label} must decode to a JSON object`);
336
+ return parsed;
337
+ }
338
+
339
+ // src/providers/shared/prompt.ts
340
+ function mapToolDefinitionsToLanguageModelTools(tools) {
341
+ if (!tools || tools.length === 0)
342
+ return;
343
+ return tools.map((tool) => ({
344
+ type: "function",
345
+ name: tool.name,
346
+ description: tool.description,
347
+ inputSchema: tool.inputSchema
348
+ }));
349
+ }
350
+ function messagesToLanguageModelPrompt(messages, options = {}) {
351
+ const prompt = [];
352
+ const systemContent = messages.filter((message) => message.role === "system").map((message) => contentToText(message.content)).filter(Boolean).join(`
353
+
354
+ `);
355
+ if (systemContent)
356
+ prompt.push({ role: "system", content: systemContent });
357
+ for (const message of messages) {
358
+ if (message.role === "system")
359
+ continue;
360
+ if (message.role === "tool") {
361
+ prompt.push(toolMessageToPrompt(message));
362
+ continue;
363
+ }
364
+ if (message.role === "assistant") {
365
+ const content = [
366
+ ...options.assistantPrefixParts?.(message) ?? [],
367
+ ...contentBlocksToPromptParts(message.content),
368
+ ...toolCallsToPromptParts(message.toolCalls)
369
+ ];
370
+ if (content.length > 0)
371
+ prompt.push({ role: "assistant", content });
372
+ continue;
373
+ }
374
+ prompt.push({
375
+ role: "user",
376
+ content: contentBlocksToPromptParts(message.content)
377
+ });
378
+ }
379
+ return prompt;
380
+ }
381
+ function contentBlocksToPromptParts(content) {
382
+ return content.map((block) => {
383
+ if (block.type === "text")
384
+ return { type: "text", text: block.text };
385
+ return {
386
+ type: "file",
387
+ data: block.data,
388
+ mediaType: block.mimeType
389
+ };
390
+ });
391
+ }
392
+ function toolCallsToPromptParts(toolCalls) {
393
+ if (!toolCalls || toolCalls.length === 0)
394
+ return [];
395
+ return toolCalls.map((toolCall) => ({
396
+ type: "tool-call",
397
+ toolCallId: toolCall.id,
398
+ toolName: toolCall.function.name,
399
+ input: toolCall.function.arguments
400
+ }));
401
+ }
402
+ function toolMessageToPrompt(message) {
403
+ return {
404
+ role: "tool",
405
+ content: [{
406
+ type: "tool-result",
407
+ toolCallId: message.toolCallId,
408
+ toolName: message.toolName,
409
+ output: toolMessageToOutput(message)
410
+ }]
411
+ };
412
+ }
413
+ function toolMessageToOutput(message) {
414
+ if (message.structuredContent) {
415
+ assertJsonSafeObject(message.structuredContent, "Tool structuredContent");
416
+ return {
417
+ type: "json",
418
+ value: message.structuredContent
419
+ };
420
+ }
421
+ const text = contentToText(message.content);
422
+ if (message.isError === true) {
423
+ return {
424
+ type: "json",
425
+ value: {
426
+ content: text,
427
+ isError: true
428
+ }
429
+ };
430
+ }
431
+ return {
432
+ type: "text",
433
+ value: text
434
+ };
435
+ }
436
+
437
+ // src/providers/shared/reasoning.ts
438
+ function isRecord2(value) {
439
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
440
+ }
441
+ var LOW_HIGH_REASONING_EFFORT_MAP = {
442
+ none: "low",
443
+ minimal: "low",
444
+ low: "low",
445
+ medium: "high",
446
+ high: "high",
447
+ xhigh: "high"
448
+ };
449
+ var LOW_MEDIUM_HIGH_REASONING_EFFORT_MAP = {
450
+ none: "low",
451
+ minimal: "low",
452
+ low: "low",
453
+ medium: "medium",
454
+ high: "high",
455
+ xhigh: "high"
456
+ };
457
+ function normalizeReasoningConfig(reasoning) {
458
+ if (!isRecord2(reasoning))
459
+ return;
460
+ if (reasoning.enabled === false)
461
+ return;
462
+ return reasoning;
463
+ }
464
+ function resolveReasoningBudget(reasoning, fallback = 1024) {
465
+ const normalized = normalizeReasoningConfig(reasoning);
466
+ if (!normalized)
467
+ return;
468
+ for (const key of ["budgetTokens", "budget_tokens", "thinkingBudget"]) {
469
+ const value = normalized[key];
470
+ if (typeof value === "number" && Number.isFinite(value) && value > 0)
471
+ return Math.floor(value);
472
+ }
473
+ return fallback;
474
+ }
475
+ function resolveReasoningEffort(reasoning, allowedValues) {
476
+ const normalized = normalizeReasoningConfig(reasoning);
477
+ if (!normalized)
478
+ return;
479
+ const rawEffort = normalized.reasoningEffort ?? normalized.effort;
480
+ if (typeof rawEffort !== "string" || rawEffort.length === 0)
481
+ return;
482
+ if (!allowedValues || allowedValues.includes(rawEffort))
483
+ return rawEffort;
484
+ return;
485
+ }
486
+ function resolveLowHighReasoningEffort(reasoning) {
487
+ const normalized = normalizeReasoningConfig(reasoning);
488
+ if (!normalized)
489
+ return;
490
+ const rawEffort = normalized.reasoningEffort ?? normalized.effort;
491
+ return typeof rawEffort === "string" ? LOW_HIGH_REASONING_EFFORT_MAP[rawEffort] : undefined;
492
+ }
493
+ function resolveLowMediumHighReasoningEffort(reasoning) {
494
+ const normalized = normalizeReasoningConfig(reasoning);
495
+ if (!normalized)
496
+ return;
497
+ const rawEffort = normalized.reasoningEffort ?? normalized.effort;
498
+ return typeof rawEffort === "string" ? LOW_MEDIUM_HIGH_REASONING_EFFORT_MAP[rawEffort] : undefined;
499
+ }
500
+ function buildOpenAIResponsesProviderOptions(reasoning) {
501
+ const normalized = normalizeReasoningConfig(reasoning);
502
+ if (!normalized)
503
+ return;
504
+ const next = {};
505
+ for (const [key, value] of Object.entries(normalized)) {
506
+ if (key === "enabled" || key === "budgetTokens" || key === "budget_tokens" || key === "thinkingBudget" || key === "includeThoughts")
507
+ continue;
508
+ if (key === "effort") {
509
+ next.reasoningEffort = value;
510
+ continue;
511
+ }
512
+ if (key === "summary") {
513
+ next.reasoningSummary = value;
514
+ continue;
515
+ }
516
+ next[key] = value;
517
+ }
518
+ if (next.reasoningSummary === undefined)
519
+ next.reasoningSummary = "auto";
520
+ return next;
521
+ }
522
+ function buildOpenAIResponsesRequestReasoning(reasoning) {
523
+ const options = buildOpenAIResponsesProviderOptions(reasoning);
524
+ if (!options)
525
+ return;
526
+ const next = {};
527
+ if (typeof options.reasoningEffort === "string")
528
+ next.effort = options.reasoningEffort;
529
+ if (typeof options.reasoningSummary === "string")
530
+ next.summary = options.reasoningSummary;
531
+ return next.effort || next.summary ? next : undefined;
532
+ }
533
+ function buildReasoningEffortProviderOptions(reasoning, allowedValues) {
534
+ const reasoningEffort = resolveReasoningEffort(reasoning, allowedValues);
535
+ return reasoningEffort ? { reasoningEffort } : undefined;
536
+ }
537
+ function buildAnthropicThinkingProviderOptions(reasoning) {
538
+ const budget = resolveReasoningBudget(reasoning);
539
+ if (!budget)
540
+ return { thinking: undefined, sendReasoning: undefined };
541
+ return {
542
+ thinking: {
543
+ type: "enabled",
544
+ budgetTokens: budget
545
+ },
546
+ sendReasoning: true
547
+ };
548
+ }
549
+ function buildGeminiThinkingProviderOptions(reasoning) {
550
+ const normalized = normalizeReasoningConfig(reasoning);
551
+ if (!normalized)
552
+ return;
553
+ return {
554
+ thinkingConfig: {
555
+ thinkingBudget: resolveReasoningBudget(normalized) ?? 1024,
556
+ includeThoughts: normalized.includeThoughts !== false
557
+ }
558
+ };
559
+ }
560
+ function buildMoonshotThinkingProviderOptions(reasoning) {
561
+ const budget = resolveReasoningBudget(reasoning);
562
+ if (!budget)
563
+ return;
564
+ return {
565
+ thinking: {
566
+ type: "enabled",
567
+ budgetTokens: budget
568
+ }
569
+ };
570
+ }
571
+ function buildDeepSeekThinkingProviderOptions(reasoning) {
572
+ return normalizeReasoningConfig(reasoning) ? { thinking: { type: "enabled" } } : undefined;
573
+ }
574
+
575
+ // src/providers/aihubmix/driver.ts
576
+ var PLACEHOLDER_API_KEY = "dim-placeholder-key";
577
+ var AIHUBMIX_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "none", "xhigh"];
578
+ var aihubmixDriver = {
579
+ async generate(context) {
580
+ const model = createProvider(context.options).chat(context.request.model.modelId);
581
+ const aihubmixProviderOptions = buildReasoningEffortProviderOptions(context.request.reasoning, AIHUBMIX_REASONING_EFFORTS);
582
+ const callOptions = {
583
+ prompt: messagesToLanguageModelPrompt(context.request.messages),
584
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
585
+ maxOutputTokens: context.request.maxOutputTokens,
586
+ temperature: context.request.temperature,
587
+ topP: context.request.topP,
588
+ stopSequences: context.request.stop,
589
+ abortSignal: context.request.signal,
590
+ ...aihubmixProviderOptions ? { providerOptions: { openai: aihubmixProviderOptions } } : {}
591
+ };
592
+ return generateWithAiSdk({
593
+ model,
594
+ callOptions
595
+ });
596
+ },
597
+ normalizeError(error) {
598
+ if (APICallError.isInstance(error)) {
599
+ return createApiCallErrorPayload({
600
+ code: "aihubmix_http_error",
601
+ provider: "AIHubMix",
602
+ error
603
+ });
604
+ }
605
+ return createRequestErrorPayload({
606
+ code: "aihubmix_request_error",
607
+ error
608
+ });
609
+ }
610
+ };
611
+ function createProvider(options) {
612
+ const stripAuthorization = !options.apiKey;
613
+ warnIfPlaceholderApiKey({
614
+ provider: "AIHubMix",
615
+ shouldWarn: stripAuthorization,
616
+ hint: "This adapter does not expose provider-native auth headers in its options, so external auth must be added inside custom fetch when apiKey is omitted."
617
+ });
618
+ return createAihubmix({
619
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY,
620
+ compatibility: options.compatibility,
621
+ fetch: createProviderFetch({
622
+ fetch: options.fetch,
623
+ stripHeaders: ["authorization"],
624
+ stripWhen: stripAuthorization
625
+ })
626
+ });
627
+ }
628
+
629
+ // src/providers/aihubmix/adapter.ts
630
+ var createAihubmixAdapter = createProviderFactory({
631
+ defaultProvider: "aihubmix",
632
+ driver: aihubmixDriver
633
+ });
634
+ // src/providers/aihubmix-responses/driver.ts
635
+ import { APICallError as APICallError2 } from "@ai-sdk/provider";
636
+ import { createAihubmix as createAihubmix2 } from "@aihubmix/ai-sdk-provider";
637
+
638
+ // src/providers/shared/provider-state.ts
639
+ var PROVIDER_STATE_METADATA_KEY = "_dimProviderState";
640
+ function attachProviderState(metadata, provider, state) {
641
+ if (!state || Object.keys(state).length === 0)
642
+ return metadata;
643
+ const nextMetadata = metadata ? structuredClone(metadata) : {};
644
+ const currentBag = isRecord3(nextMetadata[PROVIDER_STATE_METADATA_KEY]) ? nextMetadata[PROVIDER_STATE_METADATA_KEY] : {};
645
+ nextMetadata[PROVIDER_STATE_METADATA_KEY] = {
646
+ ...currentBag,
647
+ [provider]: structuredClone(state)
648
+ };
649
+ return nextMetadata;
650
+ }
651
+ function readProviderState(message, provider) {
652
+ if (message.role !== "assistant" || !isRecord3(message.metadata))
653
+ return;
654
+ const bag = message.metadata[PROVIDER_STATE_METADATA_KEY];
655
+ if (!isRecord3(bag))
656
+ return;
657
+ const state = bag[provider];
658
+ return isRecord3(state) ? structuredClone(state) : undefined;
659
+ }
660
+ function isRecord3(value) {
661
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
662
+ }
663
+
664
+ // src/providers/shared/responses-state.ts
665
+ function sliceMessagesForResponses(messages, stateKey) {
666
+ let previousResponseId;
667
+ let startIndex = 0;
668
+ for (let index = messages.length - 1;index >= 0; index -= 1) {
669
+ const state = readProviderState(messages[index], stateKey);
670
+ if (typeof state?.responseId === "string") {
671
+ previousResponseId = state.responseId;
672
+ startIndex = index + 1;
673
+ break;
674
+ }
675
+ }
676
+ return {
677
+ messages: messages.slice(startIndex),
678
+ previousResponseId
679
+ };
680
+ }
681
+ function createResponsesAssistantMetadata(input) {
682
+ const responseId = resolveResponseId(input.result, input.providerMetadataKey);
683
+ if (!responseId)
684
+ return;
685
+ return attachProviderState(undefined, input.stateKey, { responseId });
686
+ }
687
+ function resolveResponseId(result, providerMetadataKey) {
688
+ const providerMetadata = providerMetadataKey ? result.providerMetadata?.[providerMetadataKey] : undefined;
689
+ if (isRecord(providerMetadata) && typeof providerMetadata.responseId === "string")
690
+ return providerMetadata.responseId;
691
+ if (typeof result.response?.id === "string")
692
+ return result.response.id;
693
+ return extractResponseIdFromBody(result.response?.body);
694
+ }
695
+ function extractResponseIdFromBody(body) {
696
+ if (isRecord(body) && typeof body.id === "string")
697
+ return body.id;
698
+ if (typeof body !== "string")
699
+ return;
700
+ try {
701
+ const parsed = JSON.parse(body);
702
+ return isRecord(parsed) && typeof parsed.id === "string" ? parsed.id : undefined;
703
+ } catch {
704
+ return;
705
+ }
706
+ }
707
+
708
+ // src/providers/aihubmix-responses/state.ts
709
+ var AIHUBMIX_RESPONSES_STATE_KEY = "aihubmixResponses";
710
+ function sliceMessagesForAihubmixResponses(messages) {
711
+ return sliceMessagesForResponses(messages, AIHUBMIX_RESPONSES_STATE_KEY);
712
+ }
713
+ function createAihubmixResponsesAssistantMetadata(result) {
714
+ return createResponsesAssistantMetadata({
715
+ result,
716
+ stateKey: AIHUBMIX_RESPONSES_STATE_KEY,
717
+ providerMetadataKey: "aihubmix"
718
+ });
719
+ }
720
+
721
+ // src/providers/aihubmix-responses/driver.ts
722
+ var PLACEHOLDER_API_KEY2 = "dim-placeholder-key";
723
+ var aihubmixResponsesDriver = {
724
+ async generate(context) {
725
+ const requestReasoning = buildOpenAIResponsesRequestReasoning(context.request.reasoning);
726
+ const model = createProvider2(context.options, requestReasoning).responses(context.request.model.modelId);
727
+ const { messages, previousResponseId } = sliceMessagesForAihubmixResponses(context.request.messages);
728
+ const aihubmixProviderOptions = {
729
+ ...buildOpenAIResponsesProviderOptions(context.request.reasoning) ?? {},
730
+ ...previousResponseId ? { previousResponseId } : {}
731
+ };
732
+ const callOptions = {
733
+ prompt: messagesToLanguageModelPrompt(messages),
734
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
735
+ maxOutputTokens: context.request.maxOutputTokens,
736
+ temperature: context.request.temperature,
737
+ topP: context.request.topP,
738
+ stopSequences: context.request.stop,
739
+ abortSignal: context.request.signal,
740
+ ...Object.keys(aihubmixProviderOptions).length > 0 ? { providerOptions: { openai: aihubmixProviderOptions } } : {}
741
+ };
742
+ return generateWithAiSdk({
743
+ model,
744
+ callOptions,
745
+ createAssistantMetadata: createAihubmixResponsesAssistantMetadata
746
+ });
747
+ },
748
+ normalizeError(error) {
749
+ if (APICallError2.isInstance(error)) {
750
+ return createApiCallErrorPayload({
751
+ code: "aihubmix_responses_http_error",
752
+ provider: "AIHubMix Responses",
753
+ error
754
+ });
755
+ }
756
+ return createRequestErrorPayload({
757
+ code: "aihubmix_responses_request_error",
758
+ error
759
+ });
760
+ }
761
+ };
762
+ function createProvider2(options, requestReasoning) {
763
+ const stripAuthorization = !options.apiKey;
764
+ warnIfPlaceholderApiKey({
765
+ provider: "AIHubMix Responses",
766
+ shouldWarn: stripAuthorization,
767
+ hint: "This adapter does not expose provider-native auth headers in its options, so external auth must be added inside custom fetch when apiKey is omitted."
768
+ });
769
+ return createAihubmix2({
770
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY2,
771
+ compatibility: options.compatibility,
772
+ fetch: createReasoningAwareResponsesFetch({
773
+ fetch: options.fetch,
774
+ stripAuthorization,
775
+ requestReasoning
776
+ })
777
+ });
778
+ }
779
+ function createReasoningAwareResponsesFetch(input) {
780
+ const baseFetch = createProviderFetch({
781
+ fetch: input.fetch,
782
+ stripHeaders: ["authorization"],
783
+ stripWhen: input.stripAuthorization
784
+ });
785
+ if (!input.requestReasoning)
786
+ return baseFetch;
787
+ const wrappedFetch = Object.assign(async (resource, init) => {
788
+ if (!init?.body)
789
+ return baseFetch(resource, init);
790
+ const body = parseJsonBody(init.body);
791
+ if (!isRecord(body) || body.reasoning !== undefined)
792
+ return baseFetch(resource, init);
793
+ return baseFetch(resource, {
794
+ ...init,
795
+ body: JSON.stringify({
796
+ ...body,
797
+ reasoning: input.requestReasoning
798
+ })
799
+ });
800
+ }, {
801
+ preconnect: typeof baseFetch.preconnect === "function" ? baseFetch.preconnect.bind(baseFetch) : undefined
802
+ });
803
+ return wrappedFetch;
804
+ }
805
+ function parseJsonBody(body) {
806
+ if (typeof body !== "string")
807
+ return;
808
+ try {
809
+ return JSON.parse(body);
810
+ } catch {
811
+ return;
812
+ }
813
+ }
814
+
815
+ // src/providers/aihubmix-responses/adapter.ts
816
+ var createAihubmixResponsesAdapter = createProviderFactory({
817
+ defaultProvider: "aihubmix-responses",
818
+ driver: aihubmixResponsesDriver
819
+ });
820
+ // src/providers/anthropic/driver.ts
821
+ import { APICallError as APICallError3 } from "@ai-sdk/provider";
822
+ import { createAnthropic } from "@ai-sdk/anthropic";
823
+
824
+ // src/providers/anthropic/state.ts
825
+ var ANTHROPIC_STATE_KEY = "anthropic";
826
+ function anthropicAssistantPrefixParts(message) {
827
+ const state = readProviderState(message, ANTHROPIC_STATE_KEY);
828
+ const rawBlocks = state?.blocks;
829
+ if (!Array.isArray(rawBlocks))
830
+ return [];
831
+ const parts = [];
832
+ for (const rawBlock of rawBlocks) {
833
+ if (!isRecord(rawBlock) || typeof rawBlock.type !== "string")
834
+ continue;
835
+ if (rawBlock.type === "thinking" && typeof rawBlock.signature === "string") {
836
+ parts.push({
837
+ type: "reasoning",
838
+ text: typeof rawBlock.thinking === "string" ? rawBlock.thinking : "",
839
+ providerOptions: {
840
+ anthropic: {
841
+ signature: rawBlock.signature
842
+ }
843
+ }
844
+ });
845
+ continue;
846
+ }
847
+ if (rawBlock.type === "redacted_thinking" && typeof rawBlock.data === "string") {
848
+ parts.push({
849
+ type: "reasoning",
850
+ text: "",
851
+ providerOptions: {
852
+ anthropic: {
853
+ redactedData: rawBlock.data
854
+ }
855
+ }
856
+ });
857
+ }
858
+ }
859
+ return parts;
860
+ }
861
+ function createAnthropicAssistantMetadata(result) {
862
+ const blocks = result.content.flatMap((part) => {
863
+ if (part.type !== "reasoning")
864
+ return [];
865
+ const metadata = part.providerMetadata?.anthropic;
866
+ if (!isRecord(metadata))
867
+ return [];
868
+ if (typeof metadata.signature === "string") {
869
+ return [{
870
+ type: "thinking",
871
+ thinking: part.text,
872
+ signature: metadata.signature
873
+ }];
874
+ }
875
+ if (typeof metadata.redactedData === "string") {
876
+ return [{
877
+ type: "redacted_thinking",
878
+ data: metadata.redactedData
879
+ }];
880
+ }
881
+ return [];
882
+ });
883
+ if (blocks.length === 0)
884
+ return;
885
+ return attachProviderState(undefined, ANTHROPIC_STATE_KEY, { blocks });
886
+ }
887
+
888
+ // src/providers/anthropic/driver.ts
889
+ var DEFAULT_ANTHROPIC_VERSION = "2023-06-01";
890
+ var PLACEHOLDER_API_KEY3 = "dim-placeholder-key";
891
+ var anthropicDriver = {
892
+ async generate(context) {
893
+ const model = createProvider3(context.options)(context.request.model.modelId);
894
+ const prompt = messagesToLanguageModelPrompt(context.request.messages, {
895
+ assistantPrefixParts: anthropicAssistantPrefixParts
896
+ });
897
+ const anthropicProviderOptions = {
898
+ ...buildAnthropicThinkingProviderOptions(context.request.reasoning) ?? {},
899
+ ...hasReasoningState(context.request.messages) ? { sendReasoning: true } : {}
900
+ };
901
+ const callOptions = {
902
+ prompt,
903
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
904
+ maxOutputTokens: context.request.maxOutputTokens,
905
+ temperature: context.request.temperature,
906
+ topP: context.request.topP,
907
+ stopSequences: context.request.stop,
908
+ abortSignal: context.request.signal,
909
+ ...Object.keys(anthropicProviderOptions).length > 0 ? { providerOptions: { anthropic: anthropicProviderOptions } } : {}
910
+ };
911
+ return generateWithAiSdk({
912
+ model,
913
+ callOptions,
914
+ createAssistantMetadata: createAnthropicAssistantMetadata
915
+ });
916
+ },
917
+ normalizeError(error) {
918
+ if (APICallError3.isInstance(error)) {
919
+ return createApiCallErrorPayload({
920
+ code: "anthropic_http_error",
921
+ provider: "Anthropic",
922
+ error
923
+ });
924
+ }
925
+ return createRequestErrorPayload({
926
+ code: "anthropic_request_error",
927
+ error
928
+ });
929
+ }
930
+ };
931
+ function createProvider3(options) {
932
+ const stripAuthentication = !options.apiKey && !hasHeader(options.headers, "x-api-key") && !hasHeader(options.headers, "authorization");
933
+ warnIfPlaceholderApiKey({
934
+ provider: "Anthropic",
935
+ shouldWarn: stripAuthentication
936
+ });
937
+ return createAnthropic({
938
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY3,
939
+ ...options.baseUrl ? { baseURL: normalizeBaseUrl(options.baseUrl) } : {},
940
+ headers: {
941
+ "anthropic-version": options.anthropicVersion ?? DEFAULT_ANTHROPIC_VERSION,
942
+ ...options.headers
943
+ },
944
+ fetch: createProviderFetch({
945
+ fetch: options.fetch,
946
+ stripHeaders: ["x-api-key", "authorization"],
947
+ stripWhen: stripAuthentication
948
+ })
949
+ });
950
+ }
951
+ function hasReasoningState(messages) {
952
+ return messages.some((message) => message.role === "assistant" && anthropicAssistantPrefixParts(message).length > 0);
953
+ }
954
+ function normalizeBaseUrl(baseUrl) {
955
+ const normalized = (baseUrl ?? "").replace(/\/$/, "");
956
+ return normalized.endsWith("/v1") ? normalized : `${normalized}/v1`;
957
+ }
958
+
959
+ // src/providers/anthropic/adapter.ts
960
+ var createAnthropicAdapter = createProviderFactory({
961
+ defaultProvider: "anthropic",
962
+ driver: anthropicDriver
963
+ });
964
+ // src/providers/deepseek/driver.ts
965
+ import { APICallError as APICallError4 } from "@ai-sdk/provider";
966
+ import { createDeepSeek } from "@ai-sdk/deepseek";
967
+ var DEFAULT_BASE_URL = "https://api.deepseek.com";
968
+ var PLACEHOLDER_API_KEY4 = "dim-placeholder-key";
969
+ var deepSeekDriver = {
970
+ async generate(context) {
971
+ const model = createProvider4(context.options).chat(context.request.model.modelId);
972
+ const deepseekProviderOptions = buildDeepSeekThinkingProviderOptions(context.request.reasoning);
973
+ const callOptions = {
974
+ prompt: messagesToLanguageModelPrompt(context.request.messages),
975
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
976
+ maxOutputTokens: context.request.maxOutputTokens,
977
+ temperature: context.request.temperature,
978
+ topP: context.request.topP,
979
+ stopSequences: context.request.stop,
980
+ abortSignal: context.request.signal,
981
+ ...deepseekProviderOptions ? { providerOptions: { deepseek: deepseekProviderOptions } } : {}
982
+ };
983
+ return generateWithAiSdk({
984
+ model,
985
+ callOptions
986
+ });
987
+ },
988
+ normalizeError(error) {
989
+ if (APICallError4.isInstance(error)) {
990
+ return createApiCallErrorPayload({
991
+ code: "deepseek_http_error",
992
+ provider: "DeepSeek",
993
+ error
994
+ });
995
+ }
996
+ return createRequestErrorPayload({
997
+ code: "deepseek_request_error",
998
+ error
999
+ });
1000
+ }
1001
+ };
1002
+ function createProvider4(options) {
1003
+ const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
1004
+ warnIfPlaceholderApiKey({
1005
+ provider: "DeepSeek",
1006
+ shouldWarn: stripAuthorization
1007
+ });
1008
+ return createDeepSeek({
1009
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY4,
1010
+ baseURL: normalizeBaseUrl2(options.baseUrl),
1011
+ headers: options.headers,
1012
+ fetch: createProviderFetch({
1013
+ fetch: options.fetch,
1014
+ stripHeaders: ["authorization"],
1015
+ stripWhen: stripAuthorization
1016
+ })
1017
+ });
1018
+ }
1019
+ function normalizeBaseUrl2(baseUrl) {
1020
+ return (baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
1021
+ }
1022
+
1023
+ // src/providers/deepseek/adapter.ts
1024
+ var createDeepSeekAdapter = createProviderFactory({
1025
+ defaultProvider: "deepseek",
1026
+ driver: deepSeekDriver
1027
+ });
1028
+ // src/providers/gemini/driver.ts
1029
+ import { APICallError as APICallError5 } from "@ai-sdk/provider";
1030
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
1031
+
1032
+ // src/providers/gemini/state.ts
1033
+ var GEMINI_STATE_KEY = "gemini";
1034
+ function geminiAssistantPrefixParts(message) {
1035
+ const state = readProviderState(message, GEMINI_STATE_KEY);
1036
+ const rawParts = state?.parts;
1037
+ if (!Array.isArray(rawParts))
1038
+ return [];
1039
+ const parts = [];
1040
+ for (const rawPart of rawParts) {
1041
+ if (!isRecord(rawPart))
1042
+ continue;
1043
+ const thoughtSignature = typeof rawPart.thoughtSignature === "string" ? rawPart.thoughtSignature : undefined;
1044
+ if (isRecord(rawPart.functionCall) && typeof rawPart.functionCall.name === "string") {
1045
+ parts.push({
1046
+ type: "tool-call",
1047
+ toolCallId: crypto.randomUUID(),
1048
+ toolName: rawPart.functionCall.name,
1049
+ input: isRecord(rawPart.functionCall.args) ? rawPart.functionCall.args : {},
1050
+ ...thoughtSignature ? {
1051
+ providerOptions: {
1052
+ google: {
1053
+ thoughtSignature
1054
+ }
1055
+ }
1056
+ } : {}
1057
+ });
1058
+ continue;
1059
+ }
1060
+ if (typeof rawPart.text === "string") {
1061
+ parts.push({
1062
+ type: rawPart.thought === true ? "reasoning" : "text",
1063
+ text: rawPart.text,
1064
+ ...thoughtSignature ? {
1065
+ providerOptions: {
1066
+ google: {
1067
+ thoughtSignature
1068
+ }
1069
+ }
1070
+ } : {}
1071
+ });
1072
+ }
1073
+ }
1074
+ return parts;
1075
+ }
1076
+ function createGeminiAssistantMetadata(result) {
1077
+ const parts = result.content.flatMap((part) => {
1078
+ const metadata = part.providerMetadata?.google;
1079
+ const thoughtSignature = isRecord(metadata) && typeof metadata.thoughtSignature === "string" ? metadata.thoughtSignature : undefined;
1080
+ if (!thoughtSignature && part.type !== "reasoning")
1081
+ return [];
1082
+ if (part.type === "reasoning") {
1083
+ return [{
1084
+ text: part.text,
1085
+ thought: true,
1086
+ thoughtSignature
1087
+ }];
1088
+ }
1089
+ if (part.type === "tool-call") {
1090
+ return [{
1091
+ functionCall: {
1092
+ name: part.toolName,
1093
+ args: parseToolArguments(part.input)
1094
+ },
1095
+ thoughtSignature
1096
+ }];
1097
+ }
1098
+ if (part.type === "text") {
1099
+ return [{
1100
+ text: part.text,
1101
+ thoughtSignature
1102
+ }];
1103
+ }
1104
+ return [];
1105
+ });
1106
+ if (parts.length === 0)
1107
+ return;
1108
+ return attachProviderState(undefined, GEMINI_STATE_KEY, { parts });
1109
+ }
1110
+ function parseToolArguments(input) {
1111
+ try {
1112
+ const parsed = JSON.parse(input);
1113
+ return isRecord(parsed) ? parsed : {};
1114
+ } catch {
1115
+ return {};
1116
+ }
1117
+ }
1118
+
1119
+ // src/providers/gemini/driver.ts
1120
+ var DEFAULT_BASE_URL2 = "https://generativelanguage.googleapis.com";
1121
+ var PLACEHOLDER_API_KEY5 = "dim-placeholder-key";
1122
+ var geminiDriver = {
1123
+ async generate(context) {
1124
+ const model = createProvider5(context.options)(context.request.model.modelId);
1125
+ const googleProviderOptions = buildGeminiThinkingProviderOptions(context.request.reasoning);
1126
+ const callOptions = {
1127
+ prompt: messagesToLanguageModelPrompt(context.request.messages, {
1128
+ assistantPrefixParts: geminiAssistantPrefixParts
1129
+ }),
1130
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
1131
+ maxOutputTokens: context.request.maxOutputTokens,
1132
+ temperature: context.request.temperature,
1133
+ topP: context.request.topP,
1134
+ stopSequences: context.request.stop,
1135
+ abortSignal: context.request.signal,
1136
+ ...googleProviderOptions ? { providerOptions: { google: googleProviderOptions } } : {}
1137
+ };
1138
+ return generateWithAiSdk({
1139
+ model,
1140
+ callOptions,
1141
+ createAssistantMetadata: createGeminiAssistantMetadata
1142
+ });
1143
+ },
1144
+ normalizeError(error) {
1145
+ if (APICallError5.isInstance(error)) {
1146
+ return createApiCallErrorPayload({
1147
+ code: "gemini_http_error",
1148
+ provider: "Gemini",
1149
+ error
1150
+ });
1151
+ }
1152
+ return createRequestErrorPayload({
1153
+ code: "gemini_request_error",
1154
+ error
1155
+ });
1156
+ }
1157
+ };
1158
+ function createProvider5(options) {
1159
+ const stripApiKey = !options.apiKey && !hasHeader(options.headers, "x-goog-api-key");
1160
+ warnIfPlaceholderApiKey({
1161
+ provider: "Gemini",
1162
+ shouldWarn: stripApiKey
1163
+ });
1164
+ return createGoogleGenerativeAI({
1165
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY5,
1166
+ baseURL: normalizeBaseUrl3(options.baseUrl),
1167
+ headers: options.headers,
1168
+ fetch: createProviderFetch({
1169
+ fetch: options.fetch,
1170
+ stripHeaders: ["x-goog-api-key"],
1171
+ stripWhen: stripApiKey
1172
+ })
1173
+ });
1174
+ }
1175
+ function normalizeBaseUrl3(baseUrl) {
1176
+ const normalized = (baseUrl ?? DEFAULT_BASE_URL2).replace(/\/$/, "");
1177
+ return normalized.endsWith("/v1beta") ? normalized : `${normalized}/v1beta`;
1178
+ }
1179
+
1180
+ // src/providers/gemini/adapter.ts
1181
+ var createGeminiAdapter = createProviderFactory({
1182
+ defaultProvider: "gemini",
1183
+ driver: geminiDriver
1184
+ });
1185
+ // src/providers/moonshotai/driver.ts
1186
+ import { APICallError as APICallError6 } from "@ai-sdk/provider";
1187
+ import { createMoonshotAI } from "@ai-sdk/moonshotai";
1188
+ var DEFAULT_BASE_URL3 = "https://api.moonshot.ai/v1";
1189
+ var PLACEHOLDER_API_KEY6 = "dim-placeholder-key";
1190
+ var moonshotAIDriver = {
1191
+ async generate(context) {
1192
+ const model = createProvider6(context.options).languageModel(context.request.model.modelId);
1193
+ const moonshotaiProviderOptions = buildMoonshotThinkingProviderOptions(context.request.reasoning);
1194
+ const callOptions = {
1195
+ prompt: messagesToLanguageModelPrompt(context.request.messages),
1196
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
1197
+ maxOutputTokens: context.request.maxOutputTokens,
1198
+ temperature: context.request.temperature,
1199
+ topP: context.request.topP,
1200
+ stopSequences: context.request.stop,
1201
+ abortSignal: context.request.signal,
1202
+ ...moonshotaiProviderOptions ? { providerOptions: { moonshotai: moonshotaiProviderOptions } } : {}
1203
+ };
1204
+ return generateWithAiSdk({
1205
+ model,
1206
+ callOptions
1207
+ });
1208
+ },
1209
+ normalizeError(error) {
1210
+ if (APICallError6.isInstance(error)) {
1211
+ return createApiCallErrorPayload({
1212
+ code: "moonshotai_http_error",
1213
+ provider: "MoonshotAI",
1214
+ error
1215
+ });
1216
+ }
1217
+ return createRequestErrorPayload({
1218
+ code: "moonshotai_request_error",
1219
+ error
1220
+ });
1221
+ }
1222
+ };
1223
+ function createProvider6(options) {
1224
+ const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
1225
+ warnIfPlaceholderApiKey({
1226
+ provider: "MoonshotAI",
1227
+ shouldWarn: stripAuthorization
1228
+ });
1229
+ return createMoonshotAI({
1230
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY6,
1231
+ baseURL: normalizeBaseUrl4(options.baseUrl),
1232
+ headers: options.headers,
1233
+ fetch: createProviderFetch({
1234
+ fetch: options.fetch,
1235
+ stripHeaders: ["authorization"],
1236
+ stripWhen: stripAuthorization
1237
+ })
1238
+ });
1239
+ }
1240
+ function normalizeBaseUrl4(baseUrl) {
1241
+ return (baseUrl ?? DEFAULT_BASE_URL3).replace(/\/$/, "");
1242
+ }
1243
+
1244
+ // src/providers/moonshotai/adapter.ts
1245
+ var createMoonshotAIAdapter = createProviderFactory({
1246
+ defaultProvider: "moonshotai",
1247
+ driver: moonshotAIDriver
1248
+ });
1249
+ // src/providers/openai/driver.ts
1250
+ import { APICallError as APICallError7 } from "@ai-sdk/provider";
1251
+ import { createOpenAI } from "@ai-sdk/openai";
1252
+ var DEFAULT_BASE_URL4 = "https://api.openai.com/v1";
1253
+ var PLACEHOLDER_API_KEY7 = "dim-placeholder-key";
1254
+ var openAIDriver = {
1255
+ async generate(context) {
1256
+ const model = createProvider7(context.options).chat(context.request.model.modelId);
1257
+ const callOptions = {
1258
+ prompt: messagesToLanguageModelPrompt(context.request.messages),
1259
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
1260
+ maxOutputTokens: context.request.maxOutputTokens,
1261
+ temperature: context.request.temperature,
1262
+ topP: context.request.topP,
1263
+ stopSequences: context.request.stop,
1264
+ abortSignal: context.request.signal
1265
+ };
1266
+ return generateWithAiSdk({
1267
+ model,
1268
+ callOptions
1269
+ });
1270
+ },
1271
+ normalizeError(error) {
1272
+ if (APICallError7.isInstance(error)) {
1273
+ return createApiCallErrorPayload({
1274
+ code: "openai_http_error",
1275
+ provider: "OpenAI-compatible",
1276
+ error
1277
+ });
1278
+ }
1279
+ return createRequestErrorPayload({
1280
+ code: "openai_request_error",
1281
+ error
1282
+ });
1283
+ }
1284
+ };
1285
+ function createProvider7(options) {
1286
+ const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
1287
+ warnIfPlaceholderApiKey({
1288
+ provider: "OpenAI-compatible",
1289
+ shouldWarn: stripAuthorization
1290
+ });
1291
+ return createOpenAI({
1292
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY7,
1293
+ baseURL: normalizeBaseUrl5(options.baseUrl),
1294
+ headers: options.headers,
1295
+ fetch: createProviderFetch({
1296
+ fetch: options.fetch,
1297
+ stripHeaders: ["authorization"],
1298
+ stripWhen: stripAuthorization
1299
+ })
1300
+ });
1301
+ }
1302
+ function normalizeBaseUrl5(baseUrl) {
1303
+ return (baseUrl ?? DEFAULT_BASE_URL4).replace(/\/$/, "");
1304
+ }
1305
+
1306
+ // src/providers/openai/adapter.ts
1307
+ var createOpenAIAdapter = createProviderFactory({
1308
+ defaultProvider: "openai-compatible",
1309
+ driver: openAIDriver
1310
+ });
1311
+ // src/providers/openai-responses/driver.ts
1312
+ import { APICallError as APICallError8 } from "@ai-sdk/provider";
1313
+ import { createOpenAI as createOpenAI2 } from "@ai-sdk/openai";
1314
+
1315
+ // src/providers/openai-responses/state.ts
1316
+ var OPENAI_RESPONSES_STATE_KEY = "openaiResponses";
1317
+ function sliceMessagesForOpenAIResponses(messages) {
1318
+ return sliceMessagesForResponses(messages, OPENAI_RESPONSES_STATE_KEY);
1319
+ }
1320
+ function createOpenAIResponsesAssistantMetadata(result) {
1321
+ return createResponsesAssistantMetadata({
1322
+ result,
1323
+ stateKey: OPENAI_RESPONSES_STATE_KEY,
1324
+ providerMetadataKey: "openai"
1325
+ });
1326
+ }
1327
+
1328
+ // src/providers/openai-responses/driver.ts
1329
+ var DEFAULT_BASE_URL5 = "https://api.openai.com/v1";
1330
+ var PLACEHOLDER_API_KEY8 = "dim-placeholder-key";
1331
+ var openAIResponsesDriver = {
1332
+ async generate(context) {
1333
+ const model = createProvider8(context.options).responses(context.request.model.modelId);
1334
+ const { messages, previousResponseId } = sliceMessagesForOpenAIResponses(context.request.messages);
1335
+ const openaiProviderOptions = {
1336
+ ...buildOpenAIResponsesProviderOptions(context.request.reasoning) ?? {},
1337
+ ...previousResponseId ? { previousResponseId } : {}
1338
+ };
1339
+ const callOptions = {
1340
+ prompt: messagesToLanguageModelPrompt(messages),
1341
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
1342
+ maxOutputTokens: context.request.maxOutputTokens,
1343
+ temperature: context.request.temperature,
1344
+ topP: context.request.topP,
1345
+ stopSequences: context.request.stop,
1346
+ abortSignal: context.request.signal,
1347
+ ...Object.keys(openaiProviderOptions).length > 0 ? { providerOptions: { openai: openaiProviderOptions } } : {}
1348
+ };
1349
+ return generateWithAiSdk({
1350
+ model,
1351
+ callOptions,
1352
+ createAssistantMetadata: createOpenAIResponsesAssistantMetadata
1353
+ });
1354
+ },
1355
+ normalizeError(error) {
1356
+ if (APICallError8.isInstance(error)) {
1357
+ return createApiCallErrorPayload({
1358
+ code: "openai_responses_http_error",
1359
+ provider: "OpenAI Responses",
1360
+ error
1361
+ });
1362
+ }
1363
+ return createRequestErrorPayload({
1364
+ code: "openai_responses_request_error",
1365
+ error
1366
+ });
1367
+ }
1368
+ };
1369
+ function createProvider8(options) {
1370
+ const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
1371
+ warnIfPlaceholderApiKey({
1372
+ provider: "OpenAI Responses",
1373
+ shouldWarn: stripAuthorization
1374
+ });
1375
+ return createOpenAI2({
1376
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY8,
1377
+ baseURL: normalizeBaseUrl6(options.baseUrl),
1378
+ headers: options.headers,
1379
+ fetch: createProviderFetch({
1380
+ fetch: options.fetch,
1381
+ stripHeaders: ["authorization"],
1382
+ stripWhen: stripAuthorization
1383
+ })
1384
+ });
1385
+ }
1386
+ function normalizeBaseUrl6(baseUrl) {
1387
+ return (baseUrl ?? DEFAULT_BASE_URL5).replace(/\/$/, "");
1388
+ }
1389
+
1390
+ // src/providers/openai-responses/adapter.ts
1391
+ var createOpenAIResponsesAdapter = createProviderFactory({
1392
+ defaultProvider: "openai-responses",
1393
+ driver: openAIResponsesDriver
1394
+ });
1395
+ // src/providers/xai/driver.ts
1396
+ import { APICallError as APICallError9 } from "@ai-sdk/provider";
1397
+ import { createXai } from "@ai-sdk/xai";
1398
+ var DEFAULT_BASE_URL6 = "https://api.x.ai/v1";
1399
+ var PLACEHOLDER_API_KEY9 = "dim-placeholder-key";
1400
+ var xaiDriver = {
1401
+ async generate(context) {
1402
+ const model = createProvider9(context.options).chat(context.request.model.modelId);
1403
+ const reasoningEffort = resolveLowHighReasoningEffort(context.request.reasoning);
1404
+ const callOptions = {
1405
+ prompt: messagesToLanguageModelPrompt(context.request.messages),
1406
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
1407
+ maxOutputTokens: context.request.maxOutputTokens,
1408
+ temperature: context.request.temperature,
1409
+ topP: context.request.topP,
1410
+ stopSequences: context.request.stop,
1411
+ abortSignal: context.request.signal,
1412
+ ...reasoningEffort ? { providerOptions: { xai: { reasoningEffort } } } : {}
1413
+ };
1414
+ return generateWithAiSdk({
1415
+ model,
1416
+ callOptions
1417
+ });
1418
+ },
1419
+ normalizeError(error) {
1420
+ if (APICallError9.isInstance(error)) {
1421
+ return createApiCallErrorPayload({
1422
+ code: "xai_http_error",
1423
+ provider: "xAI",
1424
+ error
1425
+ });
1426
+ }
1427
+ return createRequestErrorPayload({
1428
+ code: "xai_request_error",
1429
+ error
1430
+ });
1431
+ }
1432
+ };
1433
+ function createProvider9(options) {
1434
+ const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
1435
+ warnIfPlaceholderApiKey({
1436
+ provider: "xAI",
1437
+ shouldWarn: stripAuthorization
1438
+ });
1439
+ return createXai({
1440
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY9,
1441
+ baseURL: normalizeBaseUrl7(options.baseUrl),
1442
+ headers: options.headers,
1443
+ fetch: createProviderFetch({
1444
+ fetch: options.fetch,
1445
+ stripHeaders: ["authorization"],
1446
+ stripWhen: stripAuthorization
1447
+ })
1448
+ });
1449
+ }
1450
+ function normalizeBaseUrl7(baseUrl) {
1451
+ return (baseUrl ?? DEFAULT_BASE_URL6).replace(/\/$/, "");
1452
+ }
1453
+
1454
+ // src/providers/xai/adapter.ts
1455
+ var createXaiAdapter = createProviderFactory({
1456
+ defaultProvider: "xai",
1457
+ driver: xaiDriver
1458
+ });
1459
+ // src/providers/xai-responses/driver.ts
1460
+ import { APICallError as APICallError10 } from "@ai-sdk/provider";
1461
+ import { createXai as createXai2 } from "@ai-sdk/xai";
1462
+
1463
+ // src/providers/xai-responses/state.ts
1464
+ var XAI_RESPONSES_STATE_KEY = "xaiResponses";
1465
+ function sliceMessagesForXaiResponses(messages) {
1466
+ return sliceMessagesForResponses(messages, XAI_RESPONSES_STATE_KEY);
1467
+ }
1468
+ function createXaiResponsesAssistantMetadata(result) {
1469
+ return createResponsesAssistantMetadata({
1470
+ result,
1471
+ stateKey: XAI_RESPONSES_STATE_KEY,
1472
+ providerMetadataKey: "xai"
1473
+ });
1474
+ }
1475
+
1476
+ // src/providers/xai-responses/driver.ts
1477
+ var DEFAULT_BASE_URL7 = "https://api.x.ai/v1";
1478
+ var PLACEHOLDER_API_KEY10 = "dim-placeholder-key";
1479
+ var xaiResponsesDriver = {
1480
+ async generate(context) {
1481
+ const model = createProvider10(context.options).responses(context.request.model.modelId);
1482
+ const { messages, previousResponseId } = sliceMessagesForXaiResponses(context.request.messages);
1483
+ const reasoningEffort = resolveLowMediumHighReasoningEffort(context.request.reasoning);
1484
+ const xaiProviderOptions = {
1485
+ ...reasoningEffort ? { reasoningEffort } : {},
1486
+ ...previousResponseId ? { previousResponseId } : {}
1487
+ };
1488
+ const callOptions = {
1489
+ prompt: messagesToLanguageModelPrompt(messages),
1490
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
1491
+ maxOutputTokens: context.request.maxOutputTokens,
1492
+ temperature: context.request.temperature,
1493
+ topP: context.request.topP,
1494
+ stopSequences: context.request.stop,
1495
+ abortSignal: context.request.signal,
1496
+ ...Object.keys(xaiProviderOptions).length > 0 ? { providerOptions: { xai: xaiProviderOptions } } : {}
1497
+ };
1498
+ return generateWithAiSdk({
1499
+ model,
1500
+ callOptions,
1501
+ createAssistantMetadata: createXaiResponsesAssistantMetadata
1502
+ });
1503
+ },
1504
+ normalizeError(error) {
1505
+ if (APICallError10.isInstance(error)) {
1506
+ return createApiCallErrorPayload({
1507
+ code: "xai_responses_http_error",
1508
+ provider: "xAI Responses",
1509
+ error
1510
+ });
1511
+ }
1512
+ return createRequestErrorPayload({
1513
+ code: "xai_responses_request_error",
1514
+ error
1515
+ });
1516
+ }
1517
+ };
1518
+ function createProvider10(options) {
1519
+ const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
1520
+ warnIfPlaceholderApiKey({
1521
+ provider: "xAI Responses",
1522
+ shouldWarn: stripAuthorization
1523
+ });
1524
+ return createXai2({
1525
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY10,
1526
+ baseURL: normalizeBaseUrl8(options.baseUrl),
1527
+ headers: options.headers,
1528
+ fetch: createProviderFetch({
1529
+ fetch: options.fetch,
1530
+ stripHeaders: ["authorization"],
1531
+ stripWhen: stripAuthorization
1532
+ })
1533
+ });
1534
+ }
1535
+ function normalizeBaseUrl8(baseUrl) {
1536
+ return (baseUrl ?? DEFAULT_BASE_URL7).replace(/\/$/, "");
1537
+ }
1538
+
1539
+ // src/providers/xai-responses/adapter.ts
1540
+ var createXaiResponsesAdapter = createProviderFactory({
1541
+ defaultProvider: "xai-responses",
1542
+ driver: xaiResponsesDriver
1543
+ });
1544
+ // src/providers/zenmux/driver.ts
1545
+ import { APICallError as APICallError11 } from "@ai-sdk/provider";
1546
+ import { createZenMux } from "@zenmux/ai-sdk-provider";
1547
+ var DEFAULT_BASE_URL8 = "https://zenmux.ai/api/v1";
1548
+ var PLACEHOLDER_API_KEY11 = "dim-placeholder-key";
1549
+ var ZENMUX_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
1550
+ var zenmuxDriver = {
1551
+ async generate(context) {
1552
+ const model = createProvider11(context.options).chat(context.request.model.modelId);
1553
+ const zenmuxProviderOptions = buildReasoningEffortProviderOptions(context.request.reasoning, ZENMUX_REASONING_EFFORTS);
1554
+ const callOptions = {
1555
+ prompt: messagesToLanguageModelPrompt(context.request.messages),
1556
+ tools: mapToolDefinitionsToLanguageModelTools(context.request.tools),
1557
+ maxOutputTokens: context.request.maxOutputTokens,
1558
+ temperature: context.request.temperature,
1559
+ topP: context.request.topP,
1560
+ stopSequences: context.request.stop,
1561
+ abortSignal: context.request.signal,
1562
+ ...zenmuxProviderOptions ? { providerOptions: { zenmux: zenmuxProviderOptions } } : {}
1563
+ };
1564
+ return generateWithAiSdk({
1565
+ model,
1566
+ callOptions
1567
+ });
1568
+ },
1569
+ normalizeError(error) {
1570
+ if (APICallError11.isInstance(error)) {
1571
+ return createApiCallErrorPayload({
1572
+ code: "zenmux_http_error",
1573
+ provider: "ZenMux",
1574
+ error
1575
+ });
1576
+ }
1577
+ return createRequestErrorPayload({
1578
+ code: "zenmux_request_error",
1579
+ error
1580
+ });
1581
+ }
1582
+ };
1583
+ function createProvider11(options) {
1584
+ const stripAuthorization = !options.apiKey && !hasHeader(options.headers, "authorization");
1585
+ warnIfPlaceholderApiKey({
1586
+ provider: "ZenMux",
1587
+ shouldWarn: stripAuthorization
1588
+ });
1589
+ return createZenMux({
1590
+ apiKey: options.apiKey ?? PLACEHOLDER_API_KEY11,
1591
+ baseURL: normalizeBaseUrl9(options.baseUrl),
1592
+ headers: options.headers,
1593
+ organization: options.organization,
1594
+ project: options.project,
1595
+ fetch: createProviderFetch({
1596
+ fetch: options.fetch,
1597
+ stripHeaders: ["authorization"],
1598
+ stripWhen: stripAuthorization
1599
+ })
1600
+ });
1601
+ }
1602
+ function normalizeBaseUrl9(baseUrl) {
1603
+ return (baseUrl ?? DEFAULT_BASE_URL8).replace(/\/$/, "");
1604
+ }
1605
+
1606
+ // src/providers/zenmux/adapter.ts
1607
+ var createZenMuxAdapter = createProviderFactory({
1608
+ defaultProvider: "zenmux",
1609
+ driver: zenmuxDriver
1610
+ });
1611
+ // src/context/auto-context-manager.ts
1612
+ import path from "node:path";
1613
+
1614
+ // src/utils/id.ts
1615
+ function createId(prefix) {
1616
+ return `${prefix}_${crypto.randomUUID()}`;
1617
+ }
1618
+
1619
+ // src/context/auto-context-manager.ts
1620
+ class AutoContextManager {
1621
+ services;
1622
+ pluginHost;
1623
+ maxItems;
1624
+ maxChars;
1625
+ constructor(options) {
1626
+ this.services = options.services;
1627
+ this.pluginHost = options.pluginHost;
1628
+ this.maxItems = options.maxItems ?? 8;
1629
+ this.maxChars = options.maxChars ?? 8000;
1630
+ }
1631
+ async resolve(options) {
1632
+ const items = [];
1633
+ if (options.cwd) {
1634
+ items.push({
1635
+ id: createId("ctx"),
1636
+ type: "cwd",
1637
+ title: "Working directory",
1638
+ content: options.cwd,
1639
+ priority: 10,
1640
+ source: "agent"
1641
+ });
1642
+ }
1643
+ items.push(...await this.resolveExplicitFiles(options.input, options.cwd));
1644
+ items.push(...await this.resolveRecentFiles(options.cwd));
1645
+ items.push(...await this.resolveGitState(options.cwd));
1646
+ const contributed = await this.pluginHost?.collectContext({
1647
+ sessionId: options.sessionId,
1648
+ input: options.input,
1649
+ messages: options.messages,
1650
+ cwd: options.cwd
1651
+ });
1652
+ if (contributed)
1653
+ items.push(...contributed);
1654
+ return budgetContext(items, this.maxItems, this.maxChars);
1655
+ }
1656
+ format(items) {
1657
+ if (items.length === 0)
1658
+ return [];
1659
+ const sections = items.map((item) => {
1660
+ return [`[${item.title}]`, item.content].join(`
1661
+ `);
1662
+ });
1663
+ return [`Additional context for this turn:
1664
+
1665
+ ${sections.join(`
1666
+
1667
+ `)}`];
1668
+ }
1669
+ async resolveExplicitFiles(input, cwd) {
1670
+ const text = inputToText(input);
1671
+ const candidates = extractFileCandidates(text);
1672
+ const items = [];
1673
+ for (const candidate of candidates) {
1674
+ if (!cwd)
1675
+ break;
1676
+ if (!await this.services.fileSystem.exists(candidate, { cwd }))
1677
+ continue;
1678
+ const content = await safeReadText(this.services, candidate, cwd);
1679
+ if (!content)
1680
+ continue;
1681
+ items.push({
1682
+ id: createId("ctx"),
1683
+ type: "file",
1684
+ title: `File: ${candidate}`,
1685
+ content,
1686
+ priority: 100,
1687
+ source: "explicit-file"
1688
+ });
1689
+ }
1690
+ return items;
1691
+ }
1692
+ async resolveRecentFiles(cwd) {
1693
+ if (!cwd || !this.pluginHost)
1694
+ return [];
1695
+ const items = [];
1696
+ for (const filePath of this.pluginHost.recentFiles(3)) {
1697
+ const relative = toRelative(cwd, filePath);
1698
+ const content = await safeReadText(this.services, relative, cwd);
1699
+ if (!content)
1700
+ continue;
1701
+ items.push({
1702
+ id: createId("ctx"),
1703
+ type: "file",
1704
+ title: `Recent file: ${relative}`,
1705
+ content,
1706
+ priority: 70,
1707
+ source: "recent-file"
1708
+ });
1709
+ }
1710
+ return items;
1711
+ }
1712
+ async resolveGitState(cwd) {
1713
+ if (!cwd)
1714
+ return [];
1715
+ const items = [];
1716
+ const status = await this.services.git.status({ cwd });
1717
+ if (status) {
1718
+ items.push({
1719
+ id: createId("ctx"),
1720
+ type: "git_status",
1721
+ title: "Git status",
1722
+ content: status,
1723
+ priority: 60,
1724
+ source: "git"
1725
+ });
1726
+ }
1727
+ const diff = await this.services.git.diff({ cwd });
1728
+ if (diff) {
1729
+ items.push({
1730
+ id: createId("ctx"),
1731
+ type: "git_diff",
1732
+ title: "Git diff",
1733
+ content: trimText(diff, 4000),
1734
+ priority: 50,
1735
+ source: "git"
1736
+ });
1737
+ }
1738
+ return items;
1739
+ }
1740
+ }
1741
+ function inputToText(input) {
1742
+ return contentToText(normalizeContent(input));
1743
+ }
1744
+ function extractFileCandidates(text) {
1745
+ const matches = text.match(/(?:[A-Za-z0-9._-]+\/)*[A-Za-z0-9._-]+\.[A-Za-z0-9_-]+/g) ?? [];
1746
+ return [...new Set(matches)];
1747
+ }
1748
+ function trimText(text, maxChars) {
1749
+ return text.length <= maxChars ? text : `${text.slice(0, maxChars)}
1750
+ ...`;
1751
+ }
1752
+ async function safeReadText(services, filePath, cwd) {
1753
+ try {
1754
+ const text = await services.fileSystem.readText(filePath, { cwd });
1755
+ return trimText(text, 2000);
1756
+ } catch {
1757
+ return null;
1758
+ }
1759
+ }
1760
+ function budgetContext(items, maxItems, maxChars) {
1761
+ const sorted = [...items].sort((left, right) => right.priority - left.priority);
1762
+ const selected = [];
1763
+ let totalChars = 0;
1764
+ for (const item of sorted) {
1765
+ if (selected.length >= maxItems)
1766
+ break;
1767
+ if (totalChars + item.content.length > maxChars && selected.length > 0)
1768
+ continue;
1769
+ selected.push(item);
1770
+ totalChars += item.content.length;
1771
+ }
1772
+ return selected;
1773
+ }
1774
+ function toRelative(cwd, filePath) {
1775
+ if (!path.isAbsolute(filePath))
1776
+ return filePath;
1777
+ return path.relative(cwd, filePath) || path.basename(filePath);
1778
+ }
1779
+ // src/plugin-host/helpers.ts
1780
+ function isHookControlResult(value) {
1781
+ if (!value || typeof value !== "object")
1782
+ return false;
1783
+ const candidate = value;
1784
+ return (candidate.type === "continue" || candidate.type === "replace" || candidate.type === "stop") && "payload" in candidate;
1785
+ }
1786
+ function isToolBeforeExecuteControlResult(value) {
1787
+ if (!value || typeof value !== "object")
1788
+ return false;
1789
+ const candidate = value;
1790
+ return candidate.type === "allow" || candidate.type === "deny" || candidate.type === "ask" || candidate.type === "replaceToolCall" || candidate.type === "provideResult";
1791
+ }
1792
+ function isNotificationControlResult(value) {
1793
+ if (!value || typeof value !== "object")
1794
+ return false;
1795
+ const candidate = value;
1796
+ return candidate.type === "continue" || candidate.type === "replace" || candidate.type === "suppress";
1797
+ }
1798
+ function isRunStopControlResult(value) {
1799
+ if (!value || typeof value !== "object")
1800
+ return false;
1801
+ const candidate = value;
1802
+ return candidate.type === "continue" || candidate.type === "finalize";
1803
+ }
1804
+
1805
+ // src/plugin-host/hook-pipeline.ts
1806
+ class HookPipeline {
1807
+ registrations = [];
1808
+ nextOrder = 0;
1809
+ register(pluginId, pluginPriority, hooks, services) {
1810
+ if (!hooks)
1811
+ return;
1812
+ for (const entry of hooks) {
1813
+ if (!entry.middleware?.length && !entry.observers?.length)
1814
+ continue;
1815
+ if (entry.descriptor.name === "model.event" && entry.middleware && entry.middleware.length > 0)
1816
+ throw new Error(`Plugin ${pluginId} cannot register middleware for model.event`);
1817
+ if (entry.descriptor.mode === "async" && entry.middleware && entry.middleware.length > 0)
1818
+ throw new Error(`Plugin ${pluginId} cannot register async middleware for ${entry.descriptor.name}`);
1819
+ this.registrations.push({
1820
+ pluginId,
1821
+ order: this.nextOrder++,
1822
+ priority: entry.descriptor.priority ?? pluginPriority,
1823
+ descriptor: entry.descriptor,
1824
+ services,
1825
+ middleware: [...entry.middleware ?? []],
1826
+ observers: [...entry.observers ?? []]
1827
+ });
1828
+ }
1829
+ this.registrations.sort((left, right) => {
1830
+ if (left.priority !== right.priority)
1831
+ return right.priority - left.priority;
1832
+ return left.order - right.order;
1833
+ });
1834
+ }
1835
+ async runMiddleware(name, payload, context) {
1836
+ let current = payload;
1837
+ for (const registration of this.matchingRegistrations(name, current)) {
1838
+ for (const middleware of registration.middleware) {
1839
+ const result = await this.runMiddlewareHandler(registration, middleware, current, context);
1840
+ if (result === undefined)
1841
+ continue;
1842
+ if (isHookControlResult(result)) {
1843
+ current = result.payload;
1844
+ if (result.type === "stop")
1845
+ return current;
1846
+ continue;
1847
+ }
1848
+ if (isNotificationControlResult(result) || isRunStopControlResult(result) || isToolBeforeExecuteControlResult(result))
1849
+ throw new Error(`Hook ${registration.descriptor.name} returned an unsupported control result`);
1850
+ current = result;
1851
+ }
1852
+ }
1853
+ return current;
1854
+ }
1855
+ async runToolBeforeExecute(payload, context) {
1856
+ let current = payload;
1857
+ for (const registration of this.matchingRegistrations("tool.beforeExecute", current)) {
1858
+ for (const middleware of registration.middleware) {
1859
+ const result = await this.runMiddlewareHandler(registration, middleware, current, context);
1860
+ if (result === undefined)
1861
+ continue;
1862
+ if (isHookControlResult(result)) {
1863
+ current = result.payload;
1864
+ if (result.type === "stop")
1865
+ return { payload: current };
1866
+ continue;
1867
+ }
1868
+ if (isToolBeforeExecuteControlResult(result)) {
1869
+ if (result.type === "replaceToolCall") {
1870
+ current = { ...current, toolCall: result.toolCall };
1871
+ continue;
1872
+ }
1873
+ if (result.type === "ask" && result.toolCall)
1874
+ current = { ...current, toolCall: result.toolCall };
1875
+ return { payload: current, control: result };
1876
+ }
1877
+ current = result;
1878
+ }
1879
+ }
1880
+ return { payload: current };
1881
+ }
1882
+ async runNotifyMessage(payload, context) {
1883
+ let current = payload;
1884
+ for (const registration of this.matchingRegistrations("notify.message", current)) {
1885
+ for (const middleware of registration.middleware) {
1886
+ const result = await this.runMiddlewareHandler(registration, middleware, current, context);
1887
+ if (result === undefined)
1888
+ continue;
1889
+ if (isHookControlResult(result)) {
1890
+ current = result.payload;
1891
+ if (result.type === "stop")
1892
+ return { payload: current };
1893
+ continue;
1894
+ }
1895
+ if (isNotificationControlResult(result)) {
1896
+ if (result.type === "replace") {
1897
+ current = { ...current, notification: result.notification };
1898
+ continue;
1899
+ }
1900
+ if (result.type === "suppress")
1901
+ return { payload: current, suppressed: true };
1902
+ continue;
1903
+ }
1904
+ current = result;
1905
+ }
1906
+ }
1907
+ return { payload: current };
1908
+ }
1909
+ async runRunStop(payload, context) {
1910
+ let current = payload;
1911
+ for (const registration of this.matchingRegistrations("run.stop", current)) {
1912
+ for (const middleware of registration.middleware) {
1913
+ const result = await this.runMiddlewareHandler(registration, middleware, current, context);
1914
+ if (result === undefined)
1915
+ continue;
1916
+ if (isHookControlResult(result)) {
1917
+ current = result.payload;
1918
+ if (result.type === "stop")
1919
+ return { payload: current };
1920
+ continue;
1921
+ }
1922
+ if (isRunStopControlResult(result))
1923
+ return { payload: current, control: result };
1924
+ current = result;
1925
+ }
1926
+ }
1927
+ return { payload: current };
1928
+ }
1929
+ async runObservers(name, payload, context) {
1930
+ for (const registration of this.matchingRegistrations(name, payload)) {
1931
+ for (const observer of registration.observers) {
1932
+ const task = this.runObserverHandler(registration, observer, payload, context);
1933
+ if (registration.descriptor.mode === "async") {
1934
+ task.catch(() => {});
1935
+ continue;
1936
+ }
1937
+ await task.catch(() => {});
1938
+ }
1939
+ }
1940
+ }
1941
+ matchingRegistrations(name, payload) {
1942
+ return this.registrations.filter((registration) => {
1943
+ return registration.descriptor.name === name && matchesHookDescriptor(registration.descriptor, payload);
1944
+ });
1945
+ }
1946
+ async runMiddlewareHandler(registration, middleware, payload, context) {
1947
+ const task = Promise.resolve(middleware({
1948
+ payload,
1949
+ context: this.withHandlerMetadata(context, registration)
1950
+ }));
1951
+ return await withTimeout(task, registration.descriptor.timeoutMs, () => {
1952
+ return new Error(`Hook ${registration.descriptor.name} for plugin ${registration.pluginId} timed out after ${registration.descriptor.timeoutMs}ms`);
1953
+ });
1954
+ }
1955
+ async runObserverHandler(registration, observer, payload, context) {
1956
+ const task = Promise.resolve(observer({
1957
+ payload,
1958
+ context: this.withHandlerMetadata(context, registration)
1959
+ }));
1960
+ await withTimeout(task, registration.descriptor.timeoutMs, () => {
1961
+ return new Error(`Hook ${registration.descriptor.name} for plugin ${registration.pluginId} timed out after ${registration.descriptor.timeoutMs}ms`);
1962
+ });
1963
+ }
1964
+ withHandlerMetadata(context, registration) {
1965
+ return {
1966
+ ...context,
1967
+ services: registration.services ?? context.services,
1968
+ status: context.status ? structuredClone(context.status) : undefined,
1969
+ metadata: {
1970
+ ...context.metadata,
1971
+ pluginId: registration.pluginId,
1972
+ hookName: registration.descriptor.name
1973
+ }
1974
+ };
1975
+ }
1976
+ }
1977
+ function matchesHookDescriptor(descriptor, payload) {
1978
+ const matcher = descriptor.when;
1979
+ if (!matcher)
1980
+ return true;
1981
+ if (matcher.toolName && !matchesValue(matcher.toolName, readToolName(payload)))
1982
+ return false;
1983
+ if (matcher.notificationType && !matchesValue(matcher.notificationType, readNotificationType(payload)))
1984
+ return false;
1985
+ if (matcher.stopReason && !matchesValue(matcher.stopReason, readStopReason(payload)))
1986
+ return false;
1987
+ if (matcher.source && !matchesValue(matcher.source, readSource(payload)))
1988
+ return false;
1989
+ return true;
1990
+ }
1991
+ function readToolName(payload) {
1992
+ if ("toolCall" in payload)
1993
+ return payload.toolCall.function.name;
1994
+ return;
1995
+ }
1996
+ function readNotificationType(payload) {
1997
+ if ("notification" in payload)
1998
+ return payload.notification.type;
1999
+ return;
2000
+ }
2001
+ function readStopReason(payload) {
2002
+ if ("stopReason" in payload)
2003
+ return payload.stopReason;
2004
+ return;
2005
+ }
2006
+ function readSource(payload) {
2007
+ if ("notification" in payload)
2008
+ return payload.notification.source;
2009
+ return;
2010
+ }
2011
+ function matchesValue(expected, actual) {
2012
+ if (!actual)
2013
+ return false;
2014
+ if (Array.isArray(expected))
2015
+ return expected.includes(actual);
2016
+ return expected === actual;
2017
+ }
2018
+ async function withTimeout(promise, timeoutMs, createError) {
2019
+ if (!timeoutMs || timeoutMs <= 0)
2020
+ return await promise;
2021
+ let timeoutHandle;
2022
+ try {
2023
+ return await Promise.race([
2024
+ promise,
2025
+ new Promise((_, reject) => {
2026
+ timeoutHandle = setTimeout(() => reject(createError()), timeoutMs);
2027
+ })
2028
+ ]);
2029
+ } finally {
2030
+ if (timeoutHandle)
2031
+ clearTimeout(timeoutHandle);
2032
+ }
2033
+ }
2034
+
2035
+ // src/plugin-host/plugin-host.ts
2036
+ class PluginHost {
2037
+ pipeline = new HookPipeline;
2038
+ contextContributors = [];
2039
+ promptContributors = [];
2040
+ tools = [];
2041
+ sessionControllerFactories = [];
2042
+ services;
2043
+ cwd;
2044
+ agentId;
2045
+ tracker;
2046
+ constructor(options) {
2047
+ this.agentId = options.agentId;
2048
+ this.cwd = options.cwd;
2049
+ this.services = options.services;
2050
+ this.tracker = options.tracker;
2051
+ for (const plugin of options.plugins ?? []) {
2052
+ const priority = plugin.manifest.priority ?? 0;
2053
+ const scopedServices = options.permissionGateway.scopeServices(this.services, plugin.manifest.id, plugin.manifest.permissions);
2054
+ const setup = plugin.setup?.({
2055
+ cwd: this.cwd,
2056
+ manifest: plugin.manifest,
2057
+ services: scopedServices
2058
+ });
2059
+ this.pipeline.register(plugin.manifest.id, priority, setup?.hooks, scopedServices);
2060
+ for (const tool of setup?.tools ?? []) {
2061
+ this.tools.push({
2062
+ pluginId: plugin.manifest.id,
2063
+ tool: wrapTool(plugin.manifest.id, tool, scopedServices)
2064
+ });
2065
+ }
2066
+ for (const contributor of setup?.contextContributors ?? [])
2067
+ this.contextContributors.push({ pluginId: plugin.manifest.id, contributor });
2068
+ for (const contributor of setup?.promptContributors ?? [])
2069
+ this.promptContributors.push({ pluginId: plugin.manifest.id, contributor });
2070
+ if (setup?.createSessionController) {
2071
+ this.sessionControllerFactories.push({
2072
+ pluginId: plugin.manifest.id,
2073
+ factory: setup.createSessionController,
2074
+ services: scopedServices
2075
+ });
2076
+ }
2077
+ }
2078
+ }
2079
+ pluginTools() {
2080
+ return this.tools.map((entry) => entry.tool);
2081
+ }
2082
+ recentFiles(limit = 5) {
2083
+ return this.tracker?.recentFiles(limit) ?? [];
2084
+ }
2085
+ createSessionControllers(input) {
2086
+ const controllers = new Map;
2087
+ for (const entry of this.sessionControllerFactories) {
2088
+ controllers.set(entry.pluginId, entry.factory({
2089
+ sessionId: input.sessionId,
2090
+ metadata: input.metadata ? structuredClone(input.metadata) : undefined,
2091
+ getStatus: input.getStatus,
2092
+ pluginState: entry.services.pluginState,
2093
+ save: input.save,
2094
+ isRunning: input.isRunning
2095
+ }));
2096
+ }
2097
+ return controllers;
2098
+ }
2099
+ async runMiddleware(name, payload, context = {}) {
2100
+ return this.pipeline.runMiddleware(name, payload, this.createRuntimeContext(context));
2101
+ }
2102
+ async runToolBeforeExecute(payload, context = {}) {
2103
+ return this.pipeline.runToolBeforeExecute(payload, this.createRuntimeContext(context));
2104
+ }
2105
+ async runNotifyMessage(payload, context = {}) {
2106
+ return this.pipeline.runNotifyMessage(payload, this.createRuntimeContext(context));
2107
+ }
2108
+ async runRunStop(payload, context = {}) {
2109
+ return this.pipeline.runRunStop(payload, this.createRuntimeContext(context));
2110
+ }
2111
+ async runObservers(name, payload, context = {}) {
2112
+ await this.pipeline.runObservers(name, payload, this.createRuntimeContext(context));
2113
+ }
2114
+ async collectContext(input) {
2115
+ const items = [];
2116
+ for (const entry of this.contextContributors) {
2117
+ const next = await entry.contributor(input);
2118
+ if (next.length > 0)
2119
+ items.push(...next);
2120
+ }
2121
+ return items;
2122
+ }
2123
+ async collectPromptSegments(input) {
2124
+ const segments = [];
2125
+ for (const entry of this.promptContributors) {
2126
+ const next = await entry.contributor(input);
2127
+ if (!next)
2128
+ continue;
2129
+ if (Array.isArray(next))
2130
+ segments.push(...next.filter(Boolean));
2131
+ else
2132
+ segments.push(next);
2133
+ }
2134
+ return segments;
2135
+ }
2136
+ createRuntimeContext(context) {
2137
+ return {
2138
+ agentId: this.agentId,
2139
+ cwd: context.cwd ?? this.cwd,
2140
+ sessionId: context.sessionId,
2141
+ requestId: context.requestId,
2142
+ iteration: context.iteration,
2143
+ status: context.status ? structuredClone(context.status) : undefined,
2144
+ metadata: context.metadata,
2145
+ services: context.services ?? this.services
2146
+ };
2147
+ }
2148
+ }
2149
+ function wrapTool(pluginId, tool, services) {
2150
+ return {
2151
+ definition: tool.definition,
2152
+ async execute(args, context) {
2153
+ return tool.execute(args, {
2154
+ ...context,
2155
+ metadata: {
2156
+ ...context.metadata,
2157
+ pluginId
2158
+ },
2159
+ emitEvent: (event) => context.emitEvent?.({
2160
+ ...event,
2161
+ pluginId: event.pluginId ?? pluginId
2162
+ }),
2163
+ services
2164
+ });
2165
+ }
2166
+ };
2167
+ }
2168
+
2169
+ // src/services/activity.ts
2170
+ class ActivityTracker {
2171
+ records = [];
2172
+ record(record) {
2173
+ this.records.push({ ...record, timestamp: record.timestamp });
2174
+ if (this.records.length > 200)
2175
+ this.records.splice(0, this.records.length - 200);
2176
+ }
2177
+ recentFiles(limit = 5) {
2178
+ const seen = new Set;
2179
+ const files = [];
2180
+ for (let index = this.records.length - 1;index >= 0; index -= 1) {
2181
+ const record = this.records[index];
2182
+ if (!record || record.type !== "file")
2183
+ continue;
2184
+ if (seen.has(record.label))
2185
+ continue;
2186
+ seen.add(record.label);
2187
+ files.push(record.label);
2188
+ if (files.length >= limit)
2189
+ break;
2190
+ }
2191
+ return files;
2192
+ }
2193
+ }
2194
+ // src/services/exec-gateway.ts
2195
+ import { spawn } from "node:child_process";
2196
+
2197
+ class NodeExecGateway {
2198
+ cwd;
2199
+ env;
2200
+ tracker;
2201
+ constructor(options = {}) {
2202
+ this.cwd = options.cwd;
2203
+ this.env = options.env ?? process.env;
2204
+ this.tracker = options.tracker;
2205
+ }
2206
+ async execute(command, options = {}) {
2207
+ const cwd = options.cwd ?? this.cwd;
2208
+ const env = {
2209
+ ...this.env,
2210
+ ...options.env
2211
+ };
2212
+ const result = await new Promise((resolve, reject) => {
2213
+ const child = spawn(command, {
2214
+ cwd,
2215
+ env,
2216
+ shell: true,
2217
+ signal: options.signal
2218
+ });
2219
+ let stdout = "";
2220
+ let stderr = "";
2221
+ let settled = false;
2222
+ let timedOut = false;
2223
+ let timeout;
2224
+ const finish = (value, isError) => {
2225
+ if (settled)
2226
+ return;
2227
+ settled = true;
2228
+ if (timeout)
2229
+ clearTimeout(timeout);
2230
+ if (isError)
2231
+ reject(value);
2232
+ else
2233
+ resolve(value);
2234
+ };
2235
+ if (options.timeoutMs !== undefined) {
2236
+ timeout = setTimeout(() => {
2237
+ timedOut = true;
2238
+ child.kill("SIGTERM");
2239
+ }, options.timeoutMs);
2240
+ }
2241
+ child.stdout.on("data", (chunk) => {
2242
+ stdout += String(chunk);
2243
+ });
2244
+ child.stderr.on("data", (chunk) => {
2245
+ stderr += String(chunk);
2246
+ });
2247
+ child.on("error", (error) => finish(error, true));
2248
+ child.on("close", (code, signal) => {
2249
+ finish({
2250
+ command,
2251
+ cwd: cwd ?? null,
2252
+ stdout,
2253
+ stderr,
2254
+ exitCode: code,
2255
+ signal: signal ?? null,
2256
+ timedOut
2257
+ }, false);
2258
+ });
2259
+ });
2260
+ this.tracker?.record({
2261
+ type: "command",
2262
+ label: command,
2263
+ timestamp: Date.now()
2264
+ });
2265
+ return result;
2266
+ }
2267
+ }
2268
+ // src/services/file-system-gateway.ts
2269
+ import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
2270
+ import path2 from "node:path";
2271
+
2272
+ class NodeFileSystemGateway {
2273
+ cwd;
2274
+ tracker;
2275
+ constructor(options = {}) {
2276
+ this.cwd = options.cwd;
2277
+ this.tracker = options.tracker;
2278
+ }
2279
+ async readText(targetPath, options = {}) {
2280
+ const resolved = resolvePath(this.cwd, targetPath, options.cwd);
2281
+ const text = await readFile(resolved, "utf8");
2282
+ this.recordFile(resolved);
2283
+ return text;
2284
+ }
2285
+ async writeText(targetPath, content, options = {}) {
2286
+ const resolved = resolvePath(this.cwd, targetPath, options.cwd);
2287
+ await mkdir(path2.dirname(resolved), { recursive: true });
2288
+ await writeFile(resolved, content, "utf8");
2289
+ this.recordFile(resolved);
2290
+ return {
2291
+ path: resolved,
2292
+ bytes: Buffer.byteLength(content, "utf8")
2293
+ };
2294
+ }
2295
+ async editText(targetPath, options) {
2296
+ const resolved = resolvePath(this.cwd, targetPath, options.cwd);
2297
+ const source = await readFile(resolved, "utf8");
2298
+ const matches = source.split(options.oldText).length - 1;
2299
+ if (matches === 0)
2300
+ throw new Error("oldText was not found in the target file");
2301
+ if (!options.replaceAll && matches > 1)
2302
+ throw new Error("oldText matched more than once; set replaceAll to true to replace all matches");
2303
+ const updated = options.replaceAll ? source.split(options.oldText).join(options.newText) : source.replace(options.oldText, options.newText);
2304
+ await writeFile(resolved, updated, "utf8");
2305
+ this.recordFile(resolved);
2306
+ return {
2307
+ path: resolved,
2308
+ replacements: options.replaceAll ? matches : 1
2309
+ };
2310
+ }
2311
+ async exists(targetPath, options = {}) {
2312
+ try {
2313
+ const resolved = resolvePath(this.cwd, targetPath, options.cwd);
2314
+ await stat(resolved);
2315
+ return true;
2316
+ } catch {
2317
+ return false;
2318
+ }
2319
+ }
2320
+ async glob(pattern, options = {}) {
2321
+ const root = path2.resolve(options.cwd ?? this.cwd ?? process.cwd());
2322
+ const matcher = compileGlob(pattern);
2323
+ const limit = options.limit ?? 100;
2324
+ const matches = [];
2325
+ await walk(root, root, async (absolutePath, relativePath) => {
2326
+ if (matches.length >= limit)
2327
+ return false;
2328
+ if (matcher.test(relativePath))
2329
+ matches.push(absolutePath);
2330
+ return true;
2331
+ });
2332
+ return matches;
2333
+ }
2334
+ async grep(query, options = {}) {
2335
+ const pattern = options.pattern ?? "**/*";
2336
+ const files = await this.glob(pattern, options);
2337
+ const matches = [];
2338
+ const limit = options.limit ?? 50;
2339
+ for (const filePath of files) {
2340
+ if (matches.length >= limit)
2341
+ break;
2342
+ let text;
2343
+ try {
2344
+ text = await readFile(filePath, "utf8");
2345
+ } catch {
2346
+ continue;
2347
+ }
2348
+ const lines = text.split(/\r?\n/g);
2349
+ for (let index = 0;index < lines.length; index += 1) {
2350
+ const line = lines[index];
2351
+ if (!line || !line.includes(query))
2352
+ continue;
2353
+ matches.push({
2354
+ path: filePath,
2355
+ lineNumber: index + 1,
2356
+ line
2357
+ });
2358
+ if (matches.length >= limit)
2359
+ break;
2360
+ }
2361
+ }
2362
+ return matches;
2363
+ }
2364
+ recordFile(filePath) {
2365
+ this.tracker?.record({
2366
+ type: "file",
2367
+ label: filePath,
2368
+ timestamp: Date.now()
2369
+ });
2370
+ }
2371
+ }
2372
+ function resolvePath(defaultCwd, targetPath, cwdOverride) {
2373
+ if (!targetPath.trim())
2374
+ throw new Error("path is required");
2375
+ if (path2.isAbsolute(targetPath))
2376
+ return path2.normalize(targetPath);
2377
+ return path2.resolve(cwdOverride ?? defaultCwd ?? process.cwd(), targetPath);
2378
+ }
2379
+ function compileGlob(pattern) {
2380
+ const normalized = pattern.replace(/\\/g, "/").replace(/^\.\//, "");
2381
+ let expression = "^";
2382
+ for (let index = 0;index < normalized.length; index += 1) {
2383
+ const character = normalized[index];
2384
+ const next = normalized[index + 1];
2385
+ if (character === "*" && next === "*") {
2386
+ expression += ".*";
2387
+ index += 1;
2388
+ continue;
2389
+ }
2390
+ if (character === "*") {
2391
+ expression += "[^/]*";
2392
+ continue;
2393
+ }
2394
+ expression += /[.+^${}()|[\]\\]/.test(character) ? `\\${character}` : character;
2395
+ }
2396
+ expression += "$";
2397
+ return new RegExp(expression);
2398
+ }
2399
+ async function walk(root, current, visit) {
2400
+ const entries = await readdir(current, { withFileTypes: true });
2401
+ for (const entry of entries) {
2402
+ if (entry.name === "node_modules" || entry.name === ".git")
2403
+ continue;
2404
+ const absolutePath = path2.join(current, entry.name);
2405
+ const relativePath = path2.relative(root, absolutePath).replace(/\\/g, "/");
2406
+ if (entry.isDirectory()) {
2407
+ const keepGoing = await visit(absolutePath, relativePath);
2408
+ if (keepGoing !== false)
2409
+ await walk(root, absolutePath, visit);
2410
+ continue;
2411
+ }
2412
+ await visit(absolutePath, relativePath);
2413
+ }
2414
+ }
2415
+ // src/services/git-gateway.ts
2416
+ class DefaultGitGateway {
2417
+ exec;
2418
+ cwd;
2419
+ constructor(options) {
2420
+ this.exec = options.exec;
2421
+ this.cwd = options.cwd;
2422
+ }
2423
+ async status(options = {}) {
2424
+ return this.runGitCommand("git status --short", options.cwd);
2425
+ }
2426
+ async diff(options = {}) {
2427
+ return this.runGitCommand('git diff --stat && printf "\\n---\\n" && git diff -- .', options.cwd);
2428
+ }
2429
+ async runGitCommand(command, cwd) {
2430
+ try {
2431
+ const result = await this.exec.execute(command, { cwd: cwd ?? this.cwd, timeoutMs: 1e4 });
2432
+ if (result.exitCode !== 0)
2433
+ return null;
2434
+ const text = [result.stdout, result.stderr].filter(Boolean).join(result.stdout && result.stderr ? `
2435
+ ` : "");
2436
+ return text.trim() || null;
2437
+ } catch {
2438
+ return null;
2439
+ }
2440
+ }
2441
+ }
2442
+ // src/services/model-gateway.ts
2443
+ class DefaultModelGateway {
2444
+ model;
2445
+ constructor(model) {
2446
+ this.model = model;
2447
+ }
2448
+ stream(request) {
2449
+ return this.model.stream(request);
2450
+ }
2451
+ }
2452
+ // src/services/network-gateway.ts
2453
+ class DefaultNetworkGateway {
2454
+ fetchImpl;
2455
+ constructor(fetchImpl = globalThis.fetch) {
2456
+ this.fetchImpl = fetchImpl;
2457
+ }
2458
+ fetch(input, init) {
2459
+ return this.fetchImpl(input, init);
2460
+ }
2461
+ }
2462
+ // src/services/permissions.ts
2463
+ var fullPermissions = {
2464
+ fs: "full",
2465
+ git: true,
2466
+ network: true,
2467
+ process: true,
2468
+ model: true,
2469
+ mcp: true
2470
+ };
2471
+
2472
+ class PermissionDeniedError extends Error {
2473
+ code = "permission_denied";
2474
+ constructor(message) {
2475
+ super(message);
2476
+ this.name = "PermissionDeniedError";
2477
+ }
2478
+ }
2479
+ function normalizePermissions(input) {
2480
+ return {
2481
+ ...fullPermissions,
2482
+ ...input
2483
+ };
2484
+ }
2485
+ function canReadFs(permissions) {
2486
+ return permissions.fs === true || permissions.fs === "read" || permissions.fs === "full";
2487
+ }
2488
+ function canWriteFs(permissions) {
2489
+ return permissions.fs === true || permissions.fs === "write" || permissions.fs === "full";
2490
+ }
2491
+ // src/services/permission-gateway.ts
2492
+ class PermissionGateway {
2493
+ permissions;
2494
+ compactionOwnerPluginId;
2495
+ constructor(options = {}) {
2496
+ this.permissions = normalizePermissions(options.permissions);
2497
+ this.compactionOwnerPluginId = options.compactionOwnerPluginId;
2498
+ }
2499
+ get agentPermissions() {
2500
+ return { ...this.permissions };
2501
+ }
2502
+ scopeServices(services, pluginId, requested) {
2503
+ const effective = intersectPermissions(this.permissions, requested);
2504
+ const pluginState = services.pluginState;
2505
+ return {
2506
+ fileSystem: {
2507
+ readText: (path3, options) => {
2508
+ if (!canReadFs(effective))
2509
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to read files`);
2510
+ return services.fileSystem.readText(path3, options);
2511
+ },
2512
+ writeText: (path3, content, options) => {
2513
+ if (!canWriteFs(effective))
2514
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to write files`);
2515
+ return services.fileSystem.writeText(path3, content, options);
2516
+ },
2517
+ editText: (path3, options) => {
2518
+ if (!canWriteFs(effective))
2519
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to edit files`);
2520
+ return services.fileSystem.editText(path3, options);
2521
+ },
2522
+ exists: (path3, options) => {
2523
+ if (!canReadFs(effective))
2524
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to inspect files`);
2525
+ return services.fileSystem.exists(path3, options);
2526
+ },
2527
+ glob: (pattern, options) => {
2528
+ if (!canReadFs(effective))
2529
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to glob files`);
2530
+ return services.fileSystem.glob(pattern, options);
2531
+ },
2532
+ grep: (query, options) => {
2533
+ if (!canReadFs(effective))
2534
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to grep files`);
2535
+ return services.fileSystem.grep(query, options);
2536
+ }
2537
+ },
2538
+ exec: {
2539
+ execute: (command, options) => {
2540
+ if (effective.process !== true)
2541
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to execute commands`);
2542
+ return services.exec.execute(command, options);
2543
+ }
2544
+ },
2545
+ git: {
2546
+ status: (options) => {
2547
+ if (effective.git !== true)
2548
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to inspect git state`);
2549
+ return services.git.status(options);
2550
+ },
2551
+ diff: (options) => {
2552
+ if (effective.git !== true)
2553
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to inspect git diff`);
2554
+ return services.git.diff(options);
2555
+ }
2556
+ },
2557
+ network: {
2558
+ fetch: (input, init) => {
2559
+ if (effective.network !== true)
2560
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to access the network`);
2561
+ return services.network.fetch(input, init);
2562
+ }
2563
+ },
2564
+ model: {
2565
+ stream: (request) => {
2566
+ if (effective.model !== true)
2567
+ throw new PermissionDeniedError(`Plugin ${pluginId} is not allowed to call the model gateway`);
2568
+ return services.model.stream(request);
2569
+ }
2570
+ },
2571
+ compaction: {
2572
+ getState: (sessionId) => services.compaction.getState(sessionId),
2573
+ apply: (update) => {
2574
+ this.ensureCompactionOwner(pluginId);
2575
+ return services.compaction.apply(update);
2576
+ },
2577
+ clear: (sessionId) => {
2578
+ this.ensureCompactionOwner(pluginId);
2579
+ return services.compaction.clear(sessionId);
2580
+ }
2581
+ },
2582
+ pluginState: {
2583
+ get: (sessionId) => pluginState.getForPlugin(sessionId, pluginId),
2584
+ replace: (sessionId, entry) => pluginState.replaceForPlugin(sessionId, pluginId, entry),
2585
+ clear: (sessionId) => pluginState.clearForPlugin(sessionId, pluginId)
2586
+ }
2587
+ };
2588
+ }
2589
+ ensureCompactionOwner(pluginId) {
2590
+ if (this.compactionOwnerPluginId === pluginId)
2591
+ return;
2592
+ const message = this.compactionOwnerPluginId ? `Plugin ${pluginId} is not the configured compaction owner (${this.compactionOwnerPluginId})` : `Plugin ${pluginId} cannot modify canonical compaction without compaction.ownerPluginId`;
2593
+ const error = new Error(message);
2594
+ error.code = "compaction_owner_required";
2595
+ throw error;
2596
+ }
2597
+ }
2598
+ function intersectPermissions(agent, requested) {
2599
+ const normalized = requested ?? {};
2600
+ return {
2601
+ fs: intersectFs(agent.fs, normalized.fs ?? false),
2602
+ git: agent.git === true && normalized.git === true,
2603
+ network: agent.network === true && normalized.network === true,
2604
+ process: agent.process === true && normalized.process === true,
2605
+ model: agent.model === true && normalized.model === true,
2606
+ mcp: agent.mcp === true && normalized.mcp === true
2607
+ };
2608
+ }
2609
+ function intersectFs(left, right) {
2610
+ const rank = new Map([
2611
+ [false, 0],
2612
+ ["read", 1],
2613
+ ["write", 1],
2614
+ [true, 2],
2615
+ ["full", 2]
2616
+ ]);
2617
+ const leftValue = left ?? false;
2618
+ const rightValue = right ?? false;
2619
+ if (leftValue === "full" || leftValue === true)
2620
+ return rightValue;
2621
+ if (rightValue === "full" || rightValue === true)
2622
+ return leftValue;
2623
+ if (leftValue === rightValue)
2624
+ return leftValue;
2625
+ if (rank.get(leftValue) === 0 || rank.get(rightValue) === 0)
2626
+ return false;
2627
+ if (leftValue === "read" && rightValue === "write" || leftValue === "write" && rightValue === "read")
2628
+ return false;
2629
+ return leftValue;
2630
+ }
2631
+ // src/contracts/tool-normalize.ts
2632
+ function normalizeToolSchema(schema) {
2633
+ if (!isRecord(schema) || schema.type !== "object")
2634
+ throw new TypeError('Tool input schema must have type "object"');
2635
+ const properties = schema.properties;
2636
+ if (properties !== undefined && !isRecord(properties))
2637
+ throw new TypeError("Tool input schema properties must be an object");
2638
+ const required = schema.required;
2639
+ if (required !== undefined && !isStringArray(required))
2640
+ throw new TypeError("Tool input schema required must be a string array");
2641
+ const normalized = {
2642
+ ...schema,
2643
+ type: "object",
2644
+ properties: properties ? cloneSchemaRecord(properties) : {}
2645
+ };
2646
+ return normalized;
2647
+ }
2648
+ function cloneSchemaRecord(record) {
2649
+ return Object.fromEntries(Object.entries(record).map(([key, value]) => {
2650
+ if (!isRecord(value))
2651
+ throw new TypeError(`Tool schema property ${key} must be an object`);
2652
+ return [key, { ...value }];
2653
+ }));
2654
+ }
2655
+ function normalizeToolResult(result) {
2656
+ const normalized = {
2657
+ content: normalizeContent(result.content),
2658
+ isError: result.isError === true
2659
+ };
2660
+ if (result.structuredContent !== undefined) {
2661
+ assertJsonSafeObject(result.structuredContent, "Tool structuredContent");
2662
+ normalized.structuredContent = { ...result.structuredContent };
2663
+ }
2664
+ return normalized;
2665
+ }
2666
+
2667
+ // src/tools/base-tool.ts
2668
+ class BaseTool {
2669
+ definition;
2670
+ constructor(definition) {
2671
+ this.definition = {
2672
+ ...definition,
2673
+ inputSchema: normalizeToolSchema(definition.inputSchema)
2674
+ };
2675
+ }
2676
+ }
2677
+ // src/tools/result.ts
2678
+ function textToolResult(text) {
2679
+ return {
2680
+ content: normalizeContent(text)
2681
+ };
2682
+ }
2683
+ // src/tools/tool-registry.ts
2684
+ class ToolRegistry {
2685
+ tools = new Map;
2686
+ register(tool) {
2687
+ const name = tool.definition.name.trim();
2688
+ if (!name)
2689
+ throw new Error("Tool name is required");
2690
+ if (this.tools.has(name))
2691
+ throw new Error(`Tool already registered: ${name}`);
2692
+ const normalizedDefinition = {
2693
+ ...tool.definition,
2694
+ name,
2695
+ description: tool.definition.description.trim(),
2696
+ inputSchema: normalizeToolSchema(tool.definition.inputSchema)
2697
+ };
2698
+ const normalizedTool = {
2699
+ definition: normalizedDefinition,
2700
+ execute(args, context) {
2701
+ return tool.execute(args, context);
2702
+ }
2703
+ };
2704
+ this.tools.set(name, normalizedTool);
2705
+ return this;
2706
+ }
2707
+ unregister(name) {
2708
+ return this.tools.delete(name);
2709
+ }
2710
+ get(name) {
2711
+ return this.tools.get(name);
2712
+ }
2713
+ list() {
2714
+ return [...this.tools.values()];
2715
+ }
2716
+ definitions() {
2717
+ return this.list().map((tool) => ({
2718
+ ...tool.definition,
2719
+ inputSchema: normalizeToolSchema(tool.definition.inputSchema)
2720
+ }));
2721
+ }
2722
+ }
2723
+ // src/tools/builtins/utils.ts
2724
+ function readStringArg(args, key, options = {}) {
2725
+ const value = args[key];
2726
+ if (typeof value !== "string")
2727
+ throw new Error(`${key} must be a string`);
2728
+ if (!options.allowEmpty && value.length === 0)
2729
+ throw new Error(`${key} must be a non-empty string`);
2730
+ return value;
2731
+ }
2732
+ function readOptionalBooleanArg(args, key) {
2733
+ const value = args[key];
2734
+ if (value === undefined)
2735
+ return;
2736
+ if (typeof value !== "boolean")
2737
+ throw new Error(`${key} must be a boolean`);
2738
+ return value;
2739
+ }
2740
+ function readOptionalNumberArg(args, key) {
2741
+ const value = args[key];
2742
+ if (value === undefined)
2743
+ return;
2744
+ if (typeof value !== "number" || !Number.isFinite(value))
2745
+ throw new Error(`${key} must be a finite number`);
2746
+ return value;
2747
+ }
2748
+
2749
+ // src/tools/builtins/edit-tool.ts
2750
+ class EditTool extends BaseTool {
2751
+ constructor() {
2752
+ super({
2753
+ name: "edit",
2754
+ description: "Replace text in a UTF-8 file.",
2755
+ inputSchema: {
2756
+ type: "object",
2757
+ properties: {
2758
+ path: { type: "string", description: "File path to edit." },
2759
+ oldText: { type: "string", description: "Text to replace." },
2760
+ newText: { type: "string", description: "Replacement text." },
2761
+ replaceAll: { type: "boolean", description: "Replace all matches when true." }
2762
+ },
2763
+ required: ["path", "oldText", "newText"]
2764
+ }
2765
+ });
2766
+ }
2767
+ async execute(args, context) {
2768
+ const fileSystem = context.services?.fileSystem;
2769
+ if (!fileSystem)
2770
+ throw new Error("FileSystemGateway is not available in the tool execution context");
2771
+ const targetPath = readStringArg(args, "path");
2772
+ const oldText = readStringArg(args, "oldText");
2773
+ const newText = readStringArg(args, "newText", { allowEmpty: true });
2774
+ const replaceAll = readOptionalBooleanArg(args, "replaceAll") ?? false;
2775
+ const result = await fileSystem.editText(targetPath, {
2776
+ oldText,
2777
+ newText,
2778
+ replaceAll,
2779
+ cwd: context.cwd
2780
+ });
2781
+ return normalizeToolResult({
2782
+ content: [{ type: "text", text: `Edited ${result.path}` }],
2783
+ structuredContent: result
2784
+ });
2785
+ }
2786
+ }
2787
+ // src/tools/builtins/exec-tool.ts
2788
+ class ExecTool extends BaseTool {
2789
+ constructor() {
2790
+ super({
2791
+ name: "exec",
2792
+ description: "Execute a shell command.",
2793
+ inputSchema: {
2794
+ type: "object",
2795
+ properties: {
2796
+ command: { type: "string", description: "Shell command to execute." },
2797
+ cwd: { type: "string", description: "Optional working directory override." },
2798
+ timeoutMs: { type: "number", description: "Optional timeout in milliseconds." }
2799
+ },
2800
+ required: ["command"]
2801
+ }
2802
+ });
2803
+ }
2804
+ async execute(args, context) {
2805
+ const exec = context.services?.exec;
2806
+ if (!exec)
2807
+ throw new Error("ExecGateway is not available in the tool execution context");
2808
+ const command = readStringArg(args, "command");
2809
+ const cwd = typeof args.cwd === "string" && args.cwd.length > 0 ? args.cwd : context.cwd;
2810
+ const timeoutMs = readOptionalNumberArg(args, "timeoutMs");
2811
+ const result = await exec.execute(command, {
2812
+ cwd,
2813
+ timeoutMs,
2814
+ signal: context.signal
2815
+ });
2816
+ const text = [result.stdout, result.stderr].filter(Boolean).join(result.stdout && result.stderr ? `
2817
+ ` : "");
2818
+ return normalizeToolResult({
2819
+ content: [{ type: "text", text: text || `Command exited with code ${result.exitCode ?? -1}` }],
2820
+ structuredContent: { ...result },
2821
+ isError: result.exitCode !== 0
2822
+ });
2823
+ }
2824
+ }
2825
+ // src/tools/builtins/read-tool.ts
2826
+ class ReadTool extends BaseTool {
2827
+ constructor() {
2828
+ super({
2829
+ name: "read",
2830
+ description: "Read a UTF-8 text file.",
2831
+ inputSchema: {
2832
+ type: "object",
2833
+ properties: {
2834
+ path: { type: "string", description: "File path to read." }
2835
+ },
2836
+ required: ["path"]
2837
+ }
2838
+ });
2839
+ }
2840
+ async execute(args, context) {
2841
+ const fileSystem = context.services?.fileSystem;
2842
+ if (!fileSystem)
2843
+ throw new Error("FileSystemGateway is not available in the tool execution context");
2844
+ const targetPath = readStringArg(args, "path");
2845
+ const text = await fileSystem.readText(targetPath, { cwd: context.cwd });
2846
+ return normalizeToolResult({
2847
+ content: [{ type: "text", text }],
2848
+ structuredContent: {
2849
+ path: targetPath,
2850
+ size: Buffer.byteLength(text, "utf8")
2851
+ }
2852
+ });
2853
+ }
2854
+ }
2855
+ // src/tools/builtins/write-tool.ts
2856
+ class WriteTool extends BaseTool {
2857
+ constructor() {
2858
+ super({
2859
+ name: "write",
2860
+ description: "Write a UTF-8 text file.",
2861
+ inputSchema: {
2862
+ type: "object",
2863
+ properties: {
2864
+ path: { type: "string", description: "File path to write." },
2865
+ content: { type: "string", description: "Text content to write." }
2866
+ },
2867
+ required: ["path", "content"]
2868
+ }
2869
+ });
2870
+ }
2871
+ async execute(args, context) {
2872
+ const fileSystem = context.services?.fileSystem;
2873
+ if (!fileSystem)
2874
+ throw new Error("FileSystemGateway is not available in the tool execution context");
2875
+ const targetPath = readStringArg(args, "path");
2876
+ const content = readStringArg(args, "content", { allowEmpty: true });
2877
+ const result = await fileSystem.writeText(targetPath, content, { cwd: context.cwd });
2878
+ return normalizeToolResult({
2879
+ content: [{ type: "text", text: `Wrote ${result.path}` }],
2880
+ structuredContent: result
2881
+ });
2882
+ }
2883
+ }
2884
+ // src/agent-core/approvals.ts
2885
+ class DefaultApprovalManager {
2886
+ handler;
2887
+ notifications;
2888
+ constructor(options = {}) {
2889
+ this.handler = options.handler;
2890
+ this.notifications = options.notifications;
2891
+ }
2892
+ async requestApproval(request, context) {
2893
+ const normalizedRequest = {
2894
+ ...request,
2895
+ id: request.id ?? createId("approval")
2896
+ };
2897
+ await this.notifications?.emit({
2898
+ type: "approval.requested",
2899
+ source: "approval",
2900
+ level: "warning",
2901
+ message: normalizedRequest.message,
2902
+ metadata: {
2903
+ approvalId: normalizedRequest.id,
2904
+ toolName: normalizedRequest.toolCall.function.name
2905
+ }
2906
+ }, context);
2907
+ if (!this.handler) {
2908
+ const denied = {
2909
+ type: "denied",
2910
+ reason: "No approval handler configured"
2911
+ };
2912
+ await this.notifications?.emit({
2913
+ type: "approval.denied",
2914
+ source: "approval",
2915
+ level: "warning",
2916
+ message: denied.reason,
2917
+ metadata: {
2918
+ approvalId: normalizedRequest.id,
2919
+ toolName: normalizedRequest.toolCall.function.name
2920
+ }
2921
+ }, context);
2922
+ return denied;
2923
+ }
2924
+ const decision = await this.handler(normalizedRequest);
2925
+ await this.notifications?.emit({
2926
+ type: decision.type === "approved" ? "approval.approved" : "approval.denied",
2927
+ source: "approval",
2928
+ level: decision.type === "approved" ? "info" : "warning",
2929
+ message: decision.type === "approved" ? `Approved tool call: ${normalizedRequest.toolCall.function.name}` : decision.reason ?? `Denied tool call: ${normalizedRequest.toolCall.function.name}`,
2930
+ metadata: {
2931
+ approvalId: normalizedRequest.id,
2932
+ toolName: normalizedRequest.toolCall.function.name
2933
+ }
2934
+ }, context);
2935
+ return decision;
2936
+ }
2937
+ }
2938
+
2939
+ // src/agent-core/session-state.ts
2940
+ function touchRuntimeSessionState(state) {
2941
+ state.updatedAt = Date.now();
2942
+ }
2943
+
2944
+ // src/agent-core/compaction.ts
2945
+ function createEmptyCompactionState() {
2946
+ return {
2947
+ cursor: 0,
2948
+ systemSegments: [],
2949
+ checkpoints: []
2950
+ };
2951
+ }
2952
+ function cloneCompactionState(state) {
2953
+ if (!state)
2954
+ return createEmptyCompactionState();
2955
+ return structuredClone({
2956
+ cursor: state.cursor,
2957
+ systemSegments: [...state.systemSegments],
2958
+ checkpoints: state.checkpoints.map((checkpoint) => ({
2959
+ ...checkpoint,
2960
+ systemSegments: [...checkpoint.systemSegments],
2961
+ metadata: checkpoint.metadata ? structuredClone(checkpoint.metadata) : undefined
2962
+ }))
2963
+ });
2964
+ }
2965
+ function normalizeCompactionState(state, messages) {
2966
+ const current = cloneCompactionState(state);
2967
+ return {
2968
+ cursor: clampCursor(current.cursor, messages.length),
2969
+ systemSegments: current.systemSegments.filter(Boolean),
2970
+ checkpoints: current.checkpoints.map((checkpoint) => ({
2971
+ ...checkpoint,
2972
+ cursor: clampCursor(checkpoint.cursor, messages.length),
2973
+ systemSegments: checkpoint.systemSegments.filter(Boolean)
2974
+ }))
2975
+ };
2976
+ }
2977
+ function applyCompactionUpdate(state, update) {
2978
+ const nextCursor = clampCursor(update.cursor, state.messages.length);
2979
+ const nextSystemSegments = [...update.systemSegments ?? state.compaction.systemSegments].filter(Boolean);
2980
+ const nextCheckpoint = {
2981
+ id: createId("compact"),
2982
+ cursor: nextCursor,
2983
+ systemSegments: nextSystemSegments,
2984
+ summary: update.summary,
2985
+ reason: update.reason ?? "manual",
2986
+ createdAt: Date.now(),
2987
+ metadata: update.metadata ? structuredClone(update.metadata) : undefined
2988
+ };
2989
+ state.compaction = {
2990
+ cursor: nextCursor,
2991
+ systemSegments: nextSystemSegments,
2992
+ checkpoints: [...state.compaction.checkpoints, nextCheckpoint]
2993
+ };
2994
+ touchRuntimeSessionState(state);
2995
+ return cloneCompactionState(state.compaction);
2996
+ }
2997
+ function clearCompactionState(state) {
2998
+ state.compaction = createEmptyCompactionState();
2999
+ touchRuntimeSessionState(state);
3000
+ return cloneCompactionState(state.compaction);
3001
+ }
3002
+ function projectMessagesForRequest(messages, compaction) {
3003
+ const leadingSystemMessages = readLeadingSystemMessages(messages);
3004
+ const startIndex = Math.max(compaction.cursor, leadingSystemMessages.length);
3005
+ return [
3006
+ ...leadingSystemMessages,
3007
+ ...messages.slice(startIndex)
3008
+ ];
3009
+ }
3010
+ function buildCompactionPromptSegments(compaction) {
3011
+ return compaction.systemSegments.filter(Boolean);
3012
+ }
3013
+ function calculateThresholdTokens(options) {
3014
+ if (options.triggerTokens !== undefined)
3015
+ return options.triggerTokens;
3016
+ const ratio = options.triggerRatio ?? 0.8;
3017
+ return Math.max(1, Math.floor(options.maxInputTokens * ratio));
3018
+ }
3019
+ async function estimateCompactionBudget(options, input) {
3020
+ const estimatedInputTokens = options.estimator ? await options.estimator(input) : estimateByHeuristic(input);
3021
+ return {
3022
+ estimatedInputTokens,
3023
+ thresholdTokens: calculateThresholdTokens(options),
3024
+ maxInputTokens: options.maxInputTokens
3025
+ };
3026
+ }
3027
+ function isCompactionRequired(options, budget) {
3028
+ if (!options || options.enabled === false || !budget)
3029
+ return false;
3030
+ return budget.estimatedInputTokens >= budget.thresholdTokens;
3031
+ }
3032
+ function didCompactionStateChange(before, after) {
3033
+ return before.cursor !== after.cursor || JSON.stringify(before.systemSegments) !== JSON.stringify(after.systemSegments) || before.checkpoints.length !== after.checkpoints.length;
3034
+ }
3035
+
3036
+ class DefaultCompactionService {
3037
+ sessions = new Map;
3038
+ registerSession(state) {
3039
+ state.compaction = normalizeCompactionState(state.compaction, state.messages);
3040
+ this.sessions.set(state.id, state);
3041
+ }
3042
+ unregisterSession(sessionId) {
3043
+ this.sessions.delete(sessionId);
3044
+ }
3045
+ async getState(sessionId) {
3046
+ return cloneCompactionState(this.requireSession(sessionId).compaction);
3047
+ }
3048
+ async apply(update) {
3049
+ return applyCompactionUpdate(this.requireSession(update.sessionId), update);
3050
+ }
3051
+ async clear(sessionId) {
3052
+ return clearCompactionState(this.requireSession(sessionId));
3053
+ }
3054
+ requireSession(sessionId) {
3055
+ const state = this.sessions.get(sessionId);
3056
+ if (!state)
3057
+ throw new Error(`Unknown session for compaction: ${sessionId}`);
3058
+ return state;
3059
+ }
3060
+ }
3061
+ function clampCursor(cursor, max) {
3062
+ if (!Number.isFinite(cursor))
3063
+ return 0;
3064
+ return Math.max(0, Math.min(Math.floor(cursor), max));
3065
+ }
3066
+ function readLeadingSystemMessages(messages) {
3067
+ const systemMessages = [];
3068
+ for (const message of messages) {
3069
+ if (message.role !== "system")
3070
+ break;
3071
+ systemMessages.push(message);
3072
+ }
3073
+ return systemMessages;
3074
+ }
3075
+ function estimateByHeuristic(input) {
3076
+ const messageChars = input.messages.reduce((total, message) => {
3077
+ const contentChars = JSON.stringify(message.content).length;
3078
+ const metadataChars = message.metadata ? JSON.stringify(message.metadata).length : 0;
3079
+ return total + message.role.length + contentChars + metadataChars;
3080
+ }, 0);
3081
+ const toolChars = input.tools ? JSON.stringify(input.tools).length : 0;
3082
+ const modelChars = `${input.model.provider}:${input.model.modelId}`.length;
3083
+ return Math.max(1, Math.ceil((messageChars + toolChars + modelChars) / 4));
3084
+ }
3085
+
3086
+ // src/agent-core/plugin-state.ts
3087
+ var APP_PLUGIN_NAMESPACE = "__agent__";
3088
+ function clonePluginSessionStateEntry(entry) {
3089
+ if (!entry)
3090
+ return null;
3091
+ return structuredClone({
3092
+ version: entry.version,
3093
+ data: structuredClone(entry.data),
3094
+ updatedAt: entry.updatedAt
3095
+ });
3096
+ }
3097
+ function clonePluginStateMap(state) {
3098
+ if (!state)
3099
+ return {};
3100
+ return Object.fromEntries(Object.entries(state).map(([pluginId, entry]) => [pluginId, clonePluginSessionStateEntry(entry)]));
3101
+ }
3102
+ function normalizePluginStateMap(state) {
3103
+ if (!state)
3104
+ return {};
3105
+ return Object.fromEntries(Object.entries(state).map(([pluginId, entry]) => [pluginId, normalizePluginSessionStateEntry(entry, `Plugin session state for ${pluginId}`)]));
3106
+ }
3107
+
3108
+ class DefaultPluginStateService {
3109
+ sessions = new Map;
3110
+ registerSession(state) {
3111
+ state.pluginState = normalizePluginStateMap(state.pluginState);
3112
+ this.sessions.set(state.id, state);
3113
+ }
3114
+ unregisterSession(sessionId) {
3115
+ this.sessions.delete(sessionId);
3116
+ }
3117
+ async get(sessionId) {
3118
+ return this.getForPlugin(sessionId, APP_PLUGIN_NAMESPACE);
3119
+ }
3120
+ async replace(sessionId, entry) {
3121
+ return this.replaceForPlugin(sessionId, APP_PLUGIN_NAMESPACE, entry);
3122
+ }
3123
+ async clear(sessionId) {
3124
+ await this.clearForPlugin(sessionId, APP_PLUGIN_NAMESPACE);
3125
+ }
3126
+ async getForPlugin(sessionId, pluginId) {
3127
+ const state = this.requireSession(sessionId);
3128
+ return clonePluginSessionStateEntry(state.pluginState[pluginId]);
3129
+ }
3130
+ async replaceForPlugin(sessionId, pluginId, entry) {
3131
+ const state = this.requireSession(sessionId);
3132
+ const nextEntry = normalizePluginSessionStateEntry(entry, `Plugin session state for ${pluginId}`);
3133
+ state.pluginState = {
3134
+ ...state.pluginState,
3135
+ [pluginId]: nextEntry
3136
+ };
3137
+ touchRuntimeSessionState(state);
3138
+ return clonePluginSessionStateEntry(nextEntry);
3139
+ }
3140
+ async clearForPlugin(sessionId, pluginId) {
3141
+ const state = this.requireSession(sessionId);
3142
+ if (!(pluginId in state.pluginState))
3143
+ return;
3144
+ const nextState = { ...state.pluginState };
3145
+ delete nextState[pluginId];
3146
+ state.pluginState = nextState;
3147
+ touchRuntimeSessionState(state);
3148
+ }
3149
+ async list(sessionId) {
3150
+ return clonePluginStateMap(this.requireSession(sessionId).pluginState);
3151
+ }
3152
+ requireSession(sessionId) {
3153
+ const state = this.sessions.get(sessionId);
3154
+ if (!state)
3155
+ throw new Error(`Unknown session for plugin state: ${sessionId}`);
3156
+ return state;
3157
+ }
3158
+ }
3159
+ function normalizePluginSessionStateEntry(entry, label) {
3160
+ if (!Number.isFinite(entry.version))
3161
+ throw new TypeError(`${label} version must be a finite number`);
3162
+ if (!Number.isFinite(entry.updatedAt))
3163
+ throw new TypeError(`${label} updatedAt must be a finite number`);
3164
+ assertJsonSafeObject(entry.data, `${label} data`);
3165
+ return {
3166
+ version: Math.floor(entry.version),
3167
+ data: structuredClone(entry.data),
3168
+ updatedAt: entry.updatedAt
3169
+ };
3170
+ }
3171
+
3172
+ // src/agent-core/message-factory.ts
3173
+ class DefaultMessageFactory {
3174
+ createSystemMessage(input) {
3175
+ return {
3176
+ id: createId("msg"),
3177
+ role: "system",
3178
+ content: normalizeContent(input),
3179
+ createdAt: Date.now()
3180
+ };
3181
+ }
3182
+ createUserMessage(input) {
3183
+ return {
3184
+ id: createId("msg"),
3185
+ role: "user",
3186
+ content: normalizeContent(input),
3187
+ createdAt: Date.now()
3188
+ };
3189
+ }
3190
+ createAssistantMessage(input) {
3191
+ return {
3192
+ id: createId("msg"),
3193
+ role: "assistant",
3194
+ content: input.text.length > 0 ? normalizeContent(input.text) : [],
3195
+ createdAt: Date.now(),
3196
+ thinking: input.thinking,
3197
+ toolCalls: input.toolCalls.length > 0 ? input.toolCalls : undefined,
3198
+ stopReason: input.stopReason,
3199
+ metadata: input.metadata
3200
+ };
3201
+ }
3202
+ createToolMessage(toolCall, result) {
3203
+ return {
3204
+ id: createId("msg"),
3205
+ role: "tool",
3206
+ content: result.content,
3207
+ createdAt: Date.now(),
3208
+ toolCallId: toolCall.id,
3209
+ toolName: toolCall.function.name,
3210
+ structuredContent: result.structuredContent,
3211
+ isError: result.isError
3212
+ };
3213
+ }
3214
+ }
3215
+
3216
+ // src/agent-core/notifications.ts
3217
+ class DefaultNotificationBus {
3218
+ pluginHost;
3219
+ services;
3220
+ constructor(options) {
3221
+ this.pluginHost = options.pluginHost;
3222
+ this.services = options.services;
3223
+ }
3224
+ async emit(notification, context = {}) {
3225
+ const normalized = {
3226
+ id: notification.id ?? createId("note"),
3227
+ level: notification.level ?? "info",
3228
+ ...notification
3229
+ };
3230
+ if (!this.pluginHost)
3231
+ return normalized;
3232
+ const result = await this.pluginHost.runNotifyMessage({ notification: normalized }, {
3233
+ sessionId: context.sessionId,
3234
+ requestId: context.requestId,
3235
+ iteration: context.iteration,
3236
+ cwd: context.cwd,
3237
+ status: context.status,
3238
+ metadata: context.metadata,
3239
+ services: this.services
3240
+ });
3241
+ if (result.suppressed)
3242
+ return;
3243
+ await this.pluginHost.runObservers("notify.message", result.payload, {
3244
+ sessionId: context.sessionId,
3245
+ requestId: context.requestId,
3246
+ iteration: context.iteration,
3247
+ cwd: context.cwd,
3248
+ status: context.status,
3249
+ metadata: context.metadata,
3250
+ services: this.services
3251
+ });
3252
+ return result.payload.notification;
3253
+ }
3254
+ }
3255
+
3256
+ // src/persistence/snapshot-codec.ts
3257
+ class JsonSnapshotCodec {
3258
+ encode(input) {
3259
+ return structuredClone({
3260
+ schemaVersion: 2,
3261
+ sessionId: input.sessionId,
3262
+ model: input.model,
3263
+ cwd: input.cwd,
3264
+ messages: input.messages,
3265
+ usage: input.usage,
3266
+ compaction: input.compaction,
3267
+ pluginState: input.pluginState,
3268
+ createdAt: input.createdAt,
3269
+ updatedAt: input.updatedAt,
3270
+ metadata: input.metadata,
3271
+ messageQueue: input.messageQueue
3272
+ });
3273
+ }
3274
+ decode(value) {
3275
+ if (!value || typeof value !== "object")
3276
+ throw new TypeError("Session snapshot must be an object");
3277
+ const snapshot = value;
3278
+ if (snapshot.schemaVersion !== 1 && snapshot.schemaVersion !== 2)
3279
+ throw new TypeError("Unsupported session snapshot schemaVersion");
3280
+ if (typeof snapshot.sessionId !== "string")
3281
+ throw new TypeError("Session snapshot sessionId is required");
3282
+ if (!Array.isArray(snapshot.messages))
3283
+ throw new TypeError("Session snapshot messages must be an array");
3284
+ if (typeof snapshot.createdAt !== "number" || typeof snapshot.updatedAt !== "number")
3285
+ throw new TypeError("Session snapshot timestamps are required");
3286
+ if (snapshot.schemaVersion === 1) {
3287
+ return structuredClone({
3288
+ ...snapshot,
3289
+ schemaVersion: 1
3290
+ });
3291
+ }
3292
+ return structuredClone(snapshot);
3293
+ }
3294
+ }
3295
+ var sessionSnapshotCodec = new JsonSnapshotCodec;
3296
+
3297
+ // src/utils/usage.ts
3298
+ function createEmptyUsage() {
3299
+ return {
3300
+ promptTokens: 0,
3301
+ completionTokens: 0,
3302
+ totalTokens: 0
3303
+ };
3304
+ }
3305
+ function addUsage(left, right) {
3306
+ if (!right)
3307
+ return { ...left };
3308
+ return {
3309
+ promptTokens: left.promptTokens + right.promptTokens,
3310
+ completionTokens: left.completionTokens + right.completionTokens,
3311
+ totalTokens: left.totalTokens + right.totalTokens
3312
+ };
3313
+ }
3314
+
3315
+ // src/agent-core/errors.ts
3316
+ class SessionExecutionError extends Error {
3317
+ payload;
3318
+ payloadSummary;
3319
+ constructor(payload) {
3320
+ super(payload.message);
3321
+ this.name = "SessionExecutionError";
3322
+ this.payload = payload;
3323
+ this.payloadSummary = stringifyPayload(payload);
3324
+ }
3325
+ }
3326
+ function stringifyPayload(payload) {
3327
+ try {
3328
+ return JSON.stringify(payload, null, 2);
3329
+ } catch {
3330
+ return String(payload);
3331
+ }
3332
+ }
3333
+
3334
+ // src/agent-core/tool-call.ts
3335
+ function startToolCall(callId, toolName) {
3336
+ if (!callId.trim())
3337
+ throw new Error("Tool call id is required");
3338
+ if (!toolName.trim())
3339
+ throw new Error("Tool name is required");
3340
+ return {
3341
+ callId,
3342
+ toolName,
3343
+ argsText: ""
3344
+ };
3345
+ }
3346
+ function appendToolCallArgsDelta(draft, delta) {
3347
+ return {
3348
+ ...draft,
3349
+ argsText: `${draft.argsText}${delta}`
3350
+ };
3351
+ }
3352
+ function finalizeToolCall(draft) {
3353
+ const rawArgumentsText = draft.argsText.trim();
3354
+ const argumentsObject = rawArgumentsText.length === 0 ? {} : parseJsonObject(rawArgumentsText, `Tool call ${draft.callId} arguments`);
3355
+ return {
3356
+ id: draft.callId,
3357
+ type: "function",
3358
+ function: {
3359
+ name: draft.toolName,
3360
+ arguments: argumentsObject
3361
+ },
3362
+ rawArgumentsText
3363
+ };
3364
+ }
3365
+
3366
+ // src/agent-core/model-turn-collector.ts
3367
+ class DefaultModelTurnCollector {
3368
+ async* collect(options) {
3369
+ const assistantTextParts = [];
3370
+ const thinkingParts = [];
3371
+ const toolCalls = [];
3372
+ const drafts = new Map;
3373
+ let stopReason = "final";
3374
+ let responseUsage;
3375
+ let assistantMetadata;
3376
+ for await (const event of options.events) {
3377
+ await options.onEvent?.(event);
3378
+ if (event.type === "response_start")
3379
+ continue;
3380
+ if (event.type === "text_delta") {
3381
+ assistantTextParts.push(event.delta);
3382
+ yield { type: "text_delta", sessionId: options.sessionId, delta: event.delta };
3383
+ continue;
3384
+ }
3385
+ if (event.type === "thinking_delta") {
3386
+ thinkingParts.push(event.delta);
3387
+ yield { type: "thinking_delta", sessionId: options.sessionId, delta: event.delta };
3388
+ continue;
3389
+ }
3390
+ if (event.type === "tool_call_start") {
3391
+ drafts.set(event.callId, startToolCall(event.callId, event.toolName));
3392
+ continue;
3393
+ }
3394
+ if (event.type === "tool_call_args_delta") {
3395
+ const draft = drafts.get(event.callId);
3396
+ if (!draft) {
3397
+ const payload2 = {
3398
+ code: "tool_call_state_error",
3399
+ message: `Received tool_call_args_delta before tool_call_start for ${event.callId}`,
3400
+ requestId: options.requestId
3401
+ };
3402
+ yield { type: "error", sessionId: options.sessionId, error: payload2 };
3403
+ throw new SessionExecutionError(payload2);
3404
+ }
3405
+ drafts.set(event.callId, appendToolCallArgsDelta(draft, event.delta));
3406
+ continue;
3407
+ }
3408
+ if (event.type === "tool_call_end") {
3409
+ const draft = drafts.get(event.callId);
3410
+ if (!draft) {
3411
+ const payload2 = {
3412
+ code: "tool_call_state_error",
3413
+ message: `Received tool_call_end before tool_call_start for ${event.callId}`,
3414
+ requestId: options.requestId
3415
+ };
3416
+ yield { type: "error", sessionId: options.sessionId, error: payload2 };
3417
+ throw new SessionExecutionError(payload2);
3418
+ }
3419
+ try {
3420
+ toolCalls.push(finalizeToolCall(draft));
3421
+ } catch (error) {
3422
+ const payload2 = {
3423
+ code: "tool_call_parse_error",
3424
+ message: error instanceof Error ? error.message : String(error),
3425
+ requestId: options.requestId
3426
+ };
3427
+ yield { type: "error", sessionId: options.sessionId, error: payload2 };
3428
+ throw new SessionExecutionError(payload2);
3429
+ }
3430
+ continue;
3431
+ }
3432
+ if (event.type === "response_end") {
3433
+ stopReason = event.stopReason;
3434
+ responseUsage = event.usage;
3435
+ assistantMetadata = event.assistantMetadata;
3436
+ continue;
3437
+ }
3438
+ const payload = {
3439
+ ...event.error,
3440
+ requestId: options.requestId
3441
+ };
3442
+ yield { type: "error", sessionId: options.sessionId, error: payload };
3443
+ throw new SessionExecutionError(payload);
3444
+ }
3445
+ return {
3446
+ requestId: options.requestId,
3447
+ text: assistantTextParts.join(""),
3448
+ thinking: thinkingParts.join("") || undefined,
3449
+ toolCalls,
3450
+ stopReason,
3451
+ usage: responseUsage,
3452
+ assistantMetadata
3453
+ };
3454
+ }
3455
+ }
3456
+
3457
+ // src/agent-core/session-status.ts
3458
+ function createSessionStatus(state) {
3459
+ return {
3460
+ sessionId: state.id,
3461
+ model: { ...state.modelRef },
3462
+ cwd: state.cwd,
3463
+ usage: { ...state.usage },
3464
+ compaction: cloneCompactionState(state.compaction),
3465
+ messageCount: state.messages.length,
3466
+ createdAt: state.createdAt,
3467
+ updatedAt: state.updatedAt,
3468
+ metadata: state.metadata ? structuredClone(state.metadata) : undefined
3469
+ };
3470
+ }
3471
+
3472
+ // src/agent-core/loop-runner.ts
3473
+ class LoopRunner {
3474
+ messageFactory;
3475
+ turnCollector;
3476
+ toolExecutor;
3477
+ terminationPolicy;
3478
+ contextManager;
3479
+ pluginHost;
3480
+ notificationBus;
3481
+ constructor(dependencies) {
3482
+ this.messageFactory = dependencies.messageFactory;
3483
+ this.turnCollector = dependencies.turnCollector;
3484
+ this.toolExecutor = dependencies.toolExecutor;
3485
+ this.terminationPolicy = dependencies.terminationPolicy;
3486
+ this.contextManager = dependencies.contextManager;
3487
+ this.pluginHost = dependencies.pluginHost;
3488
+ this.notificationBus = dependencies.notificationBus;
3489
+ }
3490
+ async* run(state, input, options = {}) {
3491
+ const startPayload = await this.pluginHost?.runMiddleware("run.start", {
3492
+ sessionId: state.id,
3493
+ input
3494
+ }, this.createHookContext(state));
3495
+ const initialInput = startPayload?.input ?? input;
3496
+ await this.pluginHost?.runObservers("run.start", {
3497
+ sessionId: state.id,
3498
+ input: initialInput
3499
+ }, this.createHookContext(state));
3500
+ const userMessage = this.messageFactory.createUserMessage(initialInput);
3501
+ state.messages.push(userMessage);
3502
+ touchRuntimeSessionState(state);
3503
+ await this.notificationBus.emit({
3504
+ type: "run.start",
3505
+ source: "runtime",
3506
+ message: `Run started for session ${state.id}`,
3507
+ metadata: {
3508
+ sessionId: state.id
3509
+ }
3510
+ }, {
3511
+ ...this.createHookContext(state)
3512
+ });
3513
+ let lastRequestId;
3514
+ let lastIteration = 0;
3515
+ let pendingContextSegments = [];
3516
+ try {
3517
+ for (let iteration = 0;iteration < state.maxIterations; iteration += 1) {
3518
+ lastIteration = iteration;
3519
+ const requestId = createId("req");
3520
+ lastRequestId = requestId;
3521
+ const turnStart = await this.pluginHost?.runMiddleware("turn.start", {
3522
+ requestId,
3523
+ iteration,
3524
+ messages: [...state.messages]
3525
+ }, this.createHookContext(state, { requestId, iteration }));
3526
+ const contextItems = await this.contextManager.resolve({
3527
+ sessionId: state.id,
3528
+ input: initialInput,
3529
+ messages: state.messages,
3530
+ cwd: state.cwd
3531
+ });
3532
+ const resolvedContext = await this.pluginHost?.runMiddleware("context.resolve", {
3533
+ contextItems,
3534
+ input: initialInput,
3535
+ messages: [...state.messages]
3536
+ }, this.createHookContext(state, { requestId, iteration }));
3537
+ const effectiveContext = resolvedContext?.contextItems ?? contextItems;
3538
+ const pluginPromptSegments = await this.pluginHost?.collectPromptSegments({
3539
+ sessionId: state.id,
3540
+ input: initialInput,
3541
+ messages: state.messages,
3542
+ contextItems: effectiveContext,
3543
+ cwd: state.cwd
3544
+ }) ?? [];
3545
+ const promptSegments = [
3546
+ ...options.persistentPromptSegments ?? [],
3547
+ ...pendingContextSegments,
3548
+ ...this.contextManager.format(effectiveContext),
3549
+ ...pluginPromptSegments
3550
+ ];
3551
+ pendingContextSegments = [];
3552
+ const resolvedPrompt = await this.pluginHost?.runMiddleware("prompt.resolve", {
3553
+ promptSegments,
3554
+ contextItems: effectiveContext,
3555
+ messages: [...state.messages]
3556
+ }, this.createHookContext(state, { requestId, iteration }));
3557
+ const effectivePromptSegments = resolvedPrompt?.promptSegments ?? promptSegments;
3558
+ const toolDefinitions = state.tools?.definitions() ?? [];
3559
+ const resolvedToolset = await this.pluginHost?.runMiddleware("toolset.resolve", {
3560
+ tools: toolDefinitions
3561
+ }, this.createHookContext(state, { requestId, iteration }));
3562
+ const effectiveTools = resolvedToolset?.tools ?? toolDefinitions;
3563
+ const requestMessages = await this.resolveRequestMessages({
3564
+ state,
3565
+ requestId,
3566
+ iteration,
3567
+ baseMessages: [...turnStart?.messages ?? state.messages],
3568
+ runtimePromptSegments: effectivePromptSegments,
3569
+ contextItems: effectiveContext,
3570
+ tools: effectiveTools
3571
+ });
3572
+ const request = {
3573
+ requestId,
3574
+ model: state.modelRef,
3575
+ messages: requestMessages,
3576
+ tools: effectiveTools,
3577
+ reasoning: state.reasoning,
3578
+ signal: options.signal
3579
+ };
3580
+ const resolvedRequest = await this.pluginHost?.runMiddleware("model.request", {
3581
+ request
3582
+ }, this.createHookContext(state, { requestId, iteration }));
3583
+ const effectiveRequest = resolvedRequest?.request ?? request;
3584
+ const turn = yield* this.turnCollector.collect({
3585
+ sessionId: state.id,
3586
+ requestId,
3587
+ events: state.model.stream(effectiveRequest),
3588
+ onEvent: async (event) => {
3589
+ if (event.type === "error") {
3590
+ await this.notificationBus.emit({
3591
+ type: "provider.error",
3592
+ source: "provider",
3593
+ level: "error",
3594
+ message: event.error.message,
3595
+ metadata: {
3596
+ requestId,
3597
+ code: event.error.code,
3598
+ status: event.error.status
3599
+ }
3600
+ }, {
3601
+ ...this.createHookContext(state, { requestId, iteration })
3602
+ });
3603
+ }
3604
+ await this.pluginHost?.runObservers("model.event", { event }, {
3605
+ ...this.createHookContext(state, { requestId, iteration })
3606
+ });
3607
+ }
3608
+ });
3609
+ const assistantDraft = this.messageFactory.createAssistantMessage({
3610
+ text: turn.text,
3611
+ thinking: turn.thinking,
3612
+ toolCalls: turn.toolCalls,
3613
+ stopReason: turn.stopReason,
3614
+ metadata: turn.assistantMetadata
3615
+ });
3616
+ const assistantPayload = await this.pluginHost?.runMiddleware("assistant.message", {
3617
+ message: assistantDraft
3618
+ }, this.createHookContext(state, { requestId, iteration }));
3619
+ let assistantMessage = assistantPayload?.message ?? assistantDraft;
3620
+ state.messages.push(assistantMessage);
3621
+ state.usage = addUsage(state.usage, turn.usage);
3622
+ touchRuntimeSessionState(state);
3623
+ const baseDecision = this.terminationPolicy.afterAssistantTurn(turn.toolCalls);
3624
+ const stopBasePayload = {
3625
+ assistantMessage,
3626
+ toolCalls: turn.toolCalls,
3627
+ stopReason: turn.stopReason,
3628
+ decision: baseDecision
3629
+ };
3630
+ const stopResult = await this.pluginHost?.runRunStop(stopBasePayload, {
3631
+ ...this.createHookContext(state, { requestId, iteration })
3632
+ });
3633
+ const stopPayload = stopResult?.payload ?? stopBasePayload;
3634
+ const stopControl = stopResult?.control;
3635
+ await this.pluginHost?.runObservers("run.stop", {
3636
+ ...stopPayload,
3637
+ additionalContext: stopControl?.type === "finalize" ? stopControl.additionalContext ?? stopPayload.additionalContext : stopPayload.additionalContext,
3638
+ finalMessage: stopControl?.type === "finalize" ? stopControl.finalMessage ?? stopPayload.finalMessage : stopPayload.finalMessage
3639
+ }, this.createHookContext(state, { requestId, iteration }));
3640
+ const stopDecision = stopControl?.type === "finalize" ? { type: "done" } : stopPayload.decision;
3641
+ const additionalContext = stopControl?.type === "finalize" ? stopControl.additionalContext : stopPayload.additionalContext;
3642
+ const finalMessage = stopControl?.type === "finalize" ? stopControl.finalMessage ?? stopPayload.finalMessage ?? stopPayload.assistantMessage : stopPayload.finalMessage ?? stopPayload.assistantMessage;
3643
+ if (additionalContext && additionalContext.length > 0 && stopDecision.type === "continue")
3644
+ pendingContextSegments = [...pendingContextSegments, ...additionalContext];
3645
+ if (stopDecision.type === "done") {
3646
+ assistantMessage = finalMessage;
3647
+ state.messages[state.messages.length - 1] = assistantMessage;
3648
+ touchRuntimeSessionState(state);
3649
+ const endPayload = await this.pluginHost?.runMiddleware("run.end", {
3650
+ message: assistantMessage,
3651
+ usage: { ...state.usage }
3652
+ }, this.createHookContext(state, { requestId, iteration }));
3653
+ const completedMessage = endPayload?.message ?? assistantMessage;
3654
+ const completedUsage = endPayload?.usage ?? { ...state.usage };
3655
+ state.messages[state.messages.length - 1] = completedMessage;
3656
+ state.usage = { ...completedUsage };
3657
+ touchRuntimeSessionState(state);
3658
+ await this.notificationBus.emit({
3659
+ type: "run.end",
3660
+ source: "runtime",
3661
+ message: `Run completed for session ${state.id}`,
3662
+ metadata: {
3663
+ sessionId: state.id,
3664
+ requestId
3665
+ }
3666
+ }, {
3667
+ ...this.createHookContext(state, { requestId, iteration })
3668
+ });
3669
+ yield {
3670
+ type: "done",
3671
+ sessionId: state.id,
3672
+ message: completedMessage,
3673
+ usage: completedUsage
3674
+ };
3675
+ await this.pluginHost?.runObservers("run.end", {
3676
+ message: completedMessage,
3677
+ usage: completedUsage
3678
+ }, this.createHookContext(state, { requestId, iteration }));
3679
+ await options.onDone?.(completedMessage);
3680
+ return completedMessage;
3681
+ }
3682
+ for (const toolCall of turn.toolCalls) {
3683
+ yield { type: "tool_call", sessionId: state.id, toolCall };
3684
+ const pluginEvents = [];
3685
+ const result = await this.toolExecutor.execute(toolCall, {
3686
+ signal: options.signal,
3687
+ cwd: state.cwd,
3688
+ requestId,
3689
+ iteration,
3690
+ status: createSessionStatus(state),
3691
+ onEvent: async (event) => {
3692
+ pluginEvents.push(event);
3693
+ }
3694
+ });
3695
+ for (const event of pluginEvents)
3696
+ yield event;
3697
+ const toolMessage = this.messageFactory.createToolMessage(toolCall, result);
3698
+ state.messages.push(toolMessage);
3699
+ touchRuntimeSessionState(state);
3700
+ yield { type: "tool_result", sessionId: state.id, toolCallId: toolCall.id, result };
3701
+ }
3702
+ }
3703
+ } catch (error) {
3704
+ if (error instanceof SessionExecutionError) {
3705
+ await this.notificationBus.emit({
3706
+ type: error.payload.code.startsWith("openai_") || error.payload.code.startsWith("anthropic_") || error.payload.code.startsWith("gemini_") ? "provider.error" : "runtime.error",
3707
+ source: error.payload.code.includes("_http_") || error.payload.code.includes("_request_") ? "provider" : "runtime",
3708
+ level: "error",
3709
+ message: error.payload.message,
3710
+ metadata: {
3711
+ requestId: lastRequestId,
3712
+ code: error.payload.code
3713
+ }
3714
+ }, {
3715
+ ...this.createHookContext(state, { requestId: lastRequestId, iteration: lastIteration })
3716
+ });
3717
+ await this.pluginHost?.runObservers("session.error", { error: error.payload }, {
3718
+ ...this.createHookContext(state, { requestId: lastRequestId })
3719
+ });
3720
+ }
3721
+ throw error;
3722
+ }
3723
+ const payload = this.terminationPolicy.onMaxIterationsExceeded(state.maxIterations, lastRequestId);
3724
+ yield { type: "error", sessionId: state.id, error: payload };
3725
+ await this.notificationBus.emit({
3726
+ type: "runtime.error",
3727
+ source: "runtime",
3728
+ level: "error",
3729
+ message: payload.message,
3730
+ metadata: {
3731
+ requestId: lastRequestId,
3732
+ code: payload.code
3733
+ }
3734
+ }, {
3735
+ ...this.createHookContext(state, { requestId: lastRequestId, iteration: lastIteration })
3736
+ });
3737
+ await this.pluginHost?.runObservers("session.error", { error: payload }, {
3738
+ ...this.createHookContext(state, { requestId: lastRequestId })
3739
+ });
3740
+ throw new SessionExecutionError(payload);
3741
+ }
3742
+ async resolveRequestMessages(input) {
3743
+ const initialAttempt = await this.buildProjectedRequestMessages(input.state, input.baseMessages, input.runtimePromptSegments, input.tools);
3744
+ if (!isCompactionRequired(input.state.compactionOptions, initialAttempt.budget))
3745
+ return initialAttempt.messages;
3746
+ const budget = initialAttempt.budget;
3747
+ if (!budget)
3748
+ return initialAttempt.messages;
3749
+ await this.notificationBus.emit({
3750
+ type: "context.compaction.required",
3751
+ source: "runtime",
3752
+ level: "warning",
3753
+ message: `Context compaction required for session ${input.state.id}`,
3754
+ metadata: {
3755
+ requestId: input.requestId,
3756
+ estimatedInputTokens: budget.estimatedInputTokens,
3757
+ thresholdTokens: budget.thresholdTokens,
3758
+ maxInputTokens: budget.maxInputTokens,
3759
+ cursor: input.state.compaction.cursor
3760
+ }
3761
+ }, {
3762
+ ...this.createHookContext(input.state, { requestId: input.requestId, iteration: input.iteration })
3763
+ });
3764
+ const beforeState = cloneCompactionState(input.state.compaction);
3765
+ const compactPayload = await this.pluginHost?.runMiddleware("context.compact.before", {
3766
+ sessionId: input.state.id,
3767
+ messages: [...input.state.messages],
3768
+ cursor: beforeState.cursor,
3769
+ systemSegments: [...beforeState.systemSegments],
3770
+ contextItems: input.contextItems,
3771
+ estimatedInputTokens: budget.estimatedInputTokens,
3772
+ thresholdTokens: budget.thresholdTokens,
3773
+ maxInputTokens: budget.maxInputTokens,
3774
+ trigger: "threshold"
3775
+ }, {
3776
+ ...this.createHookContext(input.state, { requestId: input.requestId, iteration: input.iteration })
3777
+ });
3778
+ await this.pluginHost?.runObservers("context.compact.before", compactPayload ?? {
3779
+ sessionId: input.state.id,
3780
+ messages: [...input.state.messages],
3781
+ cursor: beforeState.cursor,
3782
+ systemSegments: [...beforeState.systemSegments],
3783
+ contextItems: input.contextItems,
3784
+ estimatedInputTokens: budget.estimatedInputTokens,
3785
+ thresholdTokens: budget.thresholdTokens,
3786
+ maxInputTokens: budget.maxInputTokens,
3787
+ trigger: "threshold"
3788
+ }, {
3789
+ ...this.createHookContext(input.state, { requestId: input.requestId, iteration: input.iteration })
3790
+ });
3791
+ input.state.compaction = normalizeCompactionState(input.state.compaction, input.state.messages);
3792
+ const afterState = cloneCompactionState(input.state.compaction);
3793
+ if (didCompactionStateChange(beforeState, afterState)) {
3794
+ const latestCheckpoint = afterState.checkpoints.at(-1);
3795
+ await this.notificationBus.emit({
3796
+ type: "context.compacted",
3797
+ source: "runtime",
3798
+ level: "info",
3799
+ message: `Context compacted for session ${input.state.id}`,
3800
+ metadata: {
3801
+ requestId: input.requestId,
3802
+ cursor: afterState.cursor,
3803
+ checkpointId: latestCheckpoint?.id,
3804
+ reason: latestCheckpoint?.reason
3805
+ }
3806
+ }, {
3807
+ ...this.createHookContext(input.state, { requestId: input.requestId, iteration: input.iteration })
3808
+ });
3809
+ }
3810
+ const compactedAttempt = await this.buildProjectedRequestMessages(input.state, input.baseMessages, input.runtimePromptSegments, input.tools);
3811
+ if (!isCompactionRequired(input.state.compactionOptions, compactedAttempt.budget))
3812
+ return compactedAttempt.messages;
3813
+ throw new SessionExecutionError({
3814
+ code: "context_compaction_required",
3815
+ message: `Context compaction required before continuing the run (estimated ${budget.estimatedInputTokens} tokens, threshold ${budget.thresholdTokens})`,
3816
+ requestId: input.requestId
3817
+ });
3818
+ }
3819
+ async buildProjectedRequestMessages(state, baseMessages, runtimePromptSegments, tools) {
3820
+ const projectedMessages = projectMessagesForRequest(baseMessages, state.compaction);
3821
+ const promptSegments = [
3822
+ ...buildCompactionPromptSegments(state.compaction),
3823
+ ...runtimePromptSegments
3824
+ ];
3825
+ const requestMessages = [...projectedMessages];
3826
+ if (promptSegments.length > 0)
3827
+ requestMessages.unshift(this.messageFactory.createSystemMessage(promptSegments.join(`
3828
+
3829
+ `)));
3830
+ const budget = state.compactionOptions && state.compactionOptions.enabled !== false ? await estimateCompactionBudget(state.compactionOptions, {
3831
+ model: state.modelRef,
3832
+ messages: requestMessages,
3833
+ tools
3834
+ }) : undefined;
3835
+ return {
3836
+ messages: requestMessages,
3837
+ budget
3838
+ };
3839
+ }
3840
+ createHookContext(state, input = {}) {
3841
+ return {
3842
+ sessionId: state.id,
3843
+ requestId: input.requestId,
3844
+ iteration: input.iteration,
3845
+ cwd: state.cwd,
3846
+ metadata: state.metadata,
3847
+ status: createSessionStatus(state)
3848
+ };
3849
+ }
3850
+ }
3851
+
3852
+ // src/agent-core/termination-policy.ts
3853
+ class DefaultTerminationPolicy {
3854
+ afterAssistantTurn(toolCalls) {
3855
+ return toolCalls.length === 0 ? { type: "done" } : { type: "continue" };
3856
+ }
3857
+ onMaxIterationsExceeded(maxIterations, requestId) {
3858
+ return {
3859
+ code: "max_iterations_exceeded",
3860
+ message: `Session exceeded maxIterations (${maxIterations})`,
3861
+ requestId
3862
+ };
3863
+ }
3864
+ }
3865
+
3866
+ // src/agent-core/tool-executor.ts
3867
+ class DefaultToolExecutor {
3868
+ sessionId;
3869
+ tools;
3870
+ metadata;
3871
+ services;
3872
+ pluginHost;
3873
+ approvalManager;
3874
+ notificationBus;
3875
+ constructor(options) {
3876
+ this.sessionId = options.sessionId;
3877
+ this.tools = options.tools;
3878
+ this.metadata = options.metadata;
3879
+ this.services = options.services;
3880
+ this.pluginHost = options.pluginHost;
3881
+ this.approvalManager = options.approvalManager;
3882
+ this.notificationBus = options.notificationBus;
3883
+ }
3884
+ async execute(toolCall, options = {}) {
3885
+ const hookContext = {
3886
+ sessionId: this.sessionId,
3887
+ requestId: options.requestId,
3888
+ iteration: options.iteration,
3889
+ cwd: options.cwd,
3890
+ status: options.status,
3891
+ services: this.services,
3892
+ metadata: this.metadata
3893
+ };
3894
+ const before = await this.pluginHost?.runToolBeforeExecute({
3895
+ toolCall
3896
+ }, hookContext);
3897
+ let currentToolCall = before?.payload.toolCall ?? toolCall;
3898
+ let result;
3899
+ if (before?.control) {
3900
+ if (before.control.type === "provideResult") {
3901
+ result = normalizeToolResult(before.control.result);
3902
+ } else if (before.control.type === "deny") {
3903
+ result = normalizeToolResult(before.control.result ?? {
3904
+ ...textToolResult(before.control.reason ?? `Tool denied: ${currentToolCall.function.name}`),
3905
+ isError: true
3906
+ });
3907
+ await this.notificationBus.emit({
3908
+ type: "tool.denied",
3909
+ source: "permission",
3910
+ level: "warning",
3911
+ message: before.control.reason ?? `Tool denied: ${currentToolCall.function.name}`,
3912
+ metadata: {
3913
+ toolName: currentToolCall.function.name
3914
+ }
3915
+ }, hookContext);
3916
+ } else if (before.control.type === "ask") {
3917
+ currentToolCall = before.control.toolCall ?? currentToolCall;
3918
+ const approvalRequest = {
3919
+ id: undefined,
3920
+ kind: "tool_execution",
3921
+ toolCall: currentToolCall,
3922
+ message: before.control.request?.message ?? `Approval required to execute tool: ${currentToolCall.function.name}`,
3923
+ metadata: before.control.request?.metadata
3924
+ };
3925
+ const decision = await this.approvalManager.requestApproval(approvalRequest, hookContext);
3926
+ if (decision.type === "denied") {
3927
+ result = normalizeToolResult({
3928
+ ...textToolResult(decision.reason ?? `Tool approval denied: ${currentToolCall.function.name}`),
3929
+ isError: true
3930
+ });
3931
+ }
3932
+ }
3933
+ }
3934
+ if (!result) {
3935
+ const tool = this.tools?.get(currentToolCall.function.name);
3936
+ if (!tool) {
3937
+ result = normalizeToolResult({ ...textToolResult(`Tool not found: ${currentToolCall.function.name}`), isError: true });
3938
+ } else {
3939
+ try {
3940
+ result = normalizeToolResult(await tool.execute(currentToolCall.function.arguments, {
3941
+ sessionId: this.sessionId,
3942
+ cwd: options.cwd,
3943
+ signal: options.signal,
3944
+ metadata: this.metadata,
3945
+ services: this.services,
3946
+ emitEvent: async (event) => {
3947
+ const pluginId = event.pluginId;
3948
+ if (!pluginId)
3949
+ throw new Error(`Tool ${currentToolCall.function.name} emitted a plugin event without pluginId`);
3950
+ await options.onEvent?.({
3951
+ type: "plugin_event",
3952
+ sessionId: this.sessionId,
3953
+ pluginId,
3954
+ event: event.event,
3955
+ data: event.data ? structuredClone(event.data) : undefined
3956
+ });
3957
+ }
3958
+ }));
3959
+ } catch (error) {
3960
+ const message = error instanceof Error ? error.message : String(error);
3961
+ result = normalizeToolResult({
3962
+ ...textToolResult(message),
3963
+ isError: true
3964
+ });
3965
+ }
3966
+ }
3967
+ }
3968
+ const after = await this.pluginHost?.runMiddleware("tool.afterExecute", {
3969
+ toolCall: currentToolCall,
3970
+ result
3971
+ }, hookContext);
3972
+ const finalResult = normalizeToolResult(after?.result ?? result);
3973
+ await this.notificationBus.emit({
3974
+ type: finalResult.isError ? "tool.failed" : "tool.completed",
3975
+ source: "tool",
3976
+ level: finalResult.isError ? "error" : "info",
3977
+ message: finalResult.isError ? `Tool failed: ${currentToolCall.function.name}` : `Tool completed: ${currentToolCall.function.name}`,
3978
+ metadata: {
3979
+ toolName: currentToolCall.function.name,
3980
+ isError: finalResult.isError === true
3981
+ }
3982
+ }, hookContext);
3983
+ return finalResult;
3984
+ }
3985
+ }
3986
+
3987
+ // src/agent-core/session.ts
3988
+ var DEFAULT_MESSAGE_QUEUE_CONFIG = {
3989
+ autoProcessQueue: true
3990
+ };
3991
+
3992
+ class Session {
3993
+ id;
3994
+ createdAt;
3995
+ stateStore;
3996
+ state;
3997
+ pluginHost;
3998
+ contextManager;
3999
+ services;
4000
+ approvalManager;
4001
+ notificationBus;
4002
+ compactionService;
4003
+ pluginStateService;
4004
+ pluginControllers;
4005
+ bufferedEvents = [];
4006
+ stateChangeWaiters = [];
4007
+ activeRunCount = 0;
4008
+ processingPromise = null;
4009
+ receiveActive = false;
4010
+ activeReceiveSignal;
4011
+ haltProcessingUntilReceive = false;
4012
+ saveChain = Promise.resolve();
4013
+ constructor(options) {
4014
+ const now = Date.now();
4015
+ this.id = options.id ?? createId("session");
4016
+ this.createdAt = options.createdAt ?? now;
4017
+ this.stateStore = options.stateStore;
4018
+ this.pluginHost = options.pluginHost;
4019
+ this.contextManager = options.contextManager;
4020
+ this.services = options.services;
4021
+ this.approvalManager = options.approvalManager;
4022
+ this.notificationBus = options.notificationBus;
4023
+ this.compactionService = options.compactionService;
4024
+ this.pluginStateService = options.pluginStateService;
4025
+ this.state = {
4026
+ id: this.id,
4027
+ model: options.model,
4028
+ modelRef: options.modelRef ?? options.model.model,
4029
+ tools: options.tools,
4030
+ maxIterations: options.maxIterations ?? 8,
4031
+ cwd: options.cwd,
4032
+ metadata: options.metadata,
4033
+ reasoning: options.reasoning,
4034
+ messages: [...options.messages ?? []],
4035
+ usage: options.usage ? { ...options.usage } : createEmptyUsage(),
4036
+ compaction: cloneCompactionState(options.compaction ?? createEmptyCompactionState()),
4037
+ pluginState: clonePluginStateMap(options.pluginState),
4038
+ messageQueue: cloneMessageQueueSnapshot(options.messageQueue ?? {
4039
+ items: [],
4040
+ config: createMessageQueueConfig(options.messageQueueConfig)
4041
+ }),
4042
+ compactionOptions: options.compactionOptions,
4043
+ createdAt: this.createdAt,
4044
+ updatedAt: options.updatedAt ?? now
4045
+ };
4046
+ if (options.messageQueueConfig)
4047
+ this.state.messageQueue.config = createMessageQueueConfig(options.messageQueueConfig, this.state.messageQueue.config);
4048
+ this.compactionService.registerSession(this.state);
4049
+ this.pluginStateService.registerSession(this.state);
4050
+ this.pluginControllers = this.pluginHost?.createSessionControllers({
4051
+ sessionId: this.id,
4052
+ metadata: this.state.metadata,
4053
+ getStatus: () => this.getStatus(),
4054
+ save: () => this.save(),
4055
+ isRunning: () => this.activeRunCount > 0
4056
+ }) ?? new Map;
4057
+ }
4058
+ get messages() {
4059
+ return [...this.state.messages];
4060
+ }
4061
+ get usage() {
4062
+ return { ...this.state.usage };
4063
+ }
4064
+ getStatus() {
4065
+ return createSessionStatus(this.state);
4066
+ }
4067
+ getCompactionState() {
4068
+ return cloneCompactionState(this.state.compaction);
4069
+ }
4070
+ getPluginState(pluginId) {
4071
+ return clonePluginSessionStateEntry(this.state.pluginState[pluginId]);
4072
+ }
4073
+ listPluginStates() {
4074
+ return clonePluginStateMap(this.state.pluginState);
4075
+ }
4076
+ getPlugin(pluginId) {
4077
+ return this.pluginControllers.get(pluginId) ?? null;
4078
+ }
4079
+ get updatedAt() {
4080
+ return this.state.updatedAt;
4081
+ }
4082
+ getCwd() {
4083
+ return this.state.cwd;
4084
+ }
4085
+ setCwd(cwd) {
4086
+ this.state.cwd = cwd;
4087
+ touchRuntimeSessionState(this.state);
4088
+ }
4089
+ send(input, options = {}) {
4090
+ return this.enqueueItem("user", input, options);
4091
+ }
4092
+ sendBatch(items) {
4093
+ const maxQueueSize = this.state.messageQueue.config.maxQueueSize;
4094
+ if (maxQueueSize !== undefined && this.state.messageQueue.items.length + items.length > maxQueueSize)
4095
+ throw new SessionExecutionError(createQueueError("DIM_QUEUE_FULL", `Session queue is full (max ${maxQueueSize})`));
4096
+ const prepared = items.map(({ input, options }) => prepareQueueItem("user", input, options));
4097
+ for (const item of prepared)
4098
+ this.state.messageQueue.items.push(item);
4099
+ if (prepared.length > 0)
4100
+ this.onQueueMutated();
4101
+ return prepared.map((item) => item.id);
4102
+ }
4103
+ steer(input, options = {}) {
4104
+ return this.enqueueItem("steer", input, options);
4105
+ }
4106
+ cancelQueuedItem(itemId) {
4107
+ const index = this.state.messageQueue.items.findIndex((item) => item.id === itemId);
4108
+ if (index < 0)
4109
+ return false;
4110
+ this.state.messageQueue.items.splice(index, 1);
4111
+ this.onQueueMutated();
4112
+ return true;
4113
+ }
4114
+ getQueueStatus() {
4115
+ const items = [...this.state.messageQueue.items].sort(compareQueueItems).map((item) => ({
4116
+ id: item.id,
4117
+ kind: item.kind,
4118
+ priority: item.priority,
4119
+ enqueuedAt: item.enqueuedAt,
4120
+ preview: createQueuePreview(item.input)
4121
+ }));
4122
+ return {
4123
+ length: items.length,
4124
+ items,
4125
+ isProcessing: this.processingPromise !== null,
4126
+ config: cloneMessageQueueConfig(this.state.messageQueue.config)
4127
+ };
4128
+ }
4129
+ clearQueue(filter = {}) {
4130
+ const before = this.state.messageQueue.items.length;
4131
+ if (!filter.kind) {
4132
+ this.state.messageQueue.items = [];
4133
+ } else {
4134
+ this.state.messageQueue.items = this.state.messageQueue.items.filter((item) => item.kind !== filter.kind);
4135
+ }
4136
+ const cleared = before - this.state.messageQueue.items.length;
4137
+ if (cleared > 0)
4138
+ this.onQueueMutated();
4139
+ return cleared;
4140
+ }
4141
+ async* receive(options = {}) {
4142
+ if (this.receiveActive)
4143
+ throw new SessionExecutionError(createQueueError("DIM_QUEUE_BUSY", "Only one receive() call can be active for a session"));
4144
+ this.receiveActive = true;
4145
+ this.activeReceiveSignal = options.signal;
4146
+ this.haltProcessingUntilReceive = false;
4147
+ let deliveredEvent = null;
4148
+ try {
4149
+ while (true) {
4150
+ if (deliveredEvent) {
4151
+ deliveredEvent.ack();
4152
+ deliveredEvent = null;
4153
+ }
4154
+ this.ensureQueueProcessing("receive");
4155
+ const nextBufferedEvent = this.bufferedEvents.shift();
4156
+ if (nextBufferedEvent) {
4157
+ deliveredEvent = nextBufferedEvent;
4158
+ yield nextBufferedEvent.event;
4159
+ continue;
4160
+ }
4161
+ if (!this.processingPromise && !this.hasRunnableItems())
4162
+ return;
4163
+ await this.waitForStateChange(options.signal);
4164
+ }
4165
+ } finally {
4166
+ if (deliveredEvent)
4167
+ deliveredEvent.ack();
4168
+ this.receiveActive = false;
4169
+ if (this.activeReceiveSignal === options.signal)
4170
+ this.activeReceiveSignal = undefined;
4171
+ this.notifyStateChange();
4172
+ }
4173
+ }
4174
+ async compact(update) {
4175
+ const beforeState = this.getCompactionState();
4176
+ const estimatedInputTokens = await this.readEstimatedInputTokens();
4177
+ const thresholdTokens = this.state.compactionOptions?.triggerTokens ?? (this.state.compactionOptions ? Math.max(1, Math.floor(this.state.compactionOptions.maxInputTokens * (this.state.compactionOptions.triggerRatio ?? 0.8))) : 0);
4178
+ const maxInputTokens = this.state.compactionOptions?.maxInputTokens ?? 0;
4179
+ const payload = {
4180
+ sessionId: this.id,
4181
+ messages: this.messages,
4182
+ cursor: beforeState.cursor,
4183
+ systemSegments: [...beforeState.systemSegments],
4184
+ contextItems: undefined,
4185
+ estimatedInputTokens,
4186
+ thresholdTokens,
4187
+ maxInputTokens,
4188
+ trigger: "manual"
4189
+ };
4190
+ if (this.pluginHost) {
4191
+ const compactPayload = await this.pluginHost.runMiddleware("context.compact.before", payload, {
4192
+ ...this.createHookContext(),
4193
+ services: this.services
4194
+ });
4195
+ await this.pluginHost.runObservers("context.compact.before", compactPayload, {
4196
+ ...this.createHookContext(),
4197
+ services: this.services
4198
+ });
4199
+ }
4200
+ await this.compactionService.apply({
4201
+ sessionId: this.id,
4202
+ ...update,
4203
+ reason: update.reason ?? "manual"
4204
+ });
4205
+ const afterState = this.getCompactionState();
4206
+ const latestCheckpoint = afterState.checkpoints.at(-1);
4207
+ await this.notificationBus.emit({
4208
+ type: "context.compacted",
4209
+ source: "runtime",
4210
+ level: "info",
4211
+ message: `Context compacted for session ${this.id}`,
4212
+ metadata: {
4213
+ cursor: afterState.cursor,
4214
+ checkpointId: latestCheckpoint?.id,
4215
+ reason: latestCheckpoint?.reason
4216
+ }
4217
+ }, {
4218
+ ...this.createHookContext()
4219
+ });
4220
+ }
4221
+ async save() {
4222
+ return this.enqueueSave();
4223
+ }
4224
+ async writeSnapshot() {
4225
+ if (!this.stateStore)
4226
+ return;
4227
+ let snapshot = this.toSnapshot();
4228
+ if (this.pluginHost) {
4229
+ snapshot = await this.pluginHost.runMiddleware("snapshot.encode", { snapshot }, {
4230
+ ...this.createHookContext(),
4231
+ services: this.services
4232
+ }).then((payload) => payload.snapshot);
4233
+ }
4234
+ await this.stateStore.save(snapshot);
4235
+ await this.notificationBus.emit({
4236
+ type: "snapshot.saved",
4237
+ source: "persistence",
4238
+ level: "info",
4239
+ message: `Saved snapshot for session ${this.id}`,
4240
+ metadata: {
4241
+ sessionId: this.id,
4242
+ schemaVersion: snapshot.schemaVersion
4243
+ }
4244
+ }, {
4245
+ ...this.createHookContext()
4246
+ });
4247
+ }
4248
+ toSnapshot() {
4249
+ return sessionSnapshotCodec.encode({
4250
+ sessionId: this.id,
4251
+ model: this.state.modelRef,
4252
+ cwd: this.state.cwd,
4253
+ messages: this.messages,
4254
+ usage: this.usage,
4255
+ compaction: this.getCompactionState(),
4256
+ pluginState: this.listPluginStates(),
4257
+ createdAt: this.createdAt,
4258
+ updatedAt: this.updatedAt,
4259
+ metadata: this.state.metadata ? { ...this.state.metadata } : undefined,
4260
+ messageQueue: cloneMessageQueueSnapshot(this.state.messageQueue)
4261
+ });
4262
+ }
4263
+ enqueueItem(kind, input, options) {
4264
+ const maxQueueSize = this.state.messageQueue.config.maxQueueSize;
4265
+ if (maxQueueSize !== undefined && this.state.messageQueue.items.length >= maxQueueSize)
4266
+ throw new SessionExecutionError(createQueueError("DIM_QUEUE_FULL", `Session queue is full (max ${maxQueueSize})`));
4267
+ const item = prepareQueueItem(kind, input, options);
4268
+ this.state.messageQueue.items.push(item);
4269
+ this.onQueueMutated();
4270
+ return item.id;
4271
+ }
4272
+ onQueueMutated() {
4273
+ touchRuntimeSessionState(this.state);
4274
+ this.notifyStateChange();
4275
+ this.scheduleSave();
4276
+ this.ensureQueueProcessing("auto");
4277
+ }
4278
+ hasRunnableItems() {
4279
+ return this.state.messageQueue.items.some((item) => item.kind === "user");
4280
+ }
4281
+ ensureQueueProcessing(source) {
4282
+ if (this.processingPromise)
4283
+ return;
4284
+ if (!this.hasRunnableItems())
4285
+ return;
4286
+ if (this.haltProcessingUntilReceive && source !== "receive")
4287
+ return;
4288
+ const signal = source === "receive" ? this.activeReceiveSignal : undefined;
4289
+ this.processingPromise = this.processQueue(signal).finally(() => {
4290
+ this.processingPromise = null;
4291
+ this.notifyStateChange();
4292
+ if (!this.haltProcessingUntilReceive && this.state.messageQueue.config.autoProcessQueue)
4293
+ this.ensureQueueProcessing("auto");
4294
+ });
4295
+ this.notifyStateChange();
4296
+ }
4297
+ async processQueue(signal) {
4298
+ while (true) {
4299
+ const nextItem = this.dequeueNextRunnableItem();
4300
+ if (!nextItem)
4301
+ return;
4302
+ const completed = await this.processQueuedItem(nextItem, signal);
4303
+ await this.persistStateQuietly();
4304
+ if (!completed) {
4305
+ this.haltProcessingUntilReceive = true;
4306
+ return;
4307
+ }
4308
+ }
4309
+ }
4310
+ dequeueNextRunnableItem() {
4311
+ const rankedItems = [...this.state.messageQueue.items].sort(compareQueueItems);
4312
+ const userIndex = rankedItems.findIndex((item) => item.kind === "user");
4313
+ if (userIndex < 0)
4314
+ return null;
4315
+ const userItem = rankedItems[userIndex];
4316
+ const steerItems = rankedItems.slice(0, userIndex).filter((item) => item.kind === "steer");
4317
+ const consumedIds = new Set([userItem.id, ...steerItems.map((item) => item.id)]);
4318
+ this.state.messageQueue.items = this.state.messageQueue.items.filter((item) => !consumedIds.has(item.id));
4319
+ touchRuntimeSessionState(this.state);
4320
+ this.notifyStateChange();
4321
+ return {
4322
+ item: userItem,
4323
+ steerSegments: steerItems.map((item) => contentToText(normalizeContent(item.input)).trim()).filter((segment) => segment.length > 0)
4324
+ };
4325
+ }
4326
+ async processQueuedItem(input, signal) {
4327
+ const runner = this.createLoopRunner();
4328
+ let emittedError = false;
4329
+ this.activeRunCount += 1;
4330
+ try {
4331
+ const iterator = runner.run(this.state, input.item.input, {
4332
+ signal,
4333
+ persistentPromptSegments: input.steerSegments
4334
+ });
4335
+ while (true) {
4336
+ const next = await iterator.next();
4337
+ if (next.done)
4338
+ return true;
4339
+ const queuedEvent = this.attachQueueContext(next.value, input.item);
4340
+ if (queuedEvent.type === "error")
4341
+ emittedError = true;
4342
+ await this.pushBufferedEvent(queuedEvent);
4343
+ }
4344
+ } catch (error) {
4345
+ if (!emittedError)
4346
+ await this.pushBufferedEvent(this.createErrorEvent(input.item, error));
4347
+ return false;
4348
+ } finally {
4349
+ this.activeRunCount = Math.max(0, this.activeRunCount - 1);
4350
+ this.notifyStateChange();
4351
+ }
4352
+ }
4353
+ attachQueueContext(event, item) {
4354
+ return {
4355
+ ...event,
4356
+ itemId: item.id,
4357
+ itemKind: item.kind,
4358
+ priority: item.priority
4359
+ };
4360
+ }
4361
+ createErrorEvent(item, error) {
4362
+ const payload = error instanceof SessionExecutionError ? error.payload : {
4363
+ code: "runtime_error",
4364
+ message: error instanceof Error ? error.message : String(error)
4365
+ };
4366
+ return {
4367
+ type: "error",
4368
+ sessionId: this.id,
4369
+ error: payload,
4370
+ itemId: item.id,
4371
+ itemKind: item.kind,
4372
+ priority: item.priority
4373
+ };
4374
+ }
4375
+ async pushBufferedEvent(event) {
4376
+ let resolved = false;
4377
+ const ack = () => {
4378
+ if (resolved)
4379
+ return;
4380
+ resolved = true;
4381
+ this.notifyStateChange();
4382
+ };
4383
+ this.bufferedEvents.push({ event, ack });
4384
+ this.notifyStateChange();
4385
+ while (!resolved)
4386
+ await this.waitForStateChange();
4387
+ }
4388
+ scheduleSave() {
4389
+ if (!this.stateStore)
4390
+ return;
4391
+ this.enqueueSave().catch(() => {
4392
+ return;
4393
+ });
4394
+ }
4395
+ async persistStateQuietly() {
4396
+ try {
4397
+ await this.enqueueSave();
4398
+ } catch {}
4399
+ }
4400
+ enqueueSave() {
4401
+ if (!this.stateStore)
4402
+ return Promise.resolve();
4403
+ this.saveChain = this.saveChain.catch(() => {
4404
+ return;
4405
+ }).then(() => this.writeSnapshot());
4406
+ return this.saveChain;
4407
+ }
4408
+ waitForStateChange(signal) {
4409
+ if (signal?.aborted)
4410
+ return Promise.reject(new SessionExecutionError(createQueueError("session_receive_aborted", "Session receive aborted")));
4411
+ return new Promise((resolve, reject) => {
4412
+ const onAbort = () => {
4413
+ cleanup();
4414
+ reject(new SessionExecutionError(createQueueError("session_receive_aborted", "Session receive aborted")));
4415
+ };
4416
+ const resume = () => {
4417
+ cleanup();
4418
+ resolve();
4419
+ };
4420
+ const cleanup = () => {
4421
+ const index = this.stateChangeWaiters.indexOf(resume);
4422
+ if (index >= 0)
4423
+ this.stateChangeWaiters.splice(index, 1);
4424
+ signal?.removeEventListener("abort", onAbort);
4425
+ };
4426
+ this.stateChangeWaiters.push(resume);
4427
+ signal?.addEventListener("abort", onAbort, { once: true });
4428
+ });
4429
+ }
4430
+ notifyStateChange() {
4431
+ while (this.stateChangeWaiters.length > 0)
4432
+ this.stateChangeWaiters.shift()?.();
4433
+ }
4434
+ createLoopRunner() {
4435
+ return new LoopRunner({
4436
+ messageFactory: new DefaultMessageFactory,
4437
+ turnCollector: new DefaultModelTurnCollector,
4438
+ toolExecutor: new DefaultToolExecutor({
4439
+ sessionId: this.id,
4440
+ tools: this.state.tools,
4441
+ metadata: this.state.metadata,
4442
+ services: this.services,
4443
+ pluginHost: this.pluginHost,
4444
+ approvalManager: this.approvalManager,
4445
+ notificationBus: this.notificationBus
4446
+ }),
4447
+ terminationPolicy: new DefaultTerminationPolicy,
4448
+ contextManager: this.contextManager,
4449
+ pluginHost: this.pluginHost,
4450
+ notificationBus: this.notificationBus
4451
+ });
4452
+ }
4453
+ async readEstimatedInputTokens() {
4454
+ if (!this.state.compactionOptions || this.state.compactionOptions.enabled === false)
4455
+ return 0;
4456
+ const projectedMessages = projectMessagesForRequest(this.state.messages, this.state.compaction);
4457
+ const promptSegments = buildCompactionPromptSegments(this.state.compaction);
4458
+ const requestMessages = [...projectedMessages];
4459
+ if (promptSegments.length > 0)
4460
+ requestMessages.unshift(new DefaultMessageFactory().createSystemMessage(promptSegments.join(`
4461
+
4462
+ `)));
4463
+ const budget = await estimateCompactionBudget(this.state.compactionOptions, {
4464
+ model: this.state.modelRef,
4465
+ messages: requestMessages,
4466
+ tools: this.state.tools?.definitions() ?? []
4467
+ });
4468
+ return budget.estimatedInputTokens;
4469
+ }
4470
+ createHookContext(input = {}) {
4471
+ return {
4472
+ sessionId: this.id,
4473
+ requestId: input.requestId,
4474
+ iteration: input.iteration,
4475
+ cwd: this.state.cwd,
4476
+ metadata: this.state.metadata,
4477
+ status: this.getStatus()
4478
+ };
4479
+ }
4480
+ }
4481
+ function createMessageQueueConfig(overrides, base = DEFAULT_MESSAGE_QUEUE_CONFIG) {
4482
+ return {
4483
+ autoProcessQueue: overrides?.autoProcessQueue ?? base.autoProcessQueue,
4484
+ maxQueueSize: overrides?.maxQueueSize ?? base.maxQueueSize
4485
+ };
4486
+ }
4487
+ function cloneMessageQueueConfig(config) {
4488
+ return {
4489
+ autoProcessQueue: config.autoProcessQueue,
4490
+ maxQueueSize: config.maxQueueSize
4491
+ };
4492
+ }
4493
+ function clonePendingMessage(item) {
4494
+ return {
4495
+ id: item.id,
4496
+ input: structuredClone(item.input),
4497
+ kind: item.kind,
4498
+ priority: item.priority,
4499
+ enqueuedAt: item.enqueuedAt
4500
+ };
4501
+ }
4502
+ function cloneMessageQueueSnapshot(snapshot) {
4503
+ return {
4504
+ items: snapshot.items.map(clonePendingMessage),
4505
+ config: cloneMessageQueueConfig(snapshot.config)
4506
+ };
4507
+ }
4508
+ function prepareQueueItem(kind, input, options = {}) {
4509
+ const normalizedInput = normalizeContent(input);
4510
+ if (kind === "steer" && contentToText(normalizedInput).trim().length === 0)
4511
+ throw new TypeError("Steer content must contain text");
4512
+ return {
4513
+ id: createId("item"),
4514
+ input: structuredClone(input),
4515
+ kind,
4516
+ priority: options.priority ?? 0,
4517
+ enqueuedAt: Date.now()
4518
+ };
4519
+ }
4520
+ function compareQueueItems(left, right) {
4521
+ if (left.priority !== right.priority)
4522
+ return right.priority - left.priority;
4523
+ if (left.enqueuedAt !== right.enqueuedAt)
4524
+ return left.enqueuedAt - right.enqueuedAt;
4525
+ return left.id.localeCompare(right.id);
4526
+ }
4527
+ function createQueuePreview(input) {
4528
+ const text = contentToText(normalizeContent(input)).trim();
4529
+ if (text.length === 0)
4530
+ return "[non-text content]";
4531
+ if (text.length <= 80)
4532
+ return text;
4533
+ return `${text.slice(0, 77)}...`;
4534
+ }
4535
+ function createQueueError(code, message) {
4536
+ return { code, message };
4537
+ }
4538
+
4539
+ // src/agent-core/agent.ts
4540
+ class Agent {
4541
+ id;
4542
+ pluginHost;
4543
+ services;
4544
+ tools;
4545
+ permissions;
4546
+ options;
4547
+ messageFactory = new DefaultMessageFactory;
4548
+ contextManager;
4549
+ tracker;
4550
+ permissionGateway;
4551
+ approvalManager;
4552
+ notificationBus;
4553
+ compactionService;
4554
+ pluginStateService;
4555
+ constructor(options) {
4556
+ this.id = createId("agent");
4557
+ this.options = options;
4558
+ this.permissions = options.permissions;
4559
+ validateCompactionOwner(options);
4560
+ this.tracker = new ActivityTracker;
4561
+ this.compactionService = new DefaultCompactionService;
4562
+ this.pluginStateService = new DefaultPluginStateService;
4563
+ this.services = createServices(options, this.tracker, this.compactionService, this.pluginStateService);
4564
+ this.permissionGateway = new PermissionGateway({
4565
+ permissions: options.permissions,
4566
+ compactionOwnerPluginId: options.compaction?.ownerPluginId
4567
+ });
4568
+ this.pluginHost = new PluginHost({
4569
+ agentId: this.id,
4570
+ cwd: options.cwd,
4571
+ plugins: options.plugins,
4572
+ services: this.services,
4573
+ permissionGateway: this.permissionGateway,
4574
+ tracker: this.tracker
4575
+ });
4576
+ this.notificationBus = new DefaultNotificationBus({
4577
+ pluginHost: this.pluginHost,
4578
+ services: this.services
4579
+ });
4580
+ this.approvalManager = new DefaultApprovalManager({
4581
+ handler: options.approvalHandler,
4582
+ notifications: this.notificationBus
4583
+ });
4584
+ this.contextManager = options.contextManager ?? new AutoContextManager({
4585
+ services: this.services,
4586
+ pluginHost: this.pluginHost
4587
+ });
4588
+ this.tools = createToolRegistry({
4589
+ includeBuiltinTools: options.includeBuiltinTools !== false,
4590
+ tools: options.tools,
4591
+ pluginTools: this.pluginHost.pluginTools()
4592
+ });
4593
+ }
4594
+ async createSession(options = {}) {
4595
+ const messages = options.messages ? [...options.messages] : [];
4596
+ if (options.systemPrompt)
4597
+ messages.unshift(this.messageFactory.createSystemMessage(options.systemPrompt));
4598
+ return new Session({
4599
+ id: options.sessionId ?? createId("session"),
4600
+ model: this.options.model,
4601
+ modelRef: this.options.model.model,
4602
+ tools: this.tools,
4603
+ stateStore: this.options.stateStore,
4604
+ maxIterations: this.options.maxIterations,
4605
+ cwd: options.cwd ?? this.options.cwd,
4606
+ metadata: options.metadata ?? this.options.metadata,
4607
+ reasoning: this.options.reasoning,
4608
+ compactionOptions: this.options.compaction,
4609
+ messageQueueConfig: options.messageQueueConfig,
4610
+ messages,
4611
+ pluginHost: this.pluginHost,
4612
+ contextManager: this.contextManager,
4613
+ services: this.services,
4614
+ approvalManager: this.approvalManager,
4615
+ notificationBus: this.notificationBus,
4616
+ compactionService: this.compactionService,
4617
+ pluginStateService: this.pluginStateService
4618
+ });
4619
+ }
4620
+ async restoreSession(sessionId) {
4621
+ if (!this.options.stateStore)
4622
+ return null;
4623
+ const snapshot = await this.options.stateStore.load(sessionId);
4624
+ if (!snapshot)
4625
+ return null;
4626
+ return this.sessionFromSnapshot(snapshot);
4627
+ }
4628
+ sessionFromSnapshot(snapshot) {
4629
+ return new Session({
4630
+ id: snapshot.sessionId,
4631
+ model: this.options.model,
4632
+ modelRef: snapshot.model ?? this.options.model.model,
4633
+ tools: this.tools,
4634
+ stateStore: this.options.stateStore,
4635
+ maxIterations: this.options.maxIterations,
4636
+ cwd: snapshot.cwd ?? this.options.cwd,
4637
+ metadata: snapshot.metadata ?? this.options.metadata,
4638
+ reasoning: this.options.reasoning,
4639
+ messages: snapshot.messages,
4640
+ usage: snapshot.usage,
4641
+ compaction: snapshot.compaction,
4642
+ pluginState: snapshot.pluginState,
4643
+ messageQueue: snapshot.messageQueue,
4644
+ compactionOptions: this.options.compaction,
4645
+ createdAt: snapshot.createdAt,
4646
+ updatedAt: snapshot.updatedAt,
4647
+ pluginHost: this.pluginHost,
4648
+ contextManager: this.contextManager,
4649
+ services: this.services,
4650
+ approvalManager: this.approvalManager,
4651
+ notificationBus: this.notificationBus,
4652
+ compactionService: this.compactionService,
4653
+ pluginStateService: this.pluginStateService
4654
+ });
4655
+ }
4656
+ }
4657
+ function createAgent(options) {
4658
+ return new Agent(options);
4659
+ }
4660
+ function createServices(options, tracker, compaction, pluginState) {
4661
+ const exec = new NodeExecGateway({ cwd: options.cwd, tracker });
4662
+ return {
4663
+ fileSystem: new NodeFileSystemGateway({ cwd: options.cwd, tracker }),
4664
+ exec,
4665
+ git: new DefaultGitGateway({ exec, cwd: options.cwd }),
4666
+ network: new DefaultNetworkGateway,
4667
+ model: new DefaultModelGateway(options.model),
4668
+ compaction,
4669
+ pluginState
4670
+ };
4671
+ }
4672
+ function validateCompactionOwner(options) {
4673
+ const ownerPluginId = options.compaction?.ownerPluginId;
4674
+ if (!ownerPluginId)
4675
+ return;
4676
+ const loadedPluginIds = new Set((options.plugins ?? []).map((plugin) => plugin.manifest.id));
4677
+ if (!loadedPluginIds.has(ownerPluginId))
4678
+ throw new Error(`Compaction owner plugin "${ownerPluginId}" is not loaded`);
4679
+ }
4680
+ function createToolRegistry(input) {
4681
+ const registry = input.tools instanceof ToolRegistry ? cloneRegistry(input.tools) : new ToolRegistry;
4682
+ if (input.includeBuiltinTools) {
4683
+ safeRegister(registry, new ReadTool);
4684
+ safeRegister(registry, new WriteTool);
4685
+ safeRegister(registry, new EditTool);
4686
+ safeRegister(registry, new ExecTool);
4687
+ }
4688
+ for (const tool of Array.isArray(input.tools) ? input.tools : [])
4689
+ safeRegister(registry, tool);
4690
+ for (const tool of input.pluginTools)
4691
+ safeRegister(registry, tool);
4692
+ return registry;
4693
+ }
4694
+ function cloneRegistry(source) {
4695
+ const registry = new ToolRegistry;
4696
+ for (const tool of source.list())
4697
+ registry.register(tool);
4698
+ return registry;
4699
+ }
4700
+ function safeRegister(registry, tool) {
4701
+ if (!registry.get(tool.definition.name))
4702
+ registry.register(tool);
4703
+ }
4704
+ // src/persistence/file-state-store.ts
4705
+ import { mkdir as mkdir2, readFile as readFile2, readdir as readdir2, rm, writeFile as writeFile2 } from "node:fs/promises";
4706
+ import path3 from "node:path";
4707
+ class FileStateStore {
4708
+ directory;
4709
+ constructor(options) {
4710
+ this.directory = path3.resolve(options.directory);
4711
+ }
4712
+ async save(snapshot) {
4713
+ const validated = sessionSnapshotCodec.decode(snapshot);
4714
+ await mkdir2(this.directory, { recursive: true });
4715
+ await writeFile2(this.filePath(validated.sessionId), JSON.stringify(validated, null, 2), "utf8");
4716
+ }
4717
+ async load(sessionId) {
4718
+ try {
4719
+ const raw = await readFile2(this.filePath(sessionId), "utf8");
4720
+ return sessionSnapshotCodec.decode(JSON.parse(raw));
4721
+ } catch (error) {
4722
+ if (error.code === "ENOENT")
4723
+ return null;
4724
+ throw error;
4725
+ }
4726
+ }
4727
+ async delete(sessionId) {
4728
+ await rm(this.filePath(sessionId), { force: true });
4729
+ }
4730
+ async list() {
4731
+ await mkdir2(this.directory, { recursive: true });
4732
+ const entries = (await readdir2(this.directory)).sort();
4733
+ const snapshots = [];
4734
+ for (const entry of entries) {
4735
+ if (!entry.endsWith(".json"))
4736
+ continue;
4737
+ const raw = await readFile2(path3.join(this.directory, entry), "utf8");
4738
+ snapshots.push(sessionSnapshotCodec.decode(JSON.parse(raw)));
4739
+ }
4740
+ return snapshots;
4741
+ }
4742
+ filePath(sessionId) {
4743
+ return path3.join(this.directory, `${encodeURIComponent(sessionId)}.json`);
4744
+ }
4745
+ }
4746
+ // src/persistence/in-memory-state-store.ts
4747
+ class InMemoryStateStore {
4748
+ snapshots = new Map;
4749
+ async save(snapshot) {
4750
+ const validated = sessionSnapshotCodec.decode(snapshot);
4751
+ this.snapshots.set(validated.sessionId, validated);
4752
+ }
4753
+ async load(sessionId) {
4754
+ const snapshot = this.snapshots.get(sessionId);
4755
+ return snapshot ? sessionSnapshotCodec.decode(snapshot) : null;
4756
+ }
4757
+ async delete(sessionId) {
4758
+ this.snapshots.delete(sessionId);
4759
+ }
4760
+ async list() {
4761
+ return [...this.snapshots.values()].map((snapshot) => sessionSnapshotCodec.decode(snapshot));
4762
+ }
4763
+ }
4764
+ // src/agent-core/create-model.ts
4765
+ function createModel(adapter) {
4766
+ return {
4767
+ adapter,
4768
+ model: adapter.defaultModel,
4769
+ stream(request) {
4770
+ return adapter.stream({
4771
+ ...request,
4772
+ model: request.model ?? adapter.defaultModel
4773
+ });
4774
+ }
4775
+ };
4776
+ }
4777
+ export {
4778
+ startToolCall,
4779
+ normalizeToolSchema,
4780
+ normalizeToolResult,
4781
+ normalizePermissions,
4782
+ normalizeContent,
4783
+ fullPermissions,
4784
+ finalizeToolCall,
4785
+ createZenMuxAdapter,
4786
+ createXaiResponsesAdapter,
4787
+ createXaiAdapter,
4788
+ createOpenAIResponsesAdapter,
4789
+ createOpenAIAdapter,
4790
+ createMoonshotAIAdapter,
4791
+ createModel,
4792
+ createGeminiAdapter,
4793
+ createDeepSeekAdapter,
4794
+ createAnthropicAdapter,
4795
+ createAihubmixResponsesAdapter,
4796
+ createAihubmixAdapter,
4797
+ createAgent,
4798
+ appendToolCallArgsDelta,
4799
+ WriteTool,
4800
+ ToolRegistry,
4801
+ SessionExecutionError,
4802
+ Session,
4803
+ ReadTool,
4804
+ PermissionGateway,
4805
+ PermissionDeniedError,
4806
+ NodeFileSystemGateway,
4807
+ NodeExecGateway,
4808
+ InMemoryStateStore,
4809
+ FileStateStore,
4810
+ ExecTool,
4811
+ EditTool,
4812
+ DefaultNetworkGateway,
4813
+ DefaultModelGateway,
4814
+ DefaultGitGateway,
4815
+ DefaultCompactionService,
4816
+ BaseTool,
4817
+ AutoContextManager,
4818
+ Agent,
4819
+ ActivityTracker
4820
+ };