@sentry/junior 0.95.0 → 0.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{agent-hooks-FTQ5EGPO.js → agent-hooks-XSUIVRQS.js} +10 -8
- package/dist/{reporting → api}/conversations/activity.d.ts +1 -1
- package/dist/api/conversations/detail-projection.d.ts +10 -0
- package/dist/api/conversations/detail.d.ts +3 -0
- package/dist/api/conversations/detail.query.d.ts +3 -0
- package/dist/api/conversations/list.d.ts +3 -0
- package/dist/api/conversations/list.query.d.ts +94 -0
- package/dist/api/conversations/projection.d.ts +14 -0
- package/dist/api/conversations/schema.d.ts +683 -0
- package/dist/{reporting → api}/conversations/shared.d.ts +1 -5
- package/dist/api/conversations/stats.d.ts +3 -0
- package/dist/api/conversations/stats.query.d.ts +3 -0
- package/dist/api/conversations/subagent.d.ts +3 -0
- package/dist/{reporting → api}/conversations/transcript.d.ts +4 -4
- package/dist/api/people/list.d.ts +1 -2
- package/dist/api/people/list.query.d.ts +3 -4
- package/dist/api/people/profile.d.ts +1 -2
- package/dist/api/people/profile.query.d.ts +3 -4
- package/dist/api/people/schema.d.ts +193 -0
- package/dist/api/people/shared.d.ts +31 -9
- package/dist/api/schema.d.ts +20 -0
- package/dist/api/schema.js +50 -0
- package/dist/api-reference.d.ts +4 -3
- package/dist/api.d.ts +3 -0
- package/dist/api.js +156 -0
- package/dist/app.d.ts +1 -4
- package/dist/app.js +108 -370
- package/dist/build/virtual-config.d.ts +2 -2
- package/dist/{catalog-runtime-2D7IVKUT.js → catalog-runtime-PFHVMHDR.js} +5 -4
- package/dist/chat/agent/resume.d.ts +3 -1
- package/dist/chat/agent/tools.d.ts +2 -1
- package/dist/chat/config.d.ts +1 -8
- package/dist/chat/conversations/history.d.ts +241 -27
- package/dist/chat/conversations/legacy-advisor-session.d.ts +7 -0
- package/dist/chat/conversations/legacy-import.d.ts +2 -2
- package/dist/chat/conversations/projection.d.ts +19 -3
- package/dist/chat/conversations/sql/legacy-history-import.d.ts +1 -1
- package/dist/chat/conversations/sql/store.d.ts +15 -9
- package/dist/chat/conversations/store.d.ts +9 -4
- package/dist/chat/logging.d.ts +2 -2
- package/dist/chat/model-profile.d.ts +14 -0
- package/dist/chat/pi/transcript.d.ts +5 -3
- package/dist/chat/plugins/auth/oauth-request.d.ts +2 -0
- package/dist/chat/resource-events/notification.d.ts +2 -0
- package/dist/chat/resource-events/store.d.ts +2 -2
- package/dist/chat/runtime/agent-run-outcome.d.ts +3 -0
- package/dist/chat/sentry.d.ts +1 -1
- package/dist/chat/services/context-compaction.d.ts +15 -0
- package/dist/chat/services/turn-result.d.ts +1 -0
- package/dist/chat/services/turn-session-record.d.ts +6 -6
- package/dist/chat/state/turn-session.d.ts +18 -5
- package/dist/chat/task-execution/store.d.ts +2 -2
- package/dist/chat/tools/handoff/tool.d.ts +45 -0
- package/dist/chat/tools/types.d.ts +7 -2
- package/dist/chat/usage.d.ts +27 -13
- package/dist/{chunk-6ONME5IG.js → chunk-35BNLDOJ.js} +339 -578
- package/dist/{chunk-HDTO3A74.js → chunk-3ECW2K2O.js} +8 -3
- package/dist/{chunk-CRRBJ3JP.js → chunk-3F4OPKGF.js} +90 -56
- package/dist/chunk-3V7OFJZC.js +264 -0
- package/dist/chunk-4ZNGQH7C.js +25 -0
- package/dist/{chunk-NSCHU54X.js → chunk-5HLDPVYS.js} +15 -448
- package/dist/{chunk-3DA7X2U3.js → chunk-6GWA276C.js} +15 -0
- package/dist/{chunk-HZNJLKKI.js → chunk-6U26PYI5.js} +24 -14
- package/dist/chunk-AUUCAFDE.js +546 -0
- package/dist/{chunk-6APU57E6.js → chunk-B3IT5END.js} +41 -260
- package/dist/chunk-CEA3A3UA.js +86 -0
- package/dist/{chunk-AYP4ERVZ.js → chunk-D5KZYS4T.js} +1 -1
- package/dist/{chunk-GUE7HTNR.js → chunk-EEZCY5WX.js} +79 -29
- package/dist/{chunk-E3E2XNCN.js → chunk-EOWXRY5E.js} +2 -2
- package/dist/{chunk-5XMNOD3S.js → chunk-FBHZJFHI.js} +3 -3
- package/dist/{chunk-CZEX6KIQ.js → chunk-G3E7SCME.js} +0 -23
- package/dist/chunk-GUAP3H7O.js +319 -0
- package/dist/{chunk-WCMQJE4F.js → chunk-H66UCBPW.js} +7 -5
- package/dist/{chunk-WPOJ443W.js → chunk-I35CTGPO.js} +58 -6
- package/dist/{chunk-GVOUCI2O.js → chunk-LMJPRYHP.js} +16 -6
- package/dist/chunk-LUAE4MGW.js +199 -0
- package/dist/{chunk-GY34VGP5.js → chunk-LVA4I4H7.js} +3 -1
- package/dist/chunk-LVUKF5CE.js +63 -0
- package/dist/{chunk-EKNJM5IG.js → chunk-NG2AV7IB.js} +2 -72
- package/dist/chunk-ON6YKIQ7.js +260 -0
- package/dist/chunk-PDO5BLNM.js +22 -0
- package/dist/chunk-QNVHH5PU.js +20 -0
- package/dist/{chunk-XX4N4E6C.js → chunk-T533JLM3.js} +9 -11
- package/dist/chunk-UAMKJPDF.js +11 -0
- package/dist/chunk-VFH4ZKZT.js +66 -0
- package/dist/{chunk-KDPCGVIT.js → chunk-WGXMTFNU.js} +17 -75
- package/dist/{chunk-WAGQ377B.js → chunk-WJOSZOON.js} +288 -263
- package/dist/chunk-WTYEKPXU.js +451 -0
- package/dist/{chunk-HCXXB35T.js → chunk-XIRPQQVE.js} +613 -369
- package/dist/cli/chat.js +26 -23
- package/dist/cli/check.js +6 -5
- package/dist/cli/init.js +12 -0
- package/dist/cli/main.js +1 -1
- package/dist/cli/plugins.js +14 -11
- package/dist/cli/snapshot-warmup.js +10 -8
- package/dist/cli/upgrade.js +267 -139
- package/dist/db/db.d.ts +4 -0
- package/dist/db/schema/conversations.d.ts +128 -0
- package/dist/db/schema.d.ts +129 -60
- package/dist/{db-W55B74OP.js → db-BWXYIKFQ.js} +5 -5
- package/dist/detail-GA6NXWQJ.js +43 -0
- package/dist/discovery-RMHYSRL7.js +43 -0
- package/dist/handlers/health.d.ts +3 -0
- package/dist/instrumentation.js +2 -2
- package/dist/{legacy-import-ZPLGLAFD.js → legacy-import-3NQJVGQL.js} +6 -6
- package/dist/{api/people/list.js → list-A3WFRIYX.js} +26 -16
- package/dist/list-UXJI5Q5X.js +27 -0
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +2 -1
- package/dist/plugin-conversations-DDNGC35A.js +36 -0
- package/dist/{api/people/profile.js → profile-4RYDXWTF.js} +33 -18
- package/dist/reporting/plugin-conversations.d.ts +3 -0
- package/dist/reporting-schema.d.ts +140 -0
- package/dist/reporting.d.ts +12 -81
- package/dist/{runner-OOSBDYRK.js → runner-JALSYH2P.js} +19 -14
- package/dist/{sentry-EGFOV3DH.js → sentry-JMWTS32N.js} +11 -1
- package/dist/skills-MAZXZ2KE.js +26 -0
- package/dist/stats-XKXH3PTY.js +217 -0
- package/dist/subagent-TZ55XY37.js +48 -0
- package/dist/usage-schema.d.ts +25 -0
- package/dist/{validation-QCGRFRFZ.js → validation-FMEAEKCY.js} +6 -5
- package/migrations/0000_initial.sql +115 -0
- package/migrations/0001_conversation_metrics.sql +4 -0
- package/migrations/README.md +12 -30
- package/migrations/meta/0000_snapshot.json +1 -33
- package/migrations/meta/0001_snapshot.json +972 -0
- package/migrations/meta/_journal.json +9 -2
- package/package.json +14 -18
- package/dist/api/people/types.d.ts +0 -85
- package/dist/chat/advisor-request.d.ts +0 -4
- package/dist/chat/conversations/sql/migrations.d.ts +0 -22
- package/dist/chat/tools/advisor/session-store.d.ts +0 -9
- package/dist/chat/tools/advisor/tool.d.ts +0 -72
- package/dist/chunk-N4RNJ32C.js +0 -48
- package/dist/chunk-RAIB6WSG.js +0 -142
- package/dist/db/schema/migrations.d.ts +0 -58
- package/dist/reporting/conversations/context.d.ts +0 -8
- package/dist/reporting/conversations/details.d.ts +0 -6
- package/dist/reporting/conversations/index.d.ts +0 -4
- package/dist/reporting/conversations/statistics.d.ts +0 -4
- package/dist/reporting/conversations/summaries.d.ts +0 -17
- package/dist/reporting/conversations/types.d.ts +0 -178
- package/dist/reporting/conversations.d.ts +0 -1
- package/dist/reporting.js +0 -1065
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CooperativeTurnYieldError,
|
|
3
3
|
TurnInputCommitLostError,
|
|
4
|
-
addAgentTurnUsage,
|
|
5
4
|
canReusePendingAuthLink,
|
|
6
5
|
getInterruptionMarker,
|
|
7
|
-
hasAgentTurnUsage,
|
|
8
6
|
isTurnInputCommitLostError,
|
|
9
7
|
loadTurnSessionRecord,
|
|
10
8
|
mergeArtifactsState,
|
|
@@ -12,7 +10,25 @@ import {
|
|
|
12
10
|
persistRunningSessionRecord,
|
|
13
11
|
persistTimeoutSessionRecord,
|
|
14
12
|
persistYieldSessionRecord
|
|
15
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WGXMTFNU.js";
|
|
14
|
+
import {
|
|
15
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
16
|
+
addAgentTurnUsage,
|
|
17
|
+
hasAgentTurnUsage
|
|
18
|
+
} from "./chunk-WJOSZOON.js";
|
|
19
|
+
import {
|
|
20
|
+
loadConnectedMcpProviders,
|
|
21
|
+
loadConversationProjection,
|
|
22
|
+
openConversationProjection,
|
|
23
|
+
recordAuthorizationRequested,
|
|
24
|
+
recordMcpProviderConnected,
|
|
25
|
+
recordToolExecutionStarted
|
|
26
|
+
} from "./chunk-GUAP3H7O.js";
|
|
27
|
+
import {
|
|
28
|
+
estimateTextTokens,
|
|
29
|
+
getAgentContextCompactionTriggerTokens,
|
|
30
|
+
updateConversationStats
|
|
31
|
+
} from "./chunk-3F4OPKGF.js";
|
|
16
32
|
import {
|
|
17
33
|
buildNonInteractiveShellScript,
|
|
18
34
|
createSandboxInstance,
|
|
@@ -22,64 +38,58 @@ import {
|
|
|
22
38
|
isSnapshotMissingError,
|
|
23
39
|
resolveRuntimeDependencySnapshot,
|
|
24
40
|
runNonInteractiveCommand
|
|
25
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-H66UCBPW.js";
|
|
26
42
|
import {
|
|
27
43
|
privateTraceResultAttributes
|
|
28
44
|
} from "./chunk-CM5EZD5F.js";
|
|
29
45
|
import {
|
|
30
|
-
renderAdvisorRequest
|
|
31
|
-
} from "./chunk-N4RNJ32C.js";
|
|
32
|
-
import {
|
|
33
|
-
commitMessages,
|
|
34
|
-
loadConnectedMcpProviders,
|
|
35
|
-
loadProjection,
|
|
36
|
-
recordAuthorizationRequested,
|
|
37
|
-
recordMcpProviderConnected,
|
|
38
|
-
recordToolExecutionStarted
|
|
39
|
-
} from "./chunk-WAGQ377B.js";
|
|
40
|
-
import {
|
|
41
|
-
JUNIOR_THREAD_STATE_TTL_MS
|
|
42
|
-
} from "./chunk-CRRBJ3JP.js";
|
|
43
|
-
import {
|
|
44
|
-
SlackActionError,
|
|
45
46
|
createPluginHookRunner,
|
|
46
|
-
downloadPrivateSlackFile,
|
|
47
|
-
getFilePermalink,
|
|
48
47
|
getPluginSystemPromptContributions,
|
|
49
48
|
getPluginTools,
|
|
50
49
|
getPluginUserPromptContributions,
|
|
51
50
|
getPlugins,
|
|
52
|
-
getSlackClient,
|
|
53
51
|
getSlackToolContext,
|
|
52
|
+
resolveChannelCapabilities
|
|
53
|
+
} from "./chunk-5HLDPVYS.js";
|
|
54
|
+
import {
|
|
55
|
+
SlackActionError,
|
|
56
|
+
downloadPrivateSlackFile,
|
|
57
|
+
getFilePermalink,
|
|
58
|
+
getSlackClient,
|
|
54
59
|
isConversationScopedChannel,
|
|
55
60
|
isDmChannel,
|
|
56
61
|
normalizeSlackConversationId,
|
|
57
|
-
resolveChannelCapabilities,
|
|
58
62
|
withSlackRetries
|
|
59
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-WTYEKPXU.js";
|
|
60
64
|
import {
|
|
61
65
|
createPluginLogger
|
|
62
|
-
} from "./chunk-
|
|
63
|
-
import {
|
|
64
|
-
SANDBOX_DATA_ROOT,
|
|
65
|
-
SANDBOX_SKILLS_ROOT,
|
|
66
|
-
SANDBOX_WORKSPACE_ROOT,
|
|
67
|
-
sandboxSkillDir,
|
|
68
|
-
sandboxSkillFile,
|
|
69
|
-
sleep
|
|
70
|
-
} from "./chunk-CZEX6KIQ.js";
|
|
66
|
+
} from "./chunk-EOWXRY5E.js";
|
|
71
67
|
import {
|
|
68
|
+
contextProvenance,
|
|
72
69
|
getAgentStepStore,
|
|
73
70
|
getConversationStore,
|
|
74
71
|
getDb,
|
|
75
72
|
instructionActors,
|
|
76
73
|
instructionProvenanceFor
|
|
77
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-35BNLDOJ.js";
|
|
78
75
|
import {
|
|
76
|
+
SANDBOX_DATA_ROOT,
|
|
77
|
+
SANDBOX_SKILLS_ROOT,
|
|
78
|
+
SANDBOX_WORKSPACE_ROOT,
|
|
79
|
+
sandboxSkillDir,
|
|
80
|
+
sandboxSkillFile
|
|
81
|
+
} from "./chunk-G3E7SCME.js";
|
|
82
|
+
import {
|
|
83
|
+
sleep
|
|
84
|
+
} from "./chunk-4ZNGQH7C.js";
|
|
85
|
+
import {
|
|
86
|
+
DEFAULT_HANDOFF_MODEL_PROFILE,
|
|
79
87
|
GEN_AI_PROVIDER_NAME,
|
|
80
88
|
GEN_AI_SERVER_ADDRESS,
|
|
81
89
|
GEN_AI_SERVER_PORT,
|
|
82
90
|
MISSING_GATEWAY_CREDENTIALS_ERROR,
|
|
91
|
+
ModelProfileNotConfiguredError,
|
|
92
|
+
STANDARD_MODEL_PROFILE,
|
|
83
93
|
TURN_CONTEXT_TAG,
|
|
84
94
|
acquireActiveLock,
|
|
85
95
|
botConfig,
|
|
@@ -96,13 +106,17 @@ import {
|
|
|
96
106
|
isProviderRetryError,
|
|
97
107
|
isToolResultError,
|
|
98
108
|
isToolResultMessage,
|
|
109
|
+
modelIdForProfile,
|
|
99
110
|
nextProviderRetry,
|
|
100
111
|
normalizeSlackEmojiName,
|
|
101
112
|
normalizeToolNameFromResult,
|
|
102
113
|
renderCurrentInstruction,
|
|
103
114
|
resolveGatewayModel,
|
|
104
|
-
|
|
105
|
-
|
|
115
|
+
retainRuntimeTurnContext,
|
|
116
|
+
stripRuntimeTurnContext,
|
|
117
|
+
trimTrailingAssistantMessages,
|
|
118
|
+
unwrapCurrentInstruction
|
|
119
|
+
} from "./chunk-EEZCY5WX.js";
|
|
106
120
|
import {
|
|
107
121
|
parseSlackThreadId,
|
|
108
122
|
resolveConversationPrivacy,
|
|
@@ -114,7 +128,7 @@ import {
|
|
|
114
128
|
toGenAiPayloadMetadata,
|
|
115
129
|
toGenAiPayloadTraceAttributes,
|
|
116
130
|
toGenAiTextMetadata
|
|
117
|
-
} from "./chunk-
|
|
131
|
+
} from "./chunk-LVA4I4H7.js";
|
|
118
132
|
import {
|
|
119
133
|
parseDestination
|
|
120
134
|
} from "./chunk-B7PUBQQM.js";
|
|
@@ -123,14 +137,14 @@ import {
|
|
|
123
137
|
findSkillByName,
|
|
124
138
|
loadSkillsByName,
|
|
125
139
|
parseSkillInvocation
|
|
126
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-3ECW2K2O.js";
|
|
127
141
|
import {
|
|
128
142
|
CredentialUnavailableError,
|
|
129
143
|
credentialContextSchema,
|
|
130
144
|
pluginCatalogRuntime,
|
|
131
145
|
resolveAuthTokenPlaceholder,
|
|
132
146
|
resolvePluginCommandEnv
|
|
133
|
-
} from "./chunk-
|
|
147
|
+
} from "./chunk-LMJPRYHP.js";
|
|
134
148
|
import {
|
|
135
149
|
createActor,
|
|
136
150
|
extractGenAiUsageAttributes,
|
|
@@ -149,24 +163,24 @@ import {
|
|
|
149
163
|
setTags,
|
|
150
164
|
summarizeMessageText,
|
|
151
165
|
withSpan
|
|
152
|
-
} from "./chunk-
|
|
166
|
+
} from "./chunk-I35CTGPO.js";
|
|
153
167
|
import {
|
|
154
168
|
isRecord
|
|
155
169
|
} from "./chunk-OB42YVAE.js";
|
|
156
170
|
import {
|
|
157
171
|
startInactiveSpan,
|
|
158
172
|
withActiveSpan
|
|
159
|
-
} from "./chunk-
|
|
160
|
-
import {
|
|
161
|
-
listReferenceFiles,
|
|
162
|
-
soulPathCandidates,
|
|
163
|
-
worldPathCandidates
|
|
164
|
-
} from "./chunk-6APU57E6.js";
|
|
173
|
+
} from "./chunk-6GWA276C.js";
|
|
165
174
|
import {
|
|
166
175
|
parseSlackChannelId,
|
|
167
176
|
parseSlackMessageTs,
|
|
168
177
|
parseSlackUserId
|
|
169
178
|
} from "./chunk-7FBGKXPE.js";
|
|
179
|
+
import {
|
|
180
|
+
listReferenceFiles,
|
|
181
|
+
soulPathCandidates,
|
|
182
|
+
worldPathCandidates
|
|
183
|
+
} from "./chunk-3V7OFJZC.js";
|
|
170
184
|
|
|
171
185
|
// src/chat/configuration/defaults.ts
|
|
172
186
|
var installDefaults = {};
|
|
@@ -249,7 +263,7 @@ function shouldPropagateSandboxEgressTrace(host, config = {}) {
|
|
|
249
263
|
}
|
|
250
264
|
|
|
251
265
|
// src/chat/agent/index.ts
|
|
252
|
-
import { Agent
|
|
266
|
+
import { Agent } from "@earendil-works/pi-agent-core";
|
|
253
267
|
|
|
254
268
|
// src/chat/sandbox/skill-sandbox.ts
|
|
255
269
|
import fs from "fs/promises";
|
|
@@ -672,7 +686,8 @@ function buildTurnResult(input) {
|
|
|
672
686
|
usage,
|
|
673
687
|
thinkingSelection,
|
|
674
688
|
correlation,
|
|
675
|
-
assistantUserName
|
|
689
|
+
assistantUserName,
|
|
690
|
+
modelId
|
|
676
691
|
} = input;
|
|
677
692
|
const toolResults = newMessages.filter(isToolResultMessage);
|
|
678
693
|
const assistantMessages = newMessages.filter(isAssistantMessage);
|
|
@@ -709,7 +724,7 @@ function buildTurnResult(input) {
|
|
|
709
724
|
slackChannelId: correlation?.channelId,
|
|
710
725
|
runId: correlation?.runId,
|
|
711
726
|
assistantUserName,
|
|
712
|
-
modelId
|
|
727
|
+
modelId
|
|
713
728
|
};
|
|
714
729
|
const markerAttributes = {
|
|
715
730
|
"app.ai.no_reply_marker": true,
|
|
@@ -733,7 +748,7 @@ function buildTurnResult(input) {
|
|
|
733
748
|
slackChannelId: correlation?.channelId,
|
|
734
749
|
runId: correlation?.runId,
|
|
735
750
|
assistantUserName,
|
|
736
|
-
modelId
|
|
751
|
+
modelId
|
|
737
752
|
},
|
|
738
753
|
{
|
|
739
754
|
"app.ai.no_reply_marker": true,
|
|
@@ -751,7 +766,7 @@ function buildTurnResult(input) {
|
|
|
751
766
|
slackChannelId: correlation?.channelId,
|
|
752
767
|
runId: correlation?.runId,
|
|
753
768
|
assistantUserName,
|
|
754
|
-
modelId
|
|
769
|
+
modelId
|
|
755
770
|
},
|
|
756
771
|
{
|
|
757
772
|
"app.ai.tool_results": toolResults.length,
|
|
@@ -797,7 +812,7 @@ function buildTurnResult(input) {
|
|
|
797
812
|
}
|
|
798
813
|
const resolvedDiagnostics = {
|
|
799
814
|
outcome: resolvedOutcome,
|
|
800
|
-
modelId
|
|
815
|
+
modelId,
|
|
801
816
|
assistantMessageCount: assistantMessages.length,
|
|
802
817
|
thinkingLevel: thinkingSelection.thinkingLevel,
|
|
803
818
|
toolCalls,
|
|
@@ -2031,6 +2046,7 @@ var LOCAL_HEADER = "You are a helper assistant. Follow the personality section f
|
|
|
2031
2046
|
var TURN_CONTEXT_HEADER = "Runtime context for this request. Treat these blocks as trusted runtime facts; the static system prompt remains authoritative.";
|
|
2032
2047
|
var TOOL_POLICY_RULES = [
|
|
2033
2048
|
"- 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.",
|
|
2049
|
+
"- 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.",
|
|
2034
2050
|
"- 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.",
|
|
2035
2051
|
"- Resolve provider action targets before calls: explicit target wins; ambient `<configuration>` fills omitted targets. Treat non-target links/references as context.",
|
|
2036
2052
|
"- 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.",
|
|
@@ -2062,7 +2078,6 @@ var EXECUTION_CONTRACT_RULES = [
|
|
|
2062
2078
|
var CONVERSATION_RULES = [
|
|
2063
2079
|
"- In thread follow-ups, answer from prior thread context; do not repeat resolved clarifying questions.",
|
|
2064
2080
|
"- Preserve attribution roles from thread context: the actor is the person asking now, which may differ from the original reporter or subject.",
|
|
2065
|
-
"- Treat event notifications as subscribed conversation updates, not user-authored commands. Use their subscription intent to decide whether to reply, inspect, suggest, or stay brief.",
|
|
2066
2081
|
"- Runtime owns continuation and authorization notices; on resumed turns, answer with the final requested content only."
|
|
2067
2082
|
];
|
|
2068
2083
|
var SLACK_ACTION_RULES = [
|
|
@@ -8368,252 +8383,33 @@ function createSystemTimeTool() {
|
|
|
8368
8383
|
});
|
|
8369
8384
|
}
|
|
8370
8385
|
|
|
8371
|
-
// src/chat/tools/
|
|
8372
|
-
import {
|
|
8373
|
-
Agent
|
|
8374
|
-
} from "@earendil-works/pi-agent-core";
|
|
8386
|
+
// src/chat/tools/handoff/tool.ts
|
|
8375
8387
|
import { z as z33 } from "zod";
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
"Do not assume access to parent transcript or tool output that was not included or gathered in this advisor call.",
|
|
8385
|
-
"Use only the read-only tools provided to you.",
|
|
8386
|
-
"Do not make user-visible side effects, post Slack messages, or mutate files. If a mutating action is needed, recommend it to the executor instead.",
|
|
8387
|
-
"Identify the hard part, recommend a concrete plan or correction, call out blocking risks, and propose focused verification.",
|
|
8388
|
-
"If the supplied context is insufficient, say exactly what additional evidence the executor needs to gather before acting.",
|
|
8389
|
-
"Do not write user-facing prose.",
|
|
8390
|
-
"Use concise technical memo sections when helpful: Assessment, Recommended Plan, Risks, Verification, Stop Conditions."
|
|
8391
|
-
].join("\n");
|
|
8392
|
-
function lastAssistantMessage(messages) {
|
|
8393
|
-
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
8394
|
-
const message = messages[index];
|
|
8395
|
-
if (isAssistantMessage(message)) {
|
|
8396
|
-
return message;
|
|
8397
|
-
}
|
|
8398
|
-
}
|
|
8399
|
-
return void 0;
|
|
8400
|
-
}
|
|
8401
|
-
function failure(errorCode, text = `Advisor guidance is unavailable (${errorCode}). Continue only if the next step is clear from verified evidence.`) {
|
|
8402
|
-
return {
|
|
8403
|
-
ok: false,
|
|
8404
|
-
status: "error",
|
|
8405
|
-
error_code: errorCode,
|
|
8406
|
-
memo: text
|
|
8407
|
-
};
|
|
8408
|
-
}
|
|
8409
|
-
function success(memo) {
|
|
8410
|
-
return {
|
|
8411
|
-
ok: true,
|
|
8412
|
-
status: "success",
|
|
8413
|
-
memo
|
|
8414
|
-
};
|
|
8415
|
-
}
|
|
8416
|
-
function hasReadOnlyToolAnnotations(annotations) {
|
|
8417
|
-
return annotations?.readOnlyHint === true && annotations.destructiveHint !== true;
|
|
8418
|
-
}
|
|
8419
|
-
function createAdvisorToolDefinitions(definitions) {
|
|
8420
|
-
return Object.fromEntries(
|
|
8421
|
-
Object.entries(definitions).filter(
|
|
8422
|
-
([name, definition]) => name !== "callMcpTool" && name !== "searchMcpTools" && hasReadOnlyToolAnnotations(definition.annotations)
|
|
8423
|
-
)
|
|
8424
|
-
);
|
|
8425
|
-
}
|
|
8426
|
-
function createAdvisorTool(context) {
|
|
8427
|
-
const conversationStore = () => context.conversationStore ?? getConversationStore();
|
|
8428
|
-
const spanContext = context.logContext ?? {};
|
|
8388
|
+
var HANDOFF_TOOL_NAME = "handoff";
|
|
8389
|
+
function createHandoffTool(handoff) {
|
|
8390
|
+
const profileSchema = z33.enum(handoff.profiles);
|
|
8391
|
+
const defaultProfile = handoff.profiles[0];
|
|
8392
|
+
const handoffResultSchema = juniorToolResultSchema.extend({
|
|
8393
|
+
model_profile: profileSchema
|
|
8394
|
+
});
|
|
8395
|
+
const profileNames = handoff.profiles.map((profile) => `\`${profile}\``).join(", ");
|
|
8429
8396
|
return zodTool({
|
|
8430
|
-
description:
|
|
8397
|
+
description: `Permanently switch this conversation to a more capable model profile, replace prior context with a continuation summary, and continue the same task with the same workspace and all other normal tools. Available profiles: ${profileNames}. Omit profile to use \`${defaultProfile}\`. Call it as the only tool in the assistant message when the system tool policy requires a model upgrade.`,
|
|
8398
|
+
executionMode: "sequential",
|
|
8431
8399
|
inputSchema: z33.object({
|
|
8432
|
-
|
|
8433
|
-
|
|
8434
|
-
"Curated evidence packet: relevant requirements, constraints, current plan, alternatives, code snippets, diffs, command output, and open questions."
|
|
8400
|
+
profile: profileSchema.nullish().describe(
|
|
8401
|
+
"Named model profile to use for the rest of the conversation; omit or pass null for the default"
|
|
8435
8402
|
)
|
|
8436
|
-
}),
|
|
8437
|
-
outputSchema:
|
|
8438
|
-
execute: async (
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
const advisorQuestion = question.trim();
|
|
8446
|
-
if (typeof suppliedContext !== "string" || !suppliedContext.trim()) {
|
|
8447
|
-
return failure(
|
|
8448
|
-
"invalid_context",
|
|
8449
|
-
"Advisor guidance is unavailable because the curated context was empty or invalid. Include the relevant evidence and constraints before retrying."
|
|
8450
|
-
);
|
|
8451
|
-
}
|
|
8452
|
-
const advisorContext = suppliedContext.trim();
|
|
8453
|
-
if (!context.conversationId) {
|
|
8454
|
-
return failure(
|
|
8455
|
-
"missing_conversation_id",
|
|
8456
|
-
"Advisor guidance is unavailable because this turn has no parent conversation id. Continue without assuming advisor history."
|
|
8457
|
-
);
|
|
8458
|
-
}
|
|
8459
|
-
const conversationId = context.conversationId;
|
|
8460
|
-
const childConversationId = advisorChildConversationId(conversationId);
|
|
8461
|
-
const subagentInvocationId = typeof toolCallId === "string" && toolCallId.length > 0 ? toolCallId : `advisor:${Date.now()}`;
|
|
8462
|
-
const endSubagent = async (outcome, errorCode) => {
|
|
8463
|
-
try {
|
|
8464
|
-
await getAgentStepStore().append(conversationId, [
|
|
8465
|
-
{
|
|
8466
|
-
entry: {
|
|
8467
|
-
type: "subagent_ended",
|
|
8468
|
-
subagentInvocationId,
|
|
8469
|
-
outcome,
|
|
8470
|
-
...errorCode ? { errorCode } : {}
|
|
8471
|
-
},
|
|
8472
|
-
createdAtMs: Date.now()
|
|
8473
|
-
}
|
|
8474
|
-
]);
|
|
8475
|
-
} catch (error) {
|
|
8476
|
-
logWarn("advisor_subagent_ended_append_failed", spanContext, {
|
|
8477
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
8478
|
-
});
|
|
8479
|
-
}
|
|
8480
|
-
};
|
|
8481
|
-
try {
|
|
8482
|
-
await conversationStore().ensureChildConversation({
|
|
8483
|
-
conversationId: childConversationId,
|
|
8484
|
-
parentConversationId: conversationId
|
|
8485
|
-
});
|
|
8486
|
-
await getAgentStepStore().append(conversationId, [
|
|
8487
|
-
{
|
|
8488
|
-
entry: {
|
|
8489
|
-
type: "subagent_started",
|
|
8490
|
-
subagentInvocationId,
|
|
8491
|
-
subagentKind: "advisor",
|
|
8492
|
-
modelId: context.config.modelId,
|
|
8493
|
-
...typeof toolCallId === "string" && toolCallId.length > 0 ? { parentToolCallId: toolCallId } : {},
|
|
8494
|
-
childConversationId,
|
|
8495
|
-
historyMode: "shared",
|
|
8496
|
-
reasoningLevel: context.config.thinkingLevel
|
|
8497
|
-
},
|
|
8498
|
-
createdAtMs: Date.now()
|
|
8499
|
-
}
|
|
8500
|
-
]);
|
|
8501
|
-
} catch (error) {
|
|
8502
|
-
logWarn("advisor_subagent_started_append_failed", spanContext, {
|
|
8503
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
8504
|
-
});
|
|
8505
|
-
}
|
|
8506
|
-
const conversationPrivacy = context.conversationPrivacy ?? "private";
|
|
8507
|
-
const requestText = renderAdvisorRequest(advisorQuestion, advisorContext);
|
|
8508
|
-
const advisorInputMessage = {
|
|
8509
|
-
role: "user",
|
|
8510
|
-
content: [{ type: "text", text: requestText }],
|
|
8511
|
-
timestamp: Date.now()
|
|
8403
|
+
}).strict(),
|
|
8404
|
+
outputSchema: handoffResultSchema,
|
|
8405
|
+
execute: async (input, options) => {
|
|
8406
|
+
const profile = input.profile ?? defaultProfile;
|
|
8407
|
+
await handoff.execute(profile, options.signal);
|
|
8408
|
+
return {
|
|
8409
|
+
ok: true,
|
|
8410
|
+
status: "success",
|
|
8411
|
+
model_profile: profile
|
|
8512
8412
|
};
|
|
8513
|
-
const advisorInputMessagesAttribute = serializeGenAiAttribute(
|
|
8514
|
-
conversationPrivacy !== "public" ? [toGenAiMessageMetadata(advisorInputMessage)] : [toCanonicalInputMessage(advisorInputMessage)]
|
|
8515
|
-
);
|
|
8516
|
-
return await withSpan(
|
|
8517
|
-
`invoke_agent ${context.config.modelId}`,
|
|
8518
|
-
"gen_ai.invoke_agent",
|
|
8519
|
-
spanContext,
|
|
8520
|
-
async () => {
|
|
8521
|
-
const requestMessage = {
|
|
8522
|
-
role: "user",
|
|
8523
|
-
content: [{ type: "text", text: requestText }],
|
|
8524
|
-
timestamp: Date.now()
|
|
8525
|
-
};
|
|
8526
|
-
let advisorMessages;
|
|
8527
|
-
try {
|
|
8528
|
-
advisorMessages = await loadProjection({
|
|
8529
|
-
conversationId: childConversationId
|
|
8530
|
-
});
|
|
8531
|
-
} catch {
|
|
8532
|
-
setSpanStatus("error");
|
|
8533
|
-
await endSubagent("error", "session_unavailable");
|
|
8534
|
-
return failure(
|
|
8535
|
-
"session_unavailable",
|
|
8536
|
-
"Advisor guidance is unavailable because advisor history could not be loaded. Continue without assuming advisor history."
|
|
8537
|
-
);
|
|
8538
|
-
}
|
|
8539
|
-
const apiKeyOverride = getPiGatewayApiKey();
|
|
8540
|
-
const advisorAgent = new Agent({
|
|
8541
|
-
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
8542
|
-
initialState: {
|
|
8543
|
-
systemPrompt: ADVISOR_SYSTEM_PROMPT,
|
|
8544
|
-
model: resolveGatewayModel(context.config.modelId),
|
|
8545
|
-
thinkingLevel: context.config.thinkingLevel,
|
|
8546
|
-
tools: context.getTools()
|
|
8547
|
-
},
|
|
8548
|
-
sessionId: childConversationId,
|
|
8549
|
-
streamFn: context.streamFn
|
|
8550
|
-
});
|
|
8551
|
-
advisorAgent.state.messages = advisorMessages;
|
|
8552
|
-
const beforeMessageCount = advisorAgent.state.messages.length;
|
|
8553
|
-
try {
|
|
8554
|
-
await advisorAgent.prompt(requestMessage);
|
|
8555
|
-
} catch {
|
|
8556
|
-
setSpanStatus("error");
|
|
8557
|
-
await endSubagent("error", "unavailable");
|
|
8558
|
-
return failure(
|
|
8559
|
-
"unavailable",
|
|
8560
|
-
"Advisor guidance is unavailable. Continue without advisor guidance if the next step is clear from verified evidence."
|
|
8561
|
-
);
|
|
8562
|
-
}
|
|
8563
|
-
const assistant = lastAssistantMessage(advisorAgent.state.messages);
|
|
8564
|
-
const newAdvisorMessages = advisorAgent.state.messages.slice(beforeMessageCount);
|
|
8565
|
-
const outputMessages = newAdvisorMessages.filter(isAssistantMessage);
|
|
8566
|
-
const outputMessagesAttribute = serializeGenAiAttribute(
|
|
8567
|
-
conversationPrivacy !== "public" ? outputMessages.map(toGenAiMessageMetadata) : outputMessages.map(toCanonicalOutputMessage)
|
|
8568
|
-
);
|
|
8569
|
-
setSpanAttributes({
|
|
8570
|
-
...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
|
|
8571
|
-
...toGenAiMessagesTraceAttributes("app.ai.output", outputMessages),
|
|
8572
|
-
...extractGenAiUsageAttributes(...newAdvisorMessages)
|
|
8573
|
-
});
|
|
8574
|
-
if (!assistant || assistant.stopReason === "error" || assistant.stopReason === "aborted") {
|
|
8575
|
-
setSpanStatus("error");
|
|
8576
|
-
await endSubagent(
|
|
8577
|
-
assistant?.stopReason === "aborted" ? "aborted" : "error",
|
|
8578
|
-
"unavailable"
|
|
8579
|
-
);
|
|
8580
|
-
return failure(
|
|
8581
|
-
"unavailable",
|
|
8582
|
-
"Advisor guidance is unavailable. Continue without advisor guidance if the next step is clear from verified evidence."
|
|
8583
|
-
);
|
|
8584
|
-
}
|
|
8585
|
-
const memo = extractAssistantText(assistant);
|
|
8586
|
-
try {
|
|
8587
|
-
await commitMessages({
|
|
8588
|
-
conversationId: childConversationId,
|
|
8589
|
-
messages: advisorAgent.state.messages
|
|
8590
|
-
});
|
|
8591
|
-
} catch {
|
|
8592
|
-
setSpanStatus("error");
|
|
8593
|
-
await endSubagent("error", "session_unavailable");
|
|
8594
|
-
return failure(
|
|
8595
|
-
"session_unavailable",
|
|
8596
|
-
"Advisor guidance is unavailable because advisor history could not be saved. Retry the advisor call or continue without assuming advisor history."
|
|
8597
|
-
);
|
|
8598
|
-
}
|
|
8599
|
-
await endSubagent("success");
|
|
8600
|
-
setSpanStatus("ok");
|
|
8601
|
-
return success(memo);
|
|
8602
|
-
},
|
|
8603
|
-
{
|
|
8604
|
-
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
8605
|
-
"gen_ai.operation.name": "invoke_agent",
|
|
8606
|
-
"gen_ai.request.model": context.config.modelId,
|
|
8607
|
-
"gen_ai.output.type": "text",
|
|
8608
|
-
"server.address": GEN_AI_SERVER_ADDRESS,
|
|
8609
|
-
"server.port": GEN_AI_SERVER_PORT,
|
|
8610
|
-
"app.conversation.privacy": conversationPrivacy,
|
|
8611
|
-
...toGenAiMessagesTraceAttributes("app.ai.input", [
|
|
8612
|
-
advisorInputMessage
|
|
8613
|
-
]),
|
|
8614
|
-
...advisorInputMessagesAttribute ? { "gen_ai.input.messages": advisorInputMessagesAttribute } : {}
|
|
8615
|
-
}
|
|
8616
|
-
);
|
|
8617
8413
|
}
|
|
8618
8414
|
});
|
|
8619
8415
|
}
|
|
@@ -9341,8 +9137,8 @@ function createTools(availableSkills, hooks = {}, context) {
|
|
|
9341
9137
|
hooks.toolOverrides?.imageGenerate
|
|
9342
9138
|
);
|
|
9343
9139
|
}
|
|
9344
|
-
if (context.
|
|
9345
|
-
tools.
|
|
9140
|
+
if (context.handoff) {
|
|
9141
|
+
tools.handoff = createHandoffTool(context.handoff);
|
|
9346
9142
|
}
|
|
9347
9143
|
if (canUseResourceEventSubscriptionTools(context)) {
|
|
9348
9144
|
tools.subscribeToResourceEvents = createSubscribeToResourceEventsTool(context);
|
|
@@ -14540,7 +14336,6 @@ async function wireAgentTools(args) {
|
|
|
14540
14336
|
const loadableSkills = args.availableSkills.filter(
|
|
14541
14337
|
(skill) => skill.disableModelInvocation !== true || skill.name === args.invokedSkill?.name
|
|
14542
14338
|
);
|
|
14543
|
-
let advisorTools = [];
|
|
14544
14339
|
const commonToolRuntimeContext = {
|
|
14545
14340
|
conversationId: args.sessionConversationId,
|
|
14546
14341
|
userText: args.userInput,
|
|
@@ -14566,16 +14361,7 @@ async function wireAgentTools(args) {
|
|
|
14566
14361
|
mcpToolManager,
|
|
14567
14362
|
sandbox,
|
|
14568
14363
|
surface: args.surface,
|
|
14569
|
-
|
|
14570
|
-
config: botConfig.advisor,
|
|
14571
|
-
conversationId: args.sessionConversationId,
|
|
14572
|
-
conversationPrivacy: args.conversationPrivacy,
|
|
14573
|
-
logContext: args.spanContext,
|
|
14574
|
-
getTools: () => advisorTools,
|
|
14575
|
-
streamFn: createTracedStreamFn({
|
|
14576
|
-
conversationPrivacy: args.conversationPrivacy
|
|
14577
|
-
})
|
|
14578
|
-
}
|
|
14364
|
+
...args.requestHandoff ? { handoff: args.requestHandoff } : {}
|
|
14579
14365
|
};
|
|
14580
14366
|
const toolDestination = toolInvocationDestination(args.routing);
|
|
14581
14367
|
let toolRuntimeContext;
|
|
@@ -14721,18 +14507,6 @@ async function wireAgentTools(args) {
|
|
|
14721
14507
|
args.conversationPrivacy,
|
|
14722
14508
|
args.observers.onToolResult
|
|
14723
14509
|
);
|
|
14724
|
-
advisorTools = createPiAgentTools(
|
|
14725
|
-
createAdvisorToolDefinitions(tools),
|
|
14726
|
-
args.skillSandbox,
|
|
14727
|
-
args.spanContext,
|
|
14728
|
-
args.observers.onStatus,
|
|
14729
|
-
sandboxExecutor,
|
|
14730
|
-
pluginAuth,
|
|
14731
|
-
onToolCall,
|
|
14732
|
-
pluginHooks,
|
|
14733
|
-
args.conversationPrivacy,
|
|
14734
|
-
args.observers.onToolResult
|
|
14735
|
-
);
|
|
14736
14510
|
return {
|
|
14737
14511
|
activeMcpCatalogs,
|
|
14738
14512
|
agentTools,
|
|
@@ -14771,7 +14545,7 @@ function createResumeState(args) {
|
|
|
14771
14545
|
sessionId: args.sessionId,
|
|
14772
14546
|
loadedSkillNames: args.getLoadedSkillNames(),
|
|
14773
14547
|
logContext: args.logContext,
|
|
14774
|
-
modelId: args.
|
|
14548
|
+
modelId: args.getModelId(),
|
|
14775
14549
|
...args.getReasoningLevel() ? { reasoningLevel: args.getReasoningLevel() } : {},
|
|
14776
14550
|
actor: args.actor,
|
|
14777
14551
|
...args.surface ? { surface: args.surface } : {}
|
|
@@ -14795,6 +14569,11 @@ function createResumeState(args) {
|
|
|
14795
14569
|
setBeforeMessageCount(count) {
|
|
14796
14570
|
beforeMessageCount = count;
|
|
14797
14571
|
},
|
|
14572
|
+
/** Adopt an already committed epoch replacement as every resume baseline. */
|
|
14573
|
+
adoptCommittedBoundary(messages) {
|
|
14574
|
+
latestSafeBoundaryMessages = [...messages];
|
|
14575
|
+
resumeMessages = [...messages];
|
|
14576
|
+
},
|
|
14798
14577
|
captureResumeSnapshot(messages) {
|
|
14799
14578
|
resumeMessages = [...messages];
|
|
14800
14579
|
},
|
|
@@ -14879,7 +14658,8 @@ function createResumeState(args) {
|
|
|
14879
14658
|
return {
|
|
14880
14659
|
outcome: {
|
|
14881
14660
|
status: "suspended",
|
|
14882
|
-
resumeVersion: sessionRecord.version
|
|
14661
|
+
resumeVersion: sessionRecord.version,
|
|
14662
|
+
...usage ? { usage } : {}
|
|
14883
14663
|
}
|
|
14884
14664
|
};
|
|
14885
14665
|
}
|
|
@@ -14903,7 +14683,8 @@ function createResumeState(args) {
|
|
|
14903
14683
|
return {
|
|
14904
14684
|
outcome: {
|
|
14905
14685
|
status: "suspended",
|
|
14906
|
-
resumeVersion: sessionRecord.version
|
|
14686
|
+
resumeVersion: sessionRecord.version,
|
|
14687
|
+
...usage ? { usage } : {}
|
|
14907
14688
|
}
|
|
14908
14689
|
};
|
|
14909
14690
|
}
|
|
@@ -14926,7 +14707,8 @@ function createResumeState(args) {
|
|
|
14926
14707
|
return {
|
|
14927
14708
|
outcome: {
|
|
14928
14709
|
status: "awaiting_auth",
|
|
14929
|
-
providerDisplayName: error.providerDisplayName
|
|
14710
|
+
providerDisplayName: error.providerDisplayName,
|
|
14711
|
+
...usage ? { usage } : {}
|
|
14930
14712
|
}
|
|
14931
14713
|
};
|
|
14932
14714
|
}
|
|
@@ -14936,6 +14718,319 @@ function createResumeState(args) {
|
|
|
14936
14718
|
};
|
|
14937
14719
|
}
|
|
14938
14720
|
|
|
14721
|
+
// src/chat/services/context-compaction.ts
|
|
14722
|
+
import {
|
|
14723
|
+
estimateContextTokens,
|
|
14724
|
+
estimateTokens
|
|
14725
|
+
} from "@earendil-works/pi-agent-core";
|
|
14726
|
+
var RETAINED_USER_MESSAGE_TOKENS = 2e4;
|
|
14727
|
+
var MAX_SUMMARY_INPUT_CHARS = 8e4;
|
|
14728
|
+
var MAX_VISIBLE_CONTEXT_CHARS = 2e4;
|
|
14729
|
+
var MAX_SUMMARY_CHARS = 6e3;
|
|
14730
|
+
var MAX_RENDERED_MESSAGE_CHARS = 4e3;
|
|
14731
|
+
var COMPACTION_SUMMARY_PREFIX = "Context compaction summary for future Junior turns:";
|
|
14732
|
+
var LEGACY_COMPACTION_SUMMARY_PREFIX = "Context handoff summary for future Junior turns:";
|
|
14733
|
+
var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
|
|
14734
|
+
var OMITTED_OLDER_CONTEXT_NOTICE = "[older context omitted]";
|
|
14735
|
+
function textPart(value) {
|
|
14736
|
+
if (value && typeof value === "object" && value.type === "text" && typeof value.text === "string") {
|
|
14737
|
+
return value.text;
|
|
14738
|
+
}
|
|
14739
|
+
return void 0;
|
|
14740
|
+
}
|
|
14741
|
+
function messageText(message) {
|
|
14742
|
+
const content = message.content;
|
|
14743
|
+
const unwrapTask = message.role === "user";
|
|
14744
|
+
const displayText = (text) => unwrapTask ? unwrapCurrentInstruction(text) ?? text : text;
|
|
14745
|
+
if (!Array.isArray(content)) {
|
|
14746
|
+
return typeof content === "string" ? displayText(content) : "";
|
|
14747
|
+
}
|
|
14748
|
+
return content.map(textPart).filter((text) => Boolean(text)).map(displayText).join("\n").trim();
|
|
14749
|
+
}
|
|
14750
|
+
function sanitizeText(text) {
|
|
14751
|
+
return text.replace(
|
|
14752
|
+
/<data_base64>[\s\S]*?<\/data_base64>/g,
|
|
14753
|
+
"<data_base64>[omitted]</data_base64>"
|
|
14754
|
+
).replace(
|
|
14755
|
+
/data:image\/[a-z0-9.+-]+;base64,[a-z0-9+/=]+/gi,
|
|
14756
|
+
"[image data omitted]"
|
|
14757
|
+
).replaceAll("\0", " ").trim();
|
|
14758
|
+
}
|
|
14759
|
+
function truncateToTokenBudget(text, maxTokens) {
|
|
14760
|
+
const maxChars = Math.max(0, maxTokens * 4);
|
|
14761
|
+
if (text.length <= maxChars) {
|
|
14762
|
+
return text;
|
|
14763
|
+
}
|
|
14764
|
+
return `${text.slice(0, Math.max(0, maxChars - 3)).trimEnd()}...`;
|
|
14765
|
+
}
|
|
14766
|
+
function isCompactionSummary(text) {
|
|
14767
|
+
const normalized = text.trimStart();
|
|
14768
|
+
return normalized.startsWith(COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(LEGACY_COMPACTION_SUMMARY_PREFIX) || normalized.startsWith(MODEL_HANDOFF_SUMMARY_PREFIX);
|
|
14769
|
+
}
|
|
14770
|
+
function isPayloadHeavy(text) {
|
|
14771
|
+
return /<data_base64>[\s\S]*?<\/data_base64>|data:image\/[a-z0-9.+-]+;base64,/i.test(
|
|
14772
|
+
text
|
|
14773
|
+
);
|
|
14774
|
+
}
|
|
14775
|
+
function userMessage(text) {
|
|
14776
|
+
return {
|
|
14777
|
+
role: "user",
|
|
14778
|
+
content: [{ type: "text", text }],
|
|
14779
|
+
timestamp: Date.now()
|
|
14780
|
+
};
|
|
14781
|
+
}
|
|
14782
|
+
function piMessageTimestamp(message) {
|
|
14783
|
+
const timestamp = message.timestamp;
|
|
14784
|
+
return typeof timestamp === "number" ? timestamp : Date.now();
|
|
14785
|
+
}
|
|
14786
|
+
function selectRetainedUserMessageEntries(messages, maxTokens = RETAINED_USER_MESSAGE_TOKENS) {
|
|
14787
|
+
const selected = [];
|
|
14788
|
+
let remaining = maxTokens;
|
|
14789
|
+
for (let sourceIndex = messages.length - 1; sourceIndex >= 0; sourceIndex -= 1) {
|
|
14790
|
+
const stripped = stripRuntimeTurnContext([messages[sourceIndex]]);
|
|
14791
|
+
const message = stripped[0];
|
|
14792
|
+
if (!message || message.role !== "user" || remaining <= 0) {
|
|
14793
|
+
continue;
|
|
14794
|
+
}
|
|
14795
|
+
const text = sanitizeText(messageText(message));
|
|
14796
|
+
if (!text || isCompactionSummary(text) || isPayloadHeavy(text)) {
|
|
14797
|
+
continue;
|
|
14798
|
+
}
|
|
14799
|
+
const tokens = estimateTextTokens(text);
|
|
14800
|
+
if (tokens <= remaining) {
|
|
14801
|
+
selected.push({ message: userMessage(text), sourceIndex });
|
|
14802
|
+
remaining -= tokens;
|
|
14803
|
+
continue;
|
|
14804
|
+
}
|
|
14805
|
+
const truncated = truncateToTokenBudget(text, remaining);
|
|
14806
|
+
if (truncated) {
|
|
14807
|
+
selected.push({ message: userMessage(truncated), sourceIndex });
|
|
14808
|
+
}
|
|
14809
|
+
break;
|
|
14810
|
+
}
|
|
14811
|
+
return selected.reverse();
|
|
14812
|
+
}
|
|
14813
|
+
function renderMessageForSummary(message) {
|
|
14814
|
+
const role = message.role;
|
|
14815
|
+
if (typeof role !== "string") {
|
|
14816
|
+
return void 0;
|
|
14817
|
+
}
|
|
14818
|
+
const text = sanitizeText(messageText(message));
|
|
14819
|
+
if (!text) {
|
|
14820
|
+
return void 0;
|
|
14821
|
+
}
|
|
14822
|
+
const trimmed = text.length > MAX_RENDERED_MESSAGE_CHARS ? `${text.slice(0, MAX_RENDERED_MESSAGE_CHARS).trimEnd()}...` : text;
|
|
14823
|
+
return `[${role}] ${trimmed}`;
|
|
14824
|
+
}
|
|
14825
|
+
function keepTail(text, maxChars) {
|
|
14826
|
+
if (text.length <= maxChars) {
|
|
14827
|
+
return text;
|
|
14828
|
+
}
|
|
14829
|
+
const prefix = `${OMITTED_OLDER_CONTEXT_NOTICE}
|
|
14830
|
+
`;
|
|
14831
|
+
return `${prefix}${text.slice(Math.max(0, text.length - maxChars + prefix.length))}`;
|
|
14832
|
+
}
|
|
14833
|
+
function renderSummaryInput(piMessages, conversationContext) {
|
|
14834
|
+
const lines = [];
|
|
14835
|
+
const visibleContext = conversationContext?.trim();
|
|
14836
|
+
if (visibleContext) {
|
|
14837
|
+
lines.push(
|
|
14838
|
+
"<visible-thread-context>",
|
|
14839
|
+
keepTail(visibleContext, MAX_VISIBLE_CONTEXT_CHARS),
|
|
14840
|
+
"</visible-thread-context>",
|
|
14841
|
+
""
|
|
14842
|
+
);
|
|
14843
|
+
}
|
|
14844
|
+
const renderedPiMessages = stripRuntimeTurnContext(piMessages).map(renderMessageForSummary).filter((line) => Boolean(line));
|
|
14845
|
+
if (renderedPiMessages.length > 0) {
|
|
14846
|
+
const piEnvelopeChars = "<pi-history>\n</pi-history>".length + 2;
|
|
14847
|
+
const piHistory = keepTail(
|
|
14848
|
+
renderedPiMessages.join("\n"),
|
|
14849
|
+
Math.max(
|
|
14850
|
+
1,
|
|
14851
|
+
MAX_SUMMARY_INPUT_CHARS - lines.join("\n").length - piEnvelopeChars
|
|
14852
|
+
)
|
|
14853
|
+
);
|
|
14854
|
+
lines.push("<pi-history>", piHistory, "</pi-history>");
|
|
14855
|
+
}
|
|
14856
|
+
return keepTail(lines.join("\n"), MAX_SUMMARY_INPUT_CHARS);
|
|
14857
|
+
}
|
|
14858
|
+
async function summarizeContext(args, deps) {
|
|
14859
|
+
const source = renderSummaryInput(args.piMessages, args.conversationContext);
|
|
14860
|
+
const result = await deps.completeText({
|
|
14861
|
+
modelId: botConfig.fastModelId,
|
|
14862
|
+
messageAttributeMode: "metadata",
|
|
14863
|
+
temperature: 0,
|
|
14864
|
+
signal: args.signal,
|
|
14865
|
+
messages: [
|
|
14866
|
+
{
|
|
14867
|
+
role: "user",
|
|
14868
|
+
content: [
|
|
14869
|
+
"You are performing a CONTEXT CHECKPOINT COMPACTION for Junior.",
|
|
14870
|
+
"Create a concise continuation summary for the agent that will continue this Slack thread.",
|
|
14871
|
+
"",
|
|
14872
|
+
"Include:",
|
|
14873
|
+
"- Current outstanding asks",
|
|
14874
|
+
"- Key decisions, completed work, and outcomes",
|
|
14875
|
+
"- Durable constraints, user preferences, IDs, URLs, artifacts, canvas links, sandbox references, and auth state",
|
|
14876
|
+
"- Clear next steps and unresolved blockers",
|
|
14877
|
+
"",
|
|
14878
|
+
"Do not invent details. Do not include raw secrets or credentials.",
|
|
14879
|
+
"",
|
|
14880
|
+
source
|
|
14881
|
+
].join("\n"),
|
|
14882
|
+
timestamp: Date.now()
|
|
14883
|
+
}
|
|
14884
|
+
],
|
|
14885
|
+
metadata: {
|
|
14886
|
+
modelId: botConfig.fastModelId,
|
|
14887
|
+
threadId: args.metadata?.threadId ?? "",
|
|
14888
|
+
channelId: args.metadata?.channelId ?? "",
|
|
14889
|
+
actorId: args.metadata?.actorId ?? "",
|
|
14890
|
+
runId: args.metadata?.runId ?? ""
|
|
14891
|
+
}
|
|
14892
|
+
});
|
|
14893
|
+
const summary = result.text.trim();
|
|
14894
|
+
if (!summary) {
|
|
14895
|
+
throw new Error("Compaction summary was empty");
|
|
14896
|
+
}
|
|
14897
|
+
return summary.slice(0, MAX_SUMMARY_CHARS);
|
|
14898
|
+
}
|
|
14899
|
+
function estimateHistoryTokens(messages) {
|
|
14900
|
+
const stripped = stripRuntimeTurnContext(messages);
|
|
14901
|
+
const usageEstimate = estimateContextTokens(stripped).tokens;
|
|
14902
|
+
const structuralEstimate = stripped.reduce(
|
|
14903
|
+
(total, message) => total + estimateTokens(message),
|
|
14904
|
+
0
|
|
14905
|
+
);
|
|
14906
|
+
return Math.max(usageEstimate, structuralEstimate);
|
|
14907
|
+
}
|
|
14908
|
+
function buildReplacementProvenance(args) {
|
|
14909
|
+
return [
|
|
14910
|
+
...args.retained.map(
|
|
14911
|
+
(entry) => args.sourceProvenance[entry.sourceIndex] ?? contextProvenance
|
|
14912
|
+
),
|
|
14913
|
+
contextProvenance
|
|
14914
|
+
];
|
|
14915
|
+
}
|
|
14916
|
+
function loadCompactionSource(messages) {
|
|
14917
|
+
if (messages.length > 0) {
|
|
14918
|
+
return {
|
|
14919
|
+
estimatedTokens: estimateHistoryTokens(messages),
|
|
14920
|
+
messages
|
|
14921
|
+
};
|
|
14922
|
+
}
|
|
14923
|
+
return { reason: "missing_context" };
|
|
14924
|
+
}
|
|
14925
|
+
async function maybeCompactWithDeps(args, deps) {
|
|
14926
|
+
const source = loadCompactionSource(args.piMessages);
|
|
14927
|
+
if ("reason" in source) {
|
|
14928
|
+
return { compacted: false, reason: source.reason };
|
|
14929
|
+
}
|
|
14930
|
+
const triggerTokens = deps.autoCompactionTriggerTokens ?? getAgentContextCompactionTriggerTokens();
|
|
14931
|
+
if (source.estimatedTokens <= triggerTokens) {
|
|
14932
|
+
return { compacted: false, reason: "below_threshold" };
|
|
14933
|
+
}
|
|
14934
|
+
args.onCompactionStart?.();
|
|
14935
|
+
let summary;
|
|
14936
|
+
try {
|
|
14937
|
+
summary = await summarizeContext(
|
|
14938
|
+
{
|
|
14939
|
+
conversationContext: args.conversationContext,
|
|
14940
|
+
piMessages: source.messages,
|
|
14941
|
+
metadata: args.metadata
|
|
14942
|
+
},
|
|
14943
|
+
deps
|
|
14944
|
+
);
|
|
14945
|
+
} catch (error) {
|
|
14946
|
+
logWarn(
|
|
14947
|
+
"context_compaction_summary_failed",
|
|
14948
|
+
{
|
|
14949
|
+
slackThreadId: args.metadata?.threadId,
|
|
14950
|
+
slackUserId: args.metadata?.actorId,
|
|
14951
|
+
slackChannelId: args.metadata?.channelId,
|
|
14952
|
+
runId: args.metadata?.runId,
|
|
14953
|
+
assistantUserName: botConfig.userName,
|
|
14954
|
+
modelId: botConfig.fastModelId
|
|
14955
|
+
},
|
|
14956
|
+
{
|
|
14957
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
14958
|
+
},
|
|
14959
|
+
"Context compaction failed; continuing with prior history"
|
|
14960
|
+
);
|
|
14961
|
+
return { compacted: false, reason: "summary_failed" };
|
|
14962
|
+
}
|
|
14963
|
+
return await writeCompactedThreadContext(args, source.messages, summary, {
|
|
14964
|
+
estimatedTokens: source.estimatedTokens,
|
|
14965
|
+
triggerTokens
|
|
14966
|
+
});
|
|
14967
|
+
}
|
|
14968
|
+
async function writeCompactedThreadContext(args, sourceMessages, summary, context) {
|
|
14969
|
+
const stepStore = getAgentStepStore();
|
|
14970
|
+
const sourceProjection = await loadConversationProjection({
|
|
14971
|
+
conversationId: args.conversationId
|
|
14972
|
+
});
|
|
14973
|
+
const retained = selectRetainedUserMessageEntries(
|
|
14974
|
+
trimTrailingAssistantMessages(sourceProjection.messages)
|
|
14975
|
+
);
|
|
14976
|
+
const replacement = [
|
|
14977
|
+
...retained.map((entry) => entry.message),
|
|
14978
|
+
userMessage(`${COMPACTION_SUMMARY_PREFIX}
|
|
14979
|
+
${summary}`)
|
|
14980
|
+
];
|
|
14981
|
+
const replacementProvenance = buildReplacementProvenance({
|
|
14982
|
+
retained,
|
|
14983
|
+
sourceProvenance: sourceProjection.provenance
|
|
14984
|
+
});
|
|
14985
|
+
await stepStore.startEpoch(args.conversationId, {
|
|
14986
|
+
reason: "compaction",
|
|
14987
|
+
modelProfile: sourceProjection.modelProfile,
|
|
14988
|
+
modelId: modelIdForProfile(botConfig, sourceProjection.modelProfile),
|
|
14989
|
+
messages: replacement.map((message, index) => ({
|
|
14990
|
+
message,
|
|
14991
|
+
createdAtMs: piMessageTimestamp(message),
|
|
14992
|
+
provenance: replacementProvenance[index]
|
|
14993
|
+
}))
|
|
14994
|
+
});
|
|
14995
|
+
updateConversationStats(args.conversation);
|
|
14996
|
+
setSpanAttributes({
|
|
14997
|
+
"app.compaction.input_messages": sourceMessages.length,
|
|
14998
|
+
"app.compaction.retained_messages": replacement.length - 1,
|
|
14999
|
+
"app.compaction.summary_chars": summary.length,
|
|
15000
|
+
...context.triggerTokens !== void 0 ? { "app.compaction.trigger_tokens": context.triggerTokens } : {},
|
|
15001
|
+
"app.context_tokens_estimated": context.estimatedTokens
|
|
15002
|
+
});
|
|
15003
|
+
return {
|
|
15004
|
+
compacted: true,
|
|
15005
|
+
piMessages: replacement
|
|
15006
|
+
};
|
|
15007
|
+
}
|
|
15008
|
+
function createContextCompactor(deps) {
|
|
15009
|
+
return {
|
|
15010
|
+
maybeCompact: async (args) => await maybeCompactWithDeps(args, deps)
|
|
15011
|
+
};
|
|
15012
|
+
}
|
|
15013
|
+
async function compactContextForHandoff(args, deps) {
|
|
15014
|
+
const summary = await summarizeContext(args, deps);
|
|
15015
|
+
const message = userMessage(`${MODEL_HANDOFF_SUMMARY_PREFIX}
|
|
15016
|
+
${summary}`);
|
|
15017
|
+
const messages = [message];
|
|
15018
|
+
args.signal?.throwIfAborted();
|
|
15019
|
+
await getAgentStepStore().startEpoch(args.conversationId, {
|
|
15020
|
+
reason: "handoff",
|
|
15021
|
+
modelProfile: args.target.modelProfile,
|
|
15022
|
+
modelId: args.target.modelId,
|
|
15023
|
+
messages: [
|
|
15024
|
+
{
|
|
15025
|
+
message,
|
|
15026
|
+
createdAtMs: piMessageTimestamp(message),
|
|
15027
|
+
provenance: contextProvenance
|
|
15028
|
+
}
|
|
15029
|
+
]
|
|
15030
|
+
});
|
|
15031
|
+
return messages;
|
|
15032
|
+
}
|
|
15033
|
+
|
|
14939
15034
|
// src/chat/agent/index.ts
|
|
14940
15035
|
var AGENT_ABORT_SETTLE_GRACE_MS = 5e3;
|
|
14941
15036
|
function waitForAbortSettlement(promise, timeoutMs) {
|
|
@@ -15004,7 +15099,10 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15004
15099
|
let connectedMcpProviders = /* @__PURE__ */ new Set();
|
|
15005
15100
|
let canRecordMcpProviders = false;
|
|
15006
15101
|
let turnUsage;
|
|
15102
|
+
let handoffPhaseUsage;
|
|
15007
15103
|
let thinkingSelection;
|
|
15104
|
+
let activeModelProfile = STANDARD_MODEL_PROFILE;
|
|
15105
|
+
let activeModelId = modelIdForProfile(botConfig, activeModelProfile);
|
|
15008
15106
|
const actor = actorFromRouting(routing);
|
|
15009
15107
|
const surface = surfaceFromRouting(routing);
|
|
15010
15108
|
const runSource = routing.source;
|
|
@@ -15020,8 +15118,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15020
15118
|
channelId: routing.correlation?.channelId,
|
|
15021
15119
|
runId: routing.correlation?.runId,
|
|
15022
15120
|
...credentialActorLogContext,
|
|
15023
|
-
assistantUserName: botConfig.userName
|
|
15024
|
-
modelId: botConfig.modelId
|
|
15121
|
+
assistantUserName: botConfig.userName
|
|
15025
15122
|
};
|
|
15026
15123
|
const { conversationId: sessionConversationId, sessionId } = getSessionIdentifiers(routing);
|
|
15027
15124
|
const recordConnectedMcpProvider = async (provider) => {
|
|
@@ -15047,6 +15144,14 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15047
15144
|
sandboxDependencyProfileHash: lastKnownSandboxDependencyProfileHash
|
|
15048
15145
|
});
|
|
15049
15146
|
try {
|
|
15147
|
+
if (sessionConversationId) {
|
|
15148
|
+
const projection = await openConversationProjection({
|
|
15149
|
+
conversationId: sessionConversationId,
|
|
15150
|
+
modelId: activeModelId
|
|
15151
|
+
});
|
|
15152
|
+
activeModelProfile = projection.modelProfile;
|
|
15153
|
+
activeModelId = modelIdForProfile(botConfig, activeModelProfile);
|
|
15154
|
+
}
|
|
15050
15155
|
const shouldTrace = shouldEmitDevAgentTrace();
|
|
15051
15156
|
const spanContext = {
|
|
15052
15157
|
conversationId: sessionConversationId,
|
|
@@ -15056,7 +15161,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15056
15161
|
runId: routing.correlation?.runId,
|
|
15057
15162
|
...credentialActorLogContext,
|
|
15058
15163
|
assistantUserName: botConfig.userName,
|
|
15059
|
-
modelId:
|
|
15164
|
+
modelId: activeModelId
|
|
15060
15165
|
};
|
|
15061
15166
|
const availableSkills = await discoverRunSkills({
|
|
15062
15167
|
skillDirs: policy.skillDirs,
|
|
@@ -15095,10 +15200,11 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15095
15200
|
currentSliceId,
|
|
15096
15201
|
existingSessionRecord
|
|
15097
15202
|
} = await restoreSessionRecord(routing);
|
|
15098
|
-
const committedInstructionProvenance =
|
|
15099
|
-
...existingSessionRecord
|
|
15203
|
+
const committedInstructionProvenance = [
|
|
15204
|
+
...existingSessionRecord?.piMessageProvenance ?? [],
|
|
15205
|
+
...(existingSessionRecord?.actors ?? []).map(instructionProvenanceFor),
|
|
15100
15206
|
...resumedFromSessionRecord ? [] : [instructionProvenanceFor(actor)]
|
|
15101
|
-
]
|
|
15207
|
+
];
|
|
15102
15208
|
const runActors = () => instructionActors(committedInstructionProvenance);
|
|
15103
15209
|
canRecordMcpProviders = Boolean(
|
|
15104
15210
|
sessionRecordState.canUseTurnSession && sessionConversationId && sessionId
|
|
@@ -15110,7 +15216,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15110
15216
|
getLoadedSkillNames: () => loadedSkillNamesForResume,
|
|
15111
15217
|
getReasoningLevel: () => thinkingSelection?.thinkingLevel,
|
|
15112
15218
|
logContext: sessionRecordLogContext,
|
|
15113
|
-
|
|
15219
|
+
getModelId: () => activeModelId,
|
|
15114
15220
|
recordActiveMcpProviders,
|
|
15115
15221
|
actor,
|
|
15116
15222
|
runSource,
|
|
@@ -15179,7 +15285,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15179
15285
|
messageText: userInput
|
|
15180
15286
|
});
|
|
15181
15287
|
setSpanAttributes({
|
|
15182
|
-
"gen_ai.request.model":
|
|
15288
|
+
"gen_ai.request.model": activeModelId,
|
|
15183
15289
|
"gen_ai.request.reasoning.level": thinkingSelection.thinkingLevel,
|
|
15184
15290
|
"app.ai.thinking_level_reason": thinkingSelection.reason,
|
|
15185
15291
|
...thinkingSelection.confidence !== void 0 ? {
|
|
@@ -15190,7 +15296,55 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15190
15296
|
const artifactStatePatch = {};
|
|
15191
15297
|
const toolCalls = [];
|
|
15192
15298
|
let agent;
|
|
15299
|
+
let pendingHandoff;
|
|
15193
15300
|
const currentAgentMessages = () => agent ? [...agent.state.messages] : [];
|
|
15301
|
+
const handoffProfiles = [
|
|
15302
|
+
DEFAULT_HANDOFF_MODEL_PROFILE,
|
|
15303
|
+
...Object.keys(botConfig.modelProfiles).filter((profile) => profile !== DEFAULT_HANDOFF_MODEL_PROFILE).sort()
|
|
15304
|
+
];
|
|
15305
|
+
const requestHandoff = activeModelProfile === STANDARD_MODEL_PROFILE && sessionConversationId ? {
|
|
15306
|
+
profiles: handoffProfiles,
|
|
15307
|
+
execute: async (profile, signal2) => {
|
|
15308
|
+
const sourceMessages = [...agent.state.messages];
|
|
15309
|
+
const runtimeContext = retainRuntimeTurnContext(sourceMessages);
|
|
15310
|
+
const standardPhaseUsage = extractGenAiUsageSummary(
|
|
15311
|
+
...sourceMessages.slice(runResume.beforeMessageCount).filter(isAssistantMessage)
|
|
15312
|
+
);
|
|
15313
|
+
const phaseUsage = hasAgentTurnUsage(standardPhaseUsage) ? standardPhaseUsage : void 0;
|
|
15314
|
+
const target = {
|
|
15315
|
+
modelId: modelIdForProfile(botConfig, profile),
|
|
15316
|
+
modelProfile: profile
|
|
15317
|
+
};
|
|
15318
|
+
const handoffModel = resolveGatewayModel(target.modelId);
|
|
15319
|
+
const handoffThinkingLevel = toAgentThinkingLevel(
|
|
15320
|
+
thinkingSelection.thinkingLevel
|
|
15321
|
+
);
|
|
15322
|
+
const handoffMessages = await compactContextForHandoff(
|
|
15323
|
+
{
|
|
15324
|
+
conversationContext: input.conversationContext,
|
|
15325
|
+
conversationId: sessionConversationId,
|
|
15326
|
+
piMessages: sourceMessages,
|
|
15327
|
+
signal: signal2,
|
|
15328
|
+
target,
|
|
15329
|
+
metadata: {
|
|
15330
|
+
threadId: routing.correlation?.threadId,
|
|
15331
|
+
channelId: routing.correlation?.channelId,
|
|
15332
|
+
actorId: routing.correlation?.actorId,
|
|
15333
|
+
runId: routing.correlation?.runId
|
|
15334
|
+
}
|
|
15335
|
+
},
|
|
15336
|
+
{ completeText }
|
|
15337
|
+
);
|
|
15338
|
+
handoffPhaseUsage = phaseUsage;
|
|
15339
|
+
pendingHandoff = {
|
|
15340
|
+
messages: [...handoffMessages, ...runtimeContext],
|
|
15341
|
+
model: handoffModel,
|
|
15342
|
+
thinkingLevel: handoffThinkingLevel
|
|
15343
|
+
};
|
|
15344
|
+
activeModelProfile = profile;
|
|
15345
|
+
activeModelId = target.modelId;
|
|
15346
|
+
}
|
|
15347
|
+
} : void 0;
|
|
15194
15348
|
setTags({
|
|
15195
15349
|
conversationId: spanContext.conversationId,
|
|
15196
15350
|
slackThreadId: routing.correlation?.threadId,
|
|
@@ -15199,7 +15353,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15199
15353
|
runId: routing.correlation?.runId,
|
|
15200
15354
|
...credentialActorLogContext,
|
|
15201
15355
|
assistantUserName: botConfig.userName,
|
|
15202
|
-
modelId:
|
|
15356
|
+
modelId: activeModelId
|
|
15203
15357
|
});
|
|
15204
15358
|
const wiring = await wireAgentTools({
|
|
15205
15359
|
abortAgent: () => agent?.abort(),
|
|
@@ -15223,6 +15377,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15223
15377
|
preAgentPromptMessages,
|
|
15224
15378
|
priorPiMessages,
|
|
15225
15379
|
recordConnectedMcpProvider,
|
|
15380
|
+
requestHandoff,
|
|
15226
15381
|
resume: runResume,
|
|
15227
15382
|
routing,
|
|
15228
15383
|
sessionConversationId,
|
|
@@ -15238,6 +15393,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15238
15393
|
mcpToolManager = wiring.mcpToolManager;
|
|
15239
15394
|
const sandboxExecutor = wiring.sandboxExecutor;
|
|
15240
15395
|
const getPendingAuthPause = wiring.getPendingAuthPause;
|
|
15396
|
+
const toolsAfterHandoff = wiring.agentTools.filter(
|
|
15397
|
+
(tool) => tool.name !== HANDOFF_TOOL_NAME
|
|
15398
|
+
);
|
|
15241
15399
|
const {
|
|
15242
15400
|
baseInstructions,
|
|
15243
15401
|
inputMessages,
|
|
@@ -15265,6 +15423,38 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15265
15423
|
});
|
|
15266
15424
|
let hasEmittedText = false;
|
|
15267
15425
|
let needsSeparator = false;
|
|
15426
|
+
let bufferedStandardText = "";
|
|
15427
|
+
let bufferedStandardMessageStart = false;
|
|
15428
|
+
const startAssistantMessage = () => {
|
|
15429
|
+
Promise.resolve(observers.onAssistantMessageStart?.()).catch((error) => {
|
|
15430
|
+
logWarn(
|
|
15431
|
+
"streaming_message_start_error",
|
|
15432
|
+
{},
|
|
15433
|
+
{
|
|
15434
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15435
|
+
},
|
|
15436
|
+
"Failed to deliver assistant message start to stream coordinator"
|
|
15437
|
+
);
|
|
15438
|
+
});
|
|
15439
|
+
if (hasEmittedText) {
|
|
15440
|
+
needsSeparator = true;
|
|
15441
|
+
}
|
|
15442
|
+
};
|
|
15443
|
+
const deliverText = (deltaText) => {
|
|
15444
|
+
const text = needsSeparator ? "\n\n" + deltaText : deltaText;
|
|
15445
|
+
needsSeparator = false;
|
|
15446
|
+
hasEmittedText = true;
|
|
15447
|
+
Promise.resolve(observers.onTextDelta?.(text)).catch((error) => {
|
|
15448
|
+
logWarn(
|
|
15449
|
+
"streaming_text_delta_error",
|
|
15450
|
+
{},
|
|
15451
|
+
{
|
|
15452
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15453
|
+
},
|
|
15454
|
+
"Failed to deliver text delta to stream"
|
|
15455
|
+
);
|
|
15456
|
+
});
|
|
15457
|
+
};
|
|
15268
15458
|
const drainSteeringMessages = async () => {
|
|
15269
15459
|
if (!durability.drainSteeringMessages || !sessionRecordState.canUseTurnSession || !sessionConversationId || !sessionId) {
|
|
15270
15460
|
return;
|
|
@@ -15313,18 +15503,60 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15313
15503
|
}
|
|
15314
15504
|
};
|
|
15315
15505
|
const apiKeyOverride = getPiGatewayApiKey();
|
|
15316
|
-
agent = new
|
|
15506
|
+
agent = new Agent({
|
|
15317
15507
|
...apiKeyOverride ? { getApiKey: () => apiKeyOverride } : {},
|
|
15318
15508
|
streamFn: createTracedStreamFn({ conversationPrivacy }),
|
|
15319
15509
|
steeringMode: "all",
|
|
15510
|
+
beforeToolCall: async ({ assistantMessage }) => {
|
|
15511
|
+
const toolCalls2 = assistantMessage.content.filter(
|
|
15512
|
+
(part) => part.type === "toolCall"
|
|
15513
|
+
);
|
|
15514
|
+
const containsHandoff = toolCalls2.some(
|
|
15515
|
+
(call) => call.name === HANDOFF_TOOL_NAME
|
|
15516
|
+
);
|
|
15517
|
+
if (containsHandoff && toolCalls2.length !== 1) {
|
|
15518
|
+
return {
|
|
15519
|
+
block: true,
|
|
15520
|
+
reason: "handoff must be the only tool call in its assistant message; reissue it alone"
|
|
15521
|
+
};
|
|
15522
|
+
}
|
|
15523
|
+
return void 0;
|
|
15524
|
+
},
|
|
15320
15525
|
prepareNextTurn: async () => {
|
|
15526
|
+
let update;
|
|
15527
|
+
if (pendingHandoff) {
|
|
15528
|
+
const { messages, model, thinkingLevel } = pendingHandoff;
|
|
15529
|
+
const replacement = [...messages];
|
|
15530
|
+
pendingHandoff = void 0;
|
|
15531
|
+
agent.state.messages = replacement;
|
|
15532
|
+
agent.state.model = model;
|
|
15533
|
+
agent.state.thinkingLevel = thinkingLevel;
|
|
15534
|
+
agent.state.tools = toolsAfterHandoff;
|
|
15535
|
+
runResume.setBeforeMessageCount(replacement.length);
|
|
15536
|
+
runResume.setTurnStartMessageIndex(0);
|
|
15537
|
+
runResume.adoptCommittedBoundary(replacement);
|
|
15538
|
+
setSpanAttributes({
|
|
15539
|
+
"gen_ai.request.model": activeModelId,
|
|
15540
|
+
"gen_ai.request.reasoning.level": thinkingSelection.thinkingLevel,
|
|
15541
|
+
"app.ai.model_profile": activeModelProfile
|
|
15542
|
+
});
|
|
15543
|
+
update = {
|
|
15544
|
+
context: {
|
|
15545
|
+
systemPrompt: baseInstructions,
|
|
15546
|
+
messages: replacement,
|
|
15547
|
+
tools: toolsAfterHandoff
|
|
15548
|
+
},
|
|
15549
|
+
model,
|
|
15550
|
+
thinkingLevel
|
|
15551
|
+
};
|
|
15552
|
+
}
|
|
15321
15553
|
await drainSteeringMessages();
|
|
15322
15554
|
runResume.yieldAtSafeBoundaryIfDue(currentAgentMessages());
|
|
15323
|
-
return
|
|
15555
|
+
return update;
|
|
15324
15556
|
},
|
|
15325
15557
|
initialState: {
|
|
15326
15558
|
systemPrompt: baseInstructions,
|
|
15327
|
-
model: resolveGatewayModel(
|
|
15559
|
+
model: resolveGatewayModel(activeModelId),
|
|
15328
15560
|
thinkingLevel: toAgentThinkingLevel(thinkingSelection.thinkingLevel),
|
|
15329
15561
|
tools: wiring.agentTools
|
|
15330
15562
|
}
|
|
@@ -15334,43 +15566,46 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15334
15566
|
return recordParentToolExecutionStart(event);
|
|
15335
15567
|
}
|
|
15336
15568
|
if (event.type === "turn_end" && event.toolResults.length > 0) {
|
|
15569
|
+
if (pendingHandoff) {
|
|
15570
|
+
return;
|
|
15571
|
+
}
|
|
15337
15572
|
return runResume.persistSafeBoundary([...agent.state.messages]).then(() => void 0);
|
|
15338
15573
|
}
|
|
15339
15574
|
if (event.type === "message_start") {
|
|
15340
|
-
|
|
15341
|
-
|
|
15342
|
-
|
|
15343
|
-
|
|
15344
|
-
|
|
15345
|
-
|
|
15346
|
-
|
|
15347
|
-
|
|
15348
|
-
|
|
15349
|
-
|
|
15350
|
-
|
|
15575
|
+
if (activeModelProfile === STANDARD_MODEL_PROFILE && requestHandoff) {
|
|
15576
|
+
bufferedStandardMessageStart = true;
|
|
15577
|
+
bufferedStandardText = "";
|
|
15578
|
+
} else {
|
|
15579
|
+
startAssistantMessage();
|
|
15580
|
+
}
|
|
15581
|
+
return;
|
|
15582
|
+
}
|
|
15583
|
+
if (event.type === "message_end" && isAssistantMessage(event.message)) {
|
|
15584
|
+
if (!bufferedStandardMessageStart) {
|
|
15585
|
+
return;
|
|
15586
|
+
}
|
|
15587
|
+
const containsHandoff = event.message.content.some(
|
|
15588
|
+
(part) => part.type === "toolCall" && part.name === HANDOFF_TOOL_NAME
|
|
15351
15589
|
);
|
|
15352
|
-
if (
|
|
15353
|
-
|
|
15590
|
+
if (!containsHandoff) {
|
|
15591
|
+
startAssistantMessage();
|
|
15592
|
+
if (bufferedStandardText) {
|
|
15593
|
+
deliverText(bufferedStandardText);
|
|
15594
|
+
}
|
|
15354
15595
|
}
|
|
15596
|
+
bufferedStandardMessageStart = false;
|
|
15597
|
+
bufferedStandardText = "";
|
|
15355
15598
|
return;
|
|
15356
15599
|
}
|
|
15357
15600
|
if (event.type !== "message_update") return;
|
|
15358
15601
|
if (event.assistantMessageEvent.type !== "text_delta") return;
|
|
15359
15602
|
const deltaText = event.assistantMessageEvent.delta;
|
|
15360
15603
|
if (!deltaText) return;
|
|
15361
|
-
|
|
15362
|
-
|
|
15363
|
-
|
|
15364
|
-
|
|
15365
|
-
|
|
15366
|
-
"streaming_text_delta_error",
|
|
15367
|
-
{},
|
|
15368
|
-
{
|
|
15369
|
-
"exception.message": error instanceof Error ? error.message : String(error)
|
|
15370
|
-
},
|
|
15371
|
-
"Failed to deliver text delta to stream"
|
|
15372
|
-
);
|
|
15373
|
-
});
|
|
15604
|
+
if (bufferedStandardMessageStart) {
|
|
15605
|
+
bufferedStandardText += deltaText;
|
|
15606
|
+
} else {
|
|
15607
|
+
deliverText(deltaText);
|
|
15608
|
+
}
|
|
15374
15609
|
});
|
|
15375
15610
|
let newMessages = [];
|
|
15376
15611
|
try {
|
|
@@ -15387,7 +15622,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15387
15622
|
runResume.setTurnStartMessageIndex(agent.state.messages.length);
|
|
15388
15623
|
}
|
|
15389
15624
|
await withSpan(
|
|
15390
|
-
`invoke_agent ${
|
|
15625
|
+
`invoke_agent ${activeModelId}`,
|
|
15391
15626
|
"gen_ai.invoke_agent",
|
|
15392
15627
|
spanContext,
|
|
15393
15628
|
async () => {
|
|
@@ -15452,7 +15687,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15452
15687
|
{
|
|
15453
15688
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
15454
15689
|
"gen_ai.operation.name": "invoke_agent",
|
|
15455
|
-
"gen_ai.request.model":
|
|
15690
|
+
"gen_ai.request.model": activeModelId,
|
|
15456
15691
|
...thinkingSelection ? {
|
|
15457
15692
|
"gen_ai.request.reasoning.level": thinkingSelection.thinkingLevel
|
|
15458
15693
|
} : {},
|
|
@@ -15517,7 +15752,11 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15517
15752
|
...outputMessages
|
|
15518
15753
|
);
|
|
15519
15754
|
const currentUsage = hasAgentTurnUsage(usageSummary) ? usageSummary : void 0;
|
|
15520
|
-
|
|
15755
|
+
const currentPhaseUsage = addAgentTurnUsage(
|
|
15756
|
+
retryUsage,
|
|
15757
|
+
currentUsage
|
|
15758
|
+
);
|
|
15759
|
+
turnUsage = addAgentTurnUsage(handoffPhaseUsage, currentPhaseUsage);
|
|
15521
15760
|
setSpanAttributes({
|
|
15522
15761
|
...outputMessagesAttribute ? { "gen_ai.output.messages": outputMessagesAttribute } : {},
|
|
15523
15762
|
...toGenAiMessagesTraceAttributes(
|
|
@@ -15541,7 +15780,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15541
15780
|
if (!providerRetry) {
|
|
15542
15781
|
break;
|
|
15543
15782
|
}
|
|
15544
|
-
retryUsage =
|
|
15783
|
+
retryUsage = currentPhaseUsage;
|
|
15545
15784
|
agent.state.messages = providerRetry.messages;
|
|
15546
15785
|
await runResume.persistSafeBoundary(providerRetry.messages);
|
|
15547
15786
|
logWarn(
|
|
@@ -15558,7 +15797,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15558
15797
|
{
|
|
15559
15798
|
"gen_ai.provider.name": GEN_AI_PROVIDER_NAME,
|
|
15560
15799
|
"gen_ai.operation.name": "invoke_agent",
|
|
15561
|
-
"gen_ai.request.model":
|
|
15800
|
+
"gen_ai.request.model": activeModelId,
|
|
15562
15801
|
"gen_ai.output.type": "text",
|
|
15563
15802
|
"server.address": GEN_AI_SERVER_ADDRESS,
|
|
15564
15803
|
"server.port": GEN_AI_SERVER_PORT,
|
|
@@ -15594,7 +15833,8 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15594
15833
|
usage: turnUsage,
|
|
15595
15834
|
thinkingSelection,
|
|
15596
15835
|
correlation: routing.correlation,
|
|
15597
|
-
assistantUserName: botConfig.userName
|
|
15836
|
+
assistantUserName: botConfig.userName,
|
|
15837
|
+
modelId: activeModelId
|
|
15598
15838
|
})
|
|
15599
15839
|
};
|
|
15600
15840
|
} catch (error) {
|
|
@@ -15607,6 +15847,9 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15607
15847
|
return outcome;
|
|
15608
15848
|
}
|
|
15609
15849
|
}
|
|
15850
|
+
if (error instanceof ModelProfileNotConfiguredError) {
|
|
15851
|
+
throw error;
|
|
15852
|
+
}
|
|
15610
15853
|
if (isProviderRetryError(error)) {
|
|
15611
15854
|
throw error;
|
|
15612
15855
|
}
|
|
@@ -15629,7 +15872,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15629
15872
|
runId: routing.correlation?.runId,
|
|
15630
15873
|
...credentialActorLogContext,
|
|
15631
15874
|
assistantUserName: botConfig.userName,
|
|
15632
|
-
modelId:
|
|
15875
|
+
modelId: activeModelId
|
|
15633
15876
|
},
|
|
15634
15877
|
{},
|
|
15635
15878
|
"executeAgentRun failed"
|
|
@@ -15642,7 +15885,7 @@ async function executeAgentRunInPrivacyContext(request, conversationPrivacy) {
|
|
|
15642
15885
|
...getSandboxMetadata(),
|
|
15643
15886
|
diagnostics: {
|
|
15644
15887
|
outcome: "provider_error",
|
|
15645
|
-
modelId:
|
|
15888
|
+
modelId: activeModelId,
|
|
15646
15889
|
assistantMessageCount: 0,
|
|
15647
15890
|
...thinkingSelection ? {
|
|
15648
15891
|
thinkingLevel: thinkingSelection.thinkingLevel
|
|
@@ -15729,6 +15972,7 @@ export {
|
|
|
15729
15972
|
finalizeMcpAuthorization,
|
|
15730
15973
|
resolvePluginOAuthAccount,
|
|
15731
15974
|
executeCredentialedEgressRequest,
|
|
15975
|
+
createContextCompactor,
|
|
15732
15976
|
executeAgentRun,
|
|
15733
15977
|
createAgentRunner
|
|
15734
15978
|
};
|