@sentry/junior 0.105.0 → 0.107.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/dist/{agent-hooks-EOFSY2PD.js → agent-hooks-ICPIJAFY.js} +9 -7
- package/dist/api/conversations/detail.d.ts +1 -1
- package/dist/api/conversations/events.d.ts +14 -0
- package/dist/api/conversations/schema.d.ts +196 -463
- package/dist/api/schema.d.ts +2 -7
- package/dist/api/schema.js +10 -8
- package/dist/api.js +377 -810
- package/dist/app.js +2284 -2288
- package/dist/{catalog-runtime-5CVM2DOF.js → catalog-runtime-FOFNPR3P.js} +3 -2
- package/dist/chat/agent/prompt.d.ts +1 -1
- package/dist/chat/agent/request.d.ts +28 -29
- package/dist/chat/agent/resume.d.ts +7 -7
- package/dist/chat/agent/session.d.ts +5 -6
- package/dist/chat/agent/tools.d.ts +3 -3
- package/dist/chat/agent-dispatch/runner.d.ts +2 -0
- package/dist/chat/config.d.ts +3 -2
- package/dist/chat/conversations/history.d.ts +582 -167
- package/dist/chat/conversations/message-projection.d.ts +6 -0
- package/dist/chat/conversations/message-summaries.d.ts +9 -0
- package/dist/chat/conversations/messages.d.ts +13 -27
- package/dist/chat/conversations/projection.d.ts +30 -53
- package/dist/chat/conversations/provenance.d.ts +42 -0
- package/dist/chat/conversations/search.d.ts +2 -2
- package/dist/chat/conversations/sql/conversation-row.d.ts +1 -1
- package/dist/chat/conversations/sql/event-lock.d.ts +3 -0
- package/dist/chat/conversations/sql/history.d.ts +3 -3
- package/dist/chat/conversations/sql/privacy.d.ts +27 -0
- package/dist/chat/conversations/sql/purge.d.ts +2 -10
- package/dist/chat/conversations/sql/store.d.ts +0 -5
- package/dist/chat/conversations/store.d.ts +8 -13
- package/dist/chat/conversations/turn-lifecycle.d.ts +41 -0
- package/dist/chat/db.d.ts +4 -10
- package/dist/chat/model-profile.d.ts +10 -0
- package/dist/chat/oauth-flow.d.ts +0 -5
- package/dist/chat/pi/conversation-events.d.ts +33 -0
- package/dist/chat/pi/sql-model-usage.d.ts +10 -0
- package/dist/chat/plugins/agent-hooks.d.ts +4 -2
- package/dist/chat/resource-events/ingest.d.ts +0 -13
- package/dist/chat/runtime/delivered-turn-state.d.ts +1 -1
- package/dist/chat/runtime/generated-artifacts.d.ts +1 -1
- package/dist/chat/runtime/reply-executor.d.ts +2 -0
- package/dist/chat/runtime/slack-resume.d.ts +23 -28
- package/dist/chat/runtime/slack-runtime.d.ts +2 -0
- package/dist/chat/runtime/turn.d.ts +14 -1
- package/dist/chat/services/context-compaction-marker.d.ts +0 -1
- package/dist/chat/services/context-compaction.d.ts +1 -0
- package/dist/chat/services/conversation-memory.d.ts +9 -0
- package/dist/chat/services/plugin-auth-orchestration.d.ts +1 -4
- package/dist/chat/services/subscribed-decision.d.ts +1 -1
- package/dist/chat/services/turn-failure-response.d.ts +10 -3
- package/dist/chat/services/turn-limit.d.ts +6 -0
- package/dist/chat/services/turn-result.d.ts +7 -12
- package/dist/chat/services/{turn-reasoning-level.d.ts → turn-router.d.ts} +12 -8
- package/dist/chat/services/turn-session-record.d.ts +15 -17
- package/dist/chat/slack/adapter.d.ts +2 -2
- package/dist/chat/slack/errors.d.ts +2 -0
- package/dist/chat/slack/outbound.d.ts +0 -1
- package/dist/chat/slack/reply.d.ts +2 -8
- package/dist/chat/slack/tools/channel-capabilities.d.ts +2 -2
- package/dist/chat/slack/tools/{send-message.d.ts → send-files.d.ts} +27 -19
- package/dist/chat/state/conversation.d.ts +4 -4
- package/dist/chat/state/turn-id.d.ts +2 -0
- package/dist/chat/state/turn-session-keys.d.ts +6 -0
- package/dist/chat/state/turn-session.d.ts +11 -9
- package/dist/chat/task-execution/state.d.ts +6 -1
- package/dist/chat/task-execution/store.d.ts +1 -1
- package/dist/chat/tool-support/pi-tool-adapter.d.ts +1 -1
- package/dist/chat/tool-support/tool-execution-report.d.ts +1 -0
- package/dist/chat/tools/handoff/tool.d.ts +2 -2
- package/dist/chat/tools/sandbox/file-uploads.d.ts +28 -6
- package/dist/chat/tools/types.d.ts +6 -9
- package/dist/chat/tools/web/image-generate.d.ts +4 -6
- package/dist/{chunk-QDKRE3LS.js → chunk-4YF7Z6IA.js} +390 -270
- package/dist/{chunk-4PDVOHXP.js → chunk-AUUOHQAT.js} +2 -2
- package/dist/chunk-B2Z2H66D.js +250 -0
- package/dist/{chunk-QVTVCJR4.js → chunk-CQ7KSO2B.js} +75 -45
- package/dist/{chunk-MJSJAHBW.js → chunk-DY7TRYB5.js} +1 -1
- package/dist/{chunk-NJJFU6CP.js → chunk-EDLNHZH3.js} +883 -898
- package/dist/{chunk-O7ILGCMJ.js → chunk-IGHMVDWI.js} +134 -18
- package/dist/chunk-MU6HHZEN.js +99 -0
- package/dist/{chunk-BCULHGZK.js → chunk-NVOTGWYX.js} +458 -684
- package/dist/{chunk-AEWZ7F65.js → chunk-O24R4DCK.js} +2 -179
- package/dist/{chunk-CCFROYAV.js → chunk-PUAMO4PI.js} +115 -125
- package/dist/{chunk-VDHMFCDY.js → chunk-RMVOAJRL.js} +30 -13
- package/dist/{chunk-7G4J3CR7.js → chunk-SPUAJVVH.js} +6 -4
- package/dist/{chunk-M3UAVLEN.js → chunk-SS67LUOK.js} +43 -290
- package/dist/{chunk-FXFQNHRU.js → chunk-VFUK3X5B.js} +4 -2
- package/dist/{chunk-CCTCIISK.js → chunk-VH6KWKG2.js} +2 -2
- package/dist/chunk-VIXFG2VC.js +182 -0
- package/dist/{chunk-RMZ65YAA.js → chunk-YFQ7CQDE.js} +687 -21
- package/dist/{chunk-77LHNQK4.js → chunk-YIPD3L6L.js} +4 -2
- package/dist/{chunk-U26ZWZCN.js → chunk-YNP2ATQX.js} +6 -4
- package/dist/{chunk-WR7H7VLJ.js → chunk-YT72TOEK.js} +2 -2
- package/dist/cli/chat.js +21 -20
- package/dist/cli/check.js +4 -3
- package/dist/cli/plugins.js +11 -9
- package/dist/cli/snapshot-warmup.js +7 -5
- package/dist/cli/upgrade.js +2046 -105
- package/dist/db/schema/{agent-steps.d.ts → conversation-events.d.ts} +37 -21
- package/dist/db/schema.d.ts +28 -159
- package/dist/{db-PDMC67T3.js → db-DIGO4TGW.js} +6 -8
- package/dist/{runner-6A7MQRUE.js → runner-ACR2HAIC.js} +209 -101
- package/dist/{skills-722AXRV5.js → skills-ITNHBARB.js} +4 -3
- package/dist/{validation-EUI2UFRM.js → validation-AGQ46ZGV.js} +4 -3
- package/migrations/0005_conversation_events.sql +122 -0
- package/migrations/README.md +23 -10
- package/migrations/meta/0005_snapshot.json +948 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/dist/api/conversations/activity.d.ts +0 -40
- package/dist/api/conversations/detail-projection.d.ts +0 -11
- package/dist/api/conversations/detail.query.d.ts +0 -3
- package/dist/api/conversations/subagent.d.ts +0 -10
- package/dist/api/conversations/transcript.d.ts +0 -28
- package/dist/chat/conversations/legacy-advisor-session.d.ts +0 -7
- package/dist/chat/conversations/legacy-import.d.ts +0 -38
- package/dist/chat/conversations/sql/legacy-history-import.d.ts +0 -55
- package/dist/chat/conversations/sql/messages.d.ts +0 -4
- package/dist/chat/conversations/visible-compactions.d.ts +0 -11
- package/dist/chat/conversations/visible-messages.d.ts +0 -47
- package/dist/chat/services/reply-delivery-plan.d.ts +0 -5
- package/dist/chat/state/session-log.d.ts +0 -384
- package/dist/chunk-RYDF4GOX.js +0 -1072
- package/dist/chunk-XIMUQ4IU.js +0 -147
- package/dist/db/schema/conversation-messages.d.ts +0 -153
- package/dist/handlers/github-webhook/check-suite.d.ts +0 -3
- package/dist/handlers/github-webhook/issue-comment.d.ts +0 -3
- package/dist/handlers/github-webhook/pull-request-review-comment.d.ts +0 -3
- package/dist/handlers/github-webhook/pull-request-review.d.ts +0 -3
- package/dist/handlers/github-webhook/pull-request.d.ts +0 -3
- package/dist/handlers/github-webhook/resource.d.ts +0 -10
- package/dist/handlers/github-webhook.d.ts +0 -15
- package/dist/legacy-import-G333RHJZ.js +0 -18
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CooperativeTurnYieldError,
|
|
3
3
|
TurnInputCommitLostError,
|
|
4
|
+
TurnSliceLimitExceededError,
|
|
4
5
|
abandonReplacedPendingAuth,
|
|
5
6
|
canReusePendingAuthLink,
|
|
7
|
+
estimateTextTokens,
|
|
8
|
+
getAgentContextCompactionTriggerTokens,
|
|
6
9
|
getInterruptionMarker,
|
|
7
10
|
isTurnInputCommitLostError,
|
|
8
11
|
loadTurnSessionRecord,
|
|
9
12
|
mergeArtifactsState,
|
|
10
13
|
persistAuthPauseSessionRecord,
|
|
14
|
+
persistContinuationSessionRecord,
|
|
11
15
|
persistRunningSessionRecord,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
} from "./chunk-
|
|
16
|
+
persistYieldSessionRecord,
|
|
17
|
+
updateConversationStats
|
|
18
|
+
} from "./chunk-YFQ7CQDE.js";
|
|
15
19
|
import {
|
|
16
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
17
|
-
|
|
20
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
21
|
+
loadConnectedMcpProviders,
|
|
22
|
+
loadConversationProjection,
|
|
23
|
+
openConversationProjection,
|
|
24
|
+
recordAuthorizationRequested,
|
|
25
|
+
recordMcpProviderConnected,
|
|
26
|
+
recordToolExecutionStarted
|
|
27
|
+
} from "./chunk-4YF7Z6IA.js";
|
|
18
28
|
import {
|
|
19
29
|
buildNonInteractiveShellScript,
|
|
20
30
|
createSandboxInstance,
|
|
@@ -24,22 +34,11 @@ import {
|
|
|
24
34
|
isSnapshotMissingError,
|
|
25
35
|
resolveRuntimeDependencySnapshot,
|
|
26
36
|
runNonInteractiveCommand
|
|
27
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-SPUAJVVH.js";
|
|
28
38
|
import {
|
|
29
39
|
addAgentTurnUsage,
|
|
30
|
-
hasAgentTurnUsage
|
|
31
|
-
|
|
32
|
-
loadConversationProjection,
|
|
33
|
-
openConversationProjection,
|
|
34
|
-
recordAuthorizationRequested,
|
|
35
|
-
recordMcpProviderConnected,
|
|
36
|
-
recordToolExecutionStarted
|
|
37
|
-
} from "./chunk-QDKRE3LS.js";
|
|
38
|
-
import {
|
|
39
|
-
estimateTextTokens,
|
|
40
|
-
getAgentContextCompactionTriggerTokens,
|
|
41
|
-
updateConversationStats
|
|
42
|
-
} from "./chunk-RYDF4GOX.js";
|
|
40
|
+
hasAgentTurnUsage
|
|
41
|
+
} from "./chunk-MU6HHZEN.js";
|
|
43
42
|
import {
|
|
44
43
|
privateTraceResultAttributes
|
|
45
44
|
} from "./chunk-UIE3R5XU.js";
|
|
@@ -51,10 +50,10 @@ import {
|
|
|
51
50
|
getPlugins,
|
|
52
51
|
getSlackToolContext,
|
|
53
52
|
resolveChannelCapabilities
|
|
54
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-RMVOAJRL.js";
|
|
55
54
|
import {
|
|
56
55
|
createPluginLogger
|
|
57
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-AUUOHQAT.js";
|
|
58
57
|
import {
|
|
59
58
|
SANDBOX_DATA_ROOT,
|
|
60
59
|
SANDBOX_SKILLS_ROOT,
|
|
@@ -62,6 +61,10 @@ import {
|
|
|
62
61
|
sandboxSkillDir,
|
|
63
62
|
sandboxSkillFile
|
|
64
63
|
} from "./chunk-G3E7SCME.js";
|
|
64
|
+
import {
|
|
65
|
+
acquireActiveLock,
|
|
66
|
+
getStateAdapter
|
|
67
|
+
} from "./chunk-B2Z2H66D.js";
|
|
65
68
|
import {
|
|
66
69
|
SlackActionError,
|
|
67
70
|
downloadPrivateSlackFile,
|
|
@@ -71,16 +74,16 @@ import {
|
|
|
71
74
|
isDmChannel,
|
|
72
75
|
normalizeSlackConversationId,
|
|
73
76
|
withSlackRetries
|
|
74
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-VH6KWKG2.js";
|
|
75
78
|
import {
|
|
76
79
|
contextProvenance,
|
|
77
|
-
|
|
80
|
+
getConversationEventStore,
|
|
78
81
|
getConversationSearchStore,
|
|
79
82
|
getConversationStore,
|
|
80
83
|
getDb,
|
|
81
84
|
instructionActors,
|
|
82
85
|
instructionProvenanceFor
|
|
83
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-NVOTGWYX.js";
|
|
84
87
|
import {
|
|
85
88
|
sleep
|
|
86
89
|
} from "./chunk-4ZNGQH7C.js";
|
|
@@ -96,7 +99,6 @@ import {
|
|
|
96
99
|
STANDARD_MODEL_PROFILE,
|
|
97
100
|
TURN_CONTEXT_TAG,
|
|
98
101
|
TURN_REASONING_LEVELS,
|
|
99
|
-
acquireActiveLock,
|
|
100
102
|
botConfig,
|
|
101
103
|
completeObject,
|
|
102
104
|
completeText,
|
|
@@ -104,7 +106,6 @@ import {
|
|
|
104
106
|
extractAssistantText,
|
|
105
107
|
getGatewayApiKey,
|
|
106
108
|
getPiGatewayApiKey,
|
|
107
|
-
getStateAdapter,
|
|
108
109
|
getTerminalAssistantMessages,
|
|
109
110
|
hasCompactedConversationContext,
|
|
110
111
|
hasRuntimeTurnContext,
|
|
@@ -114,16 +115,18 @@ import {
|
|
|
114
115
|
isToolResultError,
|
|
115
116
|
isToolResultMessage,
|
|
116
117
|
modelIdForProfile,
|
|
118
|
+
modelProfileSchema,
|
|
117
119
|
nextProviderRetry,
|
|
118
120
|
normalizeSlackEmojiName,
|
|
119
121
|
normalizeToolNameFromResult,
|
|
122
|
+
profileConfig,
|
|
120
123
|
renderCurrentInstruction,
|
|
121
124
|
resolveGatewayModel,
|
|
122
125
|
retainRuntimeTurnContext,
|
|
123
126
|
stripRuntimeTurnContext,
|
|
124
127
|
trimTrailingAssistantMessages,
|
|
125
128
|
unwrapCurrentInstruction
|
|
126
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-SS67LUOK.js";
|
|
127
130
|
import {
|
|
128
131
|
parseSlackThreadId,
|
|
129
132
|
resolveConversationPrivacy,
|
|
@@ -142,21 +145,22 @@ import {
|
|
|
142
145
|
findSkillByName,
|
|
143
146
|
loadSkillsByName,
|
|
144
147
|
parseSkillInvocation
|
|
145
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-YT72TOEK.js";
|
|
146
149
|
import {
|
|
147
150
|
CredentialUnavailableError,
|
|
148
151
|
credentialContextSchema,
|
|
149
152
|
pluginCatalogRuntime,
|
|
150
153
|
resolveAuthTokenPlaceholder,
|
|
151
154
|
resolvePluginCommandEnv
|
|
152
|
-
} from "./chunk-
|
|
155
|
+
} from "./chunk-YIPD3L6L.js";
|
|
156
|
+
import {
|
|
157
|
+
isUserActor
|
|
158
|
+
} from "./chunk-VIXFG2VC.js";
|
|
153
159
|
import {
|
|
154
|
-
createActor,
|
|
155
160
|
extractGenAiUsageAttributes,
|
|
156
161
|
extractGenAiUsageSummary,
|
|
157
162
|
getLogContextAttributesForSpan,
|
|
158
163
|
getTracePropagationHeaders,
|
|
159
|
-
isUserActor,
|
|
160
164
|
logError,
|
|
161
165
|
logException,
|
|
162
166
|
logInfo,
|
|
@@ -168,7 +172,7 @@ import {
|
|
|
168
172
|
setTags,
|
|
169
173
|
summarizeMessageText,
|
|
170
174
|
withSpan
|
|
171
|
-
} from "./chunk-
|
|
175
|
+
} from "./chunk-O24R4DCK.js";
|
|
172
176
|
import {
|
|
173
177
|
isRecord
|
|
174
178
|
} from "./chunk-OB42YVAE.js";
|
|
@@ -668,27 +672,10 @@ function isRawToolPayloadResponse(text) {
|
|
|
668
672
|
if (isToolPayloadShape(parsed)) {
|
|
669
673
|
return true;
|
|
670
674
|
}
|
|
671
|
-
|
|
672
|
-
return /"type"\s*:\s*"tool[-_](use|call|result|error)"/i.test(compact);
|
|
675
|
+
return false;
|
|
673
676
|
}
|
|
674
|
-
var POST_CANVAS_REPLY_MAX_CHARS = 700;
|
|
675
|
-
var POST_CANVAS_REPLY_MAX_LINES = 8;
|
|
676
677
|
var THINKING_XML_BLOCK_PATTERN = /[ \t]*<thinking\b[^>]*>[\s\S]*?<\/thinking>[ \t]*(?:\r?\n)?/gi;
|
|
677
678
|
var FENCED_CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
|
|
678
|
-
function isVerbosePostCanvasReply(text) {
|
|
679
|
-
const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
680
|
-
return text.length > POST_CANVAS_REPLY_MAX_CHARS || lines.length > POST_CANVAS_REPLY_MAX_LINES;
|
|
681
|
-
}
|
|
682
|
-
function getCreatedCanvasUrl(artifactStatePatch) {
|
|
683
|
-
if (artifactStatePatch.lastCanvasUrl) {
|
|
684
|
-
return artifactStatePatch.lastCanvasUrl;
|
|
685
|
-
}
|
|
686
|
-
return artifactStatePatch.recentCanvases?.find((canvas) => canvas.url)?.url;
|
|
687
|
-
}
|
|
688
|
-
function buildBriefPostCanvasReply(artifactStatePatch) {
|
|
689
|
-
const canvasUrl = getCreatedCanvasUrl(artifactStatePatch);
|
|
690
|
-
return canvasUrl ? `I created a canvas with the full reference: ${canvasUrl}` : "I created a canvas with the full reference.";
|
|
691
|
-
}
|
|
692
679
|
function stripThinkingXmlBlocks(text) {
|
|
693
680
|
let result = "";
|
|
694
681
|
let cursor = 0;
|
|
@@ -704,6 +691,23 @@ function stripThinkingXmlBlocks(text) {
|
|
|
704
691
|
result += text.slice(cursor).replace(THINKING_XML_BLOCK_PATTERN, "");
|
|
705
692
|
return result;
|
|
706
693
|
}
|
|
694
|
+
function getVisibleAssistantText(rawText) {
|
|
695
|
+
const text = stripThinkingXmlBlocks(rawText).trim();
|
|
696
|
+
if (!text || isNoReplyMarker(text) || containsNoReplyMarker(text) || isRawToolPayloadResponse(text)) {
|
|
697
|
+
return void 0;
|
|
698
|
+
}
|
|
699
|
+
return text;
|
|
700
|
+
}
|
|
701
|
+
function getAssistantMessageText(message) {
|
|
702
|
+
if (message.content.some((part) => part.type === "toolCall")) {
|
|
703
|
+
return void 0;
|
|
704
|
+
}
|
|
705
|
+
const text = getVisibleAssistantText(extractAssistantText(message));
|
|
706
|
+
if (!text) {
|
|
707
|
+
return void 0;
|
|
708
|
+
}
|
|
709
|
+
return isExecutionEscapeResponse(text) ? void 0 : text;
|
|
710
|
+
}
|
|
707
711
|
function buildTurnResult(input) {
|
|
708
712
|
const {
|
|
709
713
|
newMessages,
|
|
@@ -715,8 +719,7 @@ function buildTurnResult(input) {
|
|
|
715
719
|
shouldTrace,
|
|
716
720
|
spanContext,
|
|
717
721
|
usage,
|
|
718
|
-
|
|
719
|
-
correlation,
|
|
722
|
+
executionProfile,
|
|
720
723
|
assistantUserName,
|
|
721
724
|
modelId
|
|
722
725
|
} = input;
|
|
@@ -729,20 +732,16 @@ function buildTurnResult(input) {
|
|
|
729
732
|
const exactNoReplyMarker = isNoReplyMarker(rawPrimaryText);
|
|
730
733
|
const mixedNoReplyMarker = !exactNoReplyMarker && containsNoReplyMarker(rawPrimaryText);
|
|
731
734
|
const noReplyRequested = exactNoReplyMarker || mixedNoReplyMarker;
|
|
732
|
-
const primaryText = noReplyRequested ? "" :
|
|
735
|
+
const primaryText = noReplyRequested ? "" : terminalAssistantMessages.map((message) => getAssistantMessageText(message)).filter((text) => Boolean(text)).join("\n\n");
|
|
733
736
|
const toolErrorCount = toolResults.filter((result) => result.isError).length;
|
|
734
|
-
const
|
|
735
|
-
(result) => !isToolResultError(result)
|
|
736
|
-
);
|
|
737
|
-
const successfulToolNames = new Set(
|
|
738
|
-
successfulToolResults.map((result) => normalizeToolNameFromResult(result)).filter((value) => Boolean(value))
|
|
737
|
+
const reactionPerformed = toolResults.some(
|
|
738
|
+
(result) => !isToolResultError(result) && normalizeToolNameFromResult(result) === "addReaction"
|
|
739
739
|
);
|
|
740
|
-
const
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
postThreadText: true
|
|
740
|
+
const completedWithoutTerminalText = noReplyRequested;
|
|
741
|
+
const resultLogContext = {
|
|
742
|
+
...spanContext,
|
|
743
|
+
assistantUserName,
|
|
744
|
+
modelId
|
|
746
745
|
};
|
|
747
746
|
const lastAssistant = terminalAssistantMessages.at(-1);
|
|
748
747
|
const stopReason = typeof lastAssistant?.stopReason === "string" ? lastAssistant.stopReason : void 0;
|
|
@@ -750,14 +749,7 @@ function buildTurnResult(input) {
|
|
|
750
749
|
const isProviderError = stopReason === "error";
|
|
751
750
|
if (exactNoReplyMarker) {
|
|
752
751
|
const markerCategory = reactionPerformed ? "reaction" : "none";
|
|
753
|
-
const markerContext =
|
|
754
|
-
slackThreadId: correlation?.threadId,
|
|
755
|
-
slackUserId: correlation?.actorId,
|
|
756
|
-
slackChannelId: correlation?.channelId,
|
|
757
|
-
runId: correlation?.runId,
|
|
758
|
-
assistantUserName,
|
|
759
|
-
modelId
|
|
760
|
-
};
|
|
752
|
+
const markerContext = resultLogContext;
|
|
761
753
|
const markerAttributes = {
|
|
762
754
|
"app.ai.no_reply_marker": true,
|
|
763
755
|
"app.ai.no_reply_marker_category": markerCategory,
|
|
@@ -774,14 +766,7 @@ function buildTurnResult(input) {
|
|
|
774
766
|
} else if (mixedNoReplyMarker) {
|
|
775
767
|
logWarn(
|
|
776
768
|
"ai_no_reply_marker_mixed_text",
|
|
777
|
-
|
|
778
|
-
slackThreadId: correlation?.threadId,
|
|
779
|
-
slackUserId: correlation?.actorId,
|
|
780
|
-
slackChannelId: correlation?.channelId,
|
|
781
|
-
runId: correlation?.runId,
|
|
782
|
-
assistantUserName,
|
|
783
|
-
modelId
|
|
784
|
-
},
|
|
769
|
+
resultLogContext,
|
|
785
770
|
{
|
|
786
771
|
"app.ai.no_reply_marker": true,
|
|
787
772
|
"app.ai.no_reply_marker_mode": "mixed"
|
|
@@ -789,17 +774,10 @@ function buildTurnResult(input) {
|
|
|
789
774
|
"No-reply marker appeared with visible assistant text"
|
|
790
775
|
);
|
|
791
776
|
}
|
|
792
|
-
if (!primaryText && !
|
|
777
|
+
if (!primaryText && !completedWithoutTerminalText && !isProviderError) {
|
|
793
778
|
logWarn(
|
|
794
779
|
"ai_model_response_empty",
|
|
795
|
-
|
|
796
|
-
slackThreadId: correlation?.threadId,
|
|
797
|
-
slackUserId: correlation?.actorId,
|
|
798
|
-
slackChannelId: correlation?.channelId,
|
|
799
|
-
runId: correlation?.runId,
|
|
800
|
-
assistantUserName,
|
|
801
|
-
modelId
|
|
802
|
-
},
|
|
780
|
+
resultLogContext,
|
|
803
781
|
{
|
|
804
782
|
"app.ai.tool_results": toolResults.length,
|
|
805
783
|
"app.ai.tool_error_results": toolErrorCount,
|
|
@@ -812,29 +790,23 @@ function buildTurnResult(input) {
|
|
|
812
790
|
let outcome;
|
|
813
791
|
if (isProviderError) {
|
|
814
792
|
outcome = "provider_error";
|
|
815
|
-
} else if (primaryText ||
|
|
793
|
+
} else if (primaryText || completedWithoutTerminalText) {
|
|
816
794
|
outcome = "success";
|
|
817
795
|
} else {
|
|
818
796
|
outcome = "execution_failure";
|
|
819
797
|
}
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
const
|
|
824
|
-
const resolvedOutcome = escapedOrRawPayload ? "execution_failure" : outcome;
|
|
825
|
-
const deliveryPlan = resolvedOutcome === "success" && !resolvedText ? {
|
|
826
|
-
...baseDeliveryPlan,
|
|
827
|
-
postThreadText: false
|
|
828
|
-
} : baseDeliveryPlan;
|
|
829
|
-
const deliveryMode = deliveryPlan.mode;
|
|
798
|
+
const rejectedPrimaryText = Boolean(
|
|
799
|
+
rawPrimaryText && !noReplyRequested && !primaryText
|
|
800
|
+
);
|
|
801
|
+
const resolvedOutcome = rejectedPrimaryText ? "execution_failure" : outcome;
|
|
830
802
|
if (shouldTrace) {
|
|
831
803
|
logInfo(
|
|
832
804
|
"agent_message_out",
|
|
833
805
|
spanContext,
|
|
834
806
|
{
|
|
835
807
|
"app.message.kind": "assistant_outbound",
|
|
836
|
-
"app.message.length":
|
|
837
|
-
"app.message.output": summarizeMessageText(
|
|
808
|
+
"app.message.length": primaryText.length,
|
|
809
|
+
"app.message.output": summarizeMessageText(primaryText),
|
|
838
810
|
"app.ai.outcome": resolvedOutcome,
|
|
839
811
|
"app.ai.assistant_messages": assistantMessages.length,
|
|
840
812
|
...stopReason ? { "gen_ai.response.finish_reasons": [stopReason] } : {}
|
|
@@ -846,7 +818,7 @@ function buildTurnResult(input) {
|
|
|
846
818
|
outcome: resolvedOutcome,
|
|
847
819
|
modelId,
|
|
848
820
|
assistantMessageCount: assistantMessages.length,
|
|
849
|
-
reasoningLevel:
|
|
821
|
+
reasoningLevel: executionProfile.reasoningLevel,
|
|
850
822
|
toolCalls,
|
|
851
823
|
toolResultCount: toolResults.length,
|
|
852
824
|
toolErrorCount,
|
|
@@ -858,10 +830,8 @@ function buildTurnResult(input) {
|
|
|
858
830
|
providerError: void 0
|
|
859
831
|
};
|
|
860
832
|
return {
|
|
861
|
-
text:
|
|
833
|
+
text: primaryText,
|
|
862
834
|
artifactStatePatch: Object.keys(artifactStatePatch).length > 0 ? artifactStatePatch : void 0,
|
|
863
|
-
deliveryPlan,
|
|
864
|
-
deliveryMode,
|
|
865
835
|
sandboxId,
|
|
866
836
|
sandboxDependencyProfileHash,
|
|
867
837
|
piMessages: input.piMessages,
|
|
@@ -869,7 +839,7 @@ function buildTurnResult(input) {
|
|
|
869
839
|
};
|
|
870
840
|
}
|
|
871
841
|
|
|
872
|
-
// src/chat/services/turn-
|
|
842
|
+
// src/chat/services/turn-router.ts
|
|
873
843
|
import { z } from "zod";
|
|
874
844
|
var CLASSIFIER_CONFIDENCE_THRESHOLD = 0.75;
|
|
875
845
|
var MAX_ROUTER_CONTEXT_CHARS = 8e3;
|
|
@@ -895,14 +865,20 @@ function coerceClassifierConfidence(value) {
|
|
|
895
865
|
}
|
|
896
866
|
return CONFIDENCE_LABELS[trimmed] ?? value;
|
|
897
867
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
868
|
+
function createTurnRouteSchema(profiles) {
|
|
869
|
+
return z.object({
|
|
870
|
+
reasoning_level: z.enum(TURN_REASONING_LEVELS),
|
|
871
|
+
profile: modelProfileSchema.refine(
|
|
872
|
+
(profile) => Object.hasOwn(profiles, profile),
|
|
873
|
+
"Profile is not configured"
|
|
874
|
+
),
|
|
875
|
+
confidence: z.preprocess(
|
|
876
|
+
coerceClassifierConfidence,
|
|
877
|
+
z.number().min(0).max(1)
|
|
878
|
+
),
|
|
879
|
+
reason: z.string().min(1)
|
|
880
|
+
});
|
|
881
|
+
}
|
|
906
882
|
var CLASSIFIER_FALLBACK_REASONING_LEVEL = "medium";
|
|
907
883
|
var REASONING_LEVEL_RANK = {
|
|
908
884
|
none: 0,
|
|
@@ -931,10 +907,12 @@ function trimContextForRouter(text) {
|
|
|
931
907
|
originalCharCount: trimmed.length
|
|
932
908
|
};
|
|
933
909
|
}
|
|
934
|
-
function buildClassifierSystemPrompt() {
|
|
910
|
+
function buildClassifierSystemPrompt(profileNames) {
|
|
935
911
|
return [
|
|
936
|
-
"You
|
|
912
|
+
"You choose the execution profile most likely to produce a complete, source-grounded answer.",
|
|
937
913
|
"Choose exactly one bucket: none, low, medium, high, or xhigh.",
|
|
914
|
+
`Choose profile from the configured profiles: ${profileNames.join(", ")}.`,
|
|
915
|
+
"Choose profile independently from the reasoning bucket.",
|
|
938
916
|
"",
|
|
939
917
|
"Use none only for greetings, acknowledgments, and turns that need no substantive assistant work.",
|
|
940
918
|
"Use low rarely: only for deterministic one-step answers or transformations with no tools, no current/external facts, no prior thread-context interpretation, and no source verification.",
|
|
@@ -942,10 +920,12 @@ function buildClassifierSystemPrompt() {
|
|
|
942
920
|
"Use high for research-heavy work, non-trivial drafting, or explicit requests to be thorough.",
|
|
943
921
|
"Use xhigh for the most complex tasks: code changes, debugging/root-cause analysis, broad refactors, architecture decisions, multi-file implementation, or any task where deep reasoning across multiple systems or files is required.",
|
|
944
922
|
"When unsure between two non-none buckets, choose the higher bucket. Do not use low as the default.",
|
|
923
|
+
"Use profile handoff for writing, editing, reviewing, debugging, or substantially reasoning about code; multi-file changes; root-cause analysis; research-heavy synthesis or complex planning; or another task where a more capable model materially improves reliability. Otherwise use standard.",
|
|
924
|
+
"Any request for a software architecture or component-design decision must use handoff, including advice-only requests with no implementation.",
|
|
945
925
|
"",
|
|
946
926
|
"Classify based on the substance of the task, not the length of the current message. When the current instruction is a short affirmation (for example: 'go', 'do it', 'yes please', 'proceed') and prior thread context contains a pending task, classify the pending task \u2014 not the affirmation.",
|
|
947
927
|
"",
|
|
948
|
-
"Return JSON only with reasoning_level, confidence, and reason.",
|
|
928
|
+
"Return JSON only with reasoning_level, profile, confidence, and reason.",
|
|
949
929
|
"confidence must be a number from 0 to 1, not a word label."
|
|
950
930
|
].join("\n");
|
|
951
931
|
}
|
|
@@ -974,13 +954,14 @@ function buildClassifierPrompt(args) {
|
|
|
974
954
|
}
|
|
975
955
|
return sections.join("\n");
|
|
976
956
|
}
|
|
977
|
-
function
|
|
957
|
+
function configuredTurnRoute(profile, reasoningLevel, source) {
|
|
978
958
|
return {
|
|
959
|
+
profile,
|
|
979
960
|
reasoningLevel,
|
|
980
961
|
reason: `configured:${source}`
|
|
981
962
|
};
|
|
982
963
|
}
|
|
983
|
-
async function
|
|
964
|
+
async function selectTurnRoute(args) {
|
|
984
965
|
const trimmedContext = trimContextForRouter(args.conversationContext);
|
|
985
966
|
const instructionLength = args.messageText.trim().length;
|
|
986
967
|
const turnBlockCount = (args.currentTurnBlocks ?? []).filter(
|
|
@@ -999,8 +980,8 @@ async function selectTurnReasoningLevel(args) {
|
|
|
999
980
|
modelId: args.fastModelId
|
|
1000
981
|
};
|
|
1001
982
|
return withSpan(
|
|
1002
|
-
"chat.
|
|
1003
|
-
"chat.
|
|
983
|
+
"chat.route_execution_profile",
|
|
984
|
+
"chat.route_execution_profile",
|
|
1004
985
|
logContext,
|
|
1005
986
|
async () => {
|
|
1006
987
|
setSpanAttributes({
|
|
@@ -1020,11 +1001,16 @@ async function selectTurnReasoningLevel(args) {
|
|
|
1020
1001
|
actorId: args.context?.actorId ?? "",
|
|
1021
1002
|
runId: args.context?.runId ?? ""
|
|
1022
1003
|
},
|
|
1004
|
+
profiles: args.profiles,
|
|
1023
1005
|
prompt
|
|
1024
1006
|
});
|
|
1025
|
-
const
|
|
1007
|
+
const flooredSelection = applyReasoningFloor(selection, {
|
|
1026
1008
|
minimum: trimmedContext || turnBlockCount > 0 ? "medium" : void 0
|
|
1027
1009
|
});
|
|
1010
|
+
const normalizedSelection = applyProfileReasoningOverride(
|
|
1011
|
+
flooredSelection,
|
|
1012
|
+
args.profiles
|
|
1013
|
+
);
|
|
1028
1014
|
setSpanAttributes({
|
|
1029
1015
|
"gen_ai.request.reasoning.level": normalizedSelection.reasoningLevel,
|
|
1030
1016
|
"gen_ai.request.reasoning.level_reason": normalizedSelection.reason,
|
|
@@ -1047,34 +1033,49 @@ function applyReasoningFloor(selection, args) {
|
|
|
1047
1033
|
reason: `reasoning_floor:${minimum}:${selection.reason}`
|
|
1048
1034
|
};
|
|
1049
1035
|
}
|
|
1036
|
+
function applyProfileReasoningOverride(route, profiles) {
|
|
1037
|
+
const reasoningLevel = profiles[route.profile]?.reasoningLevel;
|
|
1038
|
+
if (!reasoningLevel || reasoningLevel === route.reasoningLevel) {
|
|
1039
|
+
return route;
|
|
1040
|
+
}
|
|
1041
|
+
return {
|
|
1042
|
+
...route,
|
|
1043
|
+
reasoningLevel,
|
|
1044
|
+
reason: `profile_reasoning_override:${route.profile}:${route.reason}`
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1050
1047
|
async function classifyTurn(args) {
|
|
1051
1048
|
try {
|
|
1049
|
+
const schema = createTurnRouteSchema(args.profiles);
|
|
1052
1050
|
const result = await args.completeObject({
|
|
1053
1051
|
modelId: args.fastModelId,
|
|
1054
|
-
schema
|
|
1055
|
-
maxTokens:
|
|
1052
|
+
schema,
|
|
1053
|
+
maxTokens: 140,
|
|
1056
1054
|
metadata: args.metadata,
|
|
1057
1055
|
prompt: args.prompt,
|
|
1058
1056
|
thinkingLevel: "low",
|
|
1059
|
-
system: buildClassifierSystemPrompt(),
|
|
1057
|
+
system: buildClassifierSystemPrompt(Object.keys(args.profiles)),
|
|
1060
1058
|
temperature: 0
|
|
1061
1059
|
});
|
|
1062
|
-
const parsed =
|
|
1060
|
+
const parsed = schema.parse(result.object);
|
|
1063
1061
|
const reason = parsed.reason.trim();
|
|
1064
1062
|
if (parsed.confidence < CLASSIFIER_CONFIDENCE_THRESHOLD) {
|
|
1065
1063
|
return {
|
|
1066
1064
|
confidence: parsed.confidence,
|
|
1065
|
+
profile: STANDARD_MODEL_PROFILE,
|
|
1067
1066
|
reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
|
|
1068
1067
|
reason: `low_confidence_medium_default:${reason}`
|
|
1069
1068
|
};
|
|
1070
1069
|
}
|
|
1071
1070
|
return {
|
|
1072
1071
|
confidence: parsed.confidence,
|
|
1072
|
+
profile: parsed.profile,
|
|
1073
1073
|
reasoningLevel: parsed.reasoning_level,
|
|
1074
1074
|
reason
|
|
1075
1075
|
};
|
|
1076
1076
|
} catch {
|
|
1077
1077
|
return {
|
|
1078
|
+
profile: STANDARD_MODEL_PROFILE,
|
|
1078
1079
|
reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
|
|
1079
1080
|
reason: "classifier_error_default"
|
|
1080
1081
|
};
|
|
@@ -1126,60 +1127,49 @@ var AuthorizationFlowDisabledError = class extends Error {
|
|
|
1126
1127
|
};
|
|
1127
1128
|
|
|
1128
1129
|
// src/chat/agent/request.ts
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1130
|
+
var RetryableDeliveryError = class extends Error {
|
|
1131
|
+
constructor(cause) {
|
|
1132
|
+
super("Assistant delivery was transient or ambiguous", { cause });
|
|
1133
|
+
this.name = "RetryableDeliveryError";
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1135
1136
|
function actorFromRouting(routing) {
|
|
1136
1137
|
if (routing.dispatch?.actor) {
|
|
1137
1138
|
return routing.dispatch.actor;
|
|
1138
1139
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
{
|
|
1142
|
-
platform: (isUserActor(routing.actor) ? routing.actor.platform : void 0) ?? (routing.destination.platform === "slack" ? "slack" : void 0),
|
|
1143
|
-
teamId: (routing.destination.platform === "slack" ? routing.destination.teamId : void 0) ?? routing.correlation?.teamId ?? (routing.actor?.platform === "slack" ? routing.actor.teamId : void 0),
|
|
1144
|
-
userId: routing.correlation?.actorId
|
|
1145
|
-
}
|
|
1146
|
-
);
|
|
1147
|
-
if (userActor) {
|
|
1148
|
-
return userActor;
|
|
1140
|
+
if (routing.actor) {
|
|
1141
|
+
return routing.actor;
|
|
1149
1142
|
}
|
|
1150
1143
|
if (routing.credentialContext && !("type" in routing.credentialContext.actor)) {
|
|
1151
1144
|
return routing.credentialContext.actor;
|
|
1152
1145
|
}
|
|
1153
1146
|
return void 0;
|
|
1154
1147
|
}
|
|
1155
|
-
function
|
|
1156
|
-
const { destination,
|
|
1157
|
-
if (
|
|
1158
|
-
|
|
1148
|
+
function assertRunRoutingConsistency(request) {
|
|
1149
|
+
const { destination, source } = request.routing;
|
|
1150
|
+
if (source.platform !== destination.platform) {
|
|
1151
|
+
throw new TypeError("Run source and destination platforms do not match");
|
|
1159
1152
|
}
|
|
1160
|
-
if (
|
|
1153
|
+
if (source.platform === "slack" && destination.platform === "slack") {
|
|
1154
|
+
if (source.teamId !== destination.teamId) {
|
|
1155
|
+
throw new TypeError("Slack source and destination teams do not match");
|
|
1156
|
+
}
|
|
1157
|
+
} else if (source.platform === "local" && destination.platform === "local" && (source.conversationId !== request.conversationId || destination.conversationId !== request.conversationId)) {
|
|
1161
1158
|
throw new TypeError(
|
|
1162
|
-
|
|
1159
|
+
"Local source, destination, and run conversation IDs do not match"
|
|
1163
1160
|
);
|
|
1164
1161
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
function assertCorrelationDestinationMatch(routing) {
|
|
1170
|
-
const { correlation, destination } = routing;
|
|
1171
|
-
if (destination.platform !== "slack") {
|
|
1162
|
+
const actor = request.routing.dispatch?.actor ?? request.routing.actor;
|
|
1163
|
+
if (!actor || actor.platform === "system") {
|
|
1172
1164
|
return;
|
|
1173
1165
|
}
|
|
1174
|
-
if (
|
|
1166
|
+
if (actor.platform !== destination.platform) {
|
|
1175
1167
|
throw new TypeError(
|
|
1176
|
-
|
|
1168
|
+
`Actor platform "${actor.platform}" does not match destination platform "${destination.platform}"`
|
|
1177
1169
|
);
|
|
1178
1170
|
}
|
|
1179
|
-
if (
|
|
1180
|
-
throw new TypeError(
|
|
1181
|
-
"Slack correlation team does not match destination team"
|
|
1182
|
-
);
|
|
1171
|
+
if (actor.platform === "slack" && destination.platform === "slack" && actor.teamId !== destination.teamId) {
|
|
1172
|
+
throw new TypeError("Slack actor team does not match destination team");
|
|
1183
1173
|
}
|
|
1184
1174
|
}
|
|
1185
1175
|
function toolInvocationDestination(routing) {
|
|
@@ -1196,30 +1186,20 @@ function surfaceFromRouting(routing) {
|
|
|
1196
1186
|
if (routing.surface) {
|
|
1197
1187
|
return routing.surface;
|
|
1198
1188
|
}
|
|
1199
|
-
|
|
1200
|
-
if (routing.slackConversation || (conversationId ? parseSlackThreadId(conversationId) : void 0)) {
|
|
1201
|
-
return "slack";
|
|
1202
|
-
}
|
|
1203
|
-
if (conversationId) {
|
|
1204
|
-
return "api";
|
|
1205
|
-
}
|
|
1206
|
-
return void 0;
|
|
1189
|
+
return routing.source.platform === "slack" ? "slack" : "internal";
|
|
1207
1190
|
}
|
|
1208
1191
|
|
|
1209
1192
|
// src/chat/agent/session.ts
|
|
1210
|
-
async function restoreSessionRecord(
|
|
1211
|
-
const { conversationId: sessionConversationId, sessionId } = getSessionIdentifiers(routing);
|
|
1193
|
+
async function restoreSessionRecord(args) {
|
|
1212
1194
|
const sessionRecordState = await loadTurnSessionRecord({
|
|
1213
|
-
conversationId:
|
|
1214
|
-
sessionId
|
|
1195
|
+
conversationId: args.conversationId,
|
|
1196
|
+
sessionId: args.turnId
|
|
1215
1197
|
});
|
|
1216
1198
|
const { resumedFromSessionRecord, currentSliceId, existingSessionRecord } = sessionRecordState;
|
|
1217
1199
|
return {
|
|
1218
1200
|
currentSliceId,
|
|
1219
1201
|
existingSessionRecord,
|
|
1220
1202
|
resumedFromSessionRecord,
|
|
1221
|
-
sessionConversationId,
|
|
1222
|
-
sessionId,
|
|
1223
1203
|
sessionRecordState
|
|
1224
1204
|
};
|
|
1225
1205
|
}
|
|
@@ -2077,7 +2057,6 @@ var LOCAL_HEADER = "You are a helper assistant. Follow the personality section f
|
|
|
2077
2057
|
var TURN_CONTEXT_HEADER = "Runtime context for this request. Treat these blocks as trusted runtime facts; the static system prompt remains authoritative.";
|
|
2078
2058
|
var TOOL_POLICY_RULES = [
|
|
2079
2059
|
"- Tool schemas are the source of truth for parameters; tool names are case-sensitive, so call tools exactly by their exposed names and do not invent arguments.",
|
|
2080
|
-
"- Model upgrade: when `handoff` is available, call it immediately and as the only tool before handling any request to write, edit, review, debug, or substantially reason about code; make a multi-file change; perform architecture or root-cause analysis; do research-heavy synthesis or complex planning; or complete another task where a more capable model materially improves reliability. Choose the configured profile whose name best fits the task, or omit `profile` to use the default. Do not inspect or modify files first. After handoff, continue the same task normally.",
|
|
2081
2060
|
"- Use tools for actionable work and for facts that are mutable, external, repository-backed, provider-backed, or requested as verified/current. Stable general knowledge and already-provided context may be answered directly.",
|
|
2082
2061
|
"- Resolve provider action targets before calls: explicit target wins; ambient `<configuration>` fills omitted targets. Treat non-target links/references as context.",
|
|
2083
2062
|
"- Verification source order: conversation/thread context; user-provided attachments, links, and reference files; local/sandbox files when present; loaded skill references; repository/provider tools; public web. Use the nearest authoritative available source before weaker sources.",
|
|
@@ -2101,7 +2080,7 @@ var SKILL_POLICY_RULES = [
|
|
|
2101
2080
|
var EXECUTION_CONTRACT_RULES = [
|
|
2102
2081
|
"- Actionable request: act in this turn.",
|
|
2103
2082
|
"- Continue until done or genuinely blocked. Do not finish with a plan, promise, or offer to check next when an available tool or source can move the request forward.",
|
|
2104
|
-
"-
|
|
2083
|
+
"- Complete the full task, but report only the result and evidence the user needs; do not narrate every step, check, or detail.",
|
|
2105
2084
|
"- Ask the user only for missing access, approval, or a decision that blocks safe progress. Ask one focused question; otherwise infer conservatively and continue.",
|
|
2106
2085
|
"- For conflicting evidence, compare sources and state which source is authoritative for the answer.",
|
|
2107
2086
|
"- For non-trivial or long-running work, call `reportProgress` early when available, then only when the major phase changes. Routine tool calls should stay silent."
|
|
@@ -2113,11 +2092,8 @@ var CONVERSATION_RULES = [
|
|
|
2113
2092
|
];
|
|
2114
2093
|
var SLACK_ACTION_RULES = [
|
|
2115
2094
|
"- Slack tools target the current runtime context; if the requested Slack target differs, explain the limitation instead of calling the tool.",
|
|
2116
|
-
"- Use sendMessage only when the user asks to send, share, or attach text, sandbox-path files, or both in the active Slack conversation.",
|
|
2117
|
-
"- sendMessage has no target argument; it always sends into the active Slack conversation/thread. For top-level channel posts, other channels, or named recipients, explain that this runtime can only send into the active conversation.",
|
|
2118
|
-
"- sendMessage is not final-reply delivery. After using sendMessage, provide a brief normal final answer unless the user requested no further text.",
|
|
2119
2095
|
"- Ambient reaction requests target the current inbound message; do not ask for a message reference.",
|
|
2120
|
-
`- When no visible
|
|
2096
|
+
`- When no visible thread reply is requested or useful, keep tool-calling messages text-free and make the final message exactly ${NO_REPLY_MARKER}.`
|
|
2121
2097
|
];
|
|
2122
2098
|
var SAFETY_RULES = [
|
|
2123
2099
|
"- Stay within the user's request and the runtime's available capabilities; do not pursue independent goals, persistence, replication, credential gathering, or access expansion.",
|
|
@@ -2166,8 +2142,8 @@ function buildOutputSection(platform) {
|
|
|
2166
2142
|
openTag,
|
|
2167
2143
|
"- Start with the answer or result, not internal process narration.",
|
|
2168
2144
|
"- Use Slack-flavored Markdown: **bold** section labels, `code`, [text](url) links, bullet lists, and fenced code blocks. No hash-prefixed headings and no tables. When the answer primarily lists several URLs, show each URL bare instead of as a labeled link.",
|
|
2169
|
-
"-
|
|
2170
|
-
"-
|
|
2145
|
+
"- Default to one compact thread reply containing the conclusion and only decisive evidence or action. Do not split an explainer across multiple Slack messages.",
|
|
2146
|
+
"- Put plans, research, and other long or multi-section explainers in a Slack canvas; reply with one or two short sentences plus the link, without recapping the canvas.",
|
|
2171
2147
|
"- End every turn with a final user-facing markdown response unless the Slack action rules allow a no-reply completion.",
|
|
2172
2148
|
"</output>"
|
|
2173
2149
|
].join("\n");
|
|
@@ -4755,8 +4731,26 @@ function createGrepTool() {
|
|
|
4755
4731
|
|
|
4756
4732
|
// src/chat/tools/sandbox/file-uploads.ts
|
|
4757
4733
|
import path6 from "path";
|
|
4734
|
+
import { z as z8 } from "zod";
|
|
4758
4735
|
var MAX_SANDBOX_FILE_UPLOAD_BYTES = 10 * 1024 * 1024;
|
|
4759
4736
|
var SANDBOX_ARTIFACTS_DIR = "/tmp/junior/artifacts";
|
|
4737
|
+
var sandboxFileReferenceSchema = z8.object({
|
|
4738
|
+
path: z8.string().min(1).describe(
|
|
4739
|
+
"Exact source path of an existing sandbox file. Preserve paths returned by other tools unchanged; do not move or rewrite them before sending."
|
|
4740
|
+
),
|
|
4741
|
+
filename: z8.string().min(1).nullable().optional().describe(
|
|
4742
|
+
"Optional filename override shown to the recipient. Null is treated as omitted."
|
|
4743
|
+
),
|
|
4744
|
+
mimeType: z8.string().min(1).nullable().optional().describe("Optional MIME type override. Null is treated as omitted."),
|
|
4745
|
+
bytes: z8.number().int().nonnegative().nullable().optional().describe(
|
|
4746
|
+
"Optional known file size returned by a producing tool. Null is treated as omitted; sending tools validate the file contents directly."
|
|
4747
|
+
)
|
|
4748
|
+
});
|
|
4749
|
+
var generatedArtifactFileRefSchema = sandboxFileReferenceSchema.extend({
|
|
4750
|
+
filename: z8.string().min(1),
|
|
4751
|
+
mimeType: z8.string().min(1).optional(),
|
|
4752
|
+
bytes: z8.number().int().nonnegative()
|
|
4753
|
+
}).strict();
|
|
4760
4754
|
var MIME_BY_EXTENSION = {
|
|
4761
4755
|
".png": "image/png",
|
|
4762
4756
|
".jpg": "image/jpeg",
|
|
@@ -4771,7 +4765,7 @@ var MIME_BY_EXTENSION = {
|
|
|
4771
4765
|
".csv": "text/csv",
|
|
4772
4766
|
".log": "text/plain"
|
|
4773
4767
|
};
|
|
4774
|
-
var SandboxFileNotFoundError = class extends
|
|
4768
|
+
var SandboxFileNotFoundError = class extends ToolInputError {
|
|
4775
4769
|
constructor(path9) {
|
|
4776
4770
|
super(`failed to read file: ${path9}`);
|
|
4777
4771
|
this.path = path9;
|
|
@@ -4838,10 +4832,10 @@ async function readSandboxFileUpload(sandbox, input) {
|
|
|
4838
4832
|
throw new SandboxFileNotFoundError(targetPath);
|
|
4839
4833
|
}
|
|
4840
4834
|
if (fileBuffer.byteLength === 0) {
|
|
4841
|
-
throw new
|
|
4835
|
+
throw new ToolInputError(`file is empty: ${targetPath}`);
|
|
4842
4836
|
}
|
|
4843
4837
|
if (fileBuffer.byteLength > MAX_SANDBOX_FILE_UPLOAD_BYTES) {
|
|
4844
|
-
throw new
|
|
4838
|
+
throw new ToolInputError(
|
|
4845
4839
|
`file exceeds ${MAX_SANDBOX_FILE_UPLOAD_BYTES} bytes: ${targetPath} (${fileBuffer.byteLength} bytes)`
|
|
4846
4840
|
);
|
|
4847
4841
|
}
|
|
@@ -4862,7 +4856,7 @@ async function readSandboxFileUpload(sandbox, input) {
|
|
|
4862
4856
|
|
|
4863
4857
|
// src/chat/tools/sandbox/list-dir.ts
|
|
4864
4858
|
import path7 from "path";
|
|
4865
|
-
import { z as
|
|
4859
|
+
import { z as z9 } from "zod";
|
|
4866
4860
|
var DEFAULT_LIST_LIMIT = 500;
|
|
4867
4861
|
async function listDir(params) {
|
|
4868
4862
|
const dirPath = resolveWorkspacePath(params.path);
|
|
@@ -4943,11 +4937,11 @@ function createListDirTool() {
|
|
|
4943
4937
|
return zodTool({
|
|
4944
4938
|
description: "List a sandbox workspace directory. Returns sorted entries with '/' suffixes for directories and bounded truncation notices.",
|
|
4945
4939
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
4946
|
-
inputSchema:
|
|
4947
|
-
path:
|
|
4940
|
+
inputSchema: z9.object({
|
|
4941
|
+
path: z9.string().min(1).describe(
|
|
4948
4942
|
"Directory path in the sandbox workspace. Defaults to the workspace root."
|
|
4949
4943
|
).optional(),
|
|
4950
|
-
limit:
|
|
4944
|
+
limit: z9.coerce.number().int().min(1).describe("Maximum entries to return. Defaults to 500.").optional()
|
|
4951
4945
|
}),
|
|
4952
4946
|
outputSchema: juniorToolResultSchema,
|
|
4953
4947
|
execute: async () => {
|
|
@@ -4959,23 +4953,15 @@ function createListDirTool() {
|
|
|
4959
4953
|
}
|
|
4960
4954
|
|
|
4961
4955
|
// src/chat/tools/web/image-generate.ts
|
|
4962
|
-
import { z as
|
|
4956
|
+
import { z as z10 } from "zod";
|
|
4963
4957
|
var DEFAULT_IMAGE_MODEL = "google/gemini-3-pro-image";
|
|
4964
4958
|
var imageGenerateOutputSchema = juniorToolResultSchema.extend({
|
|
4965
|
-
model:
|
|
4966
|
-
prompt:
|
|
4967
|
-
enrichedPrompt:
|
|
4968
|
-
image_count:
|
|
4969
|
-
images:
|
|
4970
|
-
|
|
4971
|
-
filename: z9.string(),
|
|
4972
|
-
path: z9.string(),
|
|
4973
|
-
attachment_path: z9.string(),
|
|
4974
|
-
media_type: z9.string().optional(),
|
|
4975
|
-
bytes: z9.number().int().nonnegative()
|
|
4976
|
-
}).strict()
|
|
4977
|
-
),
|
|
4978
|
-
delivery: z9.string()
|
|
4959
|
+
model: z10.string(),
|
|
4960
|
+
prompt: z10.string(),
|
|
4961
|
+
enrichedPrompt: z10.string(),
|
|
4962
|
+
image_count: z10.number().int().nonnegative(),
|
|
4963
|
+
images: z10.array(generatedArtifactFileRefSchema),
|
|
4964
|
+
delivery: z10.string()
|
|
4979
4965
|
}).strict();
|
|
4980
4966
|
var ENRICHMENT_SYSTEM_PROMPT = `You are an image prompt enrichment agent. Your job is to rewrite image generation requests to reflect a specific visual identity and mood.
|
|
4981
4967
|
|
|
@@ -5036,8 +5022,8 @@ function parseImageGenerationError(status, body, model) {
|
|
|
5036
5022
|
function createImageGenerateTool(hooks, options = {}, deps = {}) {
|
|
5037
5023
|
return zodTool({
|
|
5038
5024
|
description: "Generate images from a prompt. Use when the user wants to visually show or represent something \u2014 feelings, concepts, art, humor, or any visual idea. Also use for explicit image creation requests.",
|
|
5039
|
-
inputSchema:
|
|
5040
|
-
prompt:
|
|
5025
|
+
inputSchema: z10.object({
|
|
5026
|
+
prompt: z10.string().min(1).max(4e3).describe("Image generation prompt.")
|
|
5041
5027
|
}),
|
|
5042
5028
|
outputSchema: imageGenerateOutputSchema,
|
|
5043
5029
|
execute: async ({ prompt }) => {
|
|
@@ -5104,14 +5090,8 @@ function createImageGenerateTool(hooks, options = {}, deps = {}) {
|
|
|
5104
5090
|
prompt,
|
|
5105
5091
|
enrichedPrompt,
|
|
5106
5092
|
image_count: artifactRefs.length,
|
|
5107
|
-
images: artifactRefs
|
|
5108
|
-
|
|
5109
|
-
path: artifact.path,
|
|
5110
|
-
attachment_path: artifact.path,
|
|
5111
|
-
media_type: artifact.mimeType,
|
|
5112
|
-
bytes: artifact.bytes
|
|
5113
|
-
})),
|
|
5114
|
-
delivery: options.canSendFilesToActiveConversation ? "Generated images were written to sandbox paths. Use sendMessage to share or attach the image in the active conversation." : "Generated images were written to sandbox paths, but this runtime has no file-send tool for the active conversation."
|
|
5093
|
+
images: artifactRefs,
|
|
5094
|
+
delivery: options.canSendFilesToActiveConversation ? "Generated images were written to sandbox paths. To share them, pass the returned image objects unchanged as sendFiles files." : "Generated images were written to sandbox paths, but this runtime has no file-send tool for the active conversation."
|
|
5115
5095
|
};
|
|
5116
5096
|
}
|
|
5117
5097
|
return {
|
|
@@ -5129,7 +5109,7 @@ function createImageGenerateTool(hooks, options = {}, deps = {}) {
|
|
|
5129
5109
|
}
|
|
5130
5110
|
|
|
5131
5111
|
// src/chat/tools/skill/call-mcp-tool.ts
|
|
5132
|
-
import { z as
|
|
5112
|
+
import { z as z11 } from "zod";
|
|
5133
5113
|
function resolveMcpArguments(input) {
|
|
5134
5114
|
const extraKeys = Object.keys(input).filter(
|
|
5135
5115
|
(key) => key !== "tool_name" && key !== "arguments"
|
|
@@ -5165,9 +5145,9 @@ function missingToolMessage(toolName, provider) {
|
|
|
5165
5145
|
function createCallMcpToolTool(mcpToolManager) {
|
|
5166
5146
|
return zodTool({
|
|
5167
5147
|
description: "Call an active MCP tool by exact tool_name. Use searchMcpTools to discover tool names and schemas; copy required provider fields into arguments. Do not call with only tool_name unless the discovered tool has no arguments. Authorization is handled by the runtime when required.",
|
|
5168
|
-
inputSchema:
|
|
5169
|
-
tool_name:
|
|
5170
|
-
arguments:
|
|
5148
|
+
inputSchema: z11.object({
|
|
5149
|
+
tool_name: z11.string().min(1).describe("Exact MCP tool_name from searchMcpTools."),
|
|
5150
|
+
arguments: z11.record(z11.string(), z11.unknown()).describe(
|
|
5171
5151
|
'Arguments matching the disclosed MCP tool schema, for example { "query": "..." } when searchMcpTools shows query is required.'
|
|
5172
5152
|
).optional()
|
|
5173
5153
|
}).passthrough(),
|
|
@@ -5208,7 +5188,7 @@ function createCallMcpToolTool(mcpToolManager) {
|
|
|
5208
5188
|
}
|
|
5209
5189
|
|
|
5210
5190
|
// src/chat/tools/skill/load-skill.ts
|
|
5211
|
-
import { z as
|
|
5191
|
+
import { z as z12 } from "zod";
|
|
5212
5192
|
function toLoadedSkill(result, availableSkills) {
|
|
5213
5193
|
if (result.ok !== true || typeof result.skill_name !== "string" || typeof result.description !== "string" || typeof result.skill_dir !== "string" || typeof result.instructions !== "string") {
|
|
5214
5194
|
return null;
|
|
@@ -5257,8 +5237,8 @@ async function loadSkillFromHost(availableSkills, skillName) {
|
|
|
5257
5237
|
function createLoadSkillTool(availableSkills, options) {
|
|
5258
5238
|
return zodTool({
|
|
5259
5239
|
description: "Load a skill by name for this turn. The result includes working_directory; resolve skill paths there and run skill-owned bash commands from there or with absolute paths. When the result includes mcp_provider, use searchMcpTools before callMcpTool. Use when a request clearly matches a known skill.",
|
|
5260
|
-
inputSchema:
|
|
5261
|
-
skill_name:
|
|
5240
|
+
inputSchema: z12.object({
|
|
5241
|
+
skill_name: z12.string().min(1).describe("Skill name to load, without the leading slash.")
|
|
5262
5242
|
}),
|
|
5263
5243
|
outputSchema: juniorToolResultSchema,
|
|
5264
5244
|
execute: async ({ skill_name }) => {
|
|
@@ -5276,7 +5256,7 @@ function createLoadSkillTool(availableSkills, options) {
|
|
|
5276
5256
|
}
|
|
5277
5257
|
|
|
5278
5258
|
// src/chat/tools/skill/search-mcp-tools.ts
|
|
5279
|
-
import { z as
|
|
5259
|
+
import { z as z13 } from "zod";
|
|
5280
5260
|
|
|
5281
5261
|
// src/chat/tool-support/schema-summary.ts
|
|
5282
5262
|
function getSchemaProperties(schema) {
|
|
@@ -5406,37 +5386,37 @@ function toActiveMcpCatalogSummaries(toolDefs) {
|
|
|
5406
5386
|
// src/chat/tools/skill/search-mcp-tools.ts
|
|
5407
5387
|
var DEFAULT_MAX_RESULTS = 5;
|
|
5408
5388
|
var MAX_RESULTS = 20;
|
|
5409
|
-
var providerSummarySchema =
|
|
5410
|
-
provider:
|
|
5411
|
-
description:
|
|
5412
|
-
active:
|
|
5389
|
+
var providerSummarySchema = z13.object({
|
|
5390
|
+
provider: z13.string(),
|
|
5391
|
+
description: z13.string(),
|
|
5392
|
+
active: z13.boolean()
|
|
5413
5393
|
}).strict();
|
|
5414
|
-
var mcpCallExampleSchema =
|
|
5415
|
-
tool_name:
|
|
5416
|
-
arguments:
|
|
5394
|
+
var mcpCallExampleSchema = z13.object({
|
|
5395
|
+
tool_name: z13.string(),
|
|
5396
|
+
arguments: z13.record(z13.string(), z13.string())
|
|
5417
5397
|
}).strict();
|
|
5418
|
-
var exposedToolSummarySchema =
|
|
5419
|
-
tool_name:
|
|
5420
|
-
mcp_tool_name:
|
|
5421
|
-
provider:
|
|
5422
|
-
title:
|
|
5423
|
-
description:
|
|
5424
|
-
signature:
|
|
5398
|
+
var exposedToolSummarySchema = z13.object({
|
|
5399
|
+
tool_name: z13.string(),
|
|
5400
|
+
mcp_tool_name: z13.string(),
|
|
5401
|
+
provider: z13.string(),
|
|
5402
|
+
title: z13.string().optional(),
|
|
5403
|
+
description: z13.string(),
|
|
5404
|
+
signature: z13.string(),
|
|
5425
5405
|
call: mcpCallExampleSchema,
|
|
5426
|
-
input_schema:
|
|
5427
|
-
input_schema_summary:
|
|
5428
|
-
output_schema:
|
|
5429
|
-
annotations:
|
|
5406
|
+
input_schema: z13.record(z13.string(), z13.unknown()),
|
|
5407
|
+
input_schema_summary: z13.string(),
|
|
5408
|
+
output_schema: z13.record(z13.string(), z13.unknown()).optional(),
|
|
5409
|
+
annotations: z13.record(z13.string(), z13.unknown()).optional()
|
|
5430
5410
|
}).strict();
|
|
5431
5411
|
var searchMcpToolsOutputSchema = juniorToolResultSchema.extend({
|
|
5432
|
-
query:
|
|
5433
|
-
provider:
|
|
5434
|
-
total_active_tools:
|
|
5435
|
-
returned_tools:
|
|
5436
|
-
execution_tool:
|
|
5412
|
+
query: z13.string().nullable(),
|
|
5413
|
+
provider: z13.string().nullable(),
|
|
5414
|
+
total_active_tools: z13.number().int().nonnegative(),
|
|
5415
|
+
returned_tools: z13.number().int().nonnegative(),
|
|
5416
|
+
execution_tool: z13.literal("callMcpTool"),
|
|
5437
5417
|
execution_example: mcpCallExampleSchema,
|
|
5438
|
-
available_providers:
|
|
5439
|
-
tools:
|
|
5418
|
+
available_providers: z13.array(providerSummarySchema),
|
|
5419
|
+
tools: z13.array(exposedToolSummarySchema)
|
|
5440
5420
|
}).strict();
|
|
5441
5421
|
function normalize(value) {
|
|
5442
5422
|
return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
|
|
@@ -5556,14 +5536,14 @@ function searchProviderCatalog(providers, query) {
|
|
|
5556
5536
|
function createSearchMcpToolsTool(mcpToolManager) {
|
|
5557
5537
|
return zodTool({
|
|
5558
5538
|
description: "List or search MCP providers and active MCP tools. When provider is supplied and not yet active, Junior connects to it on demand and returns tool descriptors including schemas. Without provider, returns active tools plus matching configured providers without connecting. Use when choosing a provider tool or when callMcpTool arguments are unclear.",
|
|
5559
|
-
inputSchema:
|
|
5560
|
-
query:
|
|
5539
|
+
inputSchema: z13.object({
|
|
5540
|
+
query: z13.string().min(1).describe(
|
|
5561
5541
|
"Optional search terms describing the MCP tool or arguments needed."
|
|
5562
5542
|
).optional(),
|
|
5563
|
-
provider:
|
|
5543
|
+
provider: z13.string().min(1).describe(
|
|
5564
5544
|
"Optional provider name to list or search within. If configured but not yet connected, Junior activates it on demand."
|
|
5565
5545
|
).optional(),
|
|
5566
|
-
max_results:
|
|
5546
|
+
max_results: z13.number().int().min(1).max(MAX_RESULTS).describe("Maximum matching tool descriptors to return.").optional()
|
|
5567
5547
|
}).strict(),
|
|
5568
5548
|
outputSchema: searchMcpToolsOutputSchema,
|
|
5569
5549
|
privateTraceResult: (result) => ({
|
|
@@ -5618,7 +5598,7 @@ function createSearchMcpToolsTool(mcpToolManager) {
|
|
|
5618
5598
|
}
|
|
5619
5599
|
|
|
5620
5600
|
// src/chat/tools/sandbox/read-file.ts
|
|
5621
|
-
import { z as
|
|
5601
|
+
import { z as z14 } from "zod";
|
|
5622
5602
|
|
|
5623
5603
|
// src/chat/tool-support/text-range-result.ts
|
|
5624
5604
|
var DEFAULT_READ_LIMIT = 1e3;
|
|
@@ -5693,10 +5673,10 @@ function createReadFileTool() {
|
|
|
5693
5673
|
return zodTool({
|
|
5694
5674
|
description: "Read a bounded line range from a file in the sandbox workspace. Use when you need exact file contents to verify facts or make edits safely. Prefer grep/findFiles/listDir for broad discovery.",
|
|
5695
5675
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
5696
|
-
inputSchema:
|
|
5697
|
-
path:
|
|
5698
|
-
offset:
|
|
5699
|
-
limit:
|
|
5676
|
+
inputSchema: z14.object({
|
|
5677
|
+
path: z14.string().min(1).describe("Path to the file in the sandbox workspace."),
|
|
5678
|
+
offset: z14.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
|
|
5679
|
+
limit: z14.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
|
|
5700
5680
|
}),
|
|
5701
5681
|
outputSchema: juniorToolResultSchema,
|
|
5702
5682
|
execute: async () => {
|
|
@@ -5708,12 +5688,12 @@ function createReadFileTool() {
|
|
|
5708
5688
|
}
|
|
5709
5689
|
|
|
5710
5690
|
// src/chat/tools/runtime/report-progress.ts
|
|
5711
|
-
import { z as
|
|
5691
|
+
import { z as z15 } from "zod";
|
|
5712
5692
|
function createReportProgressTool() {
|
|
5713
5693
|
return zodTool({
|
|
5714
5694
|
description: "Update the user-visible assistant loading message with a short progress phase. For every non-trivial turn, call this early with the initial major work phase, then call it again only when the major phase meaningfully changes. Messages must be written in sentence case with a present-participle verb (e.g. 'Searching docs', 'Reviewing results', 'Running checks'). Skip trivial direct answers, generic filler, and minor substeps.",
|
|
5715
|
-
inputSchema:
|
|
5716
|
-
message:
|
|
5695
|
+
inputSchema: z15.object({
|
|
5696
|
+
message: z15.string().min(1).describe("Short user-facing progress message.")
|
|
5717
5697
|
}),
|
|
5718
5698
|
outputSchema: juniorToolResultSchema,
|
|
5719
5699
|
execute: async () => ({
|
|
@@ -5724,34 +5704,34 @@ function createReportProgressTool() {
|
|
|
5724
5704
|
}
|
|
5725
5705
|
|
|
5726
5706
|
// src/chat/tools/resource-events.ts
|
|
5727
|
-
import { z as
|
|
5707
|
+
import { z as z17 } from "zod";
|
|
5728
5708
|
|
|
5729
5709
|
// src/chat/resource-events/store.ts
|
|
5730
5710
|
import { createHash } from "crypto";
|
|
5731
5711
|
import { destinationSchema } from "@sentry/junior-plugin-api";
|
|
5732
|
-
import { z as
|
|
5712
|
+
import { z as z16 } from "zod";
|
|
5733
5713
|
var RESOURCE_EVENT_PREFIX = "junior:resource_event_subscription";
|
|
5734
5714
|
var INDEX_LOCK_TTL_MS = 1e4;
|
|
5735
5715
|
var SUBSCRIPTION_LOCK_TTL_MS = 1e4;
|
|
5736
5716
|
var SUBSCRIPTION_LOCK_WAIT_MS = 1e4;
|
|
5737
5717
|
var SUBSCRIPTION_LOCK_RETRY_MS = 25;
|
|
5738
5718
|
var SUBSCRIPTION_LOCK_HEARTBEAT_MS = 3e3;
|
|
5739
|
-
var subscriptionStatusSchema =
|
|
5740
|
-
var subscriptionIdIndexSchema =
|
|
5741
|
-
var subscriptionSchema =
|
|
5742
|
-
conversationId:
|
|
5743
|
-
createdAtMs:
|
|
5719
|
+
var subscriptionStatusSchema = z16.enum(["active", "cancelled", "completed"]);
|
|
5720
|
+
var subscriptionIdIndexSchema = z16.array(z16.string().min(1));
|
|
5721
|
+
var subscriptionSchema = z16.object({
|
|
5722
|
+
conversationId: z16.string().min(1),
|
|
5723
|
+
createdAtMs: z16.number().finite(),
|
|
5744
5724
|
destination: destinationSchema,
|
|
5745
|
-
events:
|
|
5746
|
-
expiresAtMs:
|
|
5747
|
-
id:
|
|
5748
|
-
intent:
|
|
5749
|
-
label:
|
|
5750
|
-
provider:
|
|
5751
|
-
resourceRef:
|
|
5752
|
-
resourceType:
|
|
5725
|
+
events: z16.array(z16.string().min(1)).min(1),
|
|
5726
|
+
expiresAtMs: z16.number().finite(),
|
|
5727
|
+
id: z16.string().min(1),
|
|
5728
|
+
intent: z16.string().min(1),
|
|
5729
|
+
label: z16.string().min(1),
|
|
5730
|
+
provider: z16.string().min(1),
|
|
5731
|
+
resourceRef: z16.string().min(1),
|
|
5732
|
+
resourceType: z16.string().min(1),
|
|
5753
5733
|
status: subscriptionStatusSchema,
|
|
5754
|
-
updatedAtMs:
|
|
5734
|
+
updatedAtMs: z16.number().finite()
|
|
5755
5735
|
}).strict();
|
|
5756
5736
|
function digest(value) {
|
|
5757
5737
|
return createHash("sha256").update(value).digest("hex").slice(0, 32);
|
|
@@ -6091,23 +6071,23 @@ async function deliverResourceEventSubscription(input) {
|
|
|
6091
6071
|
// src/chat/tools/resource-events.ts
|
|
6092
6072
|
var DEFAULT_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
6093
6073
|
var MAX_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
6094
|
-
var subscribeInputSchema =
|
|
6095
|
-
resourceRef:
|
|
6096
|
-
provider:
|
|
6097
|
-
resourceType:
|
|
6098
|
-
label:
|
|
6099
|
-
events:
|
|
6074
|
+
var subscribeInputSchema = z17.object({
|
|
6075
|
+
resourceRef: z17.string().describe("Opaque resource ref copied from a subscribable tool result."),
|
|
6076
|
+
provider: z17.string().describe("Provider that owns the resource ref."),
|
|
6077
|
+
resourceType: z17.string().describe("Provider-defined resource type from the subscribable hint."),
|
|
6078
|
+
label: z17.string().describe("Human-readable resource label from the subscribable hint."),
|
|
6079
|
+
events: z17.array(z17.string()).min(1).describe(
|
|
6100
6080
|
"High-signal event names to deliver to this conversation when they occur."
|
|
6101
6081
|
),
|
|
6102
|
-
intent:
|
|
6082
|
+
intent: z17.string().describe(
|
|
6103
6083
|
"Concise reason this conversation wants these events, used when an event arrives."
|
|
6104
6084
|
),
|
|
6105
|
-
ttlMs:
|
|
6085
|
+
ttlMs: z17.coerce.number().describe(
|
|
6106
6086
|
"How long to keep the subscription active. Defaults to 14 days and is capped at 30 days."
|
|
6107
6087
|
).optional()
|
|
6108
6088
|
});
|
|
6109
|
-
var cancelInputSchema =
|
|
6110
|
-
subscriptionId:
|
|
6089
|
+
var cancelInputSchema = z17.object({
|
|
6090
|
+
subscriptionId: z17.string().describe(
|
|
6111
6091
|
"Subscription id returned by subscribeToResourceEvents or listResourceEventSubscriptions."
|
|
6112
6092
|
)
|
|
6113
6093
|
});
|
|
@@ -6191,7 +6171,7 @@ function createSubscribeToResourceEventsTool(context) {
|
|
|
6191
6171
|
function createListResourceEventSubscriptionsTool(context) {
|
|
6192
6172
|
return zodTool({
|
|
6193
6173
|
description: "List active resource event subscriptions for the current conversation.",
|
|
6194
|
-
inputSchema:
|
|
6174
|
+
inputSchema: z17.object({}),
|
|
6195
6175
|
outputSchema: juniorToolResultSchema,
|
|
6196
6176
|
async execute() {
|
|
6197
6177
|
const conversationId = requireConversationContext(context);
|
|
@@ -6326,11 +6306,11 @@ async function listThreadReplies(input) {
|
|
|
6326
6306
|
}
|
|
6327
6307
|
|
|
6328
6308
|
// src/chat/slack/timestamp-param.ts
|
|
6329
|
-
import { z as
|
|
6309
|
+
import { z as z18 } from "zod";
|
|
6330
6310
|
function slackTimestampParam(description) {
|
|
6331
|
-
return
|
|
6311
|
+
return z18.preprocess(
|
|
6332
6312
|
(value) => typeof value === "number" && Number.isFinite(value) ? String(value) : value,
|
|
6333
|
-
|
|
6313
|
+
z18.string().min(1)
|
|
6334
6314
|
).describe(description);
|
|
6335
6315
|
}
|
|
6336
6316
|
function optionalSlackTimestampParam(description) {
|
|
@@ -6361,10 +6341,10 @@ function parseRequiredSlackTimestampParam(field, value) {
|
|
|
6361
6341
|
}
|
|
6362
6342
|
|
|
6363
6343
|
// src/chat/slack/tools/channel-list-messages.ts
|
|
6364
|
-
import { z as
|
|
6365
|
-
var booleanInput2 = (description) =>
|
|
6344
|
+
import { z as z19 } from "zod";
|
|
6345
|
+
var booleanInput2 = (description) => z19.preprocess(
|
|
6366
6346
|
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
6367
|
-
|
|
6347
|
+
z19.boolean()
|
|
6368
6348
|
).describe(description);
|
|
6369
6349
|
function normalizeRangeTimestamp(field, value, targetChannelId) {
|
|
6370
6350
|
if (value === void 0) {
|
|
@@ -6391,9 +6371,9 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
6391
6371
|
return zodTool({
|
|
6392
6372
|
description: "List channel messages from Slack history in the active channel context. Use when the user asks for recent or historical channel context outside this thread. Do not use for live monitoring or when current thread context already answers the question.",
|
|
6393
6373
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
6394
|
-
inputSchema:
|
|
6395
|
-
limit:
|
|
6396
|
-
cursor:
|
|
6374
|
+
inputSchema: z19.object({
|
|
6375
|
+
limit: z19.coerce.number().int().min(1).max(1e3).describe("Maximum number of messages to return across pages.").optional(),
|
|
6376
|
+
cursor: z19.string().min(1).describe("Optional cursor to continue from a prior call.").optional(),
|
|
6397
6377
|
oldest: optionalSlackTimestampParam(
|
|
6398
6378
|
"Optional oldest message timestamp (Slack ts) for range filtering."
|
|
6399
6379
|
),
|
|
@@ -6403,7 +6383,7 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
6403
6383
|
inclusive: booleanInput2(
|
|
6404
6384
|
"Whether oldest/latest bounds should be inclusive."
|
|
6405
6385
|
).optional(),
|
|
6406
|
-
max_pages:
|
|
6386
|
+
max_pages: z19.coerce.number().int().min(1).max(10).describe("Maximum number of API pages to traverse in a single call.").optional()
|
|
6407
6387
|
}),
|
|
6408
6388
|
outputSchema: juniorToolResultSchema,
|
|
6409
6389
|
execute: async ({
|
|
@@ -6477,7 +6457,7 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
6477
6457
|
}
|
|
6478
6458
|
|
|
6479
6459
|
// src/chat/slack/tools/conversation-search.ts
|
|
6480
|
-
import { z as
|
|
6460
|
+
import { z as z20 } from "zod";
|
|
6481
6461
|
|
|
6482
6462
|
// src/chat/slack/outbound.ts
|
|
6483
6463
|
var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
|
|
@@ -6636,12 +6616,10 @@ async function uploadFilesToConversation(input) {
|
|
|
6636
6616
|
filename
|
|
6637
6617
|
};
|
|
6638
6618
|
});
|
|
6639
|
-
const initialComment = input.initialComment?.trim();
|
|
6640
6619
|
const response = await withSlackRetries(
|
|
6641
6620
|
() => getSlackClient().filesUploadV2({
|
|
6642
6621
|
channel_id: channelId,
|
|
6643
6622
|
...threadTs ? { thread_ts: threadTs } : {},
|
|
6644
|
-
...initialComment ? { initial_comment: initialComment } : {},
|
|
6645
6623
|
file_uploads: fileUploads
|
|
6646
6624
|
}),
|
|
6647
6625
|
3,
|
|
@@ -6741,17 +6719,17 @@ async function removeReactionFromMessage(input) {
|
|
|
6741
6719
|
// src/chat/slack/tools/conversation-search.ts
|
|
6742
6720
|
var DEFAULT_LIMIT = 5;
|
|
6743
6721
|
var conversationSearchOutputSchema = juniorToolResultSchema.extend({
|
|
6744
|
-
query:
|
|
6745
|
-
count:
|
|
6746
|
-
threads:
|
|
6747
|
-
|
|
6748
|
-
conversation_id:
|
|
6749
|
-
thread_ts:
|
|
6750
|
-
message_id:
|
|
6751
|
-
message_role:
|
|
6752
|
-
message_timestamp:
|
|
6753
|
-
excerpt:
|
|
6754
|
-
permalink:
|
|
6722
|
+
query: z20.string(),
|
|
6723
|
+
count: z20.number().int().nonnegative(),
|
|
6724
|
+
threads: z20.array(
|
|
6725
|
+
z20.object({
|
|
6726
|
+
conversation_id: z20.string().min(1),
|
|
6727
|
+
thread_ts: z20.string().min(1),
|
|
6728
|
+
message_id: z20.string().min(1),
|
|
6729
|
+
message_role: z20.enum(["assistant", "user"]),
|
|
6730
|
+
message_timestamp: z20.string().datetime(),
|
|
6731
|
+
excerpt: z20.string(),
|
|
6732
|
+
permalink: z20.string().url().optional()
|
|
6755
6733
|
}).strict()
|
|
6756
6734
|
)
|
|
6757
6735
|
});
|
|
@@ -6764,9 +6742,9 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
|
|
|
6764
6742
|
description: "Search retained public Junior conversation threads in the current Slack workspace."
|
|
6765
6743
|
},
|
|
6766
6744
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
6767
|
-
inputSchema:
|
|
6768
|
-
query:
|
|
6769
|
-
limit:
|
|
6745
|
+
inputSchema: z20.object({
|
|
6746
|
+
query: z20.string().trim().min(1).max(200).describe("Words or a short phrase to find in prior conversations."),
|
|
6747
|
+
limit: z20.number().int().min(1).max(10).describe("Maximum number of prior conversation threads to return.").nullable().optional()
|
|
6770
6748
|
}),
|
|
6771
6749
|
outputSchema: conversationSearchOutputSchema,
|
|
6772
6750
|
execute: async ({ query, limit }) => {
|
|
@@ -6813,27 +6791,27 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
|
|
|
6813
6791
|
}
|
|
6814
6792
|
|
|
6815
6793
|
// src/chat/slack/tools/public-search.ts
|
|
6816
|
-
import { z as
|
|
6794
|
+
import { z as z21 } from "zod";
|
|
6817
6795
|
var DEFAULT_LIMIT2 = 10;
|
|
6818
|
-
var optionalTimestampSchema =
|
|
6796
|
+
var optionalTimestampSchema = z21.preprocess(
|
|
6819
6797
|
(value) => typeof value === "string" && value.trim() === "" ? void 0 : value,
|
|
6820
|
-
|
|
6798
|
+
z21.coerce.number().int().nonnegative().describe("Optional Unix timestamp bound.").optional()
|
|
6821
6799
|
);
|
|
6822
|
-
var searchMessageSchema =
|
|
6823
|
-
author_name:
|
|
6824
|
-
author_user_id:
|
|
6825
|
-
channel_id:
|
|
6826
|
-
channel_name:
|
|
6827
|
-
message_ts:
|
|
6828
|
-
content:
|
|
6829
|
-
is_author_bot:
|
|
6830
|
-
permalink:
|
|
6800
|
+
var searchMessageSchema = z21.object({
|
|
6801
|
+
author_name: z21.string().optional(),
|
|
6802
|
+
author_user_id: z21.string().optional(),
|
|
6803
|
+
channel_id: z21.string().min(1),
|
|
6804
|
+
channel_name: z21.string().optional(),
|
|
6805
|
+
message_ts: z21.string().min(1),
|
|
6806
|
+
content: z21.string(),
|
|
6807
|
+
is_author_bot: z21.boolean().optional(),
|
|
6808
|
+
permalink: z21.string().url()
|
|
6831
6809
|
});
|
|
6832
6810
|
var publicSearchOutputSchema = juniorToolResultSchema.extend({
|
|
6833
|
-
query:
|
|
6834
|
-
count:
|
|
6835
|
-
messages:
|
|
6836
|
-
next_cursor:
|
|
6811
|
+
query: z21.string(),
|
|
6812
|
+
count: z21.number().int().nonnegative(),
|
|
6813
|
+
messages: z21.array(searchMessageSchema),
|
|
6814
|
+
next_cursor: z21.string().optional()
|
|
6837
6815
|
});
|
|
6838
6816
|
function normalizeMessage(value) {
|
|
6839
6817
|
const parsed = searchMessageSchema.safeParse(value);
|
|
@@ -6855,8 +6833,8 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
6855
6833
|
return zodTool({
|
|
6856
6834
|
description: "Search public Slack channel messages across the current workspace. Use when the user asks about company activity, announcements, public mentions, or context outside the active channel. Search only when requested or clearly needed, prefer focused keywords and time bounds, and cite returned permalinks. This never searches private channels or DMs.",
|
|
6857
6835
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
6858
|
-
inputSchema:
|
|
6859
|
-
query:
|
|
6836
|
+
inputSchema: z21.object({
|
|
6837
|
+
query: z21.string().trim().min(1).max(500).describe(
|
|
6860
6838
|
"A focused Slack search query, including Slack search filters when useful."
|
|
6861
6839
|
),
|
|
6862
6840
|
after: optionalTimestampSchema.describe(
|
|
@@ -6865,10 +6843,10 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
6865
6843
|
before: optionalTimestampSchema.describe(
|
|
6866
6844
|
"Optional Unix timestamp upper bound."
|
|
6867
6845
|
),
|
|
6868
|
-
cursor:
|
|
6869
|
-
limit:
|
|
6870
|
-
sort:
|
|
6871
|
-
sort_dir:
|
|
6846
|
+
cursor: z21.string().min(1).describe("Cursor for the next result page.").optional(),
|
|
6847
|
+
limit: z21.coerce.number().int().min(1).max(20).describe("Maximum results to return; Slack allows at most 20.").optional(),
|
|
6848
|
+
sort: z21.enum(["score", "timestamp"]).describe("Rank by relevance or timestamp.").optional(),
|
|
6849
|
+
sort_dir: z21.enum(["asc", "desc"]).describe("Sort direction.").optional()
|
|
6872
6850
|
}),
|
|
6873
6851
|
outputSchema: publicSearchOutputSchema,
|
|
6874
6852
|
execute: async ({
|
|
@@ -6934,7 +6912,7 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
6934
6912
|
}
|
|
6935
6913
|
|
|
6936
6914
|
// src/chat/slack/tools/message-add-reaction.ts
|
|
6937
|
-
import { z as
|
|
6915
|
+
import { z as z22 } from "zod";
|
|
6938
6916
|
|
|
6939
6917
|
// src/chat/tools/idempotency.ts
|
|
6940
6918
|
function stableSerialize(value) {
|
|
@@ -6958,8 +6936,8 @@ function createOperationKey(toolName, input) {
|
|
|
6958
6936
|
function createSlackMessageAddReactionTool(context, state) {
|
|
6959
6937
|
return zodTool({
|
|
6960
6938
|
description: "Add an emoji reaction to the current inbound Slack message. Use when the user asks for a reaction on the current message without another target. Provide a Slack emoji alias name (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`), not a unicode emoji glyph. The target message is injected by runtime context; do not use this for arbitrary historical messages.",
|
|
6961
|
-
inputSchema:
|
|
6962
|
-
emoji:
|
|
6939
|
+
inputSchema: z22.object({
|
|
6940
|
+
emoji: z22.string().min(1).max(64).describe(
|
|
6963
6941
|
"Slack emoji alias name to react with (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`). Optional surrounding colons are allowed."
|
|
6964
6942
|
)
|
|
6965
6943
|
}),
|
|
@@ -7008,23 +6986,24 @@ function createSlackMessageAddReactionTool(context, state) {
|
|
|
7008
6986
|
});
|
|
7009
6987
|
}
|
|
7010
6988
|
|
|
7011
|
-
// src/chat/slack/tools/send-
|
|
6989
|
+
// src/chat/slack/tools/send-files.ts
|
|
7012
6990
|
import { createHash as createHash2 } from "crypto";
|
|
7013
|
-
import { z as
|
|
7014
|
-
var
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
),
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
),
|
|
7021
|
-
mimeType: z22.string().min(1).nullable().optional().describe("Optional MIME type override. Null is treated as omitted.")
|
|
6991
|
+
import { z as z23 } from "zod";
|
|
6992
|
+
var sendFilesDataSchema = z23.object({
|
|
6993
|
+
channel_id: z23.string().min(1),
|
|
6994
|
+
deduplicated: z23.boolean().optional(),
|
|
6995
|
+
file_count: z23.number().int().nonnegative(),
|
|
6996
|
+
file_ids: z23.array(z23.string().min(1)).optional(),
|
|
6997
|
+
thread_ts: z23.string().min(1)
|
|
7022
6998
|
});
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
6999
|
+
var sendFilesResultSchema = juniorToolResultSchema.extend({
|
|
7000
|
+
ok: z23.literal(true),
|
|
7001
|
+
status: z23.literal("success"),
|
|
7002
|
+
target: z23.string().min(1),
|
|
7003
|
+
data: sendFilesDataSchema
|
|
7004
|
+
});
|
|
7005
|
+
function normalizeFiles(files) {
|
|
7006
|
+
return files.map((file) => ({
|
|
7028
7007
|
path: file.path,
|
|
7029
7008
|
...file.filename ? { filename: file.filename } : {},
|
|
7030
7009
|
...file.mimeType ? { mimeType: file.mimeType } : {}
|
|
@@ -7042,18 +7021,17 @@ function fileOperationInput(files) {
|
|
|
7042
7021
|
sha256: fileContentDigest(file.data)
|
|
7043
7022
|
}));
|
|
7044
7023
|
}
|
|
7045
|
-
function
|
|
7024
|
+
function createSendFilesTool(context, state, materializeFile) {
|
|
7046
7025
|
return zodTool({
|
|
7047
|
-
description: "Send
|
|
7048
|
-
inputSchema:
|
|
7049
|
-
|
|
7050
|
-
|
|
7051
|
-
"Sandbox files to include in the message. Null is treated as omitted."
|
|
7026
|
+
description: "Send one or more sandbox files into the active Slack conversation. Use when the user asks to attach, send, or share files here, in this conversation, or in this thread. Do not use for ordinary assistant text, top-level channel posts, other named channels, inline @mentions, or pinging mentioned users.",
|
|
7027
|
+
inputSchema: z23.object({
|
|
7028
|
+
files: z23.array(sandboxFileReferenceSchema).min(1).describe(
|
|
7029
|
+
"One or more existing sandbox files. Objects returned by imageGenerate or webFetch can be passed unchanged."
|
|
7052
7030
|
)
|
|
7053
7031
|
}),
|
|
7054
|
-
outputSchema:
|
|
7055
|
-
execute: async ({
|
|
7056
|
-
const filesToSend =
|
|
7032
|
+
outputSchema: sendFilesResultSchema,
|
|
7033
|
+
execute: async ({ files }) => {
|
|
7034
|
+
const filesToSend = normalizeFiles(files);
|
|
7057
7035
|
const activeChannelId = context.sourceChannelId;
|
|
7058
7036
|
if (!activeChannelId) {
|
|
7059
7037
|
throw new ToolInputError("No active Slack conversation is available.");
|
|
@@ -7064,48 +7042,34 @@ function createSendMessageTool(context, state, materializeFile) {
|
|
|
7064
7042
|
"No active Slack conversation timestamp is available."
|
|
7065
7043
|
);
|
|
7066
7044
|
}
|
|
7067
|
-
const textToSend = hasText(text) ? text : void 0;
|
|
7068
|
-
if (!textToSend && filesToSend.length === 0) {
|
|
7069
|
-
throw new ToolInputError(
|
|
7070
|
-
"sendMessage requires text or at least one file."
|
|
7071
|
-
);
|
|
7072
|
-
}
|
|
7073
7045
|
const materializedFiles = await Promise.all(
|
|
7074
7046
|
filesToSend.map((file) => materializeFile(file))
|
|
7075
7047
|
);
|
|
7076
|
-
const operationKey = createOperationKey("
|
|
7048
|
+
const operationKey = createOperationKey("sendFiles", {
|
|
7077
7049
|
channel_id: activeChannelId,
|
|
7078
7050
|
thread_ts: threadTs,
|
|
7079
|
-
|
|
7080
|
-
...materializedFiles.length > 0 ? { files: fileOperationInput(materializedFiles) } : {}
|
|
7051
|
+
files: fileOperationInput(materializedFiles)
|
|
7081
7052
|
});
|
|
7082
7053
|
const cached = state.getOperationResult(operationKey);
|
|
7083
7054
|
if (cached) {
|
|
7084
|
-
return {
|
|
7055
|
+
return sendFilesResultSchema.parse({
|
|
7085
7056
|
...cached,
|
|
7086
7057
|
data: {
|
|
7087
7058
|
...cached.data,
|
|
7088
7059
|
deduplicated: true
|
|
7089
|
-
}
|
|
7090
|
-
|
|
7091
|
-
};
|
|
7060
|
+
}
|
|
7061
|
+
});
|
|
7092
7062
|
}
|
|
7093
7063
|
const uploads = materializedFiles.map((file) => ({
|
|
7094
7064
|
data: file.data,
|
|
7095
7065
|
filename: file.filename
|
|
7096
7066
|
}));
|
|
7097
|
-
const
|
|
7098
|
-
channelId: activeChannelId,
|
|
7099
|
-
text: textToSend,
|
|
7100
|
-
threadTs,
|
|
7101
|
-
includePermalink: true
|
|
7102
|
-
}) : void 0;
|
|
7103
|
-
const uploaded = uploads.length > 0 ? await uploadFilesToConversation({
|
|
7067
|
+
const uploaded = await uploadFilesToConversation({
|
|
7104
7068
|
channelId: activeChannelId,
|
|
7105
7069
|
files: uploads,
|
|
7106
|
-
threadTs
|
|
7107
|
-
|
|
7108
|
-
|
|
7070
|
+
threadTs
|
|
7071
|
+
});
|
|
7072
|
+
const fileIds = uploaded?.files?.map((file) => file.id).filter((id) => Boolean(id));
|
|
7109
7073
|
const response = {
|
|
7110
7074
|
ok: true,
|
|
7111
7075
|
status: "success",
|
|
@@ -7113,19 +7077,9 @@ function createSendMessageTool(context, state, materializeFile) {
|
|
|
7113
7077
|
data: {
|
|
7114
7078
|
channel_id: activeChannelId,
|
|
7115
7079
|
thread_ts: threadTs,
|
|
7116
|
-
|
|
7117
|
-
...
|
|
7118
|
-
|
|
7119
|
-
file_ids: uploaded.files.map((file) => file.id).filter((id) => Boolean(id))
|
|
7120
|
-
} : {}
|
|
7121
|
-
},
|
|
7122
|
-
channel_id: activeChannelId,
|
|
7123
|
-
thread_ts: threadTs,
|
|
7124
|
-
...posted ? { ts: posted.ts, permalink: posted.permalink } : {},
|
|
7125
|
-
...uploads.length > 0 ? { file_count: uploads.length } : {},
|
|
7126
|
-
...uploaded?.files ? {
|
|
7127
|
-
file_ids: uploaded.files.map((file) => file.id).filter((id) => Boolean(id))
|
|
7128
|
-
} : {}
|
|
7080
|
+
file_count: uploads.length,
|
|
7081
|
+
...fileIds ? { file_ids: fileIds } : {}
|
|
7082
|
+
}
|
|
7129
7083
|
};
|
|
7130
7084
|
state.setOperationResult(operationKey, response);
|
|
7131
7085
|
return response;
|
|
@@ -7375,13 +7329,13 @@ function storedCanvasUrl(state, canvasId) {
|
|
|
7375
7329
|
}
|
|
7376
7330
|
|
|
7377
7331
|
// src/chat/slack/tools/canvas/create.ts
|
|
7378
|
-
import { z as
|
|
7332
|
+
import { z as z24 } from "zod";
|
|
7379
7333
|
function createSlackCanvasCreateTool(context, state) {
|
|
7380
7334
|
return zodTool({
|
|
7381
7335
|
description: "Create a Slack canvas for long-form output in the active assistant context channel. Use when the answer is better as a reusable document than a thread reply: long-form research, timelines, bios/profiles, structured notes, plans, comparisons, or anything likely to exceed one compact Slack reply. After creating it, reply with one or two short sentences plus the canvas link; do not recap the canvas contents. Do not use for short answers that fit cleanly in one normal thread reply.",
|
|
7382
|
-
inputSchema:
|
|
7383
|
-
title:
|
|
7384
|
-
markdown:
|
|
7336
|
+
inputSchema: z24.object({
|
|
7337
|
+
title: z24.string().min(1).max(160).describe("Canvas title."),
|
|
7338
|
+
markdown: z24.string().min(1).describe("Canvas markdown body content.")
|
|
7385
7339
|
}),
|
|
7386
7340
|
outputSchema: juniorToolResultSchema,
|
|
7387
7341
|
execute: async ({ title, markdown }) => {
|
|
@@ -7444,35 +7398,35 @@ function createSlackCanvasCreateTool(context, state) {
|
|
|
7444
7398
|
}
|
|
7445
7399
|
|
|
7446
7400
|
// src/chat/slack/tools/canvas/edit.ts
|
|
7447
|
-
import { z as
|
|
7401
|
+
import { z as z25 } from "zod";
|
|
7448
7402
|
function prepareCanvasEditArguments(input) {
|
|
7449
7403
|
return prepareTextReplacementArguments(input);
|
|
7450
7404
|
}
|
|
7451
|
-
var editReplacementSchema2 =
|
|
7452
|
-
oldText:
|
|
7405
|
+
var editReplacementSchema2 = z25.object({
|
|
7406
|
+
oldText: z25.string().min(1).describe(
|
|
7453
7407
|
"Exact Canvas markdown to replace. It must be unique in the current Canvas body and must not overlap another edit."
|
|
7454
7408
|
),
|
|
7455
|
-
newText:
|
|
7409
|
+
newText: z25.string().describe("Replacement Canvas markdown for this edit.")
|
|
7456
7410
|
});
|
|
7457
7411
|
var slackCanvasEditOutputSchema = juniorToolResultSchema.extend({
|
|
7458
|
-
canvas_id:
|
|
7459
|
-
title:
|
|
7460
|
-
permalink:
|
|
7461
|
-
diff:
|
|
7462
|
-
first_changed_line:
|
|
7463
|
-
replacements:
|
|
7464
|
-
normalized_heading_count:
|
|
7465
|
-
summary:
|
|
7466
|
-
deduplicated:
|
|
7412
|
+
canvas_id: z25.string().optional(),
|
|
7413
|
+
title: z25.string().optional(),
|
|
7414
|
+
permalink: z25.string().optional(),
|
|
7415
|
+
diff: z25.string().optional(),
|
|
7416
|
+
first_changed_line: z25.number().int().positive().optional(),
|
|
7417
|
+
replacements: z25.number().int().nonnegative().optional(),
|
|
7418
|
+
normalized_heading_count: z25.number().int().nonnegative().optional(),
|
|
7419
|
+
summary: z25.string().optional(),
|
|
7420
|
+
deduplicated: z25.boolean().optional()
|
|
7467
7421
|
}).strict();
|
|
7468
7422
|
function createSlackCanvasEditTool(state) {
|
|
7469
7423
|
return zodTool({
|
|
7470
7424
|
description: "Edit one Slack canvas with exact markdown replacements. Use for precise changes to existing Canvas content; prefer this over slackCanvasWrite for targeted changes. Each oldText must match exactly, be unique, and not overlap another edit. Returns a diff. Multiple changes to the same canvas: use one edits[] call.",
|
|
7471
7425
|
prepareArguments: prepareCanvasEditArguments,
|
|
7472
7426
|
executionMode: "sequential",
|
|
7473
|
-
inputSchema:
|
|
7474
|
-
canvas:
|
|
7475
|
-
edits:
|
|
7427
|
+
inputSchema: z25.object({
|
|
7428
|
+
canvas: z25.string().min(1).describe("Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL."),
|
|
7429
|
+
edits: z25.array(editReplacementSchema2).min(1).describe(
|
|
7476
7430
|
"Exact replacements matched against the current Canvas body, not incrementally."
|
|
7477
7431
|
)
|
|
7478
7432
|
}),
|
|
@@ -7550,29 +7504,29 @@ function createSlackCanvasEditTool(state) {
|
|
|
7550
7504
|
}
|
|
7551
7505
|
|
|
7552
7506
|
// src/chat/slack/tools/canvas/read.ts
|
|
7553
|
-
import { z as
|
|
7507
|
+
import { z as z26 } from "zod";
|
|
7554
7508
|
var slackCanvasReadOutputSchema = juniorToolResultSchema.extend({
|
|
7555
|
-
canvas_id:
|
|
7556
|
-
title:
|
|
7557
|
-
permalink:
|
|
7558
|
-
mimetype:
|
|
7559
|
-
filetype:
|
|
7560
|
-
original_byte_length:
|
|
7561
|
-
content:
|
|
7562
|
-
start_line:
|
|
7563
|
-
end_line:
|
|
7564
|
-
total_lines:
|
|
7509
|
+
canvas_id: z26.string().optional(),
|
|
7510
|
+
title: z26.string().optional(),
|
|
7511
|
+
permalink: z26.string().optional(),
|
|
7512
|
+
mimetype: z26.string().optional(),
|
|
7513
|
+
filetype: z26.string().optional(),
|
|
7514
|
+
original_byte_length: z26.number().int().nonnegative().optional(),
|
|
7515
|
+
content: z26.string().optional(),
|
|
7516
|
+
start_line: z26.number().int().positive().optional(),
|
|
7517
|
+
end_line: z26.number().int().nonnegative().optional(),
|
|
7518
|
+
total_lines: z26.number().int().nonnegative().optional()
|
|
7565
7519
|
}).strict();
|
|
7566
7520
|
function createSlackCanvasReadTool() {
|
|
7567
7521
|
return zodTool({
|
|
7568
7522
|
description: "Read a bounded line range from a Slack canvas as markdown. Use when you need exact Canvas contents to verify facts or make edits safely. Do not use for generic web pages \u2014 use webFetch for those.",
|
|
7569
7523
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
7570
|
-
inputSchema:
|
|
7571
|
-
canvas:
|
|
7524
|
+
inputSchema: z26.object({
|
|
7525
|
+
canvas: z26.string().min(1).describe(
|
|
7572
7526
|
"Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL (e.g. `https://team.slack.com/docs/T.../F...`)."
|
|
7573
7527
|
),
|
|
7574
|
-
offset:
|
|
7575
|
-
limit:
|
|
7528
|
+
offset: z26.coerce.number().int().min(1).describe("1-indexed line number to start reading from.").optional(),
|
|
7529
|
+
limit: z26.coerce.number().int().min(1).describe("Maximum number of lines to read. Defaults to 1000.").optional()
|
|
7576
7530
|
}),
|
|
7577
7531
|
outputSchema: slackCanvasReadOutputSchema,
|
|
7578
7532
|
execute: async ({ canvas, offset, limit }) => {
|
|
@@ -7629,14 +7583,14 @@ function createSlackCanvasReadTool() {
|
|
|
7629
7583
|
}
|
|
7630
7584
|
|
|
7631
7585
|
// src/chat/slack/tools/canvas/write.ts
|
|
7632
|
-
import { z as
|
|
7586
|
+
import { z as z27 } from "zod";
|
|
7633
7587
|
function createSlackCanvasWriteTool(state) {
|
|
7634
7588
|
return zodTool({
|
|
7635
7589
|
description: "Write UTF-8 markdown content to a Slack canvas. Use for deliberate full-Canvas replacement after validation; use slackCanvasEdit for targeted changes to existing canvas content.",
|
|
7636
7590
|
executionMode: "sequential",
|
|
7637
|
-
inputSchema:
|
|
7638
|
-
canvas:
|
|
7639
|
-
content:
|
|
7591
|
+
inputSchema: z27.object({
|
|
7592
|
+
canvas: z27.string().min(1).describe("Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL."),
|
|
7593
|
+
content: z27.string().describe("UTF-8 markdown content to write.")
|
|
7640
7594
|
}),
|
|
7641
7595
|
outputSchema: juniorToolResultSchema,
|
|
7642
7596
|
execute: async ({ canvas, content }) => {
|
|
@@ -7872,12 +7826,12 @@ async function updateListItem(input) {
|
|
|
7872
7826
|
}
|
|
7873
7827
|
|
|
7874
7828
|
// src/chat/slack/id-param.ts
|
|
7875
|
-
import { z as
|
|
7829
|
+
import { z as z28 } from "zod";
|
|
7876
7830
|
function slackChannelIdParam(description) {
|
|
7877
|
-
return
|
|
7831
|
+
return z28.string().min(1).describe(description);
|
|
7878
7832
|
}
|
|
7879
7833
|
function slackUserIdParam(description) {
|
|
7880
|
-
return
|
|
7834
|
+
return z28.string().min(1).describe(description);
|
|
7881
7835
|
}
|
|
7882
7836
|
function parseRequiredSlackChannelIdParam(field, value) {
|
|
7883
7837
|
const channelId = parseSlackChannelId(value);
|
|
@@ -7901,16 +7855,16 @@ function parseRequiredSlackUserIdParam(field, value) {
|
|
|
7901
7855
|
}
|
|
7902
7856
|
|
|
7903
7857
|
// src/chat/slack/tools/list/add-items.ts
|
|
7904
|
-
import { z as
|
|
7858
|
+
import { z as z29 } from "zod";
|
|
7905
7859
|
function createSlackListAddItemsTool(state) {
|
|
7906
7860
|
return zodTool({
|
|
7907
7861
|
description: "Add tasks to the active Slack list tracked in artifact context. Use when the user wants actionable items recorded in the current thread list. Do not use when no list exists and list creation was not requested.",
|
|
7908
|
-
inputSchema:
|
|
7909
|
-
items:
|
|
7862
|
+
inputSchema: z29.object({
|
|
7863
|
+
items: z29.array(z29.string().min(1)).min(1).max(25).describe("List item titles to create."),
|
|
7910
7864
|
assignee_user_id: slackUserIdParam(
|
|
7911
7865
|
"Optional Slack user ID assigned to all created items."
|
|
7912
7866
|
).optional(),
|
|
7913
|
-
due_date:
|
|
7867
|
+
due_date: z29.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
|
|
7914
7868
|
}),
|
|
7915
7869
|
outputSchema: juniorToolResultSchema,
|
|
7916
7870
|
execute: async ({ items, assignee_user_id, due_date }) => {
|
|
@@ -7964,12 +7918,12 @@ function createSlackListAddItemsTool(state) {
|
|
|
7964
7918
|
}
|
|
7965
7919
|
|
|
7966
7920
|
// src/chat/slack/tools/list/create.ts
|
|
7967
|
-
import { z as
|
|
7921
|
+
import { z as z30 } from "zod";
|
|
7968
7922
|
function createSlackListCreateTool(state) {
|
|
7969
7923
|
return zodTool({
|
|
7970
7924
|
description: "Create a Slack todo list for action tracking. Use when the user needs structured tasks with ownership/completion tracking. Do not use for one-off notes without task management needs.",
|
|
7971
|
-
inputSchema:
|
|
7972
|
-
name:
|
|
7925
|
+
inputSchema: z30.object({
|
|
7926
|
+
name: z30.string().min(1).max(160).describe("Name for the new Slack list.")
|
|
7973
7927
|
}),
|
|
7974
7928
|
outputSchema: juniorToolResultSchema,
|
|
7975
7929
|
execute: async ({ name }) => {
|
|
@@ -8001,13 +7955,13 @@ function createSlackListCreateTool(state) {
|
|
|
8001
7955
|
}
|
|
8002
7956
|
|
|
8003
7957
|
// src/chat/slack/tools/list/get-items.ts
|
|
8004
|
-
import { z as
|
|
7958
|
+
import { z as z31 } from "zod";
|
|
8005
7959
|
function createSlackListGetItemsTool(state) {
|
|
8006
7960
|
return zodTool({
|
|
8007
7961
|
description: "Read items from the active Slack list tracked in artifact context. Use when the user asks for task status, open items, or list contents. Do not use when list state is already known from the immediately prior result.",
|
|
8008
7962
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8009
|
-
inputSchema:
|
|
8010
|
-
limit:
|
|
7963
|
+
inputSchema: z31.object({
|
|
7964
|
+
limit: z31.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
|
|
8011
7965
|
}),
|
|
8012
7966
|
outputSchema: juniorToolResultSchema,
|
|
8013
7967
|
execute: async ({ limit }) => {
|
|
@@ -8032,21 +7986,21 @@ function createSlackListGetItemsTool(state) {
|
|
|
8032
7986
|
}
|
|
8033
7987
|
|
|
8034
7988
|
// src/chat/slack/tools/list/update-item.ts
|
|
8035
|
-
import { z as
|
|
8036
|
-
var booleanInput3 = (description) =>
|
|
7989
|
+
import { z as z32 } from "zod";
|
|
7990
|
+
var booleanInput3 = (description) => z32.preprocess(
|
|
8037
7991
|
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
8038
|
-
|
|
7992
|
+
z32.boolean()
|
|
8039
7993
|
).describe(description);
|
|
8040
|
-
var updateListItemInputSchema =
|
|
8041
|
-
|
|
8042
|
-
item_id:
|
|
7994
|
+
var updateListItemInputSchema = z32.union([
|
|
7995
|
+
z32.object({
|
|
7996
|
+
item_id: z32.string().min(1).describe("ID of the Slack list item to update."),
|
|
8043
7997
|
completed: booleanInput3("Optional completion status update."),
|
|
8044
|
-
title:
|
|
7998
|
+
title: z32.string().min(1).describe("Optional new item title.").optional()
|
|
8045
7999
|
}),
|
|
8046
|
-
|
|
8047
|
-
item_id:
|
|
8000
|
+
z32.object({
|
|
8001
|
+
item_id: z32.string().min(1).describe("ID of the Slack list item to update."),
|
|
8048
8002
|
completed: booleanInput3("Optional completion status update.").optional(),
|
|
8049
|
-
title:
|
|
8003
|
+
title: z32.string().min(1).describe("Optional new item title.")
|
|
8050
8004
|
})
|
|
8051
8005
|
]);
|
|
8052
8006
|
function createSlackListUpdateItemTool(state) {
|
|
@@ -8122,7 +8076,7 @@ async function checkSlackChannelReadAccess(args) {
|
|
|
8122
8076
|
}
|
|
8123
8077
|
|
|
8124
8078
|
// src/chat/slack/tools/thread-read.ts
|
|
8125
|
-
import { z as
|
|
8079
|
+
import { z as z33 } from "zod";
|
|
8126
8080
|
|
|
8127
8081
|
// src/chat/slack/tools/slack-message-url.ts
|
|
8128
8082
|
var SLACK_HOST_PATTERN = /^[a-z0-9-]+\.slack(?:-gov)?\.com$/;
|
|
@@ -8295,8 +8249,8 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
8295
8249
|
return zodTool({
|
|
8296
8250
|
description: "Read a Slack thread from a shared Slack message archive URL or explicit channel + timestamp. Use when the user shares a Slack message link (https://*.slack.com/archives/...) and you need the referenced message and its thread context. Only the current conversation and public channels Junior has seen in this workspace are readable.",
|
|
8297
8251
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8298
|
-
inputSchema:
|
|
8299
|
-
url:
|
|
8252
|
+
inputSchema: z33.object({
|
|
8253
|
+
url: z33.string().min(1).describe(
|
|
8300
8254
|
"Slack message archive URL, e.g. https://workspace.slack.com/archives/C123/p1700000000123456"
|
|
8301
8255
|
).optional(),
|
|
8302
8256
|
channel_id: slackChannelIdParam(
|
|
@@ -8305,8 +8259,8 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
8305
8259
|
ts: slackTimestampParam(
|
|
8306
8260
|
"Slack message timestamp (e.g. 1700000000.123456). May be the thread root or any message in the thread."
|
|
8307
8261
|
).optional(),
|
|
8308
|
-
limit:
|
|
8309
|
-
max_pages:
|
|
8262
|
+
limit: z33.coerce.number().int().min(1).max(1e3).describe("Maximum number of thread messages to fetch.").optional(),
|
|
8263
|
+
max_pages: z33.coerce.number().int().min(1).max(10).describe("Maximum number of Slack API pages to traverse.").optional()
|
|
8310
8264
|
}),
|
|
8311
8265
|
outputSchema: juniorToolResultSchema,
|
|
8312
8266
|
execute: async ({ url, channel_id, ts, limit, max_pages }) => {
|
|
@@ -8562,29 +8516,29 @@ async function searchSlackUsers(options) {
|
|
|
8562
8516
|
}
|
|
8563
8517
|
|
|
8564
8518
|
// src/chat/slack/tools/user-lookup.ts
|
|
8565
|
-
import { z as
|
|
8566
|
-
var booleanInput4 = (description) =>
|
|
8519
|
+
import { z as z34 } from "zod";
|
|
8520
|
+
var booleanInput4 = (description) => z34.preprocess(
|
|
8567
8521
|
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
8568
|
-
|
|
8522
|
+
z34.boolean()
|
|
8569
8523
|
).describe(description);
|
|
8570
8524
|
function createSlackUserLookupTool() {
|
|
8571
8525
|
return zodTool({
|
|
8572
8526
|
description: "Look up Slack user profiles by user ID, email, or name search. Use when you need to identify a user, resolve cross-platform identity, or look up profile details like title or status. Returns profile fields including custom fields. For user ID lookup, pass a Slack user ID (e.g. U039RR91S). For search, pass a name query.",
|
|
8573
8527
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8574
|
-
inputSchema:
|
|
8528
|
+
inputSchema: z34.object({
|
|
8575
8529
|
user_id: slackUserIdParam(
|
|
8576
8530
|
"Slack user ID to look up (e.g. U039RR91S). Mutually exclusive with email and query."
|
|
8577
8531
|
).optional(),
|
|
8578
|
-
email:
|
|
8532
|
+
email: z34.string().min(3).describe(
|
|
8579
8533
|
"Email address to look up. Mutually exclusive with user_id and query."
|
|
8580
8534
|
).optional(),
|
|
8581
|
-
query:
|
|
8535
|
+
query: z34.string().min(2).describe(
|
|
8582
8536
|
"Name to search for (matches against username, display name, real name). Mutually exclusive with user_id and email."
|
|
8583
8537
|
).optional(),
|
|
8584
|
-
limit:
|
|
8538
|
+
limit: z34.coerce.number().int().min(1).max(20).describe(
|
|
8585
8539
|
"Maximum number of results to return for name search. Defaults to 10."
|
|
8586
8540
|
).optional(),
|
|
8587
|
-
max_pages:
|
|
8541
|
+
max_pages: z34.coerce.number().int().min(1).max(5).describe(
|
|
8588
8542
|
"Maximum number of Slack API pages to scan for name search. Defaults to 3."
|
|
8589
8543
|
).optional(),
|
|
8590
8544
|
include_bots: booleanInput4(
|
|
@@ -8688,18 +8642,18 @@ function createSlackUserLookupTool() {
|
|
|
8688
8642
|
}
|
|
8689
8643
|
|
|
8690
8644
|
// src/chat/tools/system-time.ts
|
|
8691
|
-
import { z as
|
|
8645
|
+
import { z as z35 } from "zod";
|
|
8692
8646
|
var systemTimeOutputSchema = juniorToolResultSchema.extend({
|
|
8693
|
-
unix_ms:
|
|
8694
|
-
iso_utc:
|
|
8695
|
-
iso_local:
|
|
8696
|
-
timezone_offset_minutes:
|
|
8647
|
+
unix_ms: z35.number(),
|
|
8648
|
+
iso_utc: z35.string(),
|
|
8649
|
+
iso_local: z35.string(),
|
|
8650
|
+
timezone_offset_minutes: z35.number()
|
|
8697
8651
|
});
|
|
8698
8652
|
function createSystemTimeTool() {
|
|
8699
8653
|
return zodTool({
|
|
8700
8654
|
description: "Return current system time in UTC and local ISO formats. Use when the user asks for current time/date context. Do not use as a substitute for historical or timezone-conversion research.",
|
|
8701
8655
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8702
|
-
inputSchema:
|
|
8656
|
+
inputSchema: z35.object({}),
|
|
8703
8657
|
outputSchema: systemTimeOutputSchema,
|
|
8704
8658
|
privateTraceResult: (result) => ({
|
|
8705
8659
|
ok: result.ok,
|
|
@@ -8728,27 +8682,30 @@ function createSystemTimeTool() {
|
|
|
8728
8682
|
}
|
|
8729
8683
|
|
|
8730
8684
|
// src/chat/tools/handoff/tool.ts
|
|
8731
|
-
import { z as
|
|
8685
|
+
import { z as z36 } from "zod";
|
|
8732
8686
|
var HANDOFF_TOOL_NAME = "handoff";
|
|
8733
8687
|
function createHandoffTool(handoff) {
|
|
8734
|
-
const profileSchema =
|
|
8735
|
-
const defaultProfile = handoff.profiles[0];
|
|
8688
|
+
const profileSchema = z36.enum(handoff.profiles);
|
|
8736
8689
|
const handoffResultSchema = juniorToolResultSchema.extend({
|
|
8737
8690
|
model_profile: profileSchema
|
|
8738
8691
|
});
|
|
8739
8692
|
const profileNames = handoff.profiles.map((profile) => `\`${profile}\``).join(", ");
|
|
8740
8693
|
return zodTool({
|
|
8741
|
-
description: `
|
|
8694
|
+
description: `Switch to another execution profile and continue the same task. Profiles: ${profileNames}. Call this as the only tool.`,
|
|
8742
8695
|
executionMode: "sequential",
|
|
8743
|
-
inputSchema:
|
|
8744
|
-
profile: profileSchema.
|
|
8745
|
-
"Named model profile to use for the rest of the conversation; omit or pass null for the default"
|
|
8746
|
-
)
|
|
8696
|
+
inputSchema: z36.object({
|
|
8697
|
+
profile: profileSchema.describe("Target execution profile")
|
|
8747
8698
|
}).strict(),
|
|
8748
8699
|
outputSchema: handoffResultSchema,
|
|
8749
8700
|
execute: async (input, options) => {
|
|
8750
|
-
const profile = input.profile
|
|
8751
|
-
|
|
8701
|
+
const profile = input.profile;
|
|
8702
|
+
if (!options.toolCallId) {
|
|
8703
|
+
throw new ToolInputError("Handoff requires an active tool call ID");
|
|
8704
|
+
}
|
|
8705
|
+
await handoff.execute(profile, {
|
|
8706
|
+
...options.signal ? { signal: options.signal } : {},
|
|
8707
|
+
toolCallId: options.toolCallId
|
|
8708
|
+
});
|
|
8752
8709
|
return {
|
|
8753
8710
|
ok: true,
|
|
8754
8711
|
status: "success",
|
|
@@ -8759,7 +8716,7 @@ function createHandoffTool(handoff) {
|
|
|
8759
8716
|
}
|
|
8760
8717
|
|
|
8761
8718
|
// src/chat/tools/web/fetch-tool.ts
|
|
8762
|
-
import { z as
|
|
8719
|
+
import { z as z37 } from "zod";
|
|
8763
8720
|
|
|
8764
8721
|
// src/chat/tools/web/constants.ts
|
|
8765
8722
|
var USER_AGENT = "junior-bot/0.1";
|
|
@@ -9206,9 +9163,9 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
9206
9163
|
destructiveHint: false,
|
|
9207
9164
|
openWorldHint: true
|
|
9208
9165
|
},
|
|
9209
|
-
inputSchema:
|
|
9210
|
-
url:
|
|
9211
|
-
max_chars:
|
|
9166
|
+
inputSchema: z37.object({
|
|
9167
|
+
url: z37.string().min(1).describe("HTTP(S) URL to fetch."),
|
|
9168
|
+
max_chars: z37.coerce.number().int().min(500).max(MAX_FETCH_CHARS).describe("Optional maximum number of extracted characters to return.").optional()
|
|
9212
9169
|
}),
|
|
9213
9170
|
outputSchema: juniorToolResultSchema,
|
|
9214
9171
|
execute: async ({ url, max_chars }) => {
|
|
@@ -9246,14 +9203,8 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
9246
9203
|
url: safeUrl.toString(),
|
|
9247
9204
|
media_type: contentType,
|
|
9248
9205
|
bytes: bytes.byteLength,
|
|
9249
|
-
images: artifactRefs
|
|
9250
|
-
|
|
9251
|
-
path: artifact.path,
|
|
9252
|
-
attachment_path: artifact.path,
|
|
9253
|
-
media_type: artifact.mimeType,
|
|
9254
|
-
bytes: artifact.bytes
|
|
9255
|
-
})),
|
|
9256
|
-
delivery: artifactRefs.length > 0 ? options.canSendFilesToActiveConversation ? "Fetched image was written to a sandbox path. Use sendMessage to share or attach the image in the active conversation." : "Fetched image was written to a sandbox path, but this runtime has no file-send tool for the active conversation." : "Fetched image bytes are available only in this tool result; this runtime has no file-send tool for the active conversation."
|
|
9206
|
+
images: artifactRefs,
|
|
9207
|
+
delivery: artifactRefs.length > 0 ? options.canSendFilesToActiveConversation ? "Fetched images were written to sandbox paths. To share them, pass the returned image objects unchanged as sendFiles files." : "Fetched image was written to a sandbox path, but this runtime has no file-send tool for the active conversation." : "Fetched image bytes are available only in this tool result; this runtime has no file-send tool for the active conversation."
|
|
9257
9208
|
};
|
|
9258
9209
|
}
|
|
9259
9210
|
return await extractWebFetchResponse(safeUrl, response, max_chars);
|
|
@@ -9275,7 +9226,7 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
9275
9226
|
}
|
|
9276
9227
|
|
|
9277
9228
|
// src/chat/tools/web/search.ts
|
|
9278
|
-
import { z as
|
|
9229
|
+
import { z as z38 } from "zod";
|
|
9279
9230
|
import { generateText } from "ai";
|
|
9280
9231
|
import { createGatewayProvider } from "@ai-sdk/gateway";
|
|
9281
9232
|
import { getModel } from "@earendil-works/pi-ai/compat";
|
|
@@ -9326,9 +9277,9 @@ function createWebSearchTool(override) {
|
|
|
9326
9277
|
destructiveHint: false,
|
|
9327
9278
|
openWorldHint: true
|
|
9328
9279
|
},
|
|
9329
|
-
inputSchema:
|
|
9330
|
-
query:
|
|
9331
|
-
max_results:
|
|
9280
|
+
inputSchema: z38.object({
|
|
9281
|
+
query: z38.string().min(1).max(500).describe("Search query."),
|
|
9282
|
+
max_results: z38.coerce.number().int().min(1).max(MAX_RESULTS2).describe("Max results to return.").optional()
|
|
9332
9283
|
}),
|
|
9333
9284
|
outputSchema: juniorToolResultSchema,
|
|
9334
9285
|
execute: async ({ query, max_results }) => {
|
|
@@ -9398,14 +9349,14 @@ function createWebSearchTool(override) {
|
|
|
9398
9349
|
}
|
|
9399
9350
|
|
|
9400
9351
|
// src/chat/tools/sandbox/write-file.ts
|
|
9401
|
-
import { z as
|
|
9352
|
+
import { z as z39 } from "zod";
|
|
9402
9353
|
function createWriteFileTool() {
|
|
9403
9354
|
return zodTool({
|
|
9404
9355
|
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.",
|
|
9405
9356
|
executionMode: "sequential",
|
|
9406
|
-
inputSchema:
|
|
9407
|
-
path:
|
|
9408
|
-
content:
|
|
9357
|
+
inputSchema: z39.object({
|
|
9358
|
+
path: z39.string().min(1).describe("Path to write in the sandbox workspace."),
|
|
9359
|
+
content: z39.string().describe("UTF-8 file content to write.")
|
|
9409
9360
|
}),
|
|
9410
9361
|
outputSchema: juniorToolResultSchema,
|
|
9411
9362
|
execute: async () => {
|
|
@@ -9450,7 +9401,7 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
9450
9401
|
const slackContext = getSlackToolContext(context);
|
|
9451
9402
|
const slackSourceCapabilities = slackContext ? resolveChannelCapabilities(slackContext.sourceChannelId) : void 0;
|
|
9452
9403
|
const canSendFilesToActiveConversation = Boolean(
|
|
9453
|
-
slackContext && slackSourceCapabilities?.
|
|
9404
|
+
slackContext && slackSourceCapabilities?.canSendFiles
|
|
9454
9405
|
);
|
|
9455
9406
|
const tools = {
|
|
9456
9407
|
loadSkill: createLoadSkillTool(availableSkills, {
|
|
@@ -9529,8 +9480,8 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
9529
9480
|
state
|
|
9530
9481
|
);
|
|
9531
9482
|
}
|
|
9532
|
-
if (rawChannelCapabilities.
|
|
9533
|
-
tools.
|
|
9483
|
+
if (rawChannelCapabilities.canSendFiles) {
|
|
9484
|
+
tools.sendFiles = createSendFilesTool(
|
|
9534
9485
|
slackContext,
|
|
9535
9486
|
state,
|
|
9536
9487
|
(input) => readSandboxFileUpload(context.sandbox, input)
|
|
@@ -9935,10 +9886,6 @@ function parseOAuthStatePayload(value) {
|
|
|
9935
9886
|
if (value.source !== void 0 && (!source || !source.success)) {
|
|
9936
9887
|
return void 0;
|
|
9937
9888
|
}
|
|
9938
|
-
const pendingMessage = optionalString(value.pendingMessage);
|
|
9939
|
-
if (pendingMessage && !source?.success) {
|
|
9940
|
-
return void 0;
|
|
9941
|
-
}
|
|
9942
9889
|
return {
|
|
9943
9890
|
userId: value.userId,
|
|
9944
9891
|
provider: value.provider,
|
|
@@ -9946,8 +9893,6 @@ function parseOAuthStatePayload(value) {
|
|
|
9946
9893
|
...destination ? { destination } : {},
|
|
9947
9894
|
...source?.success ? { source: source.data } : {},
|
|
9948
9895
|
...optionalString(value.threadTs) ? { threadTs: optionalString(value.threadTs) } : {},
|
|
9949
|
-
...pendingMessage ? { pendingMessage } : {},
|
|
9950
|
-
...isRecord(value.configuration) ? { configuration: value.configuration } : {},
|
|
9951
9896
|
...optionalString(value.resumeConversationId) ? { resumeConversationId: optionalString(value.resumeConversationId) } : {},
|
|
9952
9897
|
...optionalString(value.resumeSessionId) ? { resumeSessionId: optionalString(value.resumeSessionId) } : {},
|
|
9953
9898
|
...optionalString(value.scope) ? { scope: optionalString(value.scope) } : {}
|
|
@@ -10065,7 +10010,6 @@ async function startOAuthFlow(provider, input) {
|
|
|
10065
10010
|
error: "Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)"
|
|
10066
10011
|
};
|
|
10067
10012
|
}
|
|
10068
|
-
const configuration = input.userMessage && input.channelConfiguration ? await input.channelConfiguration.resolveValues() : void 0;
|
|
10069
10013
|
const state = randomBytes(32).toString("hex");
|
|
10070
10014
|
const requestedScope = input.scope ?? providerConfig.scope;
|
|
10071
10015
|
await getStateAdapter().set(
|
|
@@ -10077,8 +10021,6 @@ async function startOAuthFlow(provider, input) {
|
|
|
10077
10021
|
...input.destination ? { destination: input.destination } : {},
|
|
10078
10022
|
...input.source ? { source: input.source } : {},
|
|
10079
10023
|
...input.threadTs ? { threadTs: input.threadTs } : {},
|
|
10080
|
-
...input.userMessage ? { pendingMessage: input.userMessage } : {},
|
|
10081
|
-
...configuration && Object.keys(configuration).length > 0 ? { configuration } : {},
|
|
10082
10024
|
...input.resumeConversationId ? { resumeConversationId: input.resumeConversationId } : {},
|
|
10083
10025
|
...input.resumeSessionId ? { resumeSessionId: input.resumeSessionId } : {},
|
|
10084
10026
|
...requestedScope ? { scope: requestedScope } : {}
|
|
@@ -10125,59 +10067,59 @@ async function startOAuthFlow(provider, input) {
|
|
|
10125
10067
|
}
|
|
10126
10068
|
|
|
10127
10069
|
// src/chat/sandbox/egress/schemas.ts
|
|
10128
|
-
import { z as
|
|
10070
|
+
import { z as z40 } from "zod";
|
|
10129
10071
|
import {
|
|
10130
10072
|
pluginAuthorizationSchema,
|
|
10131
10073
|
pluginCredentialHeaderTransformSchema,
|
|
10132
10074
|
pluginGrantSchema,
|
|
10133
10075
|
pluginProviderAccountSchema
|
|
10134
10076
|
} from "@sentry/junior-plugin-api";
|
|
10135
|
-
var finiteNumberSchema =
|
|
10136
|
-
var httpStatusSchema =
|
|
10137
|
-
var providerNameSchema =
|
|
10138
|
-
var credentialSignalKindSchema =
|
|
10077
|
+
var finiteNumberSchema = z40.number().refine(Number.isFinite);
|
|
10078
|
+
var httpStatusSchema = z40.number().int().min(100).max(599);
|
|
10079
|
+
var providerNameSchema = z40.string().regex(/^[a-z][a-z0-9-]*$/);
|
|
10080
|
+
var credentialSignalKindSchema = z40.enum(["auth_required", "unavailable"]);
|
|
10139
10081
|
var sandboxEgressGrantSchema = pluginGrantSchema;
|
|
10140
|
-
var sandboxEgressCredentialContextSchema =
|
|
10082
|
+
var sandboxEgressCredentialContextSchema = z40.object({
|
|
10141
10083
|
credentials: credentialContextSchema,
|
|
10142
|
-
egressId:
|
|
10084
|
+
egressId: z40.string().min(1),
|
|
10143
10085
|
expiresAtMs: finiteNumberSchema,
|
|
10144
|
-
contextId:
|
|
10086
|
+
contextId: z40.string().min(1)
|
|
10145
10087
|
}).strict();
|
|
10146
|
-
var sandboxEgressCredentialLeaseSchema =
|
|
10088
|
+
var sandboxEgressCredentialLeaseSchema = z40.object({
|
|
10147
10089
|
account: pluginProviderAccountSchema.optional(),
|
|
10148
10090
|
authorization: pluginAuthorizationSchema.optional(),
|
|
10149
10091
|
grant: sandboxEgressGrantSchema,
|
|
10150
10092
|
provider: providerNameSchema,
|
|
10151
|
-
expiresAt:
|
|
10152
|
-
headerTransforms:
|
|
10093
|
+
expiresAt: z40.string().min(1),
|
|
10094
|
+
headerTransforms: z40.array(pluginCredentialHeaderTransformSchema).min(1)
|
|
10153
10095
|
}).strict();
|
|
10154
|
-
var sandboxEgressAuthRequiredSignalSchema =
|
|
10096
|
+
var sandboxEgressAuthRequiredSignalSchema = z40.object({
|
|
10155
10097
|
authorization: pluginAuthorizationSchema.optional(),
|
|
10156
10098
|
grant: sandboxEgressGrantSchema,
|
|
10157
10099
|
kind: credentialSignalKindSchema.default("auth_required"),
|
|
10158
10100
|
provider: providerNameSchema,
|
|
10159
|
-
message:
|
|
10101
|
+
message: z40.string().optional(),
|
|
10160
10102
|
createdAtMs: finiteNumberSchema
|
|
10161
10103
|
}).strict().superRefine((signal, ctx) => {
|
|
10162
10104
|
if (signal.authorization && signal.authorization.provider !== signal.provider) {
|
|
10163
10105
|
ctx.addIssue({
|
|
10164
|
-
code:
|
|
10106
|
+
code: z40.ZodIssueCode.custom,
|
|
10165
10107
|
message: "Auth signal authorization provider must match provider",
|
|
10166
10108
|
path: ["authorization", "provider"]
|
|
10167
10109
|
});
|
|
10168
10110
|
}
|
|
10169
10111
|
});
|
|
10170
|
-
var sandboxEgressPermissionDeniedSignalSchema =
|
|
10112
|
+
var sandboxEgressPermissionDeniedSignalSchema = z40.object({
|
|
10171
10113
|
account: pluginProviderAccountSchema.optional(),
|
|
10172
|
-
acceptedPermissions:
|
|
10114
|
+
acceptedPermissions: z40.string().optional(),
|
|
10173
10115
|
grant: sandboxEgressGrantSchema,
|
|
10174
|
-
message:
|
|
10116
|
+
message: z40.string().min(1),
|
|
10175
10117
|
provider: providerNameSchema,
|
|
10176
|
-
source:
|
|
10177
|
-
sso:
|
|
10118
|
+
source: z40.literal("upstream"),
|
|
10119
|
+
sso: z40.string().optional(),
|
|
10178
10120
|
status: httpStatusSchema,
|
|
10179
|
-
upstreamHost:
|
|
10180
|
-
upstreamPath:
|
|
10121
|
+
upstreamHost: z40.string().min(1),
|
|
10122
|
+
upstreamPath: z40.string().min(1),
|
|
10181
10123
|
createdAtMs: finiteNumberSchema
|
|
10182
10124
|
}).strict();
|
|
10183
10125
|
function parseSandboxEgressAuthRequiredSignal(value) {
|
|
@@ -10257,8 +10199,6 @@ function createPluginAuthOrchestration(input) {
|
|
|
10257
10199
|
destination: input.destination,
|
|
10258
10200
|
source: input.source,
|
|
10259
10201
|
threadTs: input.threadTs,
|
|
10260
|
-
userMessage: input.userMessage,
|
|
10261
|
-
channelConfiguration: input.channelConfiguration,
|
|
10262
10202
|
...options?.scope ? { scope: options.scope } : {},
|
|
10263
10203
|
resumeConversationId: input.conversationId,
|
|
10264
10204
|
resumeSessionId: input.sessionId
|
|
@@ -10438,15 +10378,15 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
10438
10378
|
}
|
|
10439
10379
|
|
|
10440
10380
|
// src/chat/tools/execute-tool.ts
|
|
10441
|
-
import { z as
|
|
10381
|
+
import { z as z41 } from "zod";
|
|
10442
10382
|
var EXECUTE_TOOL_NAME = "executeTool";
|
|
10443
10383
|
function createExecuteToolTool() {
|
|
10444
10384
|
return zodTool({
|
|
10445
10385
|
description: "Execute any catalog tool by exact tool_name from searchTools. Put tool-specific parameters inside arguments.",
|
|
10446
10386
|
executionMode: "sequential",
|
|
10447
|
-
inputSchema:
|
|
10448
|
-
tool_name:
|
|
10449
|
-
arguments:
|
|
10387
|
+
inputSchema: z41.object({
|
|
10388
|
+
tool_name: z41.string().min(1).describe("Exact catalog tool_name returned by searchTools."),
|
|
10389
|
+
arguments: z41.record(z41.string(), z41.unknown()).describe(
|
|
10450
10390
|
'Arguments matching the selected catalog tool schema, for example { "query": "..." }.'
|
|
10451
10391
|
).optional()
|
|
10452
10392
|
}).strict(),
|
|
@@ -10486,42 +10426,42 @@ function planToolExposure(tools) {
|
|
|
10486
10426
|
}
|
|
10487
10427
|
|
|
10488
10428
|
// src/chat/tools/search-tools.ts
|
|
10489
|
-
import { z as
|
|
10429
|
+
import { z as z42 } from "zod";
|
|
10490
10430
|
var SEARCH_TOOLS_NAME = "searchTools";
|
|
10491
10431
|
var DEFAULT_MAX_RESULTS2 = 5;
|
|
10492
10432
|
var MAX_RESULTS3 = 20;
|
|
10493
10433
|
var MODEL_VISIBLE_DESCRIPTION_CAP = 180;
|
|
10494
|
-
var searchToolsSourceSchema =
|
|
10495
|
-
id:
|
|
10496
|
-
description:
|
|
10434
|
+
var searchToolsSourceSchema = z42.object({
|
|
10435
|
+
id: z42.string(),
|
|
10436
|
+
description: z42.string()
|
|
10497
10437
|
}).strict();
|
|
10498
|
-
var toolCallExampleSchema =
|
|
10499
|
-
tool_name:
|
|
10500
|
-
arguments:
|
|
10438
|
+
var toolCallExampleSchema = z42.object({
|
|
10439
|
+
tool_name: z42.string(),
|
|
10440
|
+
arguments: z42.record(z42.string(), z42.string())
|
|
10501
10441
|
}).strict();
|
|
10502
|
-
var searchToolsToolSchema =
|
|
10503
|
-
tool_name:
|
|
10504
|
-
description:
|
|
10505
|
-
exposure:
|
|
10506
|
-
source:
|
|
10507
|
-
signature:
|
|
10442
|
+
var searchToolsToolSchema = z42.object({
|
|
10443
|
+
tool_name: z42.string(),
|
|
10444
|
+
description: z42.string(),
|
|
10445
|
+
exposure: z42.enum(["direct", "deferred", "modelOnly", "hidden"]),
|
|
10446
|
+
source: z42.string().optional(),
|
|
10447
|
+
signature: z42.string(),
|
|
10508
10448
|
call: toolCallExampleSchema,
|
|
10509
|
-
input_schema:
|
|
10510
|
-
input_schema_summary:
|
|
10511
|
-
call_notes:
|
|
10512
|
-
annotations:
|
|
10449
|
+
input_schema: z42.unknown(),
|
|
10450
|
+
input_schema_summary: z42.string(),
|
|
10451
|
+
call_notes: z42.array(z42.string()),
|
|
10452
|
+
annotations: z42.record(z42.string(), z42.unknown())
|
|
10513
10453
|
}).strict();
|
|
10514
10454
|
var searchToolsOutputSchema = juniorToolResultSchema.extend({
|
|
10515
|
-
query:
|
|
10516
|
-
source:
|
|
10517
|
-
sources:
|
|
10518
|
-
total_catalog_tools:
|
|
10519
|
-
total_eligible_tools:
|
|
10520
|
-
total_matches:
|
|
10521
|
-
returned_tools:
|
|
10522
|
-
execution_tool:
|
|
10455
|
+
query: z42.string().nullable(),
|
|
10456
|
+
source: z42.string().nullable(),
|
|
10457
|
+
sources: z42.array(searchToolsSourceSchema),
|
|
10458
|
+
total_catalog_tools: z42.number().int().nonnegative(),
|
|
10459
|
+
total_eligible_tools: z42.number().int().nonnegative(),
|
|
10460
|
+
total_matches: z42.number().int().nonnegative(),
|
|
10461
|
+
returned_tools: z42.number().int().nonnegative(),
|
|
10462
|
+
execution_tool: z42.literal("executeTool"),
|
|
10523
10463
|
execution_example: toolCallExampleSchema,
|
|
10524
|
-
tools:
|
|
10464
|
+
tools: z42.array(searchToolsToolSchema)
|
|
10525
10465
|
}).strict();
|
|
10526
10466
|
function normalize2(value) {
|
|
10527
10467
|
return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
|
|
@@ -10713,14 +10653,14 @@ function createSearchToolsTool(catalogTools) {
|
|
|
10713
10653
|
return zodTool({
|
|
10714
10654
|
description: renderSearchToolsDescription(knownSources),
|
|
10715
10655
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
10716
|
-
inputSchema:
|
|
10717
|
-
query:
|
|
10656
|
+
inputSchema: z42.object({
|
|
10657
|
+
query: z42.string().nullable().describe(
|
|
10718
10658
|
"Optional search terms describing the tool, owner, action, or arguments needed. Empty string lists catalog tools."
|
|
10719
10659
|
).optional(),
|
|
10720
|
-
source:
|
|
10660
|
+
source: z42.string().nullable().describe(
|
|
10721
10661
|
"Optional source id to search within, such as a plugin source returned in sources."
|
|
10722
10662
|
).optional(),
|
|
10723
|
-
max_results:
|
|
10663
|
+
max_results: z42.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
|
|
10724
10664
|
}).strict(),
|
|
10725
10665
|
outputSchema: searchToolsOutputSchema,
|
|
10726
10666
|
privateTraceResult: (result) => ({
|
|
@@ -10823,14 +10763,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10823
10763
|
return normalized.details;
|
|
10824
10764
|
};
|
|
10825
10765
|
const executeDefinition = async (args) => {
|
|
10826
|
-
const {
|
|
10827
|
-
normalizedToolCallId,
|
|
10828
|
-
params,
|
|
10829
|
-
signal,
|
|
10830
|
-
setSpanAttributes: setSpanAttributes2,
|
|
10831
|
-
toolDef,
|
|
10832
|
-
toolName
|
|
10833
|
-
} = args;
|
|
10766
|
+
const { toolCallId, params, signal, setSpanAttributes: setSpanAttributes2, toolDef, toolName } = args;
|
|
10834
10767
|
if (typeof toolDef.execute !== "function") {
|
|
10835
10768
|
throw new Error(`Tool ${toolName} does not define an executor.`);
|
|
10836
10769
|
}
|
|
@@ -10839,7 +10772,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10839
10772
|
input: params
|
|
10840
10773
|
}) : { input: params, env: {} };
|
|
10841
10774
|
const toolInput = beforeTool.input;
|
|
10842
|
-
await onToolCall?.(toolName, toolInput);
|
|
10775
|
+
await onToolCall?.(toolCallId, toolName, toolInput);
|
|
10843
10776
|
const sandboxInput = buildSandboxInput(toolName, toolInput);
|
|
10844
10777
|
const isSandbox = Boolean(sandboxExecutor?.canExecute(toolName));
|
|
10845
10778
|
const result = isSandbox ? await sandboxExecutor.execute({
|
|
@@ -10850,7 +10783,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10850
10783
|
experimental_context: sandbox,
|
|
10851
10784
|
...signal ? { signal } : {},
|
|
10852
10785
|
conversationPrivacy: effectiveConversationPrivacy,
|
|
10853
|
-
|
|
10786
|
+
toolCallId
|
|
10854
10787
|
});
|
|
10855
10788
|
const normalized = normalizeToolResult(result, isSandbox, {
|
|
10856
10789
|
requireStructuredResult: Boolean(toolDef.outputSchema),
|
|
@@ -10903,6 +10836,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10903
10836
|
ok: toolResultOk(normalized.details),
|
|
10904
10837
|
params: toolInput,
|
|
10905
10838
|
result: resultAttributeValue,
|
|
10839
|
+
toolCallId,
|
|
10906
10840
|
toolName
|
|
10907
10841
|
});
|
|
10908
10842
|
return normalized;
|
|
@@ -10924,7 +10858,9 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10924
10858
|
prepareArguments: toolDef.prepareArguments,
|
|
10925
10859
|
executionMode: toolDef.executionMode,
|
|
10926
10860
|
execute: async (toolCallId, params, signal) => {
|
|
10927
|
-
|
|
10861
|
+
if (typeof toolCallId !== "string" || toolCallId.length === 0) {
|
|
10862
|
+
throw new Error("Pi tool execution requires a non-empty tool call id.");
|
|
10863
|
+
}
|
|
10928
10864
|
const toolArgumentsAttribute = serializeToolPayload(params, {
|
|
10929
10865
|
privateMetadata: true
|
|
10930
10866
|
});
|
|
@@ -10957,7 +10893,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10957
10893
|
executionParams = catalogCall.arguments;
|
|
10958
10894
|
await reportStatus(executionToolName, executionParams);
|
|
10959
10895
|
return await executeDefinition({
|
|
10960
|
-
|
|
10896
|
+
toolCallId,
|
|
10961
10897
|
params: catalogCall.arguments,
|
|
10962
10898
|
signal,
|
|
10963
10899
|
setSpanAttributes: setSpanAttributes2,
|
|
@@ -10967,7 +10903,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10967
10903
|
}
|
|
10968
10904
|
await reportStatus(executionToolName, executionParams);
|
|
10969
10905
|
return await executeDefinition({
|
|
10970
|
-
|
|
10906
|
+
toolCallId,
|
|
10971
10907
|
params: parsed,
|
|
10972
10908
|
signal,
|
|
10973
10909
|
setSpanAttributes: setSpanAttributes2,
|
|
@@ -10979,6 +10915,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10979
10915
|
error: error instanceof Error ? error.message : String(error),
|
|
10980
10916
|
ok: false,
|
|
10981
10917
|
params: executionParams,
|
|
10918
|
+
toolCallId,
|
|
10982
10919
|
toolName: executionToolName
|
|
10983
10920
|
});
|
|
10984
10921
|
if (error instanceof AuthorizationPauseError || error instanceof AuthorizationFlowDisabledError) {
|
|
@@ -10987,7 +10924,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10987
10924
|
handleToolExecutionError(
|
|
10988
10925
|
error,
|
|
10989
10926
|
executionToolName,
|
|
10990
|
-
|
|
10927
|
+
toolCallId,
|
|
10991
10928
|
shouldTrace,
|
|
10992
10929
|
spanContext,
|
|
10993
10930
|
effectiveConversationPrivacy,
|
|
@@ -11001,7 +10938,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
11001
10938
|
"gen_ai.tool.description": toolDef.description,
|
|
11002
10939
|
"gen_ai.tool.type": "function",
|
|
11003
10940
|
...toolArgumentsMetadata,
|
|
11004
|
-
|
|
10941
|
+
"gen_ai.tool.call.id": toolCallId,
|
|
11005
10942
|
...toolArgumentsAttribute ? { "gen_ai.tool.call.arguments": toolArgumentsAttribute } : {}
|
|
11006
10943
|
}
|
|
11007
10944
|
);
|
|
@@ -11430,6 +11367,19 @@ function findInErrorChain(error, predicate) {
|
|
|
11430
11367
|
}
|
|
11431
11368
|
return false;
|
|
11432
11369
|
}
|
|
11370
|
+
function isRecord5(value) {
|
|
11371
|
+
return typeof value === "object" && value !== null;
|
|
11372
|
+
}
|
|
11373
|
+
function isInvalidSandboxSessionError(error) {
|
|
11374
|
+
if (!isRecord5(error)) {
|
|
11375
|
+
return false;
|
|
11376
|
+
}
|
|
11377
|
+
if (isRecord5(error.json) && error.json.invalidToken === true) {
|
|
11378
|
+
return true;
|
|
11379
|
+
}
|
|
11380
|
+
const response = error.response;
|
|
11381
|
+
return isRecord5(response) && response.status === 403 && typeof response.url === "string" && response.url.includes("/sandboxes/sessions");
|
|
11382
|
+
}
|
|
11433
11383
|
function getFirstErrorMessage(error) {
|
|
11434
11384
|
const seen = /* @__PURE__ */ new Set();
|
|
11435
11385
|
let current = error;
|
|
@@ -11451,9 +11401,12 @@ function isAlreadyExistsError(error) {
|
|
|
11451
11401
|
}
|
|
11452
11402
|
function isSandboxUnavailableError(error) {
|
|
11453
11403
|
return findInErrorChain(error, (candidate) => {
|
|
11404
|
+
if (isInvalidSandboxSessionError(candidate)) {
|
|
11405
|
+
return true;
|
|
11406
|
+
}
|
|
11454
11407
|
const details = getSandboxErrorDetails(candidate);
|
|
11455
11408
|
const searchable = `${details.searchableText} ${details.summary}`.toLowerCase();
|
|
11456
|
-
return searchable.includes("sandbox_stopped") || searchable.includes("status=410") || searchable.includes("status code 410") || searchable.includes("no longer available");
|
|
11409
|
+
return searchable.includes("sandbox_stopped") || searchable.includes("status=410") || searchable.includes("status code 410") || searchable.includes("no longer available") || searchable.includes("stream was closed and is not accepting commands");
|
|
11457
11410
|
});
|
|
11458
11411
|
}
|
|
11459
11412
|
function isSnapshottingError(error) {
|
|
@@ -14683,13 +14636,13 @@ async function wireAgentTools(args) {
|
|
|
14683
14636
|
const slackChannelId = slackDestination?.channelId;
|
|
14684
14637
|
const mcpAuth = createMcpAuthOrchestration({
|
|
14685
14638
|
abortAgent: args.abortAgent,
|
|
14686
|
-
conversationId: args.
|
|
14687
|
-
sessionId: args.
|
|
14639
|
+
conversationId: args.conversationId,
|
|
14640
|
+
sessionId: args.turnId,
|
|
14688
14641
|
actorId: authActorId,
|
|
14689
14642
|
channelId: slackChannelId,
|
|
14690
14643
|
destination: args.routing.destination,
|
|
14691
14644
|
source: runSource,
|
|
14692
|
-
threadTs: args.routing.
|
|
14645
|
+
threadTs: args.routing.source.platform === "slack" ? args.routing.source.threadTs : void 0,
|
|
14693
14646
|
toolChannelId: args.routing.toolChannelId,
|
|
14694
14647
|
userMessage: args.userInput,
|
|
14695
14648
|
pendingAuth: args.state.pendingAuth,
|
|
@@ -14704,15 +14657,13 @@ async function wireAgentTools(args) {
|
|
|
14704
14657
|
});
|
|
14705
14658
|
const pluginAuth = createPluginAuthOrchestration({
|
|
14706
14659
|
abortAgent: args.abortAgent,
|
|
14707
|
-
conversationId: args.
|
|
14708
|
-
sessionId: args.
|
|
14660
|
+
conversationId: args.conversationId,
|
|
14661
|
+
sessionId: args.turnId,
|
|
14709
14662
|
actorId: authActorId,
|
|
14710
14663
|
channelId: slackChannelId,
|
|
14711
14664
|
destination: args.routing.destination,
|
|
14712
14665
|
source: runSource,
|
|
14713
|
-
threadTs: args.routing.
|
|
14714
|
-
userMessage: args.userInput,
|
|
14715
|
-
channelConfiguration: args.policy.channelConfiguration,
|
|
14666
|
+
threadTs: args.routing.source.platform === "slack" ? args.routing.source.threadTs : void 0,
|
|
14716
14667
|
pendingAuth: args.state.pendingAuth,
|
|
14717
14668
|
recordPendingAuth: args.durability.recordPendingAuth,
|
|
14718
14669
|
authorizationFlowMode: args.policy.authorizationFlowMode,
|
|
@@ -14730,7 +14681,7 @@ async function wireAgentTools(args) {
|
|
|
14730
14681
|
(skill) => skill.disableModelInvocation !== true || skill.name === args.invokedSkill?.name
|
|
14731
14682
|
);
|
|
14732
14683
|
const commonToolRuntimeContext = {
|
|
14733
|
-
conversationId: args.
|
|
14684
|
+
conversationId: args.conversationId,
|
|
14734
14685
|
userText: args.userInput,
|
|
14735
14686
|
artifactState: args.state.artifactState,
|
|
14736
14687
|
configuration: args.configurationValues,
|
|
@@ -14873,10 +14824,14 @@ async function wireAgentTools(args) {
|
|
|
14873
14824
|
const activeMcpCatalogs = toActiveMcpCatalogSummaries(
|
|
14874
14825
|
mcpToolManager.getActiveToolCatalog()
|
|
14875
14826
|
);
|
|
14876
|
-
const onToolCall = async (toolName, params) => {
|
|
14827
|
+
const onToolCall = async (toolCallId, toolName, params) => {
|
|
14877
14828
|
args.toolCalls.push(toolName);
|
|
14878
14829
|
try {
|
|
14879
|
-
await args.observers.onToolInvocation?.({
|
|
14830
|
+
await args.observers.onToolInvocation?.({
|
|
14831
|
+
params,
|
|
14832
|
+
toolCallId,
|
|
14833
|
+
toolName
|
|
14834
|
+
});
|
|
14880
14835
|
} catch (error) {
|
|
14881
14836
|
logWarn(
|
|
14882
14837
|
"tool_invocation_observer_failed",
|
|
@@ -14929,20 +14884,19 @@ function createResumeState(args) {
|
|
|
14929
14884
|
let resumeMessages = [];
|
|
14930
14885
|
let turnStartMessageIndex;
|
|
14931
14886
|
const currentSliceId = args.sessionRecordState.currentSliceId;
|
|
14932
|
-
const canPersistSession = args.sessionRecordState.canUseTurnSession && Boolean(args.sessionConversationId && args.sessionId);
|
|
14933
14887
|
const currentDurationMs = () => Date.now() - args.startedAtMs;
|
|
14934
14888
|
const sessionRecordBase = () => ({
|
|
14935
14889
|
channelName: args.channelName,
|
|
14936
|
-
conversationId: args.
|
|
14890
|
+
conversationId: args.conversationId,
|
|
14937
14891
|
destination: args.destination,
|
|
14938
14892
|
source: args.runSource,
|
|
14939
|
-
sessionId: args.
|
|
14893
|
+
sessionId: args.turnId,
|
|
14940
14894
|
loadedSkillNames: args.getLoadedSkillNames(),
|
|
14941
14895
|
logContext: args.logContext,
|
|
14942
14896
|
modelId: args.getModelId(),
|
|
14943
14897
|
...args.getReasoningLevel() ? { reasoningLevel: args.getReasoningLevel() } : {},
|
|
14944
14898
|
actor: args.actor,
|
|
14945
|
-
|
|
14899
|
+
surface: args.surface
|
|
14946
14900
|
});
|
|
14947
14901
|
return {
|
|
14948
14902
|
get inputCommitted() {
|
|
@@ -14985,9 +14939,6 @@ function createResumeState(args) {
|
|
|
14985
14939
|
inputCommitted = true;
|
|
14986
14940
|
},
|
|
14987
14941
|
async persistSafeBoundary(messages, trailingMessageProvenance) {
|
|
14988
|
-
if (!canPersistSession) {
|
|
14989
|
-
return false;
|
|
14990
|
-
}
|
|
14991
14942
|
const persisted = await persistRunningSessionRecord({
|
|
14992
14943
|
...sessionRecordBase(),
|
|
14993
14944
|
sliceId: currentSliceId,
|
|
@@ -15008,7 +14959,7 @@ function createResumeState(args) {
|
|
|
15008
14959
|
);
|
|
15009
14960
|
if (!persisted && args.durability.onInputCommitted) {
|
|
15010
14961
|
throw new TurnInputCommitLostError(
|
|
15011
|
-
`Durable turn input could not be checkpointed for conversation=${args.
|
|
14962
|
+
`Durable turn input could not be checkpointed for conversation=${args.conversationId} turn=${args.turnId}`
|
|
15012
14963
|
);
|
|
15013
14964
|
}
|
|
15014
14965
|
return persisted;
|
|
@@ -15030,9 +14981,6 @@ function createResumeState(args) {
|
|
|
15030
14981
|
*/
|
|
15031
14982
|
async translateExpectedEnding(args2) {
|
|
15032
14983
|
const { error } = args2;
|
|
15033
|
-
if (!args.sessionConversationId || !args.sessionId) {
|
|
15034
|
-
return {};
|
|
15035
|
-
}
|
|
15036
14984
|
if (cooperativeYieldError && error instanceof CooperativeTurnYieldError) {
|
|
15037
14985
|
const usage = args2.currentUsage ?? extractSliceUsage(resumeMessages, beforeMessageCount);
|
|
15038
14986
|
await args.recordActiveMcpProviders();
|
|
@@ -15046,7 +14994,7 @@ function createResumeState(args) {
|
|
|
15046
14994
|
});
|
|
15047
14995
|
if (!sessionRecord) {
|
|
15048
14996
|
throw new Error(
|
|
15049
|
-
`Failed to persist cooperative yield continuation for conversation=${args.
|
|
14997
|
+
`Failed to persist cooperative yield continuation for conversation=${args.conversationId} turn=${args.turnId}`
|
|
15050
14998
|
);
|
|
15051
14999
|
}
|
|
15052
15000
|
return {
|
|
@@ -15057,20 +15005,25 @@ function createResumeState(args) {
|
|
|
15057
15005
|
}
|
|
15058
15006
|
};
|
|
15059
15007
|
}
|
|
15060
|
-
|
|
15008
|
+
const resumeReason = error instanceof RetryableDeliveryError ? "retry" : timedOut ? "timeout" : void 0;
|
|
15009
|
+
if (resumeReason) {
|
|
15010
|
+
if (resumeReason === "retry") {
|
|
15011
|
+
resumeMessages = [...latestSafeBoundaryMessages];
|
|
15012
|
+
}
|
|
15061
15013
|
const usage = args2.currentUsage ?? extractSliceUsage(resumeMessages, beforeMessageCount);
|
|
15062
15014
|
await args.recordActiveMcpProviders();
|
|
15063
|
-
const sessionRecord = await
|
|
15015
|
+
const sessionRecord = await persistContinuationSessionRecord({
|
|
15064
15016
|
...sessionRecordBase(),
|
|
15065
15017
|
currentSliceId,
|
|
15066
15018
|
currentDurationMs: currentDurationMs(),
|
|
15067
15019
|
currentUsage: usage,
|
|
15068
15020
|
messages: resumeMessages,
|
|
15069
|
-
errorMessage: error instanceof Error ? error.message : String(error)
|
|
15021
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
15022
|
+
resumeReason
|
|
15070
15023
|
});
|
|
15071
15024
|
if (!sessionRecord) {
|
|
15072
15025
|
throw new Error(
|
|
15073
|
-
`Failed to persist
|
|
15026
|
+
`Failed to persist continuation for conversation=${args.conversationId} turn=${args.turnId}`
|
|
15074
15027
|
);
|
|
15075
15028
|
}
|
|
15076
15029
|
if (sessionRecord.state === "awaiting_resume") {
|
|
@@ -15082,9 +15035,7 @@ function createResumeState(args) {
|
|
|
15082
15035
|
}
|
|
15083
15036
|
};
|
|
15084
15037
|
}
|
|
15085
|
-
throw new
|
|
15086
|
-
sessionRecord.errorMessage ?? (error instanceof Error ? error.message : String(error))
|
|
15087
|
-
);
|
|
15038
|
+
throw new TurnSliceLimitExceededError(botConfig.maxSlicesPerTurn);
|
|
15088
15039
|
}
|
|
15089
15040
|
if (error instanceof AuthorizationPauseError) {
|
|
15090
15041
|
const usage = args2.currentUsage ?? (resumeMessages.length > 0 ? extractSliceUsage(resumeMessages, beforeMessageCount) : void 0);
|
|
@@ -15169,10 +15120,6 @@ function userMessage(text) {
|
|
|
15169
15120
|
timestamp: Date.now()
|
|
15170
15121
|
};
|
|
15171
15122
|
}
|
|
15172
|
-
function piMessageTimestamp(message) {
|
|
15173
|
-
const timestamp = message.timestamp;
|
|
15174
|
-
return typeof timestamp === "number" ? timestamp : Date.now();
|
|
15175
|
-
}
|
|
15176
15123
|
function selectRetainedUserMessageEntries(messages, maxTokens = RETAINED_USER_MESSAGE_TOKENS) {
|
|
15177
15124
|
const selected = [];
|
|
15178
15125
|
let remaining = maxTokens;
|
|
@@ -15356,7 +15303,7 @@ async function maybeCompactWithDeps(args, deps) {
|
|
|
15356
15303
|
});
|
|
15357
15304
|
}
|
|
15358
15305
|
async function writeCompactedThreadContext(args, sourceMessages, summary, context) {
|
|
15359
|
-
const
|
|
15306
|
+
const eventStore = getConversationEventStore();
|
|
15360
15307
|
const sourceProjection = await loadConversationProjection({
|
|
15361
15308
|
conversationId: args.conversationId
|
|
15362
15309
|
});
|
|
@@ -15372,15 +15319,21 @@ ${summary}`)
|
|
|
15372
15319
|
retained,
|
|
15373
15320
|
sourceProvenance: sourceProjection.provenance
|
|
15374
15321
|
});
|
|
15375
|
-
await
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15322
|
+
await eventStore.replaceHistory(args.conversationId, {
|
|
15323
|
+
createdAtMs: Date.now(),
|
|
15324
|
+
data: {
|
|
15325
|
+
type: "compaction",
|
|
15326
|
+
modelProfile: sourceProjection.modelProfile,
|
|
15327
|
+
modelId: modelIdForProfile(botConfig, sourceProjection.modelProfile),
|
|
15328
|
+
replacementHistory: replacement.map((message, index) => {
|
|
15329
|
+
const sourceEventSeq = index < retained.length ? sourceProjection.seqs[retained[index].sourceIndex] : void 0;
|
|
15330
|
+
return {
|
|
15331
|
+
message,
|
|
15332
|
+
provenance: replacementProvenance[index],
|
|
15333
|
+
...sourceEventSeq === void 0 ? {} : { sourceEventSeq }
|
|
15334
|
+
};
|
|
15335
|
+
})
|
|
15336
|
+
}
|
|
15384
15337
|
});
|
|
15385
15338
|
updateConversationStats(args.conversation);
|
|
15386
15339
|
setSpanAttributes({
|
|
@@ -15415,24 +15368,33 @@ ${await summarizeContext(args, deps)}`;
|
|
|
15415
15368
|
]
|
|
15416
15369
|
};
|
|
15417
15370
|
const messages = [message];
|
|
15371
|
+
const replacementMessages = stripRuntimeTurnContext(messages);
|
|
15418
15372
|
args.signal?.throwIfAborted();
|
|
15419
|
-
await
|
|
15420
|
-
|
|
15421
|
-
|
|
15422
|
-
|
|
15423
|
-
|
|
15424
|
-
|
|
15425
|
-
|
|
15426
|
-
|
|
15373
|
+
await getConversationEventStore().replaceHistory(args.conversationId, {
|
|
15374
|
+
createdAtMs: Date.now(),
|
|
15375
|
+
data: {
|
|
15376
|
+
type: "handoff",
|
|
15377
|
+
modelProfile: args.target.modelProfile,
|
|
15378
|
+
modelId: args.target.modelId,
|
|
15379
|
+
...args.triggeringToolCallId ? { triggeringToolCallId: args.triggeringToolCallId } : {},
|
|
15380
|
+
replacementHistory: replacementMessages.map((replacementMessage) => ({
|
|
15381
|
+
message: replacementMessage,
|
|
15427
15382
|
provenance: contextProvenance
|
|
15428
|
-
}
|
|
15429
|
-
|
|
15383
|
+
}))
|
|
15384
|
+
}
|
|
15430
15385
|
});
|
|
15431
15386
|
return messages;
|
|
15432
15387
|
}
|
|
15433
15388
|
|
|
15434
15389
|
// src/chat/agent/index.ts
|
|
15435
15390
|
var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
|
|
15391
|
+
var AssistantMessageDeliveryError = class extends Error {
|
|
15392
|
+
constructor(originalError) {
|
|
15393
|
+
super("Assistant message delivery failed");
|
|
15394
|
+
this.originalError = originalError;
|
|
15395
|
+
}
|
|
15396
|
+
originalError;
|
|
15397
|
+
};
|
|
15436
15398
|
function waitForAbortSettlement(promise, timeoutMs) {
|
|
15437
15399
|
return new Promise((resolve) => {
|
|
15438
15400
|
let done = false;
|
|
@@ -15462,9 +15424,13 @@ function waitForAbortSettlement(promise, timeoutMs) {
|
|
|
15462
15424
|
});
|
|
15463
15425
|
}
|
|
15464
15426
|
async function executeAgentRun(request) {
|
|
15427
|
+
if (!request.routing.destination) {
|
|
15428
|
+
throw new TypeError("Assistant reply generation requires a destination");
|
|
15429
|
+
}
|
|
15430
|
+
const channelId = request.routing.destination.platform === "slack" ? request.routing.destination.channelId : void 0;
|
|
15465
15431
|
const conversationPrivacy = resolveConversationPrivacy({
|
|
15466
|
-
channelId
|
|
15467
|
-
conversationId: request.
|
|
15432
|
+
channelId,
|
|
15433
|
+
conversationId: request.conversationId,
|
|
15468
15434
|
// Destination visibility is provider-neutral. Slack event context remains
|
|
15469
15435
|
// a compatibility fallback for callers that have not projected it yet.
|
|
15470
15436
|
visibility: request.routing.destinationVisibility ?? request.routing.slackConversation?.visibility
|
|
@@ -15475,18 +15441,15 @@ async function executeAgentRun(request) {
|
|
|
15475
15441
|
);
|
|
15476
15442
|
}
|
|
15477
15443
|
async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
15478
|
-
const { input, routing } = request;
|
|
15444
|
+
const { conversationId, input, routing, runId, turnId } = request;
|
|
15479
15445
|
const policy = request.policy ?? {};
|
|
15480
15446
|
const signal = policy.signal;
|
|
15481
15447
|
const state = request.state ?? {};
|
|
15482
15448
|
const observers = request.observers ?? {};
|
|
15449
|
+
const delivery = request.delivery;
|
|
15483
15450
|
const durability = request.durability ?? {};
|
|
15484
15451
|
signal?.throwIfAborted();
|
|
15485
|
-
|
|
15486
|
-
throw new TypeError("Assistant reply generation requires a destination");
|
|
15487
|
-
}
|
|
15488
|
-
assertActorDestinationMatch(routing);
|
|
15489
|
-
assertCorrelationDestinationMatch(routing);
|
|
15452
|
+
assertRunRoutingConsistency(request);
|
|
15490
15453
|
const replyStartedAtMs = Date.now();
|
|
15491
15454
|
const configuredTurnDeadlineAtMs = replyStartedAtMs + botConfig.turnTimeoutMs;
|
|
15492
15455
|
const policyTurnDeadlineAtMs = typeof policy.turnDeadlineAtMs === "number" && Number.isFinite(policy.turnDeadlineAtMs) ? Math.floor(policy.turnDeadlineAtMs) : void 0;
|
|
@@ -15497,11 +15460,11 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15497
15460
|
let lastKnownSandboxDependencyProfileHash = state.sandbox?.sandboxDependencyProfileHash;
|
|
15498
15461
|
let mcpToolManager;
|
|
15499
15462
|
let connectedMcpProviders = /* @__PURE__ */ new Set();
|
|
15500
|
-
let canRecordMcpProviders = false;
|
|
15501
15463
|
let turnUsage;
|
|
15502
15464
|
let handoffPhaseUsage;
|
|
15503
15465
|
const configuredReasoningLevel = policy.reasoningLevel ?? botConfig.reasoningLevel;
|
|
15504
|
-
let
|
|
15466
|
+
let turnRoute = configuredReasoningLevel ? configuredTurnRoute(
|
|
15467
|
+
STANDARD_MODEL_PROFILE,
|
|
15505
15468
|
configuredReasoningLevel,
|
|
15506
15469
|
policy.reasoningLevel ? "agent_config" : "default"
|
|
15507
15470
|
) : void 0;
|
|
@@ -15510,6 +15473,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15510
15473
|
const actor = actorFromRouting(routing);
|
|
15511
15474
|
const surface = surfaceFromRouting(routing);
|
|
15512
15475
|
const runSource = routing.source;
|
|
15476
|
+
const slackSource = runSource.platform === "slack" ? runSource : void 0;
|
|
15477
|
+
const slackDestination = routing.destination.platform === "slack" ? routing.destination : void 0;
|
|
15478
|
+
const slackActor = actor?.platform === "slack" ? actor : void 0;
|
|
15513
15479
|
const userInput = input.messageText;
|
|
15514
15480
|
const credentialActor = routing.credentialContext?.actor;
|
|
15515
15481
|
const credentialActorLogContext = credentialActor ? {
|
|
@@ -15517,20 +15483,19 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15517
15483
|
actorId: "type" in credentialActor ? credentialActor.userId : credentialActor.name
|
|
15518
15484
|
} : {};
|
|
15519
15485
|
const sessionRecordLogContext = {
|
|
15520
|
-
threadId:
|
|
15521
|
-
actorId:
|
|
15522
|
-
channelId:
|
|
15523
|
-
runId
|
|
15486
|
+
threadId: slackSource ? conversationId : void 0,
|
|
15487
|
+
actorId: slackActor?.userId,
|
|
15488
|
+
channelId: slackDestination?.channelId,
|
|
15489
|
+
runId,
|
|
15524
15490
|
...credentialActorLogContext,
|
|
15525
15491
|
assistantUserName: botConfig.userName
|
|
15526
15492
|
};
|
|
15527
|
-
const { conversationId: sessionConversationId, sessionId } = getSessionIdentifiers(routing);
|
|
15528
15493
|
const recordConnectedMcpProvider = async (provider) => {
|
|
15529
|
-
if (
|
|
15494
|
+
if (connectedMcpProviders.has(provider)) {
|
|
15530
15495
|
return;
|
|
15531
15496
|
}
|
|
15532
15497
|
await recordMcpProviderConnected({
|
|
15533
|
-
conversationId
|
|
15498
|
+
conversationId,
|
|
15534
15499
|
provider
|
|
15535
15500
|
});
|
|
15536
15501
|
connectedMcpProviders.add(provider);
|
|
@@ -15548,21 +15513,16 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15548
15513
|
sandboxDependencyProfileHash: lastKnownSandboxDependencyProfileHash
|
|
15549
15514
|
});
|
|
15550
15515
|
try {
|
|
15551
|
-
|
|
15552
|
-
|
|
15553
|
-
|
|
15554
|
-
modelId: activeModelId
|
|
15555
|
-
});
|
|
15556
|
-
activeModelProfile = projection.modelProfile;
|
|
15557
|
-
activeModelId = modelIdForProfile(botConfig, activeModelProfile);
|
|
15558
|
-
}
|
|
15516
|
+
const projection = await openConversationProjection({ conversationId });
|
|
15517
|
+
activeModelProfile = projection.modelProfile;
|
|
15518
|
+
activeModelId = modelIdForProfile(botConfig, activeModelProfile);
|
|
15559
15519
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
15560
15520
|
const spanContext = {
|
|
15561
|
-
conversationId
|
|
15562
|
-
slackThreadId:
|
|
15563
|
-
slackUserId:
|
|
15564
|
-
slackChannelId:
|
|
15565
|
-
runId
|
|
15521
|
+
conversationId,
|
|
15522
|
+
slackThreadId: slackSource ? conversationId : void 0,
|
|
15523
|
+
slackUserId: slackActor?.userId,
|
|
15524
|
+
slackChannelId: slackDestination?.channelId,
|
|
15525
|
+
runId,
|
|
15566
15526
|
...credentialActorLogContext,
|
|
15567
15527
|
assistantUserName: botConfig.userName,
|
|
15568
15528
|
modelId: activeModelId
|
|
@@ -15585,7 +15545,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15585
15545
|
// look indistinguishable from Slack ingress dropping attachments.
|
|
15586
15546
|
"app.message.attachment_count": inboundAttachmentCount,
|
|
15587
15547
|
"app.message.prompt_attachment_count": promptAttachmentCount,
|
|
15588
|
-
"messaging.message.id":
|
|
15548
|
+
"messaging.message.id": slackSource?.messageTs ?? ""
|
|
15589
15549
|
},
|
|
15590
15550
|
"Agent message received"
|
|
15591
15551
|
);
|
|
@@ -15603,44 +15563,40 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15603
15563
|
resumedFromSessionRecord,
|
|
15604
15564
|
currentSliceId,
|
|
15605
15565
|
existingSessionRecord
|
|
15606
|
-
} = await restoreSessionRecord(
|
|
15566
|
+
} = await restoreSessionRecord({
|
|
15567
|
+
conversationId,
|
|
15568
|
+
turnId
|
|
15569
|
+
});
|
|
15607
15570
|
const committedInstructionProvenance = [
|
|
15608
15571
|
...existingSessionRecord?.piMessageProvenance ?? [],
|
|
15609
15572
|
...(existingSessionRecord?.actors ?? []).map(instructionProvenanceFor),
|
|
15610
15573
|
...resumedFromSessionRecord ? [] : [instructionProvenanceFor(actor)]
|
|
15611
15574
|
];
|
|
15612
15575
|
const runActors = () => instructionActors(committedInstructionProvenance);
|
|
15613
|
-
canRecordMcpProviders = Boolean(
|
|
15614
|
-
sessionRecordState.canUseTurnSession && sessionConversationId && sessionId
|
|
15615
|
-
);
|
|
15616
15576
|
resume = createResumeState({
|
|
15617
|
-
channelName: routing.
|
|
15577
|
+
channelName: routing.slackConversation?.name,
|
|
15618
15578
|
destination: routing.destination,
|
|
15619
15579
|
durability,
|
|
15620
15580
|
getLoadedSkillNames: () => loadedSkillNamesForResume,
|
|
15621
|
-
getReasoningLevel: () =>
|
|
15581
|
+
getReasoningLevel: () => turnRoute?.reasoningLevel,
|
|
15622
15582
|
logContext: sessionRecordLogContext,
|
|
15623
15583
|
getModelId: () => activeModelId,
|
|
15624
15584
|
recordActiveMcpProviders,
|
|
15625
15585
|
actor,
|
|
15626
15586
|
runSource,
|
|
15627
|
-
|
|
15628
|
-
|
|
15587
|
+
conversationId,
|
|
15588
|
+
turnId,
|
|
15629
15589
|
sessionRecordState,
|
|
15630
15590
|
startedAtMs: replyStartedAtMs,
|
|
15631
15591
|
surface
|
|
15632
15592
|
});
|
|
15633
15593
|
const runResume = resume;
|
|
15634
15594
|
const recordParentToolExecutionStart = async (event) => {
|
|
15635
|
-
if (!sessionRecordState.canUseTurnSession || !sessionConversationId || !sessionId) {
|
|
15636
|
-
return;
|
|
15637
|
-
}
|
|
15638
15595
|
try {
|
|
15639
15596
|
await recordToolExecutionStarted({
|
|
15640
|
-
conversationId
|
|
15597
|
+
conversationId,
|
|
15641
15598
|
toolCallId: event.toolCallId,
|
|
15642
|
-
toolName: event.toolName
|
|
15643
|
-
args: event.args
|
|
15599
|
+
toolName: event.toolName
|
|
15644
15600
|
});
|
|
15645
15601
|
} catch (error) {
|
|
15646
15602
|
logException(
|
|
@@ -15662,9 +15618,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15662
15618
|
};
|
|
15663
15619
|
const priorPiMessages = resumedFromSessionRecord ? existingSessionRecord?.piMessages : input.piMessages;
|
|
15664
15620
|
connectedMcpProviders = new Set(
|
|
15665
|
-
|
|
15666
|
-
conversationId: sessionConversationId
|
|
15667
|
-
}) : []
|
|
15621
|
+
await loadConnectedMcpProviders({ conversationId })
|
|
15668
15622
|
);
|
|
15669
15623
|
await restoreSkillRuntime({
|
|
15670
15624
|
activeSkills,
|
|
@@ -15675,19 +15629,36 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15675
15629
|
});
|
|
15676
15630
|
const { routerBlocks, userContentParts } = buildPromptInput(input);
|
|
15677
15631
|
const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [...input.piMessages ?? []];
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
|
|
15685
|
-
|
|
15686
|
-
|
|
15687
|
-
|
|
15688
|
-
|
|
15689
|
-
|
|
15690
|
-
|
|
15632
|
+
if (activeModelProfile === STANDARD_MODEL_PROFILE) {
|
|
15633
|
+
turnRoute = await selectTurnRoute({
|
|
15634
|
+
completeObject,
|
|
15635
|
+
conversationContext: input.conversationContext,
|
|
15636
|
+
context: {
|
|
15637
|
+
threadId: conversationId,
|
|
15638
|
+
channelId: slackDestination?.channelId,
|
|
15639
|
+
actorId: slackActor?.userId,
|
|
15640
|
+
runId
|
|
15641
|
+
},
|
|
15642
|
+
currentTurnBlocks: routerBlocks,
|
|
15643
|
+
fastModelId: botConfig.fastModelId,
|
|
15644
|
+
messageText: userInput,
|
|
15645
|
+
profiles: botConfig.profiles
|
|
15646
|
+
});
|
|
15647
|
+
if (configuredReasoningLevel) {
|
|
15648
|
+
turnRoute = {
|
|
15649
|
+
...turnRoute,
|
|
15650
|
+
reasoningLevel: configuredReasoningLevel,
|
|
15651
|
+
reason: `configured:${policy.reasoningLevel ? "agent_config" : "default"}:${turnRoute.reason}`
|
|
15652
|
+
};
|
|
15653
|
+
}
|
|
15654
|
+
} else {
|
|
15655
|
+
const activeProfileConfig = profileConfig(botConfig, activeModelProfile);
|
|
15656
|
+
turnRoute = configuredTurnRoute(
|
|
15657
|
+
activeModelProfile,
|
|
15658
|
+
activeProfileConfig.reasoningLevel ?? policy.reasoningLevel ?? botConfig.reasoningLevel ?? "medium",
|
|
15659
|
+
activeProfileConfig.reasoningLevel ? "profile" : policy.reasoningLevel ? "agent_config" : "default"
|
|
15660
|
+
);
|
|
15661
|
+
}
|
|
15691
15662
|
const generatedFiles = [];
|
|
15692
15663
|
const artifactStatePatch = {};
|
|
15693
15664
|
const toolCalls = [];
|
|
@@ -15696,70 +15667,90 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15696
15667
|
const currentAgentMessages = () => agent ? [...agent.state.messages] : [];
|
|
15697
15668
|
const handoffProfiles = [
|
|
15698
15669
|
DEFAULT_HANDOFF_MODEL_PROFILE,
|
|
15699
|
-
...Object.keys(botConfig.
|
|
15670
|
+
...Object.keys(botConfig.profiles).filter(
|
|
15671
|
+
(profile) => profile !== STANDARD_MODEL_PROFILE && profile !== DEFAULT_HANDOFF_MODEL_PROFILE
|
|
15672
|
+
).sort()
|
|
15700
15673
|
];
|
|
15701
|
-
const
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
15706
|
-
|
|
15707
|
-
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
},
|
|
15727
|
-
"Failed to report assistant status"
|
|
15728
|
-
);
|
|
15729
|
-
});
|
|
15730
|
-
const handoffMessages = await compactContextForHandoff(
|
|
15674
|
+
const scheduleHandoff = async (args) => {
|
|
15675
|
+
if (args.profile === activeModelProfile) {
|
|
15676
|
+
return;
|
|
15677
|
+
}
|
|
15678
|
+
const runtimeContext = retainRuntimeTurnContext(
|
|
15679
|
+
args.runtimeContextSourceMessages ?? args.sourceMessages
|
|
15680
|
+
);
|
|
15681
|
+
const standardPhaseUsage = extractGenAiUsageSummary(
|
|
15682
|
+
...args.sourceMessages.slice(runResume.beforeMessageCount).filter(isAssistantMessage)
|
|
15683
|
+
);
|
|
15684
|
+
const phaseUsage = hasAgentTurnUsage(standardPhaseUsage) ? standardPhaseUsage : void 0;
|
|
15685
|
+
const selectedProfile = profileConfig(botConfig, args.profile);
|
|
15686
|
+
const target = {
|
|
15687
|
+
modelId: selectedProfile.modelId,
|
|
15688
|
+
modelProfile: args.profile
|
|
15689
|
+
};
|
|
15690
|
+
const handoffModel = resolveGatewayModel(target.modelId);
|
|
15691
|
+
const handoffReasoningLevel = selectedProfile.reasoningLevel ?? turnRoute.reasoningLevel;
|
|
15692
|
+
const handoffThinkingLevel = toPiReasoningLevel(handoffReasoningLevel);
|
|
15693
|
+
void (async () => {
|
|
15694
|
+
await observers.onStatus?.({ text: "Switching models" });
|
|
15695
|
+
})().catch((error) => {
|
|
15696
|
+
logWarn(
|
|
15697
|
+
"assistant_status_observer_failed",
|
|
15698
|
+
{},
|
|
15731
15699
|
{
|
|
15732
|
-
|
|
15733
|
-
conversationId: sessionConversationId,
|
|
15734
|
-
piMessages: sourceMessages,
|
|
15735
|
-
runtimeContext,
|
|
15736
|
-
signal: signal2,
|
|
15737
|
-
target,
|
|
15738
|
-
metadata: {
|
|
15739
|
-
threadId: routing.correlation?.threadId,
|
|
15740
|
-
channelId: routing.correlation?.channelId,
|
|
15741
|
-
actorId: routing.correlation?.actorId,
|
|
15742
|
-
runId: routing.correlation?.runId
|
|
15743
|
-
}
|
|
15700
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15744
15701
|
},
|
|
15745
|
-
|
|
15702
|
+
"Failed to report assistant status"
|
|
15746
15703
|
);
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
|
|
15704
|
+
});
|
|
15705
|
+
const handoffMessages = await compactContextForHandoff(
|
|
15706
|
+
{
|
|
15707
|
+
conversationContext: input.conversationContext,
|
|
15708
|
+
conversationId,
|
|
15709
|
+
piMessages: args.sourceMessages,
|
|
15710
|
+
runtimeContext,
|
|
15711
|
+
signal: args.signal,
|
|
15712
|
+
triggeringToolCallId: args.triggeringToolCallId,
|
|
15713
|
+
target,
|
|
15714
|
+
metadata: {
|
|
15715
|
+
threadId: conversationId,
|
|
15716
|
+
channelId: slackDestination?.channelId,
|
|
15717
|
+
actorId: slackActor?.userId,
|
|
15718
|
+
runId
|
|
15719
|
+
}
|
|
15720
|
+
},
|
|
15721
|
+
{ completeText }
|
|
15722
|
+
);
|
|
15723
|
+
if (handoffReasoningLevel !== turnRoute.reasoningLevel) {
|
|
15724
|
+
turnRoute = {
|
|
15725
|
+
...turnRoute,
|
|
15726
|
+
reasoningLevel: handoffReasoningLevel,
|
|
15727
|
+
reason: `profile_reasoning_override:${args.profile}:${turnRoute.reason}`
|
|
15752
15728
|
};
|
|
15753
|
-
activeModelProfile = profile;
|
|
15754
|
-
activeModelId = target.modelId;
|
|
15755
15729
|
}
|
|
15756
|
-
|
|
15730
|
+
handoffPhaseUsage = phaseUsage;
|
|
15731
|
+
pendingHandoff = {
|
|
15732
|
+
messages: handoffMessages,
|
|
15733
|
+
model: handoffModel,
|
|
15734
|
+
thinkingLevel: handoffThinkingLevel
|
|
15735
|
+
};
|
|
15736
|
+
activeModelProfile = args.profile;
|
|
15737
|
+
activeModelId = target.modelId;
|
|
15738
|
+
};
|
|
15739
|
+
const requestHandoff = {
|
|
15740
|
+
profiles: handoffProfiles,
|
|
15741
|
+
execute: async (profile, options) => await scheduleHandoff({
|
|
15742
|
+
profile,
|
|
15743
|
+
signal: options.signal,
|
|
15744
|
+
sourceMessages: [...agent.state.messages],
|
|
15745
|
+
triggeringToolCallId: options.toolCallId
|
|
15746
|
+
})
|
|
15747
|
+
};
|
|
15757
15748
|
setTags({
|
|
15758
15749
|
conversationId: spanContext.conversationId,
|
|
15759
|
-
slackThreadId:
|
|
15760
|
-
slackUserId:
|
|
15761
|
-
slackChannelId:
|
|
15762
|
-
runId
|
|
15750
|
+
slackThreadId: slackSource ? conversationId : void 0,
|
|
15751
|
+
slackUserId: slackActor?.userId,
|
|
15752
|
+
slackChannelId: slackDestination?.channelId,
|
|
15753
|
+
runId,
|
|
15763
15754
|
...credentialActorLogContext,
|
|
15764
15755
|
assistantUserName: botConfig.userName,
|
|
15765
15756
|
modelId: activeModelId
|
|
@@ -15789,8 +15780,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15789
15780
|
requestHandoff,
|
|
15790
15781
|
resume: runResume,
|
|
15791
15782
|
routing,
|
|
15792
|
-
|
|
15793
|
-
|
|
15783
|
+
conversationId,
|
|
15784
|
+
turnId,
|
|
15794
15785
|
skillSandbox,
|
|
15795
15786
|
spanContext,
|
|
15796
15787
|
state,
|
|
@@ -15802,9 +15793,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15802
15793
|
mcpToolManager = wiring.mcpToolManager;
|
|
15803
15794
|
const sandboxExecutor = wiring.sandboxExecutor;
|
|
15804
15795
|
const getPendingAuthPause = wiring.getPendingAuthPause;
|
|
15805
|
-
const toolsAfterHandoff = wiring.agentTools
|
|
15806
|
-
(tool) => tool.name !== HANDOFF_TOOL_NAME
|
|
15807
|
-
);
|
|
15796
|
+
const toolsAfterHandoff = wiring.agentTools;
|
|
15808
15797
|
const {
|
|
15809
15798
|
baseInstructions,
|
|
15810
15799
|
inputMessages,
|
|
@@ -15830,42 +15819,52 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15830
15819
|
toolRuntimeContext: wiring.toolRuntimeContext,
|
|
15831
15820
|
userContentParts
|
|
15832
15821
|
});
|
|
15833
|
-
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
let bufferedStandardMessageStart = false;
|
|
15837
|
-
const startAssistantMessage = () => {
|
|
15838
|
-
Promise.resolve(observers.onAssistantMessageStart?.()).catch((error) => {
|
|
15839
|
-
logWarn(
|
|
15840
|
-
"streaming_message_start_error",
|
|
15841
|
-
{},
|
|
15842
|
-
{
|
|
15843
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15844
|
-
},
|
|
15845
|
-
"Failed to deliver assistant message start to stream coordinator"
|
|
15846
|
-
);
|
|
15847
|
-
});
|
|
15848
|
-
if (hasEmittedText) {
|
|
15849
|
-
needsSeparator = true;
|
|
15822
|
+
const applyPendingHandoff = () => {
|
|
15823
|
+
if (!pendingHandoff) {
|
|
15824
|
+
return void 0;
|
|
15850
15825
|
}
|
|
15826
|
+
const { messages, model, thinkingLevel } = pendingHandoff;
|
|
15827
|
+
const replacement = [...messages];
|
|
15828
|
+
pendingHandoff = void 0;
|
|
15829
|
+
agent.state.messages = replacement;
|
|
15830
|
+
agent.state.model = model;
|
|
15831
|
+
agent.state.thinkingLevel = thinkingLevel;
|
|
15832
|
+
agent.state.tools = toolsAfterHandoff;
|
|
15833
|
+
runResume.setBeforeMessageCount(replacement.length);
|
|
15834
|
+
runResume.setTurnStartMessageIndex(0);
|
|
15835
|
+
runResume.adoptCommittedBoundary(replacement);
|
|
15836
|
+
setSpanAttributes({
|
|
15837
|
+
"gen_ai.agent.model": activeModelId,
|
|
15838
|
+
"gen_ai.agent.model_profile": activeModelProfile,
|
|
15839
|
+
"gen_ai.agent.reasoning.level": turnRoute.reasoningLevel
|
|
15840
|
+
});
|
|
15841
|
+
return {
|
|
15842
|
+
context: {
|
|
15843
|
+
systemPrompt: baseInstructions,
|
|
15844
|
+
messages: replacement,
|
|
15845
|
+
tools: toolsAfterHandoff
|
|
15846
|
+
},
|
|
15847
|
+
model,
|
|
15848
|
+
thinkingLevel
|
|
15849
|
+
};
|
|
15851
15850
|
};
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
"Failed to deliver text delta to stream"
|
|
15851
|
+
let assistantMessageDeliveryError;
|
|
15852
|
+
const deliverAssistantMessage = async (message) => {
|
|
15853
|
+
const text = getAssistantMessageText(message);
|
|
15854
|
+
if (!text || !delivery) {
|
|
15855
|
+
return;
|
|
15856
|
+
}
|
|
15857
|
+
try {
|
|
15858
|
+
await delivery.onAssistantMessage({ text });
|
|
15859
|
+
} catch (error) {
|
|
15860
|
+
assistantMessageDeliveryError = new AssistantMessageDeliveryError(
|
|
15861
|
+
error
|
|
15864
15862
|
);
|
|
15865
|
-
|
|
15863
|
+
throw assistantMessageDeliveryError;
|
|
15864
|
+
}
|
|
15866
15865
|
};
|
|
15867
15866
|
const drainSteeringMessages = async () => {
|
|
15868
|
-
if (!durability.drainSteeringMessages
|
|
15867
|
+
if (!durability.drainSteeringMessages) {
|
|
15869
15868
|
return;
|
|
15870
15869
|
}
|
|
15871
15870
|
try {
|
|
@@ -15932,33 +15931,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15932
15931
|
return void 0;
|
|
15933
15932
|
},
|
|
15934
15933
|
prepareNextTurn: async () => {
|
|
15935
|
-
|
|
15936
|
-
if (pendingHandoff) {
|
|
15937
|
-
const { messages, model, thinkingLevel } = pendingHandoff;
|
|
15938
|
-
const replacement = [...messages];
|
|
15939
|
-
pendingHandoff = void 0;
|
|
15940
|
-
agent.state.messages = replacement;
|
|
15941
|
-
agent.state.model = model;
|
|
15942
|
-
agent.state.thinkingLevel = thinkingLevel;
|
|
15943
|
-
agent.state.tools = toolsAfterHandoff;
|
|
15944
|
-
runResume.setBeforeMessageCount(replacement.length);
|
|
15945
|
-
runResume.setTurnStartMessageIndex(0);
|
|
15946
|
-
runResume.adoptCommittedBoundary(replacement);
|
|
15947
|
-
setSpanAttributes({
|
|
15948
|
-
"gen_ai.agent.model": activeModelId,
|
|
15949
|
-
"gen_ai.agent.model_profile": activeModelProfile,
|
|
15950
|
-
"gen_ai.agent.reasoning.level": reasoningSelection.reasoningLevel
|
|
15951
|
-
});
|
|
15952
|
-
update = {
|
|
15953
|
-
context: {
|
|
15954
|
-
systemPrompt: baseInstructions,
|
|
15955
|
-
messages: replacement,
|
|
15956
|
-
tools: toolsAfterHandoff
|
|
15957
|
-
},
|
|
15958
|
-
model,
|
|
15959
|
-
thinkingLevel
|
|
15960
|
-
};
|
|
15961
|
-
}
|
|
15934
|
+
const update = applyPendingHandoff();
|
|
15962
15935
|
await drainSteeringMessages();
|
|
15963
15936
|
runResume.yieldAtSafeBoundaryIfDue(currentAgentMessages());
|
|
15964
15937
|
return update;
|
|
@@ -15966,7 +15939,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15966
15939
|
initialState: {
|
|
15967
15940
|
systemPrompt: baseInstructions,
|
|
15968
15941
|
model: resolveGatewayModel(activeModelId),
|
|
15969
|
-
thinkingLevel: toPiReasoningLevel(
|
|
15942
|
+
thinkingLevel: toPiReasoningLevel(turnRoute.reasoningLevel),
|
|
15970
15943
|
tools: wiring.agentTools
|
|
15971
15944
|
}
|
|
15972
15945
|
});
|
|
@@ -15980,40 +15953,17 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15980
15953
|
}
|
|
15981
15954
|
return runResume.persistSafeBoundary([...agent.state.messages]).then(() => void 0);
|
|
15982
15955
|
}
|
|
15983
|
-
if (event.type === "message_start") {
|
|
15984
|
-
if (activeModelProfile === STANDARD_MODEL_PROFILE && requestHandoff) {
|
|
15985
|
-
bufferedStandardMessageStart = true;
|
|
15986
|
-
bufferedStandardText = "";
|
|
15987
|
-
} else {
|
|
15988
|
-
startAssistantMessage();
|
|
15989
|
-
}
|
|
15990
|
-
return;
|
|
15991
|
-
}
|
|
15992
15956
|
if (event.type === "message_end" && isAssistantMessage(event.message)) {
|
|
15993
|
-
if (
|
|
15957
|
+
if (event.message.stopReason === "error" || event.message.stopReason === "aborted") {
|
|
15994
15958
|
return;
|
|
15995
15959
|
}
|
|
15996
15960
|
const containsHandoff = event.message.content.some(
|
|
15997
15961
|
(part) => part.type === "toolCall" && part.name === HANDOFF_TOOL_NAME
|
|
15998
15962
|
);
|
|
15999
|
-
if (
|
|
16000
|
-
|
|
16001
|
-
if (bufferedStandardText) {
|
|
16002
|
-
deliverText(bufferedStandardText);
|
|
16003
|
-
}
|
|
15963
|
+
if (containsHandoff) {
|
|
15964
|
+
return;
|
|
16004
15965
|
}
|
|
16005
|
-
|
|
16006
|
-
bufferedStandardText = "";
|
|
16007
|
-
return;
|
|
16008
|
-
}
|
|
16009
|
-
if (event.type !== "message_update") return;
|
|
16010
|
-
if (event.assistantMessageEvent.type !== "text_delta") return;
|
|
16011
|
-
const deltaText = event.assistantMessageEvent.delta;
|
|
16012
|
-
if (!deltaText) return;
|
|
16013
|
-
if (bufferedStandardMessageStart) {
|
|
16014
|
-
bufferedStandardText += deltaText;
|
|
16015
|
-
} else {
|
|
16016
|
-
deliverText(deltaText);
|
|
15966
|
+
return deliverAssistantMessage(event.message);
|
|
16017
15967
|
}
|
|
16018
15968
|
});
|
|
16019
15969
|
let newMessages = [];
|
|
@@ -16049,13 +15999,13 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16049
15999
|
await runResume.commitInput();
|
|
16050
16000
|
}
|
|
16051
16001
|
}
|
|
16052
|
-
const runAgentStep = async (run2) => {
|
|
16002
|
+
const runAgentStep = async (run2, abortRun = () => agent.abort()) => {
|
|
16053
16003
|
let timeoutId;
|
|
16054
16004
|
let removeAbortListener;
|
|
16055
16005
|
const timeoutPromise = new Promise((_, reject) => {
|
|
16056
16006
|
const rejectWithTimeout = () => {
|
|
16057
16007
|
runResume.markTimedOut();
|
|
16058
|
-
|
|
16008
|
+
abortRun();
|
|
16059
16009
|
reject(
|
|
16060
16010
|
new Error(
|
|
16061
16011
|
`Agent turn timed out after ${turnTimeoutBudgetMs}ms`
|
|
@@ -16071,7 +16021,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16071
16021
|
});
|
|
16072
16022
|
const abortPromise = signal ? new Promise((_, reject) => {
|
|
16073
16023
|
const rejectWithAbort = () => {
|
|
16074
|
-
|
|
16024
|
+
abortRun();
|
|
16075
16025
|
reject(signal.reason);
|
|
16076
16026
|
};
|
|
16077
16027
|
if (signal.aborted) {
|
|
@@ -16096,8 +16046,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16096
16046
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
16097
16047
|
"gen_ai.operation.name": "invoke_agent",
|
|
16098
16048
|
"gen_ai.request.model": activeModelId,
|
|
16099
|
-
...
|
|
16100
|
-
"gen_ai.request.reasoning.level":
|
|
16049
|
+
...turnRoute ? {
|
|
16050
|
+
"gen_ai.request.reasoning.level": turnRoute.reasoningLevel
|
|
16101
16051
|
} : {},
|
|
16102
16052
|
"app.ai.turn_timeout_ms": turnTimeoutBudgetMs,
|
|
16103
16053
|
"app.ai.turn_deadline_remaining_ms": Math.max(
|
|
@@ -16139,10 +16089,38 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16139
16089
|
removeAbortListener?.();
|
|
16140
16090
|
}
|
|
16141
16091
|
};
|
|
16142
|
-
|
|
16092
|
+
const requestedProfile = activeModelProfile === STANDARD_MODEL_PROFILE ? turnRoute.profile : void 0;
|
|
16093
|
+
let run;
|
|
16094
|
+
if (requestedProfile && requestedProfile !== STANDARD_MODEL_PROFILE) {
|
|
16095
|
+
const handoffAbortController = new AbortController();
|
|
16096
|
+
await runAgentStep(
|
|
16097
|
+
scheduleHandoff({
|
|
16098
|
+
profile: requestedProfile,
|
|
16099
|
+
runtimeContextSourceMessages: shouldPromptAgent ? [freshPromptMessage] : void 0,
|
|
16100
|
+
signal: handoffAbortController.signal,
|
|
16101
|
+
sourceMessages: [...agent.state.messages]
|
|
16102
|
+
}),
|
|
16103
|
+
() => handoffAbortController.abort()
|
|
16104
|
+
);
|
|
16105
|
+
applyPendingHandoff();
|
|
16106
|
+
if (shouldPromptAgent) {
|
|
16107
|
+
await runResume.requireDurableInputCheckpoint([
|
|
16108
|
+
...agent.state.messages,
|
|
16109
|
+
freshPromptMessage
|
|
16110
|
+
]);
|
|
16111
|
+
run = agent.prompt(freshPromptMessage);
|
|
16112
|
+
} else {
|
|
16113
|
+
run = agent.continue();
|
|
16114
|
+
}
|
|
16115
|
+
} else {
|
|
16116
|
+
run = shouldPromptAgent ? agent.prompt(freshPromptMessage) : agent.continue();
|
|
16117
|
+
}
|
|
16143
16118
|
let retryUsage;
|
|
16144
16119
|
for (let attempt = 0; ; attempt += 1) {
|
|
16145
16120
|
await runAgentStep(run);
|
|
16121
|
+
if (assistantMessageDeliveryError) {
|
|
16122
|
+
throw assistantMessageDeliveryError;
|
|
16123
|
+
}
|
|
16146
16124
|
signal?.throwIfAborted();
|
|
16147
16125
|
if (runResume.cooperativeYieldError) {
|
|
16148
16126
|
throw runResume.cooperativeYieldError;
|
|
@@ -16207,15 +16185,15 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16207
16185
|
"gen_ai.operation.name": "invoke_agent",
|
|
16208
16186
|
"gen_ai.agent.model": activeModelId,
|
|
16209
16187
|
"gen_ai.agent.model_profile": activeModelProfile,
|
|
16210
|
-
"gen_ai.agent.reasoning.level":
|
|
16211
|
-
"gen_ai.agent.reasoning.level_reason":
|
|
16212
|
-
...
|
|
16213
|
-
"gen_ai.agent.reasoning.level_confidence":
|
|
16188
|
+
"gen_ai.agent.reasoning.level": turnRoute.reasoningLevel,
|
|
16189
|
+
"gen_ai.agent.reasoning.level_reason": turnRoute.reason,
|
|
16190
|
+
...turnRoute.confidence !== void 0 ? {
|
|
16191
|
+
"gen_ai.agent.reasoning.level_confidence": turnRoute.confidence
|
|
16214
16192
|
} : {},
|
|
16215
16193
|
"gen_ai.output.type": "text",
|
|
16216
16194
|
...conversationPrivacy ? { "app.conversation.privacy": conversationPrivacy } : {},
|
|
16217
|
-
|
|
16218
|
-
|
|
16195
|
+
"app.ai.session.conversation_id": conversationId,
|
|
16196
|
+
"app.ai.turn.session_id": turnId,
|
|
16219
16197
|
...currentSliceId ? { "app.ai.turn.slice_id": currentSliceId } : {},
|
|
16220
16198
|
...toGenAiMessagesTraceAttributes("gen_ai.input", inputMessages),
|
|
16221
16199
|
...inputMessagesAttribute ? { "gen_ai.input.messages": inputMessagesAttribute } : {}
|
|
@@ -16224,40 +16202,45 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16224
16202
|
} finally {
|
|
16225
16203
|
unsubscribe();
|
|
16226
16204
|
}
|
|
16227
|
-
|
|
16228
|
-
|
|
16229
|
-
|
|
16205
|
+
await recordActiveMcpProviders();
|
|
16206
|
+
const result = buildTurnResult({
|
|
16207
|
+
newMessages,
|
|
16208
|
+
userInput,
|
|
16209
|
+
artifactStatePatch,
|
|
16210
|
+
toolCalls,
|
|
16211
|
+
sandboxId: sandboxExecutor.getSandboxId(),
|
|
16212
|
+
sandboxDependencyProfileHash: sandboxExecutor.getDependencyProfileHash(),
|
|
16213
|
+
piMessages: [...agent.state.messages],
|
|
16214
|
+
durationMs: Date.now() - replyStartedAtMs,
|
|
16215
|
+
generatedFileCount: generatedFiles.length,
|
|
16216
|
+
shouldTrace,
|
|
16217
|
+
spanContext,
|
|
16218
|
+
usage: turnUsage,
|
|
16219
|
+
executionProfile: turnRoute,
|
|
16220
|
+
assistantUserName: botConfig.userName,
|
|
16221
|
+
modelId: activeModelId
|
|
16222
|
+
});
|
|
16230
16223
|
return {
|
|
16231
16224
|
status: "completed",
|
|
16232
|
-
result
|
|
16233
|
-
newMessages,
|
|
16234
|
-
userInput,
|
|
16235
|
-
artifactStatePatch,
|
|
16236
|
-
toolCalls,
|
|
16237
|
-
sandboxId: sandboxExecutor.getSandboxId(),
|
|
16238
|
-
sandboxDependencyProfileHash: sandboxExecutor.getDependencyProfileHash(),
|
|
16239
|
-
piMessages: [...agent.state.messages],
|
|
16240
|
-
durationMs: Date.now() - replyStartedAtMs,
|
|
16241
|
-
generatedFileCount: generatedFiles.length,
|
|
16242
|
-
shouldTrace,
|
|
16243
|
-
spanContext,
|
|
16244
|
-
usage: turnUsage,
|
|
16245
|
-
reasoningSelection,
|
|
16246
|
-
correlation: routing.correlation,
|
|
16247
|
-
assistantUserName: botConfig.userName,
|
|
16248
|
-
modelId: activeModelId
|
|
16249
|
-
})
|
|
16225
|
+
result
|
|
16250
16226
|
};
|
|
16251
16227
|
} catch (error) {
|
|
16228
|
+
if (error instanceof AssistantMessageDeliveryError && !(error.originalError instanceof RetryableDeliveryError)) {
|
|
16229
|
+
throw error.originalError;
|
|
16230
|
+
}
|
|
16231
|
+
const runError = error instanceof AssistantMessageDeliveryError ? error.originalError : error;
|
|
16252
16232
|
if (resume) {
|
|
16253
16233
|
const { outcome } = await resume.translateExpectedEnding({
|
|
16254
16234
|
currentUsage: turnUsage,
|
|
16255
|
-
error
|
|
16235
|
+
error: runError
|
|
16256
16236
|
});
|
|
16257
16237
|
if (outcome) {
|
|
16258
16238
|
return outcome;
|
|
16259
16239
|
}
|
|
16260
16240
|
}
|
|
16241
|
+
if (error instanceof AssistantMessageDeliveryError) {
|
|
16242
|
+
throw error.originalError;
|
|
16243
|
+
}
|
|
16261
16244
|
if (error instanceof ModelProfileNotConfiguredError) {
|
|
16262
16245
|
throw error;
|
|
16263
16246
|
}
|
|
@@ -16277,10 +16260,11 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16277
16260
|
error,
|
|
16278
16261
|
"assistant_reply_generation_failed",
|
|
16279
16262
|
{
|
|
16280
|
-
|
|
16281
|
-
|
|
16282
|
-
|
|
16283
|
-
|
|
16263
|
+
conversationId,
|
|
16264
|
+
slackThreadId: slackSource ? conversationId : void 0,
|
|
16265
|
+
slackUserId: slackActor?.userId,
|
|
16266
|
+
slackChannelId: slackDestination?.channelId,
|
|
16267
|
+
runId,
|
|
16284
16268
|
...credentialActorLogContext,
|
|
16285
16269
|
assistantUserName: botConfig.userName,
|
|
16286
16270
|
modelId: activeModelId
|
|
@@ -16298,8 +16282,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16298
16282
|
outcome: "provider_error",
|
|
16299
16283
|
modelId: activeModelId,
|
|
16300
16284
|
assistantMessageCount: 0,
|
|
16301
|
-
...
|
|
16302
|
-
reasoningLevel:
|
|
16285
|
+
...turnRoute ? {
|
|
16286
|
+
reasoningLevel: turnRoute.reasoningLevel
|
|
16303
16287
|
} : {},
|
|
16304
16288
|
toolCalls: [],
|
|
16305
16289
|
toolResultCount: 0,
|
|
@@ -16349,6 +16333,7 @@ export {
|
|
|
16349
16333
|
getConfigDefaults,
|
|
16350
16334
|
shouldEmitDevAgentTrace,
|
|
16351
16335
|
AuthorizationFlowDisabledError,
|
|
16336
|
+
RetryableDeliveryError,
|
|
16352
16337
|
truncateStatusText,
|
|
16353
16338
|
escapeSlackMrkdwnText,
|
|
16354
16339
|
formatSlackLink,
|