@sentry/junior 0.115.0 → 0.116.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-hooks-4EUUXP2F.js → agent-hooks-GUAAS3XH.js} +9 -9
- package/dist/api/conversations/detail.d.ts +18 -0
- package/dist/api/conversations/event-page.d.ts +1 -1
- package/dist/api/conversations/events.d.ts +1 -1
- package/dist/api/people/profile.d.ts +2 -2
- package/dist/api/people/shared.d.ts +1 -1
- package/dist/api/personal-tokens/create.d.ts +11 -0
- package/dist/api/personal-tokens/list.d.ts +12 -0
- package/dist/api/personal-tokens/revoke.d.ts +5 -0
- package/dist/api/personal-tokens/routes.d.ts +4 -0
- package/dist/api/plugins.d.ts +0 -1
- package/dist/api/route.d.ts +1 -1
- package/dist/api/schema/conversation.d.ts +18 -0
- package/dist/api/schema/person.d.ts +3 -3
- package/dist/api/schema/personal-token.d.ts +38 -0
- package/dist/api/schema.d.ts +2 -0
- package/dist/api/schema.js +15 -3
- package/dist/api.d.ts +1 -0
- package/dist/api.js +179 -39
- package/dist/app.js +1035 -853
- package/dist/{catalog-runtime-Y32UEQLB.js → catalog-runtime-WMPC4J4U.js} +5 -5
- package/dist/chat/agent/request.d.ts +1 -0
- package/dist/chat/agent/resume.d.ts +1 -0
- package/dist/chat/agent/sandbox.d.ts +1 -0
- package/dist/chat/agent/tools.d.ts +1 -0
- package/dist/chat/agent-dispatch/context.d.ts +2 -0
- package/dist/chat/agent-dispatch/heartbeat.d.ts +11 -5
- package/dist/chat/agent-dispatch/signing.d.ts +14 -5
- package/dist/chat/agent-dispatch/store.d.ts +36 -15
- package/dist/chat/agent-dispatch/types.d.ts +23 -10
- package/dist/chat/agent-dispatch/work.d.ts +58 -0
- package/dist/chat/app/factory.d.ts +12 -3
- package/dist/chat/conversations/history.d.ts +285 -290
- package/dist/chat/conversations/projection.d.ts +2 -2
- package/dist/chat/mcp/tool-manager.d.ts +2 -1
- package/dist/chat/pi/conversation-events.d.ts +6 -2
- package/dist/chat/plugins/annotations.d.ts +8 -0
- package/dist/chat/plugins/registry.d.ts +0 -3
- package/dist/chat/plugins/types.d.ts +0 -2
- package/dist/chat/runtime/agent-continue-runner.d.ts +4 -0
- package/dist/chat/runtime/reply-executor.d.ts +6 -1
- package/dist/chat/runtime/slack-resume.d.ts +5 -1
- package/dist/chat/runtime/turn-input.d.ts +3 -0
- package/dist/chat/sandbox/sandbox.d.ts +2 -1
- package/dist/chat/sandbox/session.d.ts +2 -11
- package/dist/chat/sandbox/workspace.d.ts +10 -2
- package/dist/chat/services/turn-session-record.d.ts +14 -1
- package/dist/chat/slack/dispatch-turn.d.ts +25 -0
- package/dist/chat/state/turn-session.d.ts +11 -0
- package/dist/chat/tool-support/text-range-result.d.ts +3 -0
- package/dist/chat/tool-support/zod-tool.d.ts +1 -0
- package/dist/chat/tools/definition.d.ts +3 -10
- package/dist/chat/tools/query-conversation-events.d.ts +68 -0
- package/dist/chat/tools/sandbox/file-utils.d.ts +8 -1
- package/dist/chat/tools/sandbox/find-files.d.ts +2 -1
- package/dist/chat/tools/sandbox/grep.d.ts +2 -1
- package/dist/{chunk-6V762AB4.js → chunk-2YYPXQNQ.js} +1 -1
- package/dist/{chunk-MIAKQNYX.js → chunk-6ZK6FZIV.js} +1 -1
- package/dist/{chunk-67CVNDJ7.js → chunk-7CSVG54J.js} +1 -1
- package/dist/{chunk-HWCQRGLL.js → chunk-BFYVIOTS.js} +105 -37
- package/dist/{chunk-LYA2AB5G.js → chunk-CGXLCMWI.js} +8 -52
- package/dist/{chunk-SYJT7AKB.js → chunk-CY7NXM32.js} +1 -1
- package/dist/{chunk-2QG4MZQ7.js → chunk-DLLW5ITL.js} +2 -2
- package/dist/{chunk-NVUQSFWX.js → chunk-F3SWGSPG.js} +3 -15
- package/dist/{chunk-CWEZEPD4.js → chunk-FAEALXEH.js} +68 -2
- package/dist/{chunk-43RYMWJ2.js → chunk-GDAXWEIJ.js} +809 -213
- package/dist/{chunk-AGLQYELI.js → chunk-H35BDAUS.js} +170 -170
- package/dist/{chunk-YCLO7D7M.js → chunk-JPKGW6L6.js} +77 -26
- package/dist/{chunk-G5SX4UPR.js → chunk-KNCELO2M.js} +2 -2
- package/dist/{chunk-FHC4JUSF.js → chunk-N3C4XCRE.js} +1 -2
- package/dist/{chunk-6FKLPVF3.js → chunk-OY2PQQ4P.js} +1 -1
- package/dist/{chunk-6OPTF4BQ.js → chunk-PE44LDDQ.js} +0 -1
- package/dist/{chunk-JQFJO5WH.js → chunk-RXRQJF7Y.js} +74 -17
- package/dist/{chunk-CEYOL62C.js → chunk-RYFAVWP3.js} +120 -20
- package/dist/{chunk-G36V2YGB.js → chunk-TC4ZEM2D.js} +33 -1
- package/dist/{chunk-PVZHG2XZ.js → chunk-VBMMMVVQ.js} +112 -35
- package/dist/{chunk-SG5WAA7H.js → chunk-WKU7TY22.js} +0 -3
- package/dist/{chunk-TVE25LPW.js → chunk-WLT72MRP.js} +1 -1
- package/dist/{chunk-EW5MLKT5.js → chunk-XA3VLFPK.js} +1 -55
- package/dist/{chunk-RAVKCKXA.js → chunk-ZYHLNTC2.js} +20 -5
- package/dist/cli/chat.js +23 -23
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +13 -13
- package/dist/cli/snapshot-warmup.js +8 -8
- package/dist/cli/upgrade.js +7 -7
- package/dist/db/schema/api-tokens.d.ts +160 -0
- package/dist/db/schema/conversation-annotations.d.ts +142 -0
- package/dist/db/schema.d.ts +305 -1
- package/dist/{db-KBSJHAZU.js → db-FH4R5ZQ4.js} +6 -6
- package/dist/handlers/agent-dispatch.d.ts +7 -3
- package/dist/instrumentation.js +2 -2
- package/dist/nitro.js +5 -5
- package/dist/{oauth-callback-server-EYRMJTCS.js → oauth-callback-server-C2SSJ3FQ.js} +18 -18
- package/dist/personal-tokens/store.d.ts +27 -0
- package/dist/{plugins-PZMDS7AT.js → plugins-IUJA4VBU.js} +1 -1
- package/dist/reporting-schema.d.ts +0 -2
- package/dist/{runner-RQGZ5Z2S.js → runner-NAALFIXM.js} +12 -12
- package/dist/{skills-JJQIE3BT.js → skills-UN2JXYYF.js} +6 -6
- package/dist/{validation-MZ47PZP5.js → validation-EEF4ROHR.js} +6 -6
- package/dist/version.js +1 -1
- package/migrations/0008_sticky_rage.sql +14 -0
- package/migrations/0009_slippery_harrier.sql +12 -0
- package/migrations/0010_native_conversation_history.sql +142 -0
- package/migrations/meta/0008_snapshot.json +1076 -0
- package/migrations/meta/0009_snapshot.json +1146 -0
- package/migrations/meta/0010_snapshot.json +1190 -0
- package/migrations/meta/_journal.json +22 -1
- package/package.json +5 -6
- package/dist/chat/agent-dispatch/runner.d.ts +0 -13
- package/dist/chat/capabilities/catalog.d.ts +0 -16
- package/dist/{chunk-KNFROR7R.js → chunk-5I6ORJUY.js} +1 -1
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
surfaceFromRouting,
|
|
26
26
|
toolInvocationDestination,
|
|
27
27
|
uploadFilesToConversation
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-CGXLCMWI.js";
|
|
29
29
|
import {
|
|
30
30
|
CooperativeTurnYieldError,
|
|
31
31
|
JUNIOR_THREAD_STATE_TTL_MS,
|
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
getPiMessageRole,
|
|
42
42
|
getTerminalAssistantMessages,
|
|
43
43
|
hasRuntimeTurnContext,
|
|
44
|
+
historyItemFromPiMessage,
|
|
44
45
|
isAssistantMessage,
|
|
45
46
|
isContinuablePiBoundary,
|
|
46
47
|
isToolResultError,
|
|
@@ -57,6 +58,7 @@ import {
|
|
|
57
58
|
persistContinuationSessionRecord,
|
|
58
59
|
persistRunningSessionRecord,
|
|
59
60
|
persistYieldSessionRecord,
|
|
61
|
+
piMessageFromHistoryItem,
|
|
60
62
|
recordAuthorizationRequested,
|
|
61
63
|
recordMcpProviderConnected,
|
|
62
64
|
recordToolExecutionStarted,
|
|
@@ -65,7 +67,7 @@ import {
|
|
|
65
67
|
stripRuntimeTurnContext,
|
|
66
68
|
trimTrailingAssistantMessages,
|
|
67
69
|
updateConversationStats
|
|
68
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-RYFAVWP3.js";
|
|
69
71
|
import {
|
|
70
72
|
parseSandboxEgressAuthRequiredSignal,
|
|
71
73
|
parseSandboxEgressPermissionDeniedSignal,
|
|
@@ -73,6 +75,7 @@ import {
|
|
|
73
75
|
sandboxEgressCredentialLeaseSchema
|
|
74
76
|
} from "./chunk-HDSDCEPK.js";
|
|
75
77
|
import {
|
|
78
|
+
bindSandboxFileSystem,
|
|
76
79
|
buildNonInteractiveShellScript,
|
|
77
80
|
createSandboxSession,
|
|
78
81
|
getRuntimeDependencyProfileHash,
|
|
@@ -88,7 +91,7 @@ import {
|
|
|
88
91
|
runNonInteractiveCommand,
|
|
89
92
|
throwSandboxOperationError,
|
|
90
93
|
wrapSandboxSetupError
|
|
91
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-VBMMMVVQ.js";
|
|
92
95
|
import {
|
|
93
96
|
addAgentTurnUsage,
|
|
94
97
|
hasAgentTurnUsage
|
|
@@ -103,7 +106,7 @@ import {
|
|
|
103
106
|
getPluginUserPromptContributions,
|
|
104
107
|
getSlackToolContext,
|
|
105
108
|
resolveChannelCapabilities
|
|
106
|
-
} from "./chunk-
|
|
109
|
+
} from "./chunk-ZYHLNTC2.js";
|
|
107
110
|
import {
|
|
108
111
|
SANDBOX_DATA_ROOT,
|
|
109
112
|
SANDBOX_SKILLS_ROOT,
|
|
@@ -111,7 +114,7 @@ import {
|
|
|
111
114
|
getStateAdapter,
|
|
112
115
|
sandboxSkillDir,
|
|
113
116
|
sandboxSkillFile
|
|
114
|
-
} from "./chunk-
|
|
117
|
+
} from "./chunk-7CSVG54J.js";
|
|
115
118
|
import {
|
|
116
119
|
SlackActionError,
|
|
117
120
|
downloadPrivateSlackFile,
|
|
@@ -120,15 +123,16 @@ import {
|
|
|
120
123
|
isConversationScopedChannel,
|
|
121
124
|
normalizeSlackConversationId,
|
|
122
125
|
withSlackRetries
|
|
123
|
-
} from "./chunk-
|
|
126
|
+
} from "./chunk-FAEALXEH.js";
|
|
124
127
|
import {
|
|
128
|
+
KNOWN_CONVERSATION_EVENT_TYPES,
|
|
125
129
|
contextProvenance,
|
|
126
130
|
getConversationEventStore,
|
|
127
131
|
getConversationSearchStore,
|
|
128
132
|
getConversationStore,
|
|
129
133
|
instructionActors,
|
|
130
134
|
instructionProvenanceFor
|
|
131
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-BFYVIOTS.js";
|
|
132
136
|
import {
|
|
133
137
|
sleep
|
|
134
138
|
} from "./chunk-4ZNGQH7C.js";
|
|
@@ -161,8 +165,9 @@ import {
|
|
|
161
165
|
renderCurrentInstruction,
|
|
162
166
|
resolveGatewayModel,
|
|
163
167
|
unwrapCurrentInstruction
|
|
164
|
-
} from "./chunk-
|
|
168
|
+
} from "./chunk-CY7NXM32.js";
|
|
165
169
|
import {
|
|
170
|
+
canExposeConversationPayload,
|
|
166
171
|
parseSlackThreadId,
|
|
167
172
|
resolveConversationPrivacy,
|
|
168
173
|
runWithConversationPrivacy,
|
|
@@ -177,15 +182,15 @@ import {
|
|
|
177
182
|
findSkillByName,
|
|
178
183
|
loadSkillsByName,
|
|
179
184
|
parseSkillInvocation
|
|
180
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-DLLW5ITL.js";
|
|
181
186
|
import {
|
|
182
187
|
pluginCatalogRuntime
|
|
183
|
-
} from "./chunk-
|
|
188
|
+
} from "./chunk-OY2PQQ4P.js";
|
|
184
189
|
import {
|
|
185
190
|
CredentialUnavailableError,
|
|
186
191
|
resolveAuthTokenPlaceholder,
|
|
187
192
|
resolvePluginCommandEnv
|
|
188
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-XA3VLFPK.js";
|
|
189
194
|
import {
|
|
190
195
|
credentialUserSubjectId
|
|
191
196
|
} from "./chunk-W3U3YQYI.js";
|
|
@@ -209,7 +214,7 @@ import {
|
|
|
209
214
|
summarizeMessageText,
|
|
210
215
|
withLogContext,
|
|
211
216
|
withSpan
|
|
212
|
-
} from "./chunk-
|
|
217
|
+
} from "./chunk-F3SWGSPG.js";
|
|
213
218
|
import {
|
|
214
219
|
parseSlackChannelId,
|
|
215
220
|
parseSlackMessageTs,
|
|
@@ -2623,7 +2628,6 @@ ${usage}
|
|
|
2623
2628
|
name: plugin.manifest.name,
|
|
2624
2629
|
displayName: plugin.manifest.displayName,
|
|
2625
2630
|
description: plugin.manifest.description,
|
|
2626
|
-
capabilities: [...plugin.manifest.capabilities],
|
|
2627
2631
|
configKeys: [...plugin.manifest.configKeys]
|
|
2628
2632
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
2629
2633
|
return commandResult({
|
|
@@ -3020,7 +3024,6 @@ async function resolveSandboxCommandEnvironment() {
|
|
|
3020
3024
|
// src/chat/sandbox/session.ts
|
|
3021
3025
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3022
3026
|
import { Sandbox } from "@vercel/sandbox";
|
|
3023
|
-
import { createBashTool } from "bash-tool";
|
|
3024
3027
|
|
|
3025
3028
|
// src/chat/sandbox/skill-sync.ts
|
|
3026
3029
|
import fs3 from "fs/promises";
|
|
@@ -3195,36 +3198,8 @@ var SANDBOX_RUNTIME_BIN_DIR = `${SANDBOX_WORKSPACE_ROOT}/.junior/bin`;
|
|
|
3195
3198
|
var SNAPSHOT_BOOT_RETRY_COUNT = 3;
|
|
3196
3199
|
var SNAPSHOT_BOOT_RETRY_DELAY_MS = 1e3;
|
|
3197
3200
|
var SANDBOX_NAME_PREFIX = "junior-";
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
async executeCommand(command) {
|
|
3201
|
-
const result = await sandbox.runCommand({
|
|
3202
|
-
cmd: "bash",
|
|
3203
|
-
args: ["-c", command]
|
|
3204
|
-
});
|
|
3205
|
-
return {
|
|
3206
|
-
stdout: result.stdout,
|
|
3207
|
-
stderr: result.stderr,
|
|
3208
|
-
exitCode: result.exitCode
|
|
3209
|
-
};
|
|
3210
|
-
},
|
|
3211
|
-
async readFile(filePath) {
|
|
3212
|
-
const content = await sandbox.readFileToBuffer({ path: filePath });
|
|
3213
|
-
if (content == null) {
|
|
3214
|
-
throw new Error(`File not found: ${filePath}`);
|
|
3215
|
-
}
|
|
3216
|
-
return content.toString("utf8");
|
|
3217
|
-
},
|
|
3218
|
-
async writeFiles(files) {
|
|
3219
|
-
await sandbox.writeFiles(
|
|
3220
|
-
files.map((file) => ({
|
|
3221
|
-
path: file.path,
|
|
3222
|
-
content: file.content
|
|
3223
|
-
}))
|
|
3224
|
-
);
|
|
3225
|
-
}
|
|
3226
|
-
};
|
|
3227
|
-
}
|
|
3201
|
+
var MAX_KEEPALIVE_INTERVAL_MS = 3e4;
|
|
3202
|
+
var MIN_KEEPALIVE_INTERVAL_MS = 1e3;
|
|
3228
3203
|
function truncateOutput(output, maxLength) {
|
|
3229
3204
|
if (output.length <= maxLength) {
|
|
3230
3205
|
return { value: output, truncated: false };
|
|
@@ -3261,6 +3236,8 @@ function createSandboxRuntime(options) {
|
|
|
3261
3236
|
const availableSkills = [...options.skills];
|
|
3262
3237
|
const availableReferenceFiles = [...options.referenceFiles];
|
|
3263
3238
|
let acquiringSandbox;
|
|
3239
|
+
let keepAliveTimer;
|
|
3240
|
+
let closed = false;
|
|
3264
3241
|
const timeoutMs = options.timeoutMs ?? 1e3 * 60 * 30;
|
|
3265
3242
|
const traceContext = options.traceContext ?? {};
|
|
3266
3243
|
const dependencyProfileHash = getRuntimeDependencyProfileHash(SANDBOX_RUNTIME);
|
|
@@ -3271,6 +3248,10 @@ function createSandboxRuntime(options) {
|
|
|
3271
3248
|
return;
|
|
3272
3249
|
}
|
|
3273
3250
|
activeSandbox = null;
|
|
3251
|
+
if (keepAliveTimer) {
|
|
3252
|
+
clearTimeout(keepAliveTimer);
|
|
3253
|
+
keepAliveTimer = void 0;
|
|
3254
|
+
}
|
|
3274
3255
|
};
|
|
3275
3256
|
const adaptSandbox = (vercelSandbox) => createSandboxSession(vercelSandbox, {
|
|
3276
3257
|
onUnavailable: invalidateSession
|
|
@@ -3640,24 +3621,37 @@ function createSandboxRuntime(options) {
|
|
|
3640
3621
|
}
|
|
3641
3622
|
}
|
|
3642
3623
|
};
|
|
3643
|
-
const
|
|
3644
|
-
const
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
{
|
|
3648
|
-
"app.sandbox.tool_name": "bash",
|
|
3649
|
-
"app.sandbox.destination": SANDBOX_WORKSPACE_ROOT
|
|
3650
|
-
},
|
|
3651
|
-
async () => await createBashTool({
|
|
3652
|
-
sandbox: createBashToolSandboxAdapter(sandboxInstance),
|
|
3653
|
-
destination: SANDBOX_WORKSPACE_ROOT
|
|
3654
|
-
})
|
|
3655
|
-
);
|
|
3656
|
-
const executeReadFile = toolkit.tools.readFile.execute;
|
|
3657
|
-
const executeWriteFile = toolkit.tools.writeFile.execute;
|
|
3658
|
-
if (!executeReadFile || !executeWriteFile) {
|
|
3659
|
-
throw new Error("bash-tool did not return executable tool handlers");
|
|
3624
|
+
const startKeepAlive = (session) => {
|
|
3625
|
+
const keepAliveMs = parseKeepAliveMs();
|
|
3626
|
+
if (keepAliveMs === 0 || closed || keepAliveTimer) {
|
|
3627
|
+
return;
|
|
3660
3628
|
}
|
|
3629
|
+
const intervalMs = Math.max(
|
|
3630
|
+
MIN_KEEPALIVE_INTERVAL_MS,
|
|
3631
|
+
Math.min(MAX_KEEPALIVE_INTERVAL_MS, Math.floor(keepAliveMs / 2))
|
|
3632
|
+
);
|
|
3633
|
+
const schedule = () => {
|
|
3634
|
+
keepAliveTimer = setTimeout(async () => {
|
|
3635
|
+
keepAliveTimer = void 0;
|
|
3636
|
+
if (closed || activeSandbox?.session !== session) {
|
|
3637
|
+
return;
|
|
3638
|
+
}
|
|
3639
|
+
try {
|
|
3640
|
+
await extendKeepAlive(session);
|
|
3641
|
+
} catch {
|
|
3642
|
+
invalidateSession(session.sessionId);
|
|
3643
|
+
return;
|
|
3644
|
+
}
|
|
3645
|
+
if (closed || activeSandbox?.session !== session) {
|
|
3646
|
+
return;
|
|
3647
|
+
}
|
|
3648
|
+
schedule();
|
|
3649
|
+
}, intervalMs);
|
|
3650
|
+
keepAliveTimer.unref?.();
|
|
3651
|
+
};
|
|
3652
|
+
schedule();
|
|
3653
|
+
};
|
|
3654
|
+
const createToolExecutors = (sandboxInstance) => {
|
|
3661
3655
|
return {
|
|
3662
3656
|
sessionId: sandboxInstance.sessionId,
|
|
3663
3657
|
bash: async (input) => {
|
|
@@ -3725,50 +3719,17 @@ function createSandboxRuntime(options) {
|
|
|
3725
3719
|
}
|
|
3726
3720
|
}
|
|
3727
3721
|
},
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
messages: []
|
|
3731
|
-
}),
|
|
3732
|
-
writeFile: async (input) => await executeWriteFile(input, {
|
|
3733
|
-
toolCallId: "sandbox-write-file",
|
|
3734
|
-
messages: []
|
|
3735
|
-
}),
|
|
3736
|
-
fs: sandboxInstance.fs
|
|
3722
|
+
fs: sandboxInstance.fs,
|
|
3723
|
+
runCommand: async (input) => await sandboxInstance.runCommand(input)
|
|
3737
3724
|
};
|
|
3738
3725
|
};
|
|
3739
3726
|
const ensureReadySandbox = async () => {
|
|
3740
3727
|
const activeSandbox2 = await getOrAcquireSandbox();
|
|
3741
3728
|
await probeSession(activeSandbox2);
|
|
3742
3729
|
await extendKeepAlive(activeSandbox2);
|
|
3730
|
+
startKeepAlive(activeSandbox2);
|
|
3743
3731
|
return activeSandbox2;
|
|
3744
3732
|
};
|
|
3745
|
-
const loadToolExecutors = async (session) => {
|
|
3746
|
-
const active = activeSandbox;
|
|
3747
|
-
if (!active || active.session !== session) {
|
|
3748
|
-
throw new Error("sandbox session changed before tool initialization");
|
|
3749
|
-
}
|
|
3750
|
-
if (active.toolExecutors) {
|
|
3751
|
-
return active.toolExecutors;
|
|
3752
|
-
}
|
|
3753
|
-
if (active.loadingToolExecutors) {
|
|
3754
|
-
return await active.loadingToolExecutors;
|
|
3755
|
-
}
|
|
3756
|
-
let nextToolExecutors;
|
|
3757
|
-
nextToolExecutors = buildToolExecutors(session).then((executors) => {
|
|
3758
|
-
if (activeSandbox === active && active.loadingToolExecutors === nextToolExecutors) {
|
|
3759
|
-
active.toolExecutors = executors;
|
|
3760
|
-
}
|
|
3761
|
-
return executors;
|
|
3762
|
-
});
|
|
3763
|
-
active.loadingToolExecutors = nextToolExecutors;
|
|
3764
|
-
try {
|
|
3765
|
-
return await nextToolExecutors;
|
|
3766
|
-
} finally {
|
|
3767
|
-
if (active.loadingToolExecutors === nextToolExecutors) {
|
|
3768
|
-
active.loadingToolExecutors = void 0;
|
|
3769
|
-
}
|
|
3770
|
-
}
|
|
3771
|
-
};
|
|
3772
3733
|
return {
|
|
3773
3734
|
sandboxRef() {
|
|
3774
3735
|
return sandboxRef ? { ...sandboxRef } : void 0;
|
|
@@ -3777,7 +3738,7 @@ function createSandboxRuntime(options) {
|
|
|
3777
3738
|
return await getOrAcquireSandbox();
|
|
3778
3739
|
},
|
|
3779
3740
|
async tools() {
|
|
3780
|
-
return
|
|
3741
|
+
return createToolExecutors(await ensureReadySandbox());
|
|
3781
3742
|
},
|
|
3782
3743
|
async refreshNetworkPolicy(traceHeaders) {
|
|
3783
3744
|
const active = activeSandbox;
|
|
@@ -3785,6 +3746,13 @@ function createSandboxRuntime(options) {
|
|
|
3785
3746
|
return;
|
|
3786
3747
|
}
|
|
3787
3748
|
await applyNetworkPolicy(active.session, traceHeaders);
|
|
3749
|
+
},
|
|
3750
|
+
close() {
|
|
3751
|
+
closed = true;
|
|
3752
|
+
if (keepAliveTimer) {
|
|
3753
|
+
clearTimeout(keepAliveTimer);
|
|
3754
|
+
keepAliveTimer = void 0;
|
|
3755
|
+
}
|
|
3788
3756
|
}
|
|
3789
3757
|
};
|
|
3790
3758
|
}
|
|
@@ -3802,6 +3770,10 @@ var ToolInputError = class extends Error {
|
|
|
3802
3770
|
|
|
3803
3771
|
// src/chat/tools/sandbox/file-utils.ts
|
|
3804
3772
|
var MAX_TEXT_CHARS = 6e4;
|
|
3773
|
+
var RIPGREP_EXCLUDED_GLOBS = [
|
|
3774
|
+
"!**/.git/**",
|
|
3775
|
+
"!**/node_modules/**"
|
|
3776
|
+
];
|
|
3805
3777
|
var SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
3806
3778
|
function positiveInteger(value) {
|
|
3807
3779
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -3905,6 +3877,15 @@ function resolveWorkspacePath(input, fallback = ".") {
|
|
|
3905
3877
|
}
|
|
3906
3878
|
return normalized;
|
|
3907
3879
|
}
|
|
3880
|
+
function getRipgrepSearchLocation(root, rootIsDirectory) {
|
|
3881
|
+
if (rootIsDirectory) {
|
|
3882
|
+
return { cwd: root, target: "." };
|
|
3883
|
+
}
|
|
3884
|
+
return {
|
|
3885
|
+
cwd: path4.posix.dirname(root),
|
|
3886
|
+
target: path4.posix.basename(root)
|
|
3887
|
+
};
|
|
3888
|
+
}
|
|
3908
3889
|
async function collectFiles(params) {
|
|
3909
3890
|
const files = [];
|
|
3910
3891
|
let limitReached = false;
|
|
@@ -4387,6 +4368,16 @@ async function findFiles(params) {
|
|
|
4387
4368
|
}
|
|
4388
4369
|
const root = resolveWorkspacePath(params.path);
|
|
4389
4370
|
const limit = positiveInteger(params.limit) ?? DEFAULT_FIND_LIMIT;
|
|
4371
|
+
if (params.runCommand) {
|
|
4372
|
+
return await findFilesWithRipgrep({
|
|
4373
|
+
fs: params.fs,
|
|
4374
|
+
limit,
|
|
4375
|
+
path: params.path,
|
|
4376
|
+
pattern: params.pattern,
|
|
4377
|
+
root,
|
|
4378
|
+
runCommand: params.runCommand
|
|
4379
|
+
});
|
|
4380
|
+
}
|
|
4390
4381
|
const { files, limitReached, missingPath, missingRoot } = await collectFiles({
|
|
4391
4382
|
fs: params.fs,
|
|
4392
4383
|
root,
|
|
@@ -4435,6 +4426,80 @@ async function findFiles(params) {
|
|
|
4435
4426
|
{ content: [{ type: "text", text }] }
|
|
4436
4427
|
);
|
|
4437
4428
|
}
|
|
4429
|
+
async function findFilesWithRipgrep(params) {
|
|
4430
|
+
let rootIsDirectory;
|
|
4431
|
+
try {
|
|
4432
|
+
rootIsDirectory = (await params.fs.stat(params.root)).isDirectory();
|
|
4433
|
+
} catch (error) {
|
|
4434
|
+
if (isMissingPathError(error)) {
|
|
4435
|
+
return missingPathSearchResult({
|
|
4436
|
+
path: params.path ?? ".",
|
|
4437
|
+
displayPath: params.path ?? "."
|
|
4438
|
+
});
|
|
4439
|
+
}
|
|
4440
|
+
throw error;
|
|
4441
|
+
}
|
|
4442
|
+
const location = getRipgrepSearchLocation(params.root, rootIsDirectory);
|
|
4443
|
+
const args = [
|
|
4444
|
+
"--files",
|
|
4445
|
+
"--null",
|
|
4446
|
+
"--hidden",
|
|
4447
|
+
"--sort=path",
|
|
4448
|
+
"--glob",
|
|
4449
|
+
params.pattern
|
|
4450
|
+
];
|
|
4451
|
+
for (const excludedGlob of RIPGREP_EXCLUDED_GLOBS) {
|
|
4452
|
+
args.push("--glob", excludedGlob);
|
|
4453
|
+
}
|
|
4454
|
+
args.push("--", location.target);
|
|
4455
|
+
const result = await params.runCommand({
|
|
4456
|
+
cmd: "rg",
|
|
4457
|
+
args,
|
|
4458
|
+
cwd: location.cwd
|
|
4459
|
+
});
|
|
4460
|
+
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
4461
|
+
const detail = result.stderr.trim() || result.stdout.trim() || "command failed";
|
|
4462
|
+
throw new Error(`ripgrep file search failed: ${detail}`);
|
|
4463
|
+
}
|
|
4464
|
+
const allPaths = result.stdout.split("\0").filter(Boolean).map((filePath) => {
|
|
4465
|
+
const absolute = filePath.startsWith("/") ? path5.posix.normalize(filePath) : path5.posix.resolve(location.cwd, filePath);
|
|
4466
|
+
return rootIsDirectory ? path5.posix.relative(params.root, absolute) : path5.posix.basename(absolute);
|
|
4467
|
+
});
|
|
4468
|
+
const limitReached = allPaths.length > params.limit;
|
|
4469
|
+
const relativePaths = allPaths.slice(0, params.limit);
|
|
4470
|
+
const bounded = truncateText(
|
|
4471
|
+
relativePaths.length > 0 ? relativePaths.join("\n") : "No files found matching pattern"
|
|
4472
|
+
);
|
|
4473
|
+
const notices = [];
|
|
4474
|
+
if (limitReached) {
|
|
4475
|
+
notices.push(
|
|
4476
|
+
`${params.limit} results limit reached. Refine pattern or raise limit.`
|
|
4477
|
+
);
|
|
4478
|
+
}
|
|
4479
|
+
if (bounded.truncated) {
|
|
4480
|
+
notices.push(`${MAX_TEXT_CHARS} character output limit reached.`);
|
|
4481
|
+
}
|
|
4482
|
+
const text = notices.length > 0 ? `${bounded.content}
|
|
4483
|
+
|
|
4484
|
+
[${notices.join(" ")}]` : bounded.content;
|
|
4485
|
+
return makeStructuredToolResult(
|
|
4486
|
+
{
|
|
4487
|
+
ok: true,
|
|
4488
|
+
status: "success",
|
|
4489
|
+
target: params.path ?? ".",
|
|
4490
|
+
path: params.path ?? ".",
|
|
4491
|
+
truncated: limitReached || bounded.truncated,
|
|
4492
|
+
data: {
|
|
4493
|
+
files: relativePaths,
|
|
4494
|
+
file_count: relativePaths.length,
|
|
4495
|
+
path: params.path ?? ".",
|
|
4496
|
+
...notices.length > 0 ? { truncation_reasons: notices } : {}
|
|
4497
|
+
},
|
|
4498
|
+
...limitReached ? { result_limit_reached: params.limit } : {}
|
|
4499
|
+
},
|
|
4500
|
+
{ content: [{ type: "text", text }] }
|
|
4501
|
+
);
|
|
4502
|
+
}
|
|
4438
4503
|
function createFindFilesTool() {
|
|
4439
4504
|
return zodTool({
|
|
4440
4505
|
description: "Find sandbox workspace files by glob pattern. Returns bounded paths relative to the search root and skips dependency/cache directories.",
|
|
@@ -4491,6 +4556,20 @@ async function grepFiles(params) {
|
|
|
4491
4556
|
const root = resolveWorkspacePath(params.path);
|
|
4492
4557
|
const limit = positiveInteger(params.limit) ?? DEFAULT_GREP_LIMIT;
|
|
4493
4558
|
const context = positiveInteger(params.context) ?? 0;
|
|
4559
|
+
if (params.runCommand) {
|
|
4560
|
+
return await grepFilesWithRipgrep({
|
|
4561
|
+
context,
|
|
4562
|
+
fs: params.fs,
|
|
4563
|
+
glob: params.glob,
|
|
4564
|
+
ignoreCase: params.ignoreCase,
|
|
4565
|
+
limit,
|
|
4566
|
+
literal: params.literal,
|
|
4567
|
+
path: params.path,
|
|
4568
|
+
pattern: params.pattern,
|
|
4569
|
+
root,
|
|
4570
|
+
runCommand: params.runCommand
|
|
4571
|
+
});
|
|
4572
|
+
}
|
|
4494
4573
|
let regex;
|
|
4495
4574
|
if (!params.literal) {
|
|
4496
4575
|
try {
|
|
@@ -4609,6 +4688,174 @@ async function grepFiles(params) {
|
|
|
4609
4688
|
...lineTruncated ? { line_truncated: true } : {}
|
|
4610
4689
|
});
|
|
4611
4690
|
}
|
|
4691
|
+
function decodeRipgrepText(value) {
|
|
4692
|
+
if (typeof value?.text === "string") {
|
|
4693
|
+
return value.text;
|
|
4694
|
+
}
|
|
4695
|
+
if (typeof value?.bytes === "string") {
|
|
4696
|
+
return Buffer.from(value.bytes, "base64").toString("utf8");
|
|
4697
|
+
}
|
|
4698
|
+
return "";
|
|
4699
|
+
}
|
|
4700
|
+
async function grepFilesWithRipgrep(params) {
|
|
4701
|
+
let rootIsDirectory;
|
|
4702
|
+
try {
|
|
4703
|
+
rootIsDirectory = (await params.fs.stat(params.root)).isDirectory();
|
|
4704
|
+
} catch (error) {
|
|
4705
|
+
if (isMissingPathError(error)) {
|
|
4706
|
+
return missingPathSearchResult({
|
|
4707
|
+
path: params.path ?? ".",
|
|
4708
|
+
displayPath: params.path ?? "."
|
|
4709
|
+
});
|
|
4710
|
+
}
|
|
4711
|
+
throw error;
|
|
4712
|
+
}
|
|
4713
|
+
const location = getRipgrepSearchLocation(params.root, rootIsDirectory);
|
|
4714
|
+
const args = ["--json", "--line-number", "--hidden", "--sort=path"];
|
|
4715
|
+
if (params.ignoreCase) {
|
|
4716
|
+
args.push("--ignore-case");
|
|
4717
|
+
}
|
|
4718
|
+
if (params.literal) {
|
|
4719
|
+
args.push("--fixed-strings");
|
|
4720
|
+
}
|
|
4721
|
+
if (params.glob) {
|
|
4722
|
+
args.push("--glob", params.glob);
|
|
4723
|
+
}
|
|
4724
|
+
for (const excludedGlob of RIPGREP_EXCLUDED_GLOBS) {
|
|
4725
|
+
args.push("--glob", excludedGlob);
|
|
4726
|
+
}
|
|
4727
|
+
if (params.context > 0) {
|
|
4728
|
+
args.push("--context", String(params.context));
|
|
4729
|
+
}
|
|
4730
|
+
args.push("--", params.pattern, location.target);
|
|
4731
|
+
const result = await params.runCommand({
|
|
4732
|
+
cmd: "rg",
|
|
4733
|
+
args,
|
|
4734
|
+
cwd: location.cwd
|
|
4735
|
+
});
|
|
4736
|
+
if (result.exitCode !== 0 && result.exitCode !== 1) {
|
|
4737
|
+
const detail = result.stderr.trim() || result.stdout.trim() || "command failed";
|
|
4738
|
+
if (/regex parse error|error parsing regex/i.test(detail)) {
|
|
4739
|
+
throw new ToolInputError(`Invalid regex pattern: ${params.pattern}`, {
|
|
4740
|
+
cause: new Error(detail)
|
|
4741
|
+
});
|
|
4742
|
+
}
|
|
4743
|
+
throw new Error(`ripgrep search failed: ${detail}`);
|
|
4744
|
+
}
|
|
4745
|
+
const recordsByPath = /* @__PURE__ */ new Map();
|
|
4746
|
+
const pathOrder = [];
|
|
4747
|
+
let totalMatches = 0;
|
|
4748
|
+
for (const rawLine of normalizeToLf(result.stdout).split("\n")) {
|
|
4749
|
+
if (!rawLine) {
|
|
4750
|
+
continue;
|
|
4751
|
+
}
|
|
4752
|
+
let record;
|
|
4753
|
+
try {
|
|
4754
|
+
record = JSON.parse(rawLine);
|
|
4755
|
+
} catch (error) {
|
|
4756
|
+
throw new Error("ripgrep returned invalid JSON output", { cause: error });
|
|
4757
|
+
}
|
|
4758
|
+
if (record.type !== "match" && record.type !== "context") {
|
|
4759
|
+
continue;
|
|
4760
|
+
}
|
|
4761
|
+
const line = record.data?.line_number;
|
|
4762
|
+
const rawPath = decodeRipgrepText(record.data?.path);
|
|
4763
|
+
if (!line || !rawPath) {
|
|
4764
|
+
continue;
|
|
4765
|
+
}
|
|
4766
|
+
const absolutePath = rawPath.startsWith("/") ? path6.posix.normalize(rawPath) : path6.posix.resolve(location.cwd, rawPath);
|
|
4767
|
+
const displayPath = rootIsDirectory ? path6.posix.relative(params.root, absolutePath) : path6.posix.basename(absolutePath);
|
|
4768
|
+
let records = recordsByPath.get(displayPath);
|
|
4769
|
+
if (!records) {
|
|
4770
|
+
records = [];
|
|
4771
|
+
recordsByPath.set(displayPath, records);
|
|
4772
|
+
pathOrder.push(displayPath);
|
|
4773
|
+
}
|
|
4774
|
+
const matched = record.type === "match";
|
|
4775
|
+
if (matched) {
|
|
4776
|
+
totalMatches += 1;
|
|
4777
|
+
}
|
|
4778
|
+
records.push({
|
|
4779
|
+
line,
|
|
4780
|
+
matched,
|
|
4781
|
+
text: decodeRipgrepText(record.data?.lines).replace(/\r?\n$/, "")
|
|
4782
|
+
});
|
|
4783
|
+
}
|
|
4784
|
+
let remainingMatches = params.limit;
|
|
4785
|
+
const output = [];
|
|
4786
|
+
let lineTruncated = false;
|
|
4787
|
+
for (const displayPath of pathOrder) {
|
|
4788
|
+
const records = recordsByPath.get(displayPath) ?? [];
|
|
4789
|
+
const selectedMatchLines = [];
|
|
4790
|
+
for (const record of records) {
|
|
4791
|
+
if (record.matched && remainingMatches > 0) {
|
|
4792
|
+
selectedMatchLines.push(record.line);
|
|
4793
|
+
remainingMatches -= 1;
|
|
4794
|
+
}
|
|
4795
|
+
}
|
|
4796
|
+
if (selectedMatchLines.length === 0) {
|
|
4797
|
+
continue;
|
|
4798
|
+
}
|
|
4799
|
+
const selectedMatchSet = new Set(selectedMatchLines);
|
|
4800
|
+
const emittedLines = /* @__PURE__ */ new Set();
|
|
4801
|
+
for (const record of records) {
|
|
4802
|
+
if (emittedLines.has(record.line)) {
|
|
4803
|
+
continue;
|
|
4804
|
+
}
|
|
4805
|
+
const include = selectedMatchLines.some(
|
|
4806
|
+
(matchLine) => Math.abs(record.line - matchLine) <= params.context
|
|
4807
|
+
);
|
|
4808
|
+
if (!include) {
|
|
4809
|
+
continue;
|
|
4810
|
+
}
|
|
4811
|
+
emittedLines.add(record.line);
|
|
4812
|
+
const truncated = truncateGrepLine(record.text);
|
|
4813
|
+
lineTruncated ||= truncated.truncated;
|
|
4814
|
+
const separator = selectedMatchSet.has(record.line) ? ":" : "-";
|
|
4815
|
+
output.push(
|
|
4816
|
+
`${displayPath}${separator}${record.line}${separator} ${truncated.line}`
|
|
4817
|
+
);
|
|
4818
|
+
}
|
|
4819
|
+
}
|
|
4820
|
+
const matchCount = Math.min(totalMatches, params.limit);
|
|
4821
|
+
const matchLimitReached = totalMatches > params.limit;
|
|
4822
|
+
const bounded = truncateText(
|
|
4823
|
+
output.length > 0 ? output.join("\n") : "No matches found"
|
|
4824
|
+
);
|
|
4825
|
+
const notices = [];
|
|
4826
|
+
if (matchLimitReached) {
|
|
4827
|
+
notices.push(
|
|
4828
|
+
`${params.limit} matches limit reached. Refine pattern or raise limit.`
|
|
4829
|
+
);
|
|
4830
|
+
}
|
|
4831
|
+
if (lineTruncated) {
|
|
4832
|
+
notices.push(
|
|
4833
|
+
`Some lines were truncated to ${MAX_GREP_LINE_CHARS} characters.`
|
|
4834
|
+
);
|
|
4835
|
+
}
|
|
4836
|
+
if (bounded.truncated) {
|
|
4837
|
+
notices.push(`${MAX_TEXT_CHARS} character output limit reached.`);
|
|
4838
|
+
}
|
|
4839
|
+
return makeStructuredToolResult({
|
|
4840
|
+
ok: true,
|
|
4841
|
+
status: "success",
|
|
4842
|
+
target: params.path ?? ".",
|
|
4843
|
+
path: params.path ?? ".",
|
|
4844
|
+
truncated: matchLimitReached || lineTruncated || bounded.truncated,
|
|
4845
|
+
data: {
|
|
4846
|
+
context: params.context,
|
|
4847
|
+
...params.glob ? { glob: params.glob } : {},
|
|
4848
|
+
line_count: output.length,
|
|
4849
|
+
lines: bounded.content === "No matches found" ? [] : bounded.content.split("\n"),
|
|
4850
|
+
match_count: matchCount,
|
|
4851
|
+
pattern: params.pattern,
|
|
4852
|
+
path: params.path ?? ".",
|
|
4853
|
+
...notices.length > 0 ? { truncation_reasons: notices } : {}
|
|
4854
|
+
},
|
|
4855
|
+
...matchLimitReached ? { match_limit_reached: params.limit } : {},
|
|
4856
|
+
...lineTruncated ? { line_truncated: true } : {}
|
|
4857
|
+
});
|
|
4858
|
+
}
|
|
4612
4859
|
function createGrepTool() {
|
|
4613
4860
|
return zodTool({
|
|
4614
4861
|
description: "Search sandbox workspace file contents. Returns bounded matching lines with file paths and line numbers. Respects path/glob filters and includes truncation notices.",
|
|
@@ -4738,6 +4985,7 @@ import { z as z8 } from "zod";
|
|
|
4738
4985
|
|
|
4739
4986
|
// src/chat/tool-support/text-range-result.ts
|
|
4740
4987
|
var DEFAULT_READ_LIMIT = 1e3;
|
|
4988
|
+
var MAX_READ_CHARS = 6e4;
|
|
4741
4989
|
function positiveInteger2(value) {
|
|
4742
4990
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
4743
4991
|
return void 0;
|
|
@@ -4757,16 +5005,42 @@ function sliceFileContent(params) {
|
|
|
4757
5005
|
const maxLines = requestedLimit ?? DEFAULT_READ_LIMIT;
|
|
4758
5006
|
const startIndex = Math.min(lines.length, startLine - 1);
|
|
4759
5007
|
const selected = lines.slice(startIndex, startIndex + maxLines);
|
|
4760
|
-
const
|
|
4761
|
-
|
|
5008
|
+
const returnedLines = [];
|
|
5009
|
+
let returnedCharacters = 0;
|
|
5010
|
+
let characterLimitReached = false;
|
|
5011
|
+
let lineTruncated = false;
|
|
5012
|
+
for (const line of selected) {
|
|
5013
|
+
const separatorLength = returnedLines.length > 0 ? 1 : 0;
|
|
5014
|
+
if (returnedCharacters + separatorLength + line.length <= MAX_READ_CHARS) {
|
|
5015
|
+
returnedLines.push(line);
|
|
5016
|
+
returnedCharacters += separatorLength + line.length;
|
|
5017
|
+
continue;
|
|
5018
|
+
}
|
|
5019
|
+
characterLimitReached = true;
|
|
5020
|
+
if (returnedLines.length === 0) {
|
|
5021
|
+
returnedLines.push(line.slice(0, MAX_READ_CHARS));
|
|
5022
|
+
lineTruncated = true;
|
|
5023
|
+
}
|
|
5024
|
+
break;
|
|
5025
|
+
}
|
|
5026
|
+
const endLine = returnedLines.length > 0 ? startLine + returnedLines.length - 1 : startLine - 1;
|
|
5027
|
+
const truncated = startIndex > 0 || endLine < lines.length || characterLimitReached;
|
|
4762
5028
|
const rangeRequested = requestedOffset !== void 0 || requestedLimit !== void 0;
|
|
4763
|
-
const returnedContent = !rangeRequested && !truncated ? params.content :
|
|
5029
|
+
const returnedContent = !rangeRequested && !truncated ? params.content : returnedLines.join("\n");
|
|
5030
|
+
const truncationReasons = [];
|
|
5031
|
+
if (characterLimitReached) {
|
|
5032
|
+
truncationReasons.push(`${MAX_READ_CHARS} character output limit reached.`);
|
|
5033
|
+
}
|
|
5034
|
+
if (lineTruncated) {
|
|
5035
|
+
truncationReasons.push(`Line ${startLine} was truncated.`);
|
|
5036
|
+
}
|
|
4764
5037
|
const range = {
|
|
4765
5038
|
content: returnedContent,
|
|
4766
5039
|
end_line: selected.length > 0 ? endLine : void 0,
|
|
4767
5040
|
path: params.path,
|
|
4768
5041
|
start_line: startLine,
|
|
4769
5042
|
total_lines: lines.length,
|
|
5043
|
+
...truncationReasons.length > 0 ? { truncation_reasons: truncationReasons } : {},
|
|
4770
5044
|
truncated
|
|
4771
5045
|
};
|
|
4772
5046
|
return makeStructuredToolResult({
|
|
@@ -4775,6 +5049,8 @@ function sliceFileContent(params) {
|
|
|
4775
5049
|
target: params.path,
|
|
4776
5050
|
data: range,
|
|
4777
5051
|
truncated,
|
|
5052
|
+
...characterLimitReached ? { character_limit_reached: MAX_READ_CHARS } : {},
|
|
5053
|
+
...lineTruncated ? { line_truncated: true } : {},
|
|
4778
5054
|
...endLine < lines.length ? {
|
|
4779
5055
|
continuation: {
|
|
4780
5056
|
arguments: {
|
|
@@ -4782,7 +5058,7 @@ function sliceFileContent(params) {
|
|
|
4782
5058
|
offset: endLine + 1,
|
|
4783
5059
|
limit: maxLines
|
|
4784
5060
|
},
|
|
4785
|
-
reason: "file has more lines"
|
|
5061
|
+
reason: characterLimitReached ? "character output limit reached; file has more lines" : "file has more lines"
|
|
4786
5062
|
}
|
|
4787
5063
|
} : {}
|
|
4788
5064
|
});
|
|
@@ -4918,6 +5194,30 @@ function createSandbox(options) {
|
|
|
4918
5194
|
onSandboxPrepare: options.prepare,
|
|
4919
5195
|
onSandboxRefChanged: options.onSandboxRefChanged
|
|
4920
5196
|
});
|
|
5197
|
+
const createToolCallContext = (signal) => {
|
|
5198
|
+
let fileSystemPromise;
|
|
5199
|
+
let commandRunnerPromise;
|
|
5200
|
+
return {
|
|
5201
|
+
signal,
|
|
5202
|
+
fileSystem() {
|
|
5203
|
+
signal?.throwIfAborted();
|
|
5204
|
+
return fileSystemPromise ??= runtime.tools().then(({ fs: fs5 }) => {
|
|
5205
|
+
signal?.throwIfAborted();
|
|
5206
|
+
return bindSandboxFileSystem(fs5, signal);
|
|
5207
|
+
});
|
|
5208
|
+
},
|
|
5209
|
+
commandRunner() {
|
|
5210
|
+
signal?.throwIfAborted();
|
|
5211
|
+
return commandRunnerPromise ??= runtime.tools().then(({ runCommand }) => {
|
|
5212
|
+
signal?.throwIfAborted();
|
|
5213
|
+
return async (input) => await runCommand({
|
|
5214
|
+
...input,
|
|
5215
|
+
...signal ? { signal } : {}
|
|
5216
|
+
});
|
|
5217
|
+
});
|
|
5218
|
+
}
|
|
5219
|
+
};
|
|
5220
|
+
};
|
|
4921
5221
|
const withSandboxSpan = (name, op, attributes, callback) => withSpan(name, op, traceContext, callback, attributes);
|
|
4922
5222
|
const withSandboxToolSpan = (name, op, attributes, callback) => withSandboxSpan(name, op, attributes, async () => {
|
|
4923
5223
|
await runtime.refreshNetworkPolicy(getTracePropagationHeaders());
|
|
@@ -4937,7 +5237,7 @@ function createSandbox(options) {
|
|
|
4937
5237
|
"Sandbox boot requested"
|
|
4938
5238
|
);
|
|
4939
5239
|
};
|
|
4940
|
-
const executeBashTool = async (rawInput, command,
|
|
5240
|
+
const executeBashTool = async (rawInput, command, context) => {
|
|
4941
5241
|
const env = parseEnv(rawInput.env);
|
|
4942
5242
|
const timeoutMs = positiveInteger(rawInput.timeoutMs);
|
|
4943
5243
|
logSandboxBootRequest("tool.bash", {
|
|
@@ -4957,7 +5257,7 @@ function createSandbox(options) {
|
|
|
4957
5257
|
command,
|
|
4958
5258
|
...env ? { env } : {},
|
|
4959
5259
|
...timeoutMs ? { timeoutMs } : {},
|
|
4960
|
-
...signal ? { signal } : {}
|
|
5260
|
+
...context.signal ? { signal: context.signal } : {}
|
|
4961
5261
|
});
|
|
4962
5262
|
setSpanAttributes({
|
|
4963
5263
|
"process.exit.code": response.exitCode,
|
|
@@ -4999,7 +5299,7 @@ function createSandbox(options) {
|
|
|
4999
5299
|
...permissionDenied ? { permission_denied: permissionDenied } : {}
|
|
5000
5300
|
});
|
|
5001
5301
|
};
|
|
5002
|
-
const executeReadFileTool = async (rawInput) => {
|
|
5302
|
+
const executeReadFileTool = async (rawInput, context) => {
|
|
5003
5303
|
const filePath = String(rawInput.path ?? "").trim();
|
|
5004
5304
|
if (!filePath) {
|
|
5005
5305
|
throw new ToolInputError("path is required");
|
|
@@ -5010,7 +5310,10 @@ function createSandbox(options) {
|
|
|
5010
5310
|
const hostPath = resolveHostSkillPath(options.skills, filePath) ?? resolveHostDataPath(options.referenceFiles, filePath);
|
|
5011
5311
|
if (hostPath) {
|
|
5012
5312
|
try {
|
|
5013
|
-
const content = await fs4.readFile(hostPath,
|
|
5313
|
+
const content = await fs4.readFile(hostPath, {
|
|
5314
|
+
encoding: "utf8",
|
|
5315
|
+
...context.signal ? { signal: context.signal } : {}
|
|
5316
|
+
});
|
|
5014
5317
|
setSpanAttributes({
|
|
5015
5318
|
"app.sandbox.path.length": filePath.length,
|
|
5016
5319
|
"app.sandbox.read.bytes": Buffer.byteLength(content, "utf8"),
|
|
@@ -5034,7 +5337,7 @@ function createSandbox(options) {
|
|
|
5034
5337
|
logSandboxBootRequest("tool.readFile", {
|
|
5035
5338
|
"file.path": filePath
|
|
5036
5339
|
});
|
|
5037
|
-
const
|
|
5340
|
+
const fileSystem = await context.fileSystem();
|
|
5038
5341
|
const result = await withSandboxToolSpan(
|
|
5039
5342
|
"sandbox.readFile",
|
|
5040
5343
|
"sandbox.fs.read",
|
|
@@ -5044,7 +5347,11 @@ function createSandbox(options) {
|
|
|
5044
5347
|
async () => {
|
|
5045
5348
|
let response;
|
|
5046
5349
|
try {
|
|
5047
|
-
response =
|
|
5350
|
+
response = {
|
|
5351
|
+
content: await fileSystem.readFile(resolveWorkspacePath(filePath), {
|
|
5352
|
+
encoding: "utf8"
|
|
5353
|
+
})
|
|
5354
|
+
};
|
|
5048
5355
|
} catch (error) {
|
|
5049
5356
|
if (isMissingPathError(error)) {
|
|
5050
5357
|
setSpanStatus("ok");
|
|
@@ -5070,16 +5377,17 @@ function createSandbox(options) {
|
|
|
5070
5377
|
);
|
|
5071
5378
|
return result;
|
|
5072
5379
|
};
|
|
5073
|
-
const executeWriteFileTool = async (rawInput) => {
|
|
5380
|
+
const executeWriteFileTool = async (rawInput, context) => {
|
|
5074
5381
|
const filePath = String(rawInput.path ?? "").trim();
|
|
5075
5382
|
if (!filePath) {
|
|
5076
5383
|
throw new ToolInputError("path is required");
|
|
5077
5384
|
}
|
|
5385
|
+
const workspacePath = resolveWorkspacePath(filePath);
|
|
5078
5386
|
const content = String(rawInput.content ?? "");
|
|
5079
5387
|
logSandboxBootRequest("tool.writeFile", {
|
|
5080
5388
|
"file.path": filePath
|
|
5081
5389
|
});
|
|
5082
|
-
const
|
|
5390
|
+
const fileSystem = await context.fileSystem();
|
|
5083
5391
|
await withSandboxToolSpan(
|
|
5084
5392
|
"sandbox.writeFile",
|
|
5085
5393
|
"sandbox.fs.write",
|
|
@@ -5089,8 +5397,13 @@ function createSandbox(options) {
|
|
|
5089
5397
|
},
|
|
5090
5398
|
async () => {
|
|
5091
5399
|
try {
|
|
5092
|
-
await
|
|
5400
|
+
await fileSystem.writeFile(workspacePath, content, {
|
|
5401
|
+
encoding: "utf8"
|
|
5402
|
+
});
|
|
5093
5403
|
} catch (error) {
|
|
5404
|
+
if (context.signal?.aborted) {
|
|
5405
|
+
throw error;
|
|
5406
|
+
}
|
|
5094
5407
|
throwSandboxOperationError("sandbox writeFile", error);
|
|
5095
5408
|
}
|
|
5096
5409
|
setSpanStatus("ok");
|
|
@@ -5108,7 +5421,7 @@ function createSandbox(options) {
|
|
|
5108
5421
|
bytes_written: Buffer.byteLength(content, "utf8")
|
|
5109
5422
|
});
|
|
5110
5423
|
};
|
|
5111
|
-
const executeEditFileTool = async (rawInput) => {
|
|
5424
|
+
const executeEditFileTool = async (rawInput, context) => {
|
|
5112
5425
|
const filePath = String(rawInput.path ?? "").trim();
|
|
5113
5426
|
if (!filePath) {
|
|
5114
5427
|
throw new ToolInputError("path is required");
|
|
@@ -5119,7 +5432,7 @@ function createSandbox(options) {
|
|
|
5119
5432
|
logSandboxBootRequest("tool.editFile", {
|
|
5120
5433
|
"file.path": filePath
|
|
5121
5434
|
});
|
|
5122
|
-
const
|
|
5435
|
+
const fileSystem = await context.fileSystem();
|
|
5123
5436
|
const result = await withSandboxToolSpan(
|
|
5124
5437
|
"sandbox.editFile",
|
|
5125
5438
|
"sandbox.fs.edit",
|
|
@@ -5129,7 +5442,7 @@ function createSandbox(options) {
|
|
|
5129
5442
|
},
|
|
5130
5443
|
async () => {
|
|
5131
5444
|
const response = await editFile({
|
|
5132
|
-
fs:
|
|
5445
|
+
fs: fileSystem,
|
|
5133
5446
|
path: filePath,
|
|
5134
5447
|
edits: rawInput.edits
|
|
5135
5448
|
});
|
|
@@ -5139,7 +5452,7 @@ function createSandbox(options) {
|
|
|
5139
5452
|
);
|
|
5140
5453
|
return result;
|
|
5141
5454
|
};
|
|
5142
|
-
const executeGrepTool = async (rawInput) => {
|
|
5455
|
+
const executeGrepTool = async (rawInput, context) => {
|
|
5143
5456
|
const pattern = String(rawInput.pattern ?? "");
|
|
5144
5457
|
if (!pattern) {
|
|
5145
5458
|
throw new ToolInputError("pattern is required");
|
|
@@ -5147,7 +5460,7 @@ function createSandbox(options) {
|
|
|
5147
5460
|
logSandboxBootRequest("tool.grep");
|
|
5148
5461
|
const contextLines = positiveInteger(rawInput.context);
|
|
5149
5462
|
const limit = positiveInteger(rawInput.limit);
|
|
5150
|
-
const
|
|
5463
|
+
const fileSystem = await context.fileSystem();
|
|
5151
5464
|
const result = await withSandboxToolSpan(
|
|
5152
5465
|
"sandbox.grep",
|
|
5153
5466
|
"sandbox.fs.search",
|
|
@@ -5156,7 +5469,8 @@ function createSandbox(options) {
|
|
|
5156
5469
|
},
|
|
5157
5470
|
async () => {
|
|
5158
5471
|
const response = await grepFiles({
|
|
5159
|
-
fs:
|
|
5472
|
+
fs: fileSystem,
|
|
5473
|
+
runCommand: await context.commandRunner(),
|
|
5160
5474
|
pattern,
|
|
5161
5475
|
...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
|
|
5162
5476
|
...typeof rawInput.glob === "string" ? { glob: rawInput.glob } : {},
|
|
@@ -5171,14 +5485,14 @@ function createSandbox(options) {
|
|
|
5171
5485
|
);
|
|
5172
5486
|
return result;
|
|
5173
5487
|
};
|
|
5174
|
-
const executeFindFilesTool = async (rawInput) => {
|
|
5488
|
+
const executeFindFilesTool = async (rawInput, context) => {
|
|
5175
5489
|
const pattern = String(rawInput.pattern ?? "");
|
|
5176
5490
|
if (!pattern) {
|
|
5177
5491
|
throw new ToolInputError("pattern is required");
|
|
5178
5492
|
}
|
|
5179
5493
|
logSandboxBootRequest("tool.findFiles");
|
|
5180
5494
|
const limit = positiveInteger(rawInput.limit);
|
|
5181
|
-
const
|
|
5495
|
+
const fileSystem = await context.fileSystem();
|
|
5182
5496
|
const result = await withSandboxToolSpan(
|
|
5183
5497
|
"sandbox.findFiles",
|
|
5184
5498
|
"sandbox.fs.find",
|
|
@@ -5187,7 +5501,8 @@ function createSandbox(options) {
|
|
|
5187
5501
|
},
|
|
5188
5502
|
async () => {
|
|
5189
5503
|
const response = await findFiles({
|
|
5190
|
-
fs:
|
|
5504
|
+
fs: fileSystem,
|
|
5505
|
+
runCommand: await context.commandRunner(),
|
|
5191
5506
|
pattern,
|
|
5192
5507
|
...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
|
|
5193
5508
|
...limit ? { limit } : {}
|
|
@@ -5198,17 +5513,17 @@ function createSandbox(options) {
|
|
|
5198
5513
|
);
|
|
5199
5514
|
return result;
|
|
5200
5515
|
};
|
|
5201
|
-
const executeListDirTool = async (rawInput) => {
|
|
5516
|
+
const executeListDirTool = async (rawInput, context) => {
|
|
5202
5517
|
logSandboxBootRequest("tool.listDir");
|
|
5203
5518
|
const limit = positiveInteger(rawInput.limit);
|
|
5204
|
-
const
|
|
5519
|
+
const fileSystem = await context.fileSystem();
|
|
5205
5520
|
const result = await withSandboxToolSpan(
|
|
5206
5521
|
"sandbox.listDir",
|
|
5207
5522
|
"sandbox.fs.list",
|
|
5208
5523
|
{},
|
|
5209
5524
|
async () => {
|
|
5210
5525
|
const response = await listDir({
|
|
5211
|
-
fs:
|
|
5526
|
+
fs: fileSystem,
|
|
5212
5527
|
...typeof rawInput.path === "string" ? { path: rawInput.path } : {},
|
|
5213
5528
|
...limit ? { limit } : {}
|
|
5214
5529
|
});
|
|
@@ -5220,6 +5535,7 @@ function createSandbox(options) {
|
|
|
5220
5535
|
};
|
|
5221
5536
|
const execute = async (params) => {
|
|
5222
5537
|
const rawInput = params.input ?? {};
|
|
5538
|
+
const context = createToolCallContext(params.signal);
|
|
5223
5539
|
const bashCommand2 = params.toolName === "bash" ? String(rawInput.command ?? "").trim() : void 0;
|
|
5224
5540
|
if (params.toolName === "bash") {
|
|
5225
5541
|
if (!bashCommand2) {
|
|
@@ -5228,27 +5544,28 @@ function createSandbox(options) {
|
|
|
5228
5544
|
}
|
|
5229
5545
|
try {
|
|
5230
5546
|
if (bashCommand2 !== void 0) {
|
|
5231
|
-
return await executeBashTool(rawInput, bashCommand2,
|
|
5547
|
+
return await executeBashTool(rawInput, bashCommand2, context);
|
|
5232
5548
|
}
|
|
5233
5549
|
if (params.toolName === "readFile") {
|
|
5234
|
-
return await executeReadFileTool(rawInput);
|
|
5550
|
+
return await executeReadFileTool(rawInput, context);
|
|
5235
5551
|
}
|
|
5236
5552
|
if (params.toolName === "editFile") {
|
|
5237
|
-
return await executeEditFileTool(rawInput);
|
|
5553
|
+
return await executeEditFileTool(rawInput, context);
|
|
5238
5554
|
}
|
|
5239
5555
|
if (params.toolName === "grep") {
|
|
5240
|
-
return await executeGrepTool(rawInput);
|
|
5556
|
+
return await executeGrepTool(rawInput, context);
|
|
5241
5557
|
}
|
|
5242
5558
|
if (params.toolName === "findFiles") {
|
|
5243
|
-
return await executeFindFilesTool(rawInput);
|
|
5559
|
+
return await executeFindFilesTool(rawInput, context);
|
|
5244
5560
|
}
|
|
5245
5561
|
if (params.toolName === "listDir") {
|
|
5246
|
-
return await executeListDirTool(rawInput);
|
|
5562
|
+
return await executeListDirTool(rawInput, context);
|
|
5247
5563
|
}
|
|
5248
5564
|
if (params.toolName === "writeFile") {
|
|
5249
|
-
return await executeWriteFileTool(rawInput);
|
|
5565
|
+
return await executeWriteFileTool(rawInput, context);
|
|
5250
5566
|
}
|
|
5251
5567
|
} catch (error) {
|
|
5568
|
+
params.signal?.throwIfAborted();
|
|
5252
5569
|
if (isSandboxUnavailableError(error)) {
|
|
5253
5570
|
throw createSandboxUnavailableToolError(params.toolName, error);
|
|
5254
5571
|
}
|
|
@@ -5295,6 +5612,9 @@ function createSandbox(options) {
|
|
|
5295
5612
|
},
|
|
5296
5613
|
sandboxRef() {
|
|
5297
5614
|
return runtime.sandboxRef();
|
|
5615
|
+
},
|
|
5616
|
+
close() {
|
|
5617
|
+
runtime.close();
|
|
5298
5618
|
}
|
|
5299
5619
|
};
|
|
5300
5620
|
}
|
|
@@ -5494,6 +5814,7 @@ function createAgentSandbox(options) {
|
|
|
5494
5814
|
return {
|
|
5495
5815
|
workspace: sandbox.workspace,
|
|
5496
5816
|
sandboxRef: sandbox.sandboxRef,
|
|
5817
|
+
close: sandbox.close,
|
|
5497
5818
|
tools: {
|
|
5498
5819
|
supports: sandbox.tools.supports,
|
|
5499
5820
|
async execute(params) {
|
|
@@ -6077,7 +6398,7 @@ var McpToolManager = class {
|
|
|
6077
6398
|
}
|
|
6078
6399
|
toManagedTool(plugin, client, tool) {
|
|
6079
6400
|
const outputSchema = toOptionalRecord(tool.outputSchema);
|
|
6080
|
-
const annotations =
|
|
6401
|
+
const annotations = tool.annotations;
|
|
6081
6402
|
return {
|
|
6082
6403
|
name: normalizeMcpToolName(plugin.manifest.name, tool.name),
|
|
6083
6404
|
description: describeMcpTool(plugin.manifest.name, tool),
|
|
@@ -6224,7 +6545,7 @@ function serializeMcpPayload(payload, privacy, options = {}) {
|
|
|
6224
6545
|
|
|
6225
6546
|
// src/chat/tools/sandbox/bash.ts
|
|
6226
6547
|
import { z as z10 } from "zod";
|
|
6227
|
-
function
|
|
6548
|
+
function createBashTool() {
|
|
6228
6549
|
return zodTool({
|
|
6229
6550
|
description: "Run a bash command inside the isolated sandbox workspace. Use this for repository inspection/execution tasks that need shell access. Do not use for network-sensitive or destructive actions unless explicitly required.",
|
|
6230
6551
|
inputSchema: z10.object({
|
|
@@ -9646,11 +9967,249 @@ function createSystemTimeTool() {
|
|
|
9646
9967
|
});
|
|
9647
9968
|
}
|
|
9648
9969
|
|
|
9649
|
-
// src/chat/tools/
|
|
9970
|
+
// src/chat/tools/query-conversation-events.ts
|
|
9650
9971
|
import { z as z36 } from "zod";
|
|
9972
|
+
var DEFAULT_LIMIT3 = 25;
|
|
9973
|
+
var MAX_LIMIT = 100;
|
|
9974
|
+
var CONVERSATION_EVENTS_TOOL_SOURCE = {
|
|
9975
|
+
id: "conversation-events",
|
|
9976
|
+
description: "Inspect Junior's durable conversation event log for debugging runtime behavior."
|
|
9977
|
+
};
|
|
9978
|
+
var knownEventTypeSchema = z36.enum(KNOWN_CONVERSATION_EVENT_TYPES);
|
|
9979
|
+
var projectedEventSchema = z36.object({
|
|
9980
|
+
seq: z36.number().int().nonnegative().describe("Stable event position; use it for pagination bounds."),
|
|
9981
|
+
history_version: z36.number().int().nonnegative().describe(
|
|
9982
|
+
"Model-history generation. It increments when handoff or compaction replaces active model context."
|
|
9983
|
+
),
|
|
9984
|
+
created_at: z36.iso.datetime().describe("When the event was recorded."),
|
|
9985
|
+
idempotency_key: z36.string().min(1).optional().describe("Retry-stable event identity, when one was assigned."),
|
|
9986
|
+
data: z36.record(z36.string(), z36.unknown()).describe(
|
|
9987
|
+
"Event payload. The type field identifies the event; replacement-history events report replacement_history_count instead of replaying the full model context."
|
|
9988
|
+
)
|
|
9989
|
+
}).strict();
|
|
9990
|
+
var queryConversationEventsOutputSchema = juniorToolResultSchema.extend({
|
|
9991
|
+
conversation_id: z36.string().min(1),
|
|
9992
|
+
events: z36.array(projectedEventSchema),
|
|
9993
|
+
has_older: z36.boolean().describe(
|
|
9994
|
+
"Whether matching events exist before this page; request them with before_seq set to the first returned seq."
|
|
9995
|
+
),
|
|
9996
|
+
has_newer: z36.boolean().describe(
|
|
9997
|
+
"Whether matching events exist after this page; request them with after_seq set to the last returned seq."
|
|
9998
|
+
)
|
|
9999
|
+
});
|
|
10000
|
+
function createQueryConversationEventsTool(context) {
|
|
10001
|
+
return zodTool({
|
|
10002
|
+
description: "Inspect Junior's stored turns, tool calls, handoffs, and compaction events when debugging its behavior. Returns events from the current conversation tree or another retained public conversation in the same Slack workspace, newest first by default.",
|
|
10003
|
+
exposure: "deferred",
|
|
10004
|
+
source: CONVERSATION_EVENTS_TOOL_SOURCE,
|
|
10005
|
+
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
10006
|
+
inputSchema: z36.object({
|
|
10007
|
+
conversation_id: z36.string().trim().min(1).describe(
|
|
10008
|
+
"Conversation ID to inspect, such as slack:{channelId}:{threadTs} or a child conversation id."
|
|
10009
|
+
),
|
|
10010
|
+
after_seq: z36.number().int().nonnegative().nullable().describe(
|
|
10011
|
+
"Exclusive lower bound on event seq. When set, returns the next newer page in ascending order."
|
|
10012
|
+
).optional(),
|
|
10013
|
+
before_seq: z36.number().int().nonnegative().nullable().describe(
|
|
10014
|
+
"Exclusive upper bound on event seq. Combine with defaults or after_seq to page older or bounded ranges."
|
|
10015
|
+
).optional(),
|
|
10016
|
+
limit: z36.number().int().min(1).max(MAX_LIMIT).nullable().describe(
|
|
10017
|
+
`Maximum events to return. Defaults to ${DEFAULT_LIMIT3}; max ${MAX_LIMIT}.`
|
|
10018
|
+
).optional(),
|
|
10019
|
+
types: z36.array(knownEventTypeSchema).min(1).nullable().describe(
|
|
10020
|
+
"Optional event-type filter. Omit to return every durable event type."
|
|
10021
|
+
).optional()
|
|
10022
|
+
}).strict(),
|
|
10023
|
+
outputSchema: queryConversationEventsOutputSchema,
|
|
10024
|
+
execute: async (input) => {
|
|
10025
|
+
const currentConversationId = context.conversationId?.trim();
|
|
10026
|
+
if (!currentConversationId) {
|
|
10027
|
+
throw new ToolInputError(
|
|
10028
|
+
"queryConversationEvents requires an active conversation"
|
|
10029
|
+
);
|
|
10030
|
+
}
|
|
10031
|
+
const conversationId = input.conversation_id;
|
|
10032
|
+
const afterSeq = input.after_seq ?? void 0;
|
|
10033
|
+
const beforeSeq = input.before_seq ?? void 0;
|
|
10034
|
+
const limit = input.limit ?? DEFAULT_LIMIT3;
|
|
10035
|
+
const types = input.types ?? void 0;
|
|
10036
|
+
if (afterSeq !== void 0 && beforeSeq !== void 0 && afterSeq >= beforeSeq) {
|
|
10037
|
+
throw new ToolInputError(
|
|
10038
|
+
"after_seq must be less than before_seq when both are provided"
|
|
10039
|
+
);
|
|
10040
|
+
}
|
|
10041
|
+
const conversationStore = getConversationStore();
|
|
10042
|
+
const target = await conversationStore.get({ conversationId });
|
|
10043
|
+
if (!target) {
|
|
10044
|
+
throw new ToolInputError(`Conversation not found: ${conversationId}`);
|
|
10045
|
+
}
|
|
10046
|
+
if (target.transcriptPurgedAtMs !== void 0) {
|
|
10047
|
+
throw new ToolInputError(
|
|
10048
|
+
`Conversation transcript was purged: ${conversationId}`
|
|
10049
|
+
);
|
|
10050
|
+
}
|
|
10051
|
+
const accessScope = await resolveAccessScope(
|
|
10052
|
+
conversationStore,
|
|
10053
|
+
context,
|
|
10054
|
+
currentConversationId
|
|
10055
|
+
);
|
|
10056
|
+
const targetRootConversationId = await resolveRootConversationId(
|
|
10057
|
+
conversationStore,
|
|
10058
|
+
conversationId,
|
|
10059
|
+
target.lineage?.parentConversationId
|
|
10060
|
+
);
|
|
10061
|
+
const targetRoot = targetRootConversationId === conversationId ? target : await conversationStore.get({
|
|
10062
|
+
conversationId: targetRootConversationId
|
|
10063
|
+
});
|
|
10064
|
+
assertCanQueryConversationEvents({
|
|
10065
|
+
accessScope,
|
|
10066
|
+
targetConversationId: conversationId,
|
|
10067
|
+
targetRootConversationId,
|
|
10068
|
+
targetVisibility: targetRoot?.visibility ?? target.visibility,
|
|
10069
|
+
targetDestination: targetRoot?.destination ?? target.destination
|
|
10070
|
+
});
|
|
10071
|
+
const page = await getConversationEventStore().query(conversationId, {
|
|
10072
|
+
limit,
|
|
10073
|
+
...afterSeq === void 0 ? {} : { afterSeq },
|
|
10074
|
+
...beforeSeq === void 0 ? {} : { beforeSeq },
|
|
10075
|
+
...types === void 0 ? {} : { types }
|
|
10076
|
+
});
|
|
10077
|
+
const events = projectEventsForTool(page);
|
|
10078
|
+
return {
|
|
10079
|
+
ok: true,
|
|
10080
|
+
status: "success",
|
|
10081
|
+
conversation_id: conversationId,
|
|
10082
|
+
events,
|
|
10083
|
+
has_older: page.hasOlder,
|
|
10084
|
+
has_newer: page.hasNewer
|
|
10085
|
+
};
|
|
10086
|
+
}
|
|
10087
|
+
});
|
|
10088
|
+
}
|
|
10089
|
+
async function resolveAccessScope(conversationStore, context, currentConversationId) {
|
|
10090
|
+
const current = await conversationStore.get({
|
|
10091
|
+
conversationId: currentConversationId
|
|
10092
|
+
});
|
|
10093
|
+
const currentRootConversationId = current ? await resolveRootConversationId(
|
|
10094
|
+
conversationStore,
|
|
10095
|
+
currentConversationId,
|
|
10096
|
+
current.lineage?.parentConversationId
|
|
10097
|
+
) : currentConversationId;
|
|
10098
|
+
if (context.source.platform === "slack") {
|
|
10099
|
+
return {
|
|
10100
|
+
currentConversationId,
|
|
10101
|
+
currentRootConversationId,
|
|
10102
|
+
provider: "slack",
|
|
10103
|
+
providerTenantId: context.source.teamId
|
|
10104
|
+
};
|
|
10105
|
+
}
|
|
10106
|
+
if (context.destination.platform === "slack" && "teamId" in context.destination) {
|
|
10107
|
+
return {
|
|
10108
|
+
currentConversationId,
|
|
10109
|
+
currentRootConversationId,
|
|
10110
|
+
provider: "slack",
|
|
10111
|
+
providerTenantId: context.destination.teamId
|
|
10112
|
+
};
|
|
10113
|
+
}
|
|
10114
|
+
return {
|
|
10115
|
+
currentConversationId,
|
|
10116
|
+
currentRootConversationId
|
|
10117
|
+
};
|
|
10118
|
+
}
|
|
10119
|
+
async function resolveRootConversationId(conversationStore, conversationId, parentConversationId) {
|
|
10120
|
+
if (!parentConversationId) {
|
|
10121
|
+
return conversationId;
|
|
10122
|
+
}
|
|
10123
|
+
let cursor = parentConversationId;
|
|
10124
|
+
const seen = /* @__PURE__ */ new Set([conversationId]);
|
|
10125
|
+
while (cursor) {
|
|
10126
|
+
if (seen.has(cursor)) {
|
|
10127
|
+
return conversationId;
|
|
10128
|
+
}
|
|
10129
|
+
seen.add(cursor);
|
|
10130
|
+
const parent = await conversationStore.get({ conversationId: cursor });
|
|
10131
|
+
if (!parent) {
|
|
10132
|
+
return conversationId;
|
|
10133
|
+
}
|
|
10134
|
+
if (!parent.lineage?.parentConversationId) {
|
|
10135
|
+
return parent.conversationId;
|
|
10136
|
+
}
|
|
10137
|
+
cursor = parent.lineage.parentConversationId;
|
|
10138
|
+
}
|
|
10139
|
+
return conversationId;
|
|
10140
|
+
}
|
|
10141
|
+
function assertCanQueryConversationEvents(args) {
|
|
10142
|
+
const {
|
|
10143
|
+
accessScope,
|
|
10144
|
+
targetConversationId,
|
|
10145
|
+
targetRootConversationId,
|
|
10146
|
+
targetVisibility,
|
|
10147
|
+
targetDestination
|
|
10148
|
+
} = args;
|
|
10149
|
+
if (targetConversationId === accessScope.currentConversationId || targetRootConversationId !== void 0 && targetRootConversationId === accessScope.currentRootConversationId) {
|
|
10150
|
+
return;
|
|
10151
|
+
}
|
|
10152
|
+
const publicPayloadAllowed = canExposeConversationPayload({
|
|
10153
|
+
conversationId: targetRootConversationId ?? targetConversationId,
|
|
10154
|
+
...targetVisibility ? { visibility: targetVisibility } : {},
|
|
10155
|
+
...targetDestination?.platform === "slack" ? { channelId: targetDestination.channelId } : {}
|
|
10156
|
+
});
|
|
10157
|
+
if (!publicPayloadAllowed) {
|
|
10158
|
+
throw new ToolInputError(
|
|
10159
|
+
`Conversation events are not accessible: ${targetConversationId}`
|
|
10160
|
+
);
|
|
10161
|
+
}
|
|
10162
|
+
if (accessScope.provider === "slack" && targetDestination?.platform === "slack" && accessScope.providerTenantId && targetDestination.teamId === accessScope.providerTenantId) {
|
|
10163
|
+
return;
|
|
10164
|
+
}
|
|
10165
|
+
throw new ToolInputError(
|
|
10166
|
+
`Conversation events are not accessible: ${targetConversationId}`
|
|
10167
|
+
);
|
|
10168
|
+
}
|
|
10169
|
+
function projectEventsForTool(page) {
|
|
10170
|
+
return page.events.map(projectEvent);
|
|
10171
|
+
}
|
|
10172
|
+
function projectEvent(event) {
|
|
10173
|
+
const data = stripReplacementHistory(event.data);
|
|
10174
|
+
return {
|
|
10175
|
+
seq: event.seq,
|
|
10176
|
+
history_version: event.historyVersion,
|
|
10177
|
+
created_at: new Date(event.createdAtMs).toISOString(),
|
|
10178
|
+
...event.idempotencyKey ? { idempotency_key: event.idempotencyKey } : {},
|
|
10179
|
+
data
|
|
10180
|
+
};
|
|
10181
|
+
}
|
|
10182
|
+
function stripReplacementHistory(data) {
|
|
10183
|
+
if (data.type === "unknown") {
|
|
10184
|
+
return {
|
|
10185
|
+
...data,
|
|
10186
|
+
payload: stripReplacementHistoryField(data.payload)
|
|
10187
|
+
};
|
|
10188
|
+
}
|
|
10189
|
+
if (data.type === "compaction" || data.type === "handoff") {
|
|
10190
|
+
return stripReplacementHistoryField(data);
|
|
10191
|
+
}
|
|
10192
|
+
return data;
|
|
10193
|
+
}
|
|
10194
|
+
function stripReplacementHistoryField(value) {
|
|
10195
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
10196
|
+
return value;
|
|
10197
|
+
}
|
|
10198
|
+
const { replacementHistory, ...rest } = value;
|
|
10199
|
+
if (replacementHistory === void 0) {
|
|
10200
|
+
return value;
|
|
10201
|
+
}
|
|
10202
|
+
return {
|
|
10203
|
+
...rest,
|
|
10204
|
+
replacement_history_count: Array.isArray(replacementHistory) ? replacementHistory.length : 0
|
|
10205
|
+
};
|
|
10206
|
+
}
|
|
10207
|
+
|
|
10208
|
+
// src/chat/tools/handoff/tool.ts
|
|
10209
|
+
import { z as z37 } from "zod";
|
|
9651
10210
|
var HANDOFF_TOOL_NAME = "handoff";
|
|
9652
10211
|
function createHandoffTool(handoff) {
|
|
9653
|
-
const profileSchema =
|
|
10212
|
+
const profileSchema = z37.enum(handoff.profiles);
|
|
9654
10213
|
const handoffResultSchema = juniorToolResultSchema.extend({
|
|
9655
10214
|
model_profile: profileSchema
|
|
9656
10215
|
});
|
|
@@ -9658,7 +10217,7 @@ function createHandoffTool(handoff) {
|
|
|
9658
10217
|
return zodTool({
|
|
9659
10218
|
description: `Switch to another execution profile and continue the same task. Profiles: ${profileNames}. Call this as the only tool.`,
|
|
9660
10219
|
executionMode: "sequential",
|
|
9661
|
-
inputSchema:
|
|
10220
|
+
inputSchema: z37.object({
|
|
9662
10221
|
profile: profileSchema.describe("Target execution profile")
|
|
9663
10222
|
}).strict(),
|
|
9664
10223
|
outputSchema: handoffResultSchema,
|
|
@@ -9681,7 +10240,7 @@ function createHandoffTool(handoff) {
|
|
|
9681
10240
|
}
|
|
9682
10241
|
|
|
9683
10242
|
// src/chat/tools/web/fetch-tool.ts
|
|
9684
|
-
import { z as
|
|
10243
|
+
import { z as z38 } from "zod";
|
|
9685
10244
|
|
|
9686
10245
|
// src/chat/tools/web/constants.ts
|
|
9687
10246
|
var USER_AGENT = "junior-bot/0.1";
|
|
@@ -10131,9 +10690,9 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
10131
10690
|
destructiveHint: false,
|
|
10132
10691
|
openWorldHint: true
|
|
10133
10692
|
},
|
|
10134
|
-
inputSchema:
|
|
10135
|
-
url:
|
|
10136
|
-
max_chars:
|
|
10693
|
+
inputSchema: z38.object({
|
|
10694
|
+
url: z38.string().min(1).describe("HTTP(S) URL to fetch."),
|
|
10695
|
+
max_chars: z38.coerce.number().int().min(500).max(MAX_FETCH_CHARS).describe("Optional maximum number of extracted characters to return.").optional()
|
|
10137
10696
|
}),
|
|
10138
10697
|
outputSchema: juniorToolResultSchema,
|
|
10139
10698
|
execute: async ({ url, max_chars }) => {
|
|
@@ -10194,7 +10753,7 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
10194
10753
|
}
|
|
10195
10754
|
|
|
10196
10755
|
// src/chat/tools/web/search.ts
|
|
10197
|
-
import { z as
|
|
10756
|
+
import { z as z39 } from "zod";
|
|
10198
10757
|
import { generateText } from "ai";
|
|
10199
10758
|
import { createGatewayProvider } from "@ai-sdk/gateway";
|
|
10200
10759
|
var SEARCH_TIMEOUT_MS = 6e4;
|
|
@@ -10243,9 +10802,9 @@ function createWebSearchTool(modelId, override) {
|
|
|
10243
10802
|
destructiveHint: false,
|
|
10244
10803
|
openWorldHint: true
|
|
10245
10804
|
},
|
|
10246
|
-
inputSchema:
|
|
10247
|
-
query:
|
|
10248
|
-
max_results:
|
|
10805
|
+
inputSchema: z39.object({
|
|
10806
|
+
query: z39.string().min(1).max(500).describe("Search query."),
|
|
10807
|
+
max_results: z39.coerce.number().int().min(1).max(MAX_RESULTS2).describe("Max results to return.").optional()
|
|
10249
10808
|
}),
|
|
10250
10809
|
outputSchema: juniorToolResultSchema,
|
|
10251
10810
|
execute: async ({ query, max_results }) => {
|
|
@@ -10314,14 +10873,14 @@ function createWebSearchTool(modelId, override) {
|
|
|
10314
10873
|
}
|
|
10315
10874
|
|
|
10316
10875
|
// src/chat/tools/sandbox/write-file.ts
|
|
10317
|
-
import { z as
|
|
10876
|
+
import { z as z40 } from "zod";
|
|
10318
10877
|
function createWriteFileTool() {
|
|
10319
10878
|
return zodTool({
|
|
10320
10879
|
description: "Write UTF-8 content to a file in the sandbox workspace. Use for intentional file creation or deliberate full-file replacement after validation; use editFile instead for targeted changes to existing files. Do not use for exploratory analysis-only turns.",
|
|
10321
10880
|
executionMode: "sequential",
|
|
10322
|
-
inputSchema:
|
|
10323
|
-
path:
|
|
10324
|
-
content:
|
|
10881
|
+
inputSchema: z40.object({
|
|
10882
|
+
path: z40.string().min(1).describe("Path to write in the sandbox workspace."),
|
|
10883
|
+
content: z40.string().describe("UTF-8 file content to write.")
|
|
10325
10884
|
}),
|
|
10326
10885
|
outputSchema: juniorToolResultSchema,
|
|
10327
10886
|
execute: async () => {
|
|
@@ -10374,7 +10933,7 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
10374
10933
|
}),
|
|
10375
10934
|
reportProgress: createReportProgressTool(),
|
|
10376
10935
|
systemTime: createSystemTimeTool(),
|
|
10377
|
-
bash:
|
|
10936
|
+
bash: createBashTool(),
|
|
10378
10937
|
readFile: createReadFileTool(),
|
|
10379
10938
|
editFile: createEditFileTool(),
|
|
10380
10939
|
grep: createGrepTool(),
|
|
@@ -10390,6 +10949,9 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
10390
10949
|
}),
|
|
10391
10950
|
...createResourceEventTools(context)
|
|
10392
10951
|
};
|
|
10952
|
+
if (context.conversationId) {
|
|
10953
|
+
tools.queryConversationEvents = createQueryConversationEventsTool(context);
|
|
10954
|
+
}
|
|
10393
10955
|
if (hooks.writeGeneratedArtifacts) {
|
|
10394
10956
|
tools.imageGenerate = createImageGenerateTool(
|
|
10395
10957
|
{
|
|
@@ -11063,17 +11625,17 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
11063
11625
|
}
|
|
11064
11626
|
|
|
11065
11627
|
// src/chat/tools/execute-tool.ts
|
|
11066
|
-
import { z as
|
|
11628
|
+
import { z as z41 } from "zod";
|
|
11067
11629
|
var EXECUTE_TOOL_NAME = "executeTool";
|
|
11068
11630
|
function createExecuteToolTool() {
|
|
11069
11631
|
return zodTool({
|
|
11070
11632
|
description: "Execute any catalog tool by exact tool_name from searchTools or a tool-result execution hint. Put tool-specific parameters inside arguments.",
|
|
11071
11633
|
executionMode: "sequential",
|
|
11072
|
-
inputSchema:
|
|
11073
|
-
tool_name:
|
|
11634
|
+
inputSchema: z41.object({
|
|
11635
|
+
tool_name: z41.string().min(1).describe(
|
|
11074
11636
|
"Exact catalog tool_name returned by searchTools or a tool-result execution hint."
|
|
11075
11637
|
),
|
|
11076
|
-
arguments:
|
|
11638
|
+
arguments: z41.record(z41.string(), z41.unknown()).describe(
|
|
11077
11639
|
'Arguments matching the selected catalog tool schema, for example { "query": "..." }.'
|
|
11078
11640
|
).optional()
|
|
11079
11641
|
}).strict(),
|
|
@@ -11113,42 +11675,42 @@ function planToolExposure(tools) {
|
|
|
11113
11675
|
}
|
|
11114
11676
|
|
|
11115
11677
|
// src/chat/tools/search-tools.ts
|
|
11116
|
-
import { z as
|
|
11678
|
+
import { z as z42 } from "zod";
|
|
11117
11679
|
var SEARCH_TOOLS_NAME = "searchTools";
|
|
11118
11680
|
var DEFAULT_MAX_RESULTS2 = 5;
|
|
11119
11681
|
var MAX_RESULTS3 = 20;
|
|
11120
11682
|
var MODEL_VISIBLE_DESCRIPTION_CAP = 180;
|
|
11121
|
-
var searchToolsSourceSchema =
|
|
11122
|
-
id:
|
|
11123
|
-
description:
|
|
11683
|
+
var searchToolsSourceSchema = z42.object({
|
|
11684
|
+
id: z42.string(),
|
|
11685
|
+
description: z42.string()
|
|
11124
11686
|
}).strict();
|
|
11125
|
-
var toolCallExampleSchema =
|
|
11126
|
-
tool_name:
|
|
11127
|
-
arguments:
|
|
11687
|
+
var toolCallExampleSchema = z42.object({
|
|
11688
|
+
tool_name: z42.string(),
|
|
11689
|
+
arguments: z42.record(z42.string(), z42.string())
|
|
11128
11690
|
}).strict();
|
|
11129
|
-
var searchToolsToolSchema =
|
|
11130
|
-
tool_name:
|
|
11131
|
-
description:
|
|
11132
|
-
exposure:
|
|
11133
|
-
source:
|
|
11134
|
-
signature:
|
|
11691
|
+
var searchToolsToolSchema = z42.object({
|
|
11692
|
+
tool_name: z42.string(),
|
|
11693
|
+
description: z42.string(),
|
|
11694
|
+
exposure: z42.enum(["direct", "deferred", "modelOnly", "hidden"]),
|
|
11695
|
+
source: z42.string().optional(),
|
|
11696
|
+
signature: z42.string(),
|
|
11135
11697
|
call: toolCallExampleSchema,
|
|
11136
|
-
input_schema:
|
|
11137
|
-
input_schema_summary:
|
|
11138
|
-
call_notes:
|
|
11139
|
-
annotations:
|
|
11698
|
+
input_schema: z42.unknown(),
|
|
11699
|
+
input_schema_summary: z42.string(),
|
|
11700
|
+
call_notes: z42.array(z42.string()),
|
|
11701
|
+
annotations: z42.record(z42.string(), z42.unknown())
|
|
11140
11702
|
}).strict();
|
|
11141
11703
|
var searchToolsOutputSchema = juniorToolResultSchema.extend({
|
|
11142
|
-
query:
|
|
11143
|
-
source:
|
|
11144
|
-
sources:
|
|
11145
|
-
total_catalog_tools:
|
|
11146
|
-
total_eligible_tools:
|
|
11147
|
-
total_matches:
|
|
11148
|
-
returned_tools:
|
|
11149
|
-
execution_tool:
|
|
11704
|
+
query: z42.string().nullable(),
|
|
11705
|
+
source: z42.string().nullable(),
|
|
11706
|
+
sources: z42.array(searchToolsSourceSchema),
|
|
11707
|
+
total_catalog_tools: z42.number().int().nonnegative(),
|
|
11708
|
+
total_eligible_tools: z42.number().int().nonnegative(),
|
|
11709
|
+
total_matches: z42.number().int().nonnegative(),
|
|
11710
|
+
returned_tools: z42.number().int().nonnegative(),
|
|
11711
|
+
execution_tool: z42.literal("executeTool"),
|
|
11150
11712
|
execution_example: toolCallExampleSchema,
|
|
11151
|
-
tools:
|
|
11713
|
+
tools: z42.array(searchToolsToolSchema)
|
|
11152
11714
|
}).strict();
|
|
11153
11715
|
function normalize2(value) {
|
|
11154
11716
|
return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
|
|
@@ -11340,14 +11902,14 @@ function createSearchToolsTool(catalogTools) {
|
|
|
11340
11902
|
return zodTool({
|
|
11341
11903
|
description: renderSearchToolsDescription(knownSources),
|
|
11342
11904
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
11343
|
-
inputSchema:
|
|
11344
|
-
query:
|
|
11905
|
+
inputSchema: z42.object({
|
|
11906
|
+
query: z42.string().nullable().describe(
|
|
11345
11907
|
"Optional search terms describing the tool, owner, action, or arguments needed. Empty string lists catalog tools."
|
|
11346
11908
|
).optional(),
|
|
11347
|
-
source:
|
|
11909
|
+
source: z42.string().nullable().describe(
|
|
11348
11910
|
"Optional source id to search within, such as a plugin source returned in sources."
|
|
11349
11911
|
).optional(),
|
|
11350
|
-
max_results:
|
|
11912
|
+
max_results: z42.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
|
|
11351
11913
|
}).strict(),
|
|
11352
11914
|
outputSchema: searchToolsOutputSchema,
|
|
11353
11915
|
privateTraceResult: (result) => ({
|
|
@@ -12859,6 +13421,21 @@ async function wireAgentTools(args) {
|
|
|
12859
13421
|
mcpToolManager,
|
|
12860
13422
|
pluginHooks,
|
|
12861
13423
|
getSandboxRef: agentSandbox.sandboxRef,
|
|
13424
|
+
async close() {
|
|
13425
|
+
agentSandbox.close();
|
|
13426
|
+
try {
|
|
13427
|
+
await mcpToolManager.close();
|
|
13428
|
+
} catch (closeError) {
|
|
13429
|
+
logWarn(
|
|
13430
|
+
"mcp_tool_manager_close_failed",
|
|
13431
|
+
{},
|
|
13432
|
+
{
|
|
13433
|
+
"exception.message": closeError instanceof Error ? closeError.message : String(closeError)
|
|
13434
|
+
},
|
|
13435
|
+
"Failed to close MCP tool manager"
|
|
13436
|
+
);
|
|
13437
|
+
}
|
|
13438
|
+
},
|
|
12862
13439
|
toolGuidance,
|
|
12863
13440
|
toolRuntimeContext
|
|
12864
13441
|
};
|
|
@@ -12884,6 +13461,7 @@ function createResumeState(args) {
|
|
|
12884
13461
|
channelName: args.channelName,
|
|
12885
13462
|
conversationId: args.conversationId,
|
|
12886
13463
|
destination: args.destination,
|
|
13464
|
+
...args.dispatchId ? { dispatchId: args.dispatchId } : {},
|
|
12887
13465
|
source: args.runSource,
|
|
12888
13466
|
sessionId: args.turnId,
|
|
12889
13467
|
loadedSkillNames: args.getLoadedSkillNames(),
|
|
@@ -13249,12 +13827,29 @@ function estimateHistoryTokens(messages) {
|
|
|
13249
13827
|
}
|
|
13250
13828
|
function buildReplacementProvenance(args) {
|
|
13251
13829
|
return [
|
|
13252
|
-
...args.retained.map(
|
|
13253
|
-
|
|
13254
|
-
|
|
13830
|
+
...args.retained.map((entry) => {
|
|
13831
|
+
const provenance = args.sourceProvenance[entry.sourceIndex];
|
|
13832
|
+
if (!provenance) {
|
|
13833
|
+
throw new Error("retained message provenance is missing");
|
|
13834
|
+
}
|
|
13835
|
+
return provenance;
|
|
13836
|
+
}),
|
|
13255
13837
|
contextProvenance
|
|
13256
13838
|
];
|
|
13257
13839
|
}
|
|
13840
|
+
async function loadLastInstruction(conversationId) {
|
|
13841
|
+
const event = await getConversationEventStore().loadLatestInstruction(conversationId);
|
|
13842
|
+
if (!event) return void 0;
|
|
13843
|
+
if (event.data.type === "user_message") {
|
|
13844
|
+
if (event.data.provenance.authority !== "instruction") return void 0;
|
|
13845
|
+
return {
|
|
13846
|
+
message: piMessageFromHistoryItem(event.data),
|
|
13847
|
+
provenance: event.data.provenance,
|
|
13848
|
+
sourceEventSeq: event.seq
|
|
13849
|
+
};
|
|
13850
|
+
}
|
|
13851
|
+
return void 0;
|
|
13852
|
+
}
|
|
13258
13853
|
function loadCompactionSource(messages) {
|
|
13259
13854
|
if (messages.length > 0) {
|
|
13260
13855
|
return {
|
|
@@ -13346,8 +13941,10 @@ ${summary}`)
|
|
|
13346
13941
|
replacementHistory: replacement.map((message, index) => {
|
|
13347
13942
|
const sourceEventSeq = index < retained.length ? sourceProjection.seqs[retained[index].sourceIndex] : void 0;
|
|
13348
13943
|
return {
|
|
13349
|
-
|
|
13350
|
-
|
|
13944
|
+
item: historyItemFromPiMessage(
|
|
13945
|
+
message,
|
|
13946
|
+
replacementProvenance[index]
|
|
13947
|
+
),
|
|
13351
13948
|
...sourceEventSeq === void 0 ? {} : { sourceEventSeq }
|
|
13352
13949
|
};
|
|
13353
13950
|
})
|
|
@@ -13399,8 +13996,7 @@ ${generatedSummary}`;
|
|
|
13399
13996
|
...args.triggeringToolCallId ? { triggeringToolCallId: args.triggeringToolCallId } : {},
|
|
13400
13997
|
summary: generatedSummary,
|
|
13401
13998
|
replacementHistory: replacementMessages.map((replacementMessage) => ({
|
|
13402
|
-
|
|
13403
|
-
provenance: contextProvenance
|
|
13999
|
+
item: historyItemFromPiMessage(replacementMessage, contextProvenance)
|
|
13404
14000
|
}))
|
|
13405
14001
|
}
|
|
13406
14002
|
});
|
|
@@ -13464,14 +14060,14 @@ ${summary}`;
|
|
|
13464
14060
|
...runtimeMessage,
|
|
13465
14061
|
content: [
|
|
13466
14062
|
...runtimeMessage.content,
|
|
13467
|
-
{ type: "text", text:
|
|
14063
|
+
{ type: "text", text: summaryText }
|
|
13468
14064
|
]
|
|
13469
14065
|
}
|
|
13470
|
-
] : [userMessage(
|
|
13471
|
-
const
|
|
13472
|
-
|
|
13473
|
-
|
|
13474
|
-
];
|
|
14066
|
+
] : [userMessage(summaryText)];
|
|
14067
|
+
const retainedInstruction = pendingMessages.length === 0 ? await loadLastInstruction(args.conversationId) : void 0;
|
|
14068
|
+
const instructionMessages = retainedInstruction ? [retainedInstruction.message] : pendingMessages.map((entry) => entry.message);
|
|
14069
|
+
const instructionProvenance = retainedInstruction ? [retainedInstruction.provenance] : pendingMessages.map((entry) => entry.provenance);
|
|
14070
|
+
const messages = [...summaryMessages, ...instructionMessages];
|
|
13475
14071
|
const replacementInputTokens = estimateHistoryTokens(messages);
|
|
13476
14072
|
if (replacementInputTokens >= inputLimitTokens) {
|
|
13477
14073
|
throw new ContextInputLimitExceededError(
|
|
@@ -13480,6 +14076,11 @@ ${summary}`;
|
|
|
13480
14076
|
);
|
|
13481
14077
|
}
|
|
13482
14078
|
const replacementMessages = stripRuntimeTurnContext(messages);
|
|
14079
|
+
if (replacementMessages.length !== 1 + instructionProvenance.length) {
|
|
14080
|
+
throw new Error(
|
|
14081
|
+
"persisted instruction provenance must align one-to-one with messages"
|
|
14082
|
+
);
|
|
14083
|
+
}
|
|
13483
14084
|
args.signal?.throwIfAborted();
|
|
13484
14085
|
await getConversationEventStore().replaceHistory(args.conversationId, {
|
|
13485
14086
|
createdAtMs: Date.now(),
|
|
@@ -13494,20 +14095,23 @@ ${summary}`;
|
|
|
13494
14095
|
triggerTokens,
|
|
13495
14096
|
inputLimitTokens,
|
|
13496
14097
|
inputMessageCount: source.messages.length,
|
|
13497
|
-
retainedMessageCount:
|
|
14098
|
+
retainedMessageCount: instructionMessages.length,
|
|
13498
14099
|
summaryChars: summary.length
|
|
13499
14100
|
},
|
|
13500
14101
|
summary,
|
|
13501
|
-
replacementHistory: replacementMessages.map((message, index) =>
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
14102
|
+
replacementHistory: replacementMessages.map((message, index) => {
|
|
14103
|
+
const provenance = index === 0 ? contextProvenance : instructionProvenance[index - 1];
|
|
14104
|
+
return {
|
|
14105
|
+
item: historyItemFromPiMessage(message, provenance),
|
|
14106
|
+
...index === 1 && retainedInstruction ? { sourceEventSeq: retainedInstruction.sourceEventSeq } : {}
|
|
14107
|
+
};
|
|
14108
|
+
})
|
|
13505
14109
|
}
|
|
13506
14110
|
});
|
|
13507
14111
|
setSpanAttributes({
|
|
13508
14112
|
"app.compaction.input_messages": source.messages.length,
|
|
13509
14113
|
"app.compaction.replacement_tokens": replacementInputTokens,
|
|
13510
|
-
"app.compaction.retained_messages":
|
|
14114
|
+
"app.compaction.retained_messages": instructionMessages.length,
|
|
13511
14115
|
"app.compaction.summary_chars": summary.length,
|
|
13512
14116
|
"app.compaction.trigger_tokens": triggerTokens,
|
|
13513
14117
|
"app.context_input_limit_tokens": inputLimitTokens,
|
|
@@ -13612,6 +14216,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
13612
14216
|
let resume;
|
|
13613
14217
|
let lastKnownSandboxRef = state.sandboxRef;
|
|
13614
14218
|
let mcpToolManager;
|
|
14219
|
+
let closeTools;
|
|
13615
14220
|
let connectedMcpProviders = /* @__PURE__ */ new Set();
|
|
13616
14221
|
let turnUsage;
|
|
13617
14222
|
let priorPhaseUsage;
|
|
@@ -13717,6 +14322,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
13717
14322
|
resume = createResumeState({
|
|
13718
14323
|
channelName: routing.slackConversation?.name,
|
|
13719
14324
|
destination: routing.destination,
|
|
14325
|
+
...routing.dispatch?.id ? { dispatchId: routing.dispatch.id } : {},
|
|
13720
14326
|
durability,
|
|
13721
14327
|
getLoadedSkillNames: () => loadedSkillNamesForResume,
|
|
13722
14328
|
getReasoningLevel: () => turnRoute?.reasoningLevel,
|
|
@@ -13977,6 +14583,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
13977
14583
|
userInput
|
|
13978
14584
|
});
|
|
13979
14585
|
mcpToolManager = wiring.mcpToolManager;
|
|
14586
|
+
closeTools = wiring.close;
|
|
13980
14587
|
const getPendingAuthPause = wiring.getPendingAuthPause;
|
|
13981
14588
|
const toolsAfterHandoff = wiring.agentTools;
|
|
13982
14589
|
const {
|
|
@@ -14576,18 +15183,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy, run
|
|
|
14576
15183
|
}
|
|
14577
15184
|
};
|
|
14578
15185
|
} finally {
|
|
14579
|
-
|
|
14580
|
-
await mcpToolManager?.close();
|
|
14581
|
-
} catch (closeError) {
|
|
14582
|
-
logWarn(
|
|
14583
|
-
"mcp_tool_manager_close_failed",
|
|
14584
|
-
{},
|
|
14585
|
-
{
|
|
14586
|
-
"exception.message": closeError instanceof Error ? closeError.message : String(closeError)
|
|
14587
|
-
},
|
|
14588
|
-
"Failed to close MCP tool manager"
|
|
14589
|
-
);
|
|
14590
|
-
}
|
|
15186
|
+
await closeTools?.();
|
|
14591
15187
|
}
|
|
14592
15188
|
}
|
|
14593
15189
|
|