@sentry/junior 0.106.0 → 0.107.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-hooks-KR5BCWOK.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 +3586 -3614
- 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 +2 -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-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 -16
- 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-DDRQ4U7I.js → chunk-4YF7Z6IA.js} +390 -270
- package/dist/{chunk-AZ5OMSN5.js → chunk-AUUOHQAT.js} +2 -2
- package/dist/chunk-B2Z2H66D.js +250 -0
- package/dist/{chunk-4W4O4DCV.js → chunk-CQ7KSO2B.js} +75 -45
- package/dist/{chunk-MJSJAHBW.js → chunk-DY7TRYB5.js} +1 -1
- package/dist/{chunk-GPPUTY5M.js → chunk-EDLNHZH3.js} +861 -891
- package/dist/{chunk-R5BFYK2O.js → chunk-IGHMVDWI.js} +134 -18
- package/dist/chunk-MU6HHZEN.js +99 -0
- package/dist/{chunk-XTKJPSMF.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-ZMRLBBD5.js → chunk-RMVOAJRL.js} +30 -13
- package/dist/{chunk-3NYUCBLE.js → chunk-SPUAJVVH.js} +6 -4
- package/dist/{chunk-4UYIRWDW.js → chunk-SS67LUOK.js} +41 -290
- package/dist/{chunk-FXFQNHRU.js → chunk-VFUK3X5B.js} +4 -2
- package/dist/{chunk-3MPPVPGZ.js → chunk-VH6KWKG2.js} +2 -2
- package/dist/chunk-VIXFG2VC.js +182 -0
- package/dist/{chunk-BKM4UXUD.js → chunk-YFQ7CQDE.js} +669 -18
- package/dist/{chunk-77LHNQK4.js → chunk-YIPD3L6L.js} +4 -2
- package/dist/{chunk-3OUSJPR7.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 +2041 -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-S33LFWG2.js → db-DIGO4TGW.js} +6 -8
- package/dist/{runner-HA5XAL6K.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 +5 -5
- 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-P4P7O5WG.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-TMJISRKO.js +0 -18
|
@@ -4,18 +4,27 @@ import {
|
|
|
4
4
|
TurnSliceLimitExceededError,
|
|
5
5
|
abandonReplacedPendingAuth,
|
|
6
6
|
canReusePendingAuthLink,
|
|
7
|
+
estimateTextTokens,
|
|
8
|
+
getAgentContextCompactionTriggerTokens,
|
|
7
9
|
getInterruptionMarker,
|
|
8
10
|
isTurnInputCommitLostError,
|
|
9
11
|
loadTurnSessionRecord,
|
|
10
12
|
mergeArtifactsState,
|
|
11
13
|
persistAuthPauseSessionRecord,
|
|
14
|
+
persistContinuationSessionRecord,
|
|
12
15
|
persistRunningSessionRecord,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
persistYieldSessionRecord,
|
|
17
|
+
updateConversationStats
|
|
18
|
+
} from "./chunk-YFQ7CQDE.js";
|
|
16
19
|
import {
|
|
17
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
18
|
-
|
|
20
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
21
|
+
loadConnectedMcpProviders,
|
|
22
|
+
loadConversationProjection,
|
|
23
|
+
openConversationProjection,
|
|
24
|
+
recordAuthorizationRequested,
|
|
25
|
+
recordMcpProviderConnected,
|
|
26
|
+
recordToolExecutionStarted
|
|
27
|
+
} from "./chunk-4YF7Z6IA.js";
|
|
19
28
|
import {
|
|
20
29
|
buildNonInteractiveShellScript,
|
|
21
30
|
createSandboxInstance,
|
|
@@ -25,22 +34,11 @@ import {
|
|
|
25
34
|
isSnapshotMissingError,
|
|
26
35
|
resolveRuntimeDependencySnapshot,
|
|
27
36
|
runNonInteractiveCommand
|
|
28
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-SPUAJVVH.js";
|
|
29
38
|
import {
|
|
30
39
|
addAgentTurnUsage,
|
|
31
|
-
hasAgentTurnUsage
|
|
32
|
-
|
|
33
|
-
loadConversationProjection,
|
|
34
|
-
openConversationProjection,
|
|
35
|
-
recordAuthorizationRequested,
|
|
36
|
-
recordMcpProviderConnected,
|
|
37
|
-
recordToolExecutionStarted
|
|
38
|
-
} from "./chunk-DDRQ4U7I.js";
|
|
39
|
-
import {
|
|
40
|
-
estimateTextTokens,
|
|
41
|
-
getAgentContextCompactionTriggerTokens,
|
|
42
|
-
updateConversationStats
|
|
43
|
-
} from "./chunk-P4P7O5WG.js";
|
|
40
|
+
hasAgentTurnUsage
|
|
41
|
+
} from "./chunk-MU6HHZEN.js";
|
|
44
42
|
import {
|
|
45
43
|
privateTraceResultAttributes
|
|
46
44
|
} from "./chunk-UIE3R5XU.js";
|
|
@@ -52,10 +50,10 @@ import {
|
|
|
52
50
|
getPlugins,
|
|
53
51
|
getSlackToolContext,
|
|
54
52
|
resolveChannelCapabilities
|
|
55
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-RMVOAJRL.js";
|
|
56
54
|
import {
|
|
57
55
|
createPluginLogger
|
|
58
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-AUUOHQAT.js";
|
|
59
57
|
import {
|
|
60
58
|
SANDBOX_DATA_ROOT,
|
|
61
59
|
SANDBOX_SKILLS_ROOT,
|
|
@@ -63,6 +61,10 @@ import {
|
|
|
63
61
|
sandboxSkillDir,
|
|
64
62
|
sandboxSkillFile
|
|
65
63
|
} from "./chunk-G3E7SCME.js";
|
|
64
|
+
import {
|
|
65
|
+
acquireActiveLock,
|
|
66
|
+
getStateAdapter
|
|
67
|
+
} from "./chunk-B2Z2H66D.js";
|
|
66
68
|
import {
|
|
67
69
|
SlackActionError,
|
|
68
70
|
downloadPrivateSlackFile,
|
|
@@ -72,16 +74,16 @@ import {
|
|
|
72
74
|
isDmChannel,
|
|
73
75
|
normalizeSlackConversationId,
|
|
74
76
|
withSlackRetries
|
|
75
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-VH6KWKG2.js";
|
|
76
78
|
import {
|
|
77
79
|
contextProvenance,
|
|
78
|
-
|
|
80
|
+
getConversationEventStore,
|
|
79
81
|
getConversationSearchStore,
|
|
80
82
|
getConversationStore,
|
|
81
83
|
getDb,
|
|
82
84
|
instructionActors,
|
|
83
85
|
instructionProvenanceFor
|
|
84
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-NVOTGWYX.js";
|
|
85
87
|
import {
|
|
86
88
|
sleep
|
|
87
89
|
} from "./chunk-4ZNGQH7C.js";
|
|
@@ -97,7 +99,6 @@ import {
|
|
|
97
99
|
STANDARD_MODEL_PROFILE,
|
|
98
100
|
TURN_CONTEXT_TAG,
|
|
99
101
|
TURN_REASONING_LEVELS,
|
|
100
|
-
acquireActiveLock,
|
|
101
102
|
botConfig,
|
|
102
103
|
completeObject,
|
|
103
104
|
completeText,
|
|
@@ -105,7 +106,6 @@ import {
|
|
|
105
106
|
extractAssistantText,
|
|
106
107
|
getGatewayApiKey,
|
|
107
108
|
getPiGatewayApiKey,
|
|
108
|
-
getStateAdapter,
|
|
109
109
|
getTerminalAssistantMessages,
|
|
110
110
|
hasCompactedConversationContext,
|
|
111
111
|
hasRuntimeTurnContext,
|
|
@@ -115,16 +115,18 @@ import {
|
|
|
115
115
|
isToolResultError,
|
|
116
116
|
isToolResultMessage,
|
|
117
117
|
modelIdForProfile,
|
|
118
|
+
modelProfileSchema,
|
|
118
119
|
nextProviderRetry,
|
|
119
120
|
normalizeSlackEmojiName,
|
|
120
121
|
normalizeToolNameFromResult,
|
|
122
|
+
profileConfig,
|
|
121
123
|
renderCurrentInstruction,
|
|
122
124
|
resolveGatewayModel,
|
|
123
125
|
retainRuntimeTurnContext,
|
|
124
126
|
stripRuntimeTurnContext,
|
|
125
127
|
trimTrailingAssistantMessages,
|
|
126
128
|
unwrapCurrentInstruction
|
|
127
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-SS67LUOK.js";
|
|
128
130
|
import {
|
|
129
131
|
parseSlackThreadId,
|
|
130
132
|
resolveConversationPrivacy,
|
|
@@ -143,21 +145,22 @@ import {
|
|
|
143
145
|
findSkillByName,
|
|
144
146
|
loadSkillsByName,
|
|
145
147
|
parseSkillInvocation
|
|
146
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-YT72TOEK.js";
|
|
147
149
|
import {
|
|
148
150
|
CredentialUnavailableError,
|
|
149
151
|
credentialContextSchema,
|
|
150
152
|
pluginCatalogRuntime,
|
|
151
153
|
resolveAuthTokenPlaceholder,
|
|
152
154
|
resolvePluginCommandEnv
|
|
153
|
-
} from "./chunk-
|
|
155
|
+
} from "./chunk-YIPD3L6L.js";
|
|
156
|
+
import {
|
|
157
|
+
isUserActor
|
|
158
|
+
} from "./chunk-VIXFG2VC.js";
|
|
154
159
|
import {
|
|
155
|
-
createActor,
|
|
156
160
|
extractGenAiUsageAttributes,
|
|
157
161
|
extractGenAiUsageSummary,
|
|
158
162
|
getLogContextAttributesForSpan,
|
|
159
163
|
getTracePropagationHeaders,
|
|
160
|
-
isUserActor,
|
|
161
164
|
logError,
|
|
162
165
|
logException,
|
|
163
166
|
logInfo,
|
|
@@ -169,7 +172,7 @@ import {
|
|
|
169
172
|
setTags,
|
|
170
173
|
summarizeMessageText,
|
|
171
174
|
withSpan
|
|
172
|
-
} from "./chunk-
|
|
175
|
+
} from "./chunk-O24R4DCK.js";
|
|
173
176
|
import {
|
|
174
177
|
isRecord
|
|
175
178
|
} from "./chunk-OB42YVAE.js";
|
|
@@ -669,27 +672,10 @@ function isRawToolPayloadResponse(text) {
|
|
|
669
672
|
if (isToolPayloadShape(parsed)) {
|
|
670
673
|
return true;
|
|
671
674
|
}
|
|
672
|
-
|
|
673
|
-
return /"type"\s*:\s*"tool[-_](use|call|result|error)"/i.test(compact);
|
|
675
|
+
return false;
|
|
674
676
|
}
|
|
675
|
-
var POST_CANVAS_REPLY_MAX_CHARS = 700;
|
|
676
|
-
var POST_CANVAS_REPLY_MAX_LINES = 8;
|
|
677
677
|
var THINKING_XML_BLOCK_PATTERN = /[ \t]*<thinking\b[^>]*>[\s\S]*?<\/thinking>[ \t]*(?:\r?\n)?/gi;
|
|
678
678
|
var FENCED_CODE_BLOCK_PATTERN = /```[\s\S]*?```/g;
|
|
679
|
-
function isVerbosePostCanvasReply(text) {
|
|
680
|
-
const lines = text.split(/\r?\n/).filter((line) => line.trim().length > 0);
|
|
681
|
-
return text.length > POST_CANVAS_REPLY_MAX_CHARS || lines.length > POST_CANVAS_REPLY_MAX_LINES;
|
|
682
|
-
}
|
|
683
|
-
function getCreatedCanvasUrl(artifactStatePatch) {
|
|
684
|
-
if (artifactStatePatch.lastCanvasUrl) {
|
|
685
|
-
return artifactStatePatch.lastCanvasUrl;
|
|
686
|
-
}
|
|
687
|
-
return artifactStatePatch.recentCanvases?.find((canvas) => canvas.url)?.url;
|
|
688
|
-
}
|
|
689
|
-
function buildBriefPostCanvasReply(artifactStatePatch) {
|
|
690
|
-
const canvasUrl = getCreatedCanvasUrl(artifactStatePatch);
|
|
691
|
-
return canvasUrl ? `I created a canvas with the full reference: ${canvasUrl}` : "I created a canvas with the full reference.";
|
|
692
|
-
}
|
|
693
679
|
function stripThinkingXmlBlocks(text) {
|
|
694
680
|
let result = "";
|
|
695
681
|
let cursor = 0;
|
|
@@ -705,6 +691,23 @@ function stripThinkingXmlBlocks(text) {
|
|
|
705
691
|
result += text.slice(cursor).replace(THINKING_XML_BLOCK_PATTERN, "");
|
|
706
692
|
return result;
|
|
707
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
|
+
}
|
|
708
711
|
function buildTurnResult(input) {
|
|
709
712
|
const {
|
|
710
713
|
newMessages,
|
|
@@ -716,8 +719,7 @@ function buildTurnResult(input) {
|
|
|
716
719
|
shouldTrace,
|
|
717
720
|
spanContext,
|
|
718
721
|
usage,
|
|
719
|
-
|
|
720
|
-
correlation,
|
|
722
|
+
executionProfile,
|
|
721
723
|
assistantUserName,
|
|
722
724
|
modelId
|
|
723
725
|
} = input;
|
|
@@ -730,20 +732,16 @@ function buildTurnResult(input) {
|
|
|
730
732
|
const exactNoReplyMarker = isNoReplyMarker(rawPrimaryText);
|
|
731
733
|
const mixedNoReplyMarker = !exactNoReplyMarker && containsNoReplyMarker(rawPrimaryText);
|
|
732
734
|
const noReplyRequested = exactNoReplyMarker || mixedNoReplyMarker;
|
|
733
|
-
const primaryText = noReplyRequested ? "" :
|
|
735
|
+
const primaryText = noReplyRequested ? "" : terminalAssistantMessages.map((message) => getAssistantMessageText(message)).filter((text) => Boolean(text)).join("\n\n");
|
|
734
736
|
const toolErrorCount = toolResults.filter((result) => result.isError).length;
|
|
735
|
-
const
|
|
736
|
-
(result) => !isToolResultError(result)
|
|
737
|
-
);
|
|
738
|
-
const successfulToolNames = new Set(
|
|
739
|
-
successfulToolResults.map((result) => normalizeToolNameFromResult(result)).filter((value) => Boolean(value))
|
|
737
|
+
const reactionPerformed = toolResults.some(
|
|
738
|
+
(result) => !isToolResultError(result) && normalizeToolNameFromResult(result) === "addReaction"
|
|
740
739
|
);
|
|
741
|
-
const
|
|
742
|
-
const
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
postThreadText: true
|
|
740
|
+
const completedWithoutTerminalText = noReplyRequested;
|
|
741
|
+
const resultLogContext = {
|
|
742
|
+
...spanContext,
|
|
743
|
+
assistantUserName,
|
|
744
|
+
modelId
|
|
747
745
|
};
|
|
748
746
|
const lastAssistant = terminalAssistantMessages.at(-1);
|
|
749
747
|
const stopReason = typeof lastAssistant?.stopReason === "string" ? lastAssistant.stopReason : void 0;
|
|
@@ -751,14 +749,7 @@ function buildTurnResult(input) {
|
|
|
751
749
|
const isProviderError = stopReason === "error";
|
|
752
750
|
if (exactNoReplyMarker) {
|
|
753
751
|
const markerCategory = reactionPerformed ? "reaction" : "none";
|
|
754
|
-
const markerContext =
|
|
755
|
-
slackThreadId: correlation?.threadId,
|
|
756
|
-
slackUserId: correlation?.actorId,
|
|
757
|
-
slackChannelId: correlation?.channelId,
|
|
758
|
-
runId: correlation?.runId,
|
|
759
|
-
assistantUserName,
|
|
760
|
-
modelId
|
|
761
|
-
};
|
|
752
|
+
const markerContext = resultLogContext;
|
|
762
753
|
const markerAttributes = {
|
|
763
754
|
"app.ai.no_reply_marker": true,
|
|
764
755
|
"app.ai.no_reply_marker_category": markerCategory,
|
|
@@ -775,14 +766,7 @@ function buildTurnResult(input) {
|
|
|
775
766
|
} else if (mixedNoReplyMarker) {
|
|
776
767
|
logWarn(
|
|
777
768
|
"ai_no_reply_marker_mixed_text",
|
|
778
|
-
|
|
779
|
-
slackThreadId: correlation?.threadId,
|
|
780
|
-
slackUserId: correlation?.actorId,
|
|
781
|
-
slackChannelId: correlation?.channelId,
|
|
782
|
-
runId: correlation?.runId,
|
|
783
|
-
assistantUserName,
|
|
784
|
-
modelId
|
|
785
|
-
},
|
|
769
|
+
resultLogContext,
|
|
786
770
|
{
|
|
787
771
|
"app.ai.no_reply_marker": true,
|
|
788
772
|
"app.ai.no_reply_marker_mode": "mixed"
|
|
@@ -790,17 +774,10 @@ function buildTurnResult(input) {
|
|
|
790
774
|
"No-reply marker appeared with visible assistant text"
|
|
791
775
|
);
|
|
792
776
|
}
|
|
793
|
-
if (!primaryText && !
|
|
777
|
+
if (!primaryText && !completedWithoutTerminalText && !isProviderError) {
|
|
794
778
|
logWarn(
|
|
795
779
|
"ai_model_response_empty",
|
|
796
|
-
|
|
797
|
-
slackThreadId: correlation?.threadId,
|
|
798
|
-
slackUserId: correlation?.actorId,
|
|
799
|
-
slackChannelId: correlation?.channelId,
|
|
800
|
-
runId: correlation?.runId,
|
|
801
|
-
assistantUserName,
|
|
802
|
-
modelId
|
|
803
|
-
},
|
|
780
|
+
resultLogContext,
|
|
804
781
|
{
|
|
805
782
|
"app.ai.tool_results": toolResults.length,
|
|
806
783
|
"app.ai.tool_error_results": toolErrorCount,
|
|
@@ -813,29 +790,23 @@ function buildTurnResult(input) {
|
|
|
813
790
|
let outcome;
|
|
814
791
|
if (isProviderError) {
|
|
815
792
|
outcome = "provider_error";
|
|
816
|
-
} else if (primaryText ||
|
|
793
|
+
} else if (primaryText || completedWithoutTerminalText) {
|
|
817
794
|
outcome = "success";
|
|
818
795
|
} else {
|
|
819
796
|
outcome = "execution_failure";
|
|
820
797
|
}
|
|
821
|
-
const
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const
|
|
825
|
-
const resolvedOutcome = escapedOrRawPayload ? "execution_failure" : outcome;
|
|
826
|
-
const deliveryPlan = resolvedOutcome === "success" && !resolvedText ? {
|
|
827
|
-
...baseDeliveryPlan,
|
|
828
|
-
postThreadText: false
|
|
829
|
-
} : baseDeliveryPlan;
|
|
830
|
-
const deliveryMode = deliveryPlan.mode;
|
|
798
|
+
const rejectedPrimaryText = Boolean(
|
|
799
|
+
rawPrimaryText && !noReplyRequested && !primaryText
|
|
800
|
+
);
|
|
801
|
+
const resolvedOutcome = rejectedPrimaryText ? "execution_failure" : outcome;
|
|
831
802
|
if (shouldTrace) {
|
|
832
803
|
logInfo(
|
|
833
804
|
"agent_message_out",
|
|
834
805
|
spanContext,
|
|
835
806
|
{
|
|
836
807
|
"app.message.kind": "assistant_outbound",
|
|
837
|
-
"app.message.length":
|
|
838
|
-
"app.message.output": summarizeMessageText(
|
|
808
|
+
"app.message.length": primaryText.length,
|
|
809
|
+
"app.message.output": summarizeMessageText(primaryText),
|
|
839
810
|
"app.ai.outcome": resolvedOutcome,
|
|
840
811
|
"app.ai.assistant_messages": assistantMessages.length,
|
|
841
812
|
...stopReason ? { "gen_ai.response.finish_reasons": [stopReason] } : {}
|
|
@@ -847,7 +818,7 @@ function buildTurnResult(input) {
|
|
|
847
818
|
outcome: resolvedOutcome,
|
|
848
819
|
modelId,
|
|
849
820
|
assistantMessageCount: assistantMessages.length,
|
|
850
|
-
reasoningLevel:
|
|
821
|
+
reasoningLevel: executionProfile.reasoningLevel,
|
|
851
822
|
toolCalls,
|
|
852
823
|
toolResultCount: toolResults.length,
|
|
853
824
|
toolErrorCount,
|
|
@@ -859,10 +830,8 @@ function buildTurnResult(input) {
|
|
|
859
830
|
providerError: void 0
|
|
860
831
|
};
|
|
861
832
|
return {
|
|
862
|
-
text:
|
|
833
|
+
text: primaryText,
|
|
863
834
|
artifactStatePatch: Object.keys(artifactStatePatch).length > 0 ? artifactStatePatch : void 0,
|
|
864
|
-
deliveryPlan,
|
|
865
|
-
deliveryMode,
|
|
866
835
|
sandboxId,
|
|
867
836
|
sandboxDependencyProfileHash,
|
|
868
837
|
piMessages: input.piMessages,
|
|
@@ -870,7 +839,7 @@ function buildTurnResult(input) {
|
|
|
870
839
|
};
|
|
871
840
|
}
|
|
872
841
|
|
|
873
|
-
// src/chat/services/turn-
|
|
842
|
+
// src/chat/services/turn-router.ts
|
|
874
843
|
import { z } from "zod";
|
|
875
844
|
var CLASSIFIER_CONFIDENCE_THRESHOLD = 0.75;
|
|
876
845
|
var MAX_ROUTER_CONTEXT_CHARS = 8e3;
|
|
@@ -896,14 +865,20 @@ function coerceClassifierConfidence(value) {
|
|
|
896
865
|
}
|
|
897
866
|
return CONFIDENCE_LABELS[trimmed] ?? value;
|
|
898
867
|
}
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
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
|
+
}
|
|
907
882
|
var CLASSIFIER_FALLBACK_REASONING_LEVEL = "medium";
|
|
908
883
|
var REASONING_LEVEL_RANK = {
|
|
909
884
|
none: 0,
|
|
@@ -932,10 +907,12 @@ function trimContextForRouter(text) {
|
|
|
932
907
|
originalCharCount: trimmed.length
|
|
933
908
|
};
|
|
934
909
|
}
|
|
935
|
-
function buildClassifierSystemPrompt() {
|
|
910
|
+
function buildClassifierSystemPrompt(profileNames) {
|
|
936
911
|
return [
|
|
937
|
-
"You
|
|
912
|
+
"You choose the execution profile most likely to produce a complete, source-grounded answer.",
|
|
938
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.",
|
|
939
916
|
"",
|
|
940
917
|
"Use none only for greetings, acknowledgments, and turns that need no substantive assistant work.",
|
|
941
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.",
|
|
@@ -943,10 +920,12 @@ function buildClassifierSystemPrompt() {
|
|
|
943
920
|
"Use high for research-heavy work, non-trivial drafting, or explicit requests to be thorough.",
|
|
944
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.",
|
|
945
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.",
|
|
946
925
|
"",
|
|
947
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.",
|
|
948
927
|
"",
|
|
949
|
-
"Return JSON only with reasoning_level, confidence, and reason.",
|
|
928
|
+
"Return JSON only with reasoning_level, profile, confidence, and reason.",
|
|
950
929
|
"confidence must be a number from 0 to 1, not a word label."
|
|
951
930
|
].join("\n");
|
|
952
931
|
}
|
|
@@ -975,13 +954,14 @@ function buildClassifierPrompt(args) {
|
|
|
975
954
|
}
|
|
976
955
|
return sections.join("\n");
|
|
977
956
|
}
|
|
978
|
-
function
|
|
957
|
+
function configuredTurnRoute(profile, reasoningLevel, source) {
|
|
979
958
|
return {
|
|
959
|
+
profile,
|
|
980
960
|
reasoningLevel,
|
|
981
961
|
reason: `configured:${source}`
|
|
982
962
|
};
|
|
983
963
|
}
|
|
984
|
-
async function
|
|
964
|
+
async function selectTurnRoute(args) {
|
|
985
965
|
const trimmedContext = trimContextForRouter(args.conversationContext);
|
|
986
966
|
const instructionLength = args.messageText.trim().length;
|
|
987
967
|
const turnBlockCount = (args.currentTurnBlocks ?? []).filter(
|
|
@@ -1000,8 +980,8 @@ async function selectTurnReasoningLevel(args) {
|
|
|
1000
980
|
modelId: args.fastModelId
|
|
1001
981
|
};
|
|
1002
982
|
return withSpan(
|
|
1003
|
-
"chat.
|
|
1004
|
-
"chat.
|
|
983
|
+
"chat.route_execution_profile",
|
|
984
|
+
"chat.route_execution_profile",
|
|
1005
985
|
logContext,
|
|
1006
986
|
async () => {
|
|
1007
987
|
setSpanAttributes({
|
|
@@ -1021,11 +1001,16 @@ async function selectTurnReasoningLevel(args) {
|
|
|
1021
1001
|
actorId: args.context?.actorId ?? "",
|
|
1022
1002
|
runId: args.context?.runId ?? ""
|
|
1023
1003
|
},
|
|
1004
|
+
profiles: args.profiles,
|
|
1024
1005
|
prompt
|
|
1025
1006
|
});
|
|
1026
|
-
const
|
|
1007
|
+
const flooredSelection = applyReasoningFloor(selection, {
|
|
1027
1008
|
minimum: trimmedContext || turnBlockCount > 0 ? "medium" : void 0
|
|
1028
1009
|
});
|
|
1010
|
+
const normalizedSelection = applyProfileReasoningOverride(
|
|
1011
|
+
flooredSelection,
|
|
1012
|
+
args.profiles
|
|
1013
|
+
);
|
|
1029
1014
|
setSpanAttributes({
|
|
1030
1015
|
"gen_ai.request.reasoning.level": normalizedSelection.reasoningLevel,
|
|
1031
1016
|
"gen_ai.request.reasoning.level_reason": normalizedSelection.reason,
|
|
@@ -1048,34 +1033,49 @@ function applyReasoningFloor(selection, args) {
|
|
|
1048
1033
|
reason: `reasoning_floor:${minimum}:${selection.reason}`
|
|
1049
1034
|
};
|
|
1050
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
|
+
}
|
|
1051
1047
|
async function classifyTurn(args) {
|
|
1052
1048
|
try {
|
|
1049
|
+
const schema = createTurnRouteSchema(args.profiles);
|
|
1053
1050
|
const result = await args.completeObject({
|
|
1054
1051
|
modelId: args.fastModelId,
|
|
1055
|
-
schema
|
|
1056
|
-
maxTokens:
|
|
1052
|
+
schema,
|
|
1053
|
+
maxTokens: 140,
|
|
1057
1054
|
metadata: args.metadata,
|
|
1058
1055
|
prompt: args.prompt,
|
|
1059
1056
|
thinkingLevel: "low",
|
|
1060
|
-
system: buildClassifierSystemPrompt(),
|
|
1057
|
+
system: buildClassifierSystemPrompt(Object.keys(args.profiles)),
|
|
1061
1058
|
temperature: 0
|
|
1062
1059
|
});
|
|
1063
|
-
const parsed =
|
|
1060
|
+
const parsed = schema.parse(result.object);
|
|
1064
1061
|
const reason = parsed.reason.trim();
|
|
1065
1062
|
if (parsed.confidence < CLASSIFIER_CONFIDENCE_THRESHOLD) {
|
|
1066
1063
|
return {
|
|
1067
1064
|
confidence: parsed.confidence,
|
|
1065
|
+
profile: STANDARD_MODEL_PROFILE,
|
|
1068
1066
|
reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
|
|
1069
1067
|
reason: `low_confidence_medium_default:${reason}`
|
|
1070
1068
|
};
|
|
1071
1069
|
}
|
|
1072
1070
|
return {
|
|
1073
1071
|
confidence: parsed.confidence,
|
|
1072
|
+
profile: parsed.profile,
|
|
1074
1073
|
reasoningLevel: parsed.reasoning_level,
|
|
1075
1074
|
reason
|
|
1076
1075
|
};
|
|
1077
1076
|
} catch {
|
|
1078
1077
|
return {
|
|
1078
|
+
profile: STANDARD_MODEL_PROFILE,
|
|
1079
1079
|
reasoningLevel: CLASSIFIER_FALLBACK_REASONING_LEVEL,
|
|
1080
1080
|
reason: "classifier_error_default"
|
|
1081
1081
|
};
|
|
@@ -1127,60 +1127,49 @@ var AuthorizationFlowDisabledError = class extends Error {
|
|
|
1127
1127
|
};
|
|
1128
1128
|
|
|
1129
1129
|
// src/chat/agent/request.ts
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1130
|
+
var RetryableDeliveryError = class extends Error {
|
|
1131
|
+
constructor(cause) {
|
|
1132
|
+
super("Assistant delivery was transient or ambiguous", { cause });
|
|
1133
|
+
this.name = "RetryableDeliveryError";
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
1136
|
function actorFromRouting(routing) {
|
|
1137
1137
|
if (routing.dispatch?.actor) {
|
|
1138
1138
|
return routing.dispatch.actor;
|
|
1139
1139
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
{
|
|
1143
|
-
platform: (isUserActor(routing.actor) ? routing.actor.platform : void 0) ?? (routing.destination.platform === "slack" ? "slack" : void 0),
|
|
1144
|
-
teamId: (routing.destination.platform === "slack" ? routing.destination.teamId : void 0) ?? routing.correlation?.teamId ?? (routing.actor?.platform === "slack" ? routing.actor.teamId : void 0),
|
|
1145
|
-
userId: routing.correlation?.actorId
|
|
1146
|
-
}
|
|
1147
|
-
);
|
|
1148
|
-
if (userActor) {
|
|
1149
|
-
return userActor;
|
|
1140
|
+
if (routing.actor) {
|
|
1141
|
+
return routing.actor;
|
|
1150
1142
|
}
|
|
1151
1143
|
if (routing.credentialContext && !("type" in routing.credentialContext.actor)) {
|
|
1152
1144
|
return routing.credentialContext.actor;
|
|
1153
1145
|
}
|
|
1154
1146
|
return void 0;
|
|
1155
1147
|
}
|
|
1156
|
-
function
|
|
1157
|
-
const { destination,
|
|
1158
|
-
if (
|
|
1159
|
-
|
|
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");
|
|
1160
1152
|
}
|
|
1161
|
-
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)) {
|
|
1162
1158
|
throw new TypeError(
|
|
1163
|
-
|
|
1159
|
+
"Local source, destination, and run conversation IDs do not match"
|
|
1164
1160
|
);
|
|
1165
1161
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
}
|
|
1169
|
-
}
|
|
1170
|
-
function assertCorrelationDestinationMatch(routing) {
|
|
1171
|
-
const { correlation, destination } = routing;
|
|
1172
|
-
if (destination.platform !== "slack") {
|
|
1162
|
+
const actor = request.routing.dispatch?.actor ?? request.routing.actor;
|
|
1163
|
+
if (!actor || actor.platform === "system") {
|
|
1173
1164
|
return;
|
|
1174
1165
|
}
|
|
1175
|
-
if (
|
|
1166
|
+
if (actor.platform !== destination.platform) {
|
|
1176
1167
|
throw new TypeError(
|
|
1177
|
-
|
|
1168
|
+
`Actor platform "${actor.platform}" does not match destination platform "${destination.platform}"`
|
|
1178
1169
|
);
|
|
1179
1170
|
}
|
|
1180
|
-
if (
|
|
1181
|
-
throw new TypeError(
|
|
1182
|
-
"Slack correlation team does not match destination team"
|
|
1183
|
-
);
|
|
1171
|
+
if (actor.platform === "slack" && destination.platform === "slack" && actor.teamId !== destination.teamId) {
|
|
1172
|
+
throw new TypeError("Slack actor team does not match destination team");
|
|
1184
1173
|
}
|
|
1185
1174
|
}
|
|
1186
1175
|
function toolInvocationDestination(routing) {
|
|
@@ -1197,30 +1186,20 @@ function surfaceFromRouting(routing) {
|
|
|
1197
1186
|
if (routing.surface) {
|
|
1198
1187
|
return routing.surface;
|
|
1199
1188
|
}
|
|
1200
|
-
|
|
1201
|
-
if (routing.slackConversation || (conversationId ? parseSlackThreadId(conversationId) : void 0)) {
|
|
1202
|
-
return "slack";
|
|
1203
|
-
}
|
|
1204
|
-
if (conversationId) {
|
|
1205
|
-
return "api";
|
|
1206
|
-
}
|
|
1207
|
-
return void 0;
|
|
1189
|
+
return routing.source.platform === "slack" ? "slack" : "internal";
|
|
1208
1190
|
}
|
|
1209
1191
|
|
|
1210
1192
|
// src/chat/agent/session.ts
|
|
1211
|
-
async function restoreSessionRecord(
|
|
1212
|
-
const { conversationId: sessionConversationId, sessionId } = getSessionIdentifiers(routing);
|
|
1193
|
+
async function restoreSessionRecord(args) {
|
|
1213
1194
|
const sessionRecordState = await loadTurnSessionRecord({
|
|
1214
|
-
conversationId:
|
|
1215
|
-
sessionId
|
|
1195
|
+
conversationId: args.conversationId,
|
|
1196
|
+
sessionId: args.turnId
|
|
1216
1197
|
});
|
|
1217
1198
|
const { resumedFromSessionRecord, currentSliceId, existingSessionRecord } = sessionRecordState;
|
|
1218
1199
|
return {
|
|
1219
1200
|
currentSliceId,
|
|
1220
1201
|
existingSessionRecord,
|
|
1221
1202
|
resumedFromSessionRecord,
|
|
1222
|
-
sessionConversationId,
|
|
1223
|
-
sessionId,
|
|
1224
1203
|
sessionRecordState
|
|
1225
1204
|
};
|
|
1226
1205
|
}
|
|
@@ -2078,7 +2057,6 @@ var LOCAL_HEADER = "You are a helper assistant. Follow the personality section f
|
|
|
2078
2057
|
var TURN_CONTEXT_HEADER = "Runtime context for this request. Treat these blocks as trusted runtime facts; the static system prompt remains authoritative.";
|
|
2079
2058
|
var TOOL_POLICY_RULES = [
|
|
2080
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.",
|
|
2081
|
-
"- 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.",
|
|
2082
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.",
|
|
2083
2061
|
"- Resolve provider action targets before calls: explicit target wins; ambient `<configuration>` fills omitted targets. Treat non-target links/references as context.",
|
|
2084
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.",
|
|
@@ -2114,11 +2092,8 @@ var CONVERSATION_RULES = [
|
|
|
2114
2092
|
];
|
|
2115
2093
|
var SLACK_ACTION_RULES = [
|
|
2116
2094
|
"- Slack tools target the current runtime context; if the requested Slack target differs, explain the limitation instead of calling the tool.",
|
|
2117
|
-
"- Use sendMessage only when the user asks to send, share, or attach text, sandbox-path files, or both in the active Slack conversation.",
|
|
2118
|
-
"- 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.",
|
|
2119
|
-
"- sendMessage is not final-reply delivery. After using sendMessage, provide a brief normal final answer unless the user requested no further text.",
|
|
2120
2095
|
"- Ambient reaction requests target the current inbound message; do not ask for a message reference.",
|
|
2121
|
-
`- 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}.`
|
|
2122
2097
|
];
|
|
2123
2098
|
var SAFETY_RULES = [
|
|
2124
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.",
|
|
@@ -4756,8 +4731,26 @@ function createGrepTool() {
|
|
|
4756
4731
|
|
|
4757
4732
|
// src/chat/tools/sandbox/file-uploads.ts
|
|
4758
4733
|
import path6 from "path";
|
|
4734
|
+
import { z as z8 } from "zod";
|
|
4759
4735
|
var MAX_SANDBOX_FILE_UPLOAD_BYTES = 10 * 1024 * 1024;
|
|
4760
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();
|
|
4761
4754
|
var MIME_BY_EXTENSION = {
|
|
4762
4755
|
".png": "image/png",
|
|
4763
4756
|
".jpg": "image/jpeg",
|
|
@@ -4772,7 +4765,7 @@ var MIME_BY_EXTENSION = {
|
|
|
4772
4765
|
".csv": "text/csv",
|
|
4773
4766
|
".log": "text/plain"
|
|
4774
4767
|
};
|
|
4775
|
-
var SandboxFileNotFoundError = class extends
|
|
4768
|
+
var SandboxFileNotFoundError = class extends ToolInputError {
|
|
4776
4769
|
constructor(path9) {
|
|
4777
4770
|
super(`failed to read file: ${path9}`);
|
|
4778
4771
|
this.path = path9;
|
|
@@ -4839,10 +4832,10 @@ async function readSandboxFileUpload(sandbox, input) {
|
|
|
4839
4832
|
throw new SandboxFileNotFoundError(targetPath);
|
|
4840
4833
|
}
|
|
4841
4834
|
if (fileBuffer.byteLength === 0) {
|
|
4842
|
-
throw new
|
|
4835
|
+
throw new ToolInputError(`file is empty: ${targetPath}`);
|
|
4843
4836
|
}
|
|
4844
4837
|
if (fileBuffer.byteLength > MAX_SANDBOX_FILE_UPLOAD_BYTES) {
|
|
4845
|
-
throw new
|
|
4838
|
+
throw new ToolInputError(
|
|
4846
4839
|
`file exceeds ${MAX_SANDBOX_FILE_UPLOAD_BYTES} bytes: ${targetPath} (${fileBuffer.byteLength} bytes)`
|
|
4847
4840
|
);
|
|
4848
4841
|
}
|
|
@@ -4863,7 +4856,7 @@ async function readSandboxFileUpload(sandbox, input) {
|
|
|
4863
4856
|
|
|
4864
4857
|
// src/chat/tools/sandbox/list-dir.ts
|
|
4865
4858
|
import path7 from "path";
|
|
4866
|
-
import { z as
|
|
4859
|
+
import { z as z9 } from "zod";
|
|
4867
4860
|
var DEFAULT_LIST_LIMIT = 500;
|
|
4868
4861
|
async function listDir(params) {
|
|
4869
4862
|
const dirPath = resolveWorkspacePath(params.path);
|
|
@@ -4944,11 +4937,11 @@ function createListDirTool() {
|
|
|
4944
4937
|
return zodTool({
|
|
4945
4938
|
description: "List a sandbox workspace directory. Returns sorted entries with '/' suffixes for directories and bounded truncation notices.",
|
|
4946
4939
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
4947
|
-
inputSchema:
|
|
4948
|
-
path:
|
|
4940
|
+
inputSchema: z9.object({
|
|
4941
|
+
path: z9.string().min(1).describe(
|
|
4949
4942
|
"Directory path in the sandbox workspace. Defaults to the workspace root."
|
|
4950
4943
|
).optional(),
|
|
4951
|
-
limit:
|
|
4944
|
+
limit: z9.coerce.number().int().min(1).describe("Maximum entries to return. Defaults to 500.").optional()
|
|
4952
4945
|
}),
|
|
4953
4946
|
outputSchema: juniorToolResultSchema,
|
|
4954
4947
|
execute: async () => {
|
|
@@ -4960,23 +4953,15 @@ function createListDirTool() {
|
|
|
4960
4953
|
}
|
|
4961
4954
|
|
|
4962
4955
|
// src/chat/tools/web/image-generate.ts
|
|
4963
|
-
import { z as
|
|
4956
|
+
import { z as z10 } from "zod";
|
|
4964
4957
|
var DEFAULT_IMAGE_MODEL = "google/gemini-3-pro-image";
|
|
4965
4958
|
var imageGenerateOutputSchema = juniorToolResultSchema.extend({
|
|
4966
|
-
model:
|
|
4967
|
-
prompt:
|
|
4968
|
-
enrichedPrompt:
|
|
4969
|
-
image_count:
|
|
4970
|
-
images:
|
|
4971
|
-
|
|
4972
|
-
filename: z9.string(),
|
|
4973
|
-
path: z9.string(),
|
|
4974
|
-
attachment_path: z9.string(),
|
|
4975
|
-
media_type: z9.string().optional(),
|
|
4976
|
-
bytes: z9.number().int().nonnegative()
|
|
4977
|
-
}).strict()
|
|
4978
|
-
),
|
|
4979
|
-
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()
|
|
4980
4965
|
}).strict();
|
|
4981
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.
|
|
4982
4967
|
|
|
@@ -5037,8 +5022,8 @@ function parseImageGenerationError(status, body, model) {
|
|
|
5037
5022
|
function createImageGenerateTool(hooks, options = {}, deps = {}) {
|
|
5038
5023
|
return zodTool({
|
|
5039
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.",
|
|
5040
|
-
inputSchema:
|
|
5041
|
-
prompt:
|
|
5025
|
+
inputSchema: z10.object({
|
|
5026
|
+
prompt: z10.string().min(1).max(4e3).describe("Image generation prompt.")
|
|
5042
5027
|
}),
|
|
5043
5028
|
outputSchema: imageGenerateOutputSchema,
|
|
5044
5029
|
execute: async ({ prompt }) => {
|
|
@@ -5105,14 +5090,8 @@ function createImageGenerateTool(hooks, options = {}, deps = {}) {
|
|
|
5105
5090
|
prompt,
|
|
5106
5091
|
enrichedPrompt,
|
|
5107
5092
|
image_count: artifactRefs.length,
|
|
5108
|
-
images: artifactRefs
|
|
5109
|
-
|
|
5110
|
-
path: artifact.path,
|
|
5111
|
-
attachment_path: artifact.path,
|
|
5112
|
-
media_type: artifact.mimeType,
|
|
5113
|
-
bytes: artifact.bytes
|
|
5114
|
-
})),
|
|
5115
|
-
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."
|
|
5116
5095
|
};
|
|
5117
5096
|
}
|
|
5118
5097
|
return {
|
|
@@ -5130,7 +5109,7 @@ function createImageGenerateTool(hooks, options = {}, deps = {}) {
|
|
|
5130
5109
|
}
|
|
5131
5110
|
|
|
5132
5111
|
// src/chat/tools/skill/call-mcp-tool.ts
|
|
5133
|
-
import { z as
|
|
5112
|
+
import { z as z11 } from "zod";
|
|
5134
5113
|
function resolveMcpArguments(input) {
|
|
5135
5114
|
const extraKeys = Object.keys(input).filter(
|
|
5136
5115
|
(key) => key !== "tool_name" && key !== "arguments"
|
|
@@ -5166,9 +5145,9 @@ function missingToolMessage(toolName, provider) {
|
|
|
5166
5145
|
function createCallMcpToolTool(mcpToolManager) {
|
|
5167
5146
|
return zodTool({
|
|
5168
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.",
|
|
5169
|
-
inputSchema:
|
|
5170
|
-
tool_name:
|
|
5171
|
-
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(
|
|
5172
5151
|
'Arguments matching the disclosed MCP tool schema, for example { "query": "..." } when searchMcpTools shows query is required.'
|
|
5173
5152
|
).optional()
|
|
5174
5153
|
}).passthrough(),
|
|
@@ -5209,7 +5188,7 @@ function createCallMcpToolTool(mcpToolManager) {
|
|
|
5209
5188
|
}
|
|
5210
5189
|
|
|
5211
5190
|
// src/chat/tools/skill/load-skill.ts
|
|
5212
|
-
import { z as
|
|
5191
|
+
import { z as z12 } from "zod";
|
|
5213
5192
|
function toLoadedSkill(result, availableSkills) {
|
|
5214
5193
|
if (result.ok !== true || typeof result.skill_name !== "string" || typeof result.description !== "string" || typeof result.skill_dir !== "string" || typeof result.instructions !== "string") {
|
|
5215
5194
|
return null;
|
|
@@ -5258,8 +5237,8 @@ async function loadSkillFromHost(availableSkills, skillName) {
|
|
|
5258
5237
|
function createLoadSkillTool(availableSkills, options) {
|
|
5259
5238
|
return zodTool({
|
|
5260
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.",
|
|
5261
|
-
inputSchema:
|
|
5262
|
-
skill_name:
|
|
5240
|
+
inputSchema: z12.object({
|
|
5241
|
+
skill_name: z12.string().min(1).describe("Skill name to load, without the leading slash.")
|
|
5263
5242
|
}),
|
|
5264
5243
|
outputSchema: juniorToolResultSchema,
|
|
5265
5244
|
execute: async ({ skill_name }) => {
|
|
@@ -5277,7 +5256,7 @@ function createLoadSkillTool(availableSkills, options) {
|
|
|
5277
5256
|
}
|
|
5278
5257
|
|
|
5279
5258
|
// src/chat/tools/skill/search-mcp-tools.ts
|
|
5280
|
-
import { z as
|
|
5259
|
+
import { z as z13 } from "zod";
|
|
5281
5260
|
|
|
5282
5261
|
// src/chat/tool-support/schema-summary.ts
|
|
5283
5262
|
function getSchemaProperties(schema) {
|
|
@@ -5407,37 +5386,37 @@ function toActiveMcpCatalogSummaries(toolDefs) {
|
|
|
5407
5386
|
// src/chat/tools/skill/search-mcp-tools.ts
|
|
5408
5387
|
var DEFAULT_MAX_RESULTS = 5;
|
|
5409
5388
|
var MAX_RESULTS = 20;
|
|
5410
|
-
var providerSummarySchema =
|
|
5411
|
-
provider:
|
|
5412
|
-
description:
|
|
5413
|
-
active:
|
|
5389
|
+
var providerSummarySchema = z13.object({
|
|
5390
|
+
provider: z13.string(),
|
|
5391
|
+
description: z13.string(),
|
|
5392
|
+
active: z13.boolean()
|
|
5414
5393
|
}).strict();
|
|
5415
|
-
var mcpCallExampleSchema =
|
|
5416
|
-
tool_name:
|
|
5417
|
-
arguments:
|
|
5394
|
+
var mcpCallExampleSchema = z13.object({
|
|
5395
|
+
tool_name: z13.string(),
|
|
5396
|
+
arguments: z13.record(z13.string(), z13.string())
|
|
5418
5397
|
}).strict();
|
|
5419
|
-
var exposedToolSummarySchema =
|
|
5420
|
-
tool_name:
|
|
5421
|
-
mcp_tool_name:
|
|
5422
|
-
provider:
|
|
5423
|
-
title:
|
|
5424
|
-
description:
|
|
5425
|
-
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(),
|
|
5426
5405
|
call: mcpCallExampleSchema,
|
|
5427
|
-
input_schema:
|
|
5428
|
-
input_schema_summary:
|
|
5429
|
-
output_schema:
|
|
5430
|
-
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()
|
|
5431
5410
|
}).strict();
|
|
5432
5411
|
var searchMcpToolsOutputSchema = juniorToolResultSchema.extend({
|
|
5433
|
-
query:
|
|
5434
|
-
provider:
|
|
5435
|
-
total_active_tools:
|
|
5436
|
-
returned_tools:
|
|
5437
|
-
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"),
|
|
5438
5417
|
execution_example: mcpCallExampleSchema,
|
|
5439
|
-
available_providers:
|
|
5440
|
-
tools:
|
|
5418
|
+
available_providers: z13.array(providerSummarySchema),
|
|
5419
|
+
tools: z13.array(exposedToolSummarySchema)
|
|
5441
5420
|
}).strict();
|
|
5442
5421
|
function normalize(value) {
|
|
5443
5422
|
return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
|
|
@@ -5557,14 +5536,14 @@ function searchProviderCatalog(providers, query) {
|
|
|
5557
5536
|
function createSearchMcpToolsTool(mcpToolManager) {
|
|
5558
5537
|
return zodTool({
|
|
5559
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.",
|
|
5560
|
-
inputSchema:
|
|
5561
|
-
query:
|
|
5539
|
+
inputSchema: z13.object({
|
|
5540
|
+
query: z13.string().min(1).describe(
|
|
5562
5541
|
"Optional search terms describing the MCP tool or arguments needed."
|
|
5563
5542
|
).optional(),
|
|
5564
|
-
provider:
|
|
5543
|
+
provider: z13.string().min(1).describe(
|
|
5565
5544
|
"Optional provider name to list or search within. If configured but not yet connected, Junior activates it on demand."
|
|
5566
5545
|
).optional(),
|
|
5567
|
-
max_results:
|
|
5546
|
+
max_results: z13.number().int().min(1).max(MAX_RESULTS).describe("Maximum matching tool descriptors to return.").optional()
|
|
5568
5547
|
}).strict(),
|
|
5569
5548
|
outputSchema: searchMcpToolsOutputSchema,
|
|
5570
5549
|
privateTraceResult: (result) => ({
|
|
@@ -5619,7 +5598,7 @@ function createSearchMcpToolsTool(mcpToolManager) {
|
|
|
5619
5598
|
}
|
|
5620
5599
|
|
|
5621
5600
|
// src/chat/tools/sandbox/read-file.ts
|
|
5622
|
-
import { z as
|
|
5601
|
+
import { z as z14 } from "zod";
|
|
5623
5602
|
|
|
5624
5603
|
// src/chat/tool-support/text-range-result.ts
|
|
5625
5604
|
var DEFAULT_READ_LIMIT = 1e3;
|
|
@@ -5694,10 +5673,10 @@ function createReadFileTool() {
|
|
|
5694
5673
|
return zodTool({
|
|
5695
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.",
|
|
5696
5675
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
5697
|
-
inputSchema:
|
|
5698
|
-
path:
|
|
5699
|
-
offset:
|
|
5700
|
-
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()
|
|
5701
5680
|
}),
|
|
5702
5681
|
outputSchema: juniorToolResultSchema,
|
|
5703
5682
|
execute: async () => {
|
|
@@ -5709,12 +5688,12 @@ function createReadFileTool() {
|
|
|
5709
5688
|
}
|
|
5710
5689
|
|
|
5711
5690
|
// src/chat/tools/runtime/report-progress.ts
|
|
5712
|
-
import { z as
|
|
5691
|
+
import { z as z15 } from "zod";
|
|
5713
5692
|
function createReportProgressTool() {
|
|
5714
5693
|
return zodTool({
|
|
5715
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.",
|
|
5716
|
-
inputSchema:
|
|
5717
|
-
message:
|
|
5695
|
+
inputSchema: z15.object({
|
|
5696
|
+
message: z15.string().min(1).describe("Short user-facing progress message.")
|
|
5718
5697
|
}),
|
|
5719
5698
|
outputSchema: juniorToolResultSchema,
|
|
5720
5699
|
execute: async () => ({
|
|
@@ -5725,34 +5704,34 @@ function createReportProgressTool() {
|
|
|
5725
5704
|
}
|
|
5726
5705
|
|
|
5727
5706
|
// src/chat/tools/resource-events.ts
|
|
5728
|
-
import { z as
|
|
5707
|
+
import { z as z17 } from "zod";
|
|
5729
5708
|
|
|
5730
5709
|
// src/chat/resource-events/store.ts
|
|
5731
5710
|
import { createHash } from "crypto";
|
|
5732
5711
|
import { destinationSchema } from "@sentry/junior-plugin-api";
|
|
5733
|
-
import { z as
|
|
5712
|
+
import { z as z16 } from "zod";
|
|
5734
5713
|
var RESOURCE_EVENT_PREFIX = "junior:resource_event_subscription";
|
|
5735
5714
|
var INDEX_LOCK_TTL_MS = 1e4;
|
|
5736
5715
|
var SUBSCRIPTION_LOCK_TTL_MS = 1e4;
|
|
5737
5716
|
var SUBSCRIPTION_LOCK_WAIT_MS = 1e4;
|
|
5738
5717
|
var SUBSCRIPTION_LOCK_RETRY_MS = 25;
|
|
5739
5718
|
var SUBSCRIPTION_LOCK_HEARTBEAT_MS = 3e3;
|
|
5740
|
-
var subscriptionStatusSchema =
|
|
5741
|
-
var subscriptionIdIndexSchema =
|
|
5742
|
-
var subscriptionSchema =
|
|
5743
|
-
conversationId:
|
|
5744
|
-
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(),
|
|
5745
5724
|
destination: destinationSchema,
|
|
5746
|
-
events:
|
|
5747
|
-
expiresAtMs:
|
|
5748
|
-
id:
|
|
5749
|
-
intent:
|
|
5750
|
-
label:
|
|
5751
|
-
provider:
|
|
5752
|
-
resourceRef:
|
|
5753
|
-
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),
|
|
5754
5733
|
status: subscriptionStatusSchema,
|
|
5755
|
-
updatedAtMs:
|
|
5734
|
+
updatedAtMs: z16.number().finite()
|
|
5756
5735
|
}).strict();
|
|
5757
5736
|
function digest(value) {
|
|
5758
5737
|
return createHash("sha256").update(value).digest("hex").slice(0, 32);
|
|
@@ -6092,23 +6071,23 @@ async function deliverResourceEventSubscription(input) {
|
|
|
6092
6071
|
// src/chat/tools/resource-events.ts
|
|
6093
6072
|
var DEFAULT_TTL_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
6094
6073
|
var MAX_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
6095
|
-
var subscribeInputSchema =
|
|
6096
|
-
resourceRef:
|
|
6097
|
-
provider:
|
|
6098
|
-
resourceType:
|
|
6099
|
-
label:
|
|
6100
|
-
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(
|
|
6101
6080
|
"High-signal event names to deliver to this conversation when they occur."
|
|
6102
6081
|
),
|
|
6103
|
-
intent:
|
|
6082
|
+
intent: z17.string().describe(
|
|
6104
6083
|
"Concise reason this conversation wants these events, used when an event arrives."
|
|
6105
6084
|
),
|
|
6106
|
-
ttlMs:
|
|
6085
|
+
ttlMs: z17.coerce.number().describe(
|
|
6107
6086
|
"How long to keep the subscription active. Defaults to 14 days and is capped at 30 days."
|
|
6108
6087
|
).optional()
|
|
6109
6088
|
});
|
|
6110
|
-
var cancelInputSchema =
|
|
6111
|
-
subscriptionId:
|
|
6089
|
+
var cancelInputSchema = z17.object({
|
|
6090
|
+
subscriptionId: z17.string().describe(
|
|
6112
6091
|
"Subscription id returned by subscribeToResourceEvents or listResourceEventSubscriptions."
|
|
6113
6092
|
)
|
|
6114
6093
|
});
|
|
@@ -6192,7 +6171,7 @@ function createSubscribeToResourceEventsTool(context) {
|
|
|
6192
6171
|
function createListResourceEventSubscriptionsTool(context) {
|
|
6193
6172
|
return zodTool({
|
|
6194
6173
|
description: "List active resource event subscriptions for the current conversation.",
|
|
6195
|
-
inputSchema:
|
|
6174
|
+
inputSchema: z17.object({}),
|
|
6196
6175
|
outputSchema: juniorToolResultSchema,
|
|
6197
6176
|
async execute() {
|
|
6198
6177
|
const conversationId = requireConversationContext(context);
|
|
@@ -6327,11 +6306,11 @@ async function listThreadReplies(input) {
|
|
|
6327
6306
|
}
|
|
6328
6307
|
|
|
6329
6308
|
// src/chat/slack/timestamp-param.ts
|
|
6330
|
-
import { z as
|
|
6309
|
+
import { z as z18 } from "zod";
|
|
6331
6310
|
function slackTimestampParam(description) {
|
|
6332
|
-
return
|
|
6311
|
+
return z18.preprocess(
|
|
6333
6312
|
(value) => typeof value === "number" && Number.isFinite(value) ? String(value) : value,
|
|
6334
|
-
|
|
6313
|
+
z18.string().min(1)
|
|
6335
6314
|
).describe(description);
|
|
6336
6315
|
}
|
|
6337
6316
|
function optionalSlackTimestampParam(description) {
|
|
@@ -6362,10 +6341,10 @@ function parseRequiredSlackTimestampParam(field, value) {
|
|
|
6362
6341
|
}
|
|
6363
6342
|
|
|
6364
6343
|
// src/chat/slack/tools/channel-list-messages.ts
|
|
6365
|
-
import { z as
|
|
6366
|
-
var booleanInput2 = (description) =>
|
|
6344
|
+
import { z as z19 } from "zod";
|
|
6345
|
+
var booleanInput2 = (description) => z19.preprocess(
|
|
6367
6346
|
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
6368
|
-
|
|
6347
|
+
z19.boolean()
|
|
6369
6348
|
).describe(description);
|
|
6370
6349
|
function normalizeRangeTimestamp(field, value, targetChannelId) {
|
|
6371
6350
|
if (value === void 0) {
|
|
@@ -6392,9 +6371,9 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
6392
6371
|
return zodTool({
|
|
6393
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.",
|
|
6394
6373
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
6395
|
-
inputSchema:
|
|
6396
|
-
limit:
|
|
6397
|
-
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(),
|
|
6398
6377
|
oldest: optionalSlackTimestampParam(
|
|
6399
6378
|
"Optional oldest message timestamp (Slack ts) for range filtering."
|
|
6400
6379
|
),
|
|
@@ -6404,7 +6383,7 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
6404
6383
|
inclusive: booleanInput2(
|
|
6405
6384
|
"Whether oldest/latest bounds should be inclusive."
|
|
6406
6385
|
).optional(),
|
|
6407
|
-
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()
|
|
6408
6387
|
}),
|
|
6409
6388
|
outputSchema: juniorToolResultSchema,
|
|
6410
6389
|
execute: async ({
|
|
@@ -6478,7 +6457,7 @@ function createSlackChannelListMessagesTool(context) {
|
|
|
6478
6457
|
}
|
|
6479
6458
|
|
|
6480
6459
|
// src/chat/slack/tools/conversation-search.ts
|
|
6481
|
-
import { z as
|
|
6460
|
+
import { z as z20 } from "zod";
|
|
6482
6461
|
|
|
6483
6462
|
// src/chat/slack/outbound.ts
|
|
6484
6463
|
var MAX_SLACK_MESSAGE_TEXT_CHARS = 4e4;
|
|
@@ -6637,12 +6616,10 @@ async function uploadFilesToConversation(input) {
|
|
|
6637
6616
|
filename
|
|
6638
6617
|
};
|
|
6639
6618
|
});
|
|
6640
|
-
const initialComment = input.initialComment?.trim();
|
|
6641
6619
|
const response = await withSlackRetries(
|
|
6642
6620
|
() => getSlackClient().filesUploadV2({
|
|
6643
6621
|
channel_id: channelId,
|
|
6644
6622
|
...threadTs ? { thread_ts: threadTs } : {},
|
|
6645
|
-
...initialComment ? { initial_comment: initialComment } : {},
|
|
6646
6623
|
file_uploads: fileUploads
|
|
6647
6624
|
}),
|
|
6648
6625
|
3,
|
|
@@ -6742,17 +6719,17 @@ async function removeReactionFromMessage(input) {
|
|
|
6742
6719
|
// src/chat/slack/tools/conversation-search.ts
|
|
6743
6720
|
var DEFAULT_LIMIT = 5;
|
|
6744
6721
|
var conversationSearchOutputSchema = juniorToolResultSchema.extend({
|
|
6745
|
-
query:
|
|
6746
|
-
count:
|
|
6747
|
-
threads:
|
|
6748
|
-
|
|
6749
|
-
conversation_id:
|
|
6750
|
-
thread_ts:
|
|
6751
|
-
message_id:
|
|
6752
|
-
message_role:
|
|
6753
|
-
message_timestamp:
|
|
6754
|
-
excerpt:
|
|
6755
|
-
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()
|
|
6756
6733
|
}).strict()
|
|
6757
6734
|
)
|
|
6758
6735
|
});
|
|
@@ -6765,9 +6742,9 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
|
|
|
6765
6742
|
description: "Search retained public Junior conversation threads in the current Slack workspace."
|
|
6766
6743
|
},
|
|
6767
6744
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
6768
|
-
inputSchema:
|
|
6769
|
-
query:
|
|
6770
|
-
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()
|
|
6771
6748
|
}),
|
|
6772
6749
|
outputSchema: conversationSearchOutputSchema,
|
|
6773
6750
|
execute: async ({ query, limit }) => {
|
|
@@ -6814,27 +6791,27 @@ function createSlackConversationSearchTool(scope, currentConversationId, deps =
|
|
|
6814
6791
|
}
|
|
6815
6792
|
|
|
6816
6793
|
// src/chat/slack/tools/public-search.ts
|
|
6817
|
-
import { z as
|
|
6794
|
+
import { z as z21 } from "zod";
|
|
6818
6795
|
var DEFAULT_LIMIT2 = 10;
|
|
6819
|
-
var optionalTimestampSchema =
|
|
6796
|
+
var optionalTimestampSchema = z21.preprocess(
|
|
6820
6797
|
(value) => typeof value === "string" && value.trim() === "" ? void 0 : value,
|
|
6821
|
-
|
|
6798
|
+
z21.coerce.number().int().nonnegative().describe("Optional Unix timestamp bound.").optional()
|
|
6822
6799
|
);
|
|
6823
|
-
var searchMessageSchema =
|
|
6824
|
-
author_name:
|
|
6825
|
-
author_user_id:
|
|
6826
|
-
channel_id:
|
|
6827
|
-
channel_name:
|
|
6828
|
-
message_ts:
|
|
6829
|
-
content:
|
|
6830
|
-
is_author_bot:
|
|
6831
|
-
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()
|
|
6832
6809
|
});
|
|
6833
6810
|
var publicSearchOutputSchema = juniorToolResultSchema.extend({
|
|
6834
|
-
query:
|
|
6835
|
-
count:
|
|
6836
|
-
messages:
|
|
6837
|
-
next_cursor:
|
|
6811
|
+
query: z21.string(),
|
|
6812
|
+
count: z21.number().int().nonnegative(),
|
|
6813
|
+
messages: z21.array(searchMessageSchema),
|
|
6814
|
+
next_cursor: z21.string().optional()
|
|
6838
6815
|
});
|
|
6839
6816
|
function normalizeMessage(value) {
|
|
6840
6817
|
const parsed = searchMessageSchema.safeParse(value);
|
|
@@ -6856,8 +6833,8 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
6856
6833
|
return zodTool({
|
|
6857
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.",
|
|
6858
6835
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
6859
|
-
inputSchema:
|
|
6860
|
-
query:
|
|
6836
|
+
inputSchema: z21.object({
|
|
6837
|
+
query: z21.string().trim().min(1).max(500).describe(
|
|
6861
6838
|
"A focused Slack search query, including Slack search filters when useful."
|
|
6862
6839
|
),
|
|
6863
6840
|
after: optionalTimestampSchema.describe(
|
|
@@ -6866,10 +6843,10 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
6866
6843
|
before: optionalTimestampSchema.describe(
|
|
6867
6844
|
"Optional Unix timestamp upper bound."
|
|
6868
6845
|
),
|
|
6869
|
-
cursor:
|
|
6870
|
-
limit:
|
|
6871
|
-
sort:
|
|
6872
|
-
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()
|
|
6873
6850
|
}),
|
|
6874
6851
|
outputSchema: publicSearchOutputSchema,
|
|
6875
6852
|
execute: async ({
|
|
@@ -6935,7 +6912,7 @@ function createSlackPublicSearchTool(actionToken) {
|
|
|
6935
6912
|
}
|
|
6936
6913
|
|
|
6937
6914
|
// src/chat/slack/tools/message-add-reaction.ts
|
|
6938
|
-
import { z as
|
|
6915
|
+
import { z as z22 } from "zod";
|
|
6939
6916
|
|
|
6940
6917
|
// src/chat/tools/idempotency.ts
|
|
6941
6918
|
function stableSerialize(value) {
|
|
@@ -6959,8 +6936,8 @@ function createOperationKey(toolName, input) {
|
|
|
6959
6936
|
function createSlackMessageAddReactionTool(context, state) {
|
|
6960
6937
|
return zodTool({
|
|
6961
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.",
|
|
6962
|
-
inputSchema:
|
|
6963
|
-
emoji:
|
|
6939
|
+
inputSchema: z22.object({
|
|
6940
|
+
emoji: z22.string().min(1).max(64).describe(
|
|
6964
6941
|
"Slack emoji alias name to react with (for example `thumbsup`, `white_check_mark`, or `thumbsup::skin-tone-6`). Optional surrounding colons are allowed."
|
|
6965
6942
|
)
|
|
6966
6943
|
}),
|
|
@@ -7009,23 +6986,24 @@ function createSlackMessageAddReactionTool(context, state) {
|
|
|
7009
6986
|
});
|
|
7010
6987
|
}
|
|
7011
6988
|
|
|
7012
|
-
// src/chat/slack/tools/send-
|
|
6989
|
+
// src/chat/slack/tools/send-files.ts
|
|
7013
6990
|
import { createHash as createHash2 } from "crypto";
|
|
7014
|
-
import { z as
|
|
7015
|
-
var
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
),
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
),
|
|
7022
|
-
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)
|
|
7023
6998
|
});
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
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) => ({
|
|
7029
7007
|
path: file.path,
|
|
7030
7008
|
...file.filename ? { filename: file.filename } : {},
|
|
7031
7009
|
...file.mimeType ? { mimeType: file.mimeType } : {}
|
|
@@ -7043,18 +7021,17 @@ function fileOperationInput(files) {
|
|
|
7043
7021
|
sha256: fileContentDigest(file.data)
|
|
7044
7022
|
}));
|
|
7045
7023
|
}
|
|
7046
|
-
function
|
|
7024
|
+
function createSendFilesTool(context, state, materializeFile) {
|
|
7047
7025
|
return zodTool({
|
|
7048
|
-
description: "Send
|
|
7049
|
-
inputSchema:
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
"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."
|
|
7053
7030
|
)
|
|
7054
7031
|
}),
|
|
7055
|
-
outputSchema:
|
|
7056
|
-
execute: async ({
|
|
7057
|
-
const filesToSend =
|
|
7032
|
+
outputSchema: sendFilesResultSchema,
|
|
7033
|
+
execute: async ({ files }) => {
|
|
7034
|
+
const filesToSend = normalizeFiles(files);
|
|
7058
7035
|
const activeChannelId = context.sourceChannelId;
|
|
7059
7036
|
if (!activeChannelId) {
|
|
7060
7037
|
throw new ToolInputError("No active Slack conversation is available.");
|
|
@@ -7065,48 +7042,34 @@ function createSendMessageTool(context, state, materializeFile) {
|
|
|
7065
7042
|
"No active Slack conversation timestamp is available."
|
|
7066
7043
|
);
|
|
7067
7044
|
}
|
|
7068
|
-
const textToSend = hasText(text) ? text : void 0;
|
|
7069
|
-
if (!textToSend && filesToSend.length === 0) {
|
|
7070
|
-
throw new ToolInputError(
|
|
7071
|
-
"sendMessage requires text or at least one file."
|
|
7072
|
-
);
|
|
7073
|
-
}
|
|
7074
7045
|
const materializedFiles = await Promise.all(
|
|
7075
7046
|
filesToSend.map((file) => materializeFile(file))
|
|
7076
7047
|
);
|
|
7077
|
-
const operationKey = createOperationKey("
|
|
7048
|
+
const operationKey = createOperationKey("sendFiles", {
|
|
7078
7049
|
channel_id: activeChannelId,
|
|
7079
7050
|
thread_ts: threadTs,
|
|
7080
|
-
|
|
7081
|
-
...materializedFiles.length > 0 ? { files: fileOperationInput(materializedFiles) } : {}
|
|
7051
|
+
files: fileOperationInput(materializedFiles)
|
|
7082
7052
|
});
|
|
7083
7053
|
const cached = state.getOperationResult(operationKey);
|
|
7084
7054
|
if (cached) {
|
|
7085
|
-
return {
|
|
7055
|
+
return sendFilesResultSchema.parse({
|
|
7086
7056
|
...cached,
|
|
7087
7057
|
data: {
|
|
7088
7058
|
...cached.data,
|
|
7089
7059
|
deduplicated: true
|
|
7090
|
-
}
|
|
7091
|
-
|
|
7092
|
-
};
|
|
7060
|
+
}
|
|
7061
|
+
});
|
|
7093
7062
|
}
|
|
7094
7063
|
const uploads = materializedFiles.map((file) => ({
|
|
7095
7064
|
data: file.data,
|
|
7096
7065
|
filename: file.filename
|
|
7097
7066
|
}));
|
|
7098
|
-
const
|
|
7099
|
-
channelId: activeChannelId,
|
|
7100
|
-
text: textToSend,
|
|
7101
|
-
threadTs,
|
|
7102
|
-
includePermalink: true
|
|
7103
|
-
}) : void 0;
|
|
7104
|
-
const uploaded = uploads.length > 0 ? await uploadFilesToConversation({
|
|
7067
|
+
const uploaded = await uploadFilesToConversation({
|
|
7105
7068
|
channelId: activeChannelId,
|
|
7106
7069
|
files: uploads,
|
|
7107
|
-
threadTs
|
|
7108
|
-
|
|
7109
|
-
|
|
7070
|
+
threadTs
|
|
7071
|
+
});
|
|
7072
|
+
const fileIds = uploaded?.files?.map((file) => file.id).filter((id) => Boolean(id));
|
|
7110
7073
|
const response = {
|
|
7111
7074
|
ok: true,
|
|
7112
7075
|
status: "success",
|
|
@@ -7114,19 +7077,9 @@ function createSendMessageTool(context, state, materializeFile) {
|
|
|
7114
7077
|
data: {
|
|
7115
7078
|
channel_id: activeChannelId,
|
|
7116
7079
|
thread_ts: threadTs,
|
|
7117
|
-
|
|
7118
|
-
...
|
|
7119
|
-
|
|
7120
|
-
file_ids: uploaded.files.map((file) => file.id).filter((id) => Boolean(id))
|
|
7121
|
-
} : {}
|
|
7122
|
-
},
|
|
7123
|
-
channel_id: activeChannelId,
|
|
7124
|
-
thread_ts: threadTs,
|
|
7125
|
-
...posted ? { ts: posted.ts, permalink: posted.permalink } : {},
|
|
7126
|
-
...uploads.length > 0 ? { file_count: uploads.length } : {},
|
|
7127
|
-
...uploaded?.files ? {
|
|
7128
|
-
file_ids: uploaded.files.map((file) => file.id).filter((id) => Boolean(id))
|
|
7129
|
-
} : {}
|
|
7080
|
+
file_count: uploads.length,
|
|
7081
|
+
...fileIds ? { file_ids: fileIds } : {}
|
|
7082
|
+
}
|
|
7130
7083
|
};
|
|
7131
7084
|
state.setOperationResult(operationKey, response);
|
|
7132
7085
|
return response;
|
|
@@ -7376,13 +7329,13 @@ function storedCanvasUrl(state, canvasId) {
|
|
|
7376
7329
|
}
|
|
7377
7330
|
|
|
7378
7331
|
// src/chat/slack/tools/canvas/create.ts
|
|
7379
|
-
import { z as
|
|
7332
|
+
import { z as z24 } from "zod";
|
|
7380
7333
|
function createSlackCanvasCreateTool(context, state) {
|
|
7381
7334
|
return zodTool({
|
|
7382
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.",
|
|
7383
|
-
inputSchema:
|
|
7384
|
-
title:
|
|
7385
|
-
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.")
|
|
7386
7339
|
}),
|
|
7387
7340
|
outputSchema: juniorToolResultSchema,
|
|
7388
7341
|
execute: async ({ title, markdown }) => {
|
|
@@ -7445,35 +7398,35 @@ function createSlackCanvasCreateTool(context, state) {
|
|
|
7445
7398
|
}
|
|
7446
7399
|
|
|
7447
7400
|
// src/chat/slack/tools/canvas/edit.ts
|
|
7448
|
-
import { z as
|
|
7401
|
+
import { z as z25 } from "zod";
|
|
7449
7402
|
function prepareCanvasEditArguments(input) {
|
|
7450
7403
|
return prepareTextReplacementArguments(input);
|
|
7451
7404
|
}
|
|
7452
|
-
var editReplacementSchema2 =
|
|
7453
|
-
oldText:
|
|
7405
|
+
var editReplacementSchema2 = z25.object({
|
|
7406
|
+
oldText: z25.string().min(1).describe(
|
|
7454
7407
|
"Exact Canvas markdown to replace. It must be unique in the current Canvas body and must not overlap another edit."
|
|
7455
7408
|
),
|
|
7456
|
-
newText:
|
|
7409
|
+
newText: z25.string().describe("Replacement Canvas markdown for this edit.")
|
|
7457
7410
|
});
|
|
7458
7411
|
var slackCanvasEditOutputSchema = juniorToolResultSchema.extend({
|
|
7459
|
-
canvas_id:
|
|
7460
|
-
title:
|
|
7461
|
-
permalink:
|
|
7462
|
-
diff:
|
|
7463
|
-
first_changed_line:
|
|
7464
|
-
replacements:
|
|
7465
|
-
normalized_heading_count:
|
|
7466
|
-
summary:
|
|
7467
|
-
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()
|
|
7468
7421
|
}).strict();
|
|
7469
7422
|
function createSlackCanvasEditTool(state) {
|
|
7470
7423
|
return zodTool({
|
|
7471
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.",
|
|
7472
7425
|
prepareArguments: prepareCanvasEditArguments,
|
|
7473
7426
|
executionMode: "sequential",
|
|
7474
|
-
inputSchema:
|
|
7475
|
-
canvas:
|
|
7476
|
-
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(
|
|
7477
7430
|
"Exact replacements matched against the current Canvas body, not incrementally."
|
|
7478
7431
|
)
|
|
7479
7432
|
}),
|
|
@@ -7551,29 +7504,29 @@ function createSlackCanvasEditTool(state) {
|
|
|
7551
7504
|
}
|
|
7552
7505
|
|
|
7553
7506
|
// src/chat/slack/tools/canvas/read.ts
|
|
7554
|
-
import { z as
|
|
7507
|
+
import { z as z26 } from "zod";
|
|
7555
7508
|
var slackCanvasReadOutputSchema = juniorToolResultSchema.extend({
|
|
7556
|
-
canvas_id:
|
|
7557
|
-
title:
|
|
7558
|
-
permalink:
|
|
7559
|
-
mimetype:
|
|
7560
|
-
filetype:
|
|
7561
|
-
original_byte_length:
|
|
7562
|
-
content:
|
|
7563
|
-
start_line:
|
|
7564
|
-
end_line:
|
|
7565
|
-
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()
|
|
7566
7519
|
}).strict();
|
|
7567
7520
|
function createSlackCanvasReadTool() {
|
|
7568
7521
|
return zodTool({
|
|
7569
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.",
|
|
7570
7523
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
7571
|
-
inputSchema:
|
|
7572
|
-
canvas:
|
|
7524
|
+
inputSchema: z26.object({
|
|
7525
|
+
canvas: z26.string().min(1).describe(
|
|
7573
7526
|
"Canvas/file ID (e.g. `F0ABCDEF`) or Slack canvas/docs URL (e.g. `https://team.slack.com/docs/T.../F...`)."
|
|
7574
7527
|
),
|
|
7575
|
-
offset:
|
|
7576
|
-
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()
|
|
7577
7530
|
}),
|
|
7578
7531
|
outputSchema: slackCanvasReadOutputSchema,
|
|
7579
7532
|
execute: async ({ canvas, offset, limit }) => {
|
|
@@ -7630,14 +7583,14 @@ function createSlackCanvasReadTool() {
|
|
|
7630
7583
|
}
|
|
7631
7584
|
|
|
7632
7585
|
// src/chat/slack/tools/canvas/write.ts
|
|
7633
|
-
import { z as
|
|
7586
|
+
import { z as z27 } from "zod";
|
|
7634
7587
|
function createSlackCanvasWriteTool(state) {
|
|
7635
7588
|
return zodTool({
|
|
7636
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.",
|
|
7637
7590
|
executionMode: "sequential",
|
|
7638
|
-
inputSchema:
|
|
7639
|
-
canvas:
|
|
7640
|
-
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.")
|
|
7641
7594
|
}),
|
|
7642
7595
|
outputSchema: juniorToolResultSchema,
|
|
7643
7596
|
execute: async ({ canvas, content }) => {
|
|
@@ -7873,12 +7826,12 @@ async function updateListItem(input) {
|
|
|
7873
7826
|
}
|
|
7874
7827
|
|
|
7875
7828
|
// src/chat/slack/id-param.ts
|
|
7876
|
-
import { z as
|
|
7829
|
+
import { z as z28 } from "zod";
|
|
7877
7830
|
function slackChannelIdParam(description) {
|
|
7878
|
-
return
|
|
7831
|
+
return z28.string().min(1).describe(description);
|
|
7879
7832
|
}
|
|
7880
7833
|
function slackUserIdParam(description) {
|
|
7881
|
-
return
|
|
7834
|
+
return z28.string().min(1).describe(description);
|
|
7882
7835
|
}
|
|
7883
7836
|
function parseRequiredSlackChannelIdParam(field, value) {
|
|
7884
7837
|
const channelId = parseSlackChannelId(value);
|
|
@@ -7902,16 +7855,16 @@ function parseRequiredSlackUserIdParam(field, value) {
|
|
|
7902
7855
|
}
|
|
7903
7856
|
|
|
7904
7857
|
// src/chat/slack/tools/list/add-items.ts
|
|
7905
|
-
import { z as
|
|
7858
|
+
import { z as z29 } from "zod";
|
|
7906
7859
|
function createSlackListAddItemsTool(state) {
|
|
7907
7860
|
return zodTool({
|
|
7908
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.",
|
|
7909
|
-
inputSchema:
|
|
7910
|
-
items:
|
|
7862
|
+
inputSchema: z29.object({
|
|
7863
|
+
items: z29.array(z29.string().min(1)).min(1).max(25).describe("List item titles to create."),
|
|
7911
7864
|
assignee_user_id: slackUserIdParam(
|
|
7912
7865
|
"Optional Slack user ID assigned to all created items."
|
|
7913
7866
|
).optional(),
|
|
7914
|
-
due_date:
|
|
7867
|
+
due_date: z29.string().regex(/^\d{4}-\d{2}-\d{2}$/).describe("Optional due date in YYYY-MM-DD format.").optional()
|
|
7915
7868
|
}),
|
|
7916
7869
|
outputSchema: juniorToolResultSchema,
|
|
7917
7870
|
execute: async ({ items, assignee_user_id, due_date }) => {
|
|
@@ -7965,12 +7918,12 @@ function createSlackListAddItemsTool(state) {
|
|
|
7965
7918
|
}
|
|
7966
7919
|
|
|
7967
7920
|
// src/chat/slack/tools/list/create.ts
|
|
7968
|
-
import { z as
|
|
7921
|
+
import { z as z30 } from "zod";
|
|
7969
7922
|
function createSlackListCreateTool(state) {
|
|
7970
7923
|
return zodTool({
|
|
7971
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.",
|
|
7972
|
-
inputSchema:
|
|
7973
|
-
name:
|
|
7925
|
+
inputSchema: z30.object({
|
|
7926
|
+
name: z30.string().min(1).max(160).describe("Name for the new Slack list.")
|
|
7974
7927
|
}),
|
|
7975
7928
|
outputSchema: juniorToolResultSchema,
|
|
7976
7929
|
execute: async ({ name }) => {
|
|
@@ -8002,13 +7955,13 @@ function createSlackListCreateTool(state) {
|
|
|
8002
7955
|
}
|
|
8003
7956
|
|
|
8004
7957
|
// src/chat/slack/tools/list/get-items.ts
|
|
8005
|
-
import { z as
|
|
7958
|
+
import { z as z31 } from "zod";
|
|
8006
7959
|
function createSlackListGetItemsTool(state) {
|
|
8007
7960
|
return zodTool({
|
|
8008
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.",
|
|
8009
7962
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8010
|
-
inputSchema:
|
|
8011
|
-
limit:
|
|
7963
|
+
inputSchema: z31.object({
|
|
7964
|
+
limit: z31.coerce.number().int().min(1).max(200).describe("Maximum number of list items to return.").optional()
|
|
8012
7965
|
}),
|
|
8013
7966
|
outputSchema: juniorToolResultSchema,
|
|
8014
7967
|
execute: async ({ limit }) => {
|
|
@@ -8033,21 +7986,21 @@ function createSlackListGetItemsTool(state) {
|
|
|
8033
7986
|
}
|
|
8034
7987
|
|
|
8035
7988
|
// src/chat/slack/tools/list/update-item.ts
|
|
8036
|
-
import { z as
|
|
8037
|
-
var booleanInput3 = (description) =>
|
|
7989
|
+
import { z as z32 } from "zod";
|
|
7990
|
+
var booleanInput3 = (description) => z32.preprocess(
|
|
8038
7991
|
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
8039
|
-
|
|
7992
|
+
z32.boolean()
|
|
8040
7993
|
).describe(description);
|
|
8041
|
-
var updateListItemInputSchema =
|
|
8042
|
-
|
|
8043
|
-
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."),
|
|
8044
7997
|
completed: booleanInput3("Optional completion status update."),
|
|
8045
|
-
title:
|
|
7998
|
+
title: z32.string().min(1).describe("Optional new item title.").optional()
|
|
8046
7999
|
}),
|
|
8047
|
-
|
|
8048
|
-
item_id:
|
|
8000
|
+
z32.object({
|
|
8001
|
+
item_id: z32.string().min(1).describe("ID of the Slack list item to update."),
|
|
8049
8002
|
completed: booleanInput3("Optional completion status update.").optional(),
|
|
8050
|
-
title:
|
|
8003
|
+
title: z32.string().min(1).describe("Optional new item title.")
|
|
8051
8004
|
})
|
|
8052
8005
|
]);
|
|
8053
8006
|
function createSlackListUpdateItemTool(state) {
|
|
@@ -8123,7 +8076,7 @@ async function checkSlackChannelReadAccess(args) {
|
|
|
8123
8076
|
}
|
|
8124
8077
|
|
|
8125
8078
|
// src/chat/slack/tools/thread-read.ts
|
|
8126
|
-
import { z as
|
|
8079
|
+
import { z as z33 } from "zod";
|
|
8127
8080
|
|
|
8128
8081
|
// src/chat/slack/tools/slack-message-url.ts
|
|
8129
8082
|
var SLACK_HOST_PATTERN = /^[a-z0-9-]+\.slack(?:-gov)?\.com$/;
|
|
@@ -8296,8 +8249,8 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
8296
8249
|
return zodTool({
|
|
8297
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.",
|
|
8298
8251
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8299
|
-
inputSchema:
|
|
8300
|
-
url:
|
|
8252
|
+
inputSchema: z33.object({
|
|
8253
|
+
url: z33.string().min(1).describe(
|
|
8301
8254
|
"Slack message archive URL, e.g. https://workspace.slack.com/archives/C123/p1700000000123456"
|
|
8302
8255
|
).optional(),
|
|
8303
8256
|
channel_id: slackChannelIdParam(
|
|
@@ -8306,8 +8259,8 @@ function createSlackThreadReadTool(context, deps = {}) {
|
|
|
8306
8259
|
ts: slackTimestampParam(
|
|
8307
8260
|
"Slack message timestamp (e.g. 1700000000.123456). May be the thread root or any message in the thread."
|
|
8308
8261
|
).optional(),
|
|
8309
|
-
limit:
|
|
8310
|
-
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()
|
|
8311
8264
|
}),
|
|
8312
8265
|
outputSchema: juniorToolResultSchema,
|
|
8313
8266
|
execute: async ({ url, channel_id, ts, limit, max_pages }) => {
|
|
@@ -8563,29 +8516,29 @@ async function searchSlackUsers(options) {
|
|
|
8563
8516
|
}
|
|
8564
8517
|
|
|
8565
8518
|
// src/chat/slack/tools/user-lookup.ts
|
|
8566
|
-
import { z as
|
|
8567
|
-
var booleanInput4 = (description) =>
|
|
8519
|
+
import { z as z34 } from "zod";
|
|
8520
|
+
var booleanInput4 = (description) => z34.preprocess(
|
|
8568
8521
|
(value) => value === "true" ? true : value === "false" ? false : value,
|
|
8569
|
-
|
|
8522
|
+
z34.boolean()
|
|
8570
8523
|
).describe(description);
|
|
8571
8524
|
function createSlackUserLookupTool() {
|
|
8572
8525
|
return zodTool({
|
|
8573
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.",
|
|
8574
8527
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8575
|
-
inputSchema:
|
|
8528
|
+
inputSchema: z34.object({
|
|
8576
8529
|
user_id: slackUserIdParam(
|
|
8577
8530
|
"Slack user ID to look up (e.g. U039RR91S). Mutually exclusive with email and query."
|
|
8578
8531
|
).optional(),
|
|
8579
|
-
email:
|
|
8532
|
+
email: z34.string().min(3).describe(
|
|
8580
8533
|
"Email address to look up. Mutually exclusive with user_id and query."
|
|
8581
8534
|
).optional(),
|
|
8582
|
-
query:
|
|
8535
|
+
query: z34.string().min(2).describe(
|
|
8583
8536
|
"Name to search for (matches against username, display name, real name). Mutually exclusive with user_id and email."
|
|
8584
8537
|
).optional(),
|
|
8585
|
-
limit:
|
|
8538
|
+
limit: z34.coerce.number().int().min(1).max(20).describe(
|
|
8586
8539
|
"Maximum number of results to return for name search. Defaults to 10."
|
|
8587
8540
|
).optional(),
|
|
8588
|
-
max_pages:
|
|
8541
|
+
max_pages: z34.coerce.number().int().min(1).max(5).describe(
|
|
8589
8542
|
"Maximum number of Slack API pages to scan for name search. Defaults to 3."
|
|
8590
8543
|
).optional(),
|
|
8591
8544
|
include_bots: booleanInput4(
|
|
@@ -8689,18 +8642,18 @@ function createSlackUserLookupTool() {
|
|
|
8689
8642
|
}
|
|
8690
8643
|
|
|
8691
8644
|
// src/chat/tools/system-time.ts
|
|
8692
|
-
import { z as
|
|
8645
|
+
import { z as z35 } from "zod";
|
|
8693
8646
|
var systemTimeOutputSchema = juniorToolResultSchema.extend({
|
|
8694
|
-
unix_ms:
|
|
8695
|
-
iso_utc:
|
|
8696
|
-
iso_local:
|
|
8697
|
-
timezone_offset_minutes:
|
|
8647
|
+
unix_ms: z35.number(),
|
|
8648
|
+
iso_utc: z35.string(),
|
|
8649
|
+
iso_local: z35.string(),
|
|
8650
|
+
timezone_offset_minutes: z35.number()
|
|
8698
8651
|
});
|
|
8699
8652
|
function createSystemTimeTool() {
|
|
8700
8653
|
return zodTool({
|
|
8701
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.",
|
|
8702
8655
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
8703
|
-
inputSchema:
|
|
8656
|
+
inputSchema: z35.object({}),
|
|
8704
8657
|
outputSchema: systemTimeOutputSchema,
|
|
8705
8658
|
privateTraceResult: (result) => ({
|
|
8706
8659
|
ok: result.ok,
|
|
@@ -8729,27 +8682,30 @@ function createSystemTimeTool() {
|
|
|
8729
8682
|
}
|
|
8730
8683
|
|
|
8731
8684
|
// src/chat/tools/handoff/tool.ts
|
|
8732
|
-
import { z as
|
|
8685
|
+
import { z as z36 } from "zod";
|
|
8733
8686
|
var HANDOFF_TOOL_NAME = "handoff";
|
|
8734
8687
|
function createHandoffTool(handoff) {
|
|
8735
|
-
const profileSchema =
|
|
8736
|
-
const defaultProfile = handoff.profiles[0];
|
|
8688
|
+
const profileSchema = z36.enum(handoff.profiles);
|
|
8737
8689
|
const handoffResultSchema = juniorToolResultSchema.extend({
|
|
8738
8690
|
model_profile: profileSchema
|
|
8739
8691
|
});
|
|
8740
8692
|
const profileNames = handoff.profiles.map((profile) => `\`${profile}\``).join(", ");
|
|
8741
8693
|
return zodTool({
|
|
8742
|
-
description: `
|
|
8694
|
+
description: `Switch to another execution profile and continue the same task. Profiles: ${profileNames}. Call this as the only tool.`,
|
|
8743
8695
|
executionMode: "sequential",
|
|
8744
|
-
inputSchema:
|
|
8745
|
-
profile: profileSchema.
|
|
8746
|
-
"Named model profile to use for the rest of the conversation; omit or pass null for the default"
|
|
8747
|
-
)
|
|
8696
|
+
inputSchema: z36.object({
|
|
8697
|
+
profile: profileSchema.describe("Target execution profile")
|
|
8748
8698
|
}).strict(),
|
|
8749
8699
|
outputSchema: handoffResultSchema,
|
|
8750
8700
|
execute: async (input, options) => {
|
|
8751
|
-
const profile = input.profile
|
|
8752
|
-
|
|
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
|
+
});
|
|
8753
8709
|
return {
|
|
8754
8710
|
ok: true,
|
|
8755
8711
|
status: "success",
|
|
@@ -8760,7 +8716,7 @@ function createHandoffTool(handoff) {
|
|
|
8760
8716
|
}
|
|
8761
8717
|
|
|
8762
8718
|
// src/chat/tools/web/fetch-tool.ts
|
|
8763
|
-
import { z as
|
|
8719
|
+
import { z as z37 } from "zod";
|
|
8764
8720
|
|
|
8765
8721
|
// src/chat/tools/web/constants.ts
|
|
8766
8722
|
var USER_AGENT = "junior-bot/0.1";
|
|
@@ -9207,9 +9163,9 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
9207
9163
|
destructiveHint: false,
|
|
9208
9164
|
openWorldHint: true
|
|
9209
9165
|
},
|
|
9210
|
-
inputSchema:
|
|
9211
|
-
url:
|
|
9212
|
-
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()
|
|
9213
9169
|
}),
|
|
9214
9170
|
outputSchema: juniorToolResultSchema,
|
|
9215
9171
|
execute: async ({ url, max_chars }) => {
|
|
@@ -9247,14 +9203,8 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
9247
9203
|
url: safeUrl.toString(),
|
|
9248
9204
|
media_type: contentType,
|
|
9249
9205
|
bytes: bytes.byteLength,
|
|
9250
|
-
images: artifactRefs
|
|
9251
|
-
|
|
9252
|
-
path: artifact.path,
|
|
9253
|
-
attachment_path: artifact.path,
|
|
9254
|
-
media_type: artifact.mimeType,
|
|
9255
|
-
bytes: artifact.bytes
|
|
9256
|
-
})),
|
|
9257
|
-
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."
|
|
9258
9208
|
};
|
|
9259
9209
|
}
|
|
9260
9210
|
return await extractWebFetchResponse(safeUrl, response, max_chars);
|
|
@@ -9276,7 +9226,7 @@ function createWebFetchTool(hooks, options = {}) {
|
|
|
9276
9226
|
}
|
|
9277
9227
|
|
|
9278
9228
|
// src/chat/tools/web/search.ts
|
|
9279
|
-
import { z as
|
|
9229
|
+
import { z as z38 } from "zod";
|
|
9280
9230
|
import { generateText } from "ai";
|
|
9281
9231
|
import { createGatewayProvider } from "@ai-sdk/gateway";
|
|
9282
9232
|
import { getModel } from "@earendil-works/pi-ai/compat";
|
|
@@ -9327,9 +9277,9 @@ function createWebSearchTool(override) {
|
|
|
9327
9277
|
destructiveHint: false,
|
|
9328
9278
|
openWorldHint: true
|
|
9329
9279
|
},
|
|
9330
|
-
inputSchema:
|
|
9331
|
-
query:
|
|
9332
|
-
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()
|
|
9333
9283
|
}),
|
|
9334
9284
|
outputSchema: juniorToolResultSchema,
|
|
9335
9285
|
execute: async ({ query, max_results }) => {
|
|
@@ -9399,14 +9349,14 @@ function createWebSearchTool(override) {
|
|
|
9399
9349
|
}
|
|
9400
9350
|
|
|
9401
9351
|
// src/chat/tools/sandbox/write-file.ts
|
|
9402
|
-
import { z as
|
|
9352
|
+
import { z as z39 } from "zod";
|
|
9403
9353
|
function createWriteFileTool() {
|
|
9404
9354
|
return zodTool({
|
|
9405
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.",
|
|
9406
9356
|
executionMode: "sequential",
|
|
9407
|
-
inputSchema:
|
|
9408
|
-
path:
|
|
9409
|
-
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.")
|
|
9410
9360
|
}),
|
|
9411
9361
|
outputSchema: juniorToolResultSchema,
|
|
9412
9362
|
execute: async () => {
|
|
@@ -9451,7 +9401,7 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
9451
9401
|
const slackContext = getSlackToolContext(context);
|
|
9452
9402
|
const slackSourceCapabilities = slackContext ? resolveChannelCapabilities(slackContext.sourceChannelId) : void 0;
|
|
9453
9403
|
const canSendFilesToActiveConversation = Boolean(
|
|
9454
|
-
slackContext && slackSourceCapabilities?.
|
|
9404
|
+
slackContext && slackSourceCapabilities?.canSendFiles
|
|
9455
9405
|
);
|
|
9456
9406
|
const tools = {
|
|
9457
9407
|
loadSkill: createLoadSkillTool(availableSkills, {
|
|
@@ -9530,8 +9480,8 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
9530
9480
|
state
|
|
9531
9481
|
);
|
|
9532
9482
|
}
|
|
9533
|
-
if (rawChannelCapabilities.
|
|
9534
|
-
tools.
|
|
9483
|
+
if (rawChannelCapabilities.canSendFiles) {
|
|
9484
|
+
tools.sendFiles = createSendFilesTool(
|
|
9535
9485
|
slackContext,
|
|
9536
9486
|
state,
|
|
9537
9487
|
(input) => readSandboxFileUpload(context.sandbox, input)
|
|
@@ -9936,10 +9886,6 @@ function parseOAuthStatePayload(value) {
|
|
|
9936
9886
|
if (value.source !== void 0 && (!source || !source.success)) {
|
|
9937
9887
|
return void 0;
|
|
9938
9888
|
}
|
|
9939
|
-
const pendingMessage = optionalString(value.pendingMessage);
|
|
9940
|
-
if (pendingMessage && !source?.success) {
|
|
9941
|
-
return void 0;
|
|
9942
|
-
}
|
|
9943
9889
|
return {
|
|
9944
9890
|
userId: value.userId,
|
|
9945
9891
|
provider: value.provider,
|
|
@@ -9947,8 +9893,6 @@ function parseOAuthStatePayload(value) {
|
|
|
9947
9893
|
...destination ? { destination } : {},
|
|
9948
9894
|
...source?.success ? { source: source.data } : {},
|
|
9949
9895
|
...optionalString(value.threadTs) ? { threadTs: optionalString(value.threadTs) } : {},
|
|
9950
|
-
...pendingMessage ? { pendingMessage } : {},
|
|
9951
|
-
...isRecord(value.configuration) ? { configuration: value.configuration } : {},
|
|
9952
9896
|
...optionalString(value.resumeConversationId) ? { resumeConversationId: optionalString(value.resumeConversationId) } : {},
|
|
9953
9897
|
...optionalString(value.resumeSessionId) ? { resumeSessionId: optionalString(value.resumeSessionId) } : {},
|
|
9954
9898
|
...optionalString(value.scope) ? { scope: optionalString(value.scope) } : {}
|
|
@@ -10066,7 +10010,6 @@ async function startOAuthFlow(provider, input) {
|
|
|
10066
10010
|
error: "Cannot determine base URL (set JUNIOR_BASE_URL or deploy to Vercel)"
|
|
10067
10011
|
};
|
|
10068
10012
|
}
|
|
10069
|
-
const configuration = input.userMessage && input.channelConfiguration ? await input.channelConfiguration.resolveValues() : void 0;
|
|
10070
10013
|
const state = randomBytes(32).toString("hex");
|
|
10071
10014
|
const requestedScope = input.scope ?? providerConfig.scope;
|
|
10072
10015
|
await getStateAdapter().set(
|
|
@@ -10078,8 +10021,6 @@ async function startOAuthFlow(provider, input) {
|
|
|
10078
10021
|
...input.destination ? { destination: input.destination } : {},
|
|
10079
10022
|
...input.source ? { source: input.source } : {},
|
|
10080
10023
|
...input.threadTs ? { threadTs: input.threadTs } : {},
|
|
10081
|
-
...input.userMessage ? { pendingMessage: input.userMessage } : {},
|
|
10082
|
-
...configuration && Object.keys(configuration).length > 0 ? { configuration } : {},
|
|
10083
10024
|
...input.resumeConversationId ? { resumeConversationId: input.resumeConversationId } : {},
|
|
10084
10025
|
...input.resumeSessionId ? { resumeSessionId: input.resumeSessionId } : {},
|
|
10085
10026
|
...requestedScope ? { scope: requestedScope } : {}
|
|
@@ -10126,59 +10067,59 @@ async function startOAuthFlow(provider, input) {
|
|
|
10126
10067
|
}
|
|
10127
10068
|
|
|
10128
10069
|
// src/chat/sandbox/egress/schemas.ts
|
|
10129
|
-
import { z as
|
|
10070
|
+
import { z as z40 } from "zod";
|
|
10130
10071
|
import {
|
|
10131
10072
|
pluginAuthorizationSchema,
|
|
10132
10073
|
pluginCredentialHeaderTransformSchema,
|
|
10133
10074
|
pluginGrantSchema,
|
|
10134
10075
|
pluginProviderAccountSchema
|
|
10135
10076
|
} from "@sentry/junior-plugin-api";
|
|
10136
|
-
var finiteNumberSchema =
|
|
10137
|
-
var httpStatusSchema =
|
|
10138
|
-
var providerNameSchema =
|
|
10139
|
-
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"]);
|
|
10140
10081
|
var sandboxEgressGrantSchema = pluginGrantSchema;
|
|
10141
|
-
var sandboxEgressCredentialContextSchema =
|
|
10082
|
+
var sandboxEgressCredentialContextSchema = z40.object({
|
|
10142
10083
|
credentials: credentialContextSchema,
|
|
10143
|
-
egressId:
|
|
10084
|
+
egressId: z40.string().min(1),
|
|
10144
10085
|
expiresAtMs: finiteNumberSchema,
|
|
10145
|
-
contextId:
|
|
10086
|
+
contextId: z40.string().min(1)
|
|
10146
10087
|
}).strict();
|
|
10147
|
-
var sandboxEgressCredentialLeaseSchema =
|
|
10088
|
+
var sandboxEgressCredentialLeaseSchema = z40.object({
|
|
10148
10089
|
account: pluginProviderAccountSchema.optional(),
|
|
10149
10090
|
authorization: pluginAuthorizationSchema.optional(),
|
|
10150
10091
|
grant: sandboxEgressGrantSchema,
|
|
10151
10092
|
provider: providerNameSchema,
|
|
10152
|
-
expiresAt:
|
|
10153
|
-
headerTransforms:
|
|
10093
|
+
expiresAt: z40.string().min(1),
|
|
10094
|
+
headerTransforms: z40.array(pluginCredentialHeaderTransformSchema).min(1)
|
|
10154
10095
|
}).strict();
|
|
10155
|
-
var sandboxEgressAuthRequiredSignalSchema =
|
|
10096
|
+
var sandboxEgressAuthRequiredSignalSchema = z40.object({
|
|
10156
10097
|
authorization: pluginAuthorizationSchema.optional(),
|
|
10157
10098
|
grant: sandboxEgressGrantSchema,
|
|
10158
10099
|
kind: credentialSignalKindSchema.default("auth_required"),
|
|
10159
10100
|
provider: providerNameSchema,
|
|
10160
|
-
message:
|
|
10101
|
+
message: z40.string().optional(),
|
|
10161
10102
|
createdAtMs: finiteNumberSchema
|
|
10162
10103
|
}).strict().superRefine((signal, ctx) => {
|
|
10163
10104
|
if (signal.authorization && signal.authorization.provider !== signal.provider) {
|
|
10164
10105
|
ctx.addIssue({
|
|
10165
|
-
code:
|
|
10106
|
+
code: z40.ZodIssueCode.custom,
|
|
10166
10107
|
message: "Auth signal authorization provider must match provider",
|
|
10167
10108
|
path: ["authorization", "provider"]
|
|
10168
10109
|
});
|
|
10169
10110
|
}
|
|
10170
10111
|
});
|
|
10171
|
-
var sandboxEgressPermissionDeniedSignalSchema =
|
|
10112
|
+
var sandboxEgressPermissionDeniedSignalSchema = z40.object({
|
|
10172
10113
|
account: pluginProviderAccountSchema.optional(),
|
|
10173
|
-
acceptedPermissions:
|
|
10114
|
+
acceptedPermissions: z40.string().optional(),
|
|
10174
10115
|
grant: sandboxEgressGrantSchema,
|
|
10175
|
-
message:
|
|
10116
|
+
message: z40.string().min(1),
|
|
10176
10117
|
provider: providerNameSchema,
|
|
10177
|
-
source:
|
|
10178
|
-
sso:
|
|
10118
|
+
source: z40.literal("upstream"),
|
|
10119
|
+
sso: z40.string().optional(),
|
|
10179
10120
|
status: httpStatusSchema,
|
|
10180
|
-
upstreamHost:
|
|
10181
|
-
upstreamPath:
|
|
10121
|
+
upstreamHost: z40.string().min(1),
|
|
10122
|
+
upstreamPath: z40.string().min(1),
|
|
10182
10123
|
createdAtMs: finiteNumberSchema
|
|
10183
10124
|
}).strict();
|
|
10184
10125
|
function parseSandboxEgressAuthRequiredSignal(value) {
|
|
@@ -10258,8 +10199,6 @@ function createPluginAuthOrchestration(input) {
|
|
|
10258
10199
|
destination: input.destination,
|
|
10259
10200
|
source: input.source,
|
|
10260
10201
|
threadTs: input.threadTs,
|
|
10261
|
-
userMessage: input.userMessage,
|
|
10262
|
-
channelConfiguration: input.channelConfiguration,
|
|
10263
10202
|
...options?.scope ? { scope: options.scope } : {},
|
|
10264
10203
|
resumeConversationId: input.conversationId,
|
|
10265
10204
|
resumeSessionId: input.sessionId
|
|
@@ -10439,15 +10378,15 @@ function handleToolExecutionError(error, toolName, toolCallId, shouldTrace, trac
|
|
|
10439
10378
|
}
|
|
10440
10379
|
|
|
10441
10380
|
// src/chat/tools/execute-tool.ts
|
|
10442
|
-
import { z as
|
|
10381
|
+
import { z as z41 } from "zod";
|
|
10443
10382
|
var EXECUTE_TOOL_NAME = "executeTool";
|
|
10444
10383
|
function createExecuteToolTool() {
|
|
10445
10384
|
return zodTool({
|
|
10446
10385
|
description: "Execute any catalog tool by exact tool_name from searchTools. Put tool-specific parameters inside arguments.",
|
|
10447
10386
|
executionMode: "sequential",
|
|
10448
|
-
inputSchema:
|
|
10449
|
-
tool_name:
|
|
10450
|
-
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(
|
|
10451
10390
|
'Arguments matching the selected catalog tool schema, for example { "query": "..." }.'
|
|
10452
10391
|
).optional()
|
|
10453
10392
|
}).strict(),
|
|
@@ -10487,42 +10426,42 @@ function planToolExposure(tools) {
|
|
|
10487
10426
|
}
|
|
10488
10427
|
|
|
10489
10428
|
// src/chat/tools/search-tools.ts
|
|
10490
|
-
import { z as
|
|
10429
|
+
import { z as z42 } from "zod";
|
|
10491
10430
|
var SEARCH_TOOLS_NAME = "searchTools";
|
|
10492
10431
|
var DEFAULT_MAX_RESULTS2 = 5;
|
|
10493
10432
|
var MAX_RESULTS3 = 20;
|
|
10494
10433
|
var MODEL_VISIBLE_DESCRIPTION_CAP = 180;
|
|
10495
|
-
var searchToolsSourceSchema =
|
|
10496
|
-
id:
|
|
10497
|
-
description:
|
|
10434
|
+
var searchToolsSourceSchema = z42.object({
|
|
10435
|
+
id: z42.string(),
|
|
10436
|
+
description: z42.string()
|
|
10498
10437
|
}).strict();
|
|
10499
|
-
var toolCallExampleSchema =
|
|
10500
|
-
tool_name:
|
|
10501
|
-
arguments:
|
|
10438
|
+
var toolCallExampleSchema = z42.object({
|
|
10439
|
+
tool_name: z42.string(),
|
|
10440
|
+
arguments: z42.record(z42.string(), z42.string())
|
|
10502
10441
|
}).strict();
|
|
10503
|
-
var searchToolsToolSchema =
|
|
10504
|
-
tool_name:
|
|
10505
|
-
description:
|
|
10506
|
-
exposure:
|
|
10507
|
-
source:
|
|
10508
|
-
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(),
|
|
10509
10448
|
call: toolCallExampleSchema,
|
|
10510
|
-
input_schema:
|
|
10511
|
-
input_schema_summary:
|
|
10512
|
-
call_notes:
|
|
10513
|
-
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())
|
|
10514
10453
|
}).strict();
|
|
10515
10454
|
var searchToolsOutputSchema = juniorToolResultSchema.extend({
|
|
10516
|
-
query:
|
|
10517
|
-
source:
|
|
10518
|
-
sources:
|
|
10519
|
-
total_catalog_tools:
|
|
10520
|
-
total_eligible_tools:
|
|
10521
|
-
total_matches:
|
|
10522
|
-
returned_tools:
|
|
10523
|
-
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"),
|
|
10524
10463
|
execution_example: toolCallExampleSchema,
|
|
10525
|
-
tools:
|
|
10464
|
+
tools: z42.array(searchToolsToolSchema)
|
|
10526
10465
|
}).strict();
|
|
10527
10466
|
function normalize2(value) {
|
|
10528
10467
|
return value.toLowerCase().replace(/[^a-z0-9_]+/g, " ").trim();
|
|
@@ -10714,14 +10653,14 @@ function createSearchToolsTool(catalogTools) {
|
|
|
10714
10653
|
return zodTool({
|
|
10715
10654
|
description: renderSearchToolsDescription(knownSources),
|
|
10716
10655
|
annotations: { readOnlyHint: true, destructiveHint: false },
|
|
10717
|
-
inputSchema:
|
|
10718
|
-
query:
|
|
10656
|
+
inputSchema: z42.object({
|
|
10657
|
+
query: z42.string().nullable().describe(
|
|
10719
10658
|
"Optional search terms describing the tool, owner, action, or arguments needed. Empty string lists catalog tools."
|
|
10720
10659
|
).optional(),
|
|
10721
|
-
source:
|
|
10660
|
+
source: z42.string().nullable().describe(
|
|
10722
10661
|
"Optional source id to search within, such as a plugin source returned in sources."
|
|
10723
10662
|
).optional(),
|
|
10724
|
-
max_results:
|
|
10663
|
+
max_results: z42.number().int().min(1).max(MAX_RESULTS3).nullable().describe("Maximum matching catalog tool descriptors to return.").optional()
|
|
10725
10664
|
}).strict(),
|
|
10726
10665
|
outputSchema: searchToolsOutputSchema,
|
|
10727
10666
|
privateTraceResult: (result) => ({
|
|
@@ -10824,14 +10763,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10824
10763
|
return normalized.details;
|
|
10825
10764
|
};
|
|
10826
10765
|
const executeDefinition = async (args) => {
|
|
10827
|
-
const {
|
|
10828
|
-
normalizedToolCallId,
|
|
10829
|
-
params,
|
|
10830
|
-
signal,
|
|
10831
|
-
setSpanAttributes: setSpanAttributes2,
|
|
10832
|
-
toolDef,
|
|
10833
|
-
toolName
|
|
10834
|
-
} = args;
|
|
10766
|
+
const { toolCallId, params, signal, setSpanAttributes: setSpanAttributes2, toolDef, toolName } = args;
|
|
10835
10767
|
if (typeof toolDef.execute !== "function") {
|
|
10836
10768
|
throw new Error(`Tool ${toolName} does not define an executor.`);
|
|
10837
10769
|
}
|
|
@@ -10840,7 +10772,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10840
10772
|
input: params
|
|
10841
10773
|
}) : { input: params, env: {} };
|
|
10842
10774
|
const toolInput = beforeTool.input;
|
|
10843
|
-
await onToolCall?.(toolName, toolInput);
|
|
10775
|
+
await onToolCall?.(toolCallId, toolName, toolInput);
|
|
10844
10776
|
const sandboxInput = buildSandboxInput(toolName, toolInput);
|
|
10845
10777
|
const isSandbox = Boolean(sandboxExecutor?.canExecute(toolName));
|
|
10846
10778
|
const result = isSandbox ? await sandboxExecutor.execute({
|
|
@@ -10851,7 +10783,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10851
10783
|
experimental_context: sandbox,
|
|
10852
10784
|
...signal ? { signal } : {},
|
|
10853
10785
|
conversationPrivacy: effectiveConversationPrivacy,
|
|
10854
|
-
|
|
10786
|
+
toolCallId
|
|
10855
10787
|
});
|
|
10856
10788
|
const normalized = normalizeToolResult(result, isSandbox, {
|
|
10857
10789
|
requireStructuredResult: Boolean(toolDef.outputSchema),
|
|
@@ -10904,6 +10836,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10904
10836
|
ok: toolResultOk(normalized.details),
|
|
10905
10837
|
params: toolInput,
|
|
10906
10838
|
result: resultAttributeValue,
|
|
10839
|
+
toolCallId,
|
|
10907
10840
|
toolName
|
|
10908
10841
|
});
|
|
10909
10842
|
return normalized;
|
|
@@ -10925,7 +10858,9 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10925
10858
|
prepareArguments: toolDef.prepareArguments,
|
|
10926
10859
|
executionMode: toolDef.executionMode,
|
|
10927
10860
|
execute: async (toolCallId, params, signal) => {
|
|
10928
|
-
|
|
10861
|
+
if (typeof toolCallId !== "string" || toolCallId.length === 0) {
|
|
10862
|
+
throw new Error("Pi tool execution requires a non-empty tool call id.");
|
|
10863
|
+
}
|
|
10929
10864
|
const toolArgumentsAttribute = serializeToolPayload(params, {
|
|
10930
10865
|
privateMetadata: true
|
|
10931
10866
|
});
|
|
@@ -10958,7 +10893,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10958
10893
|
executionParams = catalogCall.arguments;
|
|
10959
10894
|
await reportStatus(executionToolName, executionParams);
|
|
10960
10895
|
return await executeDefinition({
|
|
10961
|
-
|
|
10896
|
+
toolCallId,
|
|
10962
10897
|
params: catalogCall.arguments,
|
|
10963
10898
|
signal,
|
|
10964
10899
|
setSpanAttributes: setSpanAttributes2,
|
|
@@ -10968,7 +10903,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10968
10903
|
}
|
|
10969
10904
|
await reportStatus(executionToolName, executionParams);
|
|
10970
10905
|
return await executeDefinition({
|
|
10971
|
-
|
|
10906
|
+
toolCallId,
|
|
10972
10907
|
params: parsed,
|
|
10973
10908
|
signal,
|
|
10974
10909
|
setSpanAttributes: setSpanAttributes2,
|
|
@@ -10980,6 +10915,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10980
10915
|
error: error instanceof Error ? error.message : String(error),
|
|
10981
10916
|
ok: false,
|
|
10982
10917
|
params: executionParams,
|
|
10918
|
+
toolCallId,
|
|
10983
10919
|
toolName: executionToolName
|
|
10984
10920
|
});
|
|
10985
10921
|
if (error instanceof AuthorizationPauseError || error instanceof AuthorizationFlowDisabledError) {
|
|
@@ -10988,7 +10924,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
10988
10924
|
handleToolExecutionError(
|
|
10989
10925
|
error,
|
|
10990
10926
|
executionToolName,
|
|
10991
|
-
|
|
10927
|
+
toolCallId,
|
|
10992
10928
|
shouldTrace,
|
|
10993
10929
|
spanContext,
|
|
10994
10930
|
effectiveConversationPrivacy,
|
|
@@ -11002,7 +10938,7 @@ function createPiAgentTools(tools, sandbox, spanContext, onStatus, sandboxExecut
|
|
|
11002
10938
|
"gen_ai.tool.description": toolDef.description,
|
|
11003
10939
|
"gen_ai.tool.type": "function",
|
|
11004
10940
|
...toolArgumentsMetadata,
|
|
11005
|
-
|
|
10941
|
+
"gen_ai.tool.call.id": toolCallId,
|
|
11006
10942
|
...toolArgumentsAttribute ? { "gen_ai.tool.call.arguments": toolArgumentsAttribute } : {}
|
|
11007
10943
|
}
|
|
11008
10944
|
);
|
|
@@ -14700,13 +14636,13 @@ async function wireAgentTools(args) {
|
|
|
14700
14636
|
const slackChannelId = slackDestination?.channelId;
|
|
14701
14637
|
const mcpAuth = createMcpAuthOrchestration({
|
|
14702
14638
|
abortAgent: args.abortAgent,
|
|
14703
|
-
conversationId: args.
|
|
14704
|
-
sessionId: args.
|
|
14639
|
+
conversationId: args.conversationId,
|
|
14640
|
+
sessionId: args.turnId,
|
|
14705
14641
|
actorId: authActorId,
|
|
14706
14642
|
channelId: slackChannelId,
|
|
14707
14643
|
destination: args.routing.destination,
|
|
14708
14644
|
source: runSource,
|
|
14709
|
-
threadTs: args.routing.
|
|
14645
|
+
threadTs: args.routing.source.platform === "slack" ? args.routing.source.threadTs : void 0,
|
|
14710
14646
|
toolChannelId: args.routing.toolChannelId,
|
|
14711
14647
|
userMessage: args.userInput,
|
|
14712
14648
|
pendingAuth: args.state.pendingAuth,
|
|
@@ -14721,15 +14657,13 @@ async function wireAgentTools(args) {
|
|
|
14721
14657
|
});
|
|
14722
14658
|
const pluginAuth = createPluginAuthOrchestration({
|
|
14723
14659
|
abortAgent: args.abortAgent,
|
|
14724
|
-
conversationId: args.
|
|
14725
|
-
sessionId: args.
|
|
14660
|
+
conversationId: args.conversationId,
|
|
14661
|
+
sessionId: args.turnId,
|
|
14726
14662
|
actorId: authActorId,
|
|
14727
14663
|
channelId: slackChannelId,
|
|
14728
14664
|
destination: args.routing.destination,
|
|
14729
14665
|
source: runSource,
|
|
14730
|
-
threadTs: args.routing.
|
|
14731
|
-
userMessage: args.userInput,
|
|
14732
|
-
channelConfiguration: args.policy.channelConfiguration,
|
|
14666
|
+
threadTs: args.routing.source.platform === "slack" ? args.routing.source.threadTs : void 0,
|
|
14733
14667
|
pendingAuth: args.state.pendingAuth,
|
|
14734
14668
|
recordPendingAuth: args.durability.recordPendingAuth,
|
|
14735
14669
|
authorizationFlowMode: args.policy.authorizationFlowMode,
|
|
@@ -14747,7 +14681,7 @@ async function wireAgentTools(args) {
|
|
|
14747
14681
|
(skill) => skill.disableModelInvocation !== true || skill.name === args.invokedSkill?.name
|
|
14748
14682
|
);
|
|
14749
14683
|
const commonToolRuntimeContext = {
|
|
14750
|
-
conversationId: args.
|
|
14684
|
+
conversationId: args.conversationId,
|
|
14751
14685
|
userText: args.userInput,
|
|
14752
14686
|
artifactState: args.state.artifactState,
|
|
14753
14687
|
configuration: args.configurationValues,
|
|
@@ -14890,10 +14824,14 @@ async function wireAgentTools(args) {
|
|
|
14890
14824
|
const activeMcpCatalogs = toActiveMcpCatalogSummaries(
|
|
14891
14825
|
mcpToolManager.getActiveToolCatalog()
|
|
14892
14826
|
);
|
|
14893
|
-
const onToolCall = async (toolName, params) => {
|
|
14827
|
+
const onToolCall = async (toolCallId, toolName, params) => {
|
|
14894
14828
|
args.toolCalls.push(toolName);
|
|
14895
14829
|
try {
|
|
14896
|
-
await args.observers.onToolInvocation?.({
|
|
14830
|
+
await args.observers.onToolInvocation?.({
|
|
14831
|
+
params,
|
|
14832
|
+
toolCallId,
|
|
14833
|
+
toolName
|
|
14834
|
+
});
|
|
14897
14835
|
} catch (error) {
|
|
14898
14836
|
logWarn(
|
|
14899
14837
|
"tool_invocation_observer_failed",
|
|
@@ -14946,20 +14884,19 @@ function createResumeState(args) {
|
|
|
14946
14884
|
let resumeMessages = [];
|
|
14947
14885
|
let turnStartMessageIndex;
|
|
14948
14886
|
const currentSliceId = args.sessionRecordState.currentSliceId;
|
|
14949
|
-
const canPersistSession = args.sessionRecordState.canUseTurnSession && Boolean(args.sessionConversationId && args.sessionId);
|
|
14950
14887
|
const currentDurationMs = () => Date.now() - args.startedAtMs;
|
|
14951
14888
|
const sessionRecordBase = () => ({
|
|
14952
14889
|
channelName: args.channelName,
|
|
14953
|
-
conversationId: args.
|
|
14890
|
+
conversationId: args.conversationId,
|
|
14954
14891
|
destination: args.destination,
|
|
14955
14892
|
source: args.runSource,
|
|
14956
|
-
sessionId: args.
|
|
14893
|
+
sessionId: args.turnId,
|
|
14957
14894
|
loadedSkillNames: args.getLoadedSkillNames(),
|
|
14958
14895
|
logContext: args.logContext,
|
|
14959
14896
|
modelId: args.getModelId(),
|
|
14960
14897
|
...args.getReasoningLevel() ? { reasoningLevel: args.getReasoningLevel() } : {},
|
|
14961
14898
|
actor: args.actor,
|
|
14962
|
-
|
|
14899
|
+
surface: args.surface
|
|
14963
14900
|
});
|
|
14964
14901
|
return {
|
|
14965
14902
|
get inputCommitted() {
|
|
@@ -15002,9 +14939,6 @@ function createResumeState(args) {
|
|
|
15002
14939
|
inputCommitted = true;
|
|
15003
14940
|
},
|
|
15004
14941
|
async persistSafeBoundary(messages, trailingMessageProvenance) {
|
|
15005
|
-
if (!canPersistSession) {
|
|
15006
|
-
return false;
|
|
15007
|
-
}
|
|
15008
14942
|
const persisted = await persistRunningSessionRecord({
|
|
15009
14943
|
...sessionRecordBase(),
|
|
15010
14944
|
sliceId: currentSliceId,
|
|
@@ -15025,7 +14959,7 @@ function createResumeState(args) {
|
|
|
15025
14959
|
);
|
|
15026
14960
|
if (!persisted && args.durability.onInputCommitted) {
|
|
15027
14961
|
throw new TurnInputCommitLostError(
|
|
15028
|
-
`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}`
|
|
15029
14963
|
);
|
|
15030
14964
|
}
|
|
15031
14965
|
return persisted;
|
|
@@ -15047,9 +14981,6 @@ function createResumeState(args) {
|
|
|
15047
14981
|
*/
|
|
15048
14982
|
async translateExpectedEnding(args2) {
|
|
15049
14983
|
const { error } = args2;
|
|
15050
|
-
if (!args.sessionConversationId || !args.sessionId) {
|
|
15051
|
-
return {};
|
|
15052
|
-
}
|
|
15053
14984
|
if (cooperativeYieldError && error instanceof CooperativeTurnYieldError) {
|
|
15054
14985
|
const usage = args2.currentUsage ?? extractSliceUsage(resumeMessages, beforeMessageCount);
|
|
15055
14986
|
await args.recordActiveMcpProviders();
|
|
@@ -15063,7 +14994,7 @@ function createResumeState(args) {
|
|
|
15063
14994
|
});
|
|
15064
14995
|
if (!sessionRecord) {
|
|
15065
14996
|
throw new Error(
|
|
15066
|
-
`Failed to persist cooperative yield continuation for conversation=${args.
|
|
14997
|
+
`Failed to persist cooperative yield continuation for conversation=${args.conversationId} turn=${args.turnId}`
|
|
15067
14998
|
);
|
|
15068
14999
|
}
|
|
15069
15000
|
return {
|
|
@@ -15074,20 +15005,25 @@ function createResumeState(args) {
|
|
|
15074
15005
|
}
|
|
15075
15006
|
};
|
|
15076
15007
|
}
|
|
15077
|
-
|
|
15008
|
+
const resumeReason = error instanceof RetryableDeliveryError ? "retry" : timedOut ? "timeout" : void 0;
|
|
15009
|
+
if (resumeReason) {
|
|
15010
|
+
if (resumeReason === "retry") {
|
|
15011
|
+
resumeMessages = [...latestSafeBoundaryMessages];
|
|
15012
|
+
}
|
|
15078
15013
|
const usage = args2.currentUsage ?? extractSliceUsage(resumeMessages, beforeMessageCount);
|
|
15079
15014
|
await args.recordActiveMcpProviders();
|
|
15080
|
-
const sessionRecord = await
|
|
15015
|
+
const sessionRecord = await persistContinuationSessionRecord({
|
|
15081
15016
|
...sessionRecordBase(),
|
|
15082
15017
|
currentSliceId,
|
|
15083
15018
|
currentDurationMs: currentDurationMs(),
|
|
15084
15019
|
currentUsage: usage,
|
|
15085
15020
|
messages: resumeMessages,
|
|
15086
|
-
errorMessage: error instanceof Error ? error.message : String(error)
|
|
15021
|
+
errorMessage: error instanceof Error ? error.message : String(error),
|
|
15022
|
+
resumeReason
|
|
15087
15023
|
});
|
|
15088
15024
|
if (!sessionRecord) {
|
|
15089
15025
|
throw new Error(
|
|
15090
|
-
`Failed to persist
|
|
15026
|
+
`Failed to persist continuation for conversation=${args.conversationId} turn=${args.turnId}`
|
|
15091
15027
|
);
|
|
15092
15028
|
}
|
|
15093
15029
|
if (sessionRecord.state === "awaiting_resume") {
|
|
@@ -15184,10 +15120,6 @@ function userMessage(text) {
|
|
|
15184
15120
|
timestamp: Date.now()
|
|
15185
15121
|
};
|
|
15186
15122
|
}
|
|
15187
|
-
function piMessageTimestamp(message) {
|
|
15188
|
-
const timestamp = message.timestamp;
|
|
15189
|
-
return typeof timestamp === "number" ? timestamp : Date.now();
|
|
15190
|
-
}
|
|
15191
15123
|
function selectRetainedUserMessageEntries(messages, maxTokens = RETAINED_USER_MESSAGE_TOKENS) {
|
|
15192
15124
|
const selected = [];
|
|
15193
15125
|
let remaining = maxTokens;
|
|
@@ -15371,7 +15303,7 @@ async function maybeCompactWithDeps(args, deps) {
|
|
|
15371
15303
|
});
|
|
15372
15304
|
}
|
|
15373
15305
|
async function writeCompactedThreadContext(args, sourceMessages, summary, context) {
|
|
15374
|
-
const
|
|
15306
|
+
const eventStore = getConversationEventStore();
|
|
15375
15307
|
const sourceProjection = await loadConversationProjection({
|
|
15376
15308
|
conversationId: args.conversationId
|
|
15377
15309
|
});
|
|
@@ -15387,15 +15319,21 @@ ${summary}`)
|
|
|
15387
15319
|
retained,
|
|
15388
15320
|
sourceProvenance: sourceProjection.provenance
|
|
15389
15321
|
});
|
|
15390
|
-
await
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
|
|
15395
|
-
|
|
15396
|
-
|
|
15397
|
-
|
|
15398
|
-
|
|
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
|
+
}
|
|
15399
15337
|
});
|
|
15400
15338
|
updateConversationStats(args.conversation);
|
|
15401
15339
|
setSpanAttributes({
|
|
@@ -15430,24 +15368,33 @@ ${await summarizeContext(args, deps)}`;
|
|
|
15430
15368
|
]
|
|
15431
15369
|
};
|
|
15432
15370
|
const messages = [message];
|
|
15371
|
+
const replacementMessages = stripRuntimeTurnContext(messages);
|
|
15433
15372
|
args.signal?.throwIfAborted();
|
|
15434
|
-
await
|
|
15435
|
-
|
|
15436
|
-
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
15440
|
-
|
|
15441
|
-
|
|
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,
|
|
15442
15382
|
provenance: contextProvenance
|
|
15443
|
-
}
|
|
15444
|
-
|
|
15383
|
+
}))
|
|
15384
|
+
}
|
|
15445
15385
|
});
|
|
15446
15386
|
return messages;
|
|
15447
15387
|
}
|
|
15448
15388
|
|
|
15449
15389
|
// src/chat/agent/index.ts
|
|
15450
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
|
+
};
|
|
15451
15398
|
function waitForAbortSettlement(promise, timeoutMs) {
|
|
15452
15399
|
return new Promise((resolve) => {
|
|
15453
15400
|
let done = false;
|
|
@@ -15477,9 +15424,13 @@ function waitForAbortSettlement(promise, timeoutMs) {
|
|
|
15477
15424
|
});
|
|
15478
15425
|
}
|
|
15479
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;
|
|
15480
15431
|
const conversationPrivacy = resolveConversationPrivacy({
|
|
15481
|
-
channelId
|
|
15482
|
-
conversationId: request.
|
|
15432
|
+
channelId,
|
|
15433
|
+
conversationId: request.conversationId,
|
|
15483
15434
|
// Destination visibility is provider-neutral. Slack event context remains
|
|
15484
15435
|
// a compatibility fallback for callers that have not projected it yet.
|
|
15485
15436
|
visibility: request.routing.destinationVisibility ?? request.routing.slackConversation?.visibility
|
|
@@ -15490,18 +15441,15 @@ async function executeAgentRun(request) {
|
|
|
15490
15441
|
);
|
|
15491
15442
|
}
|
|
15492
15443
|
async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
15493
|
-
const { input, routing } = request;
|
|
15444
|
+
const { conversationId, input, routing, runId, turnId } = request;
|
|
15494
15445
|
const policy = request.policy ?? {};
|
|
15495
15446
|
const signal = policy.signal;
|
|
15496
15447
|
const state = request.state ?? {};
|
|
15497
15448
|
const observers = request.observers ?? {};
|
|
15449
|
+
const delivery = request.delivery;
|
|
15498
15450
|
const durability = request.durability ?? {};
|
|
15499
15451
|
signal?.throwIfAborted();
|
|
15500
|
-
|
|
15501
|
-
throw new TypeError("Assistant reply generation requires a destination");
|
|
15502
|
-
}
|
|
15503
|
-
assertActorDestinationMatch(routing);
|
|
15504
|
-
assertCorrelationDestinationMatch(routing);
|
|
15452
|
+
assertRunRoutingConsistency(request);
|
|
15505
15453
|
const replyStartedAtMs = Date.now();
|
|
15506
15454
|
const configuredTurnDeadlineAtMs = replyStartedAtMs + botConfig.turnTimeoutMs;
|
|
15507
15455
|
const policyTurnDeadlineAtMs = typeof policy.turnDeadlineAtMs === "number" && Number.isFinite(policy.turnDeadlineAtMs) ? Math.floor(policy.turnDeadlineAtMs) : void 0;
|
|
@@ -15512,11 +15460,11 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15512
15460
|
let lastKnownSandboxDependencyProfileHash = state.sandbox?.sandboxDependencyProfileHash;
|
|
15513
15461
|
let mcpToolManager;
|
|
15514
15462
|
let connectedMcpProviders = /* @__PURE__ */ new Set();
|
|
15515
|
-
let canRecordMcpProviders = false;
|
|
15516
15463
|
let turnUsage;
|
|
15517
15464
|
let handoffPhaseUsage;
|
|
15518
15465
|
const configuredReasoningLevel = policy.reasoningLevel ?? botConfig.reasoningLevel;
|
|
15519
|
-
let
|
|
15466
|
+
let turnRoute = configuredReasoningLevel ? configuredTurnRoute(
|
|
15467
|
+
STANDARD_MODEL_PROFILE,
|
|
15520
15468
|
configuredReasoningLevel,
|
|
15521
15469
|
policy.reasoningLevel ? "agent_config" : "default"
|
|
15522
15470
|
) : void 0;
|
|
@@ -15525,6 +15473,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15525
15473
|
const actor = actorFromRouting(routing);
|
|
15526
15474
|
const surface = surfaceFromRouting(routing);
|
|
15527
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;
|
|
15528
15479
|
const userInput = input.messageText;
|
|
15529
15480
|
const credentialActor = routing.credentialContext?.actor;
|
|
15530
15481
|
const credentialActorLogContext = credentialActor ? {
|
|
@@ -15532,20 +15483,19 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15532
15483
|
actorId: "type" in credentialActor ? credentialActor.userId : credentialActor.name
|
|
15533
15484
|
} : {};
|
|
15534
15485
|
const sessionRecordLogContext = {
|
|
15535
|
-
threadId:
|
|
15536
|
-
actorId:
|
|
15537
|
-
channelId:
|
|
15538
|
-
runId
|
|
15486
|
+
threadId: slackSource ? conversationId : void 0,
|
|
15487
|
+
actorId: slackActor?.userId,
|
|
15488
|
+
channelId: slackDestination?.channelId,
|
|
15489
|
+
runId,
|
|
15539
15490
|
...credentialActorLogContext,
|
|
15540
15491
|
assistantUserName: botConfig.userName
|
|
15541
15492
|
};
|
|
15542
|
-
const { conversationId: sessionConversationId, sessionId } = getSessionIdentifiers(routing);
|
|
15543
15493
|
const recordConnectedMcpProvider = async (provider) => {
|
|
15544
|
-
if (
|
|
15494
|
+
if (connectedMcpProviders.has(provider)) {
|
|
15545
15495
|
return;
|
|
15546
15496
|
}
|
|
15547
15497
|
await recordMcpProviderConnected({
|
|
15548
|
-
conversationId
|
|
15498
|
+
conversationId,
|
|
15549
15499
|
provider
|
|
15550
15500
|
});
|
|
15551
15501
|
connectedMcpProviders.add(provider);
|
|
@@ -15563,21 +15513,16 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15563
15513
|
sandboxDependencyProfileHash: lastKnownSandboxDependencyProfileHash
|
|
15564
15514
|
});
|
|
15565
15515
|
try {
|
|
15566
|
-
|
|
15567
|
-
|
|
15568
|
-
|
|
15569
|
-
modelId: activeModelId
|
|
15570
|
-
});
|
|
15571
|
-
activeModelProfile = projection.modelProfile;
|
|
15572
|
-
activeModelId = modelIdForProfile(botConfig, activeModelProfile);
|
|
15573
|
-
}
|
|
15516
|
+
const projection = await openConversationProjection({ conversationId });
|
|
15517
|
+
activeModelProfile = projection.modelProfile;
|
|
15518
|
+
activeModelId = modelIdForProfile(botConfig, activeModelProfile);
|
|
15574
15519
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
15575
15520
|
const spanContext = {
|
|
15576
|
-
conversationId
|
|
15577
|
-
slackThreadId:
|
|
15578
|
-
slackUserId:
|
|
15579
|
-
slackChannelId:
|
|
15580
|
-
runId
|
|
15521
|
+
conversationId,
|
|
15522
|
+
slackThreadId: slackSource ? conversationId : void 0,
|
|
15523
|
+
slackUserId: slackActor?.userId,
|
|
15524
|
+
slackChannelId: slackDestination?.channelId,
|
|
15525
|
+
runId,
|
|
15581
15526
|
...credentialActorLogContext,
|
|
15582
15527
|
assistantUserName: botConfig.userName,
|
|
15583
15528
|
modelId: activeModelId
|
|
@@ -15600,7 +15545,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15600
15545
|
// look indistinguishable from Slack ingress dropping attachments.
|
|
15601
15546
|
"app.message.attachment_count": inboundAttachmentCount,
|
|
15602
15547
|
"app.message.prompt_attachment_count": promptAttachmentCount,
|
|
15603
|
-
"messaging.message.id":
|
|
15548
|
+
"messaging.message.id": slackSource?.messageTs ?? ""
|
|
15604
15549
|
},
|
|
15605
15550
|
"Agent message received"
|
|
15606
15551
|
);
|
|
@@ -15618,44 +15563,40 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15618
15563
|
resumedFromSessionRecord,
|
|
15619
15564
|
currentSliceId,
|
|
15620
15565
|
existingSessionRecord
|
|
15621
|
-
} = await restoreSessionRecord(
|
|
15566
|
+
} = await restoreSessionRecord({
|
|
15567
|
+
conversationId,
|
|
15568
|
+
turnId
|
|
15569
|
+
});
|
|
15622
15570
|
const committedInstructionProvenance = [
|
|
15623
15571
|
...existingSessionRecord?.piMessageProvenance ?? [],
|
|
15624
15572
|
...(existingSessionRecord?.actors ?? []).map(instructionProvenanceFor),
|
|
15625
15573
|
...resumedFromSessionRecord ? [] : [instructionProvenanceFor(actor)]
|
|
15626
15574
|
];
|
|
15627
15575
|
const runActors = () => instructionActors(committedInstructionProvenance);
|
|
15628
|
-
canRecordMcpProviders = Boolean(
|
|
15629
|
-
sessionRecordState.canUseTurnSession && sessionConversationId && sessionId
|
|
15630
|
-
);
|
|
15631
15576
|
resume = createResumeState({
|
|
15632
|
-
channelName: routing.
|
|
15577
|
+
channelName: routing.slackConversation?.name,
|
|
15633
15578
|
destination: routing.destination,
|
|
15634
15579
|
durability,
|
|
15635
15580
|
getLoadedSkillNames: () => loadedSkillNamesForResume,
|
|
15636
|
-
getReasoningLevel: () =>
|
|
15581
|
+
getReasoningLevel: () => turnRoute?.reasoningLevel,
|
|
15637
15582
|
logContext: sessionRecordLogContext,
|
|
15638
15583
|
getModelId: () => activeModelId,
|
|
15639
15584
|
recordActiveMcpProviders,
|
|
15640
15585
|
actor,
|
|
15641
15586
|
runSource,
|
|
15642
|
-
|
|
15643
|
-
|
|
15587
|
+
conversationId,
|
|
15588
|
+
turnId,
|
|
15644
15589
|
sessionRecordState,
|
|
15645
15590
|
startedAtMs: replyStartedAtMs,
|
|
15646
15591
|
surface
|
|
15647
15592
|
});
|
|
15648
15593
|
const runResume = resume;
|
|
15649
15594
|
const recordParentToolExecutionStart = async (event) => {
|
|
15650
|
-
if (!sessionRecordState.canUseTurnSession || !sessionConversationId || !sessionId) {
|
|
15651
|
-
return;
|
|
15652
|
-
}
|
|
15653
15595
|
try {
|
|
15654
15596
|
await recordToolExecutionStarted({
|
|
15655
|
-
conversationId
|
|
15597
|
+
conversationId,
|
|
15656
15598
|
toolCallId: event.toolCallId,
|
|
15657
|
-
toolName: event.toolName
|
|
15658
|
-
args: event.args
|
|
15599
|
+
toolName: event.toolName
|
|
15659
15600
|
});
|
|
15660
15601
|
} catch (error) {
|
|
15661
15602
|
logException(
|
|
@@ -15677,9 +15618,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15677
15618
|
};
|
|
15678
15619
|
const priorPiMessages = resumedFromSessionRecord ? existingSessionRecord?.piMessages : input.piMessages;
|
|
15679
15620
|
connectedMcpProviders = new Set(
|
|
15680
|
-
|
|
15681
|
-
conversationId: sessionConversationId
|
|
15682
|
-
}) : []
|
|
15621
|
+
await loadConnectedMcpProviders({ conversationId })
|
|
15683
15622
|
);
|
|
15684
15623
|
await restoreSkillRuntime({
|
|
15685
15624
|
activeSkills,
|
|
@@ -15690,19 +15629,36 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15690
15629
|
});
|
|
15691
15630
|
const { routerBlocks, userContentParts } = buildPromptInput(input);
|
|
15692
15631
|
const preAgentPromptMessages = () => existingSessionRecord?.piMessages ?? [...input.piMessages ?? []];
|
|
15693
|
-
|
|
15694
|
-
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15702
|
-
|
|
15703
|
-
|
|
15704
|
-
|
|
15705
|
-
|
|
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
|
+
}
|
|
15706
15662
|
const generatedFiles = [];
|
|
15707
15663
|
const artifactStatePatch = {};
|
|
15708
15664
|
const toolCalls = [];
|
|
@@ -15711,70 +15667,90 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15711
15667
|
const currentAgentMessages = () => agent ? [...agent.state.messages] : [];
|
|
15712
15668
|
const handoffProfiles = [
|
|
15713
15669
|
DEFAULT_HANDOFF_MODEL_PROFILE,
|
|
15714
|
-
...Object.keys(botConfig.
|
|
15670
|
+
...Object.keys(botConfig.profiles).filter(
|
|
15671
|
+
(profile) => profile !== STANDARD_MODEL_PROFILE && profile !== DEFAULT_HANDOFF_MODEL_PROFILE
|
|
15672
|
+
).sort()
|
|
15715
15673
|
];
|
|
15716
|
-
const
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
},
|
|
15742
|
-
"Failed to report assistant status"
|
|
15743
|
-
);
|
|
15744
|
-
});
|
|
15745
|
-
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
|
+
{},
|
|
15746
15699
|
{
|
|
15747
|
-
|
|
15748
|
-
conversationId: sessionConversationId,
|
|
15749
|
-
piMessages: sourceMessages,
|
|
15750
|
-
runtimeContext,
|
|
15751
|
-
signal: signal2,
|
|
15752
|
-
target,
|
|
15753
|
-
metadata: {
|
|
15754
|
-
threadId: routing.correlation?.threadId,
|
|
15755
|
-
channelId: routing.correlation?.channelId,
|
|
15756
|
-
actorId: routing.correlation?.actorId,
|
|
15757
|
-
runId: routing.correlation?.runId
|
|
15758
|
-
}
|
|
15700
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15759
15701
|
},
|
|
15760
|
-
|
|
15702
|
+
"Failed to report assistant status"
|
|
15761
15703
|
);
|
|
15762
|
-
|
|
15763
|
-
|
|
15764
|
-
|
|
15765
|
-
|
|
15766
|
-
|
|
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}`
|
|
15767
15728
|
};
|
|
15768
|
-
activeModelProfile = profile;
|
|
15769
|
-
activeModelId = target.modelId;
|
|
15770
15729
|
}
|
|
15771
|
-
|
|
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
|
+
};
|
|
15772
15748
|
setTags({
|
|
15773
15749
|
conversationId: spanContext.conversationId,
|
|
15774
|
-
slackThreadId:
|
|
15775
|
-
slackUserId:
|
|
15776
|
-
slackChannelId:
|
|
15777
|
-
runId
|
|
15750
|
+
slackThreadId: slackSource ? conversationId : void 0,
|
|
15751
|
+
slackUserId: slackActor?.userId,
|
|
15752
|
+
slackChannelId: slackDestination?.channelId,
|
|
15753
|
+
runId,
|
|
15778
15754
|
...credentialActorLogContext,
|
|
15779
15755
|
assistantUserName: botConfig.userName,
|
|
15780
15756
|
modelId: activeModelId
|
|
@@ -15804,8 +15780,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15804
15780
|
requestHandoff,
|
|
15805
15781
|
resume: runResume,
|
|
15806
15782
|
routing,
|
|
15807
|
-
|
|
15808
|
-
|
|
15783
|
+
conversationId,
|
|
15784
|
+
turnId,
|
|
15809
15785
|
skillSandbox,
|
|
15810
15786
|
spanContext,
|
|
15811
15787
|
state,
|
|
@@ -15817,9 +15793,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15817
15793
|
mcpToolManager = wiring.mcpToolManager;
|
|
15818
15794
|
const sandboxExecutor = wiring.sandboxExecutor;
|
|
15819
15795
|
const getPendingAuthPause = wiring.getPendingAuthPause;
|
|
15820
|
-
const toolsAfterHandoff = wiring.agentTools
|
|
15821
|
-
(tool) => tool.name !== HANDOFF_TOOL_NAME
|
|
15822
|
-
);
|
|
15796
|
+
const toolsAfterHandoff = wiring.agentTools;
|
|
15823
15797
|
const {
|
|
15824
15798
|
baseInstructions,
|
|
15825
15799
|
inputMessages,
|
|
@@ -15845,42 +15819,52 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15845
15819
|
toolRuntimeContext: wiring.toolRuntimeContext,
|
|
15846
15820
|
userContentParts
|
|
15847
15821
|
});
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
let bufferedStandardMessageStart = false;
|
|
15852
|
-
const startAssistantMessage = () => {
|
|
15853
|
-
Promise.resolve(observers.onAssistantMessageStart?.()).catch((error) => {
|
|
15854
|
-
logWarn(
|
|
15855
|
-
"streaming_message_start_error",
|
|
15856
|
-
{},
|
|
15857
|
-
{
|
|
15858
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15859
|
-
},
|
|
15860
|
-
"Failed to deliver assistant message start to stream coordinator"
|
|
15861
|
-
);
|
|
15862
|
-
});
|
|
15863
|
-
if (hasEmittedText) {
|
|
15864
|
-
needsSeparator = true;
|
|
15822
|
+
const applyPendingHandoff = () => {
|
|
15823
|
+
if (!pendingHandoff) {
|
|
15824
|
+
return void 0;
|
|
15865
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
|
+
};
|
|
15866
15850
|
};
|
|
15867
|
-
|
|
15868
|
-
|
|
15869
|
-
|
|
15870
|
-
|
|
15871
|
-
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15875
|
-
|
|
15876
|
-
|
|
15877
|
-
|
|
15878
|
-
"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
|
|
15879
15862
|
);
|
|
15880
|
-
|
|
15863
|
+
throw assistantMessageDeliveryError;
|
|
15864
|
+
}
|
|
15881
15865
|
};
|
|
15882
15866
|
const drainSteeringMessages = async () => {
|
|
15883
|
-
if (!durability.drainSteeringMessages
|
|
15867
|
+
if (!durability.drainSteeringMessages) {
|
|
15884
15868
|
return;
|
|
15885
15869
|
}
|
|
15886
15870
|
try {
|
|
@@ -15947,33 +15931,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15947
15931
|
return void 0;
|
|
15948
15932
|
},
|
|
15949
15933
|
prepareNextTurn: async () => {
|
|
15950
|
-
|
|
15951
|
-
if (pendingHandoff) {
|
|
15952
|
-
const { messages, model, thinkingLevel } = pendingHandoff;
|
|
15953
|
-
const replacement = [...messages];
|
|
15954
|
-
pendingHandoff = void 0;
|
|
15955
|
-
agent.state.messages = replacement;
|
|
15956
|
-
agent.state.model = model;
|
|
15957
|
-
agent.state.thinkingLevel = thinkingLevel;
|
|
15958
|
-
agent.state.tools = toolsAfterHandoff;
|
|
15959
|
-
runResume.setBeforeMessageCount(replacement.length);
|
|
15960
|
-
runResume.setTurnStartMessageIndex(0);
|
|
15961
|
-
runResume.adoptCommittedBoundary(replacement);
|
|
15962
|
-
setSpanAttributes({
|
|
15963
|
-
"gen_ai.agent.model": activeModelId,
|
|
15964
|
-
"gen_ai.agent.model_profile": activeModelProfile,
|
|
15965
|
-
"gen_ai.agent.reasoning.level": reasoningSelection.reasoningLevel
|
|
15966
|
-
});
|
|
15967
|
-
update = {
|
|
15968
|
-
context: {
|
|
15969
|
-
systemPrompt: baseInstructions,
|
|
15970
|
-
messages: replacement,
|
|
15971
|
-
tools: toolsAfterHandoff
|
|
15972
|
-
},
|
|
15973
|
-
model,
|
|
15974
|
-
thinkingLevel
|
|
15975
|
-
};
|
|
15976
|
-
}
|
|
15934
|
+
const update = applyPendingHandoff();
|
|
15977
15935
|
await drainSteeringMessages();
|
|
15978
15936
|
runResume.yieldAtSafeBoundaryIfDue(currentAgentMessages());
|
|
15979
15937
|
return update;
|
|
@@ -15981,7 +15939,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15981
15939
|
initialState: {
|
|
15982
15940
|
systemPrompt: baseInstructions,
|
|
15983
15941
|
model: resolveGatewayModel(activeModelId),
|
|
15984
|
-
thinkingLevel: toPiReasoningLevel(
|
|
15942
|
+
thinkingLevel: toPiReasoningLevel(turnRoute.reasoningLevel),
|
|
15985
15943
|
tools: wiring.agentTools
|
|
15986
15944
|
}
|
|
15987
15945
|
});
|
|
@@ -15995,40 +15953,17 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15995
15953
|
}
|
|
15996
15954
|
return runResume.persistSafeBoundary([...agent.state.messages]).then(() => void 0);
|
|
15997
15955
|
}
|
|
15998
|
-
if (event.type === "message_start") {
|
|
15999
|
-
if (activeModelProfile === STANDARD_MODEL_PROFILE && requestHandoff) {
|
|
16000
|
-
bufferedStandardMessageStart = true;
|
|
16001
|
-
bufferedStandardText = "";
|
|
16002
|
-
} else {
|
|
16003
|
-
startAssistantMessage();
|
|
16004
|
-
}
|
|
16005
|
-
return;
|
|
16006
|
-
}
|
|
16007
15956
|
if (event.type === "message_end" && isAssistantMessage(event.message)) {
|
|
16008
|
-
if (
|
|
15957
|
+
if (event.message.stopReason === "error" || event.message.stopReason === "aborted") {
|
|
16009
15958
|
return;
|
|
16010
15959
|
}
|
|
16011
15960
|
const containsHandoff = event.message.content.some(
|
|
16012
15961
|
(part) => part.type === "toolCall" && part.name === HANDOFF_TOOL_NAME
|
|
16013
15962
|
);
|
|
16014
|
-
if (
|
|
16015
|
-
|
|
16016
|
-
if (bufferedStandardText) {
|
|
16017
|
-
deliverText(bufferedStandardText);
|
|
16018
|
-
}
|
|
15963
|
+
if (containsHandoff) {
|
|
15964
|
+
return;
|
|
16019
15965
|
}
|
|
16020
|
-
|
|
16021
|
-
bufferedStandardText = "";
|
|
16022
|
-
return;
|
|
16023
|
-
}
|
|
16024
|
-
if (event.type !== "message_update") return;
|
|
16025
|
-
if (event.assistantMessageEvent.type !== "text_delta") return;
|
|
16026
|
-
const deltaText = event.assistantMessageEvent.delta;
|
|
16027
|
-
if (!deltaText) return;
|
|
16028
|
-
if (bufferedStandardMessageStart) {
|
|
16029
|
-
bufferedStandardText += deltaText;
|
|
16030
|
-
} else {
|
|
16031
|
-
deliverText(deltaText);
|
|
15966
|
+
return deliverAssistantMessage(event.message);
|
|
16032
15967
|
}
|
|
16033
15968
|
});
|
|
16034
15969
|
let newMessages = [];
|
|
@@ -16064,13 +15999,13 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16064
15999
|
await runResume.commitInput();
|
|
16065
16000
|
}
|
|
16066
16001
|
}
|
|
16067
|
-
const runAgentStep = async (run2) => {
|
|
16002
|
+
const runAgentStep = async (run2, abortRun = () => agent.abort()) => {
|
|
16068
16003
|
let timeoutId;
|
|
16069
16004
|
let removeAbortListener;
|
|
16070
16005
|
const timeoutPromise = new Promise((_, reject) => {
|
|
16071
16006
|
const rejectWithTimeout = () => {
|
|
16072
16007
|
runResume.markTimedOut();
|
|
16073
|
-
|
|
16008
|
+
abortRun();
|
|
16074
16009
|
reject(
|
|
16075
16010
|
new Error(
|
|
16076
16011
|
`Agent turn timed out after ${turnTimeoutBudgetMs}ms`
|
|
@@ -16086,7 +16021,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16086
16021
|
});
|
|
16087
16022
|
const abortPromise = signal ? new Promise((_, reject) => {
|
|
16088
16023
|
const rejectWithAbort = () => {
|
|
16089
|
-
|
|
16024
|
+
abortRun();
|
|
16090
16025
|
reject(signal.reason);
|
|
16091
16026
|
};
|
|
16092
16027
|
if (signal.aborted) {
|
|
@@ -16111,8 +16046,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16111
16046
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
16112
16047
|
"gen_ai.operation.name": "invoke_agent",
|
|
16113
16048
|
"gen_ai.request.model": activeModelId,
|
|
16114
|
-
...
|
|
16115
|
-
"gen_ai.request.reasoning.level":
|
|
16049
|
+
...turnRoute ? {
|
|
16050
|
+
"gen_ai.request.reasoning.level": turnRoute.reasoningLevel
|
|
16116
16051
|
} : {},
|
|
16117
16052
|
"app.ai.turn_timeout_ms": turnTimeoutBudgetMs,
|
|
16118
16053
|
"app.ai.turn_deadline_remaining_ms": Math.max(
|
|
@@ -16154,10 +16089,38 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16154
16089
|
removeAbortListener?.();
|
|
16155
16090
|
}
|
|
16156
16091
|
};
|
|
16157
|
-
|
|
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
|
+
}
|
|
16158
16118
|
let retryUsage;
|
|
16159
16119
|
for (let attempt = 0; ; attempt += 1) {
|
|
16160
16120
|
await runAgentStep(run);
|
|
16121
|
+
if (assistantMessageDeliveryError) {
|
|
16122
|
+
throw assistantMessageDeliveryError;
|
|
16123
|
+
}
|
|
16161
16124
|
signal?.throwIfAborted();
|
|
16162
16125
|
if (runResume.cooperativeYieldError) {
|
|
16163
16126
|
throw runResume.cooperativeYieldError;
|
|
@@ -16222,15 +16185,15 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16222
16185
|
"gen_ai.operation.name": "invoke_agent",
|
|
16223
16186
|
"gen_ai.agent.model": activeModelId,
|
|
16224
16187
|
"gen_ai.agent.model_profile": activeModelProfile,
|
|
16225
|
-
"gen_ai.agent.reasoning.level":
|
|
16226
|
-
"gen_ai.agent.reasoning.level_reason":
|
|
16227
|
-
...
|
|
16228
|
-
"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
|
|
16229
16192
|
} : {},
|
|
16230
16193
|
"gen_ai.output.type": "text",
|
|
16231
16194
|
...conversationPrivacy ? { "app.conversation.privacy": conversationPrivacy } : {},
|
|
16232
|
-
|
|
16233
|
-
|
|
16195
|
+
"app.ai.session.conversation_id": conversationId,
|
|
16196
|
+
"app.ai.turn.session_id": turnId,
|
|
16234
16197
|
...currentSliceId ? { "app.ai.turn.slice_id": currentSliceId } : {},
|
|
16235
16198
|
...toGenAiMessagesTraceAttributes("gen_ai.input", inputMessages),
|
|
16236
16199
|
...inputMessagesAttribute ? { "gen_ai.input.messages": inputMessagesAttribute } : {}
|
|
@@ -16239,40 +16202,45 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16239
16202
|
} finally {
|
|
16240
16203
|
unsubscribe();
|
|
16241
16204
|
}
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
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
|
+
});
|
|
16245
16223
|
return {
|
|
16246
16224
|
status: "completed",
|
|
16247
|
-
result
|
|
16248
|
-
newMessages,
|
|
16249
|
-
userInput,
|
|
16250
|
-
artifactStatePatch,
|
|
16251
|
-
toolCalls,
|
|
16252
|
-
sandboxId: sandboxExecutor.getSandboxId(),
|
|
16253
|
-
sandboxDependencyProfileHash: sandboxExecutor.getDependencyProfileHash(),
|
|
16254
|
-
piMessages: [...agent.state.messages],
|
|
16255
|
-
durationMs: Date.now() - replyStartedAtMs,
|
|
16256
|
-
generatedFileCount: generatedFiles.length,
|
|
16257
|
-
shouldTrace,
|
|
16258
|
-
spanContext,
|
|
16259
|
-
usage: turnUsage,
|
|
16260
|
-
reasoningSelection,
|
|
16261
|
-
correlation: routing.correlation,
|
|
16262
|
-
assistantUserName: botConfig.userName,
|
|
16263
|
-
modelId: activeModelId
|
|
16264
|
-
})
|
|
16225
|
+
result
|
|
16265
16226
|
};
|
|
16266
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;
|
|
16267
16232
|
if (resume) {
|
|
16268
16233
|
const { outcome } = await resume.translateExpectedEnding({
|
|
16269
16234
|
currentUsage: turnUsage,
|
|
16270
|
-
error
|
|
16235
|
+
error: runError
|
|
16271
16236
|
});
|
|
16272
16237
|
if (outcome) {
|
|
16273
16238
|
return outcome;
|
|
16274
16239
|
}
|
|
16275
16240
|
}
|
|
16241
|
+
if (error instanceof AssistantMessageDeliveryError) {
|
|
16242
|
+
throw error.originalError;
|
|
16243
|
+
}
|
|
16276
16244
|
if (error instanceof ModelProfileNotConfiguredError) {
|
|
16277
16245
|
throw error;
|
|
16278
16246
|
}
|
|
@@ -16292,10 +16260,11 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16292
16260
|
error,
|
|
16293
16261
|
"assistant_reply_generation_failed",
|
|
16294
16262
|
{
|
|
16295
|
-
|
|
16296
|
-
|
|
16297
|
-
|
|
16298
|
-
|
|
16263
|
+
conversationId,
|
|
16264
|
+
slackThreadId: slackSource ? conversationId : void 0,
|
|
16265
|
+
slackUserId: slackActor?.userId,
|
|
16266
|
+
slackChannelId: slackDestination?.channelId,
|
|
16267
|
+
runId,
|
|
16299
16268
|
...credentialActorLogContext,
|
|
16300
16269
|
assistantUserName: botConfig.userName,
|
|
16301
16270
|
modelId: activeModelId
|
|
@@ -16313,8 +16282,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
16313
16282
|
outcome: "provider_error",
|
|
16314
16283
|
modelId: activeModelId,
|
|
16315
16284
|
assistantMessageCount: 0,
|
|
16316
|
-
...
|
|
16317
|
-
reasoningLevel:
|
|
16285
|
+
...turnRoute ? {
|
|
16286
|
+
reasoningLevel: turnRoute.reasoningLevel
|
|
16318
16287
|
} : {},
|
|
16319
16288
|
toolCalls: [],
|
|
16320
16289
|
toolResultCount: 0,
|
|
@@ -16364,6 +16333,7 @@ export {
|
|
|
16364
16333
|
getConfigDefaults,
|
|
16365
16334
|
shouldEmitDevAgentTrace,
|
|
16366
16335
|
AuthorizationFlowDisabledError,
|
|
16336
|
+
RetryableDeliveryError,
|
|
16367
16337
|
truncateStatusText,
|
|
16368
16338
|
escapeSlackMrkdwnText,
|
|
16369
16339
|
formatSlackLink,
|