@cydm/pie 2.6.11 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -2
- package/dist/builtin/extensions/ask-user/index.js +3 -3
- package/dist/builtin/extensions/plan-mode/index.js +130 -21
- package/dist/builtin/extensions/subagent/index.js +4 -5
- package/dist/builtin/extensions/todo/index.js +3 -3
- package/dist/builtin/skills/computer-use-axi/SKILL.md +103 -0
- package/dist/builtin/skills/computer-use-axi/computer-use-axi-cli.js +37 -0
- package/dist/builtin/{extensions/computer-use/index.js → skills/computer-use-axi/computer-use-axi-runtime.js} +754 -642
- package/dist/builtin/skills/computer-use-axi/package.json +11 -0
- package/dist/chunks/{chunk-ZVM234WE.js → chunk-6RBSTII7.js} +669 -594
- package/dist/chunks/{chunk-MA4CHFN4.js → chunk-IPNAFMOJ.js} +172 -230
- package/dist/chunks/{chunk-7B4IIBVS.js → chunk-R5I2QLF2.js} +1269 -4
- package/dist/chunks/{chunk-PAC62XU4.js → chunk-TWILEFLD.js} +25 -3
- package/dist/chunks/{src-HPIBCE2I.js → src-E7NCXMU5.js} +2 -2
- package/dist/chunks/{test-stream-Y7WXELAJ.js → test-stream-BWBJTFNI.js} +1 -1
- package/dist/cli.js +1979 -384
- package/models.schema.json +52 -0
- package/package.json +3 -3
- package/dist/builtin/extensions/computer-use/package.json +0 -14
- package/dist/builtin/extensions/computer-use/scripts/build-native.mjs +0 -278
- package/dist/builtin/extensions/computer-use/scripts/test-native-retention.mjs +0 -204
- package/dist/chunks/chunk-5353DEEC.js +0 -130
- package/dist/chunks/webapi-MBCKO7ZV.js +0 -2481
- package/dist/code-intel-worker.cjs +0 -211227
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/arm64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/linux/x64/linux-bridge +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/arm64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/Info.plist +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/MacOS/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/universal/pie-computer-use.app/Contents/_CodeSignature/CodeResources +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/macos/x64/pie-computer-use +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/prebuilt/windows/windows-bridge.exe +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/helper-path.mjs +0 -0
- /package/dist/builtin/{extensions/computer-use → skills/computer-use-axi}/scripts/setup-helper.mjs +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
|
|
3
3
|
import {
|
|
4
|
+
VERSION,
|
|
4
5
|
cleanupBashOutputArtifacts,
|
|
5
6
|
createBashTool,
|
|
6
7
|
createCliHostCapabilities,
|
|
7
8
|
createCliWebResearchHealthStore,
|
|
8
9
|
formatSize,
|
|
10
|
+
getAgentDir,
|
|
11
|
+
getBuiltinDir,
|
|
12
|
+
getConfigDir,
|
|
13
|
+
getCustomThemesDir,
|
|
14
|
+
getLogsDir,
|
|
15
|
+
getPackageDir,
|
|
16
|
+
getProjectSettingsPath,
|
|
17
|
+
getRuntimeLogPath,
|
|
18
|
+
getSessionsDir,
|
|
19
|
+
getSettingsPath,
|
|
20
|
+
getThemesDir,
|
|
21
|
+
migrateConfigFromAgentDir,
|
|
9
22
|
truncateHeadTail
|
|
10
|
-
} from "./chunks/chunk-
|
|
23
|
+
} from "./chunks/chunk-IPNAFMOJ.js";
|
|
24
|
+
import {
|
|
25
|
+
resolveCliProjectRoot
|
|
26
|
+
} from "./chunks/chunk-WLFOBECN.js";
|
|
11
27
|
import {
|
|
12
28
|
AGENTS_CONTEXT_FILE_NAME,
|
|
13
29
|
AgentSessionController,
|
|
@@ -30,6 +46,7 @@ import {
|
|
|
30
46
|
createFileObservationState,
|
|
31
47
|
createPolicyEnforcedTools,
|
|
32
48
|
createReadFileUnderstandingHandler,
|
|
49
|
+
createSearchContextTool,
|
|
33
50
|
createSessionManager,
|
|
34
51
|
createSharedFileSystemTools,
|
|
35
52
|
createSharedWebSearchTool,
|
|
@@ -51,6 +68,7 @@ import {
|
|
|
51
68
|
interactionAttentionResolution,
|
|
52
69
|
isCompactSummaryMessage,
|
|
53
70
|
isExtensionEnabled,
|
|
71
|
+
isToolAllowedInPlanMode,
|
|
54
72
|
maybeAdvanceTodoExecutionState,
|
|
55
73
|
modalityForReadFileUnderstandingKind,
|
|
56
74
|
pauseExecutionState,
|
|
@@ -58,13 +76,12 @@ import {
|
|
|
58
76
|
requestInteraction,
|
|
59
77
|
resolveExtensionIdentity,
|
|
60
78
|
restoreExecutionState,
|
|
61
|
-
selectToolsForRuntimePolicy,
|
|
62
79
|
setEnablementInMap,
|
|
63
80
|
setExtensionEnabledInSettings,
|
|
64
81
|
shouldPreserveExecutionStateForUserText,
|
|
65
82
|
supersedeExecutionState
|
|
66
|
-
} from "./chunks/chunk-
|
|
67
|
-
import "./chunks/chunk-
|
|
83
|
+
} from "./chunks/chunk-6RBSTII7.js";
|
|
84
|
+
import "./chunks/chunk-TWILEFLD.js";
|
|
68
85
|
import {
|
|
69
86
|
Deref,
|
|
70
87
|
EMPTY_ASSISTANT_CONTENT_ERROR,
|
|
@@ -87,26 +104,9 @@ import {
|
|
|
87
104
|
requiredCapabilityForToolPurpose,
|
|
88
105
|
setLogger,
|
|
89
106
|
sortToolModelCandidatesByCapability,
|
|
107
|
+
streamSimple,
|
|
90
108
|
type_exports
|
|
91
|
-
} from "./chunks/chunk-
|
|
92
|
-
import {
|
|
93
|
-
VERSION,
|
|
94
|
-
getAgentDir,
|
|
95
|
-
getBuiltinDir,
|
|
96
|
-
getConfigDir,
|
|
97
|
-
getCustomThemesDir,
|
|
98
|
-
getLogsDir,
|
|
99
|
-
getPackageDir,
|
|
100
|
-
getProjectSettingsPath,
|
|
101
|
-
getRuntimeLogPath,
|
|
102
|
-
getSessionsDir,
|
|
103
|
-
getSettingsPath,
|
|
104
|
-
getThemesDir,
|
|
105
|
-
migrateConfigFromAgentDir
|
|
106
|
-
} from "./chunks/chunk-5353DEEC.js";
|
|
107
|
-
import {
|
|
108
|
-
resolveCliProjectRoot
|
|
109
|
-
} from "./chunks/chunk-WLFOBECN.js";
|
|
109
|
+
} from "./chunks/chunk-R5I2QLF2.js";
|
|
110
110
|
import {
|
|
111
111
|
IsArray,
|
|
112
112
|
IsBigInt,
|
|
@@ -51971,6 +51971,7 @@ var MODEL_OVERRIDE_KEYS = [
|
|
|
51971
51971
|
"cost",
|
|
51972
51972
|
"contextWindow",
|
|
51973
51973
|
"maxTokens",
|
|
51974
|
+
"transport",
|
|
51974
51975
|
"headers",
|
|
51975
51976
|
"compat",
|
|
51976
51977
|
"cacheCapability",
|
|
@@ -51988,9 +51989,11 @@ function validateExtensionProviderConfig(provider, config) {
|
|
|
51988
51989
|
throw new Error(`registerProvider("${provider}"): baseUrl must be an absolute URL`);
|
|
51989
51990
|
}
|
|
51990
51991
|
assertHeadersShape(config.headers, `registerProvider("${provider}")`);
|
|
51992
|
+
validateTransport(config.transport, `registerProvider("${provider}")`);
|
|
51991
51993
|
for (const model of config.models ?? []) {
|
|
51992
51994
|
if (!model || typeof model.id !== "string" || !model.id.trim() || /\s/.test(model.id)) throw new Error(`registerProvider("${provider}"): invalid model id`);
|
|
51993
51995
|
assertHeadersShape(model.headers, `registerProvider("${provider}") model "${model.id}"`);
|
|
51996
|
+
validateTransport(model.transport, `Model "${model.id}"`);
|
|
51994
51997
|
validateCompat(model.compat, `registerProvider("${provider}") model "${model.id}" compat`);
|
|
51995
51998
|
validateCacheCapability(model.cacheCapability, `registerProvider("${provider}") model "${model.id}" cacheCapability`);
|
|
51996
51999
|
validateWebSearchCapability(model.webSearch, `registerProvider("${provider}") model "${model.id}" webSearch`);
|
|
@@ -51998,7 +52001,7 @@ function validateExtensionProviderConfig(provider, config) {
|
|
|
51998
52001
|
}
|
|
51999
52002
|
}
|
|
52000
52003
|
var REMOTE_CATALOG_CACHE_VERSION = 4;
|
|
52001
|
-
var SUPPORTED_REMOTE_APIS = /* @__PURE__ */ new Set(["openai-completions", "anthropic-messages"]);
|
|
52004
|
+
var SUPPORTED_REMOTE_APIS = /* @__PURE__ */ new Set(["openai-completions", "anthropic-messages", "openai-responses"]);
|
|
52002
52005
|
var MAX_REMOTE_CATALOG_BYTES = 2 * 1024 * 1024;
|
|
52003
52006
|
var OAUTH_RESTORE_LEEWAY_MS = 6e4;
|
|
52004
52007
|
var OAUTH_REFRESH_TIMEOUT_MS = 3e4;
|
|
@@ -52495,11 +52498,17 @@ function validateFileCapabilities(value, label) {
|
|
|
52495
52498
|
}
|
|
52496
52499
|
}
|
|
52497
52500
|
}
|
|
52501
|
+
function validateTransport(value, label) {
|
|
52502
|
+
if (value !== void 0 && value !== "sse" && value !== "websocket" && value !== "auto") throw new Error(`${label}.transport is invalid`);
|
|
52503
|
+
}
|
|
52498
52504
|
function validateCompat(value, label) {
|
|
52499
52505
|
if (value === void 0) return;
|
|
52500
52506
|
if (!isPlainRecord(value)) throw new Error(`${label} is invalid`);
|
|
52501
52507
|
assertOnlyKeys(value, [
|
|
52502
52508
|
"forcedReasoningEffort",
|
|
52509
|
+
"store",
|
|
52510
|
+
"supportsEncryptedReasoning",
|
|
52511
|
+
"responsesContinuation",
|
|
52503
52512
|
"supportsStore",
|
|
52504
52513
|
"supportsDeveloperRole",
|
|
52505
52514
|
"supportsReasoningEffort",
|
|
@@ -52517,6 +52526,9 @@ function validateCompat(value, label) {
|
|
|
52517
52526
|
throw new Error(`${label}.forcedReasoningEffort must be "none"`);
|
|
52518
52527
|
}
|
|
52519
52528
|
for (const field of [
|
|
52529
|
+
"store",
|
|
52530
|
+
"supportsEncryptedReasoning",
|
|
52531
|
+
"responsesContinuation",
|
|
52520
52532
|
"supportsStore",
|
|
52521
52533
|
"supportsDeveloperRole",
|
|
52522
52534
|
"supportsReasoningEffort",
|
|
@@ -52537,12 +52549,14 @@ function validateRemoteModel(profileId, model) {
|
|
|
52537
52549
|
if (!isPlainRecord(model) || typeof model.id !== "string" || !model.id.trim() || model.id !== model.id.trim() || /\s/.test(model.id)) throw new Error(`Remote profile "${profileId}" contains an invalid model id`);
|
|
52538
52550
|
assertOnlyKeys(model, [
|
|
52539
52551
|
"id",
|
|
52552
|
+
"api",
|
|
52540
52553
|
"name",
|
|
52541
52554
|
"reasoning",
|
|
52542
52555
|
"input",
|
|
52543
52556
|
"cost",
|
|
52544
52557
|
"contextWindow",
|
|
52545
52558
|
"maxTokens",
|
|
52559
|
+
"transport",
|
|
52546
52560
|
"compat",
|
|
52547
52561
|
"cacheCapability",
|
|
52548
52562
|
"webSearch",
|
|
@@ -52556,6 +52570,7 @@ function validateRemoteModel(profileId, model) {
|
|
|
52556
52570
|
for (const field of ["name", "displayName", "filePlatform", "attachmentPlatform", "apiKeyEnv"]) {
|
|
52557
52571
|
assertOptionalString(model[field], `Remote profile "${profileId}" model "${model.id}" ${field}`);
|
|
52558
52572
|
}
|
|
52573
|
+
if (model.api !== void 0 && !SUPPORTED_REMOTE_APIS.has(model.api)) throw new Error(`Model "${model.id}" has unsupported api ${model.api}`);
|
|
52559
52574
|
assertOptionalBoolean(model.reasoning, `Remote profile "${profileId}" model "${model.id}" reasoning`);
|
|
52560
52575
|
if (!Array.isArray(model.input) || model.input.length === 0 || model.input.some((item) => !["text", "image", "audio", "video"].includes(item))) {
|
|
52561
52576
|
throw new Error(`Remote profile "${profileId}" model "${model.id}" has invalid input capabilities`);
|
|
@@ -52569,6 +52584,7 @@ function validateRemoteModel(profileId, model) {
|
|
|
52569
52584
|
throw new Error(`Remote profile "${profileId}" model "${model.id}" has invalid token limits`);
|
|
52570
52585
|
}
|
|
52571
52586
|
if (new Set(model.input).size !== model.input.length) throw new Error(`Remote profile "${profileId}" model "${model.id}" has duplicate input capabilities`);
|
|
52587
|
+
validateTransport(model.transport, `Model "${model.id}"`);
|
|
52572
52588
|
validateCompat(model.compat, `Remote profile "${profileId}" model "${model.id}" compat`);
|
|
52573
52589
|
validateCacheCapability(model.cacheCapability, `Remote profile "${profileId}" model "${model.id}" cacheCapability`);
|
|
52574
52590
|
validateWebSearchCapability(model.webSearch, `Remote profile "${profileId}" model "${model.id}" webSearch`);
|
|
@@ -52604,6 +52620,7 @@ function sanitizeRemotePayload(decoded, remote, catalogUrl, allowLocallyInjected
|
|
|
52604
52620
|
if (!provider || provider !== provider.trim() || /\s/.test(provider) || !isPlainRecord(source)) throw new Error("catalog contains an invalid profile");
|
|
52605
52621
|
assertOnlyKeys(source, [
|
|
52606
52622
|
"baseUrl",
|
|
52623
|
+
"endpoints",
|
|
52607
52624
|
"api",
|
|
52608
52625
|
"apiKey",
|
|
52609
52626
|
"apiKeyEnv",
|
|
@@ -52611,6 +52628,7 @@ function sanitizeRemotePayload(decoded, remote, catalogUrl, allowLocallyInjected
|
|
|
52611
52628
|
"displayName",
|
|
52612
52629
|
"filePlatform",
|
|
52613
52630
|
"attachmentPlatform",
|
|
52631
|
+
"transport",
|
|
52614
52632
|
"compat",
|
|
52615
52633
|
"cacheCapability",
|
|
52616
52634
|
"webSearch",
|
|
@@ -52626,8 +52644,13 @@ function sanitizeRemotePayload(decoded, remote, catalogUrl, allowLocallyInjected
|
|
|
52626
52644
|
assertOptionalString(source[field], `Remote profile "${provider}" ${field}`);
|
|
52627
52645
|
}
|
|
52628
52646
|
validateRemoteEndpoint(source.baseUrl, catalogUrl, `Remote profile "${provider}"`);
|
|
52647
|
+
validateProfileEndpoints(source, `Remote profile "${provider}"`);
|
|
52648
|
+
for (const [api, endpoint] of Object.entries(source.endpoints ?? {})) {
|
|
52649
|
+
validateRemoteEndpoint(endpoint, catalogUrl, `Remote profile "${provider}" endpoints.${api}`);
|
|
52650
|
+
}
|
|
52629
52651
|
if (!Array.isArray(source.models) || source.models.length === 0) throw new Error(`Remote profile "${provider}" has no models`);
|
|
52630
52652
|
assertRemoteHeadersSafe(source.headers, `Remote profile "${provider}"`);
|
|
52653
|
+
validateTransport(source.transport, `Remote profile "${provider}"`);
|
|
52631
52654
|
validateCompat(source.compat, `Remote profile "${provider}" compat`);
|
|
52632
52655
|
validateCacheCapability(source.cacheCapability, `Remote profile "${provider}" cacheCapability`);
|
|
52633
52656
|
validateWebSearchCapability(source.webSearch, `Remote profile "${provider}" webSearch`);
|
|
@@ -52644,7 +52667,9 @@ function sanitizeRemotePayload(decoded, remote, catalogUrl, allowLocallyInjected
|
|
|
52644
52667
|
}
|
|
52645
52668
|
const sanitized = {
|
|
52646
52669
|
baseUrl: source.baseUrl,
|
|
52670
|
+
...source.endpoints === void 0 ? {} : { endpoints: { ...source.endpoints } },
|
|
52647
52671
|
api: source.api,
|
|
52672
|
+
transport: source.transport,
|
|
52648
52673
|
apiKeyEnv: remote.apiKeyEnv,
|
|
52649
52674
|
...source.headers === void 0 ? {} : { headers: { ...source.headers } },
|
|
52650
52675
|
...source.displayName === void 0 ? {} : { displayName: source.displayName },
|
|
@@ -52656,6 +52681,7 @@ function sanitizeRemotePayload(decoded, remote, catalogUrl, allowLocallyInjected
|
|
|
52656
52681
|
...source.fileCapabilities === void 0 ? {} : { fileCapabilities: { ...source.fileCapabilities } },
|
|
52657
52682
|
models: source.models.map((model) => ({
|
|
52658
52683
|
id: model.id,
|
|
52684
|
+
...model.api === void 0 ? {} : { api: model.api },
|
|
52659
52685
|
...model.name === void 0 ? {} : { name: model.name },
|
|
52660
52686
|
...model.reasoning === void 0 ? {} : { reasoning: model.reasoning },
|
|
52661
52687
|
input: [...model.input],
|
|
@@ -52667,6 +52693,7 @@ function sanitizeRemotePayload(decoded, remote, catalogUrl, allowLocallyInjected
|
|
|
52667
52693
|
},
|
|
52668
52694
|
contextWindow: model.contextWindow,
|
|
52669
52695
|
maxTokens: model.maxTokens,
|
|
52696
|
+
...model.transport === void 0 ? {} : { transport: model.transport },
|
|
52670
52697
|
...model.compat === void 0 ? {} : { compat: { ...model.compat } },
|
|
52671
52698
|
...model.cacheCapability === void 0 ? {} : { cacheCapability: { ...model.cacheCapability } },
|
|
52672
52699
|
...model.webSearch === void 0 ? {} : { webSearch: { ...model.webSearch } },
|
|
@@ -52739,16 +52766,41 @@ function validateModelOverrides(value) {
|
|
|
52739
52766
|
if (typeof headerValue !== "string") throw new Error(`models.json modelOverrides["${key}"].headers.${headerName} must be a string`);
|
|
52740
52767
|
}
|
|
52741
52768
|
}
|
|
52769
|
+
validateTransport(override.transport, `Model override "${key}"`);
|
|
52742
52770
|
validateCompat(override.compat, `models.json modelOverrides["${key}"].compat`);
|
|
52743
52771
|
validateCacheCapability(override.cacheCapability, `models.json modelOverrides["${key}"].cacheCapability`);
|
|
52744
52772
|
validateWebSearchCapability(override.webSearch, `models.json modelOverrides["${key}"].webSearch`);
|
|
52745
52773
|
validateFileCapabilities(override.fileCapabilities, `models.json modelOverrides["${key}"].fileCapabilities`);
|
|
52746
52774
|
}
|
|
52747
52775
|
}
|
|
52776
|
+
function validateProfileEndpoints(profile, label) {
|
|
52777
|
+
if (profile.endpoints === void 0) return;
|
|
52778
|
+
if (!isPlainRecord(profile.endpoints)) throw new Error(`${label} endpoints must be an object`);
|
|
52779
|
+
for (const [api, value] of Object.entries(profile.endpoints)) {
|
|
52780
|
+
if (!SUPPORTED_REMOTE_APIS.has(api)) throw new Error(`${label} endpoints has unsupported api ${api}`);
|
|
52781
|
+
try {
|
|
52782
|
+
if (typeof value !== "string") throw new Error("invalid URL");
|
|
52783
|
+
const endpoint = new URL(value);
|
|
52784
|
+
if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:") throw new Error("unsupported protocol");
|
|
52785
|
+
} catch {
|
|
52786
|
+
throw new Error(`${label} endpoints.${api} must be an absolute HTTP(S) URL`);
|
|
52787
|
+
}
|
|
52788
|
+
}
|
|
52789
|
+
}
|
|
52790
|
+
function resolveProfileRoute(profile, model) {
|
|
52791
|
+
const api = model.api ?? profile.api;
|
|
52792
|
+
if (!SUPPORTED_REMOTE_APIS.has(api)) throw new Error(`Model "${model.id}" has unsupported api ${api}`);
|
|
52793
|
+
const endpoint = profile.endpoints?.[api];
|
|
52794
|
+
if (model.api !== void 0 && endpoint === void 0 && api !== profile.api) {
|
|
52795
|
+
throw new Error(`Model "${model.id}" api ${api} requires profile endpoints.${api} (otherwise api must equal profile api)`);
|
|
52796
|
+
}
|
|
52797
|
+
return { api, baseUrl: endpoint ?? profile.baseUrl };
|
|
52798
|
+
}
|
|
52748
52799
|
function validateProfileConfig(profileId, profileConfig) {
|
|
52749
52800
|
if (!isPlainRecord(profileConfig)) throw new Error(`Profile "${profileId}" must be an object.`);
|
|
52750
52801
|
assertOnlyKeys(profileConfig, [
|
|
52751
52802
|
"baseUrl",
|
|
52803
|
+
"endpoints",
|
|
52752
52804
|
"api",
|
|
52753
52805
|
"apiKey",
|
|
52754
52806
|
"apiKeyEnv",
|
|
@@ -52756,6 +52808,7 @@ function validateProfileConfig(profileId, profileConfig) {
|
|
|
52756
52808
|
"displayName",
|
|
52757
52809
|
"filePlatform",
|
|
52758
52810
|
"attachmentPlatform",
|
|
52811
|
+
"transport",
|
|
52759
52812
|
"compat",
|
|
52760
52813
|
"cacheCapability",
|
|
52761
52814
|
"webSearch",
|
|
@@ -52787,7 +52840,9 @@ function validateProfileConfig(profileId, profileConfig) {
|
|
|
52787
52840
|
} catch {
|
|
52788
52841
|
throw new Error(`Profile "${profileId}" baseUrl must be an absolute HTTP(S) URL`);
|
|
52789
52842
|
}
|
|
52843
|
+
validateProfileEndpoints(profileConfig, `Profile "${profileId}"`);
|
|
52790
52844
|
assertHeadersShape(profileConfig.headers, `Profile "${profileId}"`);
|
|
52845
|
+
validateTransport(profileConfig.transport, `Profile "${profileId}"`);
|
|
52791
52846
|
validateCompat(profileConfig.compat, `Profile "${profileId}" compat`);
|
|
52792
52847
|
validateCacheCapability(profileConfig.cacheCapability, `Profile "${profileId}" cacheCapability`);
|
|
52793
52848
|
validateWebSearchCapability(profileConfig.webSearch, `Profile "${profileId}" webSearch`);
|
|
@@ -52797,12 +52852,14 @@ function validateProfileConfig(profileId, profileConfig) {
|
|
|
52797
52852
|
if (!isPlainRecord(modelConfig)) throw new Error(`Profile "${profileId}" model #${index} must be an object.`);
|
|
52798
52853
|
assertOnlyKeys(modelConfig, [
|
|
52799
52854
|
"id",
|
|
52855
|
+
"api",
|
|
52800
52856
|
"name",
|
|
52801
52857
|
"reasoning",
|
|
52802
52858
|
"input",
|
|
52803
52859
|
"cost",
|
|
52804
52860
|
"contextWindow",
|
|
52805
52861
|
"maxTokens",
|
|
52862
|
+
"transport",
|
|
52806
52863
|
"compat",
|
|
52807
52864
|
"cacheCapability",
|
|
52808
52865
|
"webSearch",
|
|
@@ -52826,6 +52883,7 @@ function validateProfileConfig(profileId, profileConfig) {
|
|
|
52826
52883
|
);
|
|
52827
52884
|
}
|
|
52828
52885
|
validateRemoteModel(profileId, modelConfig);
|
|
52886
|
+
resolveProfileRoute(profileConfig, modelConfig);
|
|
52829
52887
|
assertHeadersShape(modelConfig.headers, `Profile "${profileId}" model "${modelConfig.id}"`);
|
|
52830
52888
|
assertOptionalEnvName(modelConfig.apiKeyEnv, `Profile "${profileId}" model "${modelConfig.id}" apiKeyEnv`);
|
|
52831
52889
|
if (seenModelIds.has(modelConfig.id)) throw new Error(`Profile "${profileId}" contains duplicate model "${modelConfig.id}".`);
|
|
@@ -52916,12 +52974,13 @@ var ModelRegistry = class {
|
|
|
52916
52974
|
);
|
|
52917
52975
|
}
|
|
52918
52976
|
const existing = this.models.get(provider);
|
|
52919
|
-
if (existing && (providerConfig.baseUrl || providerConfig.api || providerConfig.headers)) {
|
|
52977
|
+
if (existing && (providerConfig.baseUrl || providerConfig.api || providerConfig.headers || providerConfig.transport)) {
|
|
52920
52978
|
for (const model of existing.values()) {
|
|
52921
52979
|
this.upsert({
|
|
52922
52980
|
...model,
|
|
52923
52981
|
baseUrl: providerConfig.baseUrl || model.baseUrl,
|
|
52924
52982
|
api: providerConfig.api || model.api,
|
|
52983
|
+
transport: providerConfig.transport ?? model.transport,
|
|
52925
52984
|
apiKeyEnv: providerConfig.apiKeyEnv || model.apiKeyEnv,
|
|
52926
52985
|
displayName: providerConfig.displayName || model.displayName || provider,
|
|
52927
52986
|
filePlatform: providerConfig.filePlatform || model.filePlatform,
|
|
@@ -52938,9 +52997,8 @@ var ModelRegistry = class {
|
|
|
52938
52997
|
this.upsert({
|
|
52939
52998
|
id: customModel.id,
|
|
52940
52999
|
name: customModel.name || baseModel?.name || customModel.id,
|
|
52941
|
-
|
|
53000
|
+
...resolveProfileRoute(providerConfig, customModel),
|
|
52942
53001
|
provider,
|
|
52943
|
-
baseUrl: providerConfig.baseUrl || baseModel?.baseUrl || "",
|
|
52944
53002
|
reasoning: customModel.reasoning ?? baseModel?.reasoning ?? false,
|
|
52945
53003
|
input: customModel.input || baseModel?.input || ["text"],
|
|
52946
53004
|
cost: customModel.cost || baseModel?.cost || { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
@@ -52951,6 +53009,7 @@ var ModelRegistry = class {
|
|
|
52951
53009
|
filePlatform: customModel.filePlatform || providerConfig.filePlatform || baseModel?.filePlatform,
|
|
52952
53010
|
attachmentPlatform: customModel.attachmentPlatform || providerConfig.attachmentPlatform || baseModel?.attachmentPlatform,
|
|
52953
53011
|
headers: providerConfig.headers ? { ...baseModel?.headers, ...providerConfig.headers, ...customModel.headers } : customModel.headers || baseModel?.headers,
|
|
53012
|
+
transport: customModel.transport ?? providerConfig.transport ?? baseModel?.transport,
|
|
52954
53013
|
compat: customModel.compat || providerConfig.compat || baseModel?.compat,
|
|
52955
53014
|
cacheCapability: customModel.cacheCapability || providerConfig.cacheCapability || baseModel?.cacheCapability,
|
|
52956
53015
|
webSearch: customModel.webSearch || providerConfig.webSearch || baseModel?.webSearch,
|
|
@@ -53003,6 +53062,7 @@ var ModelRegistry = class {
|
|
|
53003
53062
|
if (override.maxTokens !== void 0) patched.maxTokens = override.maxTokens;
|
|
53004
53063
|
if (override.cost !== void 0) patched.cost = { ...existing.cost, ...override.cost };
|
|
53005
53064
|
if (override.headers !== void 0) patched.headers = { ...existing.headers, ...override.headers };
|
|
53065
|
+
if (override.transport !== void 0) patched.transport = override.transport;
|
|
53006
53066
|
if (override.compat !== void 0) patched.compat = deepMergePlainRecords(existing.compat, override.compat);
|
|
53007
53067
|
if (override.cacheCapability !== void 0) patched.cacheCapability = { ...existing.cacheCapability, ...override.cacheCapability };
|
|
53008
53068
|
if (override.webSearch !== void 0) patched.webSearch = { ...existing.webSearch, ...override.webSearch };
|
|
@@ -53024,9 +53084,8 @@ var ModelRegistry = class {
|
|
|
53024
53084
|
this.upsert({
|
|
53025
53085
|
id: customModel.id,
|
|
53026
53086
|
name: customModel.name || customModel.id,
|
|
53027
|
-
|
|
53087
|
+
...resolveProfileRoute(providerConfig, customModel),
|
|
53028
53088
|
provider,
|
|
53029
|
-
baseUrl: providerConfig.baseUrl || "",
|
|
53030
53089
|
reasoning: customModel.reasoning ?? false,
|
|
53031
53090
|
input: customModel.input || ["text"],
|
|
53032
53091
|
cost: customModel.cost || { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
@@ -53037,6 +53096,7 @@ var ModelRegistry = class {
|
|
|
53037
53096
|
filePlatform: customModel.filePlatform || providerConfig.filePlatform,
|
|
53038
53097
|
attachmentPlatform: customModel.attachmentPlatform || providerConfig.attachmentPlatform,
|
|
53039
53098
|
headers: { ...providerConfig.headers, ...customModel.headers },
|
|
53099
|
+
transport: customModel.transport ?? providerConfig.transport,
|
|
53040
53100
|
compat: customModel.compat || providerConfig.compat,
|
|
53041
53101
|
cacheCapability: customModel.cacheCapability || providerConfig.cacheCapability,
|
|
53042
53102
|
webSearch: customModel.webSearch || providerConfig.webSearch,
|
|
@@ -53476,12 +53536,13 @@ var ModelRegistry = class {
|
|
|
53476
53536
|
this.authStorage.setProviderEnvVar(provider, config.apiKeyEnv);
|
|
53477
53537
|
}
|
|
53478
53538
|
const existing = this.models.get(provider);
|
|
53479
|
-
if (existing && (config.baseUrl || config.api || config.headers)) {
|
|
53539
|
+
if (existing && (config.baseUrl || config.api || config.headers || config.transport)) {
|
|
53480
53540
|
for (const model of existing.values()) {
|
|
53481
53541
|
this.upsert({
|
|
53482
53542
|
...model,
|
|
53483
53543
|
baseUrl: config.baseUrl || model.baseUrl,
|
|
53484
53544
|
api: config.api || model.api,
|
|
53545
|
+
transport: config.transport ?? model.transport,
|
|
53485
53546
|
headers: config.headers ? { ...model.headers, ...config.headers } : model.headers
|
|
53486
53547
|
});
|
|
53487
53548
|
}
|
|
@@ -53502,6 +53563,7 @@ var ModelRegistry = class {
|
|
|
53502
53563
|
apiKeyEnv: config.apiKeyEnv || baseModel?.apiKeyEnv,
|
|
53503
53564
|
displayName: customModel.displayName || baseModel?.displayName || provider,
|
|
53504
53565
|
headers: config.headers ? { ...baseModel?.headers, ...config.headers, ...customModel.headers } : customModel.headers || baseModel?.headers,
|
|
53566
|
+
transport: customModel.transport ?? config.transport ?? baseModel?.transport,
|
|
53505
53567
|
compat: customModel.compat || baseModel?.compat,
|
|
53506
53568
|
cacheCapability: customModel.cacheCapability || baseModel?.cacheCapability,
|
|
53507
53569
|
webSearch: customModel.webSearch || baseModel?.webSearch,
|
|
@@ -54053,7 +54115,7 @@ function checkComputerUse() {
|
|
|
54053
54115
|
id: "computer_use_helper",
|
|
54054
54116
|
label: "computer-use helper",
|
|
54055
54117
|
status: "warn",
|
|
54056
|
-
message: `computer-use helper app is not installed yet; it installs on first
|
|
54118
|
+
message: `computer-use helper app is not installed yet; it installs on first computer-use-axi use to ${appPath}. Afterwards grant Accessibility and Screen Recording to pie-computer-use.app in System Settings \u2192 Privacy & Security.`,
|
|
54057
54119
|
details: { appPath }
|
|
54058
54120
|
};
|
|
54059
54121
|
}
|
|
@@ -54341,7 +54403,7 @@ var MODE_RULES = {
|
|
|
54341
54403
|
"~/.pie is allowlisted for Pie configuration and session support.",
|
|
54342
54404
|
"Shell commands run from the workspace and return structured output, timeout, and truncation details.",
|
|
54343
54405
|
"web_research is read-only, uses provider-native web/search/fetch capabilities, and does not grant bash/curl web scraping permission.",
|
|
54344
|
-
"computer-use
|
|
54406
|
+
"Desktop control runs through the computer-use-axi skill CLI via bash: observation commands only read the screen, while act synthesizes real desktop input and goes through normal shell permission prompts.",
|
|
54345
54407
|
"Protected paths from extensions can block reads/writes even when tools are present."
|
|
54346
54408
|
],
|
|
54347
54409
|
plan: [
|
|
@@ -54351,7 +54413,7 @@ var MODE_RULES = {
|
|
|
54351
54413
|
yolo: [
|
|
54352
54414
|
"/settings/yolo relaxes filesystem sandbox directory restrictions.",
|
|
54353
54415
|
"It does not make destructive shell commands safe; use it only in trusted workspaces.",
|
|
54354
|
-
"It also
|
|
54416
|
+
"It also auto-approves shell commands, including computer-use-axi desktop input."
|
|
54355
54417
|
],
|
|
54356
54418
|
subagents: [
|
|
54357
54419
|
"Subagents inherit the parent tool set, then runtime policy removes write and high-risk tools.",
|
|
@@ -56502,7 +56564,10 @@ function createExtensionContext(extension, cwd, uiContext, abortFn, isIdleFn, ha
|
|
|
56502
56564
|
},
|
|
56503
56565
|
get yoloMode() {
|
|
56504
56566
|
return actions?.yoloMode ?? false;
|
|
56505
|
-
}
|
|
56567
|
+
},
|
|
56568
|
+
// Only expose setYoloMode when the host can actually toggle it — plan-mode
|
|
56569
|
+
// gates the option on typeof ctx.setYoloMode === "function".
|
|
56570
|
+
...actions?.setYoloMode ? { setYoloMode: (enabled) => actions.setYoloMode(enabled) } : {}
|
|
56506
56571
|
};
|
|
56507
56572
|
return context;
|
|
56508
56573
|
}
|
|
@@ -60395,8 +60460,8 @@ var Editor = class {
|
|
|
60395
60460
|
this.historyIndex = -1;
|
|
60396
60461
|
this.lastAction = null;
|
|
60397
60462
|
this.pushUndoSnapshot();
|
|
60398
|
-
const
|
|
60399
|
-
const tabExpandedText =
|
|
60463
|
+
const cleanText = pastedText.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
60464
|
+
const tabExpandedText = cleanText.replace(/\t/g, " ");
|
|
60400
60465
|
let filteredText = tabExpandedText.split("").filter((char) => char === "\n" || char.charCodeAt(0) >= 32).join("");
|
|
60401
60466
|
if (/^[/~.]/.test(filteredText)) {
|
|
60402
60467
|
const currentLine = this.state.lines[this.state.cursorLine] || "";
|
|
@@ -61480,9 +61545,9 @@ var Input = class {
|
|
|
61480
61545
|
handlePaste(pastedText) {
|
|
61481
61546
|
this.lastAction = null;
|
|
61482
61547
|
this.pushUndo();
|
|
61483
|
-
const
|
|
61484
|
-
this.value = this.value.slice(0, this.cursor) +
|
|
61485
|
-
this.cursor +=
|
|
61548
|
+
const cleanText = pastedText.replace(/\r\n/g, "").replace(/\r/g, "").replace(/\n/g, "");
|
|
61549
|
+
this.value = this.value.slice(0, this.cursor) + cleanText + this.value.slice(this.cursor);
|
|
61550
|
+
this.cursor += cleanText.length;
|
|
61486
61551
|
}
|
|
61487
61552
|
invalidate() {
|
|
61488
61553
|
}
|
|
@@ -64255,7 +64320,10 @@ var ExtensionRunner = class {
|
|
|
64255
64320
|
},
|
|
64256
64321
|
get yoloMode() {
|
|
64257
64322
|
return runner.actions.yoloMode ?? false;
|
|
64258
|
-
}
|
|
64323
|
+
},
|
|
64324
|
+
// Only expose setYoloMode when the host can actually toggle it — plan-mode
|
|
64325
|
+
// gates the option on typeof ctx.setYoloMode === "function".
|
|
64326
|
+
...runner.actions.setYoloMode ? { setYoloMode: (enabled) => runner.actions.setYoloMode(enabled) } : {}
|
|
64259
64327
|
};
|
|
64260
64328
|
return createLoggedProxy(context, `ExtensionContext#${contextId}`);
|
|
64261
64329
|
}
|
|
@@ -70171,6 +70239,100 @@ var SessionTraceWriter = class extends SessionTraceSnapshotWriter {
|
|
|
70171
70239
|
sessionManager;
|
|
70172
70240
|
};
|
|
70173
70241
|
|
|
70242
|
+
// src/runtime/context-signals.ts
|
|
70243
|
+
import { createHash as createHash4 } from "crypto";
|
|
70244
|
+
function applyContextSignalsToFooter(target) {
|
|
70245
|
+
if (!target.agent?.state) return;
|
|
70246
|
+
const signals = computeContextSignals(
|
|
70247
|
+
target,
|
|
70248
|
+
target.agent.state.systemPrompt ?? "",
|
|
70249
|
+
target.agent.state.tools,
|
|
70250
|
+
target.sessionManager.getMessages()
|
|
70251
|
+
);
|
|
70252
|
+
target.footer.setState({
|
|
70253
|
+
prefixHash: signals.prefixHash,
|
|
70254
|
+
prefixHashChanged: signals.prefixHashChanged,
|
|
70255
|
+
cacheHitRate: signals.cacheHitRate
|
|
70256
|
+
});
|
|
70257
|
+
}
|
|
70258
|
+
function computePromptPrefixHash(systemPrompt, tools) {
|
|
70259
|
+
return createHash4("sha256").update(
|
|
70260
|
+
JSON.stringify({
|
|
70261
|
+
systemPrompt,
|
|
70262
|
+
tools: tools.map((tool) => ({
|
|
70263
|
+
name: tool.name,
|
|
70264
|
+
description: tool.description ?? "",
|
|
70265
|
+
parameters: tool.parameters ?? null
|
|
70266
|
+
}))
|
|
70267
|
+
})
|
|
70268
|
+
).digest("hex").slice(0, 8);
|
|
70269
|
+
}
|
|
70270
|
+
function calculateCumulativeCacheHitRate(messages) {
|
|
70271
|
+
let input = 0;
|
|
70272
|
+
let cacheRead = 0;
|
|
70273
|
+
for (const message of messages) {
|
|
70274
|
+
if (message.role !== "assistant") continue;
|
|
70275
|
+
const usage = message.usage;
|
|
70276
|
+
if (!usage) continue;
|
|
70277
|
+
input += usage.input;
|
|
70278
|
+
cacheRead += usage.cacheRead;
|
|
70279
|
+
}
|
|
70280
|
+
const base = input + cacheRead;
|
|
70281
|
+
return base > 0 ? cacheRead / base : null;
|
|
70282
|
+
}
|
|
70283
|
+
var signalMemories = /* @__PURE__ */ new WeakMap();
|
|
70284
|
+
var lastSignals = /* @__PURE__ */ new WeakMap();
|
|
70285
|
+
function getLastContextSignals(hostKey) {
|
|
70286
|
+
return lastSignals.get(hostKey) ?? null;
|
|
70287
|
+
}
|
|
70288
|
+
function computeContextSignals(hostKey, systemPrompt, tools, messages) {
|
|
70289
|
+
const prefixHash = computePromptPrefixHash(systemPrompt, tools);
|
|
70290
|
+
const systemHash = computePromptPrefixHash(systemPrompt, []);
|
|
70291
|
+
const toolsHash = computePromptPrefixHash("", tools);
|
|
70292
|
+
const previous = signalMemories.get(hostKey);
|
|
70293
|
+
const prefixHashChanged = previous !== void 0 && previous.hash !== prefixHash;
|
|
70294
|
+
if (previous?.hash !== prefixHash) {
|
|
70295
|
+
signalMemories.set(hostKey, { hash: prefixHash, systemHash, toolsHash });
|
|
70296
|
+
}
|
|
70297
|
+
const signals = {
|
|
70298
|
+
prefixHash,
|
|
70299
|
+
prefixHashChanged,
|
|
70300
|
+
...prefixHashChanged && previous ? { previousPrefixHash: previous.hash } : {},
|
|
70301
|
+
systemPromptChanged: prefixHashChanged && previous !== void 0 && previous.systemHash !== systemHash,
|
|
70302
|
+
toolsChanged: prefixHashChanged && previous !== void 0 && previous.toolsHash !== toolsHash,
|
|
70303
|
+
cacheHitRate: calculateCumulativeCacheHitRate(messages)
|
|
70304
|
+
};
|
|
70305
|
+
lastSignals.set(hostKey, signals);
|
|
70306
|
+
return signals;
|
|
70307
|
+
}
|
|
70308
|
+
|
|
70309
|
+
// src/runtime/cache-invalidation-trace.ts
|
|
70310
|
+
function noteCacheInvalidationInChat(host, signals) {
|
|
70311
|
+
if (!signals || !signals.prefixHashChanged) return;
|
|
70312
|
+
const parts = [];
|
|
70313
|
+
if (signals.systemPromptChanged && signals.toolsChanged) parts.push("system prompt + tools rebuilt");
|
|
70314
|
+
else if (signals.toolsChanged) parts.push("tools rebuilt");
|
|
70315
|
+
else if (signals.systemPromptChanged) parts.push("system prompt rebuilt");
|
|
70316
|
+
else parts.push("prefix rebuilt");
|
|
70317
|
+
const from = signals.previousPrefixHash ?? "?";
|
|
70318
|
+
const line = `\u26A1 Prompt cache invalidated: \u2301${from} \u2192 \u2301${signals.prefixHash} (${parts.join(", ")})`;
|
|
70319
|
+
if (host.chatContainer && host.ui) {
|
|
70320
|
+
host.chatContainer.addChild(new Spacer(1));
|
|
70321
|
+
host.chatContainer.addChild(new Text(theme.fg("warning", line), 1, 0));
|
|
70322
|
+
host.ui.requestRender();
|
|
70323
|
+
}
|
|
70324
|
+
host.sessionTrace?.noteRuntimeEvent("cache_prefix_invalidated", {
|
|
70325
|
+
from,
|
|
70326
|
+
to: signals.prefixHash,
|
|
70327
|
+
systemPromptChanged: signals.systemPromptChanged,
|
|
70328
|
+
toolsChanged: signals.toolsChanged
|
|
70329
|
+
});
|
|
70330
|
+
}
|
|
70331
|
+
function applyContextSignalsWithTrace(host) {
|
|
70332
|
+
applyContextSignalsToFooter(host);
|
|
70333
|
+
noteCacheInvalidationInChat(host, getLastContextSignals(host));
|
|
70334
|
+
}
|
|
70335
|
+
|
|
70174
70336
|
// src/commands/interactive-session-commands.ts
|
|
70175
70337
|
import * as os6 from "os";
|
|
70176
70338
|
|
|
@@ -70359,6 +70521,387 @@ var SessionSelectorComponent = class extends Container {
|
|
|
70359
70521
|
}
|
|
70360
70522
|
};
|
|
70361
70523
|
|
|
70524
|
+
// src/core/context-report.ts
|
|
70525
|
+
var APPROX_BYTES_PER_TOKEN = 4;
|
|
70526
|
+
function estimateStringTokens(text) {
|
|
70527
|
+
if (!text) return 0;
|
|
70528
|
+
return Math.ceil(Buffer.byteLength(text, "utf8") / APPROX_BYTES_PER_TOKEN);
|
|
70529
|
+
}
|
|
70530
|
+
function formatReportTokens(count) {
|
|
70531
|
+
if (count < 1e3) return String(count);
|
|
70532
|
+
if (count < 1e4) return `${(count / 1e3).toFixed(1)}k`;
|
|
70533
|
+
if (count < 1e6) return `${Math.round(count / 1e3)}k`;
|
|
70534
|
+
if (count < 1e7) return `${(count / 1e6).toFixed(1)}M`;
|
|
70535
|
+
return `${Math.round(count / 1e6)}M`;
|
|
70536
|
+
}
|
|
70537
|
+
function buildSystemPromptBlocks(systemPrompt, skillsSection, knowledgeSection) {
|
|
70538
|
+
const totalTokens = estimateStringTokens(systemPrompt);
|
|
70539
|
+
const skillsTokens = skillsSection && systemPrompt.includes(skillsSection.trim()) ? estimateStringTokens(skillsSection) : null;
|
|
70540
|
+
const knowledgeTokens = knowledgeSection && systemPrompt.includes(knowledgeSection.trim()) ? estimateStringTokens(knowledgeSection) : null;
|
|
70541
|
+
const accounted = (skillsTokens ?? 0) + (knowledgeTokens ?? 0);
|
|
70542
|
+
return {
|
|
70543
|
+
totalTokens,
|
|
70544
|
+
baseTokens: Math.max(0, totalTokens - accounted),
|
|
70545
|
+
skillsTokens,
|
|
70546
|
+
knowledgeTokens
|
|
70547
|
+
};
|
|
70548
|
+
}
|
|
70549
|
+
function escapeXmlName(name) {
|
|
70550
|
+
return name.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
70551
|
+
}
|
|
70552
|
+
function extractSkillBlocks(section) {
|
|
70553
|
+
if (!section) return [];
|
|
70554
|
+
return section.split(/(?=<skill>)/).map((block) => block.trim()).filter((block) => block.startsWith("<skill>"));
|
|
70555
|
+
}
|
|
70556
|
+
function buildSkillRows(skillsSection, skills) {
|
|
70557
|
+
const blocks = extractSkillBlocks(skillsSection);
|
|
70558
|
+
if (blocks.length === 0) {
|
|
70559
|
+
return [
|
|
70560
|
+
{
|
|
70561
|
+
id: "skills:none",
|
|
70562
|
+
label: "no skills in prompt",
|
|
70563
|
+
estTokens: 0
|
|
70564
|
+
}
|
|
70565
|
+
];
|
|
70566
|
+
}
|
|
70567
|
+
return blocks.map((block, index) => {
|
|
70568
|
+
const escapedNameMatch = block.match(/<name>([\s\S]*?)<\/name>/);
|
|
70569
|
+
const escapedName = escapedNameMatch?.[1] ?? "";
|
|
70570
|
+
const skill = skills.find((candidate) => escapeXmlName(candidate.name) === escapedName) ?? skills.find((candidate) => block.includes(escapeXmlName(candidate.name)));
|
|
70571
|
+
const estTokens = estimateStringTokens(block);
|
|
70572
|
+
const source = skill?.source ? `source:${skill.source}` : void 0;
|
|
70573
|
+
const detail = skill?.inlineContent !== void 0 ? "inline content (already loaded)" : skill?.filePath ?? void 0;
|
|
70574
|
+
return {
|
|
70575
|
+
id: `skill:${skill?.name ?? index}`,
|
|
70576
|
+
label: skill?.name ?? `<skill #${index + 1}>`,
|
|
70577
|
+
estTokens,
|
|
70578
|
+
note: source,
|
|
70579
|
+
detail,
|
|
70580
|
+
drill: {
|
|
70581
|
+
kind: "text",
|
|
70582
|
+
title: `Skill \xB7 ${skill?.name ?? `#${index + 1}`}`,
|
|
70583
|
+
text: block
|
|
70584
|
+
}
|
|
70585
|
+
};
|
|
70586
|
+
}).sort((a, b2) => b2.estTokens - a.estTokens);
|
|
70587
|
+
}
|
|
70588
|
+
function parseProjectContextSection(section) {
|
|
70589
|
+
const parts = section.split(/^### (.+)$/m);
|
|
70590
|
+
const files = [];
|
|
70591
|
+
for (let i = 1; i + 1 < parts.length + 1; i += 2) {
|
|
70592
|
+
const path34 = (parts[i] ?? "").trim();
|
|
70593
|
+
const content = (parts[i + 1] ?? "").trim();
|
|
70594
|
+
if (!path34 || !content) continue;
|
|
70595
|
+
files.push({ path: path34, content });
|
|
70596
|
+
}
|
|
70597
|
+
return files;
|
|
70598
|
+
}
|
|
70599
|
+
function buildKnowledgeRows(files) {
|
|
70600
|
+
if (files.length === 0) {
|
|
70601
|
+
return [
|
|
70602
|
+
{
|
|
70603
|
+
id: "knowledge:none",
|
|
70604
|
+
label: "no AGENTS.md files found",
|
|
70605
|
+
estTokens: 0
|
|
70606
|
+
}
|
|
70607
|
+
];
|
|
70608
|
+
}
|
|
70609
|
+
return files.map((file) => {
|
|
70610
|
+
const lineCount = file.content.split("\n").length;
|
|
70611
|
+
return {
|
|
70612
|
+
id: `knowledge:${file.path}`,
|
|
70613
|
+
label: file.path,
|
|
70614
|
+
estTokens: estimateStringTokens(file.content),
|
|
70615
|
+
note: `${lineCount} lines`,
|
|
70616
|
+
detail: `AGENTS.md`,
|
|
70617
|
+
drill: {
|
|
70618
|
+
kind: "text",
|
|
70619
|
+
title: `Project Context \xB7 ${file.path}`,
|
|
70620
|
+
text: file.content
|
|
70621
|
+
}
|
|
70622
|
+
};
|
|
70623
|
+
});
|
|
70624
|
+
}
|
|
70625
|
+
function estimateToolTokens(tool) {
|
|
70626
|
+
const parameters = tool.parameters === void 0 ? "" : JSON.stringify(tool.parameters);
|
|
70627
|
+
return estimateStringTokens(`${tool.name}
|
|
70628
|
+
${tool.description ?? ""}
|
|
70629
|
+
${parameters}`);
|
|
70630
|
+
}
|
|
70631
|
+
var MAX_TOOL_DRILL_CHARS = 6e3;
|
|
70632
|
+
function buildToolRows(tools) {
|
|
70633
|
+
if (tools.length === 0) {
|
|
70634
|
+
return [{ id: "tools:none", label: "no tools registered", estTokens: 0 }];
|
|
70635
|
+
}
|
|
70636
|
+
return tools.map((tool) => {
|
|
70637
|
+
const paramsJson = tool.parameters === void 0 ? "" : JSON.stringify(tool.parameters, null, 2);
|
|
70638
|
+
const drillText = [
|
|
70639
|
+
tool.description ? `# description
|
|
70640
|
+
${tool.description}` : "",
|
|
70641
|
+
paramsJson ? `# parameters (schema)
|
|
70642
|
+
${paramsJson}` : ""
|
|
70643
|
+
].filter(Boolean).join("\n\n").slice(0, MAX_TOOL_DRILL_CHARS);
|
|
70644
|
+
return {
|
|
70645
|
+
id: `tool:${tool.name}`,
|
|
70646
|
+
label: tool.name,
|
|
70647
|
+
estTokens: estimateToolTokens(tool),
|
|
70648
|
+
note: tool.label && tool.label !== tool.name ? tool.label : void 0,
|
|
70649
|
+
detail: tool.description?.split("\n")[0]?.slice(0, 120),
|
|
70650
|
+
drill: { kind: "text", title: `Tool \xB7 ${tool.name}`, text: drillText }
|
|
70651
|
+
};
|
|
70652
|
+
}).sort((a, b2) => b2.estTokens - a.estTokens);
|
|
70653
|
+
}
|
|
70654
|
+
function entryRoleTag(entry) {
|
|
70655
|
+
return entry.role ?? entry.type;
|
|
70656
|
+
}
|
|
70657
|
+
function buildMessageRows(entries, compactionTokensBefore) {
|
|
70658
|
+
if (entries.length === 0) {
|
|
70659
|
+
return [{ id: "messages:none", label: "active context is empty", estTokens: 0 }];
|
|
70660
|
+
}
|
|
70661
|
+
return entries.map((entry) => {
|
|
70662
|
+
const roleTag = entryRoleTag(entry);
|
|
70663
|
+
const isCompaction = entry.type === "compaction";
|
|
70664
|
+
const tokensBefore = isCompaction ? compactionTokensBefore?.(entry.id) : void 0;
|
|
70665
|
+
return {
|
|
70666
|
+
id: `entry:${entry.id}`,
|
|
70667
|
+
label: `#${entry.seq} ${roleTag}`,
|
|
70668
|
+
estTokens: entry.estTokens,
|
|
70669
|
+
roleTag,
|
|
70670
|
+
marker: isCompaction ? "\u2691" : void 0,
|
|
70671
|
+
note: isCompaction ? tokensBefore !== void 0 ? `checkpoint \xB7 context was ~${formatReportTokens(tokensBefore)} before` : "checkpoint" : entry.bodyBytes > 0 ? `${formatReportTokens(entry.bodyBytes)}B body` : void 0,
|
|
70672
|
+
detail: entry.preview,
|
|
70673
|
+
drill: { kind: "entry", entryId: entry.id }
|
|
70674
|
+
};
|
|
70675
|
+
});
|
|
70676
|
+
}
|
|
70677
|
+
var MAX_PROMPT_DRILL_CHARS = 12e3;
|
|
70678
|
+
function buildContextReportData(inputs) {
|
|
70679
|
+
const knowledgeSectionText = inputs.knowledgeFiles.map((file) => `### ${file.path}
|
|
70680
|
+
${file.content}`).join("\n\n");
|
|
70681
|
+
const blocks = buildSystemPromptBlocks(
|
|
70682
|
+
inputs.systemPrompt,
|
|
70683
|
+
inputs.skillsSection,
|
|
70684
|
+
knowledgeSectionText
|
|
70685
|
+
);
|
|
70686
|
+
const systemPromptRows = [
|
|
70687
|
+
{
|
|
70688
|
+
id: "prompt:base",
|
|
70689
|
+
label: "base prompt (persona + tool guidance + guidelines + docs)",
|
|
70690
|
+
estTokens: blocks.baseTokens,
|
|
70691
|
+
drill: {
|
|
70692
|
+
kind: "text",
|
|
70693
|
+
title: "System Prompt",
|
|
70694
|
+
text: inputs.systemPrompt.slice(0, MAX_PROMPT_DRILL_CHARS)
|
|
70695
|
+
}
|
|
70696
|
+
}
|
|
70697
|
+
];
|
|
70698
|
+
if (blocks.skillsTokens !== null || inputs.skills.length > 0) {
|
|
70699
|
+
systemPromptRows.push({
|
|
70700
|
+
id: "prompt:skills",
|
|
70701
|
+
label: "skills section",
|
|
70702
|
+
estTokens: blocks.skillsTokens ?? 0,
|
|
70703
|
+
note: `${inputs.skills.length} skills`,
|
|
70704
|
+
drill: {
|
|
70705
|
+
kind: "rows",
|
|
70706
|
+
title: "System Prompt \u203A Skills",
|
|
70707
|
+
rows: buildSkillRows(inputs.skillsSection, inputs.skills),
|
|
70708
|
+
rowKind: "plain"
|
|
70709
|
+
}
|
|
70710
|
+
});
|
|
70711
|
+
}
|
|
70712
|
+
if (blocks.knowledgeTokens !== null || inputs.knowledgeFiles.length > 0) {
|
|
70713
|
+
systemPromptRows.push({
|
|
70714
|
+
id: "prompt:knowledge",
|
|
70715
|
+
label: "project context (AGENTS.md)",
|
|
70716
|
+
estTokens: blocks.knowledgeTokens ?? 0,
|
|
70717
|
+
note: `${inputs.knowledgeFiles.length} files`,
|
|
70718
|
+
drill: {
|
|
70719
|
+
kind: "rows",
|
|
70720
|
+
title: "System Prompt \u203A Project Context",
|
|
70721
|
+
rows: buildKnowledgeRows(inputs.knowledgeFiles),
|
|
70722
|
+
rowKind: "plain"
|
|
70723
|
+
}
|
|
70724
|
+
});
|
|
70725
|
+
}
|
|
70726
|
+
const systemPromptSection = {
|
|
70727
|
+
id: "system-prompt",
|
|
70728
|
+
title: "System prompt",
|
|
70729
|
+
estTokens: blocks.totalTokens,
|
|
70730
|
+
note: `base ~${formatReportTokens(blocks.baseTokens)}`,
|
|
70731
|
+
rows: systemPromptRows
|
|
70732
|
+
};
|
|
70733
|
+
const toolRows = buildToolRows(inputs.tools);
|
|
70734
|
+
const toolsTokens = toolRows.reduce((sum, row) => sum + row.estTokens, 0);
|
|
70735
|
+
const toolsSection = {
|
|
70736
|
+
id: "tools",
|
|
70737
|
+
title: `Tools (${inputs.tools.length})`,
|
|
70738
|
+
estTokens: toolsTokens,
|
|
70739
|
+
note: toolRows[0] ? `largest: ${toolRows[0].label} ~${formatReportTokens(toolRows[0].estTokens)}` : void 0,
|
|
70740
|
+
rows: toolRows
|
|
70741
|
+
};
|
|
70742
|
+
const messageRows = buildMessageRows(inputs.entries, inputs.compactionTokensBefore);
|
|
70743
|
+
const messagesTokens = inputs.entries.reduce((sum, entry) => sum + entry.estTokens, 0);
|
|
70744
|
+
const messagesSection = {
|
|
70745
|
+
id: "messages",
|
|
70746
|
+
title: `Messages (${inputs.entries.length})`,
|
|
70747
|
+
estTokens: messagesTokens,
|
|
70748
|
+
rows: messageRows
|
|
70749
|
+
};
|
|
70750
|
+
const dynamicContextSection = {
|
|
70751
|
+
id: "dynamic-context",
|
|
70752
|
+
title: "Dynamic context",
|
|
70753
|
+
estTokens: 0,
|
|
70754
|
+
note: "unmetered",
|
|
70755
|
+
rows: [
|
|
70756
|
+
{
|
|
70757
|
+
id: "dynamic:runtime-mode",
|
|
70758
|
+
label: "runtime-mode per-turn injections are not counted in these estimates",
|
|
70759
|
+
estTokens: 0,
|
|
70760
|
+
detail: "the host injects a <runtime-mode-context> block (mode flags, date, active tool names) on every request via transformContext; it is part of the est\u2212actual gap below"
|
|
70761
|
+
}
|
|
70762
|
+
]
|
|
70763
|
+
};
|
|
70764
|
+
const roleCountsMap = /* @__PURE__ */ new Map();
|
|
70765
|
+
for (const entry of inputs.entries) {
|
|
70766
|
+
const tag = entryRoleTag(entry);
|
|
70767
|
+
roleCountsMap.set(tag, (roleCountsMap.get(tag) ?? 0) + 1);
|
|
70768
|
+
}
|
|
70769
|
+
const roleCounts = [...roleCountsMap.entries()].map(([role, count]) => ({ role, count })).sort((a, b2) => b2.count - a.count || a.role.localeCompare(b2.role));
|
|
70770
|
+
const topEntries = [...inputs.entries].sort((a, b2) => b2.estTokens - a.estTokens).slice(0, 5).map((entry) => ({
|
|
70771
|
+
seq: entry.seq,
|
|
70772
|
+
label: `${entryRoleTag(entry)} \xB7 ${entry.preview}`.trim(),
|
|
70773
|
+
estTokens: entry.estTokens
|
|
70774
|
+
}));
|
|
70775
|
+
let latestCompaction = null;
|
|
70776
|
+
for (const entry of inputs.entries) {
|
|
70777
|
+
if (entry.type === "compaction") {
|
|
70778
|
+
latestCompaction = {
|
|
70779
|
+
seq: entry.seq,
|
|
70780
|
+
tokensBefore: inputs.compactionTokensBefore?.(entry.id)
|
|
70781
|
+
};
|
|
70782
|
+
}
|
|
70783
|
+
}
|
|
70784
|
+
const estimatedTotalTokens = blocks.totalTokens + toolsTokens + messagesTokens;
|
|
70785
|
+
return {
|
|
70786
|
+
sections: [systemPromptSection, toolsSection, messagesSection, dynamicContextSection],
|
|
70787
|
+
systemPromptTokens: blocks.totalTokens,
|
|
70788
|
+
toolsTokens,
|
|
70789
|
+
messagesTokens,
|
|
70790
|
+
dynamicContextTokens: 0,
|
|
70791
|
+
estimatedTotalTokens,
|
|
70792
|
+
actualTokens: inputs.actualTokens,
|
|
70793
|
+
contextWindow: inputs.contextWindow,
|
|
70794
|
+
autoCompactLimitTokens: inputs.autoCompactLimitTokens,
|
|
70795
|
+
reserveTokens: inputs.reserveTokens,
|
|
70796
|
+
promptPrefixHash: inputs.promptPrefixHash,
|
|
70797
|
+
promptPrefixChanged: inputs.promptPrefixChanged,
|
|
70798
|
+
roleCounts,
|
|
70799
|
+
topEntries,
|
|
70800
|
+
latestCompaction,
|
|
70801
|
+
entryCount: inputs.entries.length
|
|
70802
|
+
};
|
|
70803
|
+
}
|
|
70804
|
+
var identityTheme = {
|
|
70805
|
+
bold: (text) => text,
|
|
70806
|
+
fg: (_token, text) => text
|
|
70807
|
+
};
|
|
70808
|
+
function padEndVisible(text, width) {
|
|
70809
|
+
return text.length >= width ? text : text + " ".repeat(width - text.length);
|
|
70810
|
+
}
|
|
70811
|
+
function formatReportHeadline(data) {
|
|
70812
|
+
const est = `~${formatReportTokens(data.estimatedTotalTokens)}`;
|
|
70813
|
+
if (data.contextWindow > 0) {
|
|
70814
|
+
const percent = (data.estimatedTotalTokens / data.contextWindow * 100).toFixed(1);
|
|
70815
|
+
return `est ${est} / ${formatReportTokens(data.contextWindow)} (${percent}%)`;
|
|
70816
|
+
}
|
|
70817
|
+
return `est ${est} / window unknown`;
|
|
70818
|
+
}
|
|
70819
|
+
function buildContextOverviewText(data, themeInput) {
|
|
70820
|
+
const theme2 = themeInput ?? identityTheme;
|
|
70821
|
+
const lines = [];
|
|
70822
|
+
const sections = data.sections;
|
|
70823
|
+
lines.push(theme2.bold("Context Report") + theme2.fg("dim", ` \xB7 ${formatReportHeadline(data)}`));
|
|
70824
|
+
const labelWidth = 20;
|
|
70825
|
+
const branch = (index) => index === sections.length ? "\u2514" : "\u251C";
|
|
70826
|
+
sections.forEach((section, index) => {
|
|
70827
|
+
const label = padEndVisible(` ${branch(index)} ${section.title}`, labelWidth);
|
|
70828
|
+
const tokens = `~${formatReportTokens(section.estTokens)}`;
|
|
70829
|
+
const note = section.note ? theme2.fg("dim", ` ${section.note}`) : "";
|
|
70830
|
+
lines.push(`${label}${theme2.fg("accent", tokens)}${note}`);
|
|
70831
|
+
if (section.id === "messages") {
|
|
70832
|
+
const counts = data.roleCounts.map((rc) => `${rc.role} ${rc.count}`).join(" \xB7 ");
|
|
70833
|
+
if (counts) {
|
|
70834
|
+
lines.push(`${" ".repeat(labelWidth + 1)}${theme2.fg("dim", counts)}`);
|
|
70835
|
+
}
|
|
70836
|
+
for (const top of data.topEntries.slice(0, 3)) {
|
|
70837
|
+
const preview = top.label.length > 60 ? `${top.label.slice(0, 59)}\u2026` : top.label;
|
|
70838
|
+
lines.push(
|
|
70839
|
+
`${" ".repeat(labelWidth + 1)}${theme2.fg("dim", `top: #${top.seq} ${preview} (~${formatReportTokens(top.estTokens)})`)}`
|
|
70840
|
+
);
|
|
70841
|
+
}
|
|
70842
|
+
if (data.latestCompaction) {
|
|
70843
|
+
const before = data.latestCompaction.tokensBefore !== void 0 ? ` \xB7 context was ~${formatReportTokens(data.latestCompaction.tokensBefore)} before` : "";
|
|
70844
|
+
lines.push(
|
|
70845
|
+
`${" ".repeat(labelWidth + 1)}${theme2.fg("dim", `\u2691 compact checkpoint @#${data.latestCompaction.seq}${before}`)}`
|
|
70846
|
+
);
|
|
70847
|
+
}
|
|
70848
|
+
}
|
|
70849
|
+
});
|
|
70850
|
+
const autoCompact = data.autoCompactLimitTokens ? `triggers > ~${formatReportTokens(data.autoCompactLimitTokens)} (reserve ${formatReportTokens(data.reserveTokens)})` : "disabled";
|
|
70851
|
+
lines.push(
|
|
70852
|
+
`${padEndVisible(` ${branch(sections.length)} auto-compact`, labelWidth)}${theme2.fg("dim", autoCompact)}`
|
|
70853
|
+
);
|
|
70854
|
+
const reconciliation = data.actualTokens !== null ? `actual ${formatReportTokens(data.actualTokens)} (last response) \xB7 est\u2212actual \u2248 ${formatReportTokens(
|
|
70855
|
+
Math.abs(data.estimatedTotalTokens - data.actualTokens)
|
|
70856
|
+
)}${data.estimatedTotalTokens >= data.actualTokens ? " overhead" : " undercount"}` : "actual unknown until the next model response";
|
|
70857
|
+
lines.push(` ${theme2.fg("dim", reconciliation)}`);
|
|
70858
|
+
lines.push(theme2.fg("dim", " /debugs/context \xB7 Enter to drill into a section, Esc to go back"));
|
|
70859
|
+
return lines.join("\n");
|
|
70860
|
+
}
|
|
70861
|
+
function buildWindowRows(data) {
|
|
70862
|
+
const rows = [
|
|
70863
|
+
{
|
|
70864
|
+
id: "window:window",
|
|
70865
|
+
label: "context window",
|
|
70866
|
+
estTokens: data.contextWindow,
|
|
70867
|
+
valueText: data.contextWindow > 0 ? formatReportTokens(data.contextWindow) : "?",
|
|
70868
|
+
note: data.contextWindow > 0 ? `${(data.estimatedTotalTokens / data.contextWindow * 100).toFixed(1)}% used (est)` : "unknown"
|
|
70869
|
+
},
|
|
70870
|
+
{
|
|
70871
|
+
id: "window:estimated",
|
|
70872
|
+
label: "estimated total (prompt + tools + messages)",
|
|
70873
|
+
estTokens: data.estimatedTotalTokens,
|
|
70874
|
+
note: `prompt ~${formatReportTokens(data.systemPromptTokens)} \xB7 tools ~${formatReportTokens(data.toolsTokens)} \xB7 messages ~${formatReportTokens(data.messagesTokens)}`
|
|
70875
|
+
}
|
|
70876
|
+
];
|
|
70877
|
+
if (data.actualTokens !== null) {
|
|
70878
|
+
rows.push({
|
|
70879
|
+
id: "window:actual",
|
|
70880
|
+
label: "actual (last model response)",
|
|
70881
|
+
estTokens: data.actualTokens,
|
|
70882
|
+
valueText: formatReportTokens(data.actualTokens),
|
|
70883
|
+
note: `gap \u2248 ${formatReportTokens(Math.abs(data.estimatedTotalTokens - data.actualTokens))}`
|
|
70884
|
+
});
|
|
70885
|
+
}
|
|
70886
|
+
rows.push({
|
|
70887
|
+
id: "window:auto-compact",
|
|
70888
|
+
label: "auto-compact threshold",
|
|
70889
|
+
estTokens: data.autoCompactLimitTokens ?? 0,
|
|
70890
|
+
valueText: data.autoCompactLimitTokens ? `>${formatReportTokens(data.autoCompactLimitTokens)}` : "off",
|
|
70891
|
+
note: data.autoCompactLimitTokens ? `reserve ${formatReportTokens(data.reserveTokens)}` : "disabled"
|
|
70892
|
+
});
|
|
70893
|
+
if (data.promptPrefixHash) {
|
|
70894
|
+
rows.push({
|
|
70895
|
+
id: "window:prefix-hash",
|
|
70896
|
+
label: "prompt+tools hash (cache prefix)",
|
|
70897
|
+
estTokens: 0,
|
|
70898
|
+
valueText: data.promptPrefixHash,
|
|
70899
|
+
note: data.promptPrefixChanged ? "changed since last turn \u2014 provider cache invalidated \u26A1" : "stable \u2014 cache-friendly"
|
|
70900
|
+
});
|
|
70901
|
+
}
|
|
70902
|
+
return rows;
|
|
70903
|
+
}
|
|
70904
|
+
|
|
70362
70905
|
// src/components/tree-selector.ts
|
|
70363
70906
|
var RESET = "\x1B[0m";
|
|
70364
70907
|
var INVERSE = "\x1B[7m";
|
|
@@ -70728,6 +71271,9 @@ var TreeSelectorComponent = class {
|
|
|
70728
71271
|
pageNext() {
|
|
70729
71272
|
if (this.goToNextPage()) {
|
|
70730
71273
|
this.statusMessage = null;
|
|
71274
|
+
} else if (this.filteredRows.length > 0) {
|
|
71275
|
+
this.selectedIndex = Math.max(0, this.filteredRows.length - 1);
|
|
71276
|
+
this.statusMessage = "latest page - at newest entry";
|
|
70731
71277
|
} else {
|
|
70732
71278
|
this.statusMessage = this.pageSummaries.length === 0 ? "no entries" : "latest page";
|
|
70733
71279
|
}
|
|
@@ -70735,10 +71281,58 @@ var TreeSelectorComponent = class {
|
|
|
70735
71281
|
pagePrev() {
|
|
70736
71282
|
if (this.goToPreviousPage()) {
|
|
70737
71283
|
this.statusMessage = null;
|
|
71284
|
+
} else if (this.filteredRows.length > 0) {
|
|
71285
|
+
this.selectedIndex = 0;
|
|
71286
|
+
this.statusMessage = "oldest page - at first entry";
|
|
70738
71287
|
} else {
|
|
70739
71288
|
this.statusMessage = this.pageSummaries.length === 0 ? "no entries" : "oldest page";
|
|
70740
71289
|
}
|
|
70741
71290
|
}
|
|
71291
|
+
/** Jump to the oldest page (seqs start at 1; afterSeq 0 = from the start). */
|
|
71292
|
+
jumpToFirstPage() {
|
|
71293
|
+
if (this.pageSummaries.length > 0 && !this.hasPrev) {
|
|
71294
|
+
this.selectedIndex = 0;
|
|
71295
|
+
this.statusMessage = "oldest page - at first entry";
|
|
71296
|
+
return;
|
|
71297
|
+
}
|
|
71298
|
+
if (this.fetchWindow(0, null)) {
|
|
71299
|
+
this.selectedIndex = 0;
|
|
71300
|
+
this.statusMessage = null;
|
|
71301
|
+
}
|
|
71302
|
+
}
|
|
71303
|
+
/** Jump to the newest page. Seqs are 1..total (append-only journal), so the last window starts at total - pageSize. */
|
|
71304
|
+
jumpToLastPage() {
|
|
71305
|
+
if (this.pageSummaries.length > 0 && !this.hasNext) {
|
|
71306
|
+
this.selectedIndex = Math.max(0, this.filteredRows.length - 1);
|
|
71307
|
+
this.statusMessage = "latest page - at newest entry";
|
|
71308
|
+
return;
|
|
71309
|
+
}
|
|
71310
|
+
let anchor = Math.max(0, this.totalEntries - this.pageSizeValue);
|
|
71311
|
+
for (let attempt = 0; attempt < 4; attempt++) {
|
|
71312
|
+
if (this.fetchWindow(anchor, null)) {
|
|
71313
|
+
if (this.hasNext) {
|
|
71314
|
+
anchor = this.pageSummaries[this.pageSummaries.length - 1].seq;
|
|
71315
|
+
continue;
|
|
71316
|
+
}
|
|
71317
|
+
this.selectedIndex = Math.max(0, this.filteredRows.length - 1);
|
|
71318
|
+
this.statusMessage = null;
|
|
71319
|
+
return;
|
|
71320
|
+
}
|
|
71321
|
+
if (anchor === 0 || !this.hasNext) break;
|
|
71322
|
+
anchor = Math.max(0, anchor - this.pageSizeValue);
|
|
71323
|
+
}
|
|
71324
|
+
}
|
|
71325
|
+
/** Move the cursor one viewport within the resident page; ←/→ change pages. */
|
|
71326
|
+
screenScroll(delta) {
|
|
71327
|
+
if (this.filteredRows.length === 0) return;
|
|
71328
|
+
const next = Math.max(0, Math.min(this.selectedIndex + delta, this.filteredRows.length - 1));
|
|
71329
|
+
if (next === this.selectedIndex) {
|
|
71330
|
+
this.statusMessage = delta > 0 ? "end of page - \u2192 for next page" : "start of page - \u2190 for previous page";
|
|
71331
|
+
return;
|
|
71332
|
+
}
|
|
71333
|
+
this.selectedIndex = next;
|
|
71334
|
+
this.statusMessage = null;
|
|
71335
|
+
}
|
|
70742
71336
|
/**
|
|
70743
71337
|
* Bounded "next match": step to the next in-page match, otherwise scan
|
|
70744
71338
|
* forward at most SEARCH_SCAN_PAGE_LIMIT pages per press. Never scans
|
|
@@ -70792,7 +71386,7 @@ var TreeSelectorComponent = class {
|
|
|
70792
71386
|
lines.push(createLine(" Conversation Tree", width, false));
|
|
70793
71387
|
lines.push(
|
|
70794
71388
|
createLine(
|
|
70795
|
-
" \u2191\u2193:move \u2190\u2192:page e:collapse tab:
|
|
71389
|
+
" \u2191\u2193:move \u2190\u2192:page PgUp/PgDn:screen Home/End:jump e:collapse tab:match F:fork Enter:go Esc:cancel",
|
|
70796
71390
|
width,
|
|
70797
71391
|
false
|
|
70798
71392
|
)
|
|
@@ -70829,12 +71423,13 @@ var TreeSelectorComponent = class {
|
|
|
70829
71423
|
const activeIndicator = this.options.activePathSeqs.has(row.summary.seq) ? theme.fg("success", TREE_CHARS.active) : DIM + TREE_CHARS.inactive + RESET;
|
|
70830
71424
|
const expandIndicator = row.inWindowChildren ? theme.fg("dim", this.collapsed.has(row.summary.id) ? "\u25B6 " : "\u25BC ") : row.hasChildren ? theme.fg("dim", "\xB7\xB7") : " ";
|
|
70831
71425
|
const role = roleColor(roleName(row.summary));
|
|
71426
|
+
const tokenNote = row.summary.estTokens > 0 ? theme.fg("dim", ` ~${formatReportTokens(row.summary.estTokens)}`) : "";
|
|
70832
71427
|
const indicatorWidth = visibleWidth(activeIndicator) + visibleWidth(expandIndicator) + visibleWidth(role) + 2;
|
|
70833
|
-
const prefixBudget = Math.max(0, Math.min(Math.floor(width * 0.35), width - indicatorWidth - MIN_BODY_WIDTH));
|
|
71428
|
+
const prefixBudget = Math.max(0, Math.min(Math.floor(width * 0.35), width - indicatorWidth - MIN_BODY_WIDTH - visibleWidth(tokenNote)));
|
|
70834
71429
|
const displayPrefix = clampPrefixForDisplay(row.prefix, prefixBudget);
|
|
70835
|
-
const availableWidth = Math.max(0, width - visibleWidth(displayPrefix) - indicatorWidth);
|
|
71430
|
+
const availableWidth = Math.max(0, width - visibleWidth(displayPrefix) - indicatorWidth - visibleWidth(tokenNote) - 2);
|
|
70836
71431
|
const content = truncateToWidth(row.summary.preview ?? "", availableWidth);
|
|
70837
|
-
lines.push(createLine(`${displayPrefix}${activeIndicator}${expandIndicator}${role}: ${content}`, width, i === this.selectedIndex));
|
|
71432
|
+
lines.push(createLine(`${displayPrefix}${activeIndicator}${expandIndicator}${role}: ${content}${tokenNote}`, width, i === this.selectedIndex));
|
|
70838
71433
|
}
|
|
70839
71434
|
for (let i = endIndex - startIndex; i < this.maxVisibleLines; i++) {
|
|
70840
71435
|
lines.push(createLine("", width, false));
|
|
@@ -70860,10 +71455,18 @@ var TreeSelectorComponent = class {
|
|
|
70860
71455
|
this.moveUp();
|
|
70861
71456
|
} else if (kb.matches(keyData, "selectDown")) {
|
|
70862
71457
|
this.moveDown();
|
|
70863
|
-
} else if (kb.matches(keyData, "cursorRight")
|
|
71458
|
+
} else if (kb.matches(keyData, "cursorRight")) {
|
|
70864
71459
|
this.pageNext();
|
|
70865
|
-
} else if (kb.matches(keyData, "cursorLeft")
|
|
71460
|
+
} else if (kb.matches(keyData, "cursorLeft")) {
|
|
70866
71461
|
this.pagePrev();
|
|
71462
|
+
} else if (kb.matches(keyData, "selectPageDown")) {
|
|
71463
|
+
this.screenScroll(this.maxVisibleLines);
|
|
71464
|
+
} else if (kb.matches(keyData, "selectPageUp")) {
|
|
71465
|
+
this.screenScroll(-this.maxVisibleLines);
|
|
71466
|
+
} else if (kb.matches(keyData, "cursorLineStart")) {
|
|
71467
|
+
this.jumpToFirstPage();
|
|
71468
|
+
} else if (kb.matches(keyData, "cursorLineEnd")) {
|
|
71469
|
+
this.jumpToLastPage();
|
|
70867
71470
|
} else if (keyData === "e" || keyData === "E") {
|
|
70868
71471
|
this.toggleCollapse();
|
|
70869
71472
|
} else if (kb.matches(keyData, "selectConfirm")) {
|
|
@@ -72173,6 +72776,29 @@ function deriveSessionTitle(options) {
|
|
|
72173
72776
|
}
|
|
72174
72777
|
return `S:${activeSession.id.slice(-6)}`;
|
|
72175
72778
|
}
|
|
72779
|
+
function calculateSessionUsageTotals(messages) {
|
|
72780
|
+
let input = 0;
|
|
72781
|
+
let output = 0;
|
|
72782
|
+
let cacheRead = 0;
|
|
72783
|
+
let cacheWrite = 0;
|
|
72784
|
+
let cost = 0;
|
|
72785
|
+
for (const message of messages) {
|
|
72786
|
+
if (message.role !== "assistant") continue;
|
|
72787
|
+
const usage = message.usage;
|
|
72788
|
+
if (!usage) continue;
|
|
72789
|
+
input += usage.input;
|
|
72790
|
+
output += usage.output;
|
|
72791
|
+
cacheRead += usage.cacheRead;
|
|
72792
|
+
cacheWrite += usage.cacheWrite;
|
|
72793
|
+
cost += usage.cost?.total ?? 0;
|
|
72794
|
+
}
|
|
72795
|
+
return { input, output, cacheRead, cacheWrite, cost };
|
|
72796
|
+
}
|
|
72797
|
+
function formatTokensCompact(count) {
|
|
72798
|
+
if (count < 1e3) return String(count);
|
|
72799
|
+
if (count < 1e6) return `${(count / 1e3).toFixed(1)}k`;
|
|
72800
|
+
return `${(count / 1e6).toFixed(2)}M`;
|
|
72801
|
+
}
|
|
72176
72802
|
function buildSessionInfoText(options) {
|
|
72177
72803
|
const displayCwd = options.homeDir && options.cwd.startsWith(options.homeDir) ? `~${options.cwd.slice(options.homeDir.length)}` : options.cwd;
|
|
72178
72804
|
let info = options.theme.bold("Session Info") + "\n\n";
|
|
@@ -72195,6 +72821,39 @@ function buildSessionInfoText(options) {
|
|
|
72195
72821
|
`;
|
|
72196
72822
|
info += `${options.theme.fg("dim", "Thinking Level:")} ${options.thinkingLevel}
|
|
72197
72823
|
`;
|
|
72824
|
+
if (options.messages && options.messages.length > 0) {
|
|
72825
|
+
const totals = calculateSessionUsageTotals(options.messages);
|
|
72826
|
+
const turnCount = options.messages.filter((m2) => m2.role === "assistant").length;
|
|
72827
|
+
if (turnCount > 0) {
|
|
72828
|
+
info += `
|
|
72829
|
+
${options.theme.bold("Usage (active context)")}
|
|
72830
|
+
`;
|
|
72831
|
+
info += `${options.theme.fg("dim", "Turns:")} ${turnCount}
|
|
72832
|
+
`;
|
|
72833
|
+
info += `${options.theme.fg("dim", "Input:")} ${totals.input.toLocaleString()}
|
|
72834
|
+
`;
|
|
72835
|
+
info += `${options.theme.fg("dim", "Output:")} ${totals.output.toLocaleString()}
|
|
72836
|
+
`;
|
|
72837
|
+
if (totals.cacheRead > 0) {
|
|
72838
|
+
info += `${options.theme.fg("dim", "Cache Read:")} ${totals.cacheRead.toLocaleString()}
|
|
72839
|
+
`;
|
|
72840
|
+
}
|
|
72841
|
+
if (totals.cacheWrite > 0) {
|
|
72842
|
+
info += `${options.theme.fg("dim", "Cache Write:")} ${totals.cacheWrite.toLocaleString()}
|
|
72843
|
+
`;
|
|
72844
|
+
}
|
|
72845
|
+
if (totals.cost > 0) {
|
|
72846
|
+
info += `${options.theme.fg("dim", "Cost:")} $${totals.cost.toFixed(4)}
|
|
72847
|
+
`;
|
|
72848
|
+
}
|
|
72849
|
+
const hitRateBase = totals.input + totals.cacheRead;
|
|
72850
|
+
if (hitRateBase > 0 && totals.cacheRead > 0) {
|
|
72851
|
+
const hitRate = (totals.cacheRead / hitRateBase * 100).toFixed(1);
|
|
72852
|
+
info += `${options.theme.fg("dim", "Cache Hit Rate:")} ${hitRate}% (~${formatTokensCompact(hitRateBase)} served)
|
|
72853
|
+
`;
|
|
72854
|
+
}
|
|
72855
|
+
}
|
|
72856
|
+
}
|
|
72198
72857
|
return info;
|
|
72199
72858
|
}
|
|
72200
72859
|
function extractUserText(msg) {
|
|
@@ -72326,6 +72985,7 @@ async function loadSession(host, sessionId) {
|
|
|
72326
72985
|
contextPercent,
|
|
72327
72986
|
contextWindow
|
|
72328
72987
|
});
|
|
72988
|
+
applyContextSignalsWithTrace(host);
|
|
72329
72989
|
host.ui.requestRender();
|
|
72330
72990
|
setTimeout(() => host.ui.requestRender(), 100);
|
|
72331
72991
|
} catch (error) {
|
|
@@ -73103,8 +73763,9 @@ var BUILTIN_SLASH_COMMANDS = [
|
|
|
73103
73763
|
{ name: "settings/calm", description: "Toggle calm mode: show only questions and final answers" },
|
|
73104
73764
|
{ name: "settings/yolo", description: "Toggle or set YOLO mode" },
|
|
73105
73765
|
{ name: "debugs/cache-test", description: "Run provider cache diagnostics with a dedicated 2-request probe" },
|
|
73106
|
-
{ name: "debugs/context", description: "
|
|
73107
|
-
{ name: "debugs/
|
|
73766
|
+
{ name: "debugs/context", description: "Context composition report: sections, tokens, drill-down" },
|
|
73767
|
+
{ name: "debugs/trace", description: "Session trace: timeline, tool stats, runtime events" },
|
|
73768
|
+
{ name: "debugs/boot", description: "Boot composition pipeline: how the runtime was assembled" },
|
|
73108
73769
|
{ name: "settings/quit", description: "Exit Pie" },
|
|
73109
73770
|
{ name: "skills", description: "Manage skills: list, toggle enable/disable, invoke" },
|
|
73110
73771
|
{ name: "skills/list", description: "List available skills (plain text)" },
|
|
@@ -73362,6 +74023,7 @@ function bindInteractiveRuntimeEvents(host) {
|
|
|
73362
74023
|
contextPercent,
|
|
73363
74024
|
contextWindow
|
|
73364
74025
|
});
|
|
74026
|
+
applyContextSignalsWithTrace(host);
|
|
73365
74027
|
host.safeRequestRender();
|
|
73366
74028
|
host.sessionManager.save().catch((err) => {
|
|
73367
74029
|
console.error("[Session] Auto-save failed:", err);
|
|
@@ -73810,7 +74472,7 @@ function assistantDisplayBlocks(content) {
|
|
|
73810
74472
|
}
|
|
73811
74473
|
|
|
73812
74474
|
// src/commands/interactive-debug-commands.ts
|
|
73813
|
-
import { createHash as
|
|
74475
|
+
import { createHash as createHash5 } from "crypto";
|
|
73814
74476
|
function errorMessage(error) {
|
|
73815
74477
|
return error instanceof Error ? error.message : String(error);
|
|
73816
74478
|
}
|
|
@@ -73848,7 +74510,7 @@ async function handleCacheTest(host) {
|
|
|
73848
74510
|
timestamp: fixedTimestamp
|
|
73849
74511
|
}
|
|
73850
74512
|
];
|
|
73851
|
-
const prefixHash =
|
|
74513
|
+
const prefixHash = createHash5("sha256").update(
|
|
73852
74514
|
JSON.stringify({
|
|
73853
74515
|
systemPrompt: stablePrefix,
|
|
73854
74516
|
tools: toolDefs.map((tool) => ({
|
|
@@ -73957,126 +74619,6 @@ async function handleCacheTest(host) {
|
|
|
73957
74619
|
host.chatContainer.addChild(new Spacer(1));
|
|
73958
74620
|
host.ui.requestRender();
|
|
73959
74621
|
}
|
|
73960
|
-
async function handleDebugContextCommand(host) {
|
|
73961
|
-
host.chatContainer.addChild(new Spacer(1));
|
|
73962
|
-
host.chatContainer.addChild(new Text(theme.bold("Debug Context"), 1, 0));
|
|
73963
|
-
host.ui.requestRender();
|
|
73964
|
-
try {
|
|
73965
|
-
const state = host.agent.state;
|
|
73966
|
-
const debugInfo = {
|
|
73967
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
73968
|
-
systemPrompt: state.systemPrompt,
|
|
73969
|
-
model: state.model,
|
|
73970
|
-
thinkingLevel: state.thinkingLevel,
|
|
73971
|
-
tools: state.tools.map((t) => ({
|
|
73972
|
-
name: t.name,
|
|
73973
|
-
description: t.description,
|
|
73974
|
-
label: t.label
|
|
73975
|
-
})),
|
|
73976
|
-
messageCount: state.messages.length,
|
|
73977
|
-
messages: state.messages,
|
|
73978
|
-
isStreaming: state.isStreaming,
|
|
73979
|
-
pendingToolCalls: Array.from(state.pendingToolCalls)
|
|
73980
|
-
};
|
|
73981
|
-
getLogger().child({ module: "context_dump" }).info("Agent context snapshot", {
|
|
73982
|
-
snapshot: {
|
|
73983
|
-
timestamp: debugInfo.timestamp,
|
|
73984
|
-
modelId: debugInfo.model?.id ?? "",
|
|
73985
|
-
provider: debugInfo.model?.provider ?? "",
|
|
73986
|
-
thinkingLevel: debugInfo.thinkingLevel,
|
|
73987
|
-
toolCount: debugInfo.tools.length,
|
|
73988
|
-
messageCount: debugInfo.messageCount,
|
|
73989
|
-
isStreaming: debugInfo.isStreaming,
|
|
73990
|
-
pendingToolCalls: debugInfo.pendingToolCalls.length
|
|
73991
|
-
}
|
|
73992
|
-
});
|
|
73993
|
-
host.chatContainer.addChild(new Text(
|
|
73994
|
-
theme.fg("success", "\u2713 Context summary appended to ~/.pie/logs/pie-cli.log"),
|
|
73995
|
-
1,
|
|
73996
|
-
0
|
|
73997
|
-
));
|
|
73998
|
-
host.chatContainer.addChild(new Text(
|
|
73999
|
-
theme.fg("dim", ` Messages: ${state.messages.length}, Tools: ${state.tools.length}`),
|
|
74000
|
-
1,
|
|
74001
|
-
0
|
|
74002
|
-
));
|
|
74003
|
-
} catch (err) {
|
|
74004
|
-
host.showError(`Failed to save context: ${errorMessage(err)}`);
|
|
74005
|
-
}
|
|
74006
|
-
host.chatContainer.addChild(new Spacer(1));
|
|
74007
|
-
host.ui.requestRender();
|
|
74008
|
-
}
|
|
74009
|
-
async function handleDebugPackageCommand(host) {
|
|
74010
|
-
host.chatContainer.addChild(new Spacer(1));
|
|
74011
|
-
host.chatContainer.addChild(new Text(theme.bold("Debug Package"), 1, 0));
|
|
74012
|
-
host.ui.requestRender();
|
|
74013
|
-
try {
|
|
74014
|
-
const messages = host.agent.state.messages;
|
|
74015
|
-
const packageInfo = {
|
|
74016
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
74017
|
-
totalMessages: messages.length,
|
|
74018
|
-
conversation: messages.map((msg, index) => {
|
|
74019
|
-
const baseInfo = {
|
|
74020
|
-
index,
|
|
74021
|
-
role: msg.role
|
|
74022
|
-
};
|
|
74023
|
-
if (msg.role === "user") {
|
|
74024
|
-
return {
|
|
74025
|
-
...baseInfo,
|
|
74026
|
-
direction: "\u2192 SEND",
|
|
74027
|
-
content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content, null, 2)
|
|
74028
|
-
};
|
|
74029
|
-
} else if (msg.role === "assistant") {
|
|
74030
|
-
const assistantMsg = msg;
|
|
74031
|
-
const toolCalls = assistantMsg.content.filter((c) => c.type === "toolCall").map((c) => ({ name: c.name, arguments: c.arguments, id: c.id }));
|
|
74032
|
-
return {
|
|
74033
|
-
...baseInfo,
|
|
74034
|
-
direction: "\u2190 RECEIVE",
|
|
74035
|
-
content: assistantMsg.content,
|
|
74036
|
-
toolCalls,
|
|
74037
|
-
usage: assistantMsg.usage
|
|
74038
|
-
};
|
|
74039
|
-
} else if (msg.role === "toolResult") {
|
|
74040
|
-
const toolMsg = msg;
|
|
74041
|
-
return {
|
|
74042
|
-
...baseInfo,
|
|
74043
|
-
direction: "\u2192 TOOL RESULT",
|
|
74044
|
-
toolCallId: toolMsg.toolCallId,
|
|
74045
|
-
content: toolMsg.content
|
|
74046
|
-
};
|
|
74047
|
-
}
|
|
74048
|
-
return baseInfo;
|
|
74049
|
-
})
|
|
74050
|
-
};
|
|
74051
|
-
getLogger().child({ module: "package_dump" }).info("Agent package snapshot", {
|
|
74052
|
-
snapshot: {
|
|
74053
|
-
timestamp: packageInfo.timestamp,
|
|
74054
|
-
totalMessages: packageInfo.totalMessages,
|
|
74055
|
-
userMessages: packageInfo.conversation.filter((m2) => m2.role === "user").length,
|
|
74056
|
-
assistantMessages: packageInfo.conversation.filter((m2) => m2.role === "assistant").length,
|
|
74057
|
-
toolMessages: packageInfo.conversation.filter((m2) => m2.role === "toolResult").length,
|
|
74058
|
-
lastMessageRole: packageInfo.conversation.length > 0 ? packageInfo.conversation[packageInfo.conversation.length - 1].role : ""
|
|
74059
|
-
}
|
|
74060
|
-
});
|
|
74061
|
-
host.chatContainer.addChild(new Text(
|
|
74062
|
-
theme.fg("success", "\u2713 Package summary appended to ~/.pie/logs/pie-cli.log"),
|
|
74063
|
-
1,
|
|
74064
|
-
0
|
|
74065
|
-
));
|
|
74066
|
-
const userCount = messages.filter((m2) => m2.role === "user").length;
|
|
74067
|
-
const assistantCount = messages.filter((m2) => m2.role === "assistant").length;
|
|
74068
|
-
const toolCount = messages.filter((m2) => m2.role === "toolResult").length;
|
|
74069
|
-
host.chatContainer.addChild(new Text(
|
|
74070
|
-
theme.fg("dim", ` User: ${userCount}, Assistant: ${assistantCount}, Tool: ${toolCount}`),
|
|
74071
|
-
1,
|
|
74072
|
-
0
|
|
74073
|
-
));
|
|
74074
|
-
} catch (err) {
|
|
74075
|
-
host.showError(`Failed to save package log: ${errorMessage(err)}`);
|
|
74076
|
-
}
|
|
74077
|
-
host.chatContainer.addChild(new Spacer(1));
|
|
74078
|
-
host.ui.requestRender();
|
|
74079
|
-
}
|
|
74080
74622
|
|
|
74081
74623
|
// src/commands/interactive-skill-commands.ts
|
|
74082
74624
|
import * as fs24 from "fs";
|
|
@@ -74530,9 +75072,9 @@ function collectKnownToolNames(host) {
|
|
|
74530
75072
|
function describeToggleEffect(host, name, enabled) {
|
|
74531
75073
|
const loaded = collectKnownToolNames(host).active.includes(name);
|
|
74532
75074
|
if (enabled) {
|
|
74533
|
-
return loaded ? `Tool "${name}" enabled (active now).` : `Tool "${name}" enabled in ~/.pie/settings.json (loads on next start \u2014 it was not loaded this session).`;
|
|
75075
|
+
return loaded ? `Tool "${name}" enabled (saved to ~/.pie/settings.json; active now).` : `Tool "${name}" enabled in ~/.pie/settings.json (loads on next start \u2014 it was not loaded this session).`;
|
|
74534
75076
|
}
|
|
74535
|
-
return loaded ? `Tool "${name}" disabled (removed from this
|
|
75077
|
+
return loaded ? `Tool "${name}" disabled (saved to ~/.pie/settings.json; removed from this and future sessions).` : `Tool "${name}" disabled in ~/.pie/settings.json.`;
|
|
74536
75078
|
}
|
|
74537
75079
|
function showToolsManager(host) {
|
|
74538
75080
|
host.showSelector((done) => {
|
|
@@ -74637,7 +75179,7 @@ function handleToolsCommand(host, args) {
|
|
|
74637
75179
|
host.chatContainer.addChild(new Text(theme.fg("dim", " No tools available."), 1, 0));
|
|
74638
75180
|
}
|
|
74639
75181
|
for (const name of active) {
|
|
74640
|
-
const state = host.options.settingsManager.isToolEnabled(name) ? "enabled" : "disabled (removed
|
|
75182
|
+
const state = host.options.settingsManager.isToolEnabled(name) ? "enabled" : "disabled (saved to ~/.pie/settings.json; removed this session)";
|
|
74641
75183
|
host.chatContainer.addChild(new Text(theme.fg("dim", ` \u2022 ${name}: ${state}`), 1, 0));
|
|
74642
75184
|
}
|
|
74643
75185
|
for (const name of disabled) {
|
|
@@ -74653,6 +75195,944 @@ function handleToolsCommand(host, args) {
|
|
|
74653
75195
|
showToolsManager(host);
|
|
74654
75196
|
}
|
|
74655
75197
|
|
|
75198
|
+
// src/components/context-report-selector.ts
|
|
75199
|
+
var RESET2 = "\x1B[0m";
|
|
75200
|
+
var INVERSE2 = "\x1B[7m";
|
|
75201
|
+
var ROLE_FILTER_CYCLE = ["all", "user", "assistant", "toolResult", "compaction"];
|
|
75202
|
+
function createLine2(content, width, isSelected) {
|
|
75203
|
+
const normalized = content.replace(/[\r\n]+/g, " ");
|
|
75204
|
+
const body = isSelected ? INVERSE2 + normalized : normalized;
|
|
75205
|
+
return truncateToWidth(body + RESET2, width, "...", true);
|
|
75206
|
+
}
|
|
75207
|
+
function buildRootRows(sections, windowSection) {
|
|
75208
|
+
const rows = sections.map((section) => ({
|
|
75209
|
+
id: `section:${section.id}`,
|
|
75210
|
+
label: section.title,
|
|
75211
|
+
estTokens: section.estTokens,
|
|
75212
|
+
note: section.note,
|
|
75213
|
+
detail: section.id === "messages" ? "active context entries (Enter to list)" : void 0,
|
|
75214
|
+
drill: {
|
|
75215
|
+
kind: "rows",
|
|
75216
|
+
title: `${section.title}`,
|
|
75217
|
+
rows: section.rows,
|
|
75218
|
+
rowKind: section.id === "messages" ? "messages" : "plain"
|
|
75219
|
+
}
|
|
75220
|
+
}));
|
|
75221
|
+
if (windowSection) {
|
|
75222
|
+
rows.push({
|
|
75223
|
+
id: "section:window",
|
|
75224
|
+
label: windowSection.label,
|
|
75225
|
+
estTokens: windowSection.estTokens,
|
|
75226
|
+
valueText: windowSection.valueText,
|
|
75227
|
+
detail: windowSection.detail,
|
|
75228
|
+
drill: {
|
|
75229
|
+
kind: "rows",
|
|
75230
|
+
title: windowSection.title ?? windowSection.label,
|
|
75231
|
+
rows: windowSection.rows,
|
|
75232
|
+
rowKind: "plain"
|
|
75233
|
+
}
|
|
75234
|
+
});
|
|
75235
|
+
}
|
|
75236
|
+
return rows;
|
|
75237
|
+
}
|
|
75238
|
+
var ContextReportSelectorComponent = class {
|
|
75239
|
+
options;
|
|
75240
|
+
maxVisibleLines;
|
|
75241
|
+
views = [];
|
|
75242
|
+
selectedIndex = 0;
|
|
75243
|
+
searchQuery = "";
|
|
75244
|
+
statusMessage = null;
|
|
75245
|
+
_focused = false;
|
|
75246
|
+
get focused() {
|
|
75247
|
+
return this._focused;
|
|
75248
|
+
}
|
|
75249
|
+
set focused(value) {
|
|
75250
|
+
this._focused = value;
|
|
75251
|
+
}
|
|
75252
|
+
constructor(options) {
|
|
75253
|
+
this.options = options;
|
|
75254
|
+
this.maxVisibleLines = Math.max(15, Math.floor(options.terminalHeight * 0.6));
|
|
75255
|
+
this.views = [
|
|
75256
|
+
{
|
|
75257
|
+
kind: "list",
|
|
75258
|
+
title: options.title,
|
|
75259
|
+
rows: buildRootRows(options.sections, options.windowSection),
|
|
75260
|
+
rowKind: "root",
|
|
75261
|
+
roleFilter: "all",
|
|
75262
|
+
sortBySize: false
|
|
75263
|
+
}
|
|
75264
|
+
];
|
|
75265
|
+
}
|
|
75266
|
+
// ---------------------------------------------------------------------------
|
|
75267
|
+
// Filtering / sorting
|
|
75268
|
+
// ---------------------------------------------------------------------------
|
|
75269
|
+
get currentView() {
|
|
75270
|
+
return this.views[this.views.length - 1];
|
|
75271
|
+
}
|
|
75272
|
+
visibleListRows(view) {
|
|
75273
|
+
let rows = view.rows;
|
|
75274
|
+
if (view.roleFilter !== "all") {
|
|
75275
|
+
rows = rows.filter((row) => row.roleTag === view.roleFilter);
|
|
75276
|
+
}
|
|
75277
|
+
if (view.rowKind === "messages" && view.sortBySize) {
|
|
75278
|
+
rows = [...rows].sort((a, b2) => b2.estTokens - a.estTokens);
|
|
75279
|
+
}
|
|
75280
|
+
if (this.searchQuery) {
|
|
75281
|
+
const query = this.searchQuery.toLowerCase();
|
|
75282
|
+
rows = rows.filter(
|
|
75283
|
+
(row) => `${row.label} ${row.detail ?? ""} ${row.note ?? ""} ${row.roleTag ?? ""}`.toLowerCase().includes(query)
|
|
75284
|
+
);
|
|
75285
|
+
}
|
|
75286
|
+
return rows;
|
|
75287
|
+
}
|
|
75288
|
+
applyFilterChange() {
|
|
75289
|
+
this.selectedIndex = 0;
|
|
75290
|
+
this.statusMessage = null;
|
|
75291
|
+
}
|
|
75292
|
+
// ---------------------------------------------------------------------------
|
|
75293
|
+
// Navigation
|
|
75294
|
+
// ---------------------------------------------------------------------------
|
|
75295
|
+
moveUp() {
|
|
75296
|
+
const view = this.currentView;
|
|
75297
|
+
if (view.kind === "list") {
|
|
75298
|
+
const rows = this.visibleListRows(view);
|
|
75299
|
+
if (rows.length > 0) {
|
|
75300
|
+
this.selectedIndex = (this.selectedIndex - 1 + rows.length) % rows.length;
|
|
75301
|
+
}
|
|
75302
|
+
} else {
|
|
75303
|
+
view.scroll = Math.max(0, view.scroll - 1);
|
|
75304
|
+
}
|
|
75305
|
+
}
|
|
75306
|
+
moveDown() {
|
|
75307
|
+
const view = this.currentView;
|
|
75308
|
+
if (view.kind === "list") {
|
|
75309
|
+
const rows = this.visibleListRows(view);
|
|
75310
|
+
if (rows.length > 0) {
|
|
75311
|
+
this.selectedIndex = (this.selectedIndex + 1) % rows.length;
|
|
75312
|
+
}
|
|
75313
|
+
} else {
|
|
75314
|
+
view.scroll = Math.min(Math.max(0, view.lines.length - 1), view.scroll + 1);
|
|
75315
|
+
}
|
|
75316
|
+
}
|
|
75317
|
+
pageUp() {
|
|
75318
|
+
const view = this.currentView;
|
|
75319
|
+
if (view.kind === "list") {
|
|
75320
|
+
this.selectedIndex = Math.max(0, this.selectedIndex - this.maxVisibleLines);
|
|
75321
|
+
} else {
|
|
75322
|
+
view.scroll = Math.max(0, view.scroll - this.maxVisibleLines);
|
|
75323
|
+
}
|
|
75324
|
+
}
|
|
75325
|
+
pageDown() {
|
|
75326
|
+
const view = this.currentView;
|
|
75327
|
+
if (view.kind === "list") {
|
|
75328
|
+
const rows = this.visibleListRows(view);
|
|
75329
|
+
this.selectedIndex = Math.min(Math.max(0, rows.length - 1), this.selectedIndex + this.maxVisibleLines);
|
|
75330
|
+
} else {
|
|
75331
|
+
view.scroll = Math.min(
|
|
75332
|
+
Math.max(0, view.lines.length - 1),
|
|
75333
|
+
view.scroll + this.maxVisibleLines
|
|
75334
|
+
);
|
|
75335
|
+
}
|
|
75336
|
+
}
|
|
75337
|
+
pushTextView(title, text) {
|
|
75338
|
+
this.searchQuery = "";
|
|
75339
|
+
this.views.push({
|
|
75340
|
+
kind: "text",
|
|
75341
|
+
title,
|
|
75342
|
+
lines: text.replace(/\r\n/g, "\n").split("\n"),
|
|
75343
|
+
scroll: 0
|
|
75344
|
+
});
|
|
75345
|
+
this.selectedIndex = 0;
|
|
75346
|
+
this.statusMessage = null;
|
|
75347
|
+
}
|
|
75348
|
+
drillIntoSelected() {
|
|
75349
|
+
const view = this.currentView;
|
|
75350
|
+
if (view.kind !== "list") return;
|
|
75351
|
+
const rows = this.visibleListRows(view);
|
|
75352
|
+
const row = rows[this.selectedIndex];
|
|
75353
|
+
if (!row) return;
|
|
75354
|
+
if (!row.drill) {
|
|
75355
|
+
this.statusMessage = "no further detail";
|
|
75356
|
+
return;
|
|
75357
|
+
}
|
|
75358
|
+
switch (row.drill.kind) {
|
|
75359
|
+
case "rows":
|
|
75360
|
+
this.searchQuery = "";
|
|
75361
|
+
this.views.push({
|
|
75362
|
+
kind: "list",
|
|
75363
|
+
title: row.drill.title,
|
|
75364
|
+
rows: row.drill.rows,
|
|
75365
|
+
rowKind: row.drill.rowKind,
|
|
75366
|
+
roleFilter: "all",
|
|
75367
|
+
sortBySize: false
|
|
75368
|
+
});
|
|
75369
|
+
this.selectedIndex = 0;
|
|
75370
|
+
this.statusMessage = null;
|
|
75371
|
+
break;
|
|
75372
|
+
case "text":
|
|
75373
|
+
this.pushTextView(row.drill.title, row.drill.text);
|
|
75374
|
+
break;
|
|
75375
|
+
case "entry": {
|
|
75376
|
+
const text = this.options.getEntryText?.(row.drill.entryId) ?? null;
|
|
75377
|
+
if (text === null) {
|
|
75378
|
+
this.statusMessage = "entry body unavailable";
|
|
75379
|
+
} else {
|
|
75380
|
+
this.pushTextView(`Entry \xB7 ${row.label}`, text);
|
|
75381
|
+
}
|
|
75382
|
+
break;
|
|
75383
|
+
}
|
|
75384
|
+
}
|
|
75385
|
+
}
|
|
75386
|
+
popView() {
|
|
75387
|
+
if (this.views.length > 1) {
|
|
75388
|
+
this.views.pop();
|
|
75389
|
+
this.selectedIndex = 0;
|
|
75390
|
+
this.statusMessage = null;
|
|
75391
|
+
} else {
|
|
75392
|
+
this.options.onDone();
|
|
75393
|
+
}
|
|
75394
|
+
}
|
|
75395
|
+
// ---------------------------------------------------------------------------
|
|
75396
|
+
// Input
|
|
75397
|
+
// ---------------------------------------------------------------------------
|
|
75398
|
+
handleInput(keyData) {
|
|
75399
|
+
const kb = getEditorKeybindings();
|
|
75400
|
+
if (kb.matches(keyData, "selectUp")) {
|
|
75401
|
+
this.moveUp();
|
|
75402
|
+
} else if (kb.matches(keyData, "selectDown")) {
|
|
75403
|
+
this.moveDown();
|
|
75404
|
+
} else if (kb.matches(keyData, "selectPageUp")) {
|
|
75405
|
+
this.pageUp();
|
|
75406
|
+
} else if (kb.matches(keyData, "selectPageDown")) {
|
|
75407
|
+
this.pageDown();
|
|
75408
|
+
} else if (kb.matches(keyData, "selectConfirm")) {
|
|
75409
|
+
this.drillIntoSelected();
|
|
75410
|
+
} else if (kb.matches(keyData, "selectCancel")) {
|
|
75411
|
+
if (this.searchQuery) {
|
|
75412
|
+
this.searchQuery = "";
|
|
75413
|
+
this.applyFilterChange();
|
|
75414
|
+
} else {
|
|
75415
|
+
this.popView();
|
|
75416
|
+
}
|
|
75417
|
+
} else if (matchesKey(keyData, "ctrl+u")) {
|
|
75418
|
+
const view = this.currentView;
|
|
75419
|
+
if (view.kind === "list" && view.rowKind === "messages") {
|
|
75420
|
+
const next = ROLE_FILTER_CYCLE[(ROLE_FILTER_CYCLE.indexOf(view.roleFilter) + 1) % ROLE_FILTER_CYCLE.length];
|
|
75421
|
+
view.roleFilter = next;
|
|
75422
|
+
this.applyFilterChange();
|
|
75423
|
+
}
|
|
75424
|
+
} else if ((keyData === "s" || keyData === "S") && this.searchQuery === "") {
|
|
75425
|
+
const view = this.currentView;
|
|
75426
|
+
if (view.kind === "list" && view.rowKind === "messages") {
|
|
75427
|
+
view.sortBySize = !view.sortBySize;
|
|
75428
|
+
this.applyFilterChange();
|
|
75429
|
+
}
|
|
75430
|
+
} else if (kb.matches(keyData, "deleteCharBackward")) {
|
|
75431
|
+
if (this.searchQuery.length > 0) {
|
|
75432
|
+
this.searchQuery = this.searchQuery.slice(0, -1);
|
|
75433
|
+
this.applyFilterChange();
|
|
75434
|
+
}
|
|
75435
|
+
} else {
|
|
75436
|
+
const hasControlChars = [...keyData].some((ch) => {
|
|
75437
|
+
const code = ch.charCodeAt(0);
|
|
75438
|
+
return code < 32 || code === 127 || code >= 128 && code <= 159;
|
|
75439
|
+
});
|
|
75440
|
+
if (!hasControlChars && keyData.length > 0 && this.searchQuery.length < 100) {
|
|
75441
|
+
this.searchQuery += keyData;
|
|
75442
|
+
this.applyFilterChange();
|
|
75443
|
+
}
|
|
75444
|
+
}
|
|
75445
|
+
}
|
|
75446
|
+
// ---------------------------------------------------------------------------
|
|
75447
|
+
// Rendering
|
|
75448
|
+
// ---------------------------------------------------------------------------
|
|
75449
|
+
invalidate() {
|
|
75450
|
+
}
|
|
75451
|
+
hintsLine(view) {
|
|
75452
|
+
if (view.kind === "text") {
|
|
75453
|
+
return " \u2191\u2193:scroll Esc:back";
|
|
75454
|
+
}
|
|
75455
|
+
const base = " \u2191\u2193:move Enter:drill Esc:back type:search PgUp/PgDn:page";
|
|
75456
|
+
if (view.rowKind === "messages") {
|
|
75457
|
+
return `${base} ctrl+u:role(${view.roleFilter}) s:sort(${view.sortBySize ? "size" : "seq"})`;
|
|
75458
|
+
}
|
|
75459
|
+
return base;
|
|
75460
|
+
}
|
|
75461
|
+
renderRowLine(row, width, selected) {
|
|
75462
|
+
const valueText = row.valueText ?? `~${formatReportTokens(row.estTokens)}`;
|
|
75463
|
+
const rightParts = [theme.fg("accent", valueText)];
|
|
75464
|
+
if (row.note) {
|
|
75465
|
+
rightParts.push(theme.fg("dim", row.note));
|
|
75466
|
+
}
|
|
75467
|
+
const right = rightParts.join(" ");
|
|
75468
|
+
const rightWidth = visibleWidth(right);
|
|
75469
|
+
const marker = row.marker ? theme.fg("warning", `${row.marker} `) : "";
|
|
75470
|
+
const detail = row.detail ? theme.fg("dim", ` \xB7 ${row.detail}`) : "";
|
|
75471
|
+
let left = ` ${marker}${row.label}${detail}`;
|
|
75472
|
+
const leftBudget = Math.max(12, width - rightWidth - 3);
|
|
75473
|
+
if (visibleWidth(left) > leftBudget) {
|
|
75474
|
+
left = truncateToWidth(left, leftBudget, "\u2026");
|
|
75475
|
+
}
|
|
75476
|
+
const gap = Math.max(1, width - visibleWidth(left) - rightWidth - 1);
|
|
75477
|
+
return createLine2(`${left}${" ".repeat(gap)}${right}`, width, selected);
|
|
75478
|
+
}
|
|
75479
|
+
render(width) {
|
|
75480
|
+
const lines = [];
|
|
75481
|
+
const totalLines = this.maxVisibleLines + 5;
|
|
75482
|
+
const view = this.currentView;
|
|
75483
|
+
const depthSuffix = this.views.length > 1 ? theme.fg("dim", ` (${this.views.length} levels)`) : "";
|
|
75484
|
+
lines.push(createLine2(` ${theme.bold(view.title)}${depthSuffix}`, width, false));
|
|
75485
|
+
lines.push(createLine2(this.hintsLine(view), width, false));
|
|
75486
|
+
const searchPart = this.searchQuery ? `Search: ${this.searchQuery}` : "";
|
|
75487
|
+
const statusPart = this.statusMessage ? theme.fg("warning", this.statusMessage) : "";
|
|
75488
|
+
const statusLine = [searchPart, statusPart].filter(Boolean).join(" \xB7 ");
|
|
75489
|
+
lines.push(createLine2(statusLine, width, false));
|
|
75490
|
+
lines.push(createLine2("", width, false));
|
|
75491
|
+
if (view.kind === "list") {
|
|
75492
|
+
const rows = this.visibleListRows(view);
|
|
75493
|
+
if (rows.length === 0) {
|
|
75494
|
+
const notice = this.searchQuery || view.roleFilter !== "all" ? " (no matching rows)" : " (empty)";
|
|
75495
|
+
lines.push(createLine2(notice, width, false));
|
|
75496
|
+
for (let i = 1; i < this.maxVisibleLines; i++) {
|
|
75497
|
+
lines.push(createLine2("", width, false));
|
|
75498
|
+
}
|
|
75499
|
+
} else {
|
|
75500
|
+
this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, rows.length - 1));
|
|
75501
|
+
let startIndex = Math.max(
|
|
75502
|
+
0,
|
|
75503
|
+
Math.min(
|
|
75504
|
+
this.selectedIndex - Math.floor(this.maxVisibleLines / 2),
|
|
75505
|
+
rows.length - this.maxVisibleLines
|
|
75506
|
+
)
|
|
75507
|
+
);
|
|
75508
|
+
const endIndex = Math.min(startIndex + this.maxVisibleLines, rows.length);
|
|
75509
|
+
if (endIndex - startIndex < this.maxVisibleLines && startIndex > 0) {
|
|
75510
|
+
startIndex = Math.max(0, endIndex - this.maxVisibleLines);
|
|
75511
|
+
}
|
|
75512
|
+
for (let i = startIndex; i < endIndex; i++) {
|
|
75513
|
+
lines.push(this.renderRowLine(rows[i], width, i === this.selectedIndex));
|
|
75514
|
+
}
|
|
75515
|
+
for (let i = endIndex - startIndex; i < this.maxVisibleLines; i++) {
|
|
75516
|
+
lines.push(createLine2("", width, false));
|
|
75517
|
+
}
|
|
75518
|
+
}
|
|
75519
|
+
const filterSuffix = view.roleFilter !== "all" ? ` [${view.roleFilter}]` : "";
|
|
75520
|
+
const sortSuffix = view.rowKind === "messages" && view.sortBySize ? " [size]" : "";
|
|
75521
|
+
lines.push(
|
|
75522
|
+
createLine2(
|
|
75523
|
+
` (${this.selectedIndex + 1}/${this.visibleListRows(view).length})${filterSuffix}${sortSuffix}`,
|
|
75524
|
+
width,
|
|
75525
|
+
false
|
|
75526
|
+
)
|
|
75527
|
+
);
|
|
75528
|
+
} else {
|
|
75529
|
+
const total = view.lines.length;
|
|
75530
|
+
const start = Math.min(view.scroll, Math.max(0, total - 1));
|
|
75531
|
+
const end = Math.min(start + this.maxVisibleLines, total);
|
|
75532
|
+
for (let i = start; i < end; i++) {
|
|
75533
|
+
lines.push(createLine2(` ${view.lines[i]}`, width, false));
|
|
75534
|
+
}
|
|
75535
|
+
for (let i = end - start; i < this.maxVisibleLines; i++) {
|
|
75536
|
+
lines.push(createLine2("", width, false));
|
|
75537
|
+
}
|
|
75538
|
+
lines.push(
|
|
75539
|
+
createLine2(` (lines ${total > 0 ? start + 1 : 0}-${end} of ${total})`, width, false)
|
|
75540
|
+
);
|
|
75541
|
+
}
|
|
75542
|
+
while (lines.length < totalLines) {
|
|
75543
|
+
lines.push(createLine2("", width, false));
|
|
75544
|
+
}
|
|
75545
|
+
return lines.slice(0, totalLines);
|
|
75546
|
+
}
|
|
75547
|
+
};
|
|
75548
|
+
|
|
75549
|
+
// src/commands/interactive-context-command.ts
|
|
75550
|
+
var MAX_ENTRY_BODY_CHARS = 1e4;
|
|
75551
|
+
var MAX_ARCHIVED_ROWS = 200;
|
|
75552
|
+
function fetchArchivedSummaries(sessionManager, firstKeptSeq) {
|
|
75553
|
+
const result = [];
|
|
75554
|
+
let afterSeq;
|
|
75555
|
+
while (result.length < MAX_ARCHIVED_ROWS) {
|
|
75556
|
+
const page = sessionManager.getEntrySummariesPage({ limit: 100, afterSeq });
|
|
75557
|
+
if (page.summaries.length === 0) break;
|
|
75558
|
+
let crossedCutPoint = false;
|
|
75559
|
+
for (const summary of page.summaries) {
|
|
75560
|
+
if (summary.seq >= firstKeptSeq) {
|
|
75561
|
+
crossedCutPoint = true;
|
|
75562
|
+
break;
|
|
75563
|
+
}
|
|
75564
|
+
if (result.length >= MAX_ARCHIVED_ROWS) break;
|
|
75565
|
+
result.push(summary);
|
|
75566
|
+
}
|
|
75567
|
+
if (crossedCutPoint || !page.hasMore) break;
|
|
75568
|
+
afterSeq = page.summaries[page.summaries.length - 1].seq;
|
|
75569
|
+
}
|
|
75570
|
+
return result;
|
|
75571
|
+
}
|
|
75572
|
+
function enhanceCheckpointRowWithArchive(report, host, entries) {
|
|
75573
|
+
const messagesSection = report.sections.find((section) => section.id === "messages");
|
|
75574
|
+
const checkpoint = [...entries].reverse().find((entry) => entry.type === "compaction");
|
|
75575
|
+
if (!messagesSection || !checkpoint) return;
|
|
75576
|
+
const compactionEntry = host.sessionManager.getEntry(checkpoint.id);
|
|
75577
|
+
const firstKeptEntryId = compactionEntry?.compactionData?.firstKeptEntryId;
|
|
75578
|
+
if (!firstKeptEntryId) return;
|
|
75579
|
+
const firstKeptSeq = host.sessionManager.getEntrySummary(firstKeptEntryId)?.seq;
|
|
75580
|
+
if (firstKeptSeq === void 0) return;
|
|
75581
|
+
const archived = fetchArchivedSummaries(host.sessionManager, firstKeptSeq);
|
|
75582
|
+
if (archived.length === 0) return;
|
|
75583
|
+
const row = messagesSection.rows.find((candidate) => candidate.id === `entry:${checkpoint.id}`);
|
|
75584
|
+
if (!row) return;
|
|
75585
|
+
const truncated = archived.length >= MAX_ARCHIVED_ROWS;
|
|
75586
|
+
row.drill = {
|
|
75587
|
+
kind: "rows",
|
|
75588
|
+
title: `Archived @ checkpoint #${checkpoint.seq}`,
|
|
75589
|
+
rowKind: "plain",
|
|
75590
|
+
rows: [
|
|
75591
|
+
{
|
|
75592
|
+
id: "checkpoint-summary",
|
|
75593
|
+
label: "checkpoint summary",
|
|
75594
|
+
estTokens: checkpoint.estTokens,
|
|
75595
|
+
drill: {
|
|
75596
|
+
kind: "text",
|
|
75597
|
+
title: "Checkpoint Summary",
|
|
75598
|
+
text: compactionEntry?.compactionData?.summary ?? ""
|
|
75599
|
+
}
|
|
75600
|
+
},
|
|
75601
|
+
...archived.map((summary) => ({
|
|
75602
|
+
id: `archived:${summary.id}`,
|
|
75603
|
+
label: `#${summary.seq} ${summary.role ?? summary.type}`,
|
|
75604
|
+
estTokens: summary.estTokens,
|
|
75605
|
+
detail: summary.preview,
|
|
75606
|
+
drill: { kind: "entry", entryId: summary.id }
|
|
75607
|
+
})),
|
|
75608
|
+
...truncated ? [{
|
|
75609
|
+
id: "archived:truncated",
|
|
75610
|
+
label: `\u2026 archived list capped at ${MAX_ARCHIVED_ROWS} entries (oldest first)`,
|
|
75611
|
+
estTokens: 0
|
|
75612
|
+
}] : []
|
|
75613
|
+
]
|
|
75614
|
+
};
|
|
75615
|
+
}
|
|
75616
|
+
function formatEntryBodyText(entry) {
|
|
75617
|
+
if (!entry) return null;
|
|
75618
|
+
if (entry.type === "compaction") {
|
|
75619
|
+
const summary = entry.compactionData?.summary ?? "";
|
|
75620
|
+
const before = entry.compactionData?.tokensBefore;
|
|
75621
|
+
const header = before !== void 0 ? `# compaction checkpoint (context was ~${formatReportTokens(before)} before)
|
|
75622
|
+
` : "# compaction checkpoint\n";
|
|
75623
|
+
return `${header}
|
|
75624
|
+
${summary}`.slice(0, MAX_ENTRY_BODY_CHARS) || null;
|
|
75625
|
+
}
|
|
75626
|
+
const message = entry.message;
|
|
75627
|
+
if (!message) return null;
|
|
75628
|
+
if (message.role === "user") {
|
|
75629
|
+
const parts = ["# user message"];
|
|
75630
|
+
const content = message.content;
|
|
75631
|
+
if (typeof content === "string") {
|
|
75632
|
+
parts.push(content);
|
|
75633
|
+
} else if (Array.isArray(content)) {
|
|
75634
|
+
for (const block of content) {
|
|
75635
|
+
if (block && block.type === "text" && typeof block.text === "string") {
|
|
75636
|
+
parts.push(block.text);
|
|
75637
|
+
} else if (block && "type" in block) {
|
|
75638
|
+
parts.push(`[${block.type}]`);
|
|
75639
|
+
}
|
|
75640
|
+
}
|
|
75641
|
+
}
|
|
75642
|
+
return parts.join("\n").slice(0, MAX_ENTRY_BODY_CHARS) || null;
|
|
75643
|
+
}
|
|
75644
|
+
if (message.role === "assistant") {
|
|
75645
|
+
const parts = ["# assistant message"];
|
|
75646
|
+
const usage = message.usage;
|
|
75647
|
+
if (usage) {
|
|
75648
|
+
parts.push(
|
|
75649
|
+
`usage: input ${usage.input} \xB7 output ${usage.output} \xB7 cacheRead ${usage.cacheRead} \xB7 cacheWrite ${usage.cacheWrite}`
|
|
75650
|
+
);
|
|
75651
|
+
}
|
|
75652
|
+
if (Array.isArray(message.content)) {
|
|
75653
|
+
for (const block of message.content) {
|
|
75654
|
+
if (block.type === "text") {
|
|
75655
|
+
parts.push(block.text);
|
|
75656
|
+
} else if (block.type === "thinking") {
|
|
75657
|
+
parts.push("[thinking omitted from context on most providers]");
|
|
75658
|
+
} else if (block.type === "toolCall") {
|
|
75659
|
+
parts.push(`\u2192 ${block.name}(${JSON.stringify(block.arguments)})`);
|
|
75660
|
+
}
|
|
75661
|
+
}
|
|
75662
|
+
}
|
|
75663
|
+
return parts.join("\n").slice(0, MAX_ENTRY_BODY_CHARS) || null;
|
|
75664
|
+
}
|
|
75665
|
+
if (message.role === "toolResult") {
|
|
75666
|
+
const parts = [`# tool result (${message.toolCallId})`];
|
|
75667
|
+
if (Array.isArray(message.content)) {
|
|
75668
|
+
for (const block of message.content) {
|
|
75669
|
+
if (block.type === "text") {
|
|
75670
|
+
parts.push(block.text);
|
|
75671
|
+
} else if (block.type === "image") {
|
|
75672
|
+
parts.push("[image]");
|
|
75673
|
+
} else if (block.type === "audio") {
|
|
75674
|
+
parts.push("[audio]");
|
|
75675
|
+
} else if (block.type === "video") {
|
|
75676
|
+
parts.push("[video]");
|
|
75677
|
+
} else {
|
|
75678
|
+
parts.push(`[${block.type}]`);
|
|
75679
|
+
}
|
|
75680
|
+
}
|
|
75681
|
+
}
|
|
75682
|
+
return parts.join("\n").slice(0, MAX_ENTRY_BODY_CHARS) || null;
|
|
75683
|
+
}
|
|
75684
|
+
return JSON.stringify(message, null, 2).slice(0, MAX_ENTRY_BODY_CHARS) || null;
|
|
75685
|
+
}
|
|
75686
|
+
function handleContextReportCommand(host) {
|
|
75687
|
+
const systemPrompt = host.agent.state.systemPrompt ?? "";
|
|
75688
|
+
const knowledgeFiles = parseProjectContextSection(host.knowledgeSection);
|
|
75689
|
+
const entries = host.sessionManager.getActiveContextSummaries();
|
|
75690
|
+
const usage = host.calculateContextUsage();
|
|
75691
|
+
const contextWindow = host.options.model?.contextWindow ?? 0;
|
|
75692
|
+
const reserveTokens = host.options.settingsManager.getAutoCompactReserveTokens();
|
|
75693
|
+
const autoCompactLimit = contextWindow > 0 ? getAutoCompactTokenLimit(contextWindow, reserveTokens) ?? null : null;
|
|
75694
|
+
const prefixHash = computePromptPrefixHash(
|
|
75695
|
+
systemPrompt,
|
|
75696
|
+
host.agent.state.tools.map((tool) => ({
|
|
75697
|
+
name: tool.name,
|
|
75698
|
+
description: tool.description,
|
|
75699
|
+
parameters: tool.parameters
|
|
75700
|
+
}))
|
|
75701
|
+
);
|
|
75702
|
+
const lastSignals2 = getLastContextSignals(host);
|
|
75703
|
+
const promptPrefixChanged = lastSignals2 !== null && lastSignals2.prefixHash !== prefixHash;
|
|
75704
|
+
const report = buildContextReportData({
|
|
75705
|
+
systemPrompt,
|
|
75706
|
+
skillsSection: host.skillsSection,
|
|
75707
|
+
knowledgeFiles,
|
|
75708
|
+
skills: host.skills.map((skill) => ({
|
|
75709
|
+
name: skill.name,
|
|
75710
|
+
description: skill.description,
|
|
75711
|
+
filePath: skill.filePath,
|
|
75712
|
+
baseDir: skill.baseDir,
|
|
75713
|
+
source: skill.source
|
|
75714
|
+
})),
|
|
75715
|
+
tools: host.agent.state.tools.map((tool) => ({
|
|
75716
|
+
name: tool.name,
|
|
75717
|
+
label: tool.label,
|
|
75718
|
+
description: tool.description,
|
|
75719
|
+
parameters: tool.parameters
|
|
75720
|
+
})),
|
|
75721
|
+
entries,
|
|
75722
|
+
compactionTokensBefore: (entryId) => host.sessionManager.getEntry(entryId)?.compactionData?.tokensBefore,
|
|
75723
|
+
contextWindow,
|
|
75724
|
+
actualTokens: usage.tokens,
|
|
75725
|
+
autoCompactLimitTokens: autoCompactLimit,
|
|
75726
|
+
reserveTokens,
|
|
75727
|
+
promptPrefixHash: prefixHash,
|
|
75728
|
+
promptPrefixChanged
|
|
75729
|
+
});
|
|
75730
|
+
enhanceCheckpointRowWithArchive(report, host, entries);
|
|
75731
|
+
host.chatContainer.addChild(new Spacer(1));
|
|
75732
|
+
host.chatContainer.addChild(new Text(buildContextOverviewText(report, theme), 1, 0));
|
|
75733
|
+
host.ui.requestRender();
|
|
75734
|
+
host.showSelector((done) => {
|
|
75735
|
+
const selector = new ContextReportSelectorComponent({
|
|
75736
|
+
title: "Context Report",
|
|
75737
|
+
sections: report.sections,
|
|
75738
|
+
windowSection: {
|
|
75739
|
+
label: "window & thresholds",
|
|
75740
|
+
estTokens: report.contextWindow,
|
|
75741
|
+
valueText: report.contextWindow > 0 ? formatReportTokens(report.contextWindow) : "?",
|
|
75742
|
+
title: "Window & Thresholds",
|
|
75743
|
+
detail: "context window, estimate vs actual, auto-compact",
|
|
75744
|
+
rows: buildWindowRows(report)
|
|
75745
|
+
},
|
|
75746
|
+
terminalHeight: host.ui.terminal.rows,
|
|
75747
|
+
getEntryText: (entryId) => formatEntryBodyText(host.sessionManager.getEntry(entryId)),
|
|
75748
|
+
onDone: done
|
|
75749
|
+
});
|
|
75750
|
+
return { component: selector, focus: selector };
|
|
75751
|
+
});
|
|
75752
|
+
}
|
|
75753
|
+
|
|
75754
|
+
// src/core/trace-report.ts
|
|
75755
|
+
var MAX_DRILL_CHARS = 8e3;
|
|
75756
|
+
function formatTime(at) {
|
|
75757
|
+
return new Date(at).toLocaleTimeString([], { hour12: false });
|
|
75758
|
+
}
|
|
75759
|
+
function formatDurationMs(ms) {
|
|
75760
|
+
if (ms < 1e3) return `${Math.round(ms)}ms`;
|
|
75761
|
+
if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
|
|
75762
|
+
return `${Math.floor(ms / 6e4)}m${Math.round(ms % 6e4 / 1e3)}s`;
|
|
75763
|
+
}
|
|
75764
|
+
function detailsToText(event) {
|
|
75765
|
+
const header = [
|
|
75766
|
+
`# ${event.type}`,
|
|
75767
|
+
`at: ${new Date(event.at).toISOString()}`,
|
|
75768
|
+
event.summary ? `summary: ${event.summary}` : "",
|
|
75769
|
+
event.failure ? "failure: true" : ""
|
|
75770
|
+
].filter(Boolean).join("\n");
|
|
75771
|
+
const details = event.details === void 0 ? "" : `
|
|
75772
|
+
|
|
75773
|
+
# details
|
|
75774
|
+
${safeStringify(event.details).slice(0, MAX_DRILL_CHARS)}`;
|
|
75775
|
+
return `${header}${details}`;
|
|
75776
|
+
}
|
|
75777
|
+
function safeStringify(value) {
|
|
75778
|
+
try {
|
|
75779
|
+
return typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
75780
|
+
} catch {
|
|
75781
|
+
return String(value);
|
|
75782
|
+
}
|
|
75783
|
+
}
|
|
75784
|
+
function buildTimelineRows(timeline) {
|
|
75785
|
+
if (timeline.length === 0) {
|
|
75786
|
+
return [{ id: "timeline:none", label: "no runtime events recorded yet", estTokens: 0 }];
|
|
75787
|
+
}
|
|
75788
|
+
return [...timeline].sort((a, b2) => b2.at - a.at).map((event, index) => ({
|
|
75789
|
+
id: `timeline:${event.at}:${index}`,
|
|
75790
|
+
label: `${formatTime(event.at)} ${event.type}`,
|
|
75791
|
+
estTokens: 0,
|
|
75792
|
+
detail: event.summary || void 0,
|
|
75793
|
+
marker: event.failure ? "\u2716" : void 0,
|
|
75794
|
+
drill: {
|
|
75795
|
+
kind: "text",
|
|
75796
|
+
title: `Event \xB7 ${event.type}`,
|
|
75797
|
+
text: detailsToText(event)
|
|
75798
|
+
}
|
|
75799
|
+
}));
|
|
75800
|
+
}
|
|
75801
|
+
function aggregateToolStats(turns) {
|
|
75802
|
+
const stats = /* @__PURE__ */ new Map();
|
|
75803
|
+
for (const turn of turns) {
|
|
75804
|
+
for (const call of turn.toolCalls) {
|
|
75805
|
+
const stat2 = stats.get(call.toolName) ?? {
|
|
75806
|
+
name: call.toolName,
|
|
75807
|
+
calls: 0,
|
|
75808
|
+
errors: 0,
|
|
75809
|
+
totalMs: 0
|
|
75810
|
+
};
|
|
75811
|
+
stat2.calls += 1;
|
|
75812
|
+
if (call.status === "failed") stat2.errors += 1;
|
|
75813
|
+
if (call.endedAt !== void 0 && call.endedAt >= call.startedAt) {
|
|
75814
|
+
stat2.totalMs += call.endedAt - call.startedAt;
|
|
75815
|
+
}
|
|
75816
|
+
stats.set(call.toolName, stat2);
|
|
75817
|
+
}
|
|
75818
|
+
}
|
|
75819
|
+
return [...stats.values()].sort((a, b2) => b2.totalMs - a.totalMs || b2.calls - a.calls);
|
|
75820
|
+
}
|
|
75821
|
+
function buildToolStatRows(turns) {
|
|
75822
|
+
const stats = aggregateToolStats(turns);
|
|
75823
|
+
if (stats.length === 0) {
|
|
75824
|
+
return [{ id: "tools:none", label: "no tool calls in recent turns", estTokens: 0 }];
|
|
75825
|
+
}
|
|
75826
|
+
return stats.map((stat2) => ({
|
|
75827
|
+
id: `toolstat:${stat2.name}`,
|
|
75828
|
+
label: stat2.name,
|
|
75829
|
+
estTokens: 0,
|
|
75830
|
+
valueText: formatDurationMs(stat2.totalMs),
|
|
75831
|
+
note: `${stat2.calls} calls${stat2.errors > 0 ? ` \xB7 ${stat2.errors} errors` : ""}`,
|
|
75832
|
+
drill: {
|
|
75833
|
+
kind: "rows",
|
|
75834
|
+
title: `Tool Calls \xB7 ${stat2.name}`,
|
|
75835
|
+
rowKind: "plain",
|
|
75836
|
+
rows: collectCalls(turns, stat2.name)
|
|
75837
|
+
}
|
|
75838
|
+
}));
|
|
75839
|
+
}
|
|
75840
|
+
function collectCalls(turns, toolName) {
|
|
75841
|
+
const rows = [];
|
|
75842
|
+
for (const turn of turns) {
|
|
75843
|
+
for (const call of turn.toolCalls) {
|
|
75844
|
+
if (call.toolName !== toolName) continue;
|
|
75845
|
+
const duration = call.endedAt !== void 0 && call.endedAt >= call.startedAt ? formatDurationMs(call.endedAt - call.startedAt) : "running";
|
|
75846
|
+
rows.push({
|
|
75847
|
+
id: `call:${call.toolCallId ?? `${call.startedAt}:${rows.length}`}`,
|
|
75848
|
+
label: `${formatTime(call.startedAt)} ${call.status}`,
|
|
75849
|
+
estTokens: 0,
|
|
75850
|
+
valueText: duration,
|
|
75851
|
+
detail: call.resultSummary || void 0,
|
|
75852
|
+
marker: call.status === "failed" ? "\u2716" : void 0,
|
|
75853
|
+
drill: {
|
|
75854
|
+
kind: "text",
|
|
75855
|
+
title: `Call \xB7 ${toolName}`,
|
|
75856
|
+
text: [
|
|
75857
|
+
`# ${toolName} (${call.status})`,
|
|
75858
|
+
`started: ${new Date(call.startedAt).toISOString()}`,
|
|
75859
|
+
call.endedAt !== void 0 ? `ended: ${new Date(call.endedAt).toISOString()}` : "",
|
|
75860
|
+
call.outcome !== void 0 ? `
|
|
75861
|
+
# outcome
|
|
75862
|
+
${safeStringify(call.outcome)}` : ""
|
|
75863
|
+
].filter(Boolean).join("\n").slice(0, MAX_DRILL_CHARS)
|
|
75864
|
+
}
|
|
75865
|
+
});
|
|
75866
|
+
}
|
|
75867
|
+
}
|
|
75868
|
+
return rows.sort((a, b2) => a.id.localeCompare(b2.id));
|
|
75869
|
+
}
|
|
75870
|
+
function buildTurnRows(turns) {
|
|
75871
|
+
if (turns.length === 0) {
|
|
75872
|
+
return [{ id: "turns:none", label: "no completed turns recorded yet", estTokens: 0 }];
|
|
75873
|
+
}
|
|
75874
|
+
return [...turns].sort((a, b2) => b2.turnIndex - a.turnIndex).map((turn) => {
|
|
75875
|
+
const duration = turn.completedAt !== void 0 && turn.startedAt !== void 0 && turn.completedAt >= turn.startedAt ? formatDurationMs(turn.completedAt - turn.startedAt) : "\u2014";
|
|
75876
|
+
return {
|
|
75877
|
+
id: `turn:${turn.turnIndex}`,
|
|
75878
|
+
label: `#${turn.turnIndex} ${turn.state}`,
|
|
75879
|
+
estTokens: 0,
|
|
75880
|
+
valueText: duration,
|
|
75881
|
+
note: `${turn.toolCalls.length} tool calls`,
|
|
75882
|
+
detail: turn.userText?.slice(0, 80) || void 0,
|
|
75883
|
+
marker: turn.state === "failed" ? "\u2716" : void 0,
|
|
75884
|
+
drill: {
|
|
75885
|
+
kind: "text",
|
|
75886
|
+
title: `Turn #${turn.turnIndex}`,
|
|
75887
|
+
text: turnToText(turn)
|
|
75888
|
+
}
|
|
75889
|
+
};
|
|
75890
|
+
});
|
|
75891
|
+
}
|
|
75892
|
+
function turnToText(turn) {
|
|
75893
|
+
const parts = [
|
|
75894
|
+
`# turn ${turn.turnIndex} (${turn.state})`,
|
|
75895
|
+
turn.startedAt !== void 0 ? `started: ${new Date(turn.startedAt).toISOString()}` : "",
|
|
75896
|
+
turn.completedAt !== void 0 ? `completed: ${new Date(turn.completedAt).toISOString()}` : ""
|
|
75897
|
+
];
|
|
75898
|
+
if (turn.userText) parts.push(`
|
|
75899
|
+
# user
|
|
75900
|
+
${turn.userText.slice(0, 2e3)}`);
|
|
75901
|
+
if (turn.assistantText) parts.push(`
|
|
75902
|
+
# assistant
|
|
75903
|
+
${turn.assistantText.slice(0, 2e3)}`);
|
|
75904
|
+
if (turn.errorMessage) parts.push(`
|
|
75905
|
+
# error
|
|
75906
|
+
${turn.errorMessage}`);
|
|
75907
|
+
if (turn.toolCalls.length > 0) {
|
|
75908
|
+
parts.push(
|
|
75909
|
+
`
|
|
75910
|
+
# tool calls
|
|
75911
|
+
${turn.toolCalls.map(
|
|
75912
|
+
(call) => `- ${call.toolName} (${call.status})${call.endedAt !== void 0 && call.endedAt >= call.startedAt ? ` ${formatDurationMs(call.endedAt - call.startedAt)}` : ""}${call.resultSummary ? ` \u2014 ${call.resultSummary.slice(0, 200)}` : ""}`
|
|
75913
|
+
).join("\n")}`
|
|
75914
|
+
);
|
|
75915
|
+
}
|
|
75916
|
+
return parts.filter(Boolean).join("\n").slice(0, MAX_DRILL_CHARS);
|
|
75917
|
+
}
|
|
75918
|
+
function buildRuntimeSummaryRows(snapshot) {
|
|
75919
|
+
const summary = snapshot.runtimeSummary;
|
|
75920
|
+
if (!summary) {
|
|
75921
|
+
return [{ id: "runtime:none", label: "no runtime summary recorded yet", estTokens: 0 }];
|
|
75922
|
+
}
|
|
75923
|
+
const entries = [
|
|
75924
|
+
["tool results", summary.toolResults, "completed tool calls (recent turns)"],
|
|
75925
|
+
["tool errors", summary.toolErrors, "failed tool calls (recent turns)"],
|
|
75926
|
+
["retries", summary.retryEvents, "provider/overflow retries"],
|
|
75927
|
+
["auto-compactions", summary.autoCompactionEvents, "context checkpoints this session"],
|
|
75928
|
+
["runtime guard events", summary.runtimeGuardEvents, "guard advisories triggered"],
|
|
75929
|
+
["queued turn events", summary.queuedTurnEvents, "steer/followUp queue dispatches"],
|
|
75930
|
+
["subagent events", summary.subagentEvents, "subagent lifecycle events"]
|
|
75931
|
+
];
|
|
75932
|
+
return entries.map(([label, count, detail]) => ({
|
|
75933
|
+
id: `runtime:${label}`,
|
|
75934
|
+
label,
|
|
75935
|
+
estTokens: count,
|
|
75936
|
+
valueText: String(count),
|
|
75937
|
+
note: count > 0 ? void 0 : "none",
|
|
75938
|
+
detail
|
|
75939
|
+
}));
|
|
75940
|
+
}
|
|
75941
|
+
function buildSubagentRows(snapshot) {
|
|
75942
|
+
const summaries = snapshot.subagentSummaries ?? [];
|
|
75943
|
+
if (summaries.length === 0) {
|
|
75944
|
+
return [{ id: "subagents:none", label: "no subagent tasks recorded yet", estTokens: 0 }];
|
|
75945
|
+
}
|
|
75946
|
+
return summaries.map((sub, index) => ({
|
|
75947
|
+
id: `subagent:${sub.toolCallId ?? index}`,
|
|
75948
|
+
label: sub.name,
|
|
75949
|
+
estTokens: 0,
|
|
75950
|
+
valueText: sub.status,
|
|
75951
|
+
note: sub.modelId ? `${sub.modelClass ? `${sub.modelClass}/` : ""}${sub.modelId}` : void 0,
|
|
75952
|
+
detail: [
|
|
75953
|
+
sub.evidenceCount > 0 ? `${sub.evidenceCount} evidence` : "",
|
|
75954
|
+
sub.failureReason ? `failed: ${sub.failureReason}` : "",
|
|
75955
|
+
sub.modelFallbackReason ? `fallback: ${sub.modelFallbackReason}` : ""
|
|
75956
|
+
].filter(Boolean).join(" \xB7 ") || void 0,
|
|
75957
|
+
marker: sub.status === "failed" || sub.failureReason ? "\u2716" : void 0,
|
|
75958
|
+
drill: {
|
|
75959
|
+
kind: "text",
|
|
75960
|
+
title: `Subagent \xB7 ${sub.name}`,
|
|
75961
|
+
text: safeStringify(sub).slice(0, MAX_DRILL_CHARS)
|
|
75962
|
+
}
|
|
75963
|
+
}));
|
|
75964
|
+
}
|
|
75965
|
+
function buildTraceSections(snapshot) {
|
|
75966
|
+
const turns = [...snapshot.recentTurns];
|
|
75967
|
+
if (snapshot.activeTurn) turns.push(snapshot.activeTurn);
|
|
75968
|
+
const timeline = snapshot.recentTimeline ?? [];
|
|
75969
|
+
return [
|
|
75970
|
+
{
|
|
75971
|
+
id: "trace-timeline",
|
|
75972
|
+
title: `Timeline (${timeline.length})`,
|
|
75973
|
+
estTokens: 0,
|
|
75974
|
+
rows: buildTimelineRows(timeline)
|
|
75975
|
+
},
|
|
75976
|
+
{
|
|
75977
|
+
id: "trace-tools",
|
|
75978
|
+
title: "Tool stats (recent turns)",
|
|
75979
|
+
estTokens: 0,
|
|
75980
|
+
note: aggregateToolStats(turns)[0] ? `slowest: ${aggregateToolStats(turns)[0].name} ${formatDurationMs(aggregateToolStats(turns)[0].totalMs)}` : void 0,
|
|
75981
|
+
rows: buildToolStatRows(turns)
|
|
75982
|
+
},
|
|
75983
|
+
{
|
|
75984
|
+
id: "trace-turns",
|
|
75985
|
+
title: `Recent turns (${snapshot.recentTurns.length}${snapshot.activeTurn ? " +1 active" : ""})`,
|
|
75986
|
+
estTokens: 0,
|
|
75987
|
+
rows: buildTurnRows(
|
|
75988
|
+
snapshot.activeTurn ? [...snapshot.recentTurns, snapshot.activeTurn] : snapshot.recentTurns
|
|
75989
|
+
)
|
|
75990
|
+
},
|
|
75991
|
+
{
|
|
75992
|
+
id: "trace-runtime",
|
|
75993
|
+
title: "Runtime summary",
|
|
75994
|
+
estTokens: 0,
|
|
75995
|
+
rows: buildRuntimeSummaryRows(snapshot)
|
|
75996
|
+
},
|
|
75997
|
+
{
|
|
75998
|
+
id: "trace-subagents",
|
|
75999
|
+
title: `Subagents (${(snapshot.subagentSummaries ?? []).length})`,
|
|
76000
|
+
estTokens: 0,
|
|
76001
|
+
rows: buildSubagentRows(snapshot)
|
|
76002
|
+
}
|
|
76003
|
+
];
|
|
76004
|
+
}
|
|
76005
|
+
function buildTraceOverviewText(snapshot, theme2) {
|
|
76006
|
+
const t = theme2 ?? { bold: (s) => s, fg: (_k, s) => s };
|
|
76007
|
+
const lines = [];
|
|
76008
|
+
const turns = snapshot.recentTurns.length + (snapshot.activeTurn ? 1 : 0);
|
|
76009
|
+
const timeline = snapshot.recentTimeline ?? [];
|
|
76010
|
+
lines.push(t.bold("Session Trace") + t.fg("dim", ` \xB7 ${turns} recent turns \xB7 ${timeline.length} events`));
|
|
76011
|
+
const summary = snapshot.runtimeSummary;
|
|
76012
|
+
if (summary) {
|
|
76013
|
+
const notable = [];
|
|
76014
|
+
if (summary.retryEvents > 0) notable.push(`retries ${summary.retryEvents}`);
|
|
76015
|
+
if (summary.autoCompactionEvents > 0) notable.push(`compactions ${summary.autoCompactionEvents}`);
|
|
76016
|
+
if (summary.runtimeGuardEvents > 0) notable.push(`guard ${summary.runtimeGuardEvents}`);
|
|
76017
|
+
if (summary.toolErrors > 0) notable.push(`tool errors ${summary.toolErrors}`);
|
|
76018
|
+
if (notable.length > 0) {
|
|
76019
|
+
lines.push(t.fg("dim", ` events: ${notable.join(" \xB7 ")}`));
|
|
76020
|
+
} else {
|
|
76021
|
+
lines.push(t.fg("dim", " no retries, compactions, or guard events"));
|
|
76022
|
+
}
|
|
76023
|
+
}
|
|
76024
|
+
const stats = aggregateToolStats([...snapshot.recentTurns, ...snapshot.activeTurn ? [snapshot.activeTurn] : []]);
|
|
76025
|
+
if (stats.length > 0) {
|
|
76026
|
+
const top = stats.slice(0, 3).map((s) => `${s.name} ${formatDurationMs(s.totalMs)} (${s.calls})`);
|
|
76027
|
+
lines.push(t.fg("dim", ` tools: ${top.join(" \xB7 ")}`));
|
|
76028
|
+
}
|
|
76029
|
+
lines.push(t.fg("dim", " /debugs/trace \xB7 Enter to drill, Esc to go back"));
|
|
76030
|
+
return lines.join("\n");
|
|
76031
|
+
}
|
|
76032
|
+
|
|
76033
|
+
// src/commands/interactive-trace-command.ts
|
|
76034
|
+
function handleTraceCommand(host, snapshot) {
|
|
76035
|
+
if (!snapshot) {
|
|
76036
|
+
host.showStatus("No session trace yet \u2014 it starts with the first turn");
|
|
76037
|
+
return;
|
|
76038
|
+
}
|
|
76039
|
+
const sections = buildTraceSections(snapshot);
|
|
76040
|
+
host.chatContainer.addChild(new Spacer(1));
|
|
76041
|
+
host.chatContainer.addChild(new Text(buildTraceOverviewText(snapshot, theme), 1, 0));
|
|
76042
|
+
host.ui.requestRender();
|
|
76043
|
+
host.showSelector((done) => {
|
|
76044
|
+
const selector = new ContextReportSelectorComponent({
|
|
76045
|
+
title: "Session Trace",
|
|
76046
|
+
sections,
|
|
76047
|
+
terminalHeight: host.ui.terminal.rows,
|
|
76048
|
+
onDone: done
|
|
76049
|
+
});
|
|
76050
|
+
return { component: selector, focus: selector };
|
|
76051
|
+
});
|
|
76052
|
+
}
|
|
76053
|
+
|
|
76054
|
+
// src/core/boot-report.ts
|
|
76055
|
+
function stepToText(step) {
|
|
76056
|
+
const lines = [
|
|
76057
|
+
`# ${step.id}`,
|
|
76058
|
+
`input: ${step.inputSummary}`,
|
|
76059
|
+
`output: ${step.outputSummary}`
|
|
76060
|
+
];
|
|
76061
|
+
if (step.toolCount !== void 0) lines.push(`tools: ${step.toolCount}`);
|
|
76062
|
+
if (step.policyDecisions?.length) {
|
|
76063
|
+
lines.push("", "# policy decisions", ...step.policyDecisions.map((decision) => `- ${decision}`));
|
|
76064
|
+
}
|
|
76065
|
+
if (step.extensionWrapping) {
|
|
76066
|
+
lines.push(
|
|
76067
|
+
"",
|
|
76068
|
+
"# extension wrapping",
|
|
76069
|
+
`extensions: ${step.extensionWrapping.extensionCount}`,
|
|
76070
|
+
`extension tools: ${step.extensionWrapping.extensionToolCount}`,
|
|
76071
|
+
`wrapped tools: ${step.extensionWrapping.wrappedToolCount}`
|
|
76072
|
+
);
|
|
76073
|
+
}
|
|
76074
|
+
return lines.join("\n");
|
|
76075
|
+
}
|
|
76076
|
+
function buildBootRows(trace) {
|
|
76077
|
+
if (trace.steps.length === 0) {
|
|
76078
|
+
return [{ id: "boot:none", label: "no composition steps recorded", estTokens: 0 }];
|
|
76079
|
+
}
|
|
76080
|
+
return trace.steps.map((step, index) => ({
|
|
76081
|
+
id: `boot:${step.id}`,
|
|
76082
|
+
label: `${index + 1}. ${step.id}`,
|
|
76083
|
+
estTokens: 0,
|
|
76084
|
+
note: step.toolCount !== void 0 ? `${step.toolCount} tools` : void 0,
|
|
76085
|
+
detail: step.outputSummary,
|
|
76086
|
+
drill: {
|
|
76087
|
+
kind: "text",
|
|
76088
|
+
title: `Step \xB7 ${step.id}`,
|
|
76089
|
+
text: stepToText(step)
|
|
76090
|
+
}
|
|
76091
|
+
}));
|
|
76092
|
+
}
|
|
76093
|
+
function buildBootSections(trace) {
|
|
76094
|
+
return [
|
|
76095
|
+
{
|
|
76096
|
+
id: "boot-pipeline",
|
|
76097
|
+
title: `Composition pipeline (${trace.steps.length} steps)`,
|
|
76098
|
+
estTokens: 0,
|
|
76099
|
+
rows: buildBootRows(trace)
|
|
76100
|
+
}
|
|
76101
|
+
];
|
|
76102
|
+
}
|
|
76103
|
+
function buildBootOverviewText(trace, theme2) {
|
|
76104
|
+
const t = theme2 ?? { bold: (s) => s, fg: (_k, s) => s };
|
|
76105
|
+
const lines = [];
|
|
76106
|
+
lines.push(t.bold("Boot Composition") + t.fg("dim", ` \xB7 ${trace.steps.length} steps`));
|
|
76107
|
+
for (const step of trace.steps) {
|
|
76108
|
+
lines.push(t.fg("dim", ` ${step.id} \u2014 ${step.outputSummary}`));
|
|
76109
|
+
}
|
|
76110
|
+
lines.push(t.fg("dim", " /debugs/boot \xB7 Enter to drill into a step"));
|
|
76111
|
+
return lines.join("\n");
|
|
76112
|
+
}
|
|
76113
|
+
|
|
76114
|
+
// src/commands/interactive-boot-command.ts
|
|
76115
|
+
function handleBootCommand(host) {
|
|
76116
|
+
const trace = host.options.compositionTrace;
|
|
76117
|
+
if (!trace || trace.steps.length === 0) {
|
|
76118
|
+
host.showStatus("No composition trace available for this runtime");
|
|
76119
|
+
return;
|
|
76120
|
+
}
|
|
76121
|
+
const sections = buildBootSections(trace);
|
|
76122
|
+
host.chatContainer.addChild(new Spacer(1));
|
|
76123
|
+
host.chatContainer.addChild(new Text(buildBootOverviewText(trace, theme), 1, 0));
|
|
76124
|
+
host.ui.requestRender();
|
|
76125
|
+
host.showSelector((done) => {
|
|
76126
|
+
const selector = new ContextReportSelectorComponent({
|
|
76127
|
+
title: "Boot Composition",
|
|
76128
|
+
sections,
|
|
76129
|
+
terminalHeight: host.ui.terminal.rows,
|
|
76130
|
+
onDone: done
|
|
76131
|
+
});
|
|
76132
|
+
return { component: selector, focus: selector };
|
|
76133
|
+
});
|
|
76134
|
+
}
|
|
76135
|
+
|
|
74656
76136
|
// src/commands/interactive-command-handlers.ts
|
|
74657
76137
|
function showSettingsSelector(host, focusItem) {
|
|
74658
76138
|
host.showSelector((done) => {
|
|
@@ -75077,6 +76557,7 @@ async function handleClearCommand(host) {
|
|
|
75077
76557
|
contextPercent: contextWindow > 0 && contextUsage.tokens !== null ? contextUsage.tokens / contextWindow * 100 : 0,
|
|
75078
76558
|
contextWindow
|
|
75079
76559
|
});
|
|
76560
|
+
applyContextSignalsWithTrace(host);
|
|
75080
76561
|
host.updateTerminalTitle();
|
|
75081
76562
|
host.chatContainer.clear();
|
|
75082
76563
|
host.streamingComponent = void 0;
|
|
@@ -75123,6 +76604,7 @@ function handleSessionCommand(host) {
|
|
|
75123
76604
|
homeDir: process.env.HOME || process.env.USERPROFILE || "",
|
|
75124
76605
|
modelId: host.options.model?.id,
|
|
75125
76606
|
thinkingLevel: host.thinkingLevel,
|
|
76607
|
+
messages: host.sessionManager.getMessages(),
|
|
75126
76608
|
theme
|
|
75127
76609
|
});
|
|
75128
76610
|
host.chatContainer.addChild(new Spacer(1));
|
|
@@ -75164,7 +76646,10 @@ function createExtensionContextForCommands(host) {
|
|
|
75164
76646
|
console.error(`[Extension] Tools restricted to: ${tools.join(", ")}`);
|
|
75165
76647
|
}
|
|
75166
76648
|
},
|
|
75167
|
-
getActiveTools: () =>
|
|
76649
|
+
getActiveTools: () => {
|
|
76650
|
+
const tools = host.agent.state.tools;
|
|
76651
|
+
return (host.planModeEnabled ? tools.filter((tool) => isToolAllowedInPlanMode(tool)) : tools).map((tool) => tool.name);
|
|
76652
|
+
},
|
|
75168
76653
|
sendUserMessage: (content) => {
|
|
75169
76654
|
if (host.editor.onSubmit) {
|
|
75170
76655
|
void host.editor.onSubmit(content);
|
|
@@ -75356,12 +76841,16 @@ function registerBuiltinCommands(host) {
|
|
|
75356
76841
|
handler: () => host.handleCacheTest()
|
|
75357
76842
|
});
|
|
75358
76843
|
commandTree.register(["debugs", "context"], {
|
|
75359
|
-
description: "
|
|
75360
|
-
handler: () => host.
|
|
76844
|
+
description: "Context composition report: sections, tokens, drill-down",
|
|
76845
|
+
handler: () => host.handleDebugReportCommand("context")
|
|
76846
|
+
});
|
|
76847
|
+
commandTree.register(["debugs", "trace"], {
|
|
76848
|
+
description: "Session trace: timeline, tool stats, runtime events",
|
|
76849
|
+
handler: () => host.handleDebugReportCommand("trace")
|
|
75361
76850
|
});
|
|
75362
|
-
commandTree.register(["debugs", "
|
|
75363
|
-
description: "
|
|
75364
|
-
handler: () => host.
|
|
76851
|
+
commandTree.register(["debugs", "boot"], {
|
|
76852
|
+
description: "Boot composition pipeline: how the runtime was assembled",
|
|
76853
|
+
handler: () => host.handleDebugReportCommand("boot")
|
|
75365
76854
|
});
|
|
75366
76855
|
commandTree.register(["settings", "quit"], {
|
|
75367
76856
|
description: "Exit Pie",
|
|
@@ -75372,6 +76861,36 @@ function registerBuiltinCommands(host) {
|
|
|
75372
76861
|
});
|
|
75373
76862
|
}
|
|
75374
76863
|
|
|
76864
|
+
// src/runtime/compaction-diff.ts
|
|
76865
|
+
function summarizeActiveContext(summaries) {
|
|
76866
|
+
let tokens = 0;
|
|
76867
|
+
for (const summary of summaries) {
|
|
76868
|
+
tokens += summary.estTokens;
|
|
76869
|
+
}
|
|
76870
|
+
return { count: summaries.length, tokens };
|
|
76871
|
+
}
|
|
76872
|
+
function formatCompactionTokenLine(stats) {
|
|
76873
|
+
const saved = Math.max(0, stats.before.tokens - stats.after.tokens);
|
|
76874
|
+
const percent = stats.before.tokens > 0 ? Math.round(saved / stats.before.tokens * 100) : 0;
|
|
76875
|
+
return `~${formatReportTokens(stats.before.tokens)} \u2192 ~${formatReportTokens(stats.after.tokens)} tokens (saved ~${formatReportTokens(saved)}, \u2212${percent}%)`;
|
|
76876
|
+
}
|
|
76877
|
+
function renderCompactionDiffPanel(target, stats) {
|
|
76878
|
+
const archived = Math.max(0, stats.before.count - stats.after.count);
|
|
76879
|
+
target.chatContainer.addChild(new Spacer(1));
|
|
76880
|
+
target.chatContainer.addChild(new Text(theme.fg("accent", "\u2691 Context checkpoint"), 1, 0));
|
|
76881
|
+
target.chatContainer.addChild(
|
|
76882
|
+
new Text(
|
|
76883
|
+
theme.fg(
|
|
76884
|
+
"dim",
|
|
76885
|
+
` kept ${stats.after.count} entries \xB7 archived ${archived} entries \xB7 ${formatCompactionTokenLine(stats)}`
|
|
76886
|
+
),
|
|
76887
|
+
1,
|
|
76888
|
+
0
|
|
76889
|
+
)
|
|
76890
|
+
);
|
|
76891
|
+
target.safeRequestRender();
|
|
76892
|
+
}
|
|
76893
|
+
|
|
75375
76894
|
// src/commands/interactive-compact-command.ts
|
|
75376
76895
|
async function handleCompactCommand(host) {
|
|
75377
76896
|
if (host.submitLock || host.isProcessing || host.isCompacting) {
|
|
@@ -75390,6 +76909,7 @@ async function handleCompactCommand(host) {
|
|
|
75390
76909
|
host.chatContainer.addChild(new Spacer(1));
|
|
75391
76910
|
host.chatContainer.addChild(new Text(theme.fg("dim", "[/sessions/compact]"), 1, 0));
|
|
75392
76911
|
host.safeRequestRender();
|
|
76912
|
+
const beforeStats = summarizeActiveContext(host.sessionManager.getActiveContextSummaries());
|
|
75393
76913
|
try {
|
|
75394
76914
|
const activeEntryId = host.sessionManager.getActiveEntryId();
|
|
75395
76915
|
if (!activeEntryId) {
|
|
@@ -75426,14 +76946,17 @@ async function handleCompactCommand(host) {
|
|
|
75426
76946
|
const compactedMessages = host.sessionManager.getMessages();
|
|
75427
76947
|
host.replaceAgentMessagesAndMarkSynced(compactedMessages);
|
|
75428
76948
|
host.resetFileObservationState();
|
|
76949
|
+
host.resetRuntimeModeBlocks?.();
|
|
75429
76950
|
host.streamingComponent = void 0;
|
|
75430
76951
|
host.pendingTools.clear();
|
|
75431
76952
|
host.chatContainer.clear();
|
|
75432
76953
|
host.lastStatusSpacer = void 0;
|
|
75433
76954
|
host.lastStatusText = void 0;
|
|
75434
76955
|
host.renderMessageHistory(compactedMessages);
|
|
75435
|
-
host
|
|
75436
|
-
|
|
76956
|
+
renderCompactionDiffPanel(host, {
|
|
76957
|
+
before: beforeStats,
|
|
76958
|
+
after: summarizeActiveContext(host.sessionManager.getActiveContextSummaries())
|
|
76959
|
+
});
|
|
75437
76960
|
const contextUsage = host.calculateContextUsage();
|
|
75438
76961
|
const contextWindow = host.options.model?.contextWindow ?? 0;
|
|
75439
76962
|
const contextPercent = contextWindow > 0 && contextUsage.tokens !== null ? contextUsage.tokens / contextWindow * 100 : 0;
|
|
@@ -75448,6 +76971,7 @@ async function handleCompactCommand(host) {
|
|
|
75448
76971
|
contextPercent,
|
|
75449
76972
|
contextWindow
|
|
75450
76973
|
});
|
|
76974
|
+
applyContextSignalsWithTrace(host);
|
|
75451
76975
|
await host.sessionManager.save();
|
|
75452
76976
|
host.safeRequestRender();
|
|
75453
76977
|
} catch (error) {
|
|
@@ -77566,8 +79090,12 @@ function queueMessage(host, text, mode, options = {}) {
|
|
|
77566
79090
|
}
|
|
77567
79091
|
const clearEditor = options.clearEditor ?? true;
|
|
77568
79092
|
host.sessionTrace.notePendingUserText(text);
|
|
79093
|
+
const runtimeBlock = host.runtimeModeBlockForNextMessage?.();
|
|
79094
|
+
const content = runtimeBlock ? `${runtimeBlock}
|
|
79095
|
+
|
|
79096
|
+
${text}` : text;
|
|
77569
79097
|
void host.agentSessionController.prompt(
|
|
77570
|
-
{ role: "user", content
|
|
79098
|
+
{ role: "user", content, timestamp: Date.now() },
|
|
77571
79099
|
{
|
|
77572
79100
|
source: "interactive",
|
|
77573
79101
|
streamingBehavior: mode,
|
|
@@ -77824,6 +79352,14 @@ var FooterComponent = class {
|
|
|
77824
79352
|
if (state.cacheRead) statsParts.push(`R${formatTokens(state.cacheRead)}`);
|
|
77825
79353
|
if (state.cacheWrite) statsParts.push(`W${formatTokens(state.cacheWrite)}`);
|
|
77826
79354
|
if (state.cost) statsParts.push(`$${state.cost.toFixed(3)}`);
|
|
79355
|
+
if (state.cacheHitRate != null) {
|
|
79356
|
+
statsParts.push(theme.fg("dim", `ca ${(state.cacheHitRate * 100).toFixed(0)}%`));
|
|
79357
|
+
}
|
|
79358
|
+
if (state.prefixHash) {
|
|
79359
|
+
statsParts.push(
|
|
79360
|
+
state.prefixHashChanged ? theme.fg("warning", `\u26A1${state.prefixHash}`) : theme.fg("dim", `\u2301${state.prefixHash}`)
|
|
79361
|
+
);
|
|
79362
|
+
}
|
|
77827
79363
|
if (state.contextWindow) {
|
|
77828
79364
|
const autoIndicator = this.autoCompactEnabled ? " (auto)" : "";
|
|
77829
79365
|
const percent = state.contextPercent ?? 0;
|
|
@@ -77896,27 +79432,13 @@ var FooterComponent = class {
|
|
|
77896
79432
|
// src/components/todo-widget.ts
|
|
77897
79433
|
var TodoWidgetComponent = class extends Container {
|
|
77898
79434
|
state;
|
|
77899
|
-
calmMode = false;
|
|
77900
79435
|
constructor(state) {
|
|
77901
79436
|
super();
|
|
77902
79437
|
this.state = state;
|
|
77903
79438
|
void this.refresh();
|
|
77904
79439
|
}
|
|
77905
|
-
/** Calm mode hides the progress widget (questions/answers only). */
|
|
77906
|
-
setCalmMode(calm) {
|
|
77907
|
-
if (this.calmMode === calm) return;
|
|
77908
|
-
this.calmMode = calm;
|
|
77909
|
-
if (calm) {
|
|
77910
|
-
this.clear();
|
|
77911
|
-
} else {
|
|
77912
|
-
void this.refresh();
|
|
77913
|
-
}
|
|
77914
|
-
}
|
|
77915
79440
|
async refresh() {
|
|
77916
79441
|
this.clear();
|
|
77917
|
-
if (this.calmMode) {
|
|
77918
|
-
return;
|
|
77919
|
-
}
|
|
77920
79442
|
const lines = renderExecutionWidgetLines(this.state.getWidgetSteps());
|
|
77921
79443
|
if (lines.length === 0) {
|
|
77922
79444
|
return;
|
|
@@ -78907,6 +80429,7 @@ function createInteractiveAgentSessionController(host) {
|
|
|
78907
80429
|
}
|
|
78908
80430
|
let retryElapsedTicker;
|
|
78909
80431
|
let retryElapsedStartedAt = 0;
|
|
80432
|
+
let autoCompactBeforeStats = null;
|
|
78910
80433
|
const attention = cliAttention(host);
|
|
78911
80434
|
const stopRetryElapsedTicker = () => {
|
|
78912
80435
|
if (retryElapsedTicker !== void 0) {
|
|
@@ -78972,6 +80495,7 @@ function createInteractiveAgentSessionController(host) {
|
|
|
78972
80495
|
if (!firstKeptEntryId) return { aborted: true };
|
|
78973
80496
|
return { summary: beforeCompact.summary, firstKeptEntryId };
|
|
78974
80497
|
}
|
|
80498
|
+
autoCompactBeforeStats = summarizeActiveContext(context.sessionManager.getActiveContextSummaries());
|
|
78975
80499
|
return createCliAutoCompactionResult({
|
|
78976
80500
|
context,
|
|
78977
80501
|
model: host.options.model,
|
|
@@ -79140,9 +80664,11 @@ function createInteractiveAgentSessionController(host) {
|
|
|
79140
80664
|
host.showError(`${prefix}: ${event.errorMessage}`);
|
|
79141
80665
|
host.footer.setState({ status: "ready" });
|
|
79142
80666
|
host.setControllerBusy(false);
|
|
80667
|
+
autoCompactBeforeStats = null;
|
|
79143
80668
|
return;
|
|
79144
80669
|
}
|
|
79145
80670
|
host.resetFileObservationState();
|
|
80671
|
+
host.resetRuntimeModeBlocks?.();
|
|
79146
80672
|
if (!event.result?.aborted) {
|
|
79147
80673
|
host.streamingComponent = void 0;
|
|
79148
80674
|
host.pendingTools.clear();
|
|
@@ -79165,10 +80691,20 @@ function createInteractiveAgentSessionController(host) {
|
|
|
79165
80691
|
contextPercent,
|
|
79166
80692
|
contextWindow
|
|
79167
80693
|
});
|
|
80694
|
+
applyContextSignalsWithTrace(host);
|
|
79168
80695
|
host.safeRequestRender();
|
|
79169
|
-
if (!event.
|
|
79170
|
-
|
|
80696
|
+
if (!event.result?.aborted) {
|
|
80697
|
+
if (autoCompactBeforeStats !== null) {
|
|
80698
|
+
renderCompactionDiffPanel(host, {
|
|
80699
|
+
before: autoCompactBeforeStats,
|
|
80700
|
+
after: summarizeActiveContext(host.sessionManager.getActiveContextSummaries())
|
|
80701
|
+
});
|
|
80702
|
+
}
|
|
80703
|
+
if (!event.willRetry) {
|
|
80704
|
+
host.showStatus("Context auto-compacted");
|
|
80705
|
+
}
|
|
79171
80706
|
}
|
|
80707
|
+
autoCompactBeforeStats = null;
|
|
79172
80708
|
} else if (event.type === "auto_continue_scheduled") {
|
|
79173
80709
|
host.setControllerBusy(true);
|
|
79174
80710
|
if (event.reason === "todo_closure") {
|
|
@@ -79184,94 +80720,80 @@ function createInteractiveAgentSessionController(host) {
|
|
|
79184
80720
|
}
|
|
79185
80721
|
|
|
79186
80722
|
// src/runtime/runtime-mode-context.ts
|
|
79187
|
-
|
|
79188
|
-
|
|
79189
|
-
var STALE_SYSTEM_REMINDER_RE = /<system-reminder>\s*# Plan Mode[\s\S]*?<\/system-reminder>\s*/gi;
|
|
79190
|
-
var STALE_RUNTIME_CONTEXT_RE = /<runtime-mode-context>[\s\S]*?<\/runtime-mode-context>\s*/gi;
|
|
79191
|
-
function isRecord3(value) {
|
|
79192
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
80723
|
+
function isAgentMessage(value) {
|
|
80724
|
+
return !!value && typeof value === "object" && "role" in value;
|
|
79193
80725
|
}
|
|
79194
|
-
function
|
|
79195
|
-
|
|
79196
|
-
|
|
79197
|
-
|
|
79198
|
-
|
|
79199
|
-
|
|
79200
|
-
const withoutPlanReminder = withoutRuntime.replace(STALE_SYSTEM_REMINDER_RE, () => {
|
|
79201
|
-
stripped++;
|
|
79202
|
-
return "";
|
|
79203
|
-
});
|
|
79204
|
-
return { text: withoutPlanReminder, stripped };
|
|
79205
|
-
}
|
|
79206
|
-
function stripUserMessage(message) {
|
|
79207
|
-
if (!isRecord3(message) || message.role !== "user") {
|
|
79208
|
-
return { message, stripped: 0 };
|
|
80726
|
+
function prependRuntimeModeBlockToPrompt(input, block) {
|
|
80727
|
+
if (!block) return input;
|
|
80728
|
+
if (typeof input === "string") {
|
|
80729
|
+
return input.trim() ? `${block}
|
|
80730
|
+
|
|
80731
|
+
${input}` : block;
|
|
79209
80732
|
}
|
|
79210
|
-
|
|
79211
|
-
|
|
79212
|
-
|
|
79213
|
-
|
|
79214
|
-
return {
|
|
79215
|
-
message: {
|
|
79216
|
-
...message,
|
|
79217
|
-
content: cleaned.text
|
|
79218
|
-
},
|
|
79219
|
-
stripped: cleaned.stripped
|
|
79220
|
-
};
|
|
80733
|
+
if (Array.isArray(input)) {
|
|
80734
|
+
if (input.length > 0 && isAgentMessage(input[0])) {
|
|
80735
|
+
return prependBlockToMessages(input, block);
|
|
80736
|
+
}
|
|
80737
|
+
return [{ type: "text", text: block }, ...input];
|
|
79221
80738
|
}
|
|
79222
|
-
if (
|
|
79223
|
-
return
|
|
79224
|
-
}
|
|
79225
|
-
|
|
79226
|
-
const nextContent = content.map((block) => {
|
|
79227
|
-
if (!isRecord3(block) || block.type !== "text" || typeof block.text !== "string") {
|
|
79228
|
-
return block;
|
|
79229
|
-
}
|
|
79230
|
-
const cleaned = cleanText(block.text);
|
|
79231
|
-
stripped += cleaned.stripped;
|
|
79232
|
-
return { ...block, text: cleaned.text };
|
|
79233
|
-
}).filter((block) => !(isRecord3(block) && block.type === "text" && String(block.text ?? "").length === 0));
|
|
79234
|
-
if (stripped === 0) return { message, stripped: 0 };
|
|
79235
|
-
return {
|
|
79236
|
-
message: {
|
|
79237
|
-
...message,
|
|
79238
|
-
content: nextContent
|
|
79239
|
-
},
|
|
79240
|
-
stripped
|
|
79241
|
-
};
|
|
80739
|
+
if (isAgentMessage(input)) {
|
|
80740
|
+
return prependBlockToMessages([input], block)[0];
|
|
80741
|
+
}
|
|
80742
|
+
return [{ type: "text", text: block }, ...input];
|
|
79242
80743
|
}
|
|
79243
|
-
function
|
|
79244
|
-
|
|
79245
|
-
|
|
79246
|
-
for (
|
|
79247
|
-
|
|
79248
|
-
|
|
79249
|
-
|
|
79250
|
-
const content = result.message.content;
|
|
79251
|
-
if (typeof content === "string" && content.trim().length === 0) {
|
|
79252
|
-
continue;
|
|
79253
|
-
}
|
|
79254
|
-
if (Array.isArray(content) && content.length === 0) {
|
|
79255
|
-
continue;
|
|
79256
|
-
}
|
|
80744
|
+
function prependBlockToMessages(messages, block) {
|
|
80745
|
+
const next = [...messages];
|
|
80746
|
+
let target = -1;
|
|
80747
|
+
for (let index = next.length - 1; index >= 0; index--) {
|
|
80748
|
+
if (next[index]?.role === "user") {
|
|
80749
|
+
target = index;
|
|
80750
|
+
break;
|
|
79257
80751
|
}
|
|
79258
|
-
nextMessages.push(result.message);
|
|
79259
80752
|
}
|
|
79260
|
-
|
|
80753
|
+
if (target < 0) {
|
|
80754
|
+
next.push({ role: "user", content: block, timestamp: Date.now() });
|
|
80755
|
+
return next;
|
|
80756
|
+
}
|
|
80757
|
+
const message = next[target];
|
|
80758
|
+
if (typeof message.content === "string") {
|
|
80759
|
+
next[target] = { ...message, content: `${block}
|
|
80760
|
+
|
|
80761
|
+
${message.content}` };
|
|
80762
|
+
} else if (Array.isArray(message.content)) {
|
|
80763
|
+
next[target] = { ...message, content: [{ type: "text", text: block }, ...message.content] };
|
|
80764
|
+
} else {
|
|
80765
|
+
next.splice(target, 0, { role: "user", content: block, timestamp: Date.now() });
|
|
80766
|
+
}
|
|
80767
|
+
return next;
|
|
79261
80768
|
}
|
|
80769
|
+
var RUNTIME_MODE_CONTEXT_MARKER = "<runtime-mode-context>";
|
|
80770
|
+
var RUNTIME_MODE_CONTEXT_END_MARKER = "</runtime-mode-context>";
|
|
79262
80771
|
function buildRuntimeModeContext(state) {
|
|
79263
80772
|
const lines = [
|
|
79264
80773
|
RUNTIME_MODE_CONTEXT_MARKER,
|
|
79265
|
-
"Current runtime mode:"
|
|
79266
|
-
|
|
80774
|
+
"Current runtime mode:"
|
|
80775
|
+
];
|
|
80776
|
+
if (state.planMode === "planning") {
|
|
80777
|
+
lines.push(
|
|
80778
|
+
"- Plan mode: active (workspace read-only; plan_scratch permits session-local temporary drafts; submit the finished plan by calling plan_submit with the ordered steps for user approval)."
|
|
80779
|
+
);
|
|
80780
|
+
if (state.planDisabledToolNames.length > 0) {
|
|
80781
|
+
lines.push(
|
|
80782
|
+
`- Disabled this turn by plan mode (calls are denied): ${state.planDisabledToolNames.join(", ")}. Do not call them while planning.`
|
|
80783
|
+
);
|
|
80784
|
+
}
|
|
80785
|
+
} else {
|
|
80786
|
+
lines.push("- Plan mode: off.");
|
|
80787
|
+
}
|
|
80788
|
+
lines.push(
|
|
79267
80789
|
`- YOLO mode: ${state.yoloMode ? "on (filesystem sandbox directory restrictions are disabled)" : "off (workspace/protected-path restrictions apply)"}.`,
|
|
79268
80790
|
`- Filesystem scope: ${state.filesystemScope === "all" ? "all local paths may be passed directly to file tools when permitted" : "workspace paths and configured safe roots only"}.`
|
|
79269
|
-
|
|
80791
|
+
);
|
|
79270
80792
|
if (state.pendingTransition) {
|
|
79271
80793
|
const transitionText = {
|
|
79272
80794
|
entered_yolo: "YOLO mode was just enabled for this turn.",
|
|
79273
80795
|
exited_yolo: "YOLO mode was just disabled; do not assume previous absolute-path access still applies.",
|
|
79274
|
-
entered_plan: "Plan mode was just enabled; analyze and plan without changing the workspace. Use plan_scratch for temporary drafts.",
|
|
80796
|
+
entered_plan: "Plan mode was just enabled; analyze and plan without changing the workspace. Use plan_scratch for temporary drafts, then submit the finished plan by calling plan_submit with the ordered steps for user approval.",
|
|
79275
80797
|
exited_plan: "Plan mode was just disabled; execution tools may be used when the task requires them."
|
|
79276
80798
|
};
|
|
79277
80799
|
lines.push(`- Transition: ${transitionText[state.pendingTransition]}`);
|
|
@@ -79285,46 +80807,108 @@ function buildRuntimeModeContext(state) {
|
|
|
79285
80807
|
lines.push(RUNTIME_MODE_CONTEXT_END_MARKER);
|
|
79286
80808
|
return lines.join("\n");
|
|
79287
80809
|
}
|
|
79288
|
-
function
|
|
79289
|
-
|
|
79290
|
-
|
|
79291
|
-
|
|
79292
|
-
|
|
79293
|
-
|
|
79294
|
-
|
|
79295
|
-
|
|
80810
|
+
function runtimeModeBlockKey(state) {
|
|
80811
|
+
return JSON.stringify({
|
|
80812
|
+
planMode: state.planMode,
|
|
80813
|
+
yoloMode: state.yoloMode,
|
|
80814
|
+
filesystemScope: state.filesystemScope,
|
|
80815
|
+
currentDate: state.currentDate ?? null,
|
|
80816
|
+
activeToolNames: state.activeToolNames,
|
|
80817
|
+
planDisabledToolNames: state.planDisabledToolNames
|
|
80818
|
+
});
|
|
79296
80819
|
}
|
|
79297
|
-
function
|
|
79298
|
-
|
|
79299
|
-
|
|
79300
|
-
content: buildRuntimeModeContext(state),
|
|
79301
|
-
timestamp: Date.now()
|
|
79302
|
-
};
|
|
79303
|
-
const latestUserIndex = findLatestUserIndex(messages);
|
|
79304
|
-
if (latestUserIndex < 0) {
|
|
79305
|
-
return [...messages, contextMessage];
|
|
79306
|
-
}
|
|
79307
|
-
return [
|
|
79308
|
-
...messages.slice(0, latestUserIndex),
|
|
79309
|
-
contextMessage,
|
|
79310
|
-
...messages.slice(latestUserIndex)
|
|
79311
|
-
];
|
|
80820
|
+
function shouldInjectRuntimeModeBlock(lastKey, state) {
|
|
80821
|
+
if (lastKey === null) return true;
|
|
80822
|
+
return runtimeModeBlockKey(state) !== lastKey;
|
|
79312
80823
|
}
|
|
79313
|
-
function
|
|
79314
|
-
return
|
|
79315
|
-
|
|
79316
|
-
|
|
79317
|
-
|
|
79318
|
-
|
|
79319
|
-
|
|
79320
|
-
|
|
79321
|
-
|
|
79322
|
-
|
|
79323
|
-
options.consumeTransition?.();
|
|
79324
|
-
}
|
|
79325
|
-
return nextMessages;
|
|
80824
|
+
function runtimeModeTraceData(state) {
|
|
80825
|
+
return {
|
|
80826
|
+
yoloMode: state.yoloMode,
|
|
80827
|
+
planMode: state.planMode,
|
|
80828
|
+
filesystemScope: state.filesystemScope,
|
|
80829
|
+
pendingTransition: state.pendingTransition,
|
|
80830
|
+
currentDate: state.currentDate,
|
|
80831
|
+
timeZone: state.timeZone,
|
|
80832
|
+
activeToolCount: state.activeToolNames.length,
|
|
80833
|
+
planDisabledToolCount: state.planDisabledToolNames.length
|
|
79326
80834
|
};
|
|
79327
80835
|
}
|
|
80836
|
+
function currentDateInZone(timeZone) {
|
|
80837
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
80838
|
+
year: "numeric",
|
|
80839
|
+
month: "2-digit",
|
|
80840
|
+
day: "2-digit",
|
|
80841
|
+
timeZone
|
|
80842
|
+
}).formatToParts(/* @__PURE__ */ new Date());
|
|
80843
|
+
const part = (type) => parts.find((p) => p.type === type)?.value ?? "00";
|
|
80844
|
+
return `${part("year")}-${part("month")}-${part("day")}`;
|
|
80845
|
+
}
|
|
80846
|
+
var RUNTIME_MODE_BLOCK_PATTERN = /^[\t ]*<runtime-mode-context>[\s\S]*?<\/runtime-mode-context>[\t ]*(?:\r?\n){0,2}/;
|
|
80847
|
+
function refreshRuntimeModeBlockOnLastUserMessage(messages, block) {
|
|
80848
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
80849
|
+
const message = messages[i];
|
|
80850
|
+
if (message?.role !== "user") continue;
|
|
80851
|
+
const content = typeof message.content === "string" ? message.content : "";
|
|
80852
|
+
const stripped = content.replace(RUNTIME_MODE_BLOCK_PATTERN, "");
|
|
80853
|
+
const refreshed = stripped === content && content.includes("<runtime-mode-context>") ? content : `${block}
|
|
80854
|
+
|
|
80855
|
+
${stripped}`;
|
|
80856
|
+
if (refreshed === content) return messages;
|
|
80857
|
+
const next = [...messages];
|
|
80858
|
+
next[i] = { ...message, content: refreshed };
|
|
80859
|
+
return next;
|
|
80860
|
+
}
|
|
80861
|
+
return messages;
|
|
80862
|
+
}
|
|
80863
|
+
var RuntimeModeBlockInjector = class {
|
|
80864
|
+
constructor(options) {
|
|
80865
|
+
this.options = options;
|
|
80866
|
+
}
|
|
80867
|
+
options;
|
|
80868
|
+
lastKey = null;
|
|
80869
|
+
pendingRetryRefresh = false;
|
|
80870
|
+
reset() {
|
|
80871
|
+
this.lastKey = null;
|
|
80872
|
+
this.pendingRetryRefresh = true;
|
|
80873
|
+
}
|
|
80874
|
+
/** Block to prepend to the next user message, or null when unchanged. */
|
|
80875
|
+
nextBlock() {
|
|
80876
|
+
const block = this.freshBlock();
|
|
80877
|
+
this.pendingRetryRefresh = false;
|
|
80878
|
+
return block;
|
|
80879
|
+
}
|
|
80880
|
+
/**
|
|
80881
|
+
* Latest block for a request that reuses existing history (overflow retry
|
|
80882
|
+
* after compaction, manual compaction continue): the last user message may
|
|
80883
|
+
* carry a stale or evicted block, so the request-level transform refreshes
|
|
80884
|
+
* it. Consumed once per reset; null when nothing is pending.
|
|
80885
|
+
*/
|
|
80886
|
+
consumeRetryRefreshBlock() {
|
|
80887
|
+
if (!this.pendingRetryRefresh) return null;
|
|
80888
|
+
this.pendingRetryRefresh = false;
|
|
80889
|
+
const state = this.options.getState();
|
|
80890
|
+
return buildRuntimeModeContext(state);
|
|
80891
|
+
}
|
|
80892
|
+
freshBlock() {
|
|
80893
|
+
const state = this.options.getState();
|
|
80894
|
+
if (!shouldInjectRuntimeModeBlock(this.lastKey, state)) return null;
|
|
80895
|
+
this.lastKey = runtimeModeBlockKey(state);
|
|
80896
|
+
if (state.pendingTransition) this.options.consumeTransition();
|
|
80897
|
+
this.options.noteTrace(state);
|
|
80898
|
+
return buildRuntimeModeContext(state);
|
|
80899
|
+
}
|
|
80900
|
+
};
|
|
80901
|
+
|
|
80902
|
+
// src/runtime/cache-retention.ts
|
|
80903
|
+
function createCacheRetentionStreamFn(configured) {
|
|
80904
|
+
const base = configured ?? ((model, context, options) => streamSimple(model, context, options));
|
|
80905
|
+
return (model, context, options) => base(model, context, {
|
|
80906
|
+
...options,
|
|
80907
|
+
// Default only: explicit none/short requests (tests, debug commands) win.
|
|
80908
|
+
// Note: cost estimates still price cache writes at the short-TTL rate.
|
|
80909
|
+
cacheRetention: model.api === "anthropic-messages" && options?.cacheRetention === void 0 ? "long" : options?.cacheRetention
|
|
80910
|
+
});
|
|
80911
|
+
}
|
|
79328
80912
|
|
|
79329
80913
|
// src/runtime/guard-advisory-context.ts
|
|
79330
80914
|
var GUARD_ADVISORY_MARKER = "<runtime-guard-advisory>";
|
|
@@ -79338,12 +80922,19 @@ function isMarkerOnlyUserMessage(message) {
|
|
|
79338
80922
|
function stripGuardAdvisories(messages) {
|
|
79339
80923
|
return messages.filter((message) => !isMarkerOnlyUserMessage(message));
|
|
79340
80924
|
}
|
|
79341
|
-
function
|
|
80925
|
+
function findLatestUserIndex(messages) {
|
|
79342
80926
|
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
79343
80927
|
if (messages[index].role === "user") return index;
|
|
79344
80928
|
}
|
|
79345
80929
|
return -1;
|
|
79346
80930
|
}
|
|
80931
|
+
function applyRuntimeRequestTransform(messages, options) {
|
|
80932
|
+
const advisory = options.takeAdvisory();
|
|
80933
|
+
let next = advisory ? injectGuardAdvisory(messages, advisory) : stripGuardAdvisories(messages);
|
|
80934
|
+
const retryBlock = options.takeRetryBlock();
|
|
80935
|
+
if (retryBlock) next = refreshRuntimeModeBlockOnLastUserMessage(next, retryBlock);
|
|
80936
|
+
return next;
|
|
80937
|
+
}
|
|
79347
80938
|
function injectGuardAdvisory(messages, guidance) {
|
|
79348
80939
|
const advisoryMessage = {
|
|
79349
80940
|
role: "user",
|
|
@@ -79352,7 +80943,7 @@ ${guidance}
|
|
|
79352
80943
|
${GUARD_ADVISORY_END_MARKER}`,
|
|
79353
80944
|
timestamp: Date.now()
|
|
79354
80945
|
};
|
|
79355
|
-
const latestUserIndex =
|
|
80946
|
+
const latestUserIndex = findLatestUserIndex(messages);
|
|
79356
80947
|
if (latestUserIndex < 0) {
|
|
79357
80948
|
return [...messages, advisoryMessage];
|
|
79358
80949
|
}
|
|
@@ -79363,11 +80954,6 @@ ${GUARD_ADVISORY_END_MARKER}`,
|
|
|
79363
80954
|
];
|
|
79364
80955
|
}
|
|
79365
80956
|
|
|
79366
|
-
// src/runtime/tool-policy.ts
|
|
79367
|
-
function selectToolsForRuntimeMode(tools, mode) {
|
|
79368
|
-
return selectToolsForRuntimePolicy(tools, mode);
|
|
79369
|
-
}
|
|
79370
|
-
|
|
79371
80957
|
// src/runtime/terminal-bell.ts
|
|
79372
80958
|
var BEL = "\x07";
|
|
79373
80959
|
var DEFAULT_MIN_INTERVAL_MS = 500;
|
|
@@ -79565,7 +81151,7 @@ function createInteractiveExtensionUIContext(host) {
|
|
|
79565
81151
|
}
|
|
79566
81152
|
};
|
|
79567
81153
|
return {
|
|
79568
|
-
notify: (message, type = "info") => showExtensionNotification(host, message, type),
|
|
81154
|
+
notify: (message, type = "info", opts) => showExtensionNotification(host, message, type, opts),
|
|
79569
81155
|
select: (title, options, opts) => interact(() => showExtensionSelector2(host, title, options, opts)),
|
|
79570
81156
|
confirm: async (title, message, opts) => await interact(() => showExtensionConfirm(host, title, message, opts)) === true,
|
|
79571
81157
|
input: (title, placeholder, opts) => interact(() => showExtensionInput(host, title, placeholder, opts)),
|
|
@@ -79713,10 +81299,14 @@ function installInteractiveInteractionHandler(host) {
|
|
|
79713
81299
|
}
|
|
79714
81300
|
});
|
|
79715
81301
|
}
|
|
79716
|
-
function showExtensionNotification(host, message, type = "info") {
|
|
81302
|
+
function showExtensionNotification(host, message, type = "info", opts) {
|
|
79717
81303
|
const prefix = type === "error" ? "Error: " : type === "warning" ? "Warning: " : "";
|
|
79718
81304
|
host.chatContainer.addChild(new Spacer(1));
|
|
79719
|
-
|
|
81305
|
+
if (opts?.markdown) {
|
|
81306
|
+
host.chatContainer.addChild(new Markdown(`${prefix}${message}`, 1, 0, getMarkdownTheme()));
|
|
81307
|
+
} else {
|
|
81308
|
+
host.chatContainer.addChild(new Text(theme.fg(type === "error" ? "error" : type === "warning" ? "warning" : "dim", `${prefix}${message}`), 1, 0));
|
|
81309
|
+
}
|
|
79720
81310
|
host.ui.requestRender();
|
|
79721
81311
|
}
|
|
79722
81312
|
function showExtensionSelector2(host, title, options, opts) {
|
|
@@ -80087,7 +81677,10 @@ async function loadInteractiveExtensions(host) {
|
|
|
80087
81677
|
console.error(`[Extension] Tools set to: ${toolNames.join(", ")}`);
|
|
80088
81678
|
}
|
|
80089
81679
|
},
|
|
80090
|
-
getActiveTools: () =>
|
|
81680
|
+
getActiveTools: () => {
|
|
81681
|
+
const tools = host.agent.state.tools;
|
|
81682
|
+
return (host.planModeEnabled ? tools.filter((tool) => isToolAllowedInPlanMode(tool)) : tools).map((tool) => tool.name);
|
|
81683
|
+
},
|
|
80091
81684
|
sendUserMessage: (content) => {
|
|
80092
81685
|
if (host.editor.onSubmit) {
|
|
80093
81686
|
void host.editor.onSubmit(content);
|
|
@@ -80177,7 +81770,8 @@ async function loadInteractiveExtensions(host) {
|
|
|
80177
81770
|
reload: () => host.reloadRuntime(),
|
|
80178
81771
|
get yoloMode() {
|
|
80179
81772
|
return host.yoloMode;
|
|
80180
|
-
}
|
|
81773
|
+
},
|
|
81774
|
+
setYoloMode: host.setYoloMode ? (enabled) => host.setYoloMode?.(enabled) : void 0
|
|
80181
81775
|
};
|
|
80182
81776
|
const contextActions = {
|
|
80183
81777
|
isIdle: () => !host.isProcessing,
|
|
@@ -80208,7 +81802,15 @@ async function loadInteractiveExtensions(host) {
|
|
|
80208
81802
|
console.error(`[Extension] Failed to load ${path34}: ${error}`);
|
|
80209
81803
|
}
|
|
80210
81804
|
}
|
|
80211
|
-
const
|
|
81805
|
+
const policyContext = () => ({
|
|
81806
|
+
mode: host.planModeEnabled ? "plan" : "normal",
|
|
81807
|
+
yoloMode: host.yoloMode,
|
|
81808
|
+
confirmationPolicy: "allow"
|
|
81809
|
+
});
|
|
81810
|
+
const extensionTools = filterEnabledTools(
|
|
81811
|
+
createPolicyEnforcedTools(convertExtensionTools(extensions), { getContext: policyContext }),
|
|
81812
|
+
host.options.settingsManager
|
|
81813
|
+
);
|
|
80212
81814
|
const activeTools = [...host.agent.state.tools, ...extensionTools];
|
|
80213
81815
|
host.agent.state.tools = wrapToolsWithExtensions(activeTools, host.extensionRunner);
|
|
80214
81816
|
const availableTools = [
|
|
@@ -80285,6 +81887,12 @@ var InteractiveMode = class {
|
|
|
80285
81887
|
pendingYoloModeTransition = null;
|
|
80286
81888
|
executionReminder = null;
|
|
80287
81889
|
pendingRuntimeGuardAdvisory = null;
|
|
81890
|
+
/** Freezes runtime mode blocks into user messages (cache-stable history). */
|
|
81891
|
+
runtimeModeBlocks = new RuntimeModeBlockInjector({
|
|
81892
|
+
getState: () => this.getRuntimeModeState(),
|
|
81893
|
+
consumeTransition: () => this.consumeRuntimeModeTransition(),
|
|
81894
|
+
noteTrace: (state) => this.sessionTrace.noteRuntimeEvent("runtime_context_injected", runtimeModeTraceData(state))
|
|
81895
|
+
});
|
|
80288
81896
|
fileManager;
|
|
80289
81897
|
mentionHandler;
|
|
80290
81898
|
mentionPickerComponent;
|
|
@@ -80447,6 +82055,11 @@ var InteractiveMode = class {
|
|
|
80447
82055
|
get controllerSetupHost() {
|
|
80448
82056
|
return this;
|
|
80449
82057
|
}
|
|
82058
|
+
getPolicyContext = () => ({
|
|
82059
|
+
mode: this.planModeEnabled ? "plan" : "normal",
|
|
82060
|
+
yoloMode: this.yoloMode,
|
|
82061
|
+
confirmationPolicy: "allow"
|
|
82062
|
+
});
|
|
80450
82063
|
rebuildSkillAwareTools(sourceTools) {
|
|
80451
82064
|
const preservedTools = sourceTools.filter(
|
|
80452
82065
|
(tool) => !CLI_FILESYSTEM_TOOL_NAMES.includes(tool.name) && tool.name !== "bash"
|
|
@@ -80472,19 +82085,14 @@ var InteractiveMode = class {
|
|
|
80472
82085
|
});
|
|
80473
82086
|
const normalFsTools = createCliFileSystemTools(this.options.cwd, fileSystemToolOptions([this.options.configDir]));
|
|
80474
82087
|
const currentFsTools = this.yoloMode ? createCliFileSystemTools(this.options.cwd, fileSystemToolOptions(["/"])) : normalFsTools;
|
|
80475
|
-
const getPolicyContext = () => ({
|
|
80476
|
-
mode: this.planModeEnabled ? "plan" : "normal",
|
|
80477
|
-
yoloMode: this.yoloMode,
|
|
80478
|
-
confirmationPolicy: "allow"
|
|
80479
|
-
});
|
|
80480
82088
|
return {
|
|
80481
82089
|
currentTools: createPolicyEnforcedTools(
|
|
80482
82090
|
[...currentFsTools, bashTool, ...preservedTools],
|
|
80483
|
-
{ getContext: getPolicyContext }
|
|
82091
|
+
{ getContext: this.getPolicyContext }
|
|
80484
82092
|
),
|
|
80485
82093
|
originalTools: createPolicyEnforcedTools(
|
|
80486
82094
|
[...normalFsTools, bashTool, ...preservedTools],
|
|
80487
|
-
{ getContext: getPolicyContext }
|
|
82095
|
+
{ getContext: this.getPolicyContext }
|
|
80488
82096
|
)
|
|
80489
82097
|
};
|
|
80490
82098
|
}
|
|
@@ -80492,26 +82100,27 @@ var InteractiveMode = class {
|
|
|
80492
82100
|
this.options.fileObservationState.clear();
|
|
80493
82101
|
}
|
|
80494
82102
|
getRuntimeModeState() {
|
|
80495
|
-
const pendingTransition = this.getPendingRuntimeModeTransition();
|
|
80496
82103
|
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || "local";
|
|
80497
|
-
const
|
|
80498
|
-
year: "numeric",
|
|
80499
|
-
month: "2-digit",
|
|
80500
|
-
day: "2-digit",
|
|
80501
|
-
timeZone
|
|
80502
|
-
}).formatToParts(/* @__PURE__ */ new Date());
|
|
80503
|
-
const datePart = (type) => dateParts.find((part) => part.type === type)?.value ?? "00";
|
|
80504
|
-
const currentDate = `${datePart("year")}-${datePart("month")}-${datePart("day")}`;
|
|
82104
|
+
const activeTools = this.agent?.state?.tools ?? [];
|
|
80505
82105
|
return {
|
|
80506
82106
|
yoloMode: this.yoloMode,
|
|
80507
82107
|
planMode: this.planModeEnabled ? "planning" : "off",
|
|
80508
82108
|
filesystemScope: this.yoloMode ? "all" : "workspace",
|
|
80509
|
-
...
|
|
80510
|
-
currentDate,
|
|
82109
|
+
...this.getPendingRuntimeModeTransition() ? { pendingTransition: this.getPendingRuntimeModeTransition() } : {},
|
|
82110
|
+
currentDate: currentDateInZone(timeZone),
|
|
80511
82111
|
timeZone,
|
|
80512
|
-
activeToolNames:
|
|
82112
|
+
activeToolNames: activeTools.map((tool) => tool.name),
|
|
82113
|
+
planDisabledToolNames: this.planModeEnabled ? activeTools.filter((tool) => !isToolAllowedInPlanMode(tool)).map((tool) => tool.name) : []
|
|
80513
82114
|
};
|
|
80514
82115
|
}
|
|
82116
|
+
/** Public reset for compaction flows (compaction may drop the latest block). */
|
|
82117
|
+
resetRuntimeModeBlocks() {
|
|
82118
|
+
this.runtimeModeBlocks.reset();
|
|
82119
|
+
}
|
|
82120
|
+
/** Runtime mode block for the next user message; frozen into it (append-only history, cache-stable prefixes). */
|
|
82121
|
+
runtimeModeBlockForNextMessage() {
|
|
82122
|
+
return this.runtimeModeBlocks.nextBlock();
|
|
82123
|
+
}
|
|
80515
82124
|
getPendingRuntimeModeTransition() {
|
|
80516
82125
|
if (this.pendingYoloModeTransition === "enter") return "entered_yolo";
|
|
80517
82126
|
if (this.pendingYoloModeTransition === "exit") return "exited_yolo";
|
|
@@ -80530,10 +82139,7 @@ var InteractiveMode = class {
|
|
|
80530
82139
|
const currentTools = this.extensionRunner ? wrapToolsWithExtensions(rebuilt.currentTools, this.extensionRunner) : rebuilt.currentTools;
|
|
80531
82140
|
const originalTools = this.extensionRunner ? wrapToolsWithExtensions(rebuilt.originalTools, this.extensionRunner) : rebuilt.originalTools;
|
|
80532
82141
|
const activeTools = filterEnabledTools(
|
|
80533
|
-
|
|
80534
|
-
currentTools,
|
|
80535
|
-
this.planModeEnabled ? "plan" : "normal"
|
|
80536
|
-
),
|
|
82142
|
+
currentTools,
|
|
80537
82143
|
this.options.settingsManager
|
|
80538
82144
|
);
|
|
80539
82145
|
this.agent.setTools(activeTools);
|
|
@@ -80566,7 +82172,8 @@ var InteractiveMode = class {
|
|
|
80566
82172
|
this.safeRequestRender();
|
|
80567
82173
|
}
|
|
80568
82174
|
promptAgent(input) {
|
|
80569
|
-
|
|
82175
|
+
const prompt = prependRuntimeModeBlockToPrompt(input, this.runtimeModeBlockForNextMessage());
|
|
82176
|
+
return this.agentSessionController.prompt(prompt, { source: "interactive" });
|
|
80570
82177
|
}
|
|
80571
82178
|
continueAgent() {
|
|
80572
82179
|
return this.agentSessionController.continue();
|
|
@@ -80596,6 +82203,7 @@ var InteractiveMode = class {
|
|
|
80596
82203
|
this.persistExecutionState();
|
|
80597
82204
|
}
|
|
80598
82205
|
this.executionReminder = this.executionState.getReminder();
|
|
82206
|
+
this.resetRuntimeModeBlocks();
|
|
80599
82207
|
await this.refreshTodoWidget();
|
|
80600
82208
|
await this.emitExtensionEvent({
|
|
80601
82209
|
type: "session:changed",
|
|
@@ -80606,7 +82214,7 @@ var InteractiveMode = class {
|
|
|
80606
82214
|
async init() {
|
|
80607
82215
|
const activeSession = this.sessionManager.getActiveSession();
|
|
80608
82216
|
this.thinkingLevel = resolveInitialThinkingLevel({ session: activeSession, settingsManager: this.options.settingsManager });
|
|
80609
|
-
const { Agent } = await import("./chunks/src-
|
|
82217
|
+
const { Agent } = await import("./chunks/src-E7NCXMU5.js");
|
|
80610
82218
|
this.agent = new Agent({
|
|
80611
82219
|
initialState: {
|
|
80612
82220
|
systemPrompt: this.buildSystemPrompt(),
|
|
@@ -80616,28 +82224,15 @@ var InteractiveMode = class {
|
|
|
80616
82224
|
},
|
|
80617
82225
|
apiKey: this.options.apiKey,
|
|
80618
82226
|
sessionId: activeSession?.id,
|
|
80619
|
-
streamFn: this.options.streamFn,
|
|
80620
|
-
transformContext: async (messages) => {
|
|
80621
|
-
|
|
80622
|
-
|
|
80623
|
-
|
|
80624
|
-
|
|
80625
|
-
|
|
80626
|
-
|
|
80627
|
-
|
|
80628
|
-
pendingTransition: state.pendingTransition,
|
|
80629
|
-
currentDate: state.currentDate,
|
|
80630
|
-
timeZone: state.timeZone,
|
|
80631
|
-
activeToolCount: state.activeToolNames.length
|
|
80632
|
-
}),
|
|
80633
|
-
onStripped: (count) => this.sessionTrace.noteRuntimeEvent("stale_runtime_context_stripped", { count })
|
|
80634
|
-
});
|
|
80635
|
-
let transformed = await runtimeModeTransform(messages);
|
|
80636
|
-
const advisory = this.pendingRuntimeGuardAdvisory;
|
|
80637
|
-
this.pendingRuntimeGuardAdvisory = null;
|
|
80638
|
-
transformed = advisory ? injectGuardAdvisory(transformed, advisory) : stripGuardAdvisories(transformed);
|
|
80639
|
-
return transformed;
|
|
80640
|
-
}
|
|
82227
|
+
streamFn: createCacheRetentionStreamFn(this.options.streamFn),
|
|
82228
|
+
transformContext: async (messages) => applyRuntimeRequestTransform(messages, {
|
|
82229
|
+
takeAdvisory: () => {
|
|
82230
|
+
const advisory = this.pendingRuntimeGuardAdvisory;
|
|
82231
|
+
this.pendingRuntimeGuardAdvisory = null;
|
|
82232
|
+
return advisory;
|
|
82233
|
+
},
|
|
82234
|
+
takeRetryBlock: () => this.runtimeModeBlocks.consumeRetryRefreshBlock()
|
|
82235
|
+
})
|
|
80641
82236
|
});
|
|
80642
82237
|
this.agentSessionController = createInteractiveAgentSessionController(this.controllerSetupHost);
|
|
80643
82238
|
this.updateTerminalTitle();
|
|
@@ -80821,6 +82416,9 @@ var InteractiveMode = class {
|
|
|
80821
82416
|
async handleYoloCommand(args) {
|
|
80822
82417
|
return handleYoloCommand(this, args);
|
|
80823
82418
|
}
|
|
82419
|
+
setYoloMode(enabled) {
|
|
82420
|
+
void this.handleYoloCommand(enabled ? "on" : "off");
|
|
82421
|
+
}
|
|
80824
82422
|
/**
|
|
80825
82423
|
* Toggle calm mode and rebuild the chat so already-rendered rows follow
|
|
80826
82424
|
* the new mode. Delivery, tool execution, and session storage are
|
|
@@ -80832,7 +82430,6 @@ var InteractiveMode = class {
|
|
|
80832
82430
|
this.options.settingsManager.setCalmModeEnabled(enabled);
|
|
80833
82431
|
this.footer.setState({ calmMode: enabled });
|
|
80834
82432
|
applyCalmMode(this, enabled);
|
|
80835
|
-
this.todoWidget.setCalmMode(enabled);
|
|
80836
82433
|
this.extensionWidgets.setCalmMode(enabled);
|
|
80837
82434
|
this.showStatus(`Calm mode ${enabled ? "on \u2014 showing questions and final answers only" : "off"}`);
|
|
80838
82435
|
this.safeRequestRender(true);
|
|
@@ -80870,11 +82467,11 @@ var InteractiveMode = class {
|
|
|
80870
82467
|
async handleCacheTest() {
|
|
80871
82468
|
return handleCacheTest(this);
|
|
80872
82469
|
}
|
|
80873
|
-
async
|
|
80874
|
-
return
|
|
82470
|
+
async handleTreeCommand() {
|
|
82471
|
+
return handleTreeCommand(this);
|
|
80875
82472
|
}
|
|
80876
|
-
|
|
80877
|
-
return
|
|
82473
|
+
handleDebugReportCommand(kind) {
|
|
82474
|
+
return kind === "context" ? handleContextReportCommand(this) : kind === "trace" ? handleTraceCommand(this, this.sessionTrace.getLiveSnapshot()) : handleBootCommand(this);
|
|
80878
82475
|
}
|
|
80879
82476
|
async handleResumeCommand() {
|
|
80880
82477
|
return handleResumeCommand(this);
|
|
@@ -80894,9 +82491,6 @@ var InteractiveMode = class {
|
|
|
80894
82491
|
setWaitingForUser(waiting) {
|
|
80895
82492
|
return setWaitingForUser(this, waiting);
|
|
80896
82493
|
}
|
|
80897
|
-
async handleTreeCommand() {
|
|
80898
|
-
return handleTreeCommand(this);
|
|
80899
|
-
}
|
|
80900
82494
|
async forkAtEntry(entryId) {
|
|
80901
82495
|
return forkAtEntry(this, entryId);
|
|
80902
82496
|
}
|
|
@@ -81196,6 +82790,7 @@ async function composeCliRuntime(params) {
|
|
|
81196
82790
|
getPolicyContext: () => ({ mode: "normal", confirmationPolicy: "allow" })
|
|
81197
82791
|
};
|
|
81198
82792
|
const rawTools = [
|
|
82793
|
+
createSearchContextTool(() => sessionManager),
|
|
81199
82794
|
...createCliFileSystemTools(cwd, fileSystemToolOptions),
|
|
81200
82795
|
...cliHostCapabilities.tools
|
|
81201
82796
|
];
|
|
@@ -81441,7 +83036,7 @@ async function runPrintMode(params) {
|
|
|
81441
83036
|
`);
|
|
81442
83037
|
console.log("Assistant: ");
|
|
81443
83038
|
}
|
|
81444
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
83039
|
+
const { Agent: AgentClass } = await import("./chunks/src-E7NCXMU5.js");
|
|
81445
83040
|
let agent;
|
|
81446
83041
|
const printModeExtensions = await loadPrintModeExtensions({
|
|
81447
83042
|
cwd: runtime.cwd,
|
|
@@ -81681,7 +83276,7 @@ function toJsonValue(value, depth = 0, cap = MAX_EVENT_STRING_LENGTH) {
|
|
|
81681
83276
|
}
|
|
81682
83277
|
return result;
|
|
81683
83278
|
}
|
|
81684
|
-
function
|
|
83279
|
+
function isRecord3(value) {
|
|
81685
83280
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
81686
83281
|
}
|
|
81687
83282
|
function truncateForEvent(text, cap) {
|
|
@@ -81707,7 +83302,7 @@ function parseInput(line) {
|
|
|
81707
83302
|
} catch {
|
|
81708
83303
|
return null;
|
|
81709
83304
|
}
|
|
81710
|
-
if (!
|
|
83305
|
+
if (!isRecord3(parsed) || typeof parsed.type !== "string") return null;
|
|
81711
83306
|
if (parsed.type === "shutdown") {
|
|
81712
83307
|
return { type: "shutdown", reason: typeof parsed.reason === "string" ? parsed.reason : void 0 };
|
|
81713
83308
|
}
|
|
@@ -81758,7 +83353,7 @@ function parseInput(line) {
|
|
|
81758
83353
|
prompt: parsed.prompt,
|
|
81759
83354
|
streamingBehavior,
|
|
81760
83355
|
cwd: typeof parsed.cwd === "string" ? parsed.cwd : void 0,
|
|
81761
|
-
metadata:
|
|
83356
|
+
metadata: isRecord3(parsed.metadata) ? parsed.metadata : void 0
|
|
81762
83357
|
};
|
|
81763
83358
|
}
|
|
81764
83359
|
return null;
|
|
@@ -81798,15 +83393,15 @@ function readProgressText(value) {
|
|
|
81798
83393
|
function extractJsonEventsToolProgressText(partialResult) {
|
|
81799
83394
|
const plainText = readProgressText(partialResult).trim();
|
|
81800
83395
|
if (plainText) return plainText;
|
|
81801
|
-
if (!
|
|
83396
|
+
if (!isRecord3(partialResult)) return "";
|
|
81802
83397
|
const content = partialResult.content;
|
|
81803
83398
|
if (Array.isArray(content)) {
|
|
81804
|
-
return content.map((block) =>
|
|
83399
|
+
return content.map((block) => isRecord3(block) && block.type === "text" ? readProgressText(block.text) : "").filter(Boolean).join("\n").trim();
|
|
81805
83400
|
}
|
|
81806
83401
|
const directText = readProgressText(partialResult.text) || readProgressText(partialResult.message);
|
|
81807
83402
|
if (directText) return directText.trim();
|
|
81808
83403
|
const details = partialResult.details;
|
|
81809
|
-
if (
|
|
83404
|
+
if (isRecord3(details)) {
|
|
81810
83405
|
return (readProgressText(details.text) || readProgressText(details.message)).trim();
|
|
81811
83406
|
}
|
|
81812
83407
|
return "";
|
|
@@ -82302,7 +83897,7 @@ async function runJsonEventsMode(params) {
|
|
|
82302
83897
|
return;
|
|
82303
83898
|
}
|
|
82304
83899
|
const parent = agent;
|
|
82305
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
83900
|
+
const { Agent: AgentClass } = await import("./chunks/src-E7NCXMU5.js");
|
|
82306
83901
|
const sideAgent = new AgentClass({
|
|
82307
83902
|
initialState: {
|
|
82308
83903
|
systemPrompt: parent.state.systemPrompt,
|
|
@@ -82646,7 +84241,7 @@ async function runJsonEventsMode(params) {
|
|
|
82646
84241
|
if (runtime.initialModel.unconfigured || controller) {
|
|
82647
84242
|
return;
|
|
82648
84243
|
}
|
|
82649
|
-
const { Agent: AgentClass } = await import("./chunks/src-
|
|
84244
|
+
const { Agent: AgentClass } = await import("./chunks/src-E7NCXMU5.js");
|
|
82650
84245
|
const jsonModeExtensions = await loadJsonModeExtensions({ runtime, getAgent: () => agent });
|
|
82651
84246
|
extensionRunner = jsonModeExtensions.runner;
|
|
82652
84247
|
const tools = [...runtime.tools, ...jsonModeExtensions.extensionTools];
|
|
@@ -83240,7 +84835,7 @@ async function runWithJsonEventsConsoleIsolation(fn) {
|
|
|
83240
84835
|
}
|
|
83241
84836
|
async function createCliTestStreamFnFromEnv() {
|
|
83242
84837
|
if (!process.env.PIE_TEST_MOCK_STREAM_SEQUENCE) return void 0;
|
|
83243
|
-
return (await import("./chunks/test-stream-
|
|
84838
|
+
return (await import("./chunks/test-stream-BWBJTFNI.js")).createTestStreamFnFromSequenceEnv();
|
|
83244
84839
|
}
|
|
83245
84840
|
function resolveJsonEventsDetailFlag() {
|
|
83246
84841
|
for (let index = 0; index < process.argv.length; index += 1) {
|