@sema-agent/core 5.10.0 → 5.12.0
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/CHANGELOG.md +51 -0
- package/dist/agents/subagent.d.ts +1 -1
- package/dist/agents/subagent.js +6 -2
- package/dist/brain/anthropic.js +1 -1
- package/dist/brain/openai.js +1 -1
- package/dist/core/auto-compaction.d.ts +12 -1
- package/dist/core/auto-compaction.js +3 -1
- package/dist/core/background-agent-store.d.ts +2 -1
- package/dist/core/background-agent-store.js +1 -0
- package/dist/core/checkpoint-store.d.ts +2 -0
- package/dist/core/checkpoint-store.js +1 -0
- package/dist/core/exec-gate.js +12 -1
- package/dist/core/runner/assemble-result.js +9 -0
- package/dist/core/runner/compaction-call-options.d.ts +13 -1
- package/dist/core/runner/compaction-call-options.js +85 -0
- package/dist/core/runner/prepare-task.d.ts +6 -0
- package/dist/core/runner/prepare-task.js +118 -36
- package/dist/core/runner/runtask.js +71 -21
- package/dist/core/runner/tool-disclosure.d.ts +1 -0
- package/dist/core/runner/tool-disclosure.js +24 -9
- package/dist/core/runner/turn-attachments.d.ts +2 -0
- package/dist/core/runner/turn-attachments.js +17 -6
- package/dist/core/task-registry-agent.d.ts +3 -0
- package/dist/core/task-registry-agent.js +9 -2
- package/dist/core/task-registry-shared.d.ts +1 -0
- package/dist/core/task-registry.d.ts +2 -0
- package/dist/core/trace.d.ts +1 -0
- package/dist/core/types.d.ts +9 -1
- package/dist/engine/compaction/compaction.d.ts +11 -2
- package/dist/engine/compaction/compaction.js +87 -9
- package/dist/index.d.ts +1 -1
- package/dist/prompt-assembly/event-registry.js +1 -1
- package/dist/prompts/default.d.ts +1 -0
- package/dist/prompts/default.js +3 -0
- package/dist/tools/fs/fs-bash.js +4 -1
- package/dist/tools/fs/index.d.ts +1 -0
- package/dist/tools/fs/index.js +7 -4
- package/dist/tools/web.d.ts +21 -1
- package/dist/tools/web.js +126 -10
- package/package.json +1 -1
|
@@ -168,7 +168,11 @@ export function collectDueAttachments(state, inp) {
|
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
if (inp.config.toolsDelta) {
|
|
171
|
-
const body = renderToolsDelta({
|
|
171
|
+
const body = renderToolsDelta({
|
|
172
|
+
...(inp.newTools !== undefined ? { added: inp.newTools } : {}),
|
|
173
|
+
...(inp.newToolsStaticFace === true ? { staticFace: true } : {}),
|
|
174
|
+
...(inp.mcpToolsDelta ?? {}),
|
|
175
|
+
});
|
|
172
176
|
if (body !== undefined)
|
|
173
177
|
(out ??= []).push({ source: "tools_delta", body });
|
|
174
178
|
}
|
|
@@ -363,7 +367,9 @@ function renderBackgroundTasks(tasks) {
|
|
|
363
367
|
? "stopped"
|
|
364
368
|
: t.status === "running"
|
|
365
369
|
? "still running in background"
|
|
366
|
-
: t.status
|
|
370
|
+
: t.status === "parked"
|
|
371
|
+
? "parked awaiting an out-of-band approval — do NOT re-issue the gated call"
|
|
372
|
+
: t.status;
|
|
367
373
|
return `- [${t.id}] Task "${(t.description ?? "background task").slice(0, PROJECTION_CONTENT_MAX)}" ${phrase}`;
|
|
368
374
|
});
|
|
369
375
|
return ("Context was compacted. Background tasks from before the compaction (check output with TaskOutput, " +
|
|
@@ -386,15 +392,20 @@ export function renderToolsDelta(input) {
|
|
|
386
392
|
const blocks = [];
|
|
387
393
|
const added = input.added ?? [];
|
|
388
394
|
if (added.length > 0) {
|
|
389
|
-
blocks.push(
|
|
390
|
-
"directly
|
|
395
|
+
blocks.push((input.staticFace === true
|
|
396
|
+
? "The following deferred tools are now active — call them directly. Their parameter schemas were " +
|
|
397
|
+
"provided in the ToolSearch result (the tools list itself keeps compact placeholder entries):\n"
|
|
398
|
+
: "The following deferred tools are now available. Their full schemas are loaded — call them " +
|
|
399
|
+
"directly like any other tool:\n") +
|
|
391
400
|
added.map((n) => `- ${n}`).join("\n"));
|
|
392
401
|
}
|
|
393
402
|
const readded = input.readded ?? [];
|
|
394
403
|
if (readded.length > 0) {
|
|
395
404
|
blocks.push(`${readded.length} deferred tool${readded.length === 1 ? " is" : "s are"} available again (MCP server reconnected — ` +
|
|
396
|
-
`names announced earlier in this conversation): ${groupByMcpServer(readded)}.
|
|
397
|
-
|
|
405
|
+
`names announced earlier in this conversation): ${groupByMcpServer(readded)}. ` +
|
|
406
|
+
(input.staticFace === true
|
|
407
|
+
? `The tools list keeps compact placeholder entries — re-run ToolSearch ("select:<name>") if you need their current parameter schemas.`
|
|
408
|
+
: `Their schemas are loaded again — call them directly.`));
|
|
398
409
|
}
|
|
399
410
|
const removed = input.removed ?? [];
|
|
400
411
|
if (removed.length > 0) {
|
|
@@ -69,6 +69,7 @@ export declare function settleBackgroundAgentLane(core: DurableAgentCore, id: st
|
|
|
69
69
|
errorCode?: string;
|
|
70
70
|
retryable?: boolean;
|
|
71
71
|
errorKind?: string;
|
|
72
|
+
retryAfterMs?: number;
|
|
72
73
|
stoppedBy?: StopSource;
|
|
73
74
|
seq?: number;
|
|
74
75
|
cycle?: number;
|
|
@@ -105,6 +106,7 @@ export declare function settleRevivedAgentLane(core: DurableAgentCore, id: strin
|
|
|
105
106
|
errorCode?: string;
|
|
106
107
|
retryable?: boolean;
|
|
107
108
|
errorKind?: string;
|
|
109
|
+
retryAfterMs?: number;
|
|
108
110
|
}): "completed" | "failed" | "killed" | undefined;
|
|
109
111
|
export declare function noteBackgroundAgentActivityLane(core: DurableAgentCore, id: string, now?: number): void;
|
|
110
112
|
export declare function reapStaleSessionBackgroundAgentsLane(core: DurableAgentCore, staleMs: number, now?: number, onTerminal?: (note: () => void) => void): number;
|
|
@@ -137,6 +139,7 @@ export interface AgentPollDetailsInput {
|
|
|
137
139
|
error?: string;
|
|
138
140
|
errorCode?: string;
|
|
139
141
|
errorRetryable?: boolean;
|
|
142
|
+
errorRetryAfterMs?: number;
|
|
140
143
|
resultIsPartial?: boolean;
|
|
141
144
|
completionId?: string;
|
|
142
145
|
}
|
|
@@ -713,6 +713,8 @@ export function settleBackgroundAgentLane(core, id, outcome) {
|
|
|
713
713
|
handle.errorRetryable = outcome.retryable;
|
|
714
714
|
if (outcome.errorKind !== undefined)
|
|
715
715
|
handle.errorKind = outcome.errorKind;
|
|
716
|
+
if (outcome.retryAfterMs !== undefined)
|
|
717
|
+
handle.errorRetryAfterMs = outcome.retryAfterMs;
|
|
716
718
|
}
|
|
717
719
|
handle.updatedAt = Date.now();
|
|
718
720
|
if (outcome.seq !== undefined)
|
|
@@ -731,6 +733,7 @@ export function settleBackgroundAgentLane(core, id, outcome) {
|
|
|
731
733
|
...(handle.errorCode !== undefined ? { errorCode: handle.errorCode } : {}),
|
|
732
734
|
...(handle.errorRetryable !== undefined ? { errorRetryable: handle.errorRetryable } : {}),
|
|
733
735
|
...(handle.errorKind !== undefined ? { errorKind: handle.errorKind } : {}),
|
|
736
|
+
...(handle.errorRetryAfterMs !== undefined ? { errorRetryAfterMs: handle.errorRetryAfterMs } : {}),
|
|
734
737
|
}, ["parkedCheckpointToken", "parkClaimId", "parkedAt"]);
|
|
735
738
|
return outcome.status;
|
|
736
739
|
}
|
|
@@ -857,6 +860,7 @@ export function reviveBackgroundAgentLane(core, id, access, abort) {
|
|
|
857
860
|
handle.errorCode = undefined;
|
|
858
861
|
handle.errorRetryable = undefined;
|
|
859
862
|
handle.errorKind = undefined;
|
|
863
|
+
handle.errorRetryAfterMs = undefined;
|
|
860
864
|
handle.resultIsPartial = undefined;
|
|
861
865
|
handle.stopSource = undefined;
|
|
862
866
|
handle.completionId = undefined;
|
|
@@ -1052,6 +1056,7 @@ export function buildAgentPollDetails(input) {
|
|
|
1052
1056
|
...(failed && input.error !== undefined ? { error: delimitUntrusted("agent error", boundedRedactedSummary(input.error, 300)) } : {}),
|
|
1053
1057
|
...(failed && input.errorCode !== undefined ? { errorCode: input.errorCode } : {}),
|
|
1054
1058
|
...(failed && input.errorRetryable !== undefined ? { retryable: input.errorRetryable } : {}),
|
|
1059
|
+
...(failed && input.errorRetryAfterMs !== undefined ? { retryAfterMs: input.errorRetryAfterMs } : {}),
|
|
1055
1060
|
...(input.resultIsPartial === true ? { partial_result: true } : {}),
|
|
1056
1061
|
...(input.completionId !== undefined ? { completionId: input.completionId } : {}),
|
|
1057
1062
|
};
|
|
@@ -1070,7 +1075,7 @@ The agent is durably suspended, waiting for an approval decision. It resumes whe
|
|
|
1070
1075
|
};
|
|
1071
1076
|
}
|
|
1072
1077
|
const kindClause = row.status === "failed" && row.errorKind !== undefined && row.errorRetryable !== undefined
|
|
1073
|
-
? ` (error_kind: ${row.errorKind}, retryable: ${row.errorRetryable})`
|
|
1078
|
+
? ` (error_kind: ${row.errorKind}, retryable: ${row.errorRetryable}${row.errorRetryAfterMs !== undefined ? `, retry_after_ms: ${row.errorRetryAfterMs}` : ""})`
|
|
1074
1079
|
: "";
|
|
1075
1080
|
const body = `status: ${row.status}
|
|
1076
1081
|
${row.error ? `error: ${row.error}${kindClause}
|
|
@@ -1087,6 +1092,7 @@ ${clipTaskOutput(row.finalOutputFull ?? row.finalOutput)}` : "(no result text)"}
|
|
|
1087
1092
|
...(row.error !== undefined ? { error: row.error } : {}),
|
|
1088
1093
|
...(row.errorCode !== undefined ? { errorCode: row.errorCode } : {}),
|
|
1089
1094
|
...(row.errorRetryable !== undefined ? { errorRetryable: row.errorRetryable } : {}),
|
|
1095
|
+
...(row.errorRetryAfterMs !== undefined ? { errorRetryAfterMs: row.errorRetryAfterMs } : {}),
|
|
1090
1096
|
...(row.resultIsPartial === true ? { resultIsPartial: true } : {}),
|
|
1091
1097
|
...(row.completionId !== undefined ? { completionId: row.completionId } : {}),
|
|
1092
1098
|
}),
|
|
@@ -1126,7 +1132,7 @@ The agent is durably suspended, waiting for an approval decision. It resumes whe
|
|
|
1126
1132
|
const fullResult = handle.result ? (handle.resultFull ?? handle.result) : undefined;
|
|
1127
1133
|
const resultText = fullResult !== undefined ? await spillClippedAgentResult(handle, fullResult, clipTaskOutput(fullResult, handle.outputFile), store, sessionId) : undefined;
|
|
1128
1134
|
const kindClause = handle.status === "failed" && handle.errorKind !== undefined && handle.errorRetryable !== undefined
|
|
1129
|
-
? ` (error_kind: ${handle.errorKind}, retryable: ${handle.errorRetryable})`
|
|
1135
|
+
? ` (error_kind: ${handle.errorKind}, retryable: ${handle.errorRetryable}${handle.errorRetryAfterMs !== undefined ? `, retry_after_ms: ${handle.errorRetryAfterMs}` : ""})`
|
|
1130
1136
|
: "";
|
|
1131
1137
|
const body = running
|
|
1132
1138
|
? oneShot === true
|
|
@@ -1149,6 +1155,7 @@ ${resultText}` : "(no result text)"}`;
|
|
|
1149
1155
|
...(handle.error !== undefined ? { error: handle.error } : {}),
|
|
1150
1156
|
...(handle.errorCode !== undefined ? { errorCode: handle.errorCode } : {}),
|
|
1151
1157
|
...(handle.errorRetryable !== undefined ? { errorRetryable: handle.errorRetryable } : {}),
|
|
1158
|
+
...(handle.errorRetryAfterMs !== undefined ? { errorRetryAfterMs: handle.errorRetryAfterMs } : {}),
|
|
1152
1159
|
...(handle.resultIsPartial === true ? { resultIsPartial: true } : {}),
|
|
1153
1160
|
...(handle.completionId !== undefined ? { completionId: handle.completionId } : {}),
|
|
1154
1161
|
}),
|
|
@@ -139,6 +139,7 @@ export interface BackgroundAgentTaskHandle extends SemaTaskHandle {
|
|
|
139
139
|
errorCode?: string;
|
|
140
140
|
errorRetryable?: boolean;
|
|
141
141
|
errorKind?: string;
|
|
142
|
+
errorRetryAfterMs?: number;
|
|
142
143
|
resultIsPartial?: boolean;
|
|
143
144
|
stopSource?: StopSource;
|
|
144
145
|
stoppedBy?: StopSource;
|
|
@@ -141,6 +141,7 @@ export declare class TaskRegistry {
|
|
|
141
141
|
errorCode?: string;
|
|
142
142
|
retryable?: boolean;
|
|
143
143
|
errorKind?: string;
|
|
144
|
+
retryAfterMs?: number;
|
|
144
145
|
stoppedBy?: StopSource;
|
|
145
146
|
seq?: number;
|
|
146
147
|
cycle?: number;
|
|
@@ -180,6 +181,7 @@ export declare class TaskRegistry {
|
|
|
180
181
|
errorCode?: string;
|
|
181
182
|
retryable?: boolean;
|
|
182
183
|
errorKind?: string;
|
|
184
|
+
retryAfterMs?: number;
|
|
183
185
|
}): "completed" | "failed" | "killed" | undefined;
|
|
184
186
|
unmarkRetainedContinuation(id: string): void;
|
|
185
187
|
attachAgentNotify(id: string, notify: NonNullable<BackgroundAgentTaskHandle["notify"]>, cycle?: number): void;
|
package/dist/core/trace.d.ts
CHANGED
package/dist/core/types.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ import type { AgentTool, ThinkingLevel } from "../internal/harness.js";
|
|
|
3
3
|
import type { CompleteSimpleFn, DocumentContent, ImageContent, Model, ResilienceOptions, StreamFn, TextContent } from "../internal/llm.js";
|
|
4
4
|
import type { TaskNotificationPayload } from "./task-notification.js";
|
|
5
5
|
export type ModelRef = string | Model;
|
|
6
|
+
export interface StaleToolResultOffloadOptions {
|
|
7
|
+
keepRecentPerTool?: number;
|
|
8
|
+
minSavingsChars?: number;
|
|
9
|
+
}
|
|
6
10
|
export type ModelRole = "default" | "summarize" | "subagent" | "team" | "synthesize" | "advisor" | "verifier" | "classifier";
|
|
7
11
|
export type RoleSpec = ModelRef | {
|
|
8
12
|
model?: ModelRef;
|
|
@@ -109,6 +113,7 @@ export interface ToolExecuteContext {
|
|
|
109
113
|
alwaysLoadTools?: readonly string[];
|
|
110
114
|
promptProfile?: "simple" | "classic";
|
|
111
115
|
additionalDirectories?: readonly string[];
|
|
116
|
+
additionalReadDirectories?: readonly string[];
|
|
112
117
|
envFacts?: TaskSpec["envFacts"];
|
|
113
118
|
getApiKeyAndHeaders?: TaskSpec["getApiKeyAndHeaders"];
|
|
114
119
|
activeSkillScope?: () => readonly unknown[];
|
|
@@ -297,6 +302,7 @@ export interface TaskSpec {
|
|
|
297
302
|
tools?: ToolSpec[];
|
|
298
303
|
excludeTools?: string[];
|
|
299
304
|
deferTools?: string[];
|
|
305
|
+
toolMaterializeStrategy?: "swap" | "static";
|
|
300
306
|
alwaysLoadTools?: string[];
|
|
301
307
|
deferSelfResolve?: boolean;
|
|
302
308
|
promptProfile?: "simple" | "classic";
|
|
@@ -325,6 +331,7 @@ export interface TaskSpec {
|
|
|
325
331
|
checkpointStore?: import("./checkpoint-store.js").CheckpointStore | null;
|
|
326
332
|
handsReadOnly?: boolean;
|
|
327
333
|
additionalDirectories?: string[];
|
|
334
|
+
additionalReadDirectories?: string[];
|
|
328
335
|
enablePlanMode?: boolean;
|
|
329
336
|
interactiveTools?: boolean;
|
|
330
337
|
enableFork?: boolean;
|
|
@@ -368,6 +375,7 @@ export interface TaskSpec {
|
|
|
368
375
|
maxFiles?: number;
|
|
369
376
|
maxCharsPerFile?: number;
|
|
370
377
|
};
|
|
378
|
+
staleToolResultOffload?: StaleToolResultOffloadOptions;
|
|
371
379
|
clampTolerance?: number;
|
|
372
380
|
};
|
|
373
381
|
attachments?: {
|
|
@@ -379,7 +387,7 @@ export interface TaskSpec {
|
|
|
379
387
|
};
|
|
380
388
|
planModeReminder?: true;
|
|
381
389
|
budgetUsd?: true;
|
|
382
|
-
backgroundTasks?:
|
|
390
|
+
backgroundTasks?: boolean;
|
|
383
391
|
toolsDelta?: true;
|
|
384
392
|
agentListing?: boolean;
|
|
385
393
|
skillsListing?: boolean;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Model, StreamFn, Usage } from "../llm/index.js";
|
|
1
|
+
import type { Context, Message, Model, StreamFn, Tool, Usage } from "../llm/index.js";
|
|
2
2
|
import { type AgentCoreCompletionRuntimeDeps } from "../loop/runtime-deps.js";
|
|
3
3
|
import type { AgentMessage, ThinkingLevel } from "../loop/types.js";
|
|
4
4
|
import { CompactionError, type Result, type SessionTreeEntry } from "../harness/types.js";
|
|
@@ -47,6 +47,15 @@ export interface CutPointResult {
|
|
|
47
47
|
}
|
|
48
48
|
export declare function findCutPoint(entries: SessionTreeEntry[], startIndex: number, endIndex: number, keepRecentTokens: number, charsPerToken?: number): CutPointResult;
|
|
49
49
|
export declare const SUMMARIZATION_SYSTEM_PROMPT = "You are a context summarization assistant. Your task is to read a conversation between a user and an AI coding assistant, then produce a structured summary following the exact format specified.\n\nDo NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.";
|
|
50
|
+
export interface CompactionForkContext {
|
|
51
|
+
systemPrompt?: string;
|
|
52
|
+
systemBlocks?: Context["systemBlocks"];
|
|
53
|
+
messages: Message[];
|
|
54
|
+
tools?: Tool[];
|
|
55
|
+
modelId?: string;
|
|
56
|
+
}
|
|
57
|
+
export declare function extractForkSummaryEnvelope(text: string): string | undefined;
|
|
58
|
+
export declare function forkSummarizationInstruction(customInstructions?: string): string;
|
|
50
59
|
export declare function summaryOutputBudgetTokens(model: Model, settings: CompactionSettings): number;
|
|
51
60
|
export interface SummarizationInputTruncation {
|
|
52
61
|
label: "history" | "turn_prefix";
|
|
@@ -77,5 +86,5 @@ export interface CompactionPreparation {
|
|
|
77
86
|
}
|
|
78
87
|
export declare function prepareCompaction(pathEntries: SessionTreeEntry[], settings: CompactionSettings, charsPerToken?: number, windowTokens?: number): Result<CompactionPreparation | undefined, CompactionError>;
|
|
79
88
|
export { computeFileLists, serializeConversation } from "./utils.js";
|
|
80
|
-
export declare function compact(preparation: CompactionPreparation, model: Model, apiKey: string | undefined, headers?: Record<string, string>, customInstructions?: string, signal?: AbortSignal, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, runtime?: AgentCoreCompletionRuntimeDeps, charsPerToken?: number, onInputTruncated?: (info: SummarizationInputTruncation) => void, onPtlRetry?: () => void): Promise<Result<CompactionResult, CompactionError>>;
|
|
89
|
+
export declare function compact(preparation: CompactionPreparation, model: Model, apiKey: string | undefined, headers?: Record<string, string>, customInstructions?: string, signal?: AbortSignal, thinkingLevel?: ThinkingLevel, streamFn?: StreamFn, runtime?: AgentCoreCompletionRuntimeDeps, charsPerToken?: number, onInputTruncated?: (info: SummarizationInputTruncation) => void, onPtlRetry?: () => void, forkContext?: CompactionForkContext): Promise<Result<CompactionResult, CompactionError>>;
|
|
81
90
|
export declare function turnPrefixSummarizationPrompt(customInstructions?: string): string;
|
|
@@ -62,7 +62,7 @@ export const DEFAULT_CLAMP_TOLERANCE = 0.1;
|
|
|
62
62
|
export const DEFAULT_COMPACTION_SETTINGS = {
|
|
63
63
|
enabled: true,
|
|
64
64
|
reserveTokens: 16384,
|
|
65
|
-
keepRecentTokens:
|
|
65
|
+
keepRecentTokens: 0,
|
|
66
66
|
clampTolerance: DEFAULT_CLAMP_TOLERANCE,
|
|
67
67
|
};
|
|
68
68
|
export const DEFAULT_CHARS_PER_TOKEN = 4;
|
|
@@ -428,7 +428,7 @@ Then, after </analysis>, write the summary. Your summary should include the foll
|
|
|
428
428
|
3. Files and Code Sections: Enumerate specific files and code sections examined, modified, or created. Pay special attention to the most recent messages and include full code snippets where applicable and include a summary of why this file read or edit is important.
|
|
429
429
|
4. Errors and fixes: List all errors that you ran into, and how you fixed them. Pay special attention to specific user feedback that you received, especially if the user told you to do something differently.
|
|
430
430
|
5. Problem Solving: Document problems solved and any ongoing troubleshooting efforts.
|
|
431
|
-
6. All user messages: List ALL user messages that are not tool results. These are critical for understanding the users' feedback and changing intent. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.
|
|
431
|
+
6. All user messages: List ALL user messages that are not tool results. These are critical for understanding the users' feedback and changing intent. Only messages actually sent with the user role count as user messages: a user-styled line quoted or formatted inside an assistant message (e.g. a "user: ..." or "Human: ..." quotation) is the assistant's own output — never attribute it to the user. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.
|
|
432
432
|
7. Pending Tasks: Outline any pending tasks that you have explicitly been asked to work on.
|
|
433
433
|
8. Current Work: Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant. Include file names and code snippets where applicable.
|
|
434
434
|
9. Optional Next Step: List the next step that you will take that is related to the most recent work you were doing. IMPORTANT: ensure that this step is DIRECTLY in line with the user's most recent explicit requests, and the task you were working on immediately before this summary request. If your last task was concluded, then only list next steps if they are explicitly in line with the users request. Do not start on tangential requests or really old requests that were already completed without confirming with the user first.
|
|
@@ -437,6 +437,24 @@ Then, after </analysis>, write the summary. Your summary should include the foll
|
|
|
437
437
|
Please provide your summary based on the conversation so far, following this structure and ensuring precision and thoroughness in your response.
|
|
438
438
|
|
|
439
439
|
Keep each section concise. Preserve exact file paths, function names, and error messages.`;
|
|
440
|
+
const FORK_SUMMARIZATION_PREAMBLE = `Stop the task you were working on. Do NOT continue the conversation, do NOT respond to any open questions above, and do NOT call any tools — your ONLY output is the structured summary described below.
|
|
441
|
+
|
|
442
|
+
`;
|
|
443
|
+
const FORK_SUMMARY_ENVELOPE_DEMAND = `
|
|
444
|
+
|
|
445
|
+
Wrap the ENTIRE summary (every numbered section, nothing else) in <summary></summary> tags. Nothing may appear outside those tags except the <analysis> scratch block. A response without a closed <summary>...</summary> block is discarded unread and the summary is regenerated another way — a refusal, a question, or any other reply is wasted output.`;
|
|
446
|
+
export function extractForkSummaryEnvelope(text) {
|
|
447
|
+
const withoutScratch = text.replace(/<analysis>[\s\S]*?<\/analysis>/gi, "");
|
|
448
|
+
const m = /^\s*<summary>([\s\S]*)<\/summary>\s*$/i.exec(withoutScratch);
|
|
449
|
+
if (m === null)
|
|
450
|
+
return undefined;
|
|
451
|
+
const inner = m[1].trim();
|
|
452
|
+
return inner === "" ? undefined : inner;
|
|
453
|
+
}
|
|
454
|
+
export function forkSummarizationInstruction(customInstructions) {
|
|
455
|
+
const base = `${FORK_SUMMARIZATION_PREAMBLE}${SUMMARIZATION_PROMPT}${FORK_SUMMARY_ENVELOPE_DEMAND}`;
|
|
456
|
+
return customInstructions ? `${base}\n\nAdditional Instructions:\n${customInstructions}` : base;
|
|
457
|
+
}
|
|
440
458
|
const UPDATE_SUMMARIZATION_PROMPT = `The messages above are NEW conversation messages to incorporate into the existing summary provided in <previous-summary> tags.
|
|
441
459
|
|
|
442
460
|
Update the existing structured summary with new information. RULES:
|
|
@@ -455,7 +473,7 @@ First, inside an <analysis>...</analysis> block, note what is new since the prev
|
|
|
455
473
|
3. Files and Code Sections: [Preserve entries still relevant; add newly examined, modified, or created files with full code snippets where applicable]
|
|
456
474
|
4. Errors and fixes: [Preserve previous errors and fixes and add new ones; keep any user correction or "change of approach" feedback verbatim.]
|
|
457
475
|
5. Problem Solving: [Update problems solved and any ongoing troubleshooting efforts]
|
|
458
|
-
6. All user messages: [Preserve previously-recorded user messages VERBATIM and append any new ones that are not tool results, in order. To bound growth across repeated compactions, keep roughly the most recent 20 messages verbatim; older ones beyond that may be condensed to a single line each — but NEVER drop or paraphrase a user correction or change of direction. The exact words of recent messages are the strongest anti-drift signal. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.]
|
|
476
|
+
6. All user messages: [Preserve previously-recorded user messages VERBATIM and append any new ones that are not tool results, in order. Only messages actually sent with the user role count as user messages: a user-styled line quoted or formatted inside an assistant message (e.g. a "user: ..." or "Human: ..." quotation) is the assistant's own output — never attribute it to the user. To bound growth across repeated compactions, keep roughly the most recent 20 messages verbatim; older ones beyond that may be condensed to a single line each — but NEVER drop or paraphrase a user correction or change of direction. The exact words of recent messages are the strongest anti-drift signal. Preserve any security-relevant instructions or constraints verbatim so they remain in effect after compaction.]
|
|
459
477
|
7. Pending Tasks: [Update based on progress — remove completed tasks, add newly requested ones]
|
|
460
478
|
8. Current Work: [Describe in detail precisely what was being worked on immediately before this summary request, paying special attention to the most recent messages from both user and assistant]
|
|
461
479
|
9. Optional Next Step: [Update based on current state. IMPORTANT: ensure that this step is DIRECTLY in line with the user's most recent explicit requests, and the task you were working on immediately before this summary request — include a direct verbatim quote of that request. Do not start on tangential requests or really old requests that were already completed.]
|
|
@@ -678,6 +696,15 @@ async function summarizeWithPtlRetry(req) {
|
|
|
678
696
|
disclose(beforeChars - Math.max(remainingChars, 0), Math.max(remainingChars, 0));
|
|
679
697
|
}
|
|
680
698
|
}
|
|
699
|
+
function markEmptySummaryClass(e) {
|
|
700
|
+
const carrier = e;
|
|
701
|
+
carrier.semaSummaryEmptyClass = true;
|
|
702
|
+
return e;
|
|
703
|
+
}
|
|
704
|
+
function isEmptySummaryClass(e) {
|
|
705
|
+
const carrier = e;
|
|
706
|
+
return carrier.semaSummaryEmptyClass === true;
|
|
707
|
+
}
|
|
681
708
|
function stripAnalysisScratch(text, lengthTruncated) {
|
|
682
709
|
let out = text.replace(/<analysis>[\s\S]*?<\/analysis>\s*/gi, "");
|
|
683
710
|
if (lengthTruncated) {
|
|
@@ -705,8 +732,8 @@ async function summarizeWithLengthRecovery(label, model, context, baseMaxTokens,
|
|
|
705
732
|
maxTokens = Math.min(cap, Math.max(maxTokens * 2, SUMMARY_REASONING_FLOOR));
|
|
706
733
|
continue;
|
|
707
734
|
}
|
|
708
|
-
return err(new CompactionError("summarization_failed", `${label} produced an empty summary (stopReason=error, max_tokens exhausted by reasoning ` +
|
|
709
|
-
`after ${attempt + 1} attempt(s): ${response.errorMessage || "no detail"})`));
|
|
735
|
+
return err(markEmptySummaryClass(new CompactionError("summarization_failed", `${label} produced an empty summary (stopReason=error, max_tokens exhausted by reasoning ` +
|
|
736
|
+
`after ${attempt + 1} attempt(s): ${response.errorMessage || "no detail"})`)));
|
|
710
737
|
}
|
|
711
738
|
return err(new CompactionError("summarization_failed", `${label} failed: ${response.errorMessage || "Unknown error"}`));
|
|
712
739
|
}
|
|
@@ -723,10 +750,43 @@ async function summarizeWithLengthRecovery(label, model, context, baseMaxTokens,
|
|
|
723
750
|
maxTokens = Math.min(cap, Math.max(maxTokens * 2, SUMMARY_REASONING_FLOOR));
|
|
724
751
|
continue;
|
|
725
752
|
}
|
|
726
|
-
return err(new CompactionError("summarization_failed", `${label} produced an empty summary (stopReason=${response.stopReason}` +
|
|
727
|
-
`${lengthTruncated ? ", the output was analysis scratch cut at max_tokens" : ""})`));
|
|
753
|
+
return err(markEmptySummaryClass(new CompactionError("summarization_failed", `${label} produced an empty summary (stopReason=${response.stopReason}` +
|
|
754
|
+
`${lengthTruncated ? ", the output was analysis scratch cut at max_tokens" : ""})`)));
|
|
728
755
|
}
|
|
729
756
|
}
|
|
757
|
+
async function forkSummarize(fork, model, baseMaxTokens, apiKey, headers, customInstructions, signal, thinkingLevel, streamFn, runtime, charsPerToken) {
|
|
758
|
+
const instruction = forkSummarizationInstruction(customInstructions);
|
|
759
|
+
const context = {
|
|
760
|
+
...(fork.systemPrompt !== undefined ? { systemPrompt: fork.systemPrompt } : {}),
|
|
761
|
+
...(fork.systemBlocks !== undefined ? { systemBlocks: fork.systemBlocks } : {}),
|
|
762
|
+
...(fork.tools !== undefined && fork.tools.length > 0 ? { tools: fork.tools } : {}),
|
|
763
|
+
messages: [
|
|
764
|
+
...fork.messages,
|
|
765
|
+
{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() },
|
|
766
|
+
],
|
|
767
|
+
};
|
|
768
|
+
let result;
|
|
769
|
+
try {
|
|
770
|
+
result = await summarizeWithLengthRecovery("Summarization", model, context, baseMaxTokens, apiKey, headers, signal, thinkingLevel, streamFn, runtime, charsPerToken);
|
|
771
|
+
}
|
|
772
|
+
catch (e) {
|
|
773
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
774
|
+
if (parsePromptTooLong(msg).isPtl)
|
|
775
|
+
return { kind: "fallback", detail: msg };
|
|
776
|
+
throw e;
|
|
777
|
+
}
|
|
778
|
+
if (!result.ok) {
|
|
779
|
+
if (result.error.code === "summarization_failed" && (isEmptySummaryClass(result.error) || parsePromptTooLong(result.error.message).isPtl)) {
|
|
780
|
+
return { kind: "fallback", detail: result.error.message };
|
|
781
|
+
}
|
|
782
|
+
return { kind: "err", error: result.error };
|
|
783
|
+
}
|
|
784
|
+
const enveloped = extractForkSummaryEnvelope(result.value);
|
|
785
|
+
if (enveloped === undefined) {
|
|
786
|
+
return { kind: "fallback", detail: "fork response lacked a closed <summary> envelope (non-conforming output)" };
|
|
787
|
+
}
|
|
788
|
+
return { kind: "ok", summary: enveloped };
|
|
789
|
+
}
|
|
730
790
|
export async function generateSummary(currentMessages, model, summaryBudgetTokens, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, runtime, charsPerToken, onInputTruncated, onPtlRetry) {
|
|
731
791
|
let basePrompt = previousSummary ? UPDATE_SUMMARIZATION_PROMPT : SUMMARIZATION_PROMPT;
|
|
732
792
|
if (customInstructions) {
|
|
@@ -866,7 +926,7 @@ Summarize the prefix to provide context for the retained suffix:
|
|
|
866
926
|
|
|
867
927
|
Be concise. Focus on what's needed to understand the kept suffix.`;
|
|
868
928
|
export { computeFileLists, serializeConversation } from "./utils.js";
|
|
869
|
-
export async function compact(preparation, model, apiKey, headers, customInstructions, signal, thinkingLevel, streamFn, runtime, charsPerToken, onInputTruncated, onPtlRetry) {
|
|
929
|
+
export async function compact(preparation, model, apiKey, headers, customInstructions, signal, thinkingLevel, streamFn, runtime, charsPerToken, onInputTruncated, onPtlRetry, forkContext) {
|
|
870
930
|
const { firstKeptEntryId, messagesToSummarize, turnPrefixMessages, isSplitTurn, tokensBefore, previousSummary, fileOps, invokedSkills, persistedOutputRefs, elidedMessages, settings, } = preparation;
|
|
871
931
|
if (!firstKeptEntryId) {
|
|
872
932
|
return err(new CompactionError("invalid_session", "First kept entry has no UUID - session may need migration"));
|
|
@@ -876,7 +936,25 @@ export async function compact(preparation, model, apiKey, headers, customInstruc
|
|
|
876
936
|
}
|
|
877
937
|
let summary;
|
|
878
938
|
const summaryBudget = summaryOutputBudgetTokens(model, settings);
|
|
879
|
-
if (
|
|
939
|
+
if (forkContext !== undefined && forkContext.messages.length > 0) {
|
|
940
|
+
const forked = await forkSummarize(forkContext, model, Math.floor(0.8 * summaryBudget), apiKey, headers, customInstructions, signal, thinkingLevel, streamFn, runtime, charsPerToken);
|
|
941
|
+
if (forked.kind === "ok") {
|
|
942
|
+
summary = forked.summary;
|
|
943
|
+
}
|
|
944
|
+
else if (forked.kind === "err") {
|
|
945
|
+
return err(forked.error);
|
|
946
|
+
}
|
|
947
|
+
else {
|
|
948
|
+
try {
|
|
949
|
+
onPtlRetry?.();
|
|
950
|
+
}
|
|
951
|
+
catch {
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
if (summary !== undefined) {
|
|
956
|
+
}
|
|
957
|
+
else if (isSplitTurn && turnPrefixMessages.length > 0) {
|
|
880
958
|
const [historyResult, turnPrefixResult] = await Promise.all([
|
|
881
959
|
messagesToSummarize.length > 0
|
|
882
960
|
? generateSummary(messagesToSummarize, model, summaryBudget, apiKey, headers, signal, customInstructions, previousSummary, thinkingLevel, streamFn, runtime, charsPerToken, onInputTruncated, onPtlRetry)
|
package/dist/index.d.ts
CHANGED
|
@@ -206,7 +206,7 @@ export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
|
|
|
206
206
|
export { type BrainTimeoutConfig } from "./brain/timeout.js";
|
|
207
207
|
export { createAssistantMessageEventStream } from "./internal/llm.js";
|
|
208
208
|
export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
|
|
209
|
-
export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
|
|
209
|
+
export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, WorkflowGovernanceBaseline, } from "./core/types.js";
|
|
210
210
|
export { Type } from "typebox";
|
|
211
211
|
export type { TSchema, Static } from "typebox";
|
|
212
212
|
export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
|
|
@@ -7,7 +7,7 @@ export const EVENT_PROMPT_REGISTRY = new Map([
|
|
|
7
7
|
{ kind: "instructions_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", maxBytes: 512, defaultPolicy: "always", rendererRef: "turn-attachments.ts#collectInstructionsChange" },
|
|
8
8
|
{ kind: "workflow_size_guideline_change", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "always", rendererRef: "runtask.ts#workflowSizeGuidelineChangeNotice" },
|
|
9
9
|
{ kind: "budget_usd", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderBudgetUsd" },
|
|
10
|
-
{ kind: "background_tasks", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "
|
|
10
|
+
{ kind: "background_tasks", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "on", rendererRef: "turn-attachments.ts#renderBackgroundTasks" },
|
|
11
11
|
{ kind: "tools_delta", carrier: "message.user-prefix", trust: "external", dedupe: "replace-by-key", defaultPolicy: "off", rendererRef: "turn-attachments.ts#renderToolsDelta" },
|
|
12
12
|
{ kind: "agent_listing", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "on", rendererRef: "turn-attachments.ts#renderAgentListingDelta" },
|
|
13
13
|
{ kind: "skills_listing", carrier: "message.user-prefix", trust: "operator", dedupe: "replace-by-key", defaultPolicy: "on", rendererRef: "turn-attachments.ts#renderSkillsListingDelta" },
|
package/dist/prompts/default.js
CHANGED
|
@@ -237,6 +237,9 @@ export function buildEnvironmentContext(facts) {
|
|
|
237
237
|
if (facts.additionalDirectories && facts.additionalDirectories.length > 0) {
|
|
238
238
|
lines.push(`Additional working directories: ${facts.additionalDirectories.map((d) => inlineUntrusted(d)).join(", ")}`);
|
|
239
239
|
}
|
|
240
|
+
if (facts.additionalReadDirectories && facts.additionalReadDirectories.length > 0) {
|
|
241
|
+
lines.push(`Additional read-only directories: ${facts.additionalReadDirectories.map((d) => inlineUntrusted(d)).join(", ")}`);
|
|
242
|
+
}
|
|
240
243
|
if (facts.isGitRepo !== undefined)
|
|
241
244
|
lines.push(`Is a git repository: ${facts.isGitRepo ? "yes" : "no"}`);
|
|
242
245
|
if (facts.gitBranch)
|
package/dist/tools/fs/fs-bash.js
CHANGED
|
@@ -296,9 +296,12 @@ async function runShell(env, cwd, toolName, command, timeoutSec, caps, signal, c
|
|
|
296
296
|
const captured = (pStdout ? `--- partial stdout ---\n${pStdout}` : "") +
|
|
297
297
|
(pStderr ? `${pStdout ? "\n" : ""}--- partial stderr ---\n${pStderr}` : "");
|
|
298
298
|
const zeroOutput = captured.length === 0;
|
|
299
|
+
const zeroOutputHint = res.error.code === "timeout" && timeout >= 60
|
|
300
|
+
? ` — the process ran the full ${timeout}s without writing to its stdio; it may have been stalled before producing output, or holding it in a block buffer`
|
|
301
|
+
: "";
|
|
299
302
|
const body = !zeroOutput
|
|
300
303
|
? `\n${delimitUntrusted("partial command output", captured)}`
|
|
301
|
-
: `\n(no output was produced before the cutoff)`;
|
|
304
|
+
: `\n(no output was produced before the cutoff${zeroOutputHint})`;
|
|
302
305
|
const overflowNote = cutOverflowFile !== undefined ? shellRecoveryHint(cutOverflowFile, readOnly) : "";
|
|
303
306
|
return {
|
|
304
307
|
content: `Error (${toolName}): ${headline}${body}${overflowNote}`,
|
package/dist/tools/fs/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export * from "./fs-bash.js";
|
|
|
13
13
|
import { type CwdRef, type ReadImageDownsamplerOption } from "./fs-shared.js";
|
|
14
14
|
export interface HandsToolkitOptions {
|
|
15
15
|
additionalRoots?: readonly string[];
|
|
16
|
+
additionalReadRoots?: readonly string[];
|
|
16
17
|
includeShell?: boolean;
|
|
17
18
|
readOnly?: boolean;
|
|
18
19
|
bashReadonlyAllow?: readonly string[];
|
package/dist/tools/fs/index.js
CHANGED
|
@@ -16,7 +16,10 @@ import { createEditFileTool, createWriteFileTool, createNotebookEditTool } from
|
|
|
16
16
|
import { createGrepTool, createGlobTool } from "./fs-search-tools.js";
|
|
17
17
|
import { createBashTool, createBashReadonlyTool, createEnvTaskOutputTool, createEnvTaskStopTool } from "./fs-bash.js";
|
|
18
18
|
export function createHandsToolkit(env, readFileState, rootCanonical, opts = {}) {
|
|
19
|
-
const { includeShell = false, readOnly = false, bashReadonlyAllow, commitCoAuthor = false, mountBackgroundTaskTools = true, additionalRoots, } = opts;
|
|
19
|
+
const { includeShell = false, readOnly = false, bashReadonlyAllow, commitCoAuthor = false, mountBackgroundTaskTools = true, additionalRoots, additionalReadRoots, } = opts;
|
|
20
|
+
const readFaceRoots = additionalReadRoots === undefined || additionalReadRoots.length === 0
|
|
21
|
+
? additionalRoots
|
|
22
|
+
: [...(additionalRoots ?? []), ...additionalReadRoots];
|
|
20
23
|
const cwdRef = opts.cwdRef ?? { current: rootCanonical };
|
|
21
24
|
const bgReadRegistry = opts.taskRegistry;
|
|
22
25
|
const bgOutputReadExemption = bgReadRegistry === undefined
|
|
@@ -27,18 +30,18 @@ export function createHandsToolkit(env, readFileState, rootCanonical, opts = {})
|
|
|
27
30
|
...(opts.sessionId !== undefined ? { sessionId: opts.sessionId } : {}),
|
|
28
31
|
}, env);
|
|
29
32
|
const tools = [
|
|
30
|
-
createReadFileTool(env, readFileState, rootCanonical, readOnly ? undefined : cwdRef,
|
|
33
|
+
createReadFileTool(env, readFileState, rootCanonical, readOnly ? undefined : cwdRef, readFaceRoots, opts.readImageDownsampler, opts.pdfModelCapabilities, bgOutputReadExemption),
|
|
31
34
|
];
|
|
32
35
|
if (!readOnly) {
|
|
33
36
|
tools.push(createEditFileTool(env, readFileState, rootCanonical, cwdRef, additionalRoots, opts.beforeWrite), createWriteFileTool(env, readFileState, rootCanonical, cwdRef, additionalRoots, opts.beforeWrite), createNotebookEditTool(env, readFileState, rootCanonical, cwdRef, additionalRoots, opts.beforeWrite));
|
|
34
37
|
}
|
|
35
|
-
tools.push(createGrepTool(env, rootCanonical,
|
|
38
|
+
tools.push(createGrepTool(env, rootCanonical, readFaceRoots), createGlobTool(env, rootCanonical, readFaceRoots), createRepoMapTool(env, rootCanonical, readFaceRoots));
|
|
36
39
|
if (includeShell) {
|
|
37
40
|
tools.push(readOnly
|
|
38
41
|
? createBashReadonlyTool(env, rootCanonical, new Set(bashReadonlyAllow ?? BASH_READONLY_DEFAULT_ALLOW), {
|
|
39
42
|
...(opts.bashDefaultTimeoutMs !== undefined ? { bashDefaultTimeoutMs: opts.bashDefaultTimeoutMs } : {}),
|
|
40
43
|
...(opts.bashMaxTimeoutMs !== undefined ? { bashMaxTimeoutMs: opts.bashMaxTimeoutMs } : {}),
|
|
41
|
-
...(
|
|
44
|
+
...(readFaceRoots !== undefined ? { additionalRoots: readFaceRoots } : {}),
|
|
42
45
|
})
|
|
43
46
|
: createBashTool(env, rootCanonical, commitCoAuthor, cwdRef, {
|
|
44
47
|
taskRegistry: opts.taskRegistry,
|
package/dist/tools/web.d.ts
CHANGED
|
@@ -9,17 +9,37 @@ export interface WebFetchConfig {
|
|
|
9
9
|
summarize?: (content: string, prompt: string, signal?: AbortSignal) => Promise<string | {
|
|
10
10
|
text: string;
|
|
11
11
|
truncated?: boolean;
|
|
12
|
+
inputTruncated?: boolean;
|
|
13
|
+
inputChars?: number;
|
|
14
|
+
usedChars?: number;
|
|
12
15
|
}>;
|
|
13
16
|
userAgent?: string;
|
|
14
17
|
}
|
|
18
|
+
export declare const WEBFETCH_GROUNDING_MIN_TEXT_CHARS = 200;
|
|
19
|
+
export interface WebFetchGrounding {
|
|
20
|
+
level: "ok" | "low";
|
|
21
|
+
textChars: number;
|
|
22
|
+
bytes: number;
|
|
23
|
+
textRatio: number;
|
|
24
|
+
}
|
|
15
25
|
export declare function htmlToText(html: string): string;
|
|
16
26
|
export declare function webFetchToolSpec(config?: WebFetchConfig): ToolSpec;
|
|
17
27
|
export declare function createWebFetchTool(config?: WebFetchConfig): AgentTool;
|
|
18
28
|
export declare const WEBFETCH_SUMMARY_MAX_CONTENT = 100000;
|
|
19
29
|
export declare const WEBFETCH_SUMMARY_GUIDELINES: string;
|
|
20
|
-
export declare
|
|
30
|
+
export declare const WEBFETCH_SUMMARY_GROUNDING_CLAUSE: string;
|
|
31
|
+
export declare const WEBFETCH_SUMMARY_INPUT_HEADROOM = 0.8;
|
|
32
|
+
export declare const WEBFETCH_SUMMARY_MIN_CONTENT = 4000;
|
|
33
|
+
export declare function resolveSummaryInputChars(model: Model, override?: number): number;
|
|
34
|
+
export interface WebFetchSummarizerOptions {
|
|
35
|
+
maxContentChars?: number;
|
|
36
|
+
}
|
|
37
|
+
export declare function createWebFetchSummarizer(brain: Brain, model: Model, options?: WebFetchSummarizerOptions): (content: string, prompt: string, signal?: AbortSignal) => Promise<string | {
|
|
21
38
|
text: string;
|
|
22
39
|
truncated?: boolean;
|
|
40
|
+
inputTruncated?: boolean;
|
|
41
|
+
inputChars?: number;
|
|
42
|
+
usedChars?: number;
|
|
23
43
|
}>;
|
|
24
44
|
export interface WebSearchConfig {
|
|
25
45
|
search: (query: string, signal?: AbortSignal, opts?: {
|