scream-code 0.17.5 → 0.17.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/{app-CujwBxt8.mjs → app-y8MJHp3H.mjs} +4 -4
- package/dist/{dispatch-DCzx4R71.mjs → dispatch-DFFuylzQ.mjs} +605 -48
- package/dist/{dispatch-DjLS5cab.mjs → dispatch-DRdBQorE.mjs} +1 -1
- package/dist/main.mjs +1 -1
- package/dist/{text-input-dialog-BoxTq4a3.mjs → text-input-dialog-CD0sakGq.mjs} +6 -0
- package/dist/{text-input-dialog-DQaJf2zB.mjs → text-input-dialog-DcjQLJFz.mjs} +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -56,6 +56,7 @@ When Scream wants to modify files or run commands, an approval panel pops up —
|
|
|
56
56
|
- **Persistent Memory** — structured pain-point memory with FTS5 full-text + tag + vector retrieval, shared across sessions.
|
|
57
57
|
- **Local Knowledge Graph** — SAG-based visual knowledge base for multi-hop reasoning; import your own docs anytime.
|
|
58
58
|
- **RLM Mode** — persistent Python workspace for long-running tasks, with unlimited recursive sub-agents.
|
|
59
|
+
- **Script Mode** — on by default: the model can run JavaScript in a sandbox that calls the other tools for it, so batch work (dozens of files/pages, filter-then-report) finishes in one round trip — only the script's summary enters the conversation; `/script` toggles it.
|
|
59
60
|
- **Session Trace** — `/trace` exports any session as a self-contained, offline interactive HTML timeline.
|
|
60
61
|
- **Context Search** — `/search` (Ctrl+Shift+F) full-screen keyword search over the conversation.
|
|
61
62
|
- **High Cache Hit Rate** — per-session HitR in the status bar, tuned across compatible protocols to maximize cache hits without compromising quality.
|
|
@@ -65,7 +66,7 @@ When Scream wants to modify files or run commands, an approval panel pops up —
|
|
|
65
66
|
|
|
66
67
|
### Slash Commands
|
|
67
68
|
|
|
68
|
-
Type `/` in the input to browse. All
|
|
69
|
+
Type `/` in the input to browse. All 55 commands:
|
|
69
70
|
|
|
70
71
|
<details>
|
|
71
72
|
<summary>Full command reference (click to expand)</summary>
|
|
@@ -81,6 +82,7 @@ Type `/` in the input to browse. All 54 commands:
|
|
|
81
82
|
| `/wolfpack` (`/wp`) | Toggle wolfpack mode — auto-approve + batch concurrency |
|
|
82
83
|
| `/rlm` | RLM mode: persistent Python workspace, unlimited recursive subagents |
|
|
83
84
|
| `/rlm-max-depth [N]` | Set RLM recursion depth limit |
|
|
85
|
+
| `/script` | Script mode: run JavaScript in a sandbox that batches tool calls (on by default) |
|
|
84
86
|
| `/plan` | Toggle plan mode |
|
|
85
87
|
| `/fusionplan` (`/fp`) | Fusion plan mode (multi-agent parallel planning) |
|
|
86
88
|
| `/btw` | Quick question without interrupting the conversation |
|
|
@@ -5,8 +5,8 @@ const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
import { k as MemoryMemoStore } from "./src-BhZujafw.mjs";
|
|
8
|
-
import { $n as encodeWorkDirKey, $t as lerpGradient, A as highlightLines, An as embeddingFailureDetail, At as isTurnElapsedEnabled, B as ActivityGroupComponent, Bn as detectShellEnvironment, Bt as ENABLE_TERMINAL_THEME_REPORTING, Cn as getLlmNotSetMessage, Ct as clearInfoPanelState, D as ToolCallComponent, Dn as sortSlashCommands, Dt as createEditorTheme, E as UserMessageComponent, En as BUILTIN_SLASH_COMMANDS, Et as resolveThemeSync, F as StatusMessageComponent, Fn as PULSE_WAVE_FRAMES, Ft as detectTerminalTheme, G as AgentGroupComponent, Gn as CLI_COMMAND_NAME, Gt as QUERY_TERMINAL_THEME, H as estimateTokens, Hn as getInputHistoryFile, Ht as OSC11_RESPONSE, I as replaceTabs, In as TuiConfigParseError, It as parseOsc11BackgroundTheme, J as getBreathingFrame, Jn as PRODUCT_NAME, Jt as TERMINAL_THEME_DARK, K as WelcomeComponent, Kn as CLI_UI_MODE, Kt as TERMINAL_FOCUS_IN, L as sanitizeShellOutput, Ln as TuiLikePreferencesSchema, Lt as DISABLE_TERMINAL_FOCUS_REPORTING, M as CachedContainer, Mn as hasEmbeddingModelCache, Mt as createThemeStyles, N as ThinkingComponent, Nn as startManualEmbeddingDownload, Nt as contrastTextHex, O as renderDiffLines, On as isExperimentalFlagEnabled, Ot as createMarkdownTheme, P as NoticeMessageComponent, Pn as PIXEL_PULSE_FRAMES, Pt as getColorPalette, Q as refineGoal, Qn as ScreamHarness, Qt as FooterComponent, R as SkillActivationComponent, Rn as loadTuiConfig, Rt as DISABLE_TERMINAL_THEME_REPORTING, S as readJsonlFile, Sn as getCtrlDHint, St as supportsBalance, Tn as buildSkillSlashCommands, U as getSharedSpeedTracker, Un as getLogDir, Ut as OSC11_RESPONSE_PREFIX, V as charsForTokenBudget, Vn as getDataDir, Vt as OSC11_QUERY, W as BackgroundAgentStatusComponent, Wn as detectInstallSource, Wt as OSC11_RESPONSE_PREFIX_NO_ESC, X as CompactionComponent, Xn as fetchCatalog, Xt as isBusy, Y as resetBreathingClock, Yn as DEFAULT_CATALOG_URL, Yt as TERMINAL_THEME_LIGHT, Z as clearGoalState, Zn as saveCatalogCache, Zt as isStreaming, _n as EXIT_CONFIRM_WINDOW_MS, a as syncDiagramCapabilityPrompt, an as printableChar, ar as isRealUserPrompt, at as toTerminalHyperlink, b as readUpdateCache, bn as TIP_ROTATION_INTERVAL_MS, c as disposeChildren, cn as appendStreamingArgsPreview, cr as log, d as isPlanExpandable, dn as isTodoItemShape, dr as isOrphanedToolCallError, en as SubagentSlots, er as normalizeWorkDir, f as MoonLoader, fn as parseStreamingArgs, fr as ErrorCodes, ft as handleFusionPlanCommand, gn as EMPTY_SESSION_HINT_URL, hn as truncateErrorMessage, i as buildRoleAdditionalText, it as isInternalMessage, j as langFromPath, jn as getKnowledgeStore, jt as toggleEmptySessionHint, k as renderDiffLinesClustered, kn as setExperimentalFlags, kt as isEmptySessionHintDismissed, l as hasDispose, ln as argsRecord, lr as resolveGlobalLogPath, mn as stringValue, mt as handlePlanCommand, n as clearEvalPanelState, nr as readSessionIndex, on as STATUS_BULLET, or as resolveScreamHome, ot as changeThinkingLevel, p as formatMemoryMemoForInjection, pn as serializeToolResultOutput, pr as SCREAM_ERROR_INFO, q as BREATHE_CYCLE_MS, qn as CLI_USER_AGENT_PRODUCT, qt as TERMINAL_FOCUS_OUT, r as openUrl, rr as removeSessionIndexEntry, sn as appendSessionHeaderHint, sr as flushDiagnosticLogs, st as getModelCycleLevel, t as dispatchInput, tr as appendSessionIndexEntry, u as isExpandable, un as formatErrorMessage, ur as isScreamError, v as selectUpdateTarget, vn as MAIN_AGENT_ID, w as getDaemonInstructions, wn as getNoActiveSessionMessage, x as appendJsonlLine, xn as getCtrlCHint, xt as refreshProviderBalance, y as refreshUpdateCache, yn as SESSION_TIPS, z as AssistantMessageComponent, zn as saveTuiConfig, zt as ENABLE_TERMINAL_FOCUS_REPORTING } from "./dispatch-
|
|
9
|
-
import { a as setLocale, i as getLocale, o as t } from "./text-input-dialog-
|
|
8
|
+
import { $n as encodeWorkDirKey, $t as lerpGradient, A as highlightLines, An as embeddingFailureDetail, At as isTurnElapsedEnabled, B as ActivityGroupComponent, Bn as detectShellEnvironment, Bt as ENABLE_TERMINAL_THEME_REPORTING, Cn as getLlmNotSetMessage, Ct as clearInfoPanelState, D as ToolCallComponent, Dn as sortSlashCommands, Dt as createEditorTheme, E as UserMessageComponent, En as BUILTIN_SLASH_COMMANDS, Et as resolveThemeSync, F as StatusMessageComponent, Fn as PULSE_WAVE_FRAMES, Ft as detectTerminalTheme, G as AgentGroupComponent, Gn as CLI_COMMAND_NAME, Gt as QUERY_TERMINAL_THEME, H as estimateTokens, Hn as getInputHistoryFile, Ht as OSC11_RESPONSE, I as replaceTabs, In as TuiConfigParseError, It as parseOsc11BackgroundTheme, J as getBreathingFrame, Jn as PRODUCT_NAME, Jt as TERMINAL_THEME_DARK, K as WelcomeComponent, Kn as CLI_UI_MODE, Kt as TERMINAL_FOCUS_IN, L as sanitizeShellOutput, Ln as TuiLikePreferencesSchema, Lt as DISABLE_TERMINAL_FOCUS_REPORTING, M as CachedContainer, Mn as hasEmbeddingModelCache, Mt as createThemeStyles, N as ThinkingComponent, Nn as startManualEmbeddingDownload, Nt as contrastTextHex, O as renderDiffLines, On as isExperimentalFlagEnabled, Ot as createMarkdownTheme, P as NoticeMessageComponent, Pn as PIXEL_PULSE_FRAMES, Pt as getColorPalette, Q as refineGoal, Qn as ScreamHarness, Qt as FooterComponent, R as SkillActivationComponent, Rn as loadTuiConfig, Rt as DISABLE_TERMINAL_THEME_REPORTING, S as readJsonlFile, Sn as getCtrlDHint, St as supportsBalance, Tn as buildSkillSlashCommands, U as getSharedSpeedTracker, Un as getLogDir, Ut as OSC11_RESPONSE_PREFIX, V as charsForTokenBudget, Vn as getDataDir, Vt as OSC11_QUERY, W as BackgroundAgentStatusComponent, Wn as detectInstallSource, Wt as OSC11_RESPONSE_PREFIX_NO_ESC, X as CompactionComponent, Xn as fetchCatalog, Xt as isBusy, Y as resetBreathingClock, Yn as DEFAULT_CATALOG_URL, Yt as TERMINAL_THEME_LIGHT, Z as clearGoalState, Zn as saveCatalogCache, Zt as isStreaming, _n as EXIT_CONFIRM_WINDOW_MS, a as syncDiagramCapabilityPrompt, an as printableChar, ar as isRealUserPrompt, at as toTerminalHyperlink, b as readUpdateCache, bn as TIP_ROTATION_INTERVAL_MS, c as disposeChildren, cn as appendStreamingArgsPreview, cr as log, d as isPlanExpandable, dn as isTodoItemShape, dr as isOrphanedToolCallError, en as SubagentSlots, er as normalizeWorkDir, f as MoonLoader, fn as parseStreamingArgs, fr as ErrorCodes, ft as handleFusionPlanCommand, gn as EMPTY_SESSION_HINT_URL, hn as truncateErrorMessage, i as buildRoleAdditionalText, it as isInternalMessage, j as langFromPath, jn as getKnowledgeStore, jt as toggleEmptySessionHint, k as renderDiffLinesClustered, kn as setExperimentalFlags, kt as isEmptySessionHintDismissed, l as hasDispose, ln as argsRecord, lr as resolveGlobalLogPath, mn as stringValue, mt as handlePlanCommand, n as clearEvalPanelState, nr as readSessionIndex, on as STATUS_BULLET, or as resolveScreamHome, ot as changeThinkingLevel, p as formatMemoryMemoForInjection, pn as serializeToolResultOutput, pr as SCREAM_ERROR_INFO, q as BREATHE_CYCLE_MS, qn as CLI_USER_AGENT_PRODUCT, qt as TERMINAL_FOCUS_OUT, r as openUrl, rr as removeSessionIndexEntry, sn as appendSessionHeaderHint, sr as flushDiagnosticLogs, st as getModelCycleLevel, t as dispatchInput, tr as appendSessionIndexEntry, u as isExpandable, un as formatErrorMessage, ur as isScreamError, v as selectUpdateTarget, vn as MAIN_AGENT_ID, w as getDaemonInstructions, wn as getNoActiveSessionMessage, x as appendJsonlLine, xn as getCtrlCHint, xt as refreshProviderBalance, y as refreshUpdateCache, yn as SESSION_TIPS, z as AssistantMessageComponent, zn as saveTuiConfig, zt as ENABLE_TERMINAL_FOCUS_REPORTING } from "./dispatch-DFFuylzQ.mjs";
|
|
9
|
+
import { a as setLocale, i as getLocale, o as t } from "./text-input-dialog-CD0sakGq.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { randomBytes, randomUUID, scryptSync, timingSafeEqual } from "node:crypto";
|
|
12
12
|
import { access, appendFile, chmod, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
@@ -33,7 +33,7 @@ function optionalBuildString(value) {
|
|
|
33
33
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
34
34
|
}
|
|
35
35
|
const SCREAM_BUILD_INFO = {
|
|
36
|
-
version: optionalBuildString("0.17.
|
|
36
|
+
version: optionalBuildString("0.17.6"),
|
|
37
37
|
channel: optionalBuildString(""),
|
|
38
38
|
commit: optionalBuildString(""),
|
|
39
39
|
buildTarget: optionalBuildString("darwin-arm64")
|
|
@@ -14142,7 +14142,7 @@ var ScreamTUI = class {
|
|
|
14142
14142
|
const card = new OnboardingCardComponent({
|
|
14143
14143
|
colors: this.state.theme.colors,
|
|
14144
14144
|
onConfigure: () => {
|
|
14145
|
-
import("./dispatch-
|
|
14145
|
+
import("./dispatch-DRdBQorE.mjs").then(({ handleConnectCommand }) => handleConnectCommand(this, "")).finally(() => {
|
|
14146
14146
|
this.restoreEditor();
|
|
14147
14147
|
onDone?.();
|
|
14148
14148
|
});
|
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import { i as __require, o as __toESM, r as __exportAll, t as __commonJSMin } from "./chunk-D90kvbyJ.mjs";
|
|
7
7
|
import { A as classifyEmbeddingFailure, B as rankMemos, C as applyConsolidation, D as parseMemoryMemos, E as buildExitExtractionPrompt, F as createMemoryMemo, G as normalize, H as dirname$2, I as toSummary, J as resolve$2, K as parse$7, L as generateTags, M as createFastEmbedEngine, N as hasEmbeddingModelCache$1, O as stripMemoryTags, P as probeLocalEmbeddingSupport, R as normalizeTags, S as DreamTracker, T as EXIT_EXTRACTION_SYSTEM_PROMPT, U as isAbsolute$1, V as basename$1, W as join$1, a as isSupportedFile, b as sharedKnowledgeStoreReady, i as ingestFile, j as clearEmbeddingModelCache, k as MemoryMemoStore, q as relative$1, r as ingestDirectory, t as multiSearch, w as buildConsolidationPlan, y as sharedKnowledgeStore, z as buildProjectTagCloud } from "./src-BhZujafw.mjs";
|
|
8
8
|
import { n as require_base64_js, t as XMLParser } from "./XMLParser-DFAnGqkc.mjs";
|
|
9
|
-
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
9
|
+
import { a as setLocale, i as getLocale, n as assertScreamHostIdentity, o as t, r as createScreamDefaultHeaders, t as TextInputDialogComponent } from "./text-input-dialog-CD0sakGq.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
12
12
|
import * as fs$1 from "node:fs/promises";
|
|
@@ -38,6 +38,7 @@ import { StringDecoder } from "node:string_decoder";
|
|
|
38
38
|
import Pi from "assert";
|
|
39
39
|
import ro from "node:assert";
|
|
40
40
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
41
|
+
import { CodemodeSandbox, CodemodeSourceError, parseCodemodeSource, renderDeclarations } from "@earendil-works/pi-codemode";
|
|
41
42
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
42
43
|
import * as posixPath from "node:path/posix";
|
|
43
44
|
import * as win32Path from "node:path/win32";
|
|
@@ -76727,7 +76728,7 @@ const PY_DONE_MARKER = "__SCREAM_PY_DONE__";
|
|
|
76727
76728
|
const MAX_OUTPUT_CHARS = 5e4;
|
|
76728
76729
|
const TAIL_CHARS = 2e4;
|
|
76729
76730
|
const TRUNCATION_MARKER = "[...truncated]";
|
|
76730
|
-
function truncateOutput(output) {
|
|
76731
|
+
function truncateOutput$1(output) {
|
|
76731
76732
|
if (output.length <= MAX_OUTPUT_CHARS) return output;
|
|
76732
76733
|
return `${output.slice(0, MAX_OUTPUT_CHARS - TAIL_CHARS)}\n${TRUNCATION_MARKER}\n${output.slice(-2e4)}`;
|
|
76733
76734
|
}
|
|
@@ -77096,7 +77097,7 @@ except BaseException as __e:
|
|
|
77096
77097
|
this.kernel = void 0;
|
|
77097
77098
|
return {
|
|
77098
77099
|
isError: true,
|
|
77099
|
-
output: `Python execution timed out after ${Math.round(timeoutMs / 1e3)}s (kernel restarted).\n${truncateOutput(merged)}`
|
|
77100
|
+
output: `Python execution timed out after ${Math.round(timeoutMs / 1e3)}s (kernel restarted).\n${truncateOutput$1(merged)}`
|
|
77100
77101
|
};
|
|
77101
77102
|
}
|
|
77102
77103
|
if (!await this.syncKernel(proc)) {
|
|
@@ -77104,7 +77105,7 @@ except BaseException as __e:
|
|
|
77104
77105
|
this.kernel = void 0;
|
|
77105
77106
|
return {
|
|
77106
77107
|
isError: true,
|
|
77107
|
-
output: `Python execution timed out after ${Math.round(timeoutMs / 1e3)}s (kernel restarted).\n${truncateOutput(merged)}`
|
|
77108
|
+
output: `Python execution timed out after ${Math.round(timeoutMs / 1e3)}s (kernel restarted).\n${truncateOutput$1(merged)}`
|
|
77108
77109
|
};
|
|
77109
77110
|
}
|
|
77110
77111
|
await this.drainStderrQuiet(proc);
|
|
@@ -77113,11 +77114,11 @@ except BaseException as __e:
|
|
|
77113
77114
|
const timedOutMerged = [merged, interruptStderr].filter((part) => part.length > 0).join("\n");
|
|
77114
77115
|
return {
|
|
77115
77116
|
isError: true,
|
|
77116
|
-
output: `Python execution timed out after ${Math.round(timeoutMs / 1e3)}s (kernel interrupted; state preserved).\n${truncateOutput(timedOutMerged)}`
|
|
77117
|
+
output: `Python execution timed out after ${Math.round(timeoutMs / 1e3)}s (kernel interrupted; state preserved).\n${truncateOutput$1(timedOutMerged)}`
|
|
77117
77118
|
};
|
|
77118
77119
|
}
|
|
77119
77120
|
const isError = merged.includes("Traceback") || merged.toLowerCase().includes("error:");
|
|
77120
|
-
const finalOutput = truncateOutput(merged);
|
|
77121
|
+
const finalOutput = truncateOutput$1(merged);
|
|
77121
77122
|
return {
|
|
77122
77123
|
isError,
|
|
77123
77124
|
output: finalOutput.length > 0 ? finalOutput : "(no output)"
|
|
@@ -77190,6 +77191,281 @@ except BaseException as __e:
|
|
|
77190
77191
|
}
|
|
77191
77192
|
}
|
|
77192
77193
|
};
|
|
77194
|
+
//#endregion
|
|
77195
|
+
//#region ../../packages/agent-core/src/tools/builtin/script/script.ts
|
|
77196
|
+
/** Model-facing tool name. */
|
|
77197
|
+
const SCRIPT_TOOL_NAME = "RunScript";
|
|
77198
|
+
/** Declaration budget for the tool description (≈3000 tokens at 4 chars/token). */
|
|
77199
|
+
const DECLARATION_BUDGET_CHARS = 12e3;
|
|
77200
|
+
const CHARS_PER_TOKEN = 4;
|
|
77201
|
+
const DEFAULT_MAX_OUTPUT_TOKENS = 1e4;
|
|
77202
|
+
/** QuickJS heap ceiling per execution. */
|
|
77203
|
+
const SANDBOX_MEMORY_LIMIT_BYTES = 256 * 1024 * 1024;
|
|
77204
|
+
/**
|
|
77205
|
+
* Nested-call *recording* caps, mirroring the reference runner: a call always
|
|
77206
|
+
* runs — only its record degrades. Arguments are dropped from the record once
|
|
77207
|
+
* the byte budgets are exhausted, and records stop once the call cap is hit.
|
|
77208
|
+
*/
|
|
77209
|
+
const MAX_NESTED_CALLS = 256;
|
|
77210
|
+
const MAX_NESTED_ARG_BYTES = 8 * 1024;
|
|
77211
|
+
const MAX_NESTED_TOTAL_ARG_BYTES = 32 * 1024;
|
|
77212
|
+
const MAX_NESTED_MESSAGE_CHARS = 500;
|
|
77213
|
+
const ARGS_PREVIEW_CHARS = 160;
|
|
77214
|
+
const SCRIPT_PREAMBLE = [
|
|
77215
|
+
"Run JavaScript in a sandbox whose only capability is calling the tools listed below.",
|
|
77216
|
+
"The tool calls the script makes never enter the conversation — only what the script",
|
|
77217
|
+
"returns through `text(...)` (and `console.*`) is shown.",
|
|
77218
|
+
"",
|
|
77219
|
+
"When to use: several tool calls can be planned up front — batch work across many",
|
|
77220
|
+
"files, chained steps that need no decision in between, or filtering/aggregating",
|
|
77221
|
+
"results before reporting them.",
|
|
77222
|
+
"When not to use: a single tool call is enough, or each next step depends on",
|
|
77223
|
+
"observing the previous result.",
|
|
77224
|
+
"",
|
|
77225
|
+
"Rules:",
|
|
77226
|
+
"- Call tools as `await tools.<Name>({...})`; calls are auto-awaited and resolve to the",
|
|
77227
|
+
" tool's text output. A failing call rejects with an Error carrying the failure text.",
|
|
77228
|
+
"- `store(key, value)` / `load(key)` persist small JSON values across turns (only successful runs commit writes).",
|
|
77229
|
+
"- `image(dataUrlOrBytes)` attaches an image to the result.",
|
|
77230
|
+
"- `exit()` ends the script early.",
|
|
77231
|
+
"- Optional first line: `// @options: {\"max_output_tokens\": 10000, \"timeout_ms\": 60000}`."
|
|
77232
|
+
].join("\n");
|
|
77233
|
+
const ScriptInputSchema = z.object({ code: z.string().min(1).describe("JavaScript to run. Call the available tools as `tools.<Name>(args)`; only text()/console output reaches the conversation.") });
|
|
77234
|
+
/** Builds the tool description including declarations for the callable tools. */
|
|
77235
|
+
function buildScriptToolDescription(callableTools) {
|
|
77236
|
+
if (callableTools.length === 0) return `${SCRIPT_PREAMBLE}\n\nNo tools are currently available inside the script.`;
|
|
77237
|
+
const full = `${SCRIPT_PREAMBLE}\n\nTool declarations:\n\n${renderDeclarations({ tools: callableTools.map((tool) => ({
|
|
77238
|
+
name: tool.name,
|
|
77239
|
+
description: tool.description,
|
|
77240
|
+
inputSchema: tool.parameters,
|
|
77241
|
+
execute: () => void 0
|
|
77242
|
+
})) })}`;
|
|
77243
|
+
if (full.length <= DECLARATION_BUDGET_CHARS) return full;
|
|
77244
|
+
const names = callableTools.map((tool) => `- ${tool.name}: ${firstLineOf(tool.description)}`).join("\n");
|
|
77245
|
+
return [
|
|
77246
|
+
SCRIPT_PREAMBLE,
|
|
77247
|
+
"",
|
|
77248
|
+
`Tool declarations omitted (${callableTools.length} tools exceed the ${DECLARATION_BUDGET_CHARS}-character budget); call them by their exact names:`,
|
|
77249
|
+
names
|
|
77250
|
+
].join("\n");
|
|
77251
|
+
}
|
|
77252
|
+
/**
|
|
77253
|
+
* Runs model-written JavaScript in a QuickJS sandbox (worker thread) with the
|
|
77254
|
+
* current step's tools exposed as `tools.<Name>()`. Only the script's own
|
|
77255
|
+
* output enters the conversation; every nested call goes through the regular
|
|
77256
|
+
* tool pipeline (validation, hooks, approval) via `ctx.runNestedToolCall`.
|
|
77257
|
+
*/
|
|
77258
|
+
var ScriptTool = class {
|
|
77259
|
+
store;
|
|
77260
|
+
name = SCRIPT_TOOL_NAME;
|
|
77261
|
+
description = buildScriptToolDescription([]);
|
|
77262
|
+
parameters = toInputJsonSchema(ScriptInputSchema);
|
|
77263
|
+
constructor(store) {
|
|
77264
|
+
this.store = store;
|
|
77265
|
+
}
|
|
77266
|
+
resolveExecution(args) {
|
|
77267
|
+
let parsed;
|
|
77268
|
+
let parseError;
|
|
77269
|
+
try {
|
|
77270
|
+
parsed = parseCodemodeSource(args.code);
|
|
77271
|
+
} catch (error) {
|
|
77272
|
+
parseError = error instanceof CodemodeSourceError ? error.message : String(error);
|
|
77273
|
+
}
|
|
77274
|
+
return {
|
|
77275
|
+
description: "Running a script",
|
|
77276
|
+
approvalRule: this.name,
|
|
77277
|
+
execute: async (ctx) => {
|
|
77278
|
+
if (parsed === void 0) return {
|
|
77279
|
+
output: `Script rejected: ${parseError ?? "invalid source"}`,
|
|
77280
|
+
isError: true
|
|
77281
|
+
};
|
|
77282
|
+
return this.run(parsed, ctx);
|
|
77283
|
+
}
|
|
77284
|
+
};
|
|
77285
|
+
}
|
|
77286
|
+
async run(parsed, ctx) {
|
|
77287
|
+
const runner = ctx.runNestedToolCall;
|
|
77288
|
+
if (runner === void 0) return {
|
|
77289
|
+
output: "RunScript is unavailable in this context: nested tool calls are not supported here.",
|
|
77290
|
+
isError: true
|
|
77291
|
+
};
|
|
77292
|
+
const state = {
|
|
77293
|
+
calls: 0,
|
|
77294
|
+
argBytes: 0,
|
|
77295
|
+
records: []
|
|
77296
|
+
};
|
|
77297
|
+
const sandbox = new CodemodeSandbox({
|
|
77298
|
+
tools: runner.tools.map((tool) => this.toSandboxTool(tool, runner, ctx, state)),
|
|
77299
|
+
memoryLimitBytes: SANDBOX_MEMORY_LIMIT_BYTES,
|
|
77300
|
+
timeoutMs: parsed.options.timeoutMs ?? Number.POSITIVE_INFINITY
|
|
77301
|
+
});
|
|
77302
|
+
try {
|
|
77303
|
+
const result = await sandbox.execute(parsed.code, {
|
|
77304
|
+
signal: ctx.signal,
|
|
77305
|
+
store: this.store.get("scriptStore") ?? {}
|
|
77306
|
+
});
|
|
77307
|
+
if (!result.ok) return await this.failedResult(result.error, result.output, state);
|
|
77308
|
+
this.commitStoreWrites(result.storeWrites);
|
|
77309
|
+
return await this.successResult(result.output, result.value, state, parsed.options);
|
|
77310
|
+
} finally {
|
|
77311
|
+
await sandbox.close();
|
|
77312
|
+
}
|
|
77313
|
+
}
|
|
77314
|
+
toSandboxTool(tool, runner, ctx, state) {
|
|
77315
|
+
return {
|
|
77316
|
+
name: tool.name,
|
|
77317
|
+
description: tool.description,
|
|
77318
|
+
inputSchema: tool.parameters,
|
|
77319
|
+
execute: (args) => this.runNested(runner, tool.name, args, ctx, state)
|
|
77320
|
+
};
|
|
77321
|
+
}
|
|
77322
|
+
async runNested(runner, name, args, ctx, state) {
|
|
77323
|
+
state.calls += 1;
|
|
77324
|
+
const callId = `${ctx.toolCallId}/${state.calls}`;
|
|
77325
|
+
let record;
|
|
77326
|
+
if (state.records.length < MAX_NESTED_CALLS) {
|
|
77327
|
+
const serialized = tryStringify(args);
|
|
77328
|
+
const bytes = serialized === void 0 ? 0 : Buffer.byteLength(serialized, "utf8");
|
|
77329
|
+
const overBudget = serialized === void 0 || bytes > MAX_NESTED_ARG_BYTES || state.argBytes + bytes > MAX_NESTED_TOTAL_ARG_BYTES;
|
|
77330
|
+
record = {
|
|
77331
|
+
callId,
|
|
77332
|
+
name,
|
|
77333
|
+
status: "ok",
|
|
77334
|
+
durationMs: 0,
|
|
77335
|
+
...overBudget ? { incomplete: true } : { argsPreview: previewOf(serialized) }
|
|
77336
|
+
};
|
|
77337
|
+
if (!overBudget) state.argBytes += bytes;
|
|
77338
|
+
state.records.push(record);
|
|
77339
|
+
}
|
|
77340
|
+
const startedAt = Date.now();
|
|
77341
|
+
try {
|
|
77342
|
+
const result = await runner.run({
|
|
77343
|
+
name,
|
|
77344
|
+
args,
|
|
77345
|
+
callId
|
|
77346
|
+
});
|
|
77347
|
+
if (record !== void 0) {
|
|
77348
|
+
record.status = result.isError === true ? "error" : "ok";
|
|
77349
|
+
record.durationMs = Date.now() - startedAt;
|
|
77350
|
+
}
|
|
77351
|
+
return resolveNestedValue(name, result);
|
|
77352
|
+
} catch (error) {
|
|
77353
|
+
if (record !== void 0) {
|
|
77354
|
+
record.status = "error";
|
|
77355
|
+
record.durationMs = Date.now() - startedAt;
|
|
77356
|
+
}
|
|
77357
|
+
throw error;
|
|
77358
|
+
}
|
|
77359
|
+
}
|
|
77360
|
+
commitStoreWrites(writes) {
|
|
77361
|
+
const next = { ...this.store.get("scriptStore") };
|
|
77362
|
+
for (const [key, value] of Object.entries(writes.set)) if (value === void 0) delete next[key];
|
|
77363
|
+
else next[key] = value;
|
|
77364
|
+
for (const key of writes.delete) delete next[key];
|
|
77365
|
+
this.store.set("scriptStore", next);
|
|
77366
|
+
}
|
|
77367
|
+
async successResult(output, value, state, options) {
|
|
77368
|
+
const textParts = output.filter((item) => item.type === "text").map((item) => item.text);
|
|
77369
|
+
if (value !== void 0) textParts.push(valueText(value));
|
|
77370
|
+
const { shown } = await truncateOutput(textParts.join("\n"), (options.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS) * CHARS_PER_TOKEN);
|
|
77371
|
+
const parts = [];
|
|
77372
|
+
if (shown.length > 0) parts.push({
|
|
77373
|
+
type: "text",
|
|
77374
|
+
text: shown
|
|
77375
|
+
});
|
|
77376
|
+
for (const item of output) if (item.type === "image") parts.push({
|
|
77377
|
+
type: "image_url",
|
|
77378
|
+
imageUrl: { url: `data:${item.mimeType};base64,${item.data}` }
|
|
77379
|
+
});
|
|
77380
|
+
if (parts.length === 0) parts.push({
|
|
77381
|
+
type: "text",
|
|
77382
|
+
text: "(script produced no output)"
|
|
77383
|
+
});
|
|
77384
|
+
return {
|
|
77385
|
+
output: parts,
|
|
77386
|
+
...state.records.length > 0 ? { nestedCalls: state.records } : {}
|
|
77387
|
+
};
|
|
77388
|
+
}
|
|
77389
|
+
async failedResult(error, output, state) {
|
|
77390
|
+
const lines = [`Script failed (${error.kind}): ${error.message}`];
|
|
77391
|
+
const partial = output.filter((item) => item.type === "text").map((item) => item.text).join("\n");
|
|
77392
|
+
if (partial.length > 0) {
|
|
77393
|
+
const { shown } = await truncateOutput(partial, DEFAULT_MAX_OUTPUT_TOKENS * CHARS_PER_TOKEN);
|
|
77394
|
+
lines.push("", "Partial output before the failure:", shown);
|
|
77395
|
+
}
|
|
77396
|
+
if (state.records.length > 0) lines.push(`(${state.records.length} nested call${state.records.length === 1 ? "" : "s"} ran before the failure)`);
|
|
77397
|
+
return {
|
|
77398
|
+
output: lines.join("\n"),
|
|
77399
|
+
isError: true
|
|
77400
|
+
};
|
|
77401
|
+
}
|
|
77402
|
+
};
|
|
77403
|
+
/**
|
|
77404
|
+
* Provider-facing results resolve to their text for scripts; failures reject
|
|
77405
|
+
* with an Error so scripts can try/catch (mirroring the reference runner).
|
|
77406
|
+
*/
|
|
77407
|
+
function resolveNestedValue(name, result) {
|
|
77408
|
+
const text = typeof result.output === "string" ? result.output : result.output.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
77409
|
+
if (result.isError === true) {
|
|
77410
|
+
const detail = [result.message, text].filter((part) => typeof part === "string" && part.length > 0).join("\n");
|
|
77411
|
+
throw new Error(truncateChars(detail.length > 0 ? detail : `Tool "${name}" failed`, MAX_NESTED_MESSAGE_CHARS));
|
|
77412
|
+
}
|
|
77413
|
+
return text;
|
|
77414
|
+
}
|
|
77415
|
+
/** Renders a script's returned value as text (string as-is, everything else JSON). */
|
|
77416
|
+
function valueText(value) {
|
|
77417
|
+
if (typeof value === "string") return value;
|
|
77418
|
+
try {
|
|
77419
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
77420
|
+
} catch {
|
|
77421
|
+
return String(value);
|
|
77422
|
+
}
|
|
77423
|
+
}
|
|
77424
|
+
/**
|
|
77425
|
+
* Truncates to the character budget, keeping half the budget on each side
|
|
77426
|
+
* (matching the reference implementation). The full text is spilled to a
|
|
77427
|
+
* temp file and its path reported in the shown output.
|
|
77428
|
+
*/
|
|
77429
|
+
async function truncateOutput(text, maxChars) {
|
|
77430
|
+
if (text.length <= maxChars) return { shown: text };
|
|
77431
|
+
const headChars = Math.floor(maxChars / 2);
|
|
77432
|
+
const tailChars = maxChars - headChars;
|
|
77433
|
+
const removedChars = text.length - headChars - tailChars;
|
|
77434
|
+
const path = join(tmpdir(), `scream-script-output-${randomBytes(6).toString("hex")}.txt`);
|
|
77435
|
+
let spillNote;
|
|
77436
|
+
try {
|
|
77437
|
+
await writeFile(path, text, "utf8");
|
|
77438
|
+
spillNote = `[Full output: ${path}]`;
|
|
77439
|
+
} catch (error) {
|
|
77440
|
+
spillNote = `[Could not save the full output: ${String(error)}]`;
|
|
77441
|
+
}
|
|
77442
|
+
return { shown: [
|
|
77443
|
+
`Warning: truncated output (original token count: ${Math.ceil(text.length / CHARS_PER_TOKEN)})`,
|
|
77444
|
+
`Total output lines: ${text.split("\n").length}`,
|
|
77445
|
+
"",
|
|
77446
|
+
...headChars > 0 ? [text.slice(0, headChars)] : [],
|
|
77447
|
+
`… (${Math.ceil(removedChars / CHARS_PER_TOKEN)} tokens truncated) …`,
|
|
77448
|
+
...tailChars > 0 ? [text.slice(-tailChars)] : [],
|
|
77449
|
+
"",
|
|
77450
|
+
spillNote
|
|
77451
|
+
].join("\n") };
|
|
77452
|
+
}
|
|
77453
|
+
function tryStringify(args) {
|
|
77454
|
+
try {
|
|
77455
|
+
return JSON.stringify(args ?? {});
|
|
77456
|
+
} catch {
|
|
77457
|
+
return;
|
|
77458
|
+
}
|
|
77459
|
+
}
|
|
77460
|
+
function previewOf(serialized) {
|
|
77461
|
+
return truncateChars((serialized ?? "").replaceAll("\n", " "), ARGS_PREVIEW_CHARS);
|
|
77462
|
+
}
|
|
77463
|
+
function truncateChars(value, max) {
|
|
77464
|
+
return value.length <= max ? value : `${value.slice(0, max)}…`;
|
|
77465
|
+
}
|
|
77466
|
+
function firstLineOf(description) {
|
|
77467
|
+
return truncateChars(description.split("\n", 1)[0] ?? "", 120);
|
|
77468
|
+
}
|
|
77193
77469
|
/** Families eligible for command-template normalization and segment matching. */
|
|
77194
77470
|
const COMMAND_FAMILIES = new Set([
|
|
77195
77471
|
"git checkout",
|
|
@@ -79479,22 +79755,26 @@ var DefaultCompactionStrategy = class {
|
|
|
79479
79755
|
const reservedSize = this.config.reservedContextSize;
|
|
79480
79756
|
return reservedSize > 0 && reservedSize < this.maxSize && usedSize + reservedSize >= this.maxSize;
|
|
79481
79757
|
}
|
|
79482
|
-
computeCompactCount(messages, source) {
|
|
79758
|
+
computeCompactCount(messages, source, options) {
|
|
79483
79759
|
if (source === "manual") {
|
|
79484
79760
|
for (let i = messages.length - 1; i > 0; i--) if (canSplitAfter(messages, i)) return i + 1;
|
|
79485
79761
|
return 0;
|
|
79486
79762
|
}
|
|
79487
79763
|
let recentMessages = 1;
|
|
79764
|
+
let keptMessages = 0;
|
|
79488
79765
|
let recentUserMessages = 0;
|
|
79489
79766
|
let recentSize = 0;
|
|
79490
79767
|
let bestN;
|
|
79491
79768
|
for (; recentMessages < messages.length; recentMessages++) {
|
|
79492
79769
|
const splitIndex = messages.length - recentMessages - 1;
|
|
79493
79770
|
const m2 = messages[messages.length - recentMessages];
|
|
79494
|
-
if (m2
|
|
79495
|
-
|
|
79771
|
+
if (options?.isRemoved?.(m2) !== true) {
|
|
79772
|
+
keptMessages++;
|
|
79773
|
+
if (m2.role === "user") recentUserMessages++;
|
|
79774
|
+
recentSize += estimateTokensForMessage(m2);
|
|
79775
|
+
}
|
|
79496
79776
|
if (canSplitAfter(messages, splitIndex)) bestN = splitIndex + 1;
|
|
79497
|
-
if ((
|
|
79777
|
+
if ((keptMessages >= this.config.maxRecentMessages || recentUserMessages >= this.config.maxRecentUserMessages || recentSize >= this.config.maxRecentTokens || recentSize >= this.maxSize * this.config.maxRecentSizeRatio) && bestN !== void 0) break;
|
|
79498
79778
|
}
|
|
79499
79779
|
return bestN ?? 0;
|
|
79500
79780
|
}
|
|
@@ -79782,7 +80062,7 @@ var FullCompaction = class {
|
|
|
79782
80062
|
else this.compactionCountInTurn += 1;
|
|
79783
80063
|
if (this.compactionCountInTurn > this.strategy.maxCompactionPerTurn) return;
|
|
79784
80064
|
if (this.agent.records.restoring) return;
|
|
79785
|
-
const compactedCount = this.strategy.computeCompactCount(this.agent.context.history, data.source);
|
|
80065
|
+
const compactedCount = this.strategy.computeCompactCount(this.agent.context.history, data.source, { isRemoved: (message) => this.agent.context.isMessageRemovedByEdit(message) });
|
|
79786
80066
|
if (compactedCount === 0) {
|
|
79787
80067
|
if (data.source === "manual") throw new ScreamError(ErrorCodes.COMPACTION_UNABLE, "No prefix that can be compacted in current history.");
|
|
79788
80068
|
return;
|
|
@@ -79936,7 +80216,7 @@ var FullCompaction = class {
|
|
|
79936
80216
|
const originalHistory = [...this.agent.context.history];
|
|
79937
80217
|
const systemPromptTokens = estimateTokens$1(this.agent.getRuntimeSystemPrompt());
|
|
79938
80218
|
const toolTokens = estimateTokensForTools(this.agent.tools.loopTools);
|
|
79939
|
-
const tokensBefore = systemPromptTokens + toolTokens + estimateTokensForMessages(originalHistory);
|
|
80219
|
+
const tokensBefore = systemPromptTokens + toolTokens + estimateTokensForMessages(this.agent.context.applyMessageEdits(originalHistory));
|
|
79940
80220
|
const model = this.agent.config.model;
|
|
79941
80221
|
const isUpdate = extractPreviousSummary(originalHistory) !== null;
|
|
79942
80222
|
let retryCount = 0;
|
|
@@ -79945,7 +80225,7 @@ var FullCompaction = class {
|
|
|
79945
80225
|
const delays = retryBackoffDelays(5);
|
|
79946
80226
|
const summarizeOnce = async (messagesToCompact) => {
|
|
79947
80227
|
const instruction = isUpdate ? COMPACTION_UPDATE_INSTRUCTION(data.instruction) : COMPACTION_INSTRUCTION(data.instruction);
|
|
79948
|
-
const messages = [...project(this.agent.microCompaction.compact(messagesToCompact)), {
|
|
80228
|
+
const messages = [...project(this.agent.context.applyMessageEdits(this.agent.microCompaction.compact(messagesToCompact))), {
|
|
79949
80229
|
role: "user",
|
|
79950
80230
|
content: [{
|
|
79951
80231
|
type: "text",
|
|
@@ -79978,7 +80258,7 @@ var FullCompaction = class {
|
|
|
79978
80258
|
}
|
|
79979
80259
|
this.agent.log.warn("compaction overflow at minimum split, falling back to re-summarize", {
|
|
79980
80260
|
compactedCount,
|
|
79981
|
-
tokensBefore: estimateTokensForMessages(messagesToCompact)
|
|
80261
|
+
tokensBefore: estimateTokensForMessages(this.agent.context.applyMessageEdits(messagesToCompact))
|
|
79982
80262
|
});
|
|
79983
80263
|
const result = await summarizeWithFallback(messagesToCompact, summarizeOnce);
|
|
79984
80264
|
summary = result.summary;
|
|
@@ -79999,6 +80279,7 @@ var FullCompaction = class {
|
|
|
79999
80279
|
return;
|
|
80000
80280
|
}
|
|
80001
80281
|
const recent = originalHistory.slice(compactedCount);
|
|
80282
|
+
const projectedRecent = this.agent.context.applyMessageEdits(recent);
|
|
80002
80283
|
const messagesToCompactForOps = originalHistory.slice(0, compactedCount);
|
|
80003
80284
|
const fileOps = createFileOps();
|
|
80004
80285
|
if (this.lastCompactionFiles !== void 0 && extractPreviousSummary(originalHistory) !== null) {
|
|
@@ -80009,11 +80290,12 @@ var FullCompaction = class {
|
|
|
80009
80290
|
const toolCallHistory = formatToolCallHistory(messagesToCompactForOps);
|
|
80010
80291
|
const skillCandidateSummary = summary;
|
|
80011
80292
|
const processedSummary = this.postProcessSummary(summary, fileOps, toolCallHistory, compactedCount);
|
|
80012
|
-
const tokensAfter = systemPromptTokens + toolTokens + estimateTokens$1(processedSummary) + estimateTokensForMessages(
|
|
80293
|
+
const tokensAfter = systemPromptTokens + toolTokens + estimateTokens$1(processedSummary) + estimateTokensForMessages(projectedRecent);
|
|
80013
80294
|
const fileLists = computeFileLists(fileOps);
|
|
80014
80295
|
const MAX_PERSISTED_FILES = 100;
|
|
80015
80296
|
const readFiles = fileLists.readFiles.slice(0, MAX_PERSISTED_FILES);
|
|
80016
80297
|
const modifiedFiles = fileLists.modifiedFiles.slice(0, MAX_PERSISTED_FILES);
|
|
80298
|
+
const firstKeptMessageId = originalHistory[compactedCount]?.id;
|
|
80017
80299
|
const result = {
|
|
80018
80300
|
summary: processedSummary,
|
|
80019
80301
|
compactedCount,
|
|
@@ -80021,7 +80303,8 @@ var FullCompaction = class {
|
|
|
80021
80303
|
tokensAfter,
|
|
80022
80304
|
...readFiles.length > 0 ? { readFiles } : {},
|
|
80023
80305
|
...modifiedFiles.length > 0 ? { modifiedFiles } : {},
|
|
80024
|
-
...isUpdate ? { isUpdate: true } : {}
|
|
80306
|
+
...isUpdate ? { isUpdate: true } : {},
|
|
80307
|
+
...firstKeptMessageId !== void 0 ? { firstKeptMessageId } : {}
|
|
80025
80308
|
};
|
|
80026
80309
|
this.markCompleted();
|
|
80027
80310
|
this.agent.emitEvent({
|
|
@@ -81734,6 +82017,16 @@ var ContextMemory = class {
|
|
|
81734
82017
|
pendingToolResultIds = /* @__PURE__ */ new Set();
|
|
81735
82018
|
deferredMessages = [];
|
|
81736
82019
|
/**
|
|
82020
|
+
* Persisted projection edits keyed by message id: `null` removes the
|
|
82021
|
+
* message from the projection, an array replaces its content. The raw
|
|
82022
|
+
* history is never modified — every LLM-bound read path funnels through
|
|
82023
|
+
* {@link applyMessageEdits}.
|
|
82024
|
+
*/
|
|
82025
|
+
_messageEdits = /* @__PURE__ */ new Map();
|
|
82026
|
+
/** Counter behind {@link assignMessageId}. Never reset: ids must stay
|
|
82027
|
+
* unique for the whole session lifetime, including across clear/undo. */
|
|
82028
|
+
_nextMessageId = 0;
|
|
82029
|
+
/**
|
|
81737
82030
|
* Per-message fingerprints captured from the last message list handed to
|
|
81738
82031
|
* the LLM via {@link messagesForLLM}. Used to measure prefix stability
|
|
81739
82032
|
* across calls: a provider prompt cache only hits when the leading
|
|
@@ -81755,7 +82048,8 @@ var ContextMemory = class {
|
|
|
81755
82048
|
tokenCountCoveredMessageCount: this.tokenCountCoveredMessageCount,
|
|
81756
82049
|
openSteps: new Map(this.openSteps),
|
|
81757
82050
|
pendingToolResultIds: new Set(this.pendingToolResultIds),
|
|
81758
|
-
deferredMessages: [...this.deferredMessages]
|
|
82051
|
+
deferredMessages: [...this.deferredMessages],
|
|
82052
|
+
messageEdits: new Map(this._messageEdits)
|
|
81759
82053
|
};
|
|
81760
82054
|
}
|
|
81761
82055
|
restore(snapshot) {
|
|
@@ -81765,6 +82059,9 @@ var ContextMemory = class {
|
|
|
81765
82059
|
this.openSteps = new Map(snapshot.openSteps);
|
|
81766
82060
|
this.pendingToolResultIds = new Set(snapshot.pendingToolResultIds);
|
|
81767
82061
|
this.deferredMessages = [...snapshot.deferredMessages];
|
|
82062
|
+
this._messageEdits = new Map(snapshot.messageEdits ?? []);
|
|
82063
|
+
for (const message of this._history) this.assignMessageId(message);
|
|
82064
|
+
for (const message of this.deferredMessages) this.assignMessageId(message);
|
|
81768
82065
|
}
|
|
81769
82066
|
/**
|
|
81770
82067
|
* JSON-safe snapshot for wire persistence. `openSteps` values are recorded as
|
|
@@ -81779,7 +82076,8 @@ var ContextMemory = class {
|
|
|
81779
82076
|
tokenCountCoveredMessageCount: this.tokenCountCoveredMessageCount,
|
|
81780
82077
|
openSteps: [...this.openSteps.entries()].map(([uuid, message]) => [uuid, this._history.indexOf(message)]),
|
|
81781
82078
|
pendingToolResultIds: [...this.pendingToolResultIds],
|
|
81782
|
-
deferredMessages: [...this.deferredMessages]
|
|
82079
|
+
deferredMessages: [...this.deferredMessages],
|
|
82080
|
+
...this._messageEdits.size > 0 ? { messageEdits: [...this._messageEdits.entries()] } : {}
|
|
81783
82081
|
};
|
|
81784
82082
|
}
|
|
81785
82083
|
/**
|
|
@@ -81801,6 +82099,9 @@ var ContextMemory = class {
|
|
|
81801
82099
|
this.openSteps = openSteps;
|
|
81802
82100
|
this.pendingToolResultIds = new Set(snapshot.pendingToolResultIds);
|
|
81803
82101
|
this.deferredMessages = [...snapshot.deferredMessages];
|
|
82102
|
+
this._messageEdits = new Map(snapshot.messageEdits ?? []);
|
|
82103
|
+
for (const message of this._history) this.assignMessageId(message);
|
|
82104
|
+
for (const message of this.deferredMessages) this.assignMessageId(message);
|
|
81804
82105
|
}
|
|
81805
82106
|
appendUserMessage(content, origin = USER_PROMPT_ORIGIN) {
|
|
81806
82107
|
this.appendMessage({
|
|
@@ -81830,6 +82131,7 @@ var ContextMemory = class {
|
|
|
81830
82131
|
this.openSteps.clear();
|
|
81831
82132
|
this.pendingToolResultIds.clear();
|
|
81832
82133
|
this.deferredMessages = [];
|
|
82134
|
+
this._messageEdits.clear();
|
|
81833
82135
|
this.lastSentFingerprints = [];
|
|
81834
82136
|
this.agent.injection.onContextClear();
|
|
81835
82137
|
this.agent.microCompaction.reset();
|
|
@@ -81898,7 +82200,7 @@ var ContextMemory = class {
|
|
|
81898
82200
|
type: "context.apply_compaction",
|
|
81899
82201
|
...summary
|
|
81900
82202
|
});
|
|
81901
|
-
|
|
82203
|
+
const summaryMessage = {
|
|
81902
82204
|
role: "assistant",
|
|
81903
82205
|
content: [{
|
|
81904
82206
|
type: "text",
|
|
@@ -81906,13 +82208,20 @@ var ContextMemory = class {
|
|
|
81906
82208
|
}],
|
|
81907
82209
|
toolCalls: [],
|
|
81908
82210
|
origin: { kind: "compaction_summary" }
|
|
81909
|
-
}
|
|
82211
|
+
};
|
|
82212
|
+
this.assignMessageId(summaryMessage);
|
|
82213
|
+
let cut = summary.compactedCount;
|
|
82214
|
+
if (summary.firstKeptMessageId !== void 0) {
|
|
82215
|
+
const byId = this._history.findIndex((m) => m.id === summary.firstKeptMessageId);
|
|
82216
|
+
if (byId >= 0) cut = byId;
|
|
82217
|
+
}
|
|
82218
|
+
this._history = [summaryMessage, ...this._history.slice(cut)];
|
|
81910
82219
|
const survivingMessages = new Set(this._history);
|
|
81911
82220
|
for (const [uuid, message] of this.openSteps) if (!survivingMessages.has(message)) this.openSteps.delete(uuid);
|
|
81912
82221
|
this.flushDeferredMessagesIfToolExchangeClosed();
|
|
81913
82222
|
this._tokenCount = summary.tokensAfter;
|
|
81914
82223
|
this.tokenCountCoveredMessageCount = this._history.length;
|
|
81915
|
-
this.agent.injection.onContextCompacted(
|
|
82224
|
+
this.agent.injection.onContextCompacted(cut);
|
|
81916
82225
|
this.agent.emitStatusUpdated();
|
|
81917
82226
|
this.agent.microCompaction.reset();
|
|
81918
82227
|
if (!this.agent.records.restoring) this.agent.records.logRecord({
|
|
@@ -81921,6 +82230,100 @@ var ContextMemory = class {
|
|
|
81921
82230
|
compactedHistory: [...this.agent.fullCompaction.compactedHistory]
|
|
81922
82231
|
});
|
|
81923
82232
|
}
|
|
82233
|
+
/**
|
|
82234
|
+
* Apply persisted projection edits to a message list: messages edited to
|
|
82235
|
+
* `null` are dropped; messages with a replacement get a *copy* carrying the
|
|
82236
|
+
* new content (a fresh object keeps the token-estimate WeakMap from
|
|
82237
|
+
* returning the stale count). Messages without an edit — and every message
|
|
82238
|
+
* when no edits exist — pass through unchanged.
|
|
82239
|
+
*
|
|
82240
|
+
* Only what the model sees is affected: the raw history (UI, export, trace,
|
|
82241
|
+
* resume) keeps the original content.
|
|
82242
|
+
*/
|
|
82243
|
+
applyMessageEdits(messages) {
|
|
82244
|
+
if (this._messageEdits.size === 0) return messages;
|
|
82245
|
+
const result = [];
|
|
82246
|
+
for (const message of messages) {
|
|
82247
|
+
const id = message.id;
|
|
82248
|
+
const edit = id === void 0 ? void 0 : this._messageEdits.get(id);
|
|
82249
|
+
if (edit === void 0) result.push(message);
|
|
82250
|
+
else if (edit !== null) result.push({
|
|
82251
|
+
...message,
|
|
82252
|
+
content: [...edit]
|
|
82253
|
+
});
|
|
82254
|
+
}
|
|
82255
|
+
return result;
|
|
82256
|
+
}
|
|
82257
|
+
/** Whether a persisted edit removes this message from the projection. */
|
|
82258
|
+
isMessageRemovedByEdit(message) {
|
|
82259
|
+
const id = message.id;
|
|
82260
|
+
return id !== void 0 && this._messageEdits.get(id) === null;
|
|
82261
|
+
}
|
|
82262
|
+
/**
|
|
82263
|
+
* Persist a projection edit for the message with `targetId`:
|
|
82264
|
+
* `replacement: null` removes the message from every future provider
|
|
82265
|
+
* request; an array replaces its content. The edit is recorded, so it
|
|
82266
|
+
* replays on resume and survives restarts; the raw history message is never
|
|
82267
|
+
* rewritten.
|
|
82268
|
+
*
|
|
82269
|
+
* Live writes validate strictly (the target must exist and be editable).
|
|
82270
|
+
* During replay the same method runs for records read from the wire and
|
|
82271
|
+
* silently skips targets that no longer exist (e.g. the message was
|
|
82272
|
+
* compacted away before the edit replayed) — a newer wire must never fail
|
|
82273
|
+
* to load.
|
|
82274
|
+
*/
|
|
82275
|
+
applyMessageEdit(targetId, replacement) {
|
|
82276
|
+
const index = this._history.findIndex((message) => message.id === targetId);
|
|
82277
|
+
const message = index === -1 ? this.deferredMessages.find((candidate) => candidate.id === targetId) : this._history[index];
|
|
82278
|
+
if (message === void 0) {
|
|
82279
|
+
if (this.agent.records.restoring) return;
|
|
82280
|
+
throw new Error(`context.edit_message: no message with id '${targetId}'`);
|
|
82281
|
+
}
|
|
82282
|
+
if (message.role === "system" || message.origin?.kind === "compaction_summary") {
|
|
82283
|
+
if (this.agent.records.restoring) return;
|
|
82284
|
+
throw new Error(`context.edit_message: message '${targetId}' is not editable`);
|
|
82285
|
+
}
|
|
82286
|
+
const previousEdit = this._messageEdits.get(targetId);
|
|
82287
|
+
const normalized = replacement === null ? null : replacement.map((part) => ({ ...part }));
|
|
82288
|
+
this._messageEdits.set(targetId, normalized);
|
|
82289
|
+
this.agent.records.logRecord({
|
|
82290
|
+
type: "context.edit_message",
|
|
82291
|
+
targetId,
|
|
82292
|
+
replacement: normalized
|
|
82293
|
+
});
|
|
82294
|
+
if (index !== -1 && index < this.tokenCountCoveredMessageCount) {
|
|
82295
|
+
const before = previousEdit === void 0 ? estimateTokensForMessages([message]) : previousEdit === null ? 0 : estimateTokensForMessages([{
|
|
82296
|
+
...message,
|
|
82297
|
+
content: [...previousEdit]
|
|
82298
|
+
}]);
|
|
82299
|
+
const after = normalized === null ? 0 : estimateTokensForMessages([{
|
|
82300
|
+
...message,
|
|
82301
|
+
content: normalized
|
|
82302
|
+
}]);
|
|
82303
|
+
this._tokenCount = Math.max(0, this._tokenCount + after - before);
|
|
82304
|
+
}
|
|
82305
|
+
this.agent.emitStatusUpdated();
|
|
82306
|
+
}
|
|
82307
|
+
/**
|
|
82308
|
+
* Assign a stable id the first time a message enters the history (or when
|
|
82309
|
+
* it is restored from the wire). Mutates the message in place — object
|
|
82310
|
+
* identity is load-bearing: open steps, deferred messages and the history
|
|
82311
|
+
* array all reference the same object. Messages that already carry an id
|
|
82312
|
+
* only advance the counter past it.
|
|
82313
|
+
*/
|
|
82314
|
+
assignMessageId(message) {
|
|
82315
|
+
const existing = message.id;
|
|
82316
|
+
if (existing !== void 0) {
|
|
82317
|
+
const match = /^m(\d+)$/.exec(existing);
|
|
82318
|
+
if (match !== null) {
|
|
82319
|
+
const n = Number(match[1]);
|
|
82320
|
+
if (n >= this._nextMessageId) this._nextMessageId = n + 1;
|
|
82321
|
+
}
|
|
82322
|
+
return;
|
|
82323
|
+
}
|
|
82324
|
+
message.id = `m${this._nextMessageId}`;
|
|
82325
|
+
this._nextMessageId += 1;
|
|
82326
|
+
}
|
|
81924
82327
|
data() {
|
|
81925
82328
|
return {
|
|
81926
82329
|
history: this.history,
|
|
@@ -81932,14 +82335,14 @@ var ContextMemory = class {
|
|
|
81932
82335
|
}
|
|
81933
82336
|
get tokenCountWithPending() {
|
|
81934
82337
|
const pendingMessages = this._history.slice(this.tokenCountCoveredMessageCount);
|
|
81935
|
-
return this._tokenCount + estimateTokensForMessages(project(pendingMessages));
|
|
82338
|
+
return this._tokenCount + estimateTokensForMessages(project(this.applyMessageEdits(pendingMessages)));
|
|
81936
82339
|
}
|
|
81937
82340
|
get history() {
|
|
81938
82341
|
return this._history;
|
|
81939
82342
|
}
|
|
81940
82343
|
get messages() {
|
|
81941
82344
|
this.agent.microCompaction.detect();
|
|
81942
|
-
return project(this.agent.microCompaction.compact(this.history));
|
|
82345
|
+
return project(this.applyMessageEdits(this.agent.microCompaction.compact(this.history)));
|
|
81943
82346
|
}
|
|
81944
82347
|
/**
|
|
81945
82348
|
* Build the message list for an LLM call, with prefix-stability
|
|
@@ -81961,7 +82364,7 @@ var ContextMemory = class {
|
|
|
81961
82364
|
*/
|
|
81962
82365
|
messagesForLLM() {
|
|
81963
82366
|
this.agent.microCompaction.detect();
|
|
81964
|
-
const messages = project(this.agent.microCompaction.compact(this.history), { synthesizeMissing: true });
|
|
82367
|
+
const messages = project(this.applyMessageEdits(this.agent.microCompaction.compact(this.history)), { synthesizeMissing: true });
|
|
81965
82368
|
this.observePrefixStability(messages);
|
|
81966
82369
|
return messages;
|
|
81967
82370
|
}
|
|
@@ -82054,6 +82457,7 @@ var ContextMemory = class {
|
|
|
82054
82457
|
}
|
|
82055
82458
|
}
|
|
82056
82459
|
appendMessage(message) {
|
|
82460
|
+
this.assignMessageId(message);
|
|
82057
82461
|
this.agent.records.logRecord({
|
|
82058
82462
|
type: "context.append_message",
|
|
82059
82463
|
message
|
|
@@ -82098,6 +82502,7 @@ var ContextMemory = class {
|
|
|
82098
82502
|
return interruptedToolCallIds.length;
|
|
82099
82503
|
}
|
|
82100
82504
|
pushHistory(...messages) {
|
|
82505
|
+
for (const message of messages) this.assignMessageId(message);
|
|
82101
82506
|
this._history.push(...messages);
|
|
82102
82507
|
for (const message of messages) {
|
|
82103
82508
|
if (message.origin?.kind === "background_task") this.agent.background.markDeliveredNotification(message.origin);
|
|
@@ -85363,7 +85768,11 @@ const WRITE_TOOLS = new Set([
|
|
|
85363
85768
|
"Write"
|
|
85364
85769
|
]);
|
|
85365
85770
|
/** Tools that execute commands. */
|
|
85366
|
-
const EXECUTE_TOOLS = new Set([
|
|
85771
|
+
const EXECUTE_TOOLS = new Set([
|
|
85772
|
+
"Bash",
|
|
85773
|
+
"python",
|
|
85774
|
+
"RunScript"
|
|
85775
|
+
]);
|
|
85367
85776
|
/** Nesting/coordination tools — only `all` mode keeps them. A restricted
|
|
85368
85777
|
* child must not be able to spawn an unrestricted grandchild (that would
|
|
85369
85778
|
* bypass the tool filtering entirely). WolfPack is batch-spawn sugar over
|
|
@@ -87370,6 +87779,7 @@ const SNAPSHOT_FOLDED_CONTEXT_TYPES = new Set([
|
|
|
87370
87779
|
"context.append_message",
|
|
87371
87780
|
"context.append_loop_event",
|
|
87372
87781
|
"context.apply_compaction",
|
|
87782
|
+
"context.edit_message",
|
|
87373
87783
|
"micro_compaction.apply",
|
|
87374
87784
|
"full_compaction.complete",
|
|
87375
87785
|
"request.header"
|
|
@@ -88140,9 +88550,9 @@ function asMediaContainer(value) {
|
|
|
88140
88550
|
/**
|
|
88141
88551
|
* Record types whose state is fully captured by a `context.snapshot` record.
|
|
88142
88552
|
* When a snapshot exists, every one of these that predates it is skipped during
|
|
88143
|
-
* replay because the snapshot already holds the folded context memory
|
|
88144
|
-
* `
|
|
88145
|
-
*
|
|
88553
|
+
* replay because the snapshot already holds the folded context memory —
|
|
88554
|
+
* including `context.edit_message`, whose edits ride inside the snapshot
|
|
88555
|
+
* payload (`messageEdits`).
|
|
88146
88556
|
*
|
|
88147
88557
|
* `full_compaction.complete` is included because its only lasting effect is
|
|
88148
88558
|
* pushing onto `compactedHistory` — a debug trail rendered from the pre-fold
|
|
@@ -88244,6 +88654,9 @@ function restoreAgentRecord(agent, input) {
|
|
|
88244
88654
|
agent.context.applyCompaction(input);
|
|
88245
88655
|
recoverMemosFromCompactionSummary(agent, input.summary);
|
|
88246
88656
|
return;
|
|
88657
|
+
case "context.edit_message":
|
|
88658
|
+
agent.context.applyMessageEdit(input.targetId, input.replacement);
|
|
88659
|
+
return;
|
|
88247
88660
|
case "context.snapshot":
|
|
88248
88661
|
agent.context.restoreJSONSnapshot(input.snapshot);
|
|
88249
88662
|
agent.fullCompaction.restoreCompactedHistory(input.compactedHistory);
|
|
@@ -96377,7 +96790,8 @@ async function prepareToolCall(step, call) {
|
|
|
96377
96790
|
toolCallId: call.toolCall.id,
|
|
96378
96791
|
toolName: call.toolName,
|
|
96379
96792
|
args: call.args,
|
|
96380
|
-
rawArguments: call.toolCall.arguments
|
|
96793
|
+
rawArguments: call.toolCall.arguments,
|
|
96794
|
+
nested: step.nested === true
|
|
96381
96795
|
});
|
|
96382
96796
|
} catch {
|
|
96383
96797
|
reminder = null;
|
|
@@ -96448,7 +96862,8 @@ async function runPrepareToolExecutionHook(step, call) {
|
|
|
96448
96862
|
turnId,
|
|
96449
96863
|
stepNumber: currentStep,
|
|
96450
96864
|
signal,
|
|
96451
|
-
llm
|
|
96865
|
+
llm,
|
|
96866
|
+
nested: step.nested === true
|
|
96452
96867
|
});
|
|
96453
96868
|
} catch (error) {
|
|
96454
96869
|
if (isAbortError$1(error) || signal.aborted) return {
|
|
@@ -96491,7 +96906,8 @@ async function runAuthorizeToolExecutionHook(step, call, args, execution) {
|
|
|
96491
96906
|
turnId,
|
|
96492
96907
|
stepNumber: currentStep,
|
|
96493
96908
|
signal,
|
|
96494
|
-
llm
|
|
96909
|
+
llm,
|
|
96910
|
+
nested: step.nested === true
|
|
96495
96911
|
});
|
|
96496
96912
|
} catch (error) {
|
|
96497
96913
|
if (isAbortError$1(error) || signal.aborted) return {
|
|
@@ -96545,7 +96961,8 @@ async function finalizePendingToolResult(step, pendingResult) {
|
|
|
96545
96961
|
turnId,
|
|
96546
96962
|
stepNumber: currentStep,
|
|
96547
96963
|
signal,
|
|
96548
|
-
llm
|
|
96964
|
+
llm,
|
|
96965
|
+
nested: step.nested === true
|
|
96549
96966
|
}) ?? pendingResult.result, pendingResult.toolName);
|
|
96550
96967
|
return {
|
|
96551
96968
|
...pendingResult,
|
|
@@ -96578,6 +96995,10 @@ async function executeTool(step, execution, toolCall, toolName, metadata) {
|
|
|
96578
96995
|
toolCallId: toolCall.id,
|
|
96579
96996
|
metadata,
|
|
96580
96997
|
signal,
|
|
96998
|
+
runNestedToolCall: {
|
|
96999
|
+
tools: (step.tools ?? []).filter((tool) => tool.name !== toolName),
|
|
97000
|
+
run: (request) => executeNestedToolCall(step, toolName, request)
|
|
97001
|
+
},
|
|
96581
97002
|
onUpdate: (update) => {
|
|
96582
97003
|
if (signal.aborted) return;
|
|
96583
97004
|
dispatchEvent({
|
|
@@ -96653,10 +97074,16 @@ function normalizeToolResult(r) {
|
|
|
96653
97074
|
const textJoined = r.output.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
96654
97075
|
output = textJoined.length > 0 ? textJoined : TOOL_OUTPUT_EMPTY;
|
|
96655
97076
|
}
|
|
97077
|
+
const nestedCalls = r.isError === true ? void 0 : r.nestedCalls;
|
|
97078
|
+
const nested = nestedCalls !== void 0 ? { nestedCalls } : {};
|
|
96656
97079
|
return r.isError === true ? {
|
|
96657
97080
|
output,
|
|
96658
|
-
isError: true
|
|
96659
|
-
|
|
97081
|
+
isError: true,
|
|
97082
|
+
...nested
|
|
97083
|
+
} : {
|
|
97084
|
+
output,
|
|
97085
|
+
...nested
|
|
97086
|
+
};
|
|
96660
97087
|
}
|
|
96661
97088
|
function makeToolResult(call, args, result) {
|
|
96662
97089
|
return {
|
|
@@ -96682,6 +97109,7 @@ function makeErrorToolResult(call, args, output) {
|
|
|
96682
97109
|
*/
|
|
96683
97110
|
async function dispatchToolCall(step, call, args, displayFields) {
|
|
96684
97111
|
const { toolCall, toolName } = call;
|
|
97112
|
+
if (step.nested === true) return;
|
|
96685
97113
|
const index = step.toolCallBlockIndex.value++;
|
|
96686
97114
|
await step.dispatchEvent({
|
|
96687
97115
|
type: "block.start",
|
|
@@ -96714,6 +97142,34 @@ async function dispatchToolCall(step, call, args, displayFields) {
|
|
|
96714
97142
|
blockType: "tool-call"
|
|
96715
97143
|
});
|
|
96716
97144
|
}
|
|
97145
|
+
/**
|
|
97146
|
+
* Run a tool call issued by *another tool* (the script sandbox) through the
|
|
97147
|
+
* same pipeline as model-issued calls: preflight validation → prepare and
|
|
97148
|
+
* authorize hooks (host hooks + approval) → `resolveExecution` → execution
|
|
97149
|
+
* with grace timeout → finalize/normalize.
|
|
97150
|
+
*
|
|
97151
|
+
* Only the model-visible recording is suppressed: no `block.start` /
|
|
97152
|
+
* `tool.call` / `tool.result` events are dispatched, so the orchestrating
|
|
97153
|
+
* tool's own result stays the single transcript entry for the whole batch.
|
|
97154
|
+
* Everything else — argument validation, hooks, approval, aborts and the
|
|
97155
|
+
* grace timeout — behaves exactly like a direct call.
|
|
97156
|
+
*/
|
|
97157
|
+
async function executeNestedToolCall(step, parentToolName, request) {
|
|
97158
|
+
const tools = (step.tools ?? []).filter((tool) => tool.name !== parentToolName);
|
|
97159
|
+
const toolCall = {
|
|
97160
|
+
type: "function",
|
|
97161
|
+
id: request.callId,
|
|
97162
|
+
name: request.name,
|
|
97163
|
+
arguments: JSON.stringify(request.args ?? {})
|
|
97164
|
+
};
|
|
97165
|
+
const nestedStep = {
|
|
97166
|
+
...step,
|
|
97167
|
+
tools,
|
|
97168
|
+
nested: true,
|
|
97169
|
+
dispatchEvent: async () => {}
|
|
97170
|
+
};
|
|
97171
|
+
return (await finalizePendingToolResult(nestedStep, await (await (await prepareToolCall(nestedStep, preflightToolCall(tools, toolCall))).task.start()).result)).result;
|
|
97172
|
+
}
|
|
96717
97173
|
//#endregion
|
|
96718
97174
|
//#region ../../packages/agent-core/src/loop/turn-step.ts
|
|
96719
97175
|
/**
|
|
@@ -101279,7 +101735,7 @@ function normalizeSourcePath(path) {
|
|
|
101279
101735
|
}
|
|
101280
101736
|
//#endregion
|
|
101281
101737
|
//#region ../../packages/agent-core/src/profile/default/agent.yaml
|
|
101282
|
-
var agent_default = "name: agent\ndescription: Default Scream Code agent\n\nsystemPromptPath: ./system.md\npromptVars:\n roleAdditional: ''\n\ntools:\n - Read\n - Write\n - Edit\n - Grep\n - Glob\n - Bash\n - LSP\n - TaskList\n - TaskOutput\n - TaskStop\n - CronCreate\n - CronList\n - CronDelete\n - CreateGoal\n - GetGoal\n - SetGoalBudget\n - UpdateGoal\n - ReadMediaFile\n - TodoList\n - MemoryLookup\n - MemoryConsolidatePlan\n - MemoryConsolidateApply\n - MemoryWrite\n - KnowledgeLookup\n # Image generation. Like ManagePlugin, registered for main agents only —\n # subagents inherit the name but never receive the tool.\n - ImageGenerate\n - InspectOwnAssets\n - Skill\n - MakeSkillPlan\n - MakeSkillApply\n # Main-agent capability management. Subagent profiles inherit this list, but\n # the tool is only registered for main agents, so it never reaches their\n # model-visible tool set.\n - ManagePlugin\n - WebSearch\n - PaperSearch\n - Agent\n - SendSubagentMessage\n - WolfPack\n\n - FetchURL\n - AskUserQuestion\n - EnterPlanMode\n - FusionPlan\n - ExitPlanMode\n - mcp__*\n\n# Routing text for the parent's `Agent` tool: the description is the \"what\",\n# the profile's own `whenToUse` supplies the \"call me when / do not call me\n# for\" triggers. Keep both short and trigger-shaped so all types stay\n# comparable when the model picks one. This map is the single source of truth:\n# system.md must not restate it.\nsubagents:\n coder:\n description: Edits files and runs commands for non-trivial engineering work, then reports a compact, technically complete summary.\n explore:\n description: Read-only reconnaissance across files; returns a structured map (summary, inventory, architecture) and never edits.\n plan:\n description: Read-only architect; turns a request into a step-by-step, file-level implementation plan with trade-offs.\n verify:\n description: Runs the project's real gates (build, test, lint, typecheck) and reports pass/fail with raw command evidence.\n reviewer:\n description: Adversarial review of a diff; reports bugs, contract violations and integration risk by severity.\n oracle:\n description: Large-scope review of code that already exists — architecture soundness, tech debt, long-term maintainability, dead or redundant code — with evidence and a concrete fix per finding; does not edit unless asked.\n worker:\n description: Office and document automation worker; format conversion, batch file processing and file organization, and never code or prose.\n writer:\n description: Professional writing and document specialist; drafts, rewrites, translates, summarizes and produces document artifacts.\n designer:\n description: 'Visual-layer specialist: UI/UX/TUI design direction, code-grade specs, screen polish, and design audits.'\n";
|
|
101738
|
+
var agent_default = "name: agent\ndescription: Default Scream Code agent\n\nsystemPromptPath: ./system.md\npromptVars:\n roleAdditional: ''\n\ntools:\n - Read\n - Write\n - Edit\n - Grep\n - Glob\n - Bash\n # Script execution mode (enabled by default): runs model-written JavaScript\n # in a QuickJS sandbox and calls the tools above from inside the script.\n # Toggle per session with /script. Main agent only — subagent profiles keep\n # their own restricted tool lists.\n - RunScript\n - LSP\n - TaskList\n - TaskOutput\n - TaskStop\n - CronCreate\n - CronList\n - CronDelete\n - CreateGoal\n - GetGoal\n - SetGoalBudget\n - UpdateGoal\n - ReadMediaFile\n - TodoList\n - MemoryLookup\n - MemoryConsolidatePlan\n - MemoryConsolidateApply\n - MemoryWrite\n - KnowledgeLookup\n # Image generation. Like ManagePlugin, registered for main agents only —\n # subagents inherit the name but never receive the tool.\n - ImageGenerate\n - InspectOwnAssets\n - Skill\n - MakeSkillPlan\n - MakeSkillApply\n # Main-agent capability management. Subagent profiles inherit this list, but\n # the tool is only registered for main agents, so it never reaches their\n # model-visible tool set.\n - ManagePlugin\n - WebSearch\n - PaperSearch\n - Agent\n - SendSubagentMessage\n - WolfPack\n\n - FetchURL\n - AskUserQuestion\n - EnterPlanMode\n - FusionPlan\n - ExitPlanMode\n - mcp__*\n\n# Routing text for the parent's `Agent` tool: the description is the \"what\",\n# the profile's own `whenToUse` supplies the \"call me when / do not call me\n# for\" triggers. Keep both short and trigger-shaped so all types stay\n# comparable when the model picks one. This map is the single source of truth:\n# system.md must not restate it.\nsubagents:\n coder:\n description: Edits files and runs commands for non-trivial engineering work, then reports a compact, technically complete summary.\n explore:\n description: Read-only reconnaissance across files; returns a structured map (summary, inventory, architecture) and never edits.\n plan:\n description: Read-only architect; turns a request into a step-by-step, file-level implementation plan with trade-offs.\n verify:\n description: Runs the project's real gates (build, test, lint, typecheck) and reports pass/fail with raw command evidence.\n reviewer:\n description: Adversarial review of a diff; reports bugs, contract violations and integration risk by severity.\n oracle:\n description: Large-scope review of code that already exists — architecture soundness, tech debt, long-term maintainability, dead or redundant code — with evidence and a concrete fix per finding; does not edit unless asked.\n worker:\n description: Office and document automation worker; format conversion, batch file processing and file organization, and never code or prose.\n writer:\n description: Professional writing and document specialist; drafts, rewrites, translates, summarizes and produces document artifacts.\n designer:\n description: 'Visual-layer specialist: UI/UX/TUI design direction, code-grade specs, screen polish, and design audits.'\n";
|
|
101283
101739
|
//#endregion
|
|
101284
101740
|
//#region ../../packages/agent-core/src/profile/default/coder.yaml
|
|
101285
101741
|
var coder_default = "extends: agent\nname: coder\npromptVars:\n roleAdditional: |\n You are now running as a subagent. All the `user` messages are sent by the main agent. The main agent cannot see your context, it can only see your last message when you finish the task. You must treat the parent agent as your caller. Do not directly ask the end user questions. If something is unclear, explain the ambiguity in your final summary to the parent agent.\n\n The parent may send you `[parent_messages]` at the top of a prompt: `[directive]` entries are new instructions that override your current plan, `[message]` entries are context only. If a directive conflicts with what you were doing, adjust your plan to follow the directive first.\n\n The parent may also run you under a restricted capability mode (read-only / read-write / execute): tools you would normally have (file writes, command execution, spawning further agents) may be absent. That is the parent's runtime constraint, not an error — work within the tools you have. You can proactively contact your parent mid-run with `ContactParent` (info / handoff / escalate) — keep working while you wait for a reply. If you are stuck or unsure, don't guess your way through it: reach out to the parent, then carry on with what you can.\nwhenToUse: >-\n USE WHEN: the task needs files edited or commands run in the workspace, spans more than ~3 files, or is mechanical multi-file propagation (rename, migration, type sweep). NOT FOR: read-only investigation (explore), planning (plan), verification-only requests on code you did not change (verify), reviewing a diff (reviewer).\ntools:\n - ContactParent\n - Bash\n - Read\n - ReadMediaFile\n - Glob\n - Grep\n - Write\n - Edit\n - LSP\n - WebSearch\n - PaperSearch\n - FetchURL\n - MemoryLookup\n - MemoryConsolidatePlan\n - MemoryConsolidateApply\n - mcp__*\n";
|
|
@@ -102309,7 +102765,22 @@ var ToolManager = class {
|
|
|
102309
102765
|
loopToolsFor(filter) {
|
|
102310
102766
|
const mcpNames = [...this.mcpTools.keys()].filter((name) => filter.mcpPatterns.some((pattern) => import_picomatch.default.isMatch(name, pattern)));
|
|
102311
102767
|
const hideGoalMutationTools = this.agent.goal.getGoal().goal === null;
|
|
102312
|
-
|
|
102768
|
+
const tools = uniq([...filter.names, ...mcpNames]).toSorted((a, b) => a.localeCompare(b)).filter((name) => !(hideGoalMutationTools && (name === "SetGoalBudget" || name === "UpdateGoal" || name === "WriteGoalNote"))).map((name) => this.userTools.get(name) ?? this.mcpTools.get(name)?.tool ?? this.builtinTools.get(name)).filter((tool) => !!tool);
|
|
102769
|
+
return this.decorateScriptOffering(tools);
|
|
102770
|
+
}
|
|
102771
|
+
/**
|
|
102772
|
+
* The script sandbox advertises exactly the tools a script may call, so its
|
|
102773
|
+
* description is rebuilt against this step's offered set (the class-level
|
|
102774
|
+
* description is the empty-set fallback). Matches the built-in instance by
|
|
102775
|
+
* identity on purpose: a user tool that happens to reuse the name must not
|
|
102776
|
+
* be re-decorated or lose its own description.
|
|
102777
|
+
*/
|
|
102778
|
+
decorateScriptOffering(tools) {
|
|
102779
|
+
const scriptTool = this.builtinTools.get(SCRIPT_TOOL_NAME);
|
|
102780
|
+
if (scriptTool === void 0 || !tools.includes(scriptTool)) return tools;
|
|
102781
|
+
const callable = tools.filter((tool) => tool !== scriptTool);
|
|
102782
|
+
const decorated = Object.assign(Object.create(Object.getPrototypeOf(scriptTool)), scriptTool, { description: buildScriptToolDescription(callable) });
|
|
102783
|
+
return tools.map((tool) => tool === scriptTool ? decorated : tool);
|
|
102313
102784
|
}
|
|
102314
102785
|
*toolInfos() {
|
|
102315
102786
|
for (const tool of this.builtinTools.values()) yield {
|
|
@@ -102364,6 +102835,7 @@ var ToolManager = class {
|
|
|
102364
102835
|
availableTools: this.enabledTools
|
|
102365
102836
|
}),
|
|
102366
102837
|
new PythonTool(cwd, { hostHandlers: createRlmHostHandlers(this.agent) }),
|
|
102838
|
+
new ScriptTool(this.toolStore),
|
|
102367
102839
|
(modelCapabilities.image_in || modelCapabilities.video_in) && new ReadMediaFileTool(jian, workspace, modelCapabilities, videoUploader),
|
|
102368
102840
|
new EnterPlanModeTool(this.agent),
|
|
102369
102841
|
new ExitPlanModeTool(this.agent),
|
|
@@ -102535,7 +103007,8 @@ function mapLoopEvent(event, turnId) {
|
|
|
102535
103007
|
output: event.result.output,
|
|
102536
103008
|
isError: event.result.isError,
|
|
102537
103009
|
display: event.result.isError === true ? void 0 : event.result.display,
|
|
102538
|
-
message: event.result.message
|
|
103010
|
+
message: event.result.message,
|
|
103011
|
+
nestedCalls: event.result.isError === true ? void 0 : event.result.nestedCalls
|
|
102539
103012
|
};
|
|
102540
103013
|
case "turn.interrupted":
|
|
102541
103014
|
if (event.activeStep === void 0) return void 0;
|
|
@@ -103480,6 +103953,7 @@ var TurnFlow = class {
|
|
|
103480
103953
|
return { continue: false };
|
|
103481
103954
|
},
|
|
103482
103955
|
prepareToolExecution: async (ctx) => {
|
|
103956
|
+
if (ctx.nested === true) return void 0;
|
|
103483
103957
|
const cached = deduper.checkSameStep(ctx.toolCall.id, ctx.toolCall.name, ctx.args);
|
|
103484
103958
|
if (cached !== null) return { syntheticResult: cached };
|
|
103485
103959
|
if (ctx.toolCall.name === "Bash" && typeof ctx.args.command === "string") {
|
|
@@ -103495,9 +103969,9 @@ var TurnFlow = class {
|
|
|
103495
103969
|
authorizeToolExecution: async (ctx) => {
|
|
103496
103970
|
return this.agent.permission.beforeToolCall(ctx);
|
|
103497
103971
|
},
|
|
103498
|
-
onToolCallRejected: async ({ toolCallId, toolName, args, rawArguments }) => deduper.registerSkipped(toolCallId, toolName, args, rawArguments),
|
|
103972
|
+
onToolCallRejected: async ({ toolCallId, toolName, args, rawArguments, nested }) => nested === true ? void 0 : deduper.registerSkipped(toolCallId, toolName, args, rawArguments),
|
|
103499
103973
|
finalizeToolResult: async (ctx) => {
|
|
103500
|
-
const finalResult = await deduper.finalizeResult(ctx.toolCall.id, ctx.toolCall.name, ctx.args, ctx.result);
|
|
103974
|
+
const finalResult = ctx.nested === true ? ctx.result : await deduper.finalizeResult(ctx.toolCall.id, ctx.toolCall.name, ctx.args, ctx.result);
|
|
103501
103975
|
const { isError, output } = finalResult;
|
|
103502
103976
|
this.agent.sessionMemory.recordToolExecution(ctx.toolCall.name, summarizeToolArgs(ctx.args), isError === true, ctx.stepNumber);
|
|
103503
103977
|
this.recordWorkingSetPaths(ctx.toolCall.name, ctx.args, Number(ctx.turnId));
|
|
@@ -104242,6 +104716,29 @@ var Agent = class {
|
|
|
104242
104716
|
return this.rlmEnabled;
|
|
104243
104717
|
}
|
|
104244
104718
|
/**
|
|
104719
|
+
* Enables or disables the script execution mode (`undefined` toggles) and
|
|
104720
|
+
* returns the resulting state. On enable, the `RunScript` tool joins the
|
|
104721
|
+
* active tools; on disable it is removed.
|
|
104722
|
+
*
|
|
104723
|
+
* The main agent's profile enables `RunScript` by default, so the agent-level
|
|
104724
|
+
* default (not in the active list) only applies to callers that build their
|
|
104725
|
+
* own tool list. No dedicated enter/exit record is needed (unlike RLM): the
|
|
104726
|
+
* tool list itself is replayed from `tools.set_active_tools`, so resume
|
|
104727
|
+
* restores the state automatically.
|
|
104728
|
+
*/
|
|
104729
|
+
setScriptEnabled(enabled) {
|
|
104730
|
+
const current = this.tools.getActiveTools();
|
|
104731
|
+
const next = enabled ?? !current.includes("RunScript");
|
|
104732
|
+
if (next) {
|
|
104733
|
+
if (!current.includes("RunScript")) this.tools.setActiveTools([...current, "RunScript"]);
|
|
104734
|
+
} else {
|
|
104735
|
+
const withoutScript = current.filter((name) => name !== "RunScript");
|
|
104736
|
+
if (withoutScript.length !== current.length) this.tools.setActiveTools(withoutScript);
|
|
104737
|
+
}
|
|
104738
|
+
this.emitStatusUpdated();
|
|
104739
|
+
return next;
|
|
104740
|
+
}
|
|
104741
|
+
/**
|
|
104245
104742
|
* Lets a subagent inherit RLM mode from its parent at spawn time: mounts
|
|
104246
104743
|
* the python tool (so the child can keep recursing) and records rlm.enter,
|
|
104247
104744
|
* mirroring setRlmEnabled(true). The rlm.enter record keeps enter/exit
|
|
@@ -104494,6 +104991,7 @@ var Agent = class {
|
|
|
104494
104991
|
setRlmEnabled: (payload) => {
|
|
104495
104992
|
this.setRlmEnabled(payload.enabled);
|
|
104496
104993
|
},
|
|
104994
|
+
setScriptEnabled: (payload) => this.setScriptEnabled(payload.enabled),
|
|
104497
104995
|
setRlmMaxDepth: (payload) => {
|
|
104498
104996
|
this.setRlmMaxDepth(payload.maxDepth);
|
|
104499
104997
|
},
|
|
@@ -125954,6 +126452,9 @@ var SessionAPIImpl = class {
|
|
|
125954
126452
|
setRlmEnabled({ agentId, ...payload }) {
|
|
125955
126453
|
return this.getAgent(agentId).setRlmEnabled(payload);
|
|
125956
126454
|
}
|
|
126455
|
+
setScriptEnabled({ agentId, ...payload }) {
|
|
126456
|
+
return this.getAgent(agentId).setScriptEnabled(payload);
|
|
126457
|
+
}
|
|
125957
126458
|
setRlmMaxDepth({ agentId, ...payload }) {
|
|
125958
126459
|
return this.getAgent(agentId).setRlmMaxDepth(payload);
|
|
125959
126460
|
}
|
|
@@ -126965,6 +127466,9 @@ var ScreamCore = class {
|
|
|
126965
127466
|
setRlmEnabled({ sessionId, ...payload }) {
|
|
126966
127467
|
return this.sessionApi(sessionId).setRlmEnabled(payload);
|
|
126967
127468
|
}
|
|
127469
|
+
setScriptEnabled({ sessionId, ...payload }) {
|
|
127470
|
+
return this.sessionApi(sessionId).setScriptEnabled(payload);
|
|
127471
|
+
}
|
|
126968
127472
|
setRlmMaxDepth({ sessionId, ...payload }) {
|
|
126969
127473
|
return this.sessionApi(sessionId).setRlmMaxDepth(payload);
|
|
126970
127474
|
}
|
|
@@ -128045,6 +128549,13 @@ var SDKRpcClient = class {
|
|
|
128045
128549
|
enabled: input.enabled
|
|
128046
128550
|
});
|
|
128047
128551
|
}
|
|
128552
|
+
async setScriptEnabled(input) {
|
|
128553
|
+
return (await this.getRpc()).setScriptEnabled({
|
|
128554
|
+
sessionId: input.sessionId,
|
|
128555
|
+
agentId: this.interactiveAgentId,
|
|
128556
|
+
enabled: input.enabled
|
|
128557
|
+
});
|
|
128558
|
+
}
|
|
128048
128559
|
async setRlmMaxDepth(input) {
|
|
128049
128560
|
return (await this.getRpc()).setRlmMaxDepth({
|
|
128050
128561
|
sessionId: input.sessionId,
|
|
@@ -128501,6 +129012,20 @@ var Session = class {
|
|
|
128501
129012
|
enabled
|
|
128502
129013
|
});
|
|
128503
129014
|
}
|
|
129015
|
+
/**
|
|
129016
|
+
* Enables or disables the `/script` execution mode (no argument toggles)
|
|
129017
|
+
* and resolves to the resulting state. When enabled, the `RunScript` tool
|
|
129018
|
+
* (QuickJS sandbox that batches tool calls) joins the active tools; when
|
|
129019
|
+
* disabled it is removed. The main agent starts with it enabled
|
|
129020
|
+
* (`profile/default/agent.yaml`).
|
|
129021
|
+
*/
|
|
129022
|
+
async setScriptEnabled(enabled) {
|
|
129023
|
+
this.ensureOpen();
|
|
129024
|
+
return this.rpc.setScriptEnabled({
|
|
129025
|
+
sessionId: this.id,
|
|
129026
|
+
enabled
|
|
129027
|
+
});
|
|
129028
|
+
}
|
|
128504
129029
|
/** Sets the maximum RLM recursion depth (default 1). Depth 1 means the root
|
|
128505
129030
|
* kernel may spawn rlm() children but they cannot spawn grandchildren. */
|
|
128506
129031
|
async setRlmMaxDepth(maxDepth) {
|
|
@@ -129674,6 +130199,13 @@ const BUILTIN_SLASH_COMMANDS = [
|
|
|
129674
130199
|
priority: 215,
|
|
129675
130200
|
availability: "always"
|
|
129676
130201
|
},
|
|
130202
|
+
{
|
|
130203
|
+
name: "script",
|
|
130204
|
+
aliases: ["script"],
|
|
130205
|
+
description: "registry.script_desc",
|
|
130206
|
+
priority: 214,
|
|
130207
|
+
availability: "always"
|
|
130208
|
+
},
|
|
129677
130209
|
{
|
|
129678
130210
|
name: "rlm-max-depth",
|
|
129679
130211
|
aliases: [],
|
|
@@ -135099,6 +135631,27 @@ async function handleRlmCommand(host, args) {
|
|
|
135099
135631
|
host.showError(`Failed to set rlm mode: ${msg}`);
|
|
135100
135632
|
}
|
|
135101
135633
|
}
|
|
135634
|
+
/** /script [on|off] — toggle the script execution mode (sandboxed batch tool). */
|
|
135635
|
+
async function handleScriptCommand(host, args) {
|
|
135636
|
+
const session = host.session;
|
|
135637
|
+
if (session === void 0) {
|
|
135638
|
+
host.showError(getNoActiveSessionMessage());
|
|
135639
|
+
return;
|
|
135640
|
+
}
|
|
135641
|
+
const subcmd = args.trim().toLowerCase();
|
|
135642
|
+
if (subcmd !== "" && subcmd !== "on" && subcmd !== "off") {
|
|
135643
|
+
host.showError("Usage: /script [on|off]");
|
|
135644
|
+
return;
|
|
135645
|
+
}
|
|
135646
|
+
const requested = subcmd === "" ? void 0 : subcmd === "on";
|
|
135647
|
+
try {
|
|
135648
|
+
const enabled = await session.setScriptEnabled(requested);
|
|
135649
|
+
host.showNotice(t(enabled ? "config.script_on" : "config.script_off"));
|
|
135650
|
+
} catch (error) {
|
|
135651
|
+
const msg = formatErrorMessage(error);
|
|
135652
|
+
host.showError(`Failed to set script mode: ${msg}`);
|
|
135653
|
+
}
|
|
135654
|
+
}
|
|
135102
135655
|
/** /rlm-max-depth [N] — query or set the maximum RLM recursion depth.
|
|
135103
135656
|
* N=0 or no limit means unlimited (the default). */
|
|
135104
135657
|
async function handleRlmMaxDepthCommand(host, args) {
|
|
@@ -136367,7 +136920,7 @@ async function guidedGoalSetup(host) {
|
|
|
136367
136920
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
136368
136921
|
return;
|
|
136369
136922
|
}
|
|
136370
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
136923
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DcjQLJFz.mjs");
|
|
136371
136924
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
136372
136925
|
title: t("goal.setup_title_initial"),
|
|
136373
136926
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -136388,7 +136941,7 @@ async function guidedGoalSetup(host) {
|
|
|
136388
136941
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
136389
136942
|
}
|
|
136390
136943
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
136391
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
136944
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-DcjQLJFz.mjs");
|
|
136392
136945
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
136393
136946
|
title: t("goal.wizard_title", { objective }),
|
|
136394
136947
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -137579,11 +138132,12 @@ const BRANCH_PIPE = " │ ";
|
|
|
137579
138132
|
const TREE_PIPE_ROW = " │";
|
|
137580
138133
|
const THINKING_BODY_PREFIX = " ";
|
|
137581
138134
|
/**
|
|
137582
|
-
* Extra indent
|
|
137583
|
-
* line-number gutter (` 1 /**`), so
|
|
137584
|
-
*
|
|
138135
|
+
* Extra indent shared by every body row of a block. File and diff bodies
|
|
138136
|
+
* reserve three cells for their line-number gutter (` 1 /**`), so tool
|
|
138137
|
+
* bodies, reasoning rows and hints all start at that same content column
|
|
138138
|
+
* instead of sitting three cells to its left.
|
|
137585
138139
|
*/
|
|
137586
|
-
const
|
|
138140
|
+
const BODY_TEXT_INDENT = " ";
|
|
137587
138141
|
/** Cells of a background task notice bullet (`⠋ ` / `✓ ` / `✗ `). */
|
|
137588
138142
|
const NOTICE_BULLET_WIDTH = 2;
|
|
137589
138143
|
const THROTTLE_MS = 200;
|
|
@@ -138053,7 +138607,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
138053
138607
|
}
|
|
138054
138608
|
if (hidden > 0) {
|
|
138055
138609
|
const summary = t("activitygroup.segments_hidden", { count: String(hidden) });
|
|
138056
|
-
this.bodyContainer.addChild(new Text(`${BRANCH_PIPE}${chalk.dim(summary)}`, 0, 0));
|
|
138610
|
+
this.bodyContainer.addChild(new Text(`${BRANCH_PIPE}${BODY_TEXT_INDENT}${chalk.dim(summary)}`, 0, 0));
|
|
138057
138611
|
}
|
|
138058
138612
|
}
|
|
138059
138613
|
/** Renders one step of the timeline: its branch row plus its own body rows. */
|
|
@@ -138062,7 +138616,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
138062
138616
|
const row = this.toolRow(segment.tc, width, getActivityLines().expandedTool, !this.running);
|
|
138063
138617
|
const components = [new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${this.statusGlyph(row)} ${row.header}`, 0, 0)];
|
|
138064
138618
|
const continuation = isLast ? THINKING_BODY_PREFIX : BRANCH_PIPE;
|
|
138065
|
-
for (const line of row.body) components.push(new Text(`${continuation}${line}`, 0, 0));
|
|
138619
|
+
for (const line of row.body) components.push(new Text(`${continuation}${BODY_TEXT_INDENT}${line}`, 0, 0));
|
|
138066
138620
|
return {
|
|
138067
138621
|
components,
|
|
138068
138622
|
cost: 1 + row.body.length
|
|
@@ -138111,7 +138665,7 @@ var ActivityGroupComponent = class extends Container {
|
|
|
138111
138665
|
const components = [new Text(`${isLast ? BRANCH_LAST : BRANCH_FIRST}${this.thinkingGlyph(segment)}${chalk.hex(colors.roleThinking)(t("activitygroup.thinking_label"))}`, 0, 0)];
|
|
138112
138666
|
let cost = 1;
|
|
138113
138667
|
const budget = getActivityLines().expandedThinking;
|
|
138114
|
-
const textPrefix = `${continuation}${
|
|
138668
|
+
const textPrefix = `${continuation}${BODY_TEXT_INDENT}`;
|
|
138115
138669
|
const inner = Math.max(1, width - visibleWidth(textPrefix));
|
|
138116
138670
|
const height = (line) => new WrappedLine(textPrefix, textPrefix, line).render(inner).length;
|
|
138117
138671
|
let selected = segment.live ? lines.slice(-budget) : lines.slice(0, budget);
|
|
@@ -148080,6 +148634,9 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
148080
148634
|
case "rlm":
|
|
148081
148635
|
await handleRlmCommand(host, args);
|
|
148082
148636
|
return;
|
|
148637
|
+
case "script":
|
|
148638
|
+
await handleScriptCommand(host, args);
|
|
148639
|
+
return;
|
|
148083
148640
|
case "rlm-max-depth":
|
|
148084
148641
|
await handleRlmMaxDepthCommand(host, args);
|
|
148085
148642
|
return;
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { rn as handleConnectCommand } from "./dispatch-
|
|
6
|
+
import { rn as handleConnectCommand } from "./dispatch-DFFuylzQ.mjs";
|
|
7
7
|
export { handleConnectCommand };
|
package/dist/main.mjs
CHANGED
|
@@ -6,7 +6,7 @@ const __dirname = __cjsShimDirname(__filename);
|
|
|
6
6
|
import "./suppress-sqlite-warning-C2VB0doZ.mjs";
|
|
7
7
|
//#region src/main.ts
|
|
8
8
|
try {
|
|
9
|
-
(await import("./app-
|
|
9
|
+
(await import("./app-y8MJHp3H.mjs")).main();
|
|
10
10
|
} catch (error) {
|
|
11
11
|
process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`);
|
|
12
12
|
process.exit(1);
|
|
@@ -1171,6 +1171,8 @@ const dictionaries = {
|
|
|
1171
1171
|
"config.ask_already_on": "ASK 模式已开启",
|
|
1172
1172
|
"config.ask_already_off": "ASK 模式已关闭",
|
|
1173
1173
|
"config.rlm_on": "RLM 模式已开启 — 持久化 Python 内核可用",
|
|
1174
|
+
"config.script_on": "脚本模式已开启 — RunScript 可在沙箱中批量调用工具",
|
|
1175
|
+
"config.script_off": "脚本模式已关闭 — RunScript 已从工具中移除",
|
|
1174
1176
|
"config.rlm_off": "RLM 模式已关闭",
|
|
1175
1177
|
"config.rlm_usage": "用法: /rlm (切换) | /rlm on | /rlm off",
|
|
1176
1178
|
"config.auto_already_on": "自动模式已开启",
|
|
@@ -1221,6 +1223,7 @@ const dictionaries = {
|
|
|
1221
1223
|
"registry.bot_desc": "切换无人值守 Bot 模式(bot)",
|
|
1222
1224
|
"registry.ask_desc": "切换至只读问答模式(ask)",
|
|
1223
1225
|
"registry.rlm_desc": "RLM 模式:面向长任务的持久 Python 工作环境,支持无限递归子代理(/rlm 切换开关)",
|
|
1226
|
+
"registry.script_desc": "脚本模式:在沙箱中运行 JavaScript 批量调用工具(/script 切换)",
|
|
1224
1227
|
"registry.rlm_max_depth_desc": "设置 RLM 递归深度上限(/rlm-max-depth N)",
|
|
1225
1228
|
"registry.wolfpack_desc": "切换群狼协作模式,自动批准+批量并发",
|
|
1226
1229
|
"registry.sessions_desc": "浏览并恢复会话",
|
|
@@ -2478,6 +2481,8 @@ const dictionaries = {
|
|
|
2478
2481
|
"config.ask_already_on": "ASK mode is already on",
|
|
2479
2482
|
"config.ask_already_off": "ASK mode is already off",
|
|
2480
2483
|
"config.rlm_on": "RLM mode enabled — persistent python kernel available",
|
|
2484
|
+
"config.script_on": "Script mode enabled — RunScript can batch tool calls from a sandbox",
|
|
2485
|
+
"config.script_off": "Script mode disabled — RunScript removed from the tools",
|
|
2481
2486
|
"config.rlm_off": "RLM mode disabled",
|
|
2482
2487
|
"config.rlm_usage": "Usage: /rlm (toggle) | /rlm on | /rlm off",
|
|
2483
2488
|
"config.auto_already_on": "Auto mode is already on",
|
|
@@ -2528,6 +2533,7 @@ const dictionaries = {
|
|
|
2528
2533
|
"registry.bot_desc": "Toggle unattended bot mode (bot)",
|
|
2529
2534
|
"registry.ask_desc": "Toggle read-only Q&A mode (ask)",
|
|
2530
2535
|
"registry.rlm_desc": "RLM mode: a persistent Python workspace for long-running tasks with unlimited recursive subagents (/rlm toggles)",
|
|
2536
|
+
"registry.script_desc": "Script mode: run JavaScript in a sandbox that batches tool calls (/script toggles)",
|
|
2531
2537
|
"registry.rlm_max_depth_desc": "Set RLM recursion depth limit (/rlm-max-depth N)",
|
|
2532
2538
|
"registry.wolfpack_desc": "Toggle wolfpack mode, auto-approve + batch concurrency",
|
|
2533
2539
|
"registry.sessions_desc": "Browse and restore sessions",
|
|
@@ -3,5 +3,5 @@ import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
|
3
3
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
4
4
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __cjsShimDirname(__filename);
|
|
6
|
-
import { t as TextInputDialogComponent } from "./text-input-dialog-
|
|
6
|
+
import { t as TextInputDialogComponent } from "./text-input-dialog-CD0sakGq.mjs";
|
|
7
7
|
export { TextInputDialogComponent };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scream-code",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.6",
|
|
4
4
|
"description": "A terminal-native AI agent for builders",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ScreamCli",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"smoke": "node dist/main.mjs --version"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
+
"@earendil-works/pi-codemode": "0.99.1",
|
|
58
59
|
"@fontsource-variable/inter": "^5.3.0",
|
|
59
60
|
"@fontsource-variable/jetbrains-mono": "^5.3.0",
|
|
60
61
|
"@liutod-scream/pi-tui": "^0.87.1",
|