scream-code 0.19.6 → 0.19.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{app-CE9aji1S.mjs → app-Bpl0l99M.mjs} +22 -5
- package/dist/{dispatch-XPKo0cQR.mjs → dispatch-BiOeRj_C.mjs} +952 -260
- package/dist/{dispatch-DNYdiEo4.mjs → dispatch-d_R8-8sn.mjs} +1 -1
- package/dist/main.mjs +1 -1
- package/dist/{text-input-dialog-CbYhsAbz.mjs → text-input-dialog-BLUlZjUL.mjs} +1 -1
- package/dist/{text-input-dialog-BqMy3ifH.mjs → text-input-dialog-Ce2AEFU9.mjs} +2 -0
- package/docs/plugins.md +16 -1
- package/package.json +2 -2
|
@@ -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 sharedMemoStore, B as buildProjectTagCloud, C as applyConsolidation, D as parseMemoryMemos, E as buildExitExtractionPrompt, F as probeLocalEmbeddingSupport, G as join$1, H as basename$1, I as createMemoryMemo, J as relative$1, K as normalize, L as toSummary, M as clearEmbeddingModelCache, N as createEmbeddingEngine, O as stripMemoryTags, P as hasEmbeddingModelCache$1, R as generateTags, S as DreamTracker, T as EXIT_EXTRACTION_SYSTEM_PROMPT, U as dirname$2, V as rankMemos, W as isAbsolute$1, Y as resolve$2, a as isSupportedFile, b as sharedKnowledgeStoreReady, i as ingestFile, j as classifyEmbeddingFailure, k as MemoryMemoStore, q as parse$7, r as ingestDirectory, t as multiSearch, w as buildConsolidationPlan, y as sharedKnowledgeStore, z as normalizeTags } from "./src-Cu3sUIJK.mjs";
|
|
8
8
|
import { n as require_base64_js, t as XMLParser } from "./XMLParser-DFAnGqkc.mjs";
|
|
9
|
-
import { a as assertScreamHostIdentity, i as t, n as getLocale, o as createScreamDefaultHeaders, r as setLocale, t as TextInputDialogComponent } from "./text-input-dialog-
|
|
9
|
+
import { a as assertScreamHostIdentity, i as t, n as getLocale, o as createScreamDefaultHeaders, r as setLocale, t as TextInputDialogComponent } from "./text-input-dialog-Ce2AEFU9.mjs";
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { createCipheriv, createDecipheriv, createHash, randomBytes, randomInt, randomUUID } from "node:crypto";
|
|
12
12
|
import * as fs$1 from "node:fs/promises";
|
|
@@ -8711,6 +8711,8 @@ function normalizeAnthropicStopReason(raw) {
|
|
|
8711
8711
|
}
|
|
8712
8712
|
}
|
|
8713
8713
|
const INTERLEAVED_THINKING_BETA = "interleaved-thinking-2025-05-14";
|
|
8714
|
+
/** Required by Anthropic for `cache_control.ttl: '1h'` breakpoints. */
|
|
8715
|
+
const EXTENDED_CACHE_TTL_BETA = "extended-cache-ttl-2025-04-11";
|
|
8714
8716
|
const FAMILY_VERSION_RE = /(?:opus|sonnet|haiku)[.-](\d+)[.-](\d{1,2})(?!\d)/;
|
|
8715
8717
|
const OPUS_VERSION_RE = /opus[.-](\d+)[.-](\d{1,2})(?!\d)/;
|
|
8716
8718
|
const ADAPTIVE_MIN_VERSION = {
|
|
@@ -8869,7 +8871,11 @@ const ANTHROPIC_TOOL_CALL_ID_POLICY = {
|
|
|
8869
8871
|
normalize: (id) => sanitizeToolCallId(id, 64),
|
|
8870
8872
|
maxLength: 64
|
|
8871
8873
|
};
|
|
8872
|
-
const
|
|
8874
|
+
const CACHE_CONTROL_SHORT = { type: "ephemeral" };
|
|
8875
|
+
const CACHE_CONTROL_LONG = {
|
|
8876
|
+
type: "ephemeral",
|
|
8877
|
+
ttl: "1h"
|
|
8878
|
+
};
|
|
8873
8879
|
/**
|
|
8874
8880
|
* Content block types that support cache_control injection.
|
|
8875
8881
|
*/
|
|
@@ -8883,22 +8889,22 @@ const CACHEABLE_TYPES = new Set([
|
|
|
8883
8889
|
"server_tool_use",
|
|
8884
8890
|
"web_search_tool_result"
|
|
8885
8891
|
]);
|
|
8886
|
-
function injectCacheControlOnLastBlock(messages, messageIndex) {
|
|
8892
|
+
function injectCacheControlOnLastBlock(messages, cacheControl, messageIndex) {
|
|
8887
8893
|
const message = messages[messageIndex ?? messages.length - 1];
|
|
8888
8894
|
if (message === void 0) return;
|
|
8889
8895
|
const content = message.content;
|
|
8890
8896
|
if (!Array.isArray(content) || content.length === 0) return;
|
|
8891
8897
|
const lastBlock = content.at(-1);
|
|
8892
8898
|
if (lastBlock === void 0) return;
|
|
8893
|
-
if (CACHEABLE_TYPES.has(lastBlock.type)) lastBlock.cache_control =
|
|
8899
|
+
if (CACHEABLE_TYPES.has(lastBlock.type)) lastBlock.cache_control = cacheControl;
|
|
8894
8900
|
}
|
|
8895
8901
|
/**
|
|
8896
8902
|
* Inject cache_control on the last block of the second-to-last message,
|
|
8897
8903
|
* when there is enough budget for an extra breakpoint.
|
|
8898
8904
|
*/
|
|
8899
|
-
function injectCacheControlOnPenultimateMessage(messages) {
|
|
8905
|
+
function injectCacheControlOnPenultimateMessage(messages, cacheControl) {
|
|
8900
8906
|
if (messages.length < 2) return;
|
|
8901
|
-
injectCacheControlOnLastBlock(messages, messages.length - 2);
|
|
8907
|
+
injectCacheControlOnLastBlock(messages, cacheControl, messages.length - 2);
|
|
8902
8908
|
}
|
|
8903
8909
|
/**
|
|
8904
8910
|
* Check whether a MessageParam is a user message whose content consists
|
|
@@ -9221,6 +9227,7 @@ var AnthropicStreamedMessage = class {
|
|
|
9221
9227
|
}
|
|
9222
9228
|
};
|
|
9223
9229
|
var AnthropicChatProvider = class {
|
|
9230
|
+
_cacheControl;
|
|
9224
9231
|
name = "anthropic";
|
|
9225
9232
|
_model;
|
|
9226
9233
|
_stream;
|
|
@@ -9247,6 +9254,8 @@ var AnthropicChatProvider = class {
|
|
|
9247
9254
|
max_tokens: resolveDefaultMaxTokens(options.model, options.defaultMaxTokens),
|
|
9248
9255
|
betaFeatures: options.betaFeatures ?? [INTERLEAVED_THINKING_BETA]
|
|
9249
9256
|
};
|
|
9257
|
+
this._cacheControl = options.cacheRetention === "long" ? CACHE_CONTROL_LONG : CACHE_CONTROL_SHORT;
|
|
9258
|
+
if (options.cacheRetention === "long" && !this._generationKwargs.betaFeatures.includes(EXTENDED_CACHE_TTL_BETA)) this._generationKwargs.betaFeatures = [...this._generationKwargs.betaFeatures, EXTENDED_CACHE_TTL_BETA];
|
|
9250
9259
|
}
|
|
9251
9260
|
get modelName() {
|
|
9252
9261
|
return this._model;
|
|
@@ -9285,7 +9294,7 @@ var AnthropicChatProvider = class {
|
|
|
9285
9294
|
const system = systemBlocks.length === 0 ? void 0 : systemBlocks.map((text, index) => ({
|
|
9286
9295
|
type: "text",
|
|
9287
9296
|
text,
|
|
9288
|
-
...index === 0 ? { cache_control:
|
|
9297
|
+
...index === 0 ? { cache_control: this._cacheControl } : {}
|
|
9289
9298
|
}));
|
|
9290
9299
|
const normalizedHistory = normalizeToolCallIdsForProvider(history, ANTHROPIC_TOOL_CALL_ID_POLICY);
|
|
9291
9300
|
const messages = [];
|
|
@@ -9295,8 +9304,8 @@ var AnthropicChatProvider = class {
|
|
|
9295
9304
|
if (last !== void 0 && isToolResultOnly(last) && isToolResultOnly(converted)) last.content = [...last.content, ...converted.content];
|
|
9296
9305
|
else messages.push(converted);
|
|
9297
9306
|
}
|
|
9298
|
-
injectCacheControlOnPenultimateMessage(messages);
|
|
9299
|
-
injectCacheControlOnLastBlock(messages);
|
|
9307
|
+
injectCacheControlOnPenultimateMessage(messages, this._cacheControl);
|
|
9308
|
+
injectCacheControlOnLastBlock(messages, this._cacheControl);
|
|
9300
9309
|
const kwargs = {};
|
|
9301
9310
|
if (this._generationKwargs.max_tokens !== void 0) kwargs["max_tokens"] = this._generationKwargs.max_tokens;
|
|
9302
9311
|
if (this._generationKwargs.temperature !== void 0) kwargs["temperature"] = this._generationKwargs.temperature;
|
|
@@ -9310,7 +9319,7 @@ var AnthropicChatProvider = class {
|
|
|
9310
9319
|
const anthropicTools = tools.map((t) => convertTool$2(t));
|
|
9311
9320
|
if (anthropicTools.length > 0) {
|
|
9312
9321
|
const lastTool = anthropicTools.at(-1);
|
|
9313
|
-
if (lastTool !== void 0) lastTool.cache_control =
|
|
9322
|
+
if (lastTool !== void 0) lastTool.cache_control = this._cacheControl;
|
|
9314
9323
|
}
|
|
9315
9324
|
const createParams = {
|
|
9316
9325
|
model: this._model,
|
|
@@ -49805,6 +49814,7 @@ function catalogModelToCapability(model) {
|
|
|
49805
49814
|
name: typeof model.name === "string" && model.name.length > 0 ? model.name : void 0,
|
|
49806
49815
|
maxOutputSize: typeof output === "number" && output > 0 ? output : void 0,
|
|
49807
49816
|
reasoningKey: catalogReasoningKey(model.interleaved),
|
|
49817
|
+
...priceFromEntry(model) === void 0 ? {} : { price: priceFromEntry(model) },
|
|
49808
49818
|
capability: {
|
|
49809
49819
|
image_in: inputs.includes("image"),
|
|
49810
49820
|
video_in: inputs.includes("video"),
|
|
@@ -49815,6 +49825,17 @@ function catalogModelToCapability(model) {
|
|
|
49815
49825
|
}
|
|
49816
49826
|
};
|
|
49817
49827
|
}
|
|
49828
|
+
/** USD per 1M tokens when the entry carries a usable price. */
|
|
49829
|
+
function priceFromEntry(model) {
|
|
49830
|
+
const cost = model.cost;
|
|
49831
|
+
if (typeof cost?.input !== "number" || typeof cost?.output !== "number") return void 0;
|
|
49832
|
+
return {
|
|
49833
|
+
input: cost.input,
|
|
49834
|
+
output: cost.output,
|
|
49835
|
+
...typeof cost.cache_read === "number" ? { cacheRead: cost.cache_read } : {},
|
|
49836
|
+
...typeof cost.cache_write === "number" ? { cacheWrite: cost.cache_write } : {}
|
|
49837
|
+
};
|
|
49838
|
+
}
|
|
49818
49839
|
function catalogReasoningKey(interleaved) {
|
|
49819
49840
|
if (interleaved === true) return "reasoning_content";
|
|
49820
49841
|
if (typeof interleaved !== "object" || interleaved === null) return void 0;
|
|
@@ -49827,6 +49848,25 @@ function catalogProviderModels(entry) {
|
|
|
49827
49848
|
return Object.values(models).map((model) => catalogModelToCapability(model)).filter((model) => model !== void 0);
|
|
49828
49849
|
}
|
|
49829
49850
|
//#endregion
|
|
49851
|
+
//#region ../../packages/ltod/src/cost.ts
|
|
49852
|
+
/**
|
|
49853
|
+
* Cost of one usage record in USD, or `undefined` when the model has no price.
|
|
49854
|
+
*
|
|
49855
|
+
* Absence is meaningful: showing `$0.00` for an unpriced model would read as
|
|
49856
|
+
* "free", so callers must render a placeholder instead of a number.
|
|
49857
|
+
*/
|
|
49858
|
+
function estimateCost(usage, price) {
|
|
49859
|
+
if (price === void 0) return void 0;
|
|
49860
|
+
const cacheRead = price.cacheRead ?? price.input;
|
|
49861
|
+
const cacheWrite = price.cacheWrite ?? price.input;
|
|
49862
|
+
return (usage.inputOther * price.input + usage.inputCacheRead * cacheRead + usage.inputCacheCreation * cacheWrite + usage.output * price.output) / 1e6;
|
|
49863
|
+
}
|
|
49864
|
+
/** `$1.2345` with four decimals — sub-cent precision matters for single calls. */
|
|
49865
|
+
function formatUsd(cost) {
|
|
49866
|
+
if (cost === void 0) return "—";
|
|
49867
|
+
return `$${cost.toFixed(4)}`;
|
|
49868
|
+
}
|
|
49869
|
+
//#endregion
|
|
49830
49870
|
//#region ../../packages/ltod/src/idle-iterator.ts
|
|
49831
49871
|
/**
|
|
49832
49872
|
* Idle-stream watchdog.
|
|
@@ -51574,7 +51614,7 @@ function renderAgentFiles(files) {
|
|
|
51574
51614
|
const frames = files.map((file, index) => ({
|
|
51575
51615
|
annotation: annotationFor(file.path),
|
|
51576
51616
|
separator: index < files.length - 1 ? "\n\n" : "",
|
|
51577
|
-
size: byteLength$
|
|
51617
|
+
size: byteLength$2(file.content)
|
|
51578
51618
|
}));
|
|
51579
51619
|
const framed = files.map(() => false);
|
|
51580
51620
|
const allocation = files.map(() => 0);
|
|
@@ -51583,7 +51623,7 @@ function renderAgentFiles(files) {
|
|
|
51583
51623
|
const take = (index, want) => {
|
|
51584
51624
|
if (want <= 0) return 0;
|
|
51585
51625
|
const frame = frames[index];
|
|
51586
|
-
const frameCost = framed[index] === true ? 0 : byteLength$
|
|
51626
|
+
const frameCost = framed[index] === true ? 0 : byteLength$2(frame.annotation) + byteLength$2(frame.separator);
|
|
51587
51627
|
const available = remaining - frameCost;
|
|
51588
51628
|
if (available <= 0) return 0;
|
|
51589
51629
|
const give = Math.min(want, available);
|
|
@@ -51597,15 +51637,15 @@ function renderAgentFiles(files) {
|
|
|
51597
51637
|
const given = allocation[index];
|
|
51598
51638
|
if (given === 0) {
|
|
51599
51639
|
const marker = omissionMarker(file.path);
|
|
51600
|
-
const cost = byteLength$
|
|
51640
|
+
const cost = byteLength$2(frames[index].annotation) + byteLength$2(marker) + byteLength$2(frames[index].separator);
|
|
51601
51641
|
if (remaining < cost) return "";
|
|
51602
|
-
take(index, byteLength$
|
|
51642
|
+
take(index, byteLength$2(marker));
|
|
51603
51643
|
return `${frames[index].annotation}${marker.slice(2)}`;
|
|
51604
51644
|
}
|
|
51605
51645
|
if (given >= frames[index].size) return `${frames[index].annotation}${file.content}`;
|
|
51606
51646
|
const estimated = truncationMarker(frames[index].size - given, file.path);
|
|
51607
|
-
const kept = truncateUtf8$1(file.content, Math.max(0, given - byteLength$
|
|
51608
|
-
const marker = truncationMarker(frames[index].size - byteLength$
|
|
51647
|
+
const kept = truncateUtf8$1(file.content, Math.max(0, given - byteLength$2(estimated))).trim();
|
|
51648
|
+
const marker = truncationMarker(frames[index].size - byteLength$2(kept), file.path);
|
|
51609
51649
|
return `${frames[index].annotation}${kept}${marker}`;
|
|
51610
51650
|
}).filter((block) => block.length > 0).join("\n\n");
|
|
51611
51651
|
}
|
|
@@ -51619,13 +51659,13 @@ function renderAgentFiles(files) {
|
|
|
51619
51659
|
* loop for ~5s before this.
|
|
51620
51660
|
*/
|
|
51621
51661
|
function truncateUtf8$1(text, maxBytes) {
|
|
51622
|
-
if (byteLength$
|
|
51662
|
+
if (byteLength$2(text) <= maxBytes) return text;
|
|
51623
51663
|
const bytes = Buffer.from(text, "utf8");
|
|
51624
51664
|
let end = Math.min(maxBytes, bytes.length);
|
|
51625
51665
|
while (end > 0 && (bytes[end] & 192) === 128) end -= 1;
|
|
51626
51666
|
return bytes.toString("utf8", 0, end);
|
|
51627
51667
|
}
|
|
51628
|
-
function byteLength$
|
|
51668
|
+
function byteLength$2(text) {
|
|
51629
51669
|
return Buffer.byteLength(text, "utf8");
|
|
51630
51670
|
}
|
|
51631
51671
|
function annotationFor(path) {
|
|
@@ -59281,7 +59321,7 @@ function isBackgroundTaskTerminal(status) {
|
|
|
59281
59321
|
* Callers that need the full output (e.g. `TaskOutput`) must read the
|
|
59282
59322
|
* disk log via `getOutputSizeBytes` / `readOutputBytesFromDisk`.
|
|
59283
59323
|
*/
|
|
59284
|
-
const MAX_OUTPUT_BYTES$
|
|
59324
|
+
const MAX_OUTPUT_BYTES$2 = 1024 * 1024;
|
|
59285
59325
|
/**
|
|
59286
59326
|
* How many terminal tasks stay addressable after eviction from `processes`.
|
|
59287
59327
|
* The full output is on disk (`output.log`); the ring only keeps the metadata
|
|
@@ -60091,15 +60131,15 @@ var BackgroundProcessManager = class {
|
|
|
60091
60131
|
* multi-byte output cannot exceed the cap the way a code-unit count would.
|
|
60092
60132
|
*/
|
|
60093
60133
|
trimLiveOutput(entry) {
|
|
60094
|
-
while (entry.outputRingBytes > MAX_OUTPUT_BYTES$
|
|
60134
|
+
while (entry.outputRingBytes > MAX_OUTPUT_BYTES$2 && entry.outputChunks.length > 1) {
|
|
60095
60135
|
const removed = entry.outputChunks.shift();
|
|
60096
60136
|
if (removed === void 0) break;
|
|
60097
60137
|
entry.outputRingBytes -= Buffer.byteLength(removed, "utf-8");
|
|
60098
60138
|
}
|
|
60099
|
-
if (entry.outputRingBytes > MAX_OUTPUT_BYTES$
|
|
60139
|
+
if (entry.outputRingBytes > MAX_OUTPUT_BYTES$2) {
|
|
60100
60140
|
const only = entry.outputChunks[0];
|
|
60101
60141
|
if (only === void 0) return;
|
|
60102
|
-
const tail = utf8ByteTail(only, MAX_OUTPUT_BYTES$
|
|
60142
|
+
const tail = utf8ByteTail(only, MAX_OUTPUT_BYTES$2);
|
|
60103
60143
|
entry.outputChunks[0] = tail;
|
|
60104
60144
|
entry.outputRingBytes = Buffer.byteLength(tail, "utf-8");
|
|
60105
60145
|
}
|
|
@@ -60124,15 +60164,15 @@ var BackgroundProcessManager = class {
|
|
|
60124
60164
|
* budget either.
|
|
60125
60165
|
*/
|
|
60126
60166
|
trimRetiredOutput(retired) {
|
|
60127
|
-
while (retired.outputTextBytes > MAX_OUTPUT_BYTES$
|
|
60167
|
+
while (retired.outputTextBytes > MAX_OUTPUT_BYTES$2 && retired.outputChunks.length > 1) {
|
|
60128
60168
|
const removed = retired.outputChunks.shift();
|
|
60129
60169
|
if (removed === void 0) break;
|
|
60130
60170
|
retired.outputTextBytes -= Buffer.byteLength(removed, "utf-8");
|
|
60131
60171
|
}
|
|
60132
|
-
if (retired.outputTextBytes > MAX_OUTPUT_BYTES$
|
|
60172
|
+
if (retired.outputTextBytes > MAX_OUTPUT_BYTES$2) {
|
|
60133
60173
|
const only = retired.outputChunks[0];
|
|
60134
60174
|
if (only === void 0) return;
|
|
60135
|
-
const tail = utf8ByteTail(only, MAX_OUTPUT_BYTES$
|
|
60175
|
+
const tail = utf8ByteTail(only, MAX_OUTPUT_BYTES$2);
|
|
60136
60176
|
retired.outputChunks[0] = tail;
|
|
60137
60177
|
retired.outputTextBytes = Buffer.byteLength(tail, "utf-8");
|
|
60138
60178
|
}
|
|
@@ -63798,6 +63838,233 @@ function normalizePath$1(path) {
|
|
|
63798
63838
|
return folded;
|
|
63799
63839
|
}
|
|
63800
63840
|
//#endregion
|
|
63841
|
+
//#region ../../packages/agent-core/src/tools/support/result-builder.ts
|
|
63842
|
+
const DEFAULT_MAX_BYTES$1 = 50 * 1024;
|
|
63843
|
+
const DEFAULT_TAIL_BYTES = 20 * 1024;
|
|
63844
|
+
const DEFAULT_MAX_LINE_BYTES = 2048;
|
|
63845
|
+
const DEFAULT_MAX_LINES = 2e3;
|
|
63846
|
+
const DEFAULT_MAX_FULL_OUTPUT_BYTES = 1e6;
|
|
63847
|
+
const TRUNCATION_MARKER$1 = "[...truncated]";
|
|
63848
|
+
const TRUNCATION_MESSAGE = "Output is truncated to fit in the message.";
|
|
63849
|
+
var ToolResultBuilder = class {
|
|
63850
|
+
maxBytes;
|
|
63851
|
+
maxTailBytes;
|
|
63852
|
+
maxLineBytes;
|
|
63853
|
+
maxLines;
|
|
63854
|
+
artifactSink;
|
|
63855
|
+
maxFullOutputBytes;
|
|
63856
|
+
buffer = [];
|
|
63857
|
+
nBytesValue = 0;
|
|
63858
|
+
nCharsValue = 0;
|
|
63859
|
+
linesInHead = 0;
|
|
63860
|
+
truncationHappened = false;
|
|
63861
|
+
headTruncated = false;
|
|
63862
|
+
tailBuf = [];
|
|
63863
|
+
tailBytesValue = 0;
|
|
63864
|
+
tailCharsValue = 0;
|
|
63865
|
+
fullOutput;
|
|
63866
|
+
fullOutputBytes = 0;
|
|
63867
|
+
totalLinesWritten = 0;
|
|
63868
|
+
constructor(options = {}) {
|
|
63869
|
+
this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES$1;
|
|
63870
|
+
this.maxTailBytes = options.maxTailBytes ?? DEFAULT_TAIL_BYTES;
|
|
63871
|
+
this.maxLineBytes = options.maxLineBytes === void 0 ? DEFAULT_MAX_LINE_BYTES : options.maxLineBytes;
|
|
63872
|
+
this.maxLines = options.maxLines ?? DEFAULT_MAX_LINES;
|
|
63873
|
+
if (this.maxLineBytes !== null && this.maxLineBytes <= byteLength$1(TRUNCATION_MARKER$1)) throw new Error("maxLineBytes must be greater than the truncation marker length.");
|
|
63874
|
+
this.artifactSink = options.artifactSink;
|
|
63875
|
+
this.maxFullOutputBytes = options.maxFullOutputBytes ?? DEFAULT_MAX_FULL_OUTPUT_BYTES;
|
|
63876
|
+
if (this.artifactSink !== void 0) this.fullOutput = [];
|
|
63877
|
+
}
|
|
63878
|
+
/** Characters retained so far (UI/logging); the budget itself is bytes. */
|
|
63879
|
+
get nChars() {
|
|
63880
|
+
return this.nCharsValue + this.tailCharsValue;
|
|
63881
|
+
}
|
|
63882
|
+
/** Bytes retained so far. */
|
|
63883
|
+
get nBytes() {
|
|
63884
|
+
return this.nBytesValue + this.tailBytesValue;
|
|
63885
|
+
}
|
|
63886
|
+
toString() {
|
|
63887
|
+
const buffered = this.buffer.join("");
|
|
63888
|
+
if (!this.headTruncated || this.tailBytesValue === 0) return buffered;
|
|
63889
|
+
this.trimTail();
|
|
63890
|
+
const tail = this.tailBuf.join("");
|
|
63891
|
+
const headBudget = this.maxBytes - 128 - this.tailBytesValue;
|
|
63892
|
+
const head = headBudget >= 0 && byteLength$1(buffered) > headBudget ? truncateToBytes(buffered, headBudget) : buffered;
|
|
63893
|
+
const elided = this.computeElidedLines(head, tail);
|
|
63894
|
+
const marker = elided > 0 ? `[…${String(elided)} lines elided…]\n${TRUNCATION_MARKER$1}` : TRUNCATION_MARKER$1;
|
|
63895
|
+
return `${head}${head.endsWith("\n") ? `${marker}\n` : marker}${tail}`;
|
|
63896
|
+
}
|
|
63897
|
+
write(text) {
|
|
63898
|
+
if (text.length === 0) return 0;
|
|
63899
|
+
const lines = text.match(/[^\r\n]*(?:\r\n|[\n\r])|[^\r\n]+/g) ?? [];
|
|
63900
|
+
if (lines.length === 0) return 0;
|
|
63901
|
+
this.totalLinesWritten += lines.length;
|
|
63902
|
+
if (this.fullOutput !== void 0 && this.fullOutputBytes < this.maxFullOutputBytes) {
|
|
63903
|
+
this.fullOutput.push(text);
|
|
63904
|
+
this.fullOutputBytes += byteLength$1(text);
|
|
63905
|
+
}
|
|
63906
|
+
let charsWritten = 0;
|
|
63907
|
+
for (const originalLine of lines) {
|
|
63908
|
+
let line = originalLine;
|
|
63909
|
+
if (this.maxLineBytes !== null && byteLength$1(line) > this.maxLineBytes) {
|
|
63910
|
+
line = truncateLineToBytes(line, this.maxLineBytes);
|
|
63911
|
+
this.truncationHappened = true;
|
|
63912
|
+
}
|
|
63913
|
+
const lineBytes = byteLength$1(line);
|
|
63914
|
+
const remainingHeadBytes = this.maxBytes - this.nBytesValue;
|
|
63915
|
+
if (!this.headTruncated && this.linesInHead < this.maxLines && lineBytes <= remainingHeadBytes) {
|
|
63916
|
+
this.pushHead(line);
|
|
63917
|
+
charsWritten += line.length;
|
|
63918
|
+
continue;
|
|
63919
|
+
}
|
|
63920
|
+
if (!this.headTruncated && this.linesInHead === 0 && lineBytes > remainingHeadBytes && remainingHeadBytes > 0) {
|
|
63921
|
+
const prefix = truncateToBytes(line, remainingHeadBytes);
|
|
63922
|
+
this.pushHead(prefix);
|
|
63923
|
+
this.headTruncated = true;
|
|
63924
|
+
this.truncationHappened = true;
|
|
63925
|
+
const rest = line.slice(prefix.length);
|
|
63926
|
+
if (rest.length > 0) this.appendTail(rest);
|
|
63927
|
+
charsWritten += line.length;
|
|
63928
|
+
continue;
|
|
63929
|
+
}
|
|
63930
|
+
this.headTruncated = true;
|
|
63931
|
+
this.truncationHappened = true;
|
|
63932
|
+
this.appendTail(line);
|
|
63933
|
+
charsWritten += line.length;
|
|
63934
|
+
}
|
|
63935
|
+
return charsWritten;
|
|
63936
|
+
}
|
|
63937
|
+
pushHead(line) {
|
|
63938
|
+
this.buffer.push(line);
|
|
63939
|
+
this.nBytesValue += byteLength$1(line);
|
|
63940
|
+
this.nCharsValue += line.length;
|
|
63941
|
+
this.linesInHead += 1;
|
|
63942
|
+
}
|
|
63943
|
+
appendTail(text) {
|
|
63944
|
+
if (text.length === 0) return;
|
|
63945
|
+
if (this.maxTailBytes === 0) return;
|
|
63946
|
+
const bytes = byteLength$1(text);
|
|
63947
|
+
if (bytes >= this.maxTailBytes) {
|
|
63948
|
+
const trimmed = tailAtCodePoint(text, this.maxTailBytes);
|
|
63949
|
+
this.tailBuf.length = 0;
|
|
63950
|
+
this.tailBuf.push(trimmed);
|
|
63951
|
+
this.tailBytesValue = byteLength$1(trimmed);
|
|
63952
|
+
this.tailCharsValue = trimmed.length;
|
|
63953
|
+
return;
|
|
63954
|
+
}
|
|
63955
|
+
this.tailBuf.push(text);
|
|
63956
|
+
this.tailBytesValue += bytes;
|
|
63957
|
+
this.tailCharsValue += text.length;
|
|
63958
|
+
if (this.tailBytesValue > this.maxTailBytes * 2) this.trimTail();
|
|
63959
|
+
}
|
|
63960
|
+
trimTail() {
|
|
63961
|
+
if (this.tailBytesValue <= this.maxTailBytes) return;
|
|
63962
|
+
const trimmed = tailAtCodePoint(this.tailBuf.join(""), this.maxTailBytes);
|
|
63963
|
+
this.tailBuf.length = 0;
|
|
63964
|
+
this.tailBuf.push(trimmed);
|
|
63965
|
+
this.tailBytesValue = byteLength$1(trimmed);
|
|
63966
|
+
this.tailCharsValue = trimmed.length;
|
|
63967
|
+
}
|
|
63968
|
+
computeElidedLines(head, tail) {
|
|
63969
|
+
if (this.totalLinesWritten === 0) return 0;
|
|
63970
|
+
if (this.fullOutput !== void 0) {
|
|
63971
|
+
const total = countLines$1(this.fullOutput.join(""));
|
|
63972
|
+
return Math.max(0, total - countLines$1(head) - countLines$1(tail));
|
|
63973
|
+
}
|
|
63974
|
+
return Math.max(0, this.totalLinesWritten - countLines$1(head) - countLines$1(tail));
|
|
63975
|
+
}
|
|
63976
|
+
async maybeWriteArtifact() {
|
|
63977
|
+
if (this.artifactSink === void 0 || this.fullOutput === void 0) return void 0;
|
|
63978
|
+
if (!this.truncationHappened) return void 0;
|
|
63979
|
+
const full = this.fullOutput.join("");
|
|
63980
|
+
if (full.length === 0) return void 0;
|
|
63981
|
+
try {
|
|
63982
|
+
return await this.artifactSink(full);
|
|
63983
|
+
} catch {
|
|
63984
|
+
return;
|
|
63985
|
+
}
|
|
63986
|
+
}
|
|
63987
|
+
appendArtifactRef(output, ref) {
|
|
63988
|
+
const line = `[full output saved: ${ref}]`;
|
|
63989
|
+
return output.length === 0 ? line : output.endsWith("\n") ? `${output}${line}` : `${output}\n${line}`;
|
|
63990
|
+
}
|
|
63991
|
+
async ok(message = "", options = {}) {
|
|
63992
|
+
let finalMessage = message;
|
|
63993
|
+
if (finalMessage.length > 0 && !finalMessage.endsWith(".")) finalMessage += ".";
|
|
63994
|
+
if (this.truncationHappened) finalMessage = finalMessage.length === 0 ? TRUNCATION_MESSAGE : `${finalMessage} ${TRUNCATION_MESSAGE}`;
|
|
63995
|
+
const baseOutput = this.toString();
|
|
63996
|
+
const artifactRef = await this.maybeWriteArtifact();
|
|
63997
|
+
const output = artifactRef === void 0 ? baseOutput : this.appendArtifactRef(baseOutput, artifactRef);
|
|
63998
|
+
const shouldAppendMessage = finalMessage.length > 0 && (this.truncationHappened || output.length === 0);
|
|
63999
|
+
return {
|
|
64000
|
+
isError: false,
|
|
64001
|
+
output: shouldAppendMessage ? output.length === 0 ? finalMessage : output.endsWith("\n") ? `${output}${finalMessage}` : `${output}\n${finalMessage}` : output,
|
|
64002
|
+
message: shouldAppendMessage ? void 0 : finalMessage,
|
|
64003
|
+
truncated: this.truncationHappened,
|
|
64004
|
+
brief: options.brief
|
|
64005
|
+
};
|
|
64006
|
+
}
|
|
64007
|
+
async error(message, options = {}) {
|
|
64008
|
+
const finalMessage = this.truncationHappened ? message.length === 0 ? TRUNCATION_MESSAGE : `${message} ${TRUNCATION_MESSAGE}` : message;
|
|
64009
|
+
const baseOutput = this.toString();
|
|
64010
|
+
const artifactRef = await this.maybeWriteArtifact();
|
|
64011
|
+
const output = artifactRef === void 0 ? baseOutput : this.appendArtifactRef(baseOutput, artifactRef);
|
|
64012
|
+
return {
|
|
64013
|
+
isError: true,
|
|
64014
|
+
output: finalMessage.length === 0 ? output : output.length === 0 ? finalMessage : output.endsWith("\n") ? `${output}${finalMessage}` : `${output}\n${finalMessage}`,
|
|
64015
|
+
truncated: this.truncationHappened,
|
|
64016
|
+
brief: options.brief
|
|
64017
|
+
};
|
|
64018
|
+
}
|
|
64019
|
+
};
|
|
64020
|
+
/** UTF-8 byte length; the budget unit for every tool result. */
|
|
64021
|
+
function byteLength$1(text) {
|
|
64022
|
+
return Buffer.byteLength(text, "utf8");
|
|
64023
|
+
}
|
|
64024
|
+
/**
|
|
64025
|
+
* Cut `text` to a byte budget without splitting a character.
|
|
64026
|
+
*
|
|
64027
|
+
* The cut backs up to the lead byte of the sequence it would have split, so the
|
|
64028
|
+
* result decodes to complete code points — no lone surrogate, no U+FFFD.
|
|
64029
|
+
*/
|
|
64030
|
+
function truncateToBytes(text, maxBytes) {
|
|
64031
|
+
if (maxBytes <= 0) return "";
|
|
64032
|
+
if (text.length === 0) return text;
|
|
64033
|
+
if (byteLength$1(text) <= maxBytes) return text;
|
|
64034
|
+
const bytes = Buffer.from(text, "utf8");
|
|
64035
|
+
let end = Math.min(maxBytes, bytes.length);
|
|
64036
|
+
while (end > 0 && (bytes[end] & 192) === 128) end -= 1;
|
|
64037
|
+
return bytes.toString("utf8", 0, end);
|
|
64038
|
+
}
|
|
64039
|
+
/** Last `maxBytes` bytes of `text`, starting on a character boundary. */
|
|
64040
|
+
function tailToBytes(text, maxBytes) {
|
|
64041
|
+
if (maxBytes <= 0) return "";
|
|
64042
|
+
if (text.length === 0) return text;
|
|
64043
|
+
if (byteLength$1(text) <= maxBytes) return text;
|
|
64044
|
+
const bytes = Buffer.from(text, "utf8");
|
|
64045
|
+
let start = bytes.length - maxBytes;
|
|
64046
|
+
while (start < bytes.length && (bytes[start] & 192) === 128) start += 1;
|
|
64047
|
+
return bytes.toString("utf8", start);
|
|
64048
|
+
}
|
|
64049
|
+
/**
|
|
64050
|
+
* A single over-long line keeps its head and the truncation marker, and the cut
|
|
64051
|
+
* lands on a character boundary. The marker (and any trailing line break) is
|
|
64052
|
+
* reserved out of the same budget.
|
|
64053
|
+
*/
|
|
64054
|
+
function truncateLineToBytes(line, maxLineBytes) {
|
|
64055
|
+
const lineBreak = /[\r\n]+$/.exec(line)?.[0] ?? "";
|
|
64056
|
+
const suffix = TRUNCATION_MARKER$1 + lineBreak;
|
|
64057
|
+
const keep = Math.max(0, maxLineBytes - byteLength$1(suffix));
|
|
64058
|
+
return `${truncateToBytes(line.slice(0, line.length - lineBreak.length), keep)}${suffix}`;
|
|
64059
|
+
}
|
|
64060
|
+
function tailAtCodePoint(text, maxBytes) {
|
|
64061
|
+
return tailToBytes(text, maxBytes);
|
|
64062
|
+
}
|
|
64063
|
+
function countLines$1(text) {
|
|
64064
|
+
if (text.length === 0) return 0;
|
|
64065
|
+
return text.split("\n").length - (text.endsWith("\n") ? 1 : 0);
|
|
64066
|
+
}
|
|
64067
|
+
//#endregion
|
|
63801
64068
|
//#region ../../packages/agent-core/src/tools/builtin/collaboration/agent-background-disabled.md
|
|
63802
64069
|
var agent_background_disabled_default = "Background agent execution is disabled for this agent. Do not set `run_in_background=true`.";
|
|
63803
64070
|
//#endregion
|
|
@@ -64201,13 +64468,15 @@ var AgentTool = class {
|
|
|
64201
64468
|
}
|
|
64202
64469
|
/** Render the completed-subagent result text (summary + optional structured block). */
|
|
64203
64470
|
formatCompletion(handle, result, outputSchema) {
|
|
64471
|
+
const MAX_SUMMARY_BYTES = 50 * 1024;
|
|
64472
|
+
const summary = byteLength$1(result.result) <= MAX_SUMMARY_BYTES ? result.result : `${truncateToBytes(result.result, MAX_SUMMARY_BYTES - 160)}\n[...truncated; Agent(resume="${handle.agentId}") returns the rest]`;
|
|
64204
64473
|
const lines = [
|
|
64205
64474
|
`agent_id: ${handle.agentId}`,
|
|
64206
64475
|
`actual_subagent_type: ${handle.profileName}`,
|
|
64207
64476
|
"status: completed",
|
|
64208
64477
|
"",
|
|
64209
64478
|
"[summary]",
|
|
64210
|
-
|
|
64479
|
+
summary
|
|
64211
64480
|
];
|
|
64212
64481
|
if (outputSchema !== void 0) {
|
|
64213
64482
|
const structured = parseJsonObject(result.result);
|
|
@@ -67848,6 +68117,216 @@ var DiscoverMcpToolsTool = class {
|
|
|
67848
68117
|
}
|
|
67849
68118
|
};
|
|
67850
68119
|
//#endregion
|
|
68120
|
+
//#region ../../packages/agent-core/src/tools/builtin/mcp/resources.ts
|
|
68121
|
+
/**
|
|
68122
|
+
* MCP resource tools — the same three names and semantics the other agents in
|
|
68123
|
+
* this space converged on (`list_mcp_resources`, `list_mcp_resource_templates`,
|
|
68124
|
+
* `read_mcp_resource`), so a model that knows one of them knows all three:
|
|
68125
|
+
*
|
|
68126
|
+
* - `server` is optional; omitting it covers every connected server
|
|
68127
|
+
* - pagination is not exposed: our client lists a server's resources in one call
|
|
68128
|
+
* - output is JSON so the model can reason about URIs without re-parsing prose
|
|
68129
|
+
*
|
|
68130
|
+
* They exist as host tools rather than synthetic MCP tools because our MCP
|
|
68131
|
+
* registration path carries descriptors only (execution is always `callTool`),
|
|
68132
|
+
* and a resource read is not a tool call.
|
|
68133
|
+
*/
|
|
68134
|
+
const ServerArg = z.string().min(1).optional().describe("Server config name. Omit to cover every connected server.");
|
|
68135
|
+
const ListMcpResourcesInputSchema = z.object({ server: ServerArg }).strict();
|
|
68136
|
+
const ListMcpResourceTemplatesInputSchema = z.object({ server: ServerArg }).strict();
|
|
68137
|
+
const ReadMcpResourceInputSchema = z.object({
|
|
68138
|
+
server: z.string().min(1).describe("Server config name."),
|
|
68139
|
+
uri: z.string().min(1).describe("Resource URI, as listed by list_mcp_resources.")
|
|
68140
|
+
}).strict();
|
|
68141
|
+
/** Connected servers with a client, optionally narrowed to one name. */
|
|
68142
|
+
function connectedServers(mcp, server) {
|
|
68143
|
+
const names = server === void 0 ? mcp.list().map((entry) => entry.name) : [server];
|
|
68144
|
+
const servers = [];
|
|
68145
|
+
for (const name of names) {
|
|
68146
|
+
const resolved = mcp.resolved(name);
|
|
68147
|
+
if (resolved !== void 0) servers.push({
|
|
68148
|
+
name,
|
|
68149
|
+
client: resolved.client
|
|
68150
|
+
});
|
|
68151
|
+
}
|
|
68152
|
+
return servers;
|
|
68153
|
+
}
|
|
68154
|
+
function unknownServer(server, mcp) {
|
|
68155
|
+
const entries = mcp.list();
|
|
68156
|
+
if (entries.length === 0) return "No MCP servers are configured.";
|
|
68157
|
+
const configured = entries.find((entry) => entry.name === server);
|
|
68158
|
+
if (configured !== void 0) return `MCP server "${server}" is configured but not connected (status: ${configured.status}).`;
|
|
68159
|
+
return `No MCP server named "${server}". Configured: ${entries.map((entry) => entry.name).join(", ")}.`;
|
|
68160
|
+
}
|
|
68161
|
+
var ListMcpResourcesTool = class {
|
|
68162
|
+
tools;
|
|
68163
|
+
name = "ListMcpResources";
|
|
68164
|
+
description = "List MCP resources. Omit `server` to cover every connected server. Returns JSON with `resources` (each carrying its `server`) and an `instructions` map for servers that sent any during the handshake.";
|
|
68165
|
+
parameters = toInputJsonSchema(ListMcpResourcesInputSchema);
|
|
68166
|
+
annotations = {
|
|
68167
|
+
readOnlyHint: true,
|
|
68168
|
+
openWorldHint: true
|
|
68169
|
+
};
|
|
68170
|
+
constructor(tools) {
|
|
68171
|
+
this.tools = tools;
|
|
68172
|
+
}
|
|
68173
|
+
resolveExecution(args) {
|
|
68174
|
+
return {
|
|
68175
|
+
description: "Listing MCP resources",
|
|
68176
|
+
approvalRule: this.name,
|
|
68177
|
+
execute: async () => {
|
|
68178
|
+
const mcp = this.tools.mcp;
|
|
68179
|
+
if (mcp === void 0) return {
|
|
68180
|
+
output: "MCP is not configured.",
|
|
68181
|
+
isError: true
|
|
68182
|
+
};
|
|
68183
|
+
const servers = connectedServers(mcp, args.server);
|
|
68184
|
+
if (servers.length === 0) return {
|
|
68185
|
+
output: args.server === void 0 ? "No MCP servers are connected." : unknownServer(args.server, mcp),
|
|
68186
|
+
isError: args.server !== void 0
|
|
68187
|
+
};
|
|
68188
|
+
const resources = [];
|
|
68189
|
+
const instructions = {};
|
|
68190
|
+
const failures = [];
|
|
68191
|
+
for (const { name, client } of servers) {
|
|
68192
|
+
if (client.listResources === void 0) continue;
|
|
68193
|
+
const text = client.getInstructions?.();
|
|
68194
|
+
if (text !== void 0) instructions[name] = text;
|
|
68195
|
+
try {
|
|
68196
|
+
for (const resource of await client.listResources()) resources.push({
|
|
68197
|
+
server: name,
|
|
68198
|
+
...resource
|
|
68199
|
+
});
|
|
68200
|
+
} catch (error) {
|
|
68201
|
+
failures.push({
|
|
68202
|
+
server: name,
|
|
68203
|
+
error: error instanceof Error ? error.message : String(error)
|
|
68204
|
+
});
|
|
68205
|
+
}
|
|
68206
|
+
}
|
|
68207
|
+
if (resources.length === 0 && Object.keys(instructions).length === 0) return {
|
|
68208
|
+
output: JSON.stringify({
|
|
68209
|
+
resources: [],
|
|
68210
|
+
note: "No server advertises resources."
|
|
68211
|
+
}),
|
|
68212
|
+
isError: false
|
|
68213
|
+
};
|
|
68214
|
+
return {
|
|
68215
|
+
output: JSON.stringify({
|
|
68216
|
+
resources,
|
|
68217
|
+
...Object.keys(instructions).length === 0 ? {} : { instructions },
|
|
68218
|
+
...failures.length === 0 ? {} : { failures }
|
|
68219
|
+
}),
|
|
68220
|
+
isError: false
|
|
68221
|
+
};
|
|
68222
|
+
}
|
|
68223
|
+
};
|
|
68224
|
+
}
|
|
68225
|
+
};
|
|
68226
|
+
var ListMcpResourceTemplatesTool = class {
|
|
68227
|
+
tools;
|
|
68228
|
+
name = "ListMcpResourceTemplates";
|
|
68229
|
+
description = "List MCP resource templates (URI patterns a server can expand). Omit `server` for all connected servers.";
|
|
68230
|
+
parameters = toInputJsonSchema(ListMcpResourceTemplatesInputSchema);
|
|
68231
|
+
annotations = {
|
|
68232
|
+
readOnlyHint: true,
|
|
68233
|
+
openWorldHint: true
|
|
68234
|
+
};
|
|
68235
|
+
constructor(tools) {
|
|
68236
|
+
this.tools = tools;
|
|
68237
|
+
}
|
|
68238
|
+
resolveExecution(args) {
|
|
68239
|
+
return {
|
|
68240
|
+
description: "Listing MCP resource templates",
|
|
68241
|
+
approvalRule: this.name,
|
|
68242
|
+
execute: async () => {
|
|
68243
|
+
const mcp = this.tools.mcp;
|
|
68244
|
+
if (mcp === void 0) return {
|
|
68245
|
+
output: "MCP is not configured.",
|
|
68246
|
+
isError: true
|
|
68247
|
+
};
|
|
68248
|
+
const servers = connectedServers(mcp, args.server);
|
|
68249
|
+
if (servers.length === 0) return {
|
|
68250
|
+
output: args.server === void 0 ? "No MCP servers are connected." : unknownServer(args.server, mcp),
|
|
68251
|
+
isError: args.server !== void 0
|
|
68252
|
+
};
|
|
68253
|
+
const templates = [];
|
|
68254
|
+
const failures = [];
|
|
68255
|
+
for (const { name, client } of servers) {
|
|
68256
|
+
if (client.listResourceTemplates === void 0) continue;
|
|
68257
|
+
try {
|
|
68258
|
+
for (const template of await client.listResourceTemplates()) templates.push({
|
|
68259
|
+
server: name,
|
|
68260
|
+
...template
|
|
68261
|
+
});
|
|
68262
|
+
} catch (error) {
|
|
68263
|
+
failures.push({
|
|
68264
|
+
server: name,
|
|
68265
|
+
error: error instanceof Error ? error.message : String(error)
|
|
68266
|
+
});
|
|
68267
|
+
}
|
|
68268
|
+
}
|
|
68269
|
+
return {
|
|
68270
|
+
output: JSON.stringify({
|
|
68271
|
+
resourceTemplates: templates,
|
|
68272
|
+
...failures.length === 0 ? {} : { failures }
|
|
68273
|
+
}),
|
|
68274
|
+
isError: false
|
|
68275
|
+
};
|
|
68276
|
+
}
|
|
68277
|
+
};
|
|
68278
|
+
}
|
|
68279
|
+
};
|
|
68280
|
+
var ReadMcpResourceTool = class {
|
|
68281
|
+
tools;
|
|
68282
|
+
name = "ReadMcpResource";
|
|
68283
|
+
description = "Read one MCP resource by `server` + `uri`. Text contents are returned as-is; a resource without text content reports its MIME type so the caller knows it is binary.";
|
|
68284
|
+
parameters = toInputJsonSchema(ReadMcpResourceInputSchema);
|
|
68285
|
+
annotations = {
|
|
68286
|
+
readOnlyHint: true,
|
|
68287
|
+
openWorldHint: true
|
|
68288
|
+
};
|
|
68289
|
+
constructor(tools) {
|
|
68290
|
+
this.tools = tools;
|
|
68291
|
+
}
|
|
68292
|
+
resolveExecution(args) {
|
|
68293
|
+
return {
|
|
68294
|
+
description: `Reading MCP resource ${args.uri}`,
|
|
68295
|
+
approvalRule: this.name,
|
|
68296
|
+
execute: async () => {
|
|
68297
|
+
const mcp = this.tools.mcp;
|
|
68298
|
+
if (mcp === void 0) return {
|
|
68299
|
+
output: "MCP is not configured.",
|
|
68300
|
+
isError: true
|
|
68301
|
+
};
|
|
68302
|
+
const resolved = mcp.resolved(args.server);
|
|
68303
|
+
if (resolved === void 0) return {
|
|
68304
|
+
output: unknownServer(args.server, mcp),
|
|
68305
|
+
isError: true
|
|
68306
|
+
};
|
|
68307
|
+
const { client } = resolved;
|
|
68308
|
+
if (client.readResource === void 0) return {
|
|
68309
|
+
output: `Server "${args.server}" cannot read resources.`,
|
|
68310
|
+
isError: true
|
|
68311
|
+
};
|
|
68312
|
+
const content = await client.readResource(args.uri);
|
|
68313
|
+
if (content.text !== void 0) return {
|
|
68314
|
+
output: content.text,
|
|
68315
|
+
isError: false
|
|
68316
|
+
};
|
|
68317
|
+
return {
|
|
68318
|
+
output: JSON.stringify({
|
|
68319
|
+
uri: content.uri,
|
|
68320
|
+
mimeType: content.mimeType ?? null,
|
|
68321
|
+
note: "Resource has no text content (binary or unsupported)."
|
|
68322
|
+
}),
|
|
68323
|
+
isError: false
|
|
68324
|
+
};
|
|
68325
|
+
}
|
|
68326
|
+
};
|
|
68327
|
+
}
|
|
68328
|
+
};
|
|
68329
|
+
//#endregion
|
|
67851
68330
|
//#region ../../node_modules/.pnpm/object-keys@1.1.1/node_modules/object-keys/isArguments.js
|
|
67852
68331
|
var require_isArguments = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
67853
68332
|
var toStr = Object.prototype.toString;
|
|
@@ -71773,6 +72252,7 @@ const ModelAliasSchema = z.object({
|
|
|
71773
72252
|
displayName: z.string().optional(),
|
|
71774
72253
|
reasoningKey: z.string().optional(),
|
|
71775
72254
|
adaptiveThinking: z.boolean().optional(),
|
|
72255
|
+
cacheRetention: z.enum(["short", "long"]).optional(),
|
|
71776
72256
|
forceThinking: z.boolean().optional(),
|
|
71777
72257
|
thinkingLevels: z.array(ThinkingEffortSchema).optional()
|
|
71778
72258
|
});
|
|
@@ -74241,7 +74721,7 @@ const diffLinesWithBudget = diffLines;
|
|
|
74241
74721
|
* counts them: a trailing newline terminates the preceding line instead of
|
|
74242
74722
|
* opening an empty one, and the empty string has no lines.
|
|
74243
74723
|
*/
|
|
74244
|
-
function countLines
|
|
74724
|
+
function countLines(value) {
|
|
74245
74725
|
if (value.length === 0) return 0;
|
|
74246
74726
|
const lineBreaks = value.split("\n").length - 1;
|
|
74247
74727
|
return value.endsWith("\n") ? lineBreaks : lineBreaks + 1;
|
|
@@ -74263,7 +74743,7 @@ function fileDiffSummary(before, after) {
|
|
|
74263
74743
|
let added = 0;
|
|
74264
74744
|
let removed = 0;
|
|
74265
74745
|
for (const part of parts) {
|
|
74266
|
-
const lines = countLines
|
|
74746
|
+
const lines = countLines(part.value);
|
|
74267
74747
|
if (part.added) added += lines;
|
|
74268
74748
|
else if (part.removed) removed += lines;
|
|
74269
74749
|
}
|
|
@@ -74879,6 +75359,8 @@ const GlobInputSchema = z.object({
|
|
|
74879
75359
|
include_dirs: z.boolean().default(true).optional().describe("Whether to include directories in results. Defaults to true. Set false to return only files.")
|
|
74880
75360
|
});
|
|
74881
75361
|
const MAX_MATCHES = 1e3;
|
|
75362
|
+
/** Byte ceiling for the rendered path list (the match count is not a size cap). */
|
|
75363
|
+
const MAX_OUTPUT_BYTES$1 = 50 * 1024;
|
|
74882
75364
|
/**
|
|
74883
75365
|
* Directory basenames the Glob tool prunes by default — see
|
|
74884
75366
|
* `globExcludesForPattern`. Kept as one exported list so the default and
|
|
@@ -75057,17 +75539,27 @@ var GlobTool = class {
|
|
|
75057
75539
|
const relBase = searchRoots[0] ?? this.workspace.workspaceDir;
|
|
75058
75540
|
const displayLines = paths.map((p) => relativizeIfUnder$1(p, relBase, pathClass));
|
|
75059
75541
|
let output;
|
|
75542
|
+
let headerLines = 0;
|
|
75060
75543
|
if (entries.length === 0 && !truncated) output = "No matches found";
|
|
75061
75544
|
else {
|
|
75062
75545
|
const lines = [];
|
|
75063
75546
|
if (truncated) {
|
|
75064
75547
|
lines.push(`[Truncated at ${String(MAX_MATCHES)} matches — use a more specific pattern]`);
|
|
75065
75548
|
lines.push(`Only the first ${String(MAX_MATCHES)} matches are returned.`);
|
|
75549
|
+
headerLines = 2;
|
|
75066
75550
|
}
|
|
75067
75551
|
lines.push(...displayLines);
|
|
75068
75552
|
if (!truncated && entries.length === 1e3) lines.push(`Found ${String(entries.length)} matches`);
|
|
75069
75553
|
output = lines.join("\n");
|
|
75070
75554
|
}
|
|
75555
|
+
if (byteLength$1(output) > 51200) {
|
|
75556
|
+
const raw = truncateToBytes(output, MAX_OUTPUT_BYTES$1 - 96);
|
|
75557
|
+
const lastBreak = raw.lastIndexOf("\n");
|
|
75558
|
+
const kept = lastBreak > 0 ? raw.slice(0, lastBreak) : raw;
|
|
75559
|
+
const keptPaths = Math.max(0, countKeptPaths(kept) - headerLines);
|
|
75560
|
+
const omitted = Math.max(1, displayLines.length - keptPaths);
|
|
75561
|
+
output = `${kept}\n[...${String(omitted)} paths omitted: output exceeds ${String(MAX_OUTPUT_BYTES$1 / 1024)} KB — narrow the pattern]`;
|
|
75562
|
+
}
|
|
75071
75563
|
scanCache.set(searchRoots[0], args.pattern, includeDirs, output);
|
|
75072
75564
|
return { output };
|
|
75073
75565
|
} catch (error) {
|
|
@@ -75148,6 +75640,16 @@ function containsBraceExpansion(pattern) {
|
|
|
75148
75640
|
}
|
|
75149
75641
|
return false;
|
|
75150
75642
|
}
|
|
75643
|
+
/**
|
|
75644
|
+
* Paths that survived the byte cut.
|
|
75645
|
+
*
|
|
75646
|
+
* The cut backs up to the last newline, so every retained line is a complete
|
|
75647
|
+
* path: `newlines + 1`, not `newlines`.
|
|
75648
|
+
*/
|
|
75649
|
+
function countKeptPaths(text) {
|
|
75650
|
+
if (text.length === 0) return 0;
|
|
75651
|
+
return text.split("\n").length;
|
|
75652
|
+
}
|
|
75151
75653
|
//#endregion
|
|
75152
75654
|
//#region ../../node_modules/.pnpm/tar@7.5.15/node_modules/tar/dist/esm/index.min.js
|
|
75153
75655
|
var vr = Object.defineProperty;
|
|
@@ -78536,161 +79038,6 @@ function isRegexSyntaxError(stderr) {
|
|
|
78536
79038
|
return REGEX_ERROR_MARKERS.some((marker) => lower.includes(marker));
|
|
78537
79039
|
}
|
|
78538
79040
|
//#endregion
|
|
78539
|
-
//#region ../../packages/agent-core/src/tools/support/result-builder.ts
|
|
78540
|
-
const DEFAULT_MAX_CHARS = 5e4;
|
|
78541
|
-
const DEFAULT_TAIL_CHARS = 2e4;
|
|
78542
|
-
const DEFAULT_MAX_LINE_LENGTH = 2e3;
|
|
78543
|
-
const TRUNCATION_MARKER$1 = "[...truncated]";
|
|
78544
|
-
const TRUNCATION_MESSAGE = "Output is truncated to fit in the message.";
|
|
78545
|
-
var ToolResultBuilder = class {
|
|
78546
|
-
maxChars;
|
|
78547
|
-
maxTailChars;
|
|
78548
|
-
maxLineLength;
|
|
78549
|
-
artifactSink;
|
|
78550
|
-
maxFullOutputChars;
|
|
78551
|
-
buffer = [];
|
|
78552
|
-
nCharsValue = 0;
|
|
78553
|
-
truncationHappened = false;
|
|
78554
|
-
headTruncated = false;
|
|
78555
|
-
tailBuf = [];
|
|
78556
|
-
tailCharsValue = 0;
|
|
78557
|
-
fullOutput;
|
|
78558
|
-
fullOutputChars = 0;
|
|
78559
|
-
totalLinesWritten = 0;
|
|
78560
|
-
constructor(options = {}) {
|
|
78561
|
-
this.maxChars = options.maxChars ?? DEFAULT_MAX_CHARS;
|
|
78562
|
-
this.maxTailChars = options.maxTailChars ?? DEFAULT_TAIL_CHARS;
|
|
78563
|
-
this.maxLineLength = options.maxLineLength === void 0 ? DEFAULT_MAX_LINE_LENGTH : options.maxLineLength;
|
|
78564
|
-
if (this.maxLineLength !== null && this.maxLineLength <= 14) throw new Error("maxLineLength must be greater than the truncation marker length.");
|
|
78565
|
-
this.artifactSink = options.artifactSink;
|
|
78566
|
-
this.maxFullOutputChars = options.maxFullOutputChars ?? 1e6;
|
|
78567
|
-
if (this.artifactSink !== void 0) this.fullOutput = [];
|
|
78568
|
-
}
|
|
78569
|
-
get nChars() {
|
|
78570
|
-
return this.nCharsValue + this.tailCharsValue;
|
|
78571
|
-
}
|
|
78572
|
-
toString() {
|
|
78573
|
-
const head = this.buffer.join("");
|
|
78574
|
-
if (!this.headTruncated || this.tailCharsValue === 0) return head;
|
|
78575
|
-
this.trimTail();
|
|
78576
|
-
const tail = this.tailBuf.join("");
|
|
78577
|
-
const separator = head.endsWith("\n") ? "" : "\n";
|
|
78578
|
-
const elided = this.computeElidedLines(head, tail);
|
|
78579
|
-
return `${head}${separator}${elided > 0 ? `[…${String(elided)} lines elided…]\n${TRUNCATION_MARKER$1}` : TRUNCATION_MARKER$1}\n${tail}`;
|
|
78580
|
-
}
|
|
78581
|
-
write(text) {
|
|
78582
|
-
if (text.length === 0) return 0;
|
|
78583
|
-
const lines = text.match(/[^\r\n]*(?:\r\n|[\n\r])|[^\r\n]+/g) ?? [];
|
|
78584
|
-
if (lines.length === 0) return 0;
|
|
78585
|
-
this.totalLinesWritten += lines.length;
|
|
78586
|
-
if (this.fullOutput !== void 0 && this.fullOutputChars < this.maxFullOutputChars) {
|
|
78587
|
-
this.fullOutput.push(text);
|
|
78588
|
-
this.fullOutputChars += text.length;
|
|
78589
|
-
}
|
|
78590
|
-
let charsWritten = 0;
|
|
78591
|
-
for (const originalLine of lines) if (this.nCharsValue < this.maxChars) {
|
|
78592
|
-
const remainingChars = this.maxChars - this.nCharsValue;
|
|
78593
|
-
const limit = this.maxLineLength === null ? remainingChars : Math.min(remainingChars, this.maxLineLength);
|
|
78594
|
-
let line = originalLine;
|
|
78595
|
-
if (line.length > limit) {
|
|
78596
|
-
const suffix = TRUNCATION_MARKER$1 + (/[\r\n]+$/.exec(line)?.[0] ?? "");
|
|
78597
|
-
const effectiveMaxLength = Math.max(limit, suffix.length);
|
|
78598
|
-
line = line.slice(0, effectiveMaxLength - suffix.length) + suffix;
|
|
78599
|
-
this.truncationHappened = true;
|
|
78600
|
-
}
|
|
78601
|
-
this.buffer.push(line);
|
|
78602
|
-
charsWritten += line.length;
|
|
78603
|
-
this.nCharsValue += line.length;
|
|
78604
|
-
if (this.nCharsValue >= this.maxChars) {
|
|
78605
|
-
this.headTruncated = true;
|
|
78606
|
-
this.truncationHappened = true;
|
|
78607
|
-
}
|
|
78608
|
-
} else {
|
|
78609
|
-
this.appendTail(originalLine);
|
|
78610
|
-
charsWritten += originalLine.length;
|
|
78611
|
-
this.headTruncated = true;
|
|
78612
|
-
this.truncationHappened = true;
|
|
78613
|
-
}
|
|
78614
|
-
return charsWritten;
|
|
78615
|
-
}
|
|
78616
|
-
appendTail(text) {
|
|
78617
|
-
if (text.length === 0) return;
|
|
78618
|
-
if (this.maxTailChars === 0) return;
|
|
78619
|
-
if (text.length >= this.maxTailChars) {
|
|
78620
|
-
const trimmed = text.slice(-this.maxTailChars);
|
|
78621
|
-
this.tailBuf.length = 0;
|
|
78622
|
-
this.tailBuf.push(trimmed);
|
|
78623
|
-
this.tailCharsValue = trimmed.length;
|
|
78624
|
-
return;
|
|
78625
|
-
}
|
|
78626
|
-
this.tailBuf.push(text);
|
|
78627
|
-
this.tailCharsValue += text.length;
|
|
78628
|
-
if (this.tailCharsValue > this.maxTailChars * 2) this.trimTail();
|
|
78629
|
-
}
|
|
78630
|
-
trimTail() {
|
|
78631
|
-
if (this.tailCharsValue <= this.maxTailChars) return;
|
|
78632
|
-
const trimmed = this.tailBuf.join("").slice(-this.maxTailChars);
|
|
78633
|
-
this.tailBuf.length = 0;
|
|
78634
|
-
this.tailBuf.push(trimmed);
|
|
78635
|
-
this.tailCharsValue = trimmed.length;
|
|
78636
|
-
}
|
|
78637
|
-
computeElidedLines(head, tail) {
|
|
78638
|
-
if (this.totalLinesWritten === 0) return 0;
|
|
78639
|
-
if (this.fullOutput !== void 0) {
|
|
78640
|
-
const total = countLines(this.fullOutput.join(""));
|
|
78641
|
-
return Math.max(0, total - countLines(head) - countLines(tail));
|
|
78642
|
-
}
|
|
78643
|
-
return Math.max(0, this.totalLinesWritten - countLines(head) - countLines(tail));
|
|
78644
|
-
}
|
|
78645
|
-
async maybeWriteArtifact() {
|
|
78646
|
-
if (this.artifactSink === void 0 || this.fullOutput === void 0) return void 0;
|
|
78647
|
-
if (!this.truncationHappened) return void 0;
|
|
78648
|
-
const full = this.fullOutput.join("");
|
|
78649
|
-
if (full.length === 0) return void 0;
|
|
78650
|
-
try {
|
|
78651
|
-
return await this.artifactSink(full);
|
|
78652
|
-
} catch {
|
|
78653
|
-
return;
|
|
78654
|
-
}
|
|
78655
|
-
}
|
|
78656
|
-
appendArtifactRef(output, ref) {
|
|
78657
|
-
const line = `[full output saved: ${ref}]`;
|
|
78658
|
-
return output.length === 0 ? line : output.endsWith("\n") ? `${output}${line}` : `${output}\n${line}`;
|
|
78659
|
-
}
|
|
78660
|
-
async ok(message = "", options = {}) {
|
|
78661
|
-
let finalMessage = message;
|
|
78662
|
-
if (finalMessage.length > 0 && !finalMessage.endsWith(".")) finalMessage += ".";
|
|
78663
|
-
if (this.truncationHappened) finalMessage = finalMessage.length === 0 ? TRUNCATION_MESSAGE : `${finalMessage} ${TRUNCATION_MESSAGE}`;
|
|
78664
|
-
const baseOutput = this.toString();
|
|
78665
|
-
const artifactRef = await this.maybeWriteArtifact();
|
|
78666
|
-
const output = artifactRef === void 0 ? baseOutput : this.appendArtifactRef(baseOutput, artifactRef);
|
|
78667
|
-
const shouldAppendMessage = finalMessage.length > 0 && (this.truncationHappened || output.length === 0);
|
|
78668
|
-
return {
|
|
78669
|
-
isError: false,
|
|
78670
|
-
output: shouldAppendMessage ? output.length === 0 ? finalMessage : output.endsWith("\n") ? `${output}${finalMessage}` : `${output}\n${finalMessage}` : output,
|
|
78671
|
-
message: shouldAppendMessage ? void 0 : finalMessage,
|
|
78672
|
-
truncated: this.truncationHappened,
|
|
78673
|
-
brief: options.brief
|
|
78674
|
-
};
|
|
78675
|
-
}
|
|
78676
|
-
async error(message, options = {}) {
|
|
78677
|
-
const finalMessage = this.truncationHappened ? message.length === 0 ? TRUNCATION_MESSAGE : `${message} ${TRUNCATION_MESSAGE}` : message;
|
|
78678
|
-
const baseOutput = this.toString();
|
|
78679
|
-
const artifactRef = await this.maybeWriteArtifact();
|
|
78680
|
-
const output = artifactRef === void 0 ? baseOutput : this.appendArtifactRef(baseOutput, artifactRef);
|
|
78681
|
-
return {
|
|
78682
|
-
isError: true,
|
|
78683
|
-
output: finalMessage.length === 0 ? output : output.length === 0 ? finalMessage : output.endsWith("\n") ? `${output}${finalMessage}` : `${output}\n${finalMessage}`,
|
|
78684
|
-
truncated: this.truncationHappened,
|
|
78685
|
-
brief: options.brief
|
|
78686
|
-
};
|
|
78687
|
-
}
|
|
78688
|
-
};
|
|
78689
|
-
function countLines(text) {
|
|
78690
|
-
if (text.length === 0) return 0;
|
|
78691
|
-
return text.split("\n").length - (text.endsWith("\n") ? 1 : 0);
|
|
78692
|
-
}
|
|
78693
|
-
//#endregion
|
|
78694
79041
|
//#region ../../packages/agent-core/src/tools/builtin/file/grep.md
|
|
78695
79042
|
var grep_default = "Search file contents using regular expressions (powered by ripgrep).\n\nUse Grep when the task is to find unknown content or unknown file locations. Do not use shell `grep` or `rg` directly; this tool applies workspace path policy, output limits, and sensitive-file filtering.\nALWAYS use Grep tool instead of running `grep` or `rg` from a shell - direct shell calls bypass workspace policy, output limits, and sensitive-file filtering.\n\nWrite patterns in ripgrep regex syntax, which differs from POSIX `grep` syntax. For example, braces are special, so escape them as `\\{` to match a literal `{`.\n\nHidden files (dotfiles such as `.gitlab-ci.yml` or `.eslintrc.json`) are searched by default.\n";
|
|
78696
79043
|
//#endregion
|
|
@@ -79839,11 +80186,11 @@ async function partitionExistingPaths(paths, jian, workspace) {
|
|
|
79839
80186
|
}
|
|
79840
80187
|
//#endregion
|
|
79841
80188
|
//#region ../../packages/agent-core/src/tools/builtin/file/read.md
|
|
79842
|
-
var read_default = "Read a text file from the local filesystem.\n\nIf the user provides a concrete file path to a text file, call Read directly. Do not `Glob`, `ls`, or otherwise pre-check known text file paths; missing or invalid file paths return errors you can handle. Do not use Read for directories; use `ls` via Bash for a known directory, or Glob when you need files/directories matching a pattern. Use `Grep` only when the task is to search for unknown content or locations.\n\nWhen you need several files, prefer to read them in parallel: emit multiple `Read` calls in a single response instead of reading one file per turn.\n\n- Returns up to {{ MAX_BYTES_KB }} KB per call; lines longer than {{
|
|
80189
|
+
var read_default = "Read a text file from the local filesystem.\n\nIf the user provides a concrete file path to a text file, call Read directly. Do not `Glob`, `ls`, or otherwise pre-check known text file paths; missing or invalid file paths return errors you can handle. Do not use Read for directories; use `ls` via Bash for a known directory, or Glob when you need files/directories matching a pattern. Use `Grep` only when the task is to search for unknown content or locations.\n\nWhen you need several files, prefer to read them in parallel: emit multiple `Read` calls in a single response instead of reading one file per turn.\n\n- Returns up to {{ MAX_BYTES_KB }} KB per call; lines longer than {{ MAX_LINE_BYTES }} bytes are truncated mid-line, and the status block names the exact bash command that prints such a line in full.\n- Sensitive files (`.env` files, credential stores, SSH keys, and similar secrets) are refused to protect secrets; do not attempt to read them.\n- Only UTF-8 text files can be read. Non-UTF-8 encodings, binary files, and files containing NUL bytes are refused; use `ReadMediaFile` for images or video, and Bash or an MCP tool for other binary formats.\n- Output format: `<line-number>\\t<content>` per line.\n- A `<system>...</system>` status block is appended after the file content; it summarizes how much was read (line and byte counts, truncation, line-ending notes) and is not part of the file itself. The status block includes an `Anchor: <hash>` value that can be passed to `Edit.anchor` to verify the file has not changed before editing.\n- Pure CRLF files are displayed with LF line endings; `Edit` matches this output and preserves CRLF when writing back.\n- Mixed or lone carriage-return line endings are shown as `\\r` and require exact `Edit.old_string` escapes.\n- After a successful `Edit`/`Write`, do not re-read solely to prove the write landed. When the task depends on an exact file, API, or output shape, inspect the final external contract before finishing.\n";
|
|
79843
80190
|
//#endregion
|
|
79844
80191
|
//#region ../../packages/agent-core/src/tools/builtin/file/read.ts
|
|
79845
80192
|
const MAX_LINES = 1e3;
|
|
79846
|
-
const
|
|
80193
|
+
const MAX_LINE_BYTES = 2048;
|
|
79847
80194
|
const MAX_BYTES = 100 * 1024;
|
|
79848
80195
|
const S_IFMT$2 = 61440;
|
|
79849
80196
|
const S_IFREG$1 = 32768;
|
|
@@ -79858,11 +80205,9 @@ z.object({
|
|
|
79858
80205
|
content: z.string(),
|
|
79859
80206
|
lineCount: z.number().int().nonnegative()
|
|
79860
80207
|
});
|
|
79861
|
-
function truncateLine(line,
|
|
79862
|
-
if (line
|
|
79863
|
-
|
|
79864
|
-
const target = Math.max(maxLength, 3);
|
|
79865
|
-
return line.slice(0, target - 3) + marker;
|
|
80208
|
+
function truncateLine(line, maxBytes) {
|
|
80209
|
+
if (byteLength$1(line) <= maxBytes) return line;
|
|
80210
|
+
return truncateToBytes(line, Math.max(maxBytes, 3) - 3) + "...";
|
|
79866
80211
|
}
|
|
79867
80212
|
function stripTrailingLf(line) {
|
|
79868
80213
|
return line.endsWith("\n") ? line.slice(0, -1) : line;
|
|
@@ -79884,7 +80229,7 @@ function lineEndingStyleFromFlags(flags) {
|
|
|
79884
80229
|
}
|
|
79885
80230
|
function renderLine(entry, lineEndingStyle) {
|
|
79886
80231
|
const modelContent = lineEndingStyle === "crlf" && entry.rawContent.endsWith("\r") ? entry.rawContent.slice(0, -1) : entry.rawContent;
|
|
79887
|
-
const truncated = truncateLine(modelContent,
|
|
80232
|
+
const truncated = truncateLine(modelContent, MAX_LINE_BYTES);
|
|
79888
80233
|
const renderedContent = lineEndingStyle === "mixed" ? makeCarriageReturnsVisible(truncated) : truncated;
|
|
79889
80234
|
return {
|
|
79890
80235
|
line: `${String(entry.lineNo)}\t${renderedContent}`,
|
|
@@ -79933,7 +80278,7 @@ function notReadableFileOutput(path) {
|
|
|
79933
80278
|
const READ_DESCRIPTION = renderPrompt(read_default, {
|
|
79934
80279
|
MAX_LINES,
|
|
79935
80280
|
MAX_BYTES_KB: MAX_BYTES / 1024,
|
|
79936
|
-
|
|
80281
|
+
MAX_LINE_BYTES
|
|
79937
80282
|
});
|
|
79938
80283
|
var ReadTool = class {
|
|
79939
80284
|
jian;
|
|
@@ -80205,7 +80550,7 @@ var ReadTool = class {
|
|
|
80205
80550
|
if (input.maxLinesReached) parts.push(`Max ${String(MAX_LINES)} lines reached.`);
|
|
80206
80551
|
else if (input.maxBytesReached) parts.push(`Max ${String(MAX_BYTES)} bytes reached.`);
|
|
80207
80552
|
else if (lineCount < input.requestedLines) parts.push("End of file reached.");
|
|
80208
|
-
if (input.truncatedLineNumbers.length > 0) parts.push(`
|
|
80553
|
+
if (input.truncatedLineNumbers.length > 0) parts.push(`Line(s) [${input.truncatedLineNumbers.join(", ")}] exceed the ${String(Math.floor(MAX_LINE_BYTES / 1024))} KB line limit. Read one with: bash sed -n '<line>p' <file> | head -c 65536 (prints up to 64 KB of that line)`);
|
|
80209
80554
|
if (input.lineEndingStyle === "mixed") parts.push("Mixed or lone carriage-return line endings are shown as \\r. Use exact \\r\\n or \\r escapes in Edit.old_string for those lines.");
|
|
80210
80555
|
parts.push(`Anchor: ${input.anchor}`);
|
|
80211
80556
|
return parts.join(" ");
|
|
@@ -80741,7 +81086,7 @@ var WriteTool = class {
|
|
|
80741
81086
|
overwriteFileDiffDisplay(content, existing) {
|
|
80742
81087
|
if (existing.kind === "missing") return {
|
|
80743
81088
|
kind: "file_diff",
|
|
80744
|
-
added: countLines
|
|
81089
|
+
added: countLines(content),
|
|
80745
81090
|
removed: 0
|
|
80746
81091
|
};
|
|
80747
81092
|
if (existing.kind === "unavailable") return void 0;
|
|
@@ -81759,7 +82104,7 @@ var ManagePluginTool = class {
|
|
|
81759
82104
|
if (record === void 0) return result(notFound(id, manager), true);
|
|
81760
82105
|
const runtime = this.runtime;
|
|
81761
82106
|
if (runtime === void 0) return result(fail$1("extension_runtime_unavailable", "This runtime has no extension manager, so plugin code cannot be activated.", "The plugin stays installed; use the /plugin command or report this so the host can expose an ExtensionRuntime."), true);
|
|
81762
|
-
if (runtime.isActive(record.id)) return result({
|
|
82107
|
+
if (runtime.isActive(record.id, this.agent.sessionId)) return result({
|
|
81763
82108
|
action: "activate",
|
|
81764
82109
|
id: record.id,
|
|
81765
82110
|
active: true,
|
|
@@ -81797,7 +82142,7 @@ var ManagePluginTool = class {
|
|
|
81797
82142
|
async reloadCode(manager, id) {
|
|
81798
82143
|
const record = manager.get(id);
|
|
81799
82144
|
if (record === void 0) return result(notFound(id, manager), true);
|
|
81800
|
-
if (this.runtime?.isActive(record.id) === true) {
|
|
82145
|
+
if (this.runtime?.isActive(record.id, this.agent?.sessionId) === true) {
|
|
81801
82146
|
const stopped = await this.deactivate(manager, record.id);
|
|
81802
82147
|
if (stopped.isError === true) return stopped;
|
|
81803
82148
|
}
|
|
@@ -81811,12 +82156,15 @@ var ManagePluginTool = class {
|
|
|
81811
82156
|
});
|
|
81812
82157
|
}
|
|
81813
82158
|
async deactivate(manager, id) {
|
|
82159
|
+
return this.deactivateSession(manager, id, this.agent?.sessionId);
|
|
82160
|
+
}
|
|
82161
|
+
async deactivateSession(manager, id, sessionId) {
|
|
81814
82162
|
const record = manager.get(id);
|
|
81815
82163
|
if (record === void 0) return result(notFound(id, manager), true);
|
|
81816
82164
|
const runtime = this.runtime;
|
|
81817
82165
|
if (runtime === void 0) return result(fail$1("extension_runtime_unavailable", "This runtime has no extension manager to deactivate from.", "Use the /plugin command or report this so the host can expose an ExtensionRuntime."), true);
|
|
81818
82166
|
const wasActive = runtime.isActive(record.id);
|
|
81819
|
-
await runtime.deactivate(record.id);
|
|
82167
|
+
await runtime.deactivate(record.id, sessionId);
|
|
81820
82168
|
const toolsUnregistered = this.agent.services?.tools?.unregisterToolsByOwner?.(record.id) ?? 0;
|
|
81821
82169
|
return result({
|
|
81822
82170
|
action: "deactivate",
|
|
@@ -83598,7 +83946,11 @@ var BashTool = class {
|
|
|
83598
83946
|
try {
|
|
83599
83947
|
const builder = new ToolResultBuilder({ artifactSink: async (fullOutput) => {
|
|
83600
83948
|
const artifactPath = join(tmpdir(), `scream-bash-output-${randomUUID()}.log`);
|
|
83601
|
-
await writeFile(artifactPath, fullOutput,
|
|
83949
|
+
await writeFile(artifactPath, fullOutput, {
|
|
83950
|
+
encoding: "utf8",
|
|
83951
|
+
mode: 384,
|
|
83952
|
+
flag: "wx"
|
|
83953
|
+
});
|
|
83602
83954
|
return artifactPath;
|
|
83603
83955
|
} });
|
|
83604
83956
|
const stdoutDone = readStreamIntoBuilder(proc.stdout, builder, (text) => forwardChunk("stdout", text));
|
|
@@ -84499,7 +84851,7 @@ var FetchURLTool = class {
|
|
|
84499
84851
|
output: "The response body is empty.",
|
|
84500
84852
|
isError: false
|
|
84501
84853
|
};
|
|
84502
|
-
const builder = new ToolResultBuilder({
|
|
84854
|
+
const builder = new ToolResultBuilder({ maxLineBytes: null });
|
|
84503
84855
|
builder.write(content);
|
|
84504
84856
|
const message = kind === "passthrough" ? "The returned content is the full response body, returned verbatim." : "The returned content is the main text extracted from the page.";
|
|
84505
84857
|
return builder.ok(message);
|
|
@@ -84584,7 +84936,7 @@ var PaperSearchTool = class {
|
|
|
84584
84936
|
if (args.year_from !== void 0) options.yearFrom = args.year_from;
|
|
84585
84937
|
if (args.sources !== void 0) options.sources = args.sources;
|
|
84586
84938
|
const { results, failures } = await this.provider.search(args.query, options);
|
|
84587
|
-
const builder = new ToolResultBuilder({
|
|
84939
|
+
const builder = new ToolResultBuilder({ maxLineBytes: null });
|
|
84588
84940
|
if (results.length === 0) builder.write("No papers found.");
|
|
84589
84941
|
else {
|
|
84590
84942
|
let first = true;
|
|
@@ -84690,7 +85042,7 @@ var WebSearchTool = class {
|
|
|
84690
85042
|
if (args.limit !== void 0) opts.limit = args.limit;
|
|
84691
85043
|
if (args.include_content !== void 0) opts.includeContent = args.include_content;
|
|
84692
85044
|
const results = await this.provider.search(args.query, opts);
|
|
84693
|
-
const builder = new ToolResultBuilder({
|
|
85045
|
+
const builder = new ToolResultBuilder({ maxLineBytes: null });
|
|
84694
85046
|
if (results.length === 0) {
|
|
84695
85047
|
builder.write("No search results found.");
|
|
84696
85048
|
return builder.ok();
|
|
@@ -90250,13 +90602,13 @@ const KILL_GRACE_MS = 100;
|
|
|
90250
90602
|
* HookResult. Outputs below the cap round-trip byte-for-byte, so structured
|
|
90251
90603
|
* JSON parsing is unaffected.
|
|
90252
90604
|
*/
|
|
90253
|
-
const
|
|
90254
|
-
const
|
|
90605
|
+
const HOOK_STREAM_MAX_BYTES = 24 * 1024;
|
|
90606
|
+
const HOOK_STREAM_TAIL_BYTES = 8 * 1024;
|
|
90255
90607
|
function createHookStreamBuffer() {
|
|
90256
90608
|
return new ToolResultBuilder({
|
|
90257
|
-
|
|
90258
|
-
|
|
90259
|
-
|
|
90609
|
+
maxBytes: HOOK_STREAM_MAX_BYTES,
|
|
90610
|
+
maxTailBytes: HOOK_STREAM_TAIL_BYTES,
|
|
90611
|
+
maxLineBytes: null
|
|
90260
90612
|
});
|
|
90261
90613
|
}
|
|
90262
90614
|
const OptionalStringSchema = z.preprocess((value) => {
|
|
@@ -109584,6 +109936,9 @@ var ToolManager = class {
|
|
|
109584
109936
|
this.agent.cron && new CronListTool(this.agent.cron),
|
|
109585
109937
|
this.agent.cron && new CronDeleteTool(this.agent.cron),
|
|
109586
109938
|
this.agent.mcp && new DiscoverMcpToolsTool(this),
|
|
109939
|
+
this.agent.mcp && new ListMcpResourcesTool(this.agent),
|
|
109940
|
+
this.agent.mcp && new ListMcpResourceTemplatesTool(this.agent),
|
|
109941
|
+
this.agent.mcp && new ReadMcpResourceTool(this.agent),
|
|
109587
109942
|
this.agent.type === "main" && new CreateGoalTool(this.agent),
|
|
109588
109943
|
this.agent.type === "main" && new UpdateGoalTool(this.agent, createGoalGrader(this.agent)),
|
|
109589
109944
|
this.agent.type === "main" && new GetGoalTool(this.agent),
|
|
@@ -115069,6 +115424,47 @@ var HttpMcpClient = class {
|
|
|
115069
115424
|
async listTools() {
|
|
115070
115425
|
return (await this.client.listTools()).tools.map(toMcpToolDefinition);
|
|
115071
115426
|
}
|
|
115427
|
+
getInstructions() {
|
|
115428
|
+
const instructions = this.client.getInstructions?.();
|
|
115429
|
+
return typeof instructions === "string" && instructions.length > 0 ? instructions : void 0;
|
|
115430
|
+
}
|
|
115431
|
+
async listResources() {
|
|
115432
|
+
if (this.client.getServerCapabilities()?.resources === void 0) return [];
|
|
115433
|
+
return (await this.client.listResources()).resources.map((resource) => ({
|
|
115434
|
+
uri: resource.uri,
|
|
115435
|
+
...resource.name === void 0 ? {} : { name: resource.name },
|
|
115436
|
+
...resource.description === void 0 ? {} : { description: resource.description },
|
|
115437
|
+
...resource.mimeType === void 0 ? {} : { mimeType: resource.mimeType }
|
|
115438
|
+
}));
|
|
115439
|
+
}
|
|
115440
|
+
async readResource(uri) {
|
|
115441
|
+
const parts = (await this.client.readResource({ uri })).contents;
|
|
115442
|
+
const first = parts[0];
|
|
115443
|
+
if (first === void 0) return { uri };
|
|
115444
|
+
const texts = parts.map((part) => part.text).filter((value) => typeof value === "string");
|
|
115445
|
+
return {
|
|
115446
|
+
uri: first.uri ?? uri,
|
|
115447
|
+
...first.mimeType === void 0 ? {} : { mimeType: first.mimeType },
|
|
115448
|
+
...texts.length === 0 ? {} : { text: texts.join("\n\n") }
|
|
115449
|
+
};
|
|
115450
|
+
}
|
|
115451
|
+
async listResourceTemplates() {
|
|
115452
|
+
if (this.client.getServerCapabilities()?.resources === void 0) return [];
|
|
115453
|
+
return (await this.client.listResourceTemplates()).resourceTemplates.map((template) => ({
|
|
115454
|
+
uriTemplate: template.uriTemplate,
|
|
115455
|
+
...template.name === void 0 ? {} : { name: template.name },
|
|
115456
|
+
...template.description === void 0 ? {} : { description: template.description },
|
|
115457
|
+
...template.mimeType === void 0 ? {} : { mimeType: template.mimeType }
|
|
115458
|
+
}));
|
|
115459
|
+
}
|
|
115460
|
+
async listPrompts() {
|
|
115461
|
+
if (this.client.getServerCapabilities()?.prompts === void 0) return [];
|
|
115462
|
+
return (await this.client.listPrompts()).prompts.map((prompt) => ({
|
|
115463
|
+
name: prompt.name,
|
|
115464
|
+
...prompt.description === void 0 ? {} : { description: prompt.description },
|
|
115465
|
+
...prompt.arguments === void 0 ? {} : { arguments: prompt.arguments.map((argument) => argument.name) }
|
|
115466
|
+
}));
|
|
115467
|
+
}
|
|
115072
115468
|
async callTool(name, args, signal) {
|
|
115073
115469
|
const requestOptions = buildRequestOptions(this.toolCallTimeoutMs, signal);
|
|
115074
115470
|
return toMcpToolResult(await this.client.callTool({
|
|
@@ -115819,6 +116215,47 @@ var StdioMcpClient = class {
|
|
|
115819
116215
|
async listTools() {
|
|
115820
116216
|
return (await this.client.listTools()).tools.map(toMcpToolDefinition);
|
|
115821
116217
|
}
|
|
116218
|
+
getInstructions() {
|
|
116219
|
+
const instructions = this.client.getInstructions?.();
|
|
116220
|
+
return typeof instructions === "string" && instructions.length > 0 ? instructions : void 0;
|
|
116221
|
+
}
|
|
116222
|
+
async listResources() {
|
|
116223
|
+
if (this.client.getServerCapabilities()?.resources === void 0) return [];
|
|
116224
|
+
return (await this.client.listResources()).resources.map((resource) => ({
|
|
116225
|
+
uri: resource.uri,
|
|
116226
|
+
...resource.name === void 0 ? {} : { name: resource.name },
|
|
116227
|
+
...resource.description === void 0 ? {} : { description: resource.description },
|
|
116228
|
+
...resource.mimeType === void 0 ? {} : { mimeType: resource.mimeType }
|
|
116229
|
+
}));
|
|
116230
|
+
}
|
|
116231
|
+
async readResource(uri) {
|
|
116232
|
+
const parts = (await this.client.readResource({ uri })).contents;
|
|
116233
|
+
const first = parts[0];
|
|
116234
|
+
if (first === void 0) return { uri };
|
|
116235
|
+
const texts = parts.map((part) => part.text).filter((value) => typeof value === "string");
|
|
116236
|
+
return {
|
|
116237
|
+
uri: first.uri ?? uri,
|
|
116238
|
+
...first.mimeType === void 0 ? {} : { mimeType: first.mimeType },
|
|
116239
|
+
...texts.length === 0 ? {} : { text: texts.join("\n\n") }
|
|
116240
|
+
};
|
|
116241
|
+
}
|
|
116242
|
+
async listResourceTemplates() {
|
|
116243
|
+
if (this.client.getServerCapabilities()?.resources === void 0) return [];
|
|
116244
|
+
return (await this.client.listResourceTemplates()).resourceTemplates.map((template) => ({
|
|
116245
|
+
uriTemplate: template.uriTemplate,
|
|
116246
|
+
...template.name === void 0 ? {} : { name: template.name },
|
|
116247
|
+
...template.description === void 0 ? {} : { description: template.description },
|
|
116248
|
+
...template.mimeType === void 0 ? {} : { mimeType: template.mimeType }
|
|
116249
|
+
}));
|
|
116250
|
+
}
|
|
116251
|
+
async listPrompts() {
|
|
116252
|
+
if (this.client.getServerCapabilities()?.prompts === void 0) return [];
|
|
116253
|
+
return (await this.client.listPrompts()).prompts.map((prompt) => ({
|
|
116254
|
+
name: prompt.name,
|
|
116255
|
+
...prompt.description === void 0 ? {} : { description: prompt.description },
|
|
116256
|
+
...prompt.arguments === void 0 ? {} : { arguments: prompt.arguments.map((argument) => argument.name) }
|
|
116257
|
+
}));
|
|
116258
|
+
}
|
|
115822
116259
|
async callTool(name, args, signal) {
|
|
115823
116260
|
const requestOptions = buildRequestOptions(this.toolCallTimeoutMs, signal);
|
|
115824
116261
|
return toMcpToolResult(await this.client.callTool({
|
|
@@ -116323,6 +116760,29 @@ async function resolveSessionMcpConfig(input) {
|
|
|
116323
116760
|
return { servers };
|
|
116324
116761
|
}
|
|
116325
116762
|
//#endregion
|
|
116763
|
+
//#region ../../packages/agent-core/src/mcp/instructions.ts
|
|
116764
|
+
/**
|
|
116765
|
+
* Server instructions from every connected MCP server, as a bullet list.
|
|
116766
|
+
*
|
|
116767
|
+
* The MCP handshake lets a server describe how its tools should be used
|
|
116768
|
+
* (`initialize.instructions`). Those notes are per-connection, so they cannot
|
|
116769
|
+
* live in the static system prompt: MCP servers load asynchronously after the
|
|
116770
|
+
* prompt is rendered, and a prompt rebuilt later would invalidate the prefix
|
|
116771
|
+
* cache. The session injects this text as a reminder once the connections
|
|
116772
|
+
* settle, and again when the set of connected servers changes.
|
|
116773
|
+
*/
|
|
116774
|
+
function collectMcpInstructions(mcp) {
|
|
116775
|
+
if (mcp === void 0) return "";
|
|
116776
|
+
const blocks = [];
|
|
116777
|
+
for (const entry of mcp.list()) {
|
|
116778
|
+
if (entry.status !== "connected") continue;
|
|
116779
|
+
const text = mcp.resolved(entry.name)?.client.getInstructions?.();
|
|
116780
|
+
if (text === void 0) continue;
|
|
116781
|
+
blocks.push(`- **${entry.name}**: ${text.replaceAll("\n", "\n ")}`);
|
|
116782
|
+
}
|
|
116783
|
+
return blocks.join("\n");
|
|
116784
|
+
}
|
|
116785
|
+
//#endregion
|
|
116326
116786
|
//#region ../../packages/agent-core/src/session/git-context.ts
|
|
116327
116787
|
const GIT_TIMEOUT_MS = 5e3;
|
|
116328
116788
|
const MAX_DIRTY_FILES = 20;
|
|
@@ -117433,6 +117893,9 @@ var Session$1 = class {
|
|
|
117433
117893
|
backgroundManagers = /* @__PURE__ */ new Set();
|
|
117434
117894
|
skillsReady;
|
|
117435
117895
|
mcpReady;
|
|
117896
|
+
/** Coalesces a burst of MCP connect events into one instructions reminder. */
|
|
117897
|
+
mcpInstructionsTimer;
|
|
117898
|
+
lastMcpInstructions = "";
|
|
117436
117899
|
metadata = {
|
|
117437
117900
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
117438
117901
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -117522,6 +117985,9 @@ var Session$1 = class {
|
|
|
117522
117985
|
const { agent } = await this.createAgent({ type: "main" }, profile ?? DEFAULT_AGENT_PROFILES["agent"]);
|
|
117523
117986
|
await agent.memoStoreReady;
|
|
117524
117987
|
await agent.knowledgeStoreReady;
|
|
117988
|
+
this.mcpReady.then(() => {
|
|
117989
|
+
this.injectMcpInstructions();
|
|
117990
|
+
});
|
|
117525
117991
|
await this.triggerSessionStart("startup");
|
|
117526
117992
|
return agent;
|
|
117527
117993
|
}
|
|
@@ -117556,10 +118022,17 @@ var Session$1 = class {
|
|
|
117556
118022
|
kind: "injection",
|
|
117557
118023
|
variant: "recap"
|
|
117558
118024
|
});
|
|
118025
|
+
if (main !== void 0) this.mcpReady.then(() => {
|
|
118026
|
+
this.injectMcpInstructions();
|
|
118027
|
+
});
|
|
117559
118028
|
await this.triggerSessionStart("resume");
|
|
117560
118029
|
return { warning: resumeWarning };
|
|
117561
118030
|
}
|
|
117562
118031
|
async close() {
|
|
118032
|
+
if (this.mcpInstructionsTimer !== void 0) {
|
|
118033
|
+
clearTimeout(this.mcpInstructionsTimer);
|
|
118034
|
+
this.mcpInstructionsTimer = void 0;
|
|
118035
|
+
}
|
|
117563
118036
|
for (const manager of this.liveBackgroundManagers()) manager.markSessionClosed();
|
|
117564
118037
|
const main = this.agents.get("main");
|
|
117565
118038
|
if (main !== void 0) {
|
|
@@ -117872,6 +118345,7 @@ var Session$1 = class {
|
|
|
117872
118345
|
}).catch(() => {});
|
|
117873
118346
|
}
|
|
117874
118347
|
onMcpServerStatusChange(entry) {
|
|
118348
|
+
this.scheduleMcpInstructionsInjection();
|
|
117875
118349
|
this.rpc.emitEvent({
|
|
117876
118350
|
type: "mcp.server.status",
|
|
117877
118351
|
agentId: "main",
|
|
@@ -117889,6 +118363,33 @@ var Session$1 = class {
|
|
|
117889
118363
|
const timeoutS = this.options.background?.agentTaskTimeoutS;
|
|
117890
118364
|
return timeoutS === void 0 ? void 0 : timeoutS * 1e3;
|
|
117891
118365
|
}
|
|
118366
|
+
/**
|
|
118367
|
+
* Inject MCP server instructions once the connections settle.
|
|
118368
|
+
*
|
|
118369
|
+
* Servers connect asynchronously and often in a burst, so a short coalescing
|
|
118370
|
+
* window turns "three servers connected" into one reminder instead of three.
|
|
118371
|
+
* The text is compared against the last injection: reconnects that carry the
|
|
118372
|
+
* same instructions stay silent.
|
|
118373
|
+
*/
|
|
118374
|
+
scheduleMcpInstructionsInjection() {
|
|
118375
|
+
if (this.mcpInstructionsTimer !== void 0) clearTimeout(this.mcpInstructionsTimer);
|
|
118376
|
+
this.mcpInstructionsTimer = setTimeout(() => {
|
|
118377
|
+
this.mcpInstructionsTimer = void 0;
|
|
118378
|
+
this.injectMcpInstructions();
|
|
118379
|
+
}, 250);
|
|
118380
|
+
this.mcpInstructionsTimer.unref?.();
|
|
118381
|
+
}
|
|
118382
|
+
injectMcpInstructions() {
|
|
118383
|
+
const text = collectMcpInstructions(this.mcp);
|
|
118384
|
+
if (text.length === 0 || text === this.lastMcpInstructions) return;
|
|
118385
|
+
const main = this.agents.get("main");
|
|
118386
|
+
if (main === void 0) return;
|
|
118387
|
+
this.lastMcpInstructions = text;
|
|
118388
|
+
main.context.appendSystemReminder(`<scream-mcp-instructions>\n${text}\n</scream-mcp-instructions>`, {
|
|
118389
|
+
kind: "injection",
|
|
118390
|
+
variant: "mcp-instructions"
|
|
118391
|
+
});
|
|
118392
|
+
}
|
|
117892
118393
|
refreshAgentBuiltinTools() {
|
|
117893
118394
|
for (const agent of this.agents.values()) {
|
|
117894
118395
|
if (!agent.config.hasProvider) continue;
|
|
@@ -118104,24 +118605,78 @@ function createRPC() {
|
|
|
118104
118605
|
return [leftClient, rightClient];
|
|
118105
118606
|
}
|
|
118106
118607
|
//#endregion
|
|
118107
|
-
//#region ../../packages/agent-core/src/plugin/runtime/
|
|
118608
|
+
//#region ../../packages/agent-core/src/plugin/runtime/ui.ts
|
|
118108
118609
|
/**
|
|
118109
|
-
*
|
|
118610
|
+
* `QuestionResult` may be the answer map itself or a wrapper carrying
|
|
118611
|
+
* `answers`; both shapes reach a plugin depending on the host.
|
|
118612
|
+
*/
|
|
118613
|
+
function readAnswer(result, question) {
|
|
118614
|
+
if (result === null) return void 0;
|
|
118615
|
+
if ("answers" in result) return result.answers?.[question];
|
|
118616
|
+
return result[question];
|
|
118617
|
+
}
|
|
118618
|
+
/** Progress text is a status line; a burst of updates must not flood it. */
|
|
118619
|
+
const PROGRESS_MIN_INTERVAL_MS = 200;
|
|
118620
|
+
/**
|
|
118621
|
+
* Build the `ui` surface for one plugin activation.
|
|
118110
118622
|
*
|
|
118111
|
-
*
|
|
118112
|
-
*
|
|
118113
|
-
*
|
|
118114
|
-
*
|
|
118115
|
-
* then call the plugin's `activate(context)`; tools are registered by the
|
|
118116
|
-
* plugin itself via `context.services.tools.registerUserTool`. Hooks and
|
|
118117
|
-
* event subscriptions made during a failed activation are rolled back
|
|
118118
|
-
* - `deactivate()` — symmetric removal (hooks + event subscriptions +
|
|
118119
|
-
* deactivate hook + the cached module, so an edited entry point is re-imported
|
|
118120
|
-
* on the next activate), isolated so a failing plugin never breaks the agent
|
|
118121
|
-
*
|
|
118122
|
-
* Activation is deliberately lazy (a `/plugin activate` command or explicit
|
|
118123
|
-
* config opt-in), so merely installing a plugin never executes its code.
|
|
118623
|
+
* `notify` rides the existing `warning` event (the host already renders it as a
|
|
118624
|
+
* status message) with `code: 'plugin:<level>'` so the UI could style levels
|
|
118625
|
+
* later without a new event type. `confirm` rides `requestQuestion`, the same
|
|
118626
|
+
* channel `AskUserQuestion` uses, so the TUI needs no new dialog code.
|
|
118124
118627
|
*/
|
|
118628
|
+
function createPluginUi(agent, pluginId) {
|
|
118629
|
+
const notify = (level, message) => {
|
|
118630
|
+
agent.eventBus.dispatch({
|
|
118631
|
+
type: "warning",
|
|
118632
|
+
message: `[${pluginId}] ${message}`,
|
|
118633
|
+
code: `plugin:${level}`
|
|
118634
|
+
});
|
|
118635
|
+
};
|
|
118636
|
+
return {
|
|
118637
|
+
notify,
|
|
118638
|
+
async confirm(request) {
|
|
118639
|
+
const ask = agent.rpc?.requestQuestion;
|
|
118640
|
+
const confirmLabel = request.confirmLabel ?? "Yes";
|
|
118641
|
+
if (ask === void 0) {
|
|
118642
|
+
notify("warn", `"${request.title}" needs a confirmation, but this host cannot ask; denied.`);
|
|
118643
|
+
return false;
|
|
118644
|
+
}
|
|
118645
|
+
try {
|
|
118646
|
+
return readAnswer(await ask.call(agent.rpc, { questions: [{
|
|
118647
|
+
question: request.title,
|
|
118648
|
+
...request.body === void 0 ? {} : { body: request.body },
|
|
118649
|
+
options: [{ label: confirmLabel }, { label: request.cancelLabel ?? "No" }]
|
|
118650
|
+
}] }), request.title) === confirmLabel;
|
|
118651
|
+
} catch {
|
|
118652
|
+
return false;
|
|
118653
|
+
}
|
|
118654
|
+
},
|
|
118655
|
+
progress(title) {
|
|
118656
|
+
let lastEmit = 0;
|
|
118657
|
+
const emit = (level, text) => {
|
|
118658
|
+
const now = Date.now();
|
|
118659
|
+
if (level === "info" && now - lastEmit < PROGRESS_MIN_INTERVAL_MS) return;
|
|
118660
|
+
lastEmit = now;
|
|
118661
|
+
notify(level, text);
|
|
118662
|
+
};
|
|
118663
|
+
emit("info", `${title}…`);
|
|
118664
|
+
return {
|
|
118665
|
+
update: (label) => {
|
|
118666
|
+
emit("info", `${title}: ${label}`);
|
|
118667
|
+
},
|
|
118668
|
+
done: (message) => {
|
|
118669
|
+
emit("info", message ?? `${title}: done`);
|
|
118670
|
+
},
|
|
118671
|
+
fail: (message) => {
|
|
118672
|
+
emit("error", message ?? `${title}: failed`);
|
|
118673
|
+
}
|
|
118674
|
+
};
|
|
118675
|
+
}
|
|
118676
|
+
};
|
|
118677
|
+
}
|
|
118678
|
+
//#endregion
|
|
118679
|
+
//#region ../../packages/agent-core/src/plugin/runtime/extension.ts
|
|
118125
118680
|
var ExtensionRuntime = class {
|
|
118126
118681
|
loaded = /* @__PURE__ */ new Map();
|
|
118127
118682
|
/**
|
|
@@ -118133,6 +118688,11 @@ var ExtensionRuntime = class {
|
|
|
118133
118688
|
* an activation failed, which made reload re-run the broken code.
|
|
118134
118689
|
*/
|
|
118135
118690
|
generations = /* @__PURE__ */ new Map();
|
|
118691
|
+
/**
|
|
118692
|
+
* Live activations, keyed by session then plugin: two sessions can run the
|
|
118693
|
+
* same plugin independently (each with its own hooks, subscriptions and
|
|
118694
|
+
* user tools), and stopping it in one must not affect the other.
|
|
118695
|
+
*/
|
|
118136
118696
|
activations = /* @__PURE__ */ new Map();
|
|
118137
118697
|
/** Plugins that declare a code entry point, in installation order. */
|
|
118138
118698
|
discover(plugins) {
|
|
@@ -118183,7 +118743,9 @@ var ExtensionRuntime = class {
|
|
|
118183
118743
|
}
|
|
118184
118744
|
/** Activate a discovered plugin against a live agent. */
|
|
118185
118745
|
async activate(agent, extension) {
|
|
118186
|
-
|
|
118746
|
+
const sessionKey = agent.sessionId ?? "";
|
|
118747
|
+
const sessionActivations = this.sessionActivations(sessionKey);
|
|
118748
|
+
if (sessionActivations.has(extension.pluginId)) throw new Error(`Plugin "${extension.pluginId}" is already active`);
|
|
118187
118749
|
await this.assertConfined(extension);
|
|
118188
118750
|
const module = await this.load(extension.entryPoint);
|
|
118189
118751
|
let hooksUnregister;
|
|
@@ -118192,10 +118754,11 @@ var ExtensionRuntime = class {
|
|
|
118192
118754
|
let handlerFaults = 0;
|
|
118193
118755
|
const onHandlerFault = () => {
|
|
118194
118756
|
handlerFaults += 1;
|
|
118195
|
-
if (handlerFaults >= 3 && this.isActive(extension.pluginId)) this.deactivate(extension.pluginId);
|
|
118757
|
+
if (handlerFaults >= 3 && this.isActive(extension.pluginId, sessionKey)) this.deactivate(extension.pluginId, sessionKey);
|
|
118196
118758
|
};
|
|
118197
118759
|
const context = {
|
|
118198
118760
|
services: withPluginToolOwnership(agent.services, extension.pluginId),
|
|
118761
|
+
ui: createPluginUi(agent, extension.pluginId),
|
|
118199
118762
|
events: createTrackedEventBus(agent.eventBus, subscriptions, onHandlerFault),
|
|
118200
118763
|
config: extension.manifest.config,
|
|
118201
118764
|
pluginId: extension.pluginId
|
|
@@ -118208,7 +118771,7 @@ var ExtensionRuntime = class {
|
|
|
118208
118771
|
this.invalidate(extension.entryPoint);
|
|
118209
118772
|
throw error;
|
|
118210
118773
|
}
|
|
118211
|
-
|
|
118774
|
+
sessionActivations.set(extension.pluginId, {
|
|
118212
118775
|
module,
|
|
118213
118776
|
entryPoint: extension.entryPoint,
|
|
118214
118777
|
hooksUnregister,
|
|
@@ -118217,13 +118780,26 @@ var ExtensionRuntime = class {
|
|
|
118217
118780
|
agent
|
|
118218
118781
|
});
|
|
118219
118782
|
}
|
|
118220
|
-
/**
|
|
118221
|
-
|
|
118222
|
-
|
|
118223
|
-
|
|
118783
|
+
/**
|
|
118784
|
+
* Deactivate a plugin in one session, or everywhere when no session is given.
|
|
118785
|
+
*
|
|
118786
|
+
* Hosts that do not know the owning session (a global disable/remove, a
|
|
118787
|
+
* capability sync unwind) pass `undefined` and hit every copy; an explicit
|
|
118788
|
+
* session id only unwinds that one.
|
|
118789
|
+
*/
|
|
118790
|
+
async deactivate(pluginId, sessionId) {
|
|
118791
|
+
const sessionKeys = sessionId === void 0 ? [...this.activations.keys()] : sessionId !== "" && this.activations.has(sessionId) ? [sessionId] : sessionId === "" ? [...this.activations.keys()].filter((key) => key === "") : [];
|
|
118792
|
+
for (const sessionKey of sessionKeys) await this.deactivateInSession(sessionKey, pluginId);
|
|
118793
|
+
}
|
|
118794
|
+
/** Tear down one activation record; the plugin's own deactivate is isolated. */
|
|
118795
|
+
async deactivateInSession(sessionKey, pluginId) {
|
|
118796
|
+
const sessionActivations = this.activations.get(sessionKey);
|
|
118797
|
+
const activation = sessionActivations?.get(pluginId);
|
|
118798
|
+
if (sessionActivations === void 0 || activation === void 0) return;
|
|
118224
118799
|
activation.hooksUnregister?.();
|
|
118225
118800
|
releaseSubscriptions(activation.subscriptions);
|
|
118226
|
-
|
|
118801
|
+
sessionActivations.delete(pluginId);
|
|
118802
|
+
if (sessionActivations.size === 0) this.activations.delete(sessionKey);
|
|
118227
118803
|
this.invalidate(activation.entryPoint);
|
|
118228
118804
|
try {
|
|
118229
118805
|
activation.agent.services.tools?.unregisterToolsByOwner?.(pluginId);
|
|
@@ -118233,6 +118809,7 @@ var ExtensionRuntime = class {
|
|
|
118233
118809
|
} catch (error) {
|
|
118234
118810
|
activation.log?.warn("plugin deactivate failed", {
|
|
118235
118811
|
pluginId,
|
|
118812
|
+
sessionId: sessionKey === "" ? void 0 : sessionKey,
|
|
118236
118813
|
error: error instanceof Error ? error.message : String(error)
|
|
118237
118814
|
});
|
|
118238
118815
|
}
|
|
@@ -118241,14 +118818,40 @@ var ExtensionRuntime = class {
|
|
|
118241
118818
|
* Deactivate every live plugin. Provided so a host can tear down all code
|
|
118242
118819
|
* plugins in one call; each plugin's failure is isolated from the others.
|
|
118243
118820
|
*/
|
|
118821
|
+
/**
|
|
118822
|
+
* Tear down every plugin activated in one session.
|
|
118823
|
+
*
|
|
118824
|
+
* Called when a session closes: its bucket would otherwise outlive the
|
|
118825
|
+
* agent, keeping `isActive(pluginId)` true and making the plugin centre show
|
|
118826
|
+
* ● for a session nobody runs.
|
|
118827
|
+
*/
|
|
118828
|
+
async deactivateSession(sessionId) {
|
|
118829
|
+
const sessionActivations = this.activations.get(sessionId);
|
|
118830
|
+
if (sessionActivations === void 0) return;
|
|
118831
|
+
for (const pluginId of Array.from(sessionActivations.keys())) await this.deactivateInSession(sessionId, pluginId);
|
|
118832
|
+
}
|
|
118244
118833
|
async deactivateAll() {
|
|
118245
|
-
for (const
|
|
118834
|
+
for (const [sessionKey, plugins] of Array.from(this.activations.entries())) for (const pluginId of Array.from(plugins.keys())) await this.deactivateInSession(sessionKey, pluginId);
|
|
118246
118835
|
}
|
|
118247
|
-
|
|
118248
|
-
|
|
118836
|
+
/** Whether the plugin is live in the given session (or anywhere, when omitted). */
|
|
118837
|
+
isActive(pluginId, sessionId) {
|
|
118838
|
+
if (sessionId !== void 0) return this.activations.get(sessionId)?.has(pluginId) === true;
|
|
118839
|
+
for (const plugins of this.activations.values()) if (plugins.has(pluginId)) return true;
|
|
118840
|
+
return false;
|
|
118841
|
+
}
|
|
118842
|
+
/** Live plugin ids for a session (or across all sessions, when omitted). */
|
|
118843
|
+
activePluginIds(sessionId) {
|
|
118844
|
+
if (sessionId !== void 0) return [...this.activations.get(sessionId)?.keys() ?? []];
|
|
118845
|
+
return [...new Set([...this.activations.values()].flatMap((plugins) => [...plugins.keys()]))];
|
|
118249
118846
|
}
|
|
118250
|
-
|
|
118251
|
-
|
|
118847
|
+
/** Get-or-create the per-session bucket. */
|
|
118848
|
+
sessionActivations(sessionKey) {
|
|
118849
|
+
let bucket = this.activations.get(sessionKey);
|
|
118850
|
+
if (bucket === void 0) {
|
|
118851
|
+
bucket = /* @__PURE__ */ new Map();
|
|
118852
|
+
this.activations.set(sessionKey, bucket);
|
|
118853
|
+
}
|
|
118854
|
+
return bucket;
|
|
118252
118855
|
}
|
|
118253
118856
|
};
|
|
118254
118857
|
function normalizeExtensionModule(mod) {
|
|
@@ -133577,7 +134180,7 @@ var ProviderManager = class {
|
|
|
133577
134180
|
const providerConfig = this.config.providers[providerName];
|
|
133578
134181
|
if (providerConfig === void 0) throw new ScreamError(ErrorCodes.CONFIG_INVALID, `Provider "${providerName}" for model "${model}" is not configured.`);
|
|
133579
134182
|
if (!Number.isInteger(alias.maxContextSize) || alias.maxContextSize <= 0) throw new ScreamError(ErrorCodes.CONFIG_INVALID, `Model "${model}" must define a positive max_context_size in config.toml.`);
|
|
133580
|
-
const provider = toLtodProviderConfig(providerConfig, alias.model, this.options.screamRequestHeaders, alias.maxOutputSize, alias.reasoningKey, this.options.promptCacheKey, alias.adaptiveThinking, alias.forceThinking);
|
|
134183
|
+
const provider = toLtodProviderConfig(providerConfig, alias.model, this.options.screamRequestHeaders, alias.maxOutputSize, alias.reasoningKey, this.options.promptCacheKey, alias.adaptiveThinking, alias.forceThinking, alias.cacheRetention);
|
|
133581
134184
|
return {
|
|
133582
134185
|
providerName,
|
|
133583
134186
|
provider,
|
|
@@ -133666,7 +134269,7 @@ function resolvedHeaderFields(provider, sessionId, screamRequestHeaders) {
|
|
|
133666
134269
|
};
|
|
133667
134270
|
return Object.keys(headers).length > 0 ? headers : void 0;
|
|
133668
134271
|
}
|
|
133669
|
-
function toLtodProviderConfig(provider, model, screamRequestHeaders, maxOutputSize, reasoningKey, promptCacheKey, adaptiveThinking, forceThinking) {
|
|
134272
|
+
function toLtodProviderConfig(provider, model, screamRequestHeaders, maxOutputSize, reasoningKey, promptCacheKey, adaptiveThinking, forceThinking, cacheRetention) {
|
|
133670
134273
|
switch (provider.type) {
|
|
133671
134274
|
case "anthropic": return {
|
|
133672
134275
|
type: "anthropic",
|
|
@@ -133675,6 +134278,7 @@ function toLtodProviderConfig(provider, model, screamRequestHeaders, maxOutputSi
|
|
|
133675
134278
|
apiKey: providerApiKey(provider),
|
|
133676
134279
|
...maxOutputSize !== void 0 ? { defaultMaxTokens: maxOutputSize } : {},
|
|
133677
134280
|
...adaptiveThinking !== void 0 ? { adaptiveThinking } : {},
|
|
134281
|
+
...cacheRetention !== void 0 ? { cacheRetention } : {},
|
|
133678
134282
|
...defaultHeadersField(resolvedHeaderFields(provider, promptCacheKey, screamRequestHeaders))
|
|
133679
134283
|
};
|
|
133680
134284
|
case "openai": return {
|
|
@@ -134741,6 +135345,7 @@ var ScreamCore = class {
|
|
|
134741
135345
|
if (session) try {
|
|
134742
135346
|
await session.close();
|
|
134743
135347
|
} finally {
|
|
135348
|
+
await this.extensionRuntime.deactivateSession(sessionId).catch(() => void 0);
|
|
134744
135349
|
this.sessions.delete(sessionId);
|
|
134745
135350
|
}
|
|
134746
135351
|
}
|
|
@@ -134749,6 +135354,7 @@ var ScreamCore = class {
|
|
|
134749
135354
|
if (active) try {
|
|
134750
135355
|
await active.close();
|
|
134751
135356
|
} finally {
|
|
135357
|
+
await this.extensionRuntime.deactivateSession(sessionId).catch(() => void 0);
|
|
134752
135358
|
this.sessions.delete(sessionId);
|
|
134753
135359
|
}
|
|
134754
135360
|
await this.sessionStore.delete(sessionId);
|
|
@@ -134927,6 +135533,7 @@ var ScreamCore = class {
|
|
|
134927
135533
|
if (agent === void 0) throw new ScreamError(ErrorCodes.AGENT_NOT_FOUND, `Session "${sessionId}" has no main agent`, { details: { sessionId } });
|
|
134928
135534
|
const plugin = this.plugins.list().find((record) => record.id === pluginId);
|
|
134929
135535
|
if (plugin === void 0) throw new ScreamError(ErrorCodes.PLUGIN_NOT_FOUND, `Plugin "${pluginId}" was not found`, { details: { pluginId } });
|
|
135536
|
+
if (!plugin.enabled) throw new ScreamError(ErrorCodes.PLUGIN_NOT_FOUND, `Plugin "${pluginId}" is disabled; enable it before activating`, { details: { pluginId } });
|
|
134930
135537
|
const [extension] = this.extensionRuntime.discover([plugin]);
|
|
134931
135538
|
if (extension === void 0) throw new ScreamError(ErrorCodes.PLUGIN_NOT_FOUND, `Plugin "${pluginId}" has no code entry point`, { details: { pluginId } });
|
|
134932
135539
|
try {
|
|
@@ -134954,20 +135561,23 @@ var ScreamCore = class {
|
|
|
134954
135561
|
}
|
|
134955
135562
|
}
|
|
134956
135563
|
/** Deactivate a code plugin (removes its hooks and runs its deactivate). */
|
|
134957
|
-
async deactivatePlugin({ pluginId }) {
|
|
135564
|
+
async deactivatePlugin({ pluginId, sessionId }) {
|
|
134958
135565
|
await this.pluginsReady;
|
|
134959
|
-
await this.extensionRuntime.deactivate(pluginId);
|
|
134960
|
-
for (const session of this.sessions
|
|
134961
|
-
|
|
134962
|
-
|
|
135566
|
+
await this.extensionRuntime.deactivate(pluginId, sessionId);
|
|
135567
|
+
for (const [id, session] of this.sessions) {
|
|
135568
|
+
if (sessionId !== void 0 && id !== sessionId) continue;
|
|
135569
|
+
for (const agent of session.agents.values()) try {
|
|
135570
|
+
agent.tools.unregisterToolsByOwner(pluginId);
|
|
135571
|
+
} catch {}
|
|
135572
|
+
}
|
|
134963
135573
|
}
|
|
134964
135574
|
/** Code plugins the runtime can load, with their activation state. */
|
|
134965
|
-
async pluginExtensionStatus() {
|
|
135575
|
+
async pluginExtensionStatus({ sessionId } = {}) {
|
|
134966
135576
|
await this.pluginsReady;
|
|
134967
135577
|
return this.extensionRuntime.discover(this.plugins.list()).map((extension) => ({
|
|
134968
135578
|
pluginId: extension.pluginId,
|
|
134969
135579
|
entryPoint: extension.entryPoint,
|
|
134970
|
-
active: this.extensionRuntime.isActive(extension.pluginId)
|
|
135580
|
+
active: this.extensionRuntime.isActive(extension.pluginId, sessionId)
|
|
134971
135581
|
}));
|
|
134972
135582
|
}
|
|
134973
135583
|
unregisterTool({ sessionId, ...payload }) {
|
|
@@ -136187,7 +136797,10 @@ var SDKRpcClient = class {
|
|
|
136187
136797
|
});
|
|
136188
136798
|
}
|
|
136189
136799
|
async deactivatePlugin(input) {
|
|
136190
|
-
return (await this.getRpc()).deactivatePlugin({
|
|
136800
|
+
return (await this.getRpc()).deactivatePlugin({
|
|
136801
|
+
pluginId: input.pluginId,
|
|
136802
|
+
...input.sessionId === void 0 ? {} : { sessionId: input.sessionId }
|
|
136803
|
+
});
|
|
136191
136804
|
}
|
|
136192
136805
|
async pluginExtensionStatus(input) {
|
|
136193
136806
|
return (await this.getRpc()).pluginExtensionStatus({ sessionId: input.sessionId });
|
|
@@ -137140,25 +137753,58 @@ function catalogCachePath(screamHome) {
|
|
|
137140
137753
|
* the next time the network is unreachable. Best-effort — write failures
|
|
137141
137754
|
* are silently ignored so they never block the happy path.
|
|
137142
137755
|
*/
|
|
137143
|
-
function saveCatalogCache(catalog, screamHome) {
|
|
137756
|
+
function saveCatalogCache(catalog, screamHome, meta = {}) {
|
|
137144
137757
|
try {
|
|
137145
137758
|
const path = catalogCachePath(screamHome);
|
|
137146
137759
|
mkdirSync(dirname$1(path), { recursive: true });
|
|
137147
|
-
|
|
137760
|
+
const payload = meta.etag === void 0 && meta.fetchedAt === void 0 ? catalog : {
|
|
137761
|
+
catalog,
|
|
137762
|
+
...meta
|
|
137763
|
+
};
|
|
137764
|
+
writeFileSync(path, JSON.stringify(payload), "utf-8");
|
|
137148
137765
|
} catch {}
|
|
137149
137766
|
}
|
|
137150
137767
|
/**
|
|
137151
|
-
*
|
|
137152
|
-
*
|
|
137768
|
+
* Update only the freshness metadata of an existing snapshot (used after a
|
|
137769
|
+
* `304 Not Modified`, where there is no new catalog to store).
|
|
137153
137770
|
*/
|
|
137154
|
-
function
|
|
137771
|
+
function saveCatalogCacheMeta(screamHome, meta) {
|
|
137772
|
+
try {
|
|
137773
|
+
const path = catalogCachePath(screamHome);
|
|
137774
|
+
const current = loadCatalogCacheFile(screamHome);
|
|
137775
|
+
if (current === void 0) return;
|
|
137776
|
+
writeFileSync(path, JSON.stringify({
|
|
137777
|
+
...current,
|
|
137778
|
+
...meta
|
|
137779
|
+
}), "utf-8");
|
|
137780
|
+
} catch {}
|
|
137781
|
+
}
|
|
137782
|
+
/** Reads the cache file in either shape: a bare catalog (legacy) or `{catalog, etag, fetchedAt}`. */
|
|
137783
|
+
function loadCatalogCacheFile(screamHome) {
|
|
137155
137784
|
try {
|
|
137156
|
-
const raw = readFileSync(catalogCachePath(screamHome), "utf-8");
|
|
137157
|
-
|
|
137785
|
+
const raw = JSON.parse(readFileSync(catalogCachePath(screamHome), "utf-8"));
|
|
137786
|
+
if (raw !== null && typeof raw === "object" && "catalog" in raw) return raw;
|
|
137787
|
+
return { catalog: raw };
|
|
137158
137788
|
} catch {
|
|
137159
137789
|
return;
|
|
137160
137790
|
}
|
|
137161
137791
|
}
|
|
137792
|
+
/** Freshness metadata of the cached snapshot, when it has any. */
|
|
137793
|
+
function loadCatalogCacheMeta(screamHome) {
|
|
137794
|
+
const file = loadCatalogCacheFile(screamHome);
|
|
137795
|
+
if (file === void 0) return {};
|
|
137796
|
+
return {
|
|
137797
|
+
...file.fetchedAt === void 0 ? {} : { fetchedAt: file.fetchedAt },
|
|
137798
|
+
...file.etag === void 0 ? {} : { etag: file.etag }
|
|
137799
|
+
};
|
|
137800
|
+
}
|
|
137801
|
+
/**
|
|
137802
|
+
* Load the most recently cached catalog snapshot. Returns `undefined` when
|
|
137803
|
+
* no cache file exists or the file is corrupt.
|
|
137804
|
+
*/
|
|
137805
|
+
function loadCatalogCache(screamHome) {
|
|
137806
|
+
return loadCatalogCacheFile(screamHome)?.catalog;
|
|
137807
|
+
}
|
|
137162
137808
|
const DEFAULT_CATALOG_URL = "https://models.dev/api.json";
|
|
137163
137809
|
var CatalogFetchError = class extends Error {
|
|
137164
137810
|
status;
|
|
@@ -137178,6 +137824,28 @@ async function fetchCatalog(url, signal, fetchImpl = fetch) {
|
|
|
137178
137824
|
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) throw new Error(`Unexpected catalog response from ${url}.`);
|
|
137179
137825
|
return payload;
|
|
137180
137826
|
}
|
|
137827
|
+
/**
|
|
137828
|
+
* Conditional catalog fetch: sends `If-None-Match` when an ETag is known and
|
|
137829
|
+
* reports `304` as `notModified` instead of throwing.
|
|
137830
|
+
*/
|
|
137831
|
+
async function fetchCatalogWithMeta(url, options = {}, fetchImpl = fetch) {
|
|
137832
|
+
const headers = { Accept: "application/json" };
|
|
137833
|
+
if (options.etag !== void 0) headers["If-None-Match"] = options.etag;
|
|
137834
|
+
const res = await fetchImpl(url, {
|
|
137835
|
+
headers,
|
|
137836
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
137837
|
+
});
|
|
137838
|
+
if (res.status === 304) return { notModified: true };
|
|
137839
|
+
if (!res.ok) throw new CatalogFetchError(`Failed to fetch catalog (HTTP ${res.status}).`, res.status);
|
|
137840
|
+
const payload = await res.json();
|
|
137841
|
+
if (typeof payload !== "object" || payload === null || Array.isArray(payload)) throw new Error(`Unexpected catalog response from ${url}.`);
|
|
137842
|
+
const etag = res.headers.get("etag");
|
|
137843
|
+
return {
|
|
137844
|
+
catalog: payload,
|
|
137845
|
+
notModified: false,
|
|
137846
|
+
...etag === null ? {} : { etag }
|
|
137847
|
+
};
|
|
137848
|
+
}
|
|
137181
137849
|
function capabilityToStrings(capability) {
|
|
137182
137850
|
const caps = [];
|
|
137183
137851
|
if (capability.image_in) caps.push("image_in");
|
|
@@ -143487,7 +144155,7 @@ function sumTokenRows(rows) {
|
|
|
143487
144155
|
output
|
|
143488
144156
|
};
|
|
143489
144157
|
}
|
|
143490
|
-
function buildSessionUsageSection(usage, error, table, value, muted, errorStyle, subagentUsage) {
|
|
144158
|
+
function buildSessionUsageSection(usage, error, table, value, muted, errorStyle, subagentUsage, priceFor) {
|
|
143491
144159
|
if (error !== void 0) return [errorStyle(` ${error}`)];
|
|
143492
144160
|
const byModel = usage?.byModel;
|
|
143493
144161
|
const entries = Object.entries(byModel ?? {});
|
|
@@ -143496,6 +144164,12 @@ function buildSessionUsageSection(usage, error, table, value, muted, errorStyle,
|
|
|
143496
144164
|
const sessionTotal = sumTokenRows(entries.map(([, row]) => row));
|
|
143497
144165
|
const subagentRows = Object.values(subagentUsage ?? {});
|
|
143498
144166
|
const subagentTotal = sumTokenRows(subagentRows);
|
|
144167
|
+
const priceOf = (model) => priceFor?.(model);
|
|
144168
|
+
const modelCosts = entries.map(([model, row]) => estimateCost(row, priceOf(model)));
|
|
144169
|
+
const sessionCost = modelCosts.reduce((acc, cost) => {
|
|
144170
|
+
if (cost === void 0) return acc;
|
|
144171
|
+
return acc === void 0 ? cost : acc + cost;
|
|
144172
|
+
}, void 0);
|
|
143499
144173
|
const lines = [];
|
|
143500
144174
|
lines.push(padName(t("usage.session_total")) + num(sessionTotal.input) + num(sessionTotal.output) + num(sessionTotal.input + sessionTotal.output));
|
|
143501
144175
|
let cacheReadTotal = 0;
|
|
@@ -143505,6 +144179,7 @@ function buildSessionUsageSection(usage, error, table, value, muted, errorStyle,
|
|
|
143505
144179
|
cacheCreationTotal += usageNumber(row.inputCacheCreation);
|
|
143506
144180
|
}
|
|
143507
144181
|
if (cacheReadTotal > 0 || cacheCreationTotal > 0) lines.push(padName(` ↳ ${t("usage.cache_rw")}`) + num(cacheReadTotal) + num(cacheCreationTotal));
|
|
144182
|
+
if (sessionCost !== void 0) lines.push(padName(` ↳ ${t("usage.cost")}`) + value(formatUsd(sessionCost)));
|
|
143508
144183
|
if (subagentRows.length > 0) {
|
|
143509
144184
|
const mainInput = Math.max(0, sessionTotal.input - subagentTotal.input);
|
|
143510
144185
|
const mainOutput = Math.max(0, sessionTotal.output - subagentTotal.output);
|
|
@@ -143512,10 +144187,11 @@ function buildSessionUsageSection(usage, error, table, value, muted, errorStyle,
|
|
|
143512
144187
|
lines.push(padName(` └ ${t("usage.sub_agent")}`) + num(subagentTotal.input) + num(subagentTotal.output) + num(subagentTotal.input + subagentTotal.output));
|
|
143513
144188
|
}
|
|
143514
144189
|
lines.push(usageTableHeader(table, t("usage.model")));
|
|
143515
|
-
for (const [model, row] of entries) {
|
|
144190
|
+
for (const [entryIndex, [model, row]] of entries.entries()) {
|
|
143516
144191
|
const input = usageInputTotal$1(row);
|
|
143517
144192
|
const output = usageNumber(row.output);
|
|
143518
|
-
|
|
144193
|
+
const costSuffix = modelCosts[entryIndex] === void 0 ? "" : ` ${muted(formatUsd(modelCosts[entryIndex]))}`;
|
|
144194
|
+
lines.push(padNameColored(model, muted) + num(input) + num(output) + num(input + output) + costSuffix);
|
|
143519
144195
|
}
|
|
143520
144196
|
return lines;
|
|
143521
144197
|
}
|
|
@@ -143584,7 +144260,7 @@ function buildUsageReportLines(options) {
|
|
|
143584
144260
|
...subagentNames,
|
|
143585
144261
|
t("usage.managed_title")
|
|
143586
144262
|
], options.terminalWidth);
|
|
143587
|
-
const lines = buildSessionUsageSection(options.sessionUsage, options.sessionUsageError, table, value, muted, errorStyle, options.subagentUsage);
|
|
144263
|
+
const lines = buildSessionUsageSection(options.sessionUsage, options.sessionUsageError, table, value, muted, errorStyle, options.subagentUsage, options.priceFor);
|
|
143588
144264
|
if (options.maxContextTokens > 0) {
|
|
143589
144265
|
const ratio = safeUsageRatio(options.contextUsage);
|
|
143590
144266
|
const bar = renderProgressBar(ratio, 20);
|
|
@@ -143750,7 +144426,7 @@ function dismissInfoPanel(state) {
|
|
|
143750
144426
|
activeInfoTimer = void 0;
|
|
143751
144427
|
}
|
|
143752
144428
|
if (activeInfoPanel !== void 0) {
|
|
143753
|
-
state.transcriptContainer.removeChild(activeInfoPanel);
|
|
144429
|
+
state.transcriptContainer.removeChild.bind(state.transcriptContainer)(activeInfoPanel);
|
|
143754
144430
|
activeInfoPanel = void 0;
|
|
143755
144431
|
state.ui.requestRender();
|
|
143756
144432
|
}
|
|
@@ -143761,6 +144437,21 @@ function clearInfoPanelState(state) {
|
|
|
143761
144437
|
async function showUsage(host) {
|
|
143762
144438
|
const sessionUsage = await loadSessionUsageReport(host);
|
|
143763
144439
|
const managedUsage = await loadManagedUsageReport(host);
|
|
144440
|
+
const catalog = loadCatalogCache(resolveScreamHome());
|
|
144441
|
+
const prices = /* @__PURE__ */ new Map();
|
|
144442
|
+
if (catalog !== void 0) {
|
|
144443
|
+
for (const [providerId, provider] of Object.entries(catalog)) for (const [modelId, entry] of Object.entries(provider.models ?? {})) if (entry.cost?.input !== void 0 && entry.cost.output !== void 0) {
|
|
144444
|
+
const price = {
|
|
144445
|
+
input: entry.cost.input,
|
|
144446
|
+
output: entry.cost.output,
|
|
144447
|
+
...entry.cost.cache_read === void 0 ? {} : { cacheRead: entry.cost.cache_read },
|
|
144448
|
+
...entry.cost.cache_write === void 0 ? {} : { cacheWrite: entry.cost.cache_write }
|
|
144449
|
+
};
|
|
144450
|
+
prices.set(modelId, price);
|
|
144451
|
+
prices.set(`${providerId}/${modelId}`, price);
|
|
144452
|
+
}
|
|
144453
|
+
}
|
|
144454
|
+
const priceFor = (modelId) => prices.get(modelId);
|
|
143764
144455
|
const lines = buildUsageReportLines({
|
|
143765
144456
|
colors: host.state.theme.colors,
|
|
143766
144457
|
sessionUsage: sessionUsage.usage,
|
|
@@ -143771,7 +144462,8 @@ async function showUsage(host) {
|
|
|
143771
144462
|
managedUsage: managedUsage?.usage,
|
|
143772
144463
|
managedUsageError: managedUsage?.error,
|
|
143773
144464
|
subagentUsage: host.state.appState.subagentUsage,
|
|
143774
|
-
terminalWidth: host.state.terminal.columns
|
|
144465
|
+
terminalWidth: host.state.terminal.columns,
|
|
144466
|
+
priceFor
|
|
143775
144467
|
});
|
|
143776
144468
|
dismissInfoPanel(host.state);
|
|
143777
144469
|
const panel = new UsagePanelComponent(lines, host.state.theme.colors.primary);
|
|
@@ -145484,7 +146176,7 @@ async function guidedGoalSetup(host) {
|
|
|
145484
146176
|
host.showNotice(t("goal.storm_breaker"), t("goal.conflict_loop"));
|
|
145485
146177
|
return;
|
|
145486
146178
|
}
|
|
145487
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
146179
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-BLUlZjUL.mjs");
|
|
145488
146180
|
const initialDesc = await promptText(host, TextInputDialogComponent, {
|
|
145489
146181
|
title: t("goal.setup_title_initial"),
|
|
145490
146182
|
subtitle: t("goal.setup_desc_hint"),
|
|
@@ -145505,7 +146197,7 @@ async function guidedGoalSetup(host) {
|
|
|
145505
146197
|
await showGoalConfigWizard(host, session, confirmed.trim() || objective, false);
|
|
145506
146198
|
}
|
|
145507
146199
|
async function showGoalConfigWizard(host, session, objective, replace) {
|
|
145508
|
-
const { TextInputDialogComponent } = await import("./text-input-dialog-
|
|
146200
|
+
const { TextInputDialogComponent } = await import("./text-input-dialog-BLUlZjUL.mjs");
|
|
145509
146201
|
const turnInput = await promptNumber(host, TextInputDialogComponent, {
|
|
145510
146202
|
title: t("goal.wizard_title", { objective }),
|
|
145511
146203
|
subtitle: t("goal.budget_turns_hint"),
|
|
@@ -157509,4 +158201,4 @@ async function handleBuiltInSlashCommand(host, name, args) {
|
|
|
157509
158201
|
}
|
|
157510
158202
|
}
|
|
157511
158203
|
//#endregion
|
|
157512
|
-
export { handleExportMdCommand as $, validateFeishuCredentials as $n, handleLogoutCommand as $t, langFromPath as A, hasEmbeddingModelCache as An,
|
|
158204
|
+
export { handleExportMdCommand as $, validateFeishuCredentials as $n, handleLogoutCommand as $t, langFromPath as A, hasEmbeddingModelCache as An, MCP_OAUTH_AUTHORIZATION_URL_TOOL_UPDATE as Ar, createThemeStyles as At, getSharedSpeedTracker as B, isSendThrottled as Bn, OSC11_RESPONSE as Bt, handleLineCommand as C, BUILTIN_SLASH_COMMANDS as Cn, fetchCatalogWithMeta as Cr, showUsage as Ct, renderDiffLines as D, embeddingProgressLabel as Dn, saveCatalogCacheMeta as Dr, isEmptySessionHintDismissed as Dt, ToolCallComponent as E, setExperimentalFlags as En, saveCatalogCache as Er, createMarkdownTheme as Et, SkillActivationComponent as F, startLineDaemonDetached as Fn, resolveGlobalLogPath as Fr, DISABLE_TERMINAL_FOCUS_REPORTING as Ft, AgentGroupComponent as G, parseAesKey as Gn, TERMINAL_FOCUS_OUT as Gt, lerpGradient as H, DEFAULT_CDN_BASE_URL as Hn, OSC11_RESPONSE_PREFIX_NO_ESC as Ht, AssistantMessageComponent as I, stopLineDaemon as In, isScreamError as Ir, DISABLE_TERMINAL_THEME_REPORTING as It, getBreathingFrame as J, TuiConfigParseError as Jn, safeUsageRatio as Jt, WelcomeComponent as K, replaceTabs as Kn, TERMINAL_THEME_DARK as Kt, ActivityGroupComponent as L, UPLOAD_MEDIA_TYPE as Ln, isOrphanedToolCallError as Lr, ENABLE_TERMINAL_FOCUS_REPORTING as Lt, ThinkingComponent as M, PIXEL_PULSE_FRAMES as Mn, resolveScreamHome as Mr, getColorPalette as Mt, NoticeMessageComponent as N, PULSE_WAVE_FRAMES as Nn, flushDiagnosticLogs as Nr, detectTerminalTheme as Nt, renderDiffLinesClustered as O, embeddingFailureDetail as On, ScreamHarness as Or, isTurnElapsedEnabled as Ot, StatusMessageComponent as P, readLineDaemonStatus as Pn, log as Pr, parseOsc11BackgroundTheme as Pt, handleExportDebugZipCommand as Q, feishuFileType as Qn, handleConnectCommand as Qt, charsForTokenBudget as R, WeixinApiError as Rn, SCREAM_ERROR_INFO as Rr, ENABLE_TERMINAL_THEME_REPORTING as Rt, readJsonlFile as S, buildSkillSlashCommands as Sn, DEFAULT_CATALOG_URL as Sr, showStatusReport as St, UserMessageComponent as T, isExperimentalFlagEnabled as Tn, loadCatalogCacheMeta as Tr, createEditorTheme as Tt, lerpHex as U, buildCdnDownloadUrl as Un, QUERY_TERMINAL_THEME as Ut, GRADIENT_CYCLE_MS as V, validateWeixinToken as Vn, OSC11_RESPONSE_PREFIX as Vt, BackgroundAgentStatusComponent as W, decryptAesEcb as Wn, TERMINAL_FOCUS_IN as Wt, CompactionComponent as X, FeishuClient as Xn, handleTraceCommand as Xt, resetBreathingClock as Y, loadTuiConfig as Yn, SubagentSlots as Yt, clearGoalState as Z, FeishuCredentialError as Zn, handleSearchCommand as Zt, handleUpdateCommand as _, TIP_ROTATION_INTERVAL_MS as _n, detectInstallSource as _r, showPermissionPicker as _t, writeTextClipboard as a, appendStreamingArgsPreview as an, getWeixinContextTokensFile as ar, getModelCycleLevel as at, readUpdateCache as b, getLlmNotSetMessage as bn, CLI_USER_AGENT_PRODUCT as br, supportsBalance as bt, handleSkillCommand as c, isTodoItemShape as cn, loadLineConfig as cr, handleCompactCommand as ct, isExpandable as d, stringValue as dn, resolveTurnTimeoutMs as dr, handleModelCommand as dt, isBusy as en, LineConfigError as er, handleForkCommand as et, isPlanExpandable as f, truncateErrorMessage as fn, resolveWeixinOptions as fr, handlePlanCommand as ft, handleMcpCommand as g, SESSION_TIPS as gn, getLogDir as gr, showModelPicker as gt, handleMemoryCommand as h, MAIN_AGENT_ID$1 as hn, getInputHistoryFile as hr, handleYoloCommand as ht, openUrl as i, appendSessionHeaderHint as in, getLinePidFile as ir, changeThinkingLevel as it, CachedContainer as j, startManualEmbeddingDownload as jn, isRealUserPrompt as jr, contrastTextHex as jt, highlightLines as k, getKnowledgeStore as kn, normalizeWorkDir as kr, toggleEmptySessionHint as kt, disposeChildren as l, parseStreamingArgs as ln, resolveCustomCommands as lr, handleEditorCommand as lt, formatMemoryMemoForInjection as m, EXIT_CONFIRM_WINDOW_MS as mn, getDataDir as mr, handleWolfpackCommand as mt, clearEvalPanelState as n, printableChar as nn, assertSinglePlatformConfig as nr, handleTitleCommand as nt, syncDiagramCapabilityPrompt as o, argsRecord as on, getWeixinCursorFile as or, handleAutoCommand as ot, MoonLoader as p, EMPTY_SESSION_HINT_URL as pn, detectShellEnvironment as pr, handleThemeCommand as pt, BREATHE_CYCLE_MS as q, sanitizeShellOutput as qn, TERMINAL_THEME_LIGHT as qt, handleGrantsCommand as r, STATUS_BULLET as rn, getLineConfigPath as rr, toTerminalHyperlink as rt, handleExtensionCommand as s, formatErrorMessage as sn, getWeixinStateDir as sr, handleBotCommand as st, dispatchInput as t, isStreaming as tn, MINUTE_MS as tr, handleInitCommand as tt, hasDispose as u, serializeToolResultOutput as un, resolveFeishuOptions as ur, handleFusionPlanCommand as ut, selectUpdateTarget as v, getCtrlCHint as vn, CLI_COMMAND_NAME as vr, showSettingsSelector as vt, handleRevokeCommand as w, sortSlashCommands as wn, loadCatalogCache as wr, resolveThemeSync as wt, appendJsonlLine as x, getNoActiveSessionMessage as xn, PRODUCT_NAME as xr, clearInfoPanelState as xt, refreshUpdateCache as y, getCtrlDHint as yn, CLI_UI_MODE as yr, refreshProviderBalance as yt, estimateTokens as z, WeixinClient as zn, OSC11_QUERY as zt };
|