@sentry/junior 0.88.0 → 0.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -5
- package/dist/{agent-hooks-RIJ5TSWP.js → agent-hooks-MXAF7RQL.js} +10 -10
- package/dist/api/people/list.js +8 -8
- package/dist/api/people/profile.js +8 -8
- package/dist/api-reference.d.ts +1 -1
- package/dist/app.js +716 -732
- package/dist/{catalog-runtime-MW7XERSU.js → catalog-runtime-DXE6NXHT.js} +5 -5
- package/dist/chat/agent/index.d.ts +4 -0
- package/dist/chat/agent/prompt.d.ts +78 -0
- package/dist/chat/{respond.d.ts → agent/request.d.ts} +98 -55
- package/dist/chat/agent/resume.d.ts +65 -0
- package/dist/chat/agent/sandbox.d.ts +15 -0
- package/dist/chat/agent/session.d.ts +20 -0
- package/dist/chat/agent/skills.d.ts +26 -0
- package/dist/chat/agent/tools.d.ts +78 -0
- package/dist/chat/agent-dispatch/runner.d.ts +3 -5
- package/dist/chat/app/production.d.ts +3 -1
- package/dist/chat/app/services.d.ts +1 -4
- package/dist/chat/logging.d.ts +2 -0
- package/dist/chat/mcp/tool-manager.d.ts +1 -6
- package/dist/chat/pi/messages.d.ts +18 -2
- package/dist/chat/pi/transcript.d.ts +31 -0
- package/dist/chat/plugins/agent-hooks.d.ts +2 -2
- package/dist/chat/prompt.d.ts +1 -1
- package/dist/chat/runtime/agent-continue-runner.d.ts +5 -5
- package/dist/chat/runtime/agent-run-outcome.d.ts +21 -0
- package/dist/chat/runtime/agent-runner.d.ts +11 -0
- package/dist/chat/runtime/delivered-turn-state.d.ts +2 -2
- package/dist/chat/runtime/generated-artifacts.d.ts +16 -0
- package/dist/chat/runtime/reply-executor.d.ts +2 -2
- package/dist/chat/runtime/slack-resume.d.ts +21 -12
- package/dist/chat/runtime/turn.d.ts +5 -39
- package/dist/chat/services/reply-delivery-plan.d.ts +0 -8
- package/dist/chat/services/turn-failure-response.d.ts +4 -4
- package/dist/chat/services/turn-result.d.ts +4 -7
- package/dist/chat/slack/channel.d.ts +9 -5
- package/dist/chat/slack/client.d.ts +3 -1
- package/dist/chat/slack/context.d.ts +17 -5
- package/dist/chat/slack/id-param.d.ts +25 -0
- package/dist/chat/slack/ids.d.ts +18 -4
- package/dist/chat/slack/outbound.d.ts +16 -0
- package/dist/chat/slack/output.d.ts +3 -3
- package/dist/chat/slack/reply.d.ts +4 -7
- package/dist/chat/slack/timestamp-param.d.ts +25 -0
- package/dist/chat/slack/tools/canvas/context.d.ts +18 -0
- package/dist/chat/slack/tools/canvas/create.d.ts +4 -0
- package/dist/chat/slack/tools/canvas/edit.d.ts +3 -0
- package/dist/chat/slack/tools/canvas/read.d.ts +6 -0
- package/dist/chat/slack/tools/canvas/write.d.ts +3 -0
- package/dist/chat/{tools/slack → slack/tools}/channel-access.d.ts +4 -3
- package/dist/chat/{tools → slack/tools}/channel-capabilities.d.ts +2 -0
- package/dist/chat/slack/tools/channel-list-messages.d.ts +3 -0
- package/dist/chat/{tools/slack → slack/tools}/context.d.ts +5 -4
- package/dist/chat/slack/tools/list/add-items.d.ts +3 -0
- package/dist/chat/{tools/slack/lists.d.ts → slack/tools/list/api.d.ts} +2 -1
- package/dist/chat/slack/tools/list/create.d.ts +3 -0
- package/dist/chat/slack/tools/list/get-items.d.ts +3 -0
- package/dist/chat/slack/tools/list/update-item.d.ts +3 -0
- package/dist/chat/slack/tools/message-add-reaction.d.ts +4 -0
- package/dist/chat/slack/tools/send-message.d.ts +11 -0
- package/dist/chat/{tools/slack → slack/tools}/slack-message-url.d.ts +5 -5
- package/dist/chat/slack/tools/thread-read.d.ts +6 -0
- package/dist/chat/slack/tools/user-lookup.d.ts +2 -0
- package/dist/chat/slack/users.d.ts +2 -1
- package/dist/chat/{services → slack}/vision-context.d.ts +4 -2
- package/dist/chat/state/session-log.d.ts +1 -1
- package/dist/chat/tool-exposure.d.ts +10 -0
- package/dist/chat/tool-support/catalog-tool-call.d.ts +10 -0
- package/dist/chat/{tools/execution → tool-support}/normalize-result.d.ts +4 -1
- package/dist/chat/{tools/agent-tools.d.ts → tool-support/pi-tool-adapter.d.ts} +3 -9
- package/dist/chat/tool-support/schema-summary.d.ts +2 -0
- package/dist/chat/{tools → tool-support}/skill/mcp-tool-summary.d.ts +0 -6
- package/dist/chat/tool-support/structured-result.d.ts +73 -0
- package/dist/chat/tool-support/text-range-result.d.ts +58 -0
- package/dist/chat/tool-support/tool-execution-report.d.ts +7 -0
- package/dist/chat/tool-support/zod-tool.d.ts +27 -0
- package/dist/chat/tools/advisor/tool.d.ts +9 -18
- package/dist/chat/tools/definition.d.ts +56 -9
- package/dist/chat/tools/execute-tool.d.ts +3 -0
- package/dist/chat/tools/index.d.ts +3 -2
- package/dist/chat/tools/resource-events.d.ts +3 -13
- package/dist/chat/tools/runtime/report-progress.d.ts +1 -3
- package/dist/chat/tools/sandbox/bash.d.ts +1 -4
- package/dist/chat/tools/sandbox/edit-file.d.ts +25 -7
- package/dist/chat/tools/sandbox/file-uploads.d.ts +30 -0
- package/dist/chat/tools/sandbox/file-utils.d.ts +10 -1
- package/dist/chat/tools/sandbox/find-files.d.ts +12 -11
- package/dist/chat/tools/sandbox/grep.d.ts +18 -12
- package/dist/chat/tools/sandbox/list-dir.d.ts +15 -7
- package/dist/chat/tools/sandbox/read-file.d.ts +2 -31
- package/dist/chat/tools/sandbox/write-file.d.ts +1 -4
- package/dist/chat/tools/search-tools.d.ts +4 -0
- package/dist/chat/tools/skill/call-mcp-tool.d.ts +1 -4
- package/dist/chat/tools/skill/load-skill.d.ts +4 -5
- package/dist/chat/tools/skill/search-mcp-tools.d.ts +1 -5
- package/dist/chat/tools/system-time.d.ts +1 -1
- package/dist/chat/tools/types.d.ts +15 -5
- package/dist/chat/tools/web/fetch-content.d.ts +4 -2
- package/dist/chat/tools/web/fetch-tool.d.ts +4 -4
- package/dist/chat/tools/web/image-generate.d.ts +4 -3
- package/dist/chat/tools/web/search.d.ts +1 -4
- package/dist/{chunk-4IXHIV37.js → chunk-2S7M37HY.js} +6 -8
- package/dist/{chunk-L7OHKDOX.js → chunk-3MPOMK3K.js} +58 -7
- package/dist/{chunk-V6XDCS3X.js → chunk-5GBUZI6M.js} +4 -4
- package/dist/{chunk-7ES37H6U.js → chunk-AN2437E3.js} +4 -4
- package/dist/chunk-AOISHLSF.js +747 -0
- package/dist/{chunk-NYJLQI42.js → chunk-BKSZL4QO.js} +11257 -11957
- package/dist/{chunk-XS6NLQPA.js → chunk-DACFZ5CI.js} +474 -33
- package/dist/chunk-GCWD2VHP.js +1216 -0
- package/dist/chunk-GHGPTPBL.js +53 -0
- package/dist/{chunk-S35CPNPT.js → chunk-HXL2ZV74.js} +40 -216
- package/dist/{chunk-PBV4ZIVM.js → chunk-IRRMABQD.js} +1 -1
- package/dist/{chunk-2DPZRS3B.js → chunk-IX76WFJV.js} +8 -8
- package/dist/{chunk-66NX7MNW.js → chunk-KC42JAAQ.js} +1 -1
- package/dist/chunk-LFLTJQVR.js +90 -0
- package/dist/{chunk-IATAYWFU.js → chunk-NW7AXDA5.js} +2 -2
- package/dist/{chunk-F22AM3OW.js → chunk-NYWPISSO.js} +1 -1
- package/dist/chunk-OB42YVAE.js +16 -0
- package/dist/chunk-ONFOWI2D.js +955 -0
- package/dist/chunk-PHZHJTCK.js +1062 -0
- package/dist/{chunk-6UPQ5GTJ.js → chunk-QCKGI74V.js} +7 -7
- package/dist/{chunk-YPAE5RH3.js → chunk-RS6ANWVT.js} +1 -1
- package/dist/{chunk-C5NCV3OB.js → chunk-TYUXD3FN.js} +1 -1
- package/dist/{chunk-KBFQXJL4.js → chunk-XP7F4LYB.js} +5 -7
- package/dist/{chunk-VMBZFPZM.js → chunk-ZUK7BL63.js} +187 -9
- package/dist/cli/chat.js +55 -40
- package/dist/cli/check.js +6 -6
- package/dist/cli/init.js +30 -36
- package/dist/cli/plugins.js +16 -16
- package/dist/cli/snapshot-warmup.js +9 -9
- package/dist/cli/upgrade.js +21 -21
- package/dist/db-CXI7PR5U.js +18 -0
- package/dist/handlers/agent-dispatch.d.ts +3 -3
- package/dist/handlers/mcp-oauth-callback.d.ts +3 -3
- package/dist/handlers/oauth-callback.d.ts +3 -3
- package/dist/instrumentation.js +6 -5
- package/dist/nitro.js +3 -7
- package/dist/reporting.js +23 -25
- package/dist/{runner-BCRF2FCI.js → runner-FKL3RAHA.js} +89 -77
- package/dist/{validation-FMJO3L5P.js → validation-I7GD2YWS.js} +6 -6
- package/package.json +6 -6
- package/dist/chat/respond-helpers.d.ts +0 -82
- package/dist/chat/services/attachment-claims.d.ts +0 -2
- package/dist/chat/services/channel-intent.d.ts +0 -2
- package/dist/chat/tools/sandbox/attach-file.d.ts +0 -7
- package/dist/chat/tools/slack/canvas-tools.d.ts +0 -30
- package/dist/chat/tools/slack/channel-list-messages.d.ts +0 -9
- package/dist/chat/tools/slack/channel-post-message.d.ts +0 -5
- package/dist/chat/tools/slack/list-tools.d.ts +0 -21
- package/dist/chat/tools/slack/message-add-reaction.d.ts +0 -5
- package/dist/chat/tools/slack/thread-read.d.ts +0 -12
- package/dist/chat/tools/slack/user-lookup.d.ts +0 -8
- package/dist/chunk-AHLSXMOU.js +0 -506
- package/dist/chunk-FTMXFBDC.js +0 -49
- package/dist/chunk-KBSLCOGE.js +0 -2226
- package/dist/chunk-KQKIA4CU.js +0 -186
- package/dist/db-37HOGLI7.js +0 -18
- /package/dist/chat/{tools/slack/canvases.d.ts → slack/tools/canvas/api.d.ts} +0 -0
|
@@ -0,0 +1,1216 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getConnectedStateContext,
|
|
3
|
+
getStateAdapter
|
|
4
|
+
} from "./chunk-RS6ANWVT.js";
|
|
5
|
+
import {
|
|
6
|
+
getConversationStore
|
|
7
|
+
} from "./chunk-2S7M37HY.js";
|
|
8
|
+
import {
|
|
9
|
+
getChatConfig
|
|
10
|
+
} from "./chunk-HXL2ZV74.js";
|
|
11
|
+
import {
|
|
12
|
+
parseDestination
|
|
13
|
+
} from "./chunk-GHGPTPBL.js";
|
|
14
|
+
import {
|
|
15
|
+
logWarn,
|
|
16
|
+
parseRequester,
|
|
17
|
+
storedSlackRequesterSchema,
|
|
18
|
+
toStoredSlackRequester
|
|
19
|
+
} from "./chunk-ZUK7BL63.js";
|
|
20
|
+
import {
|
|
21
|
+
isRecord
|
|
22
|
+
} from "./chunk-OB42YVAE.js";
|
|
23
|
+
|
|
24
|
+
// src/chat/state/session-log.ts
|
|
25
|
+
import { isDeepStrictEqual } from "util";
|
|
26
|
+
import { z as z2 } from "zod";
|
|
27
|
+
|
|
28
|
+
// src/chat/pi/messages.ts
|
|
29
|
+
import { z } from "zod";
|
|
30
|
+
var piMessageSchema = z.object({
|
|
31
|
+
role: z.string()
|
|
32
|
+
}).passthrough().transform((value) => value);
|
|
33
|
+
var piContentMessageSchema = z.object({
|
|
34
|
+
content: z.array(z.unknown()),
|
|
35
|
+
role: z.string().min(1)
|
|
36
|
+
}).passthrough().transform((value) => value);
|
|
37
|
+
|
|
38
|
+
// src/chat/state/session-log.ts
|
|
39
|
+
var AGENT_SESSION_LOG_PREFIX = "junior:agent-session-log";
|
|
40
|
+
var AGENT_SESSION_LOG_SCHEMA_VERSION = 1;
|
|
41
|
+
var INITIAL_SESSION_ID = "session_0";
|
|
42
|
+
var SESSION_ID_PREFIX = "session_";
|
|
43
|
+
var STATE_STORE_LOCK_TTL_MS = 5e3;
|
|
44
|
+
var piMessageEntrySchema = z2.object({
|
|
45
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
46
|
+
type: z2.literal("pi_message"),
|
|
47
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
48
|
+
message: piMessageSchema,
|
|
49
|
+
requester: storedSlackRequesterSchema.optional()
|
|
50
|
+
});
|
|
51
|
+
var projectionResetEntrySchema = z2.object({
|
|
52
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
53
|
+
type: z2.literal("projection_reset"),
|
|
54
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
55
|
+
messages: z2.array(piMessageSchema),
|
|
56
|
+
requester: storedSlackRequesterSchema.optional()
|
|
57
|
+
});
|
|
58
|
+
var requesterRecordedEntrySchema = z2.object({
|
|
59
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
60
|
+
type: z2.literal("requester_recorded"),
|
|
61
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
62
|
+
requester: storedSlackRequesterSchema
|
|
63
|
+
});
|
|
64
|
+
var mcpProviderConnectedEntrySchema = z2.object({
|
|
65
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
66
|
+
type: z2.literal("mcp_provider_connected"),
|
|
67
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
68
|
+
provider: z2.string().min(1)
|
|
69
|
+
});
|
|
70
|
+
var authorizationKindSchema = z2.union([
|
|
71
|
+
z2.literal("plugin"),
|
|
72
|
+
z2.literal("mcp")
|
|
73
|
+
]);
|
|
74
|
+
var authorizationRequestedEntrySchema = z2.object({
|
|
75
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
76
|
+
type: z2.literal("authorization_requested"),
|
|
77
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
78
|
+
createdAtMs: z2.number().int().nonnegative(),
|
|
79
|
+
kind: authorizationKindSchema,
|
|
80
|
+
provider: z2.string().min(1),
|
|
81
|
+
requesterId: z2.string().min(1),
|
|
82
|
+
authorizationId: z2.string().min(1),
|
|
83
|
+
delivery: z2.union([
|
|
84
|
+
z2.literal("private_link_sent"),
|
|
85
|
+
z2.literal("private_link_reused")
|
|
86
|
+
])
|
|
87
|
+
});
|
|
88
|
+
var authorizationCompletedEntrySchema = z2.object({
|
|
89
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
90
|
+
type: z2.literal("authorization_completed"),
|
|
91
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
92
|
+
createdAtMs: z2.number().int().nonnegative(),
|
|
93
|
+
kind: authorizationKindSchema,
|
|
94
|
+
provider: z2.string().min(1),
|
|
95
|
+
requesterId: z2.string().min(1),
|
|
96
|
+
authorizationId: z2.string().min(1)
|
|
97
|
+
});
|
|
98
|
+
var transcriptRefSchema = z2.object({
|
|
99
|
+
type: z2.literal("advisor_session"),
|
|
100
|
+
parentConversationId: z2.string().min(1),
|
|
101
|
+
key: z2.string().min(1)
|
|
102
|
+
});
|
|
103
|
+
var toolExecutionStartedEntrySchema = z2.object({
|
|
104
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
105
|
+
type: z2.literal("tool_execution_started"),
|
|
106
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
107
|
+
createdAtMs: z2.number().int().nonnegative(),
|
|
108
|
+
toolCallId: z2.string().min(1),
|
|
109
|
+
toolName: z2.string().min(1),
|
|
110
|
+
args: z2.unknown().optional()
|
|
111
|
+
});
|
|
112
|
+
var subagentStartedEntrySchema = z2.object({
|
|
113
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
114
|
+
type: z2.literal("subagent_started"),
|
|
115
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
116
|
+
subagentInvocationId: z2.string().min(1),
|
|
117
|
+
subagentKind: z2.string().min(1),
|
|
118
|
+
parentToolCallId: z2.string().min(1).optional(),
|
|
119
|
+
parentConversationId: z2.string().min(1),
|
|
120
|
+
parentSessionId: z2.string().min(1).optional(),
|
|
121
|
+
transcriptRef: transcriptRefSchema,
|
|
122
|
+
historyMode: z2.literal("shared"),
|
|
123
|
+
createdAtMs: z2.number().int().nonnegative()
|
|
124
|
+
});
|
|
125
|
+
var subagentEndedEntrySchema = z2.object({
|
|
126
|
+
schemaVersion: z2.literal(AGENT_SESSION_LOG_SCHEMA_VERSION),
|
|
127
|
+
type: z2.literal("subagent_ended"),
|
|
128
|
+
sessionId: z2.string().min(1).default(INITIAL_SESSION_ID),
|
|
129
|
+
subagentInvocationId: z2.string().min(1),
|
|
130
|
+
outcome: z2.union([
|
|
131
|
+
z2.literal("success"),
|
|
132
|
+
z2.literal("error"),
|
|
133
|
+
z2.literal("aborted")
|
|
134
|
+
]),
|
|
135
|
+
errorCode: z2.string().min(1).optional(),
|
|
136
|
+
transcriptEndMessageIndex: z2.number().int().nonnegative().optional(),
|
|
137
|
+
transcriptStartMessageIndex: z2.number().int().nonnegative().optional(),
|
|
138
|
+
createdAtMs: z2.number().int().nonnegative()
|
|
139
|
+
});
|
|
140
|
+
var sessionLogEntrySchema = z2.discriminatedUnion("type", [
|
|
141
|
+
piMessageEntrySchema,
|
|
142
|
+
projectionResetEntrySchema,
|
|
143
|
+
requesterRecordedEntrySchema,
|
|
144
|
+
mcpProviderConnectedEntrySchema,
|
|
145
|
+
authorizationRequestedEntrySchema,
|
|
146
|
+
authorizationCompletedEntrySchema,
|
|
147
|
+
toolExecutionStartedEntrySchema,
|
|
148
|
+
subagentStartedEntrySchema,
|
|
149
|
+
subagentEndedEntrySchema
|
|
150
|
+
]);
|
|
151
|
+
function key(scope) {
|
|
152
|
+
const prefix = getChatConfig().state.keyPrefix;
|
|
153
|
+
return [
|
|
154
|
+
...prefix ? [prefix] : [],
|
|
155
|
+
AGENT_SESSION_LOG_PREFIX,
|
|
156
|
+
scope.conversationId
|
|
157
|
+
].join(":");
|
|
158
|
+
}
|
|
159
|
+
function rawKey(scope) {
|
|
160
|
+
return [AGENT_SESSION_LOG_PREFIX, scope.conversationId].join(":");
|
|
161
|
+
}
|
|
162
|
+
function normalizeMessageCount(value) {
|
|
163
|
+
return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : 0;
|
|
164
|
+
}
|
|
165
|
+
function countMatchingPrefix(left, right) {
|
|
166
|
+
const limit = Math.min(left.length, right.length);
|
|
167
|
+
for (let index = 0; index < limit; index += 1) {
|
|
168
|
+
if (!isDeepStrictEqual(left[index], right[index])) {
|
|
169
|
+
return index;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return limit;
|
|
173
|
+
}
|
|
174
|
+
function entrySessionId(entry) {
|
|
175
|
+
return entry.sessionId ?? INITIAL_SESSION_ID;
|
|
176
|
+
}
|
|
177
|
+
function isActivityEntry(entry) {
|
|
178
|
+
return entry.type === "tool_execution_started" || entry.type === "subagent_started" || entry.type === "subagent_ended";
|
|
179
|
+
}
|
|
180
|
+
function latestProjectionResetIndex(entries) {
|
|
181
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
182
|
+
if (entries[index]?.type === "projection_reset") {
|
|
183
|
+
return index;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return -1;
|
|
187
|
+
}
|
|
188
|
+
function currentSessionId(entries) {
|
|
189
|
+
const resetIndex = latestProjectionResetIndex(entries);
|
|
190
|
+
if (resetIndex < 0) {
|
|
191
|
+
return INITIAL_SESSION_ID;
|
|
192
|
+
}
|
|
193
|
+
return entrySessionId(entries[resetIndex]);
|
|
194
|
+
}
|
|
195
|
+
function nextSessionId(entries) {
|
|
196
|
+
const resetCount = entries.filter(
|
|
197
|
+
(entry) => entry.type === "projection_reset"
|
|
198
|
+
).length;
|
|
199
|
+
return `${SESSION_ID_PREFIX}${resetCount + 1}`;
|
|
200
|
+
}
|
|
201
|
+
function projectionEntries(entries, sessionId) {
|
|
202
|
+
if (sessionId) {
|
|
203
|
+
const sessionEntries = [];
|
|
204
|
+
let started = false;
|
|
205
|
+
for (const entry of entries) {
|
|
206
|
+
const entryId = entrySessionId(entry);
|
|
207
|
+
if (!started) {
|
|
208
|
+
if (entryId !== sessionId) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
started = true;
|
|
212
|
+
} else if (entry.type === "projection_reset" && entryId !== sessionId) {
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
if (entryId === sessionId) {
|
|
216
|
+
sessionEntries.push(entry);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return sessionEntries;
|
|
220
|
+
}
|
|
221
|
+
const resetIndex = latestProjectionResetIndex(entries);
|
|
222
|
+
const startIndex = resetIndex < 0 ? 0 : resetIndex;
|
|
223
|
+
const currentId = resetIndex < 0 ? INITIAL_SESSION_ID : entrySessionId(entries[resetIndex]);
|
|
224
|
+
return entries.slice(startIndex).filter((entry) => entrySessionId(entry) === currentId);
|
|
225
|
+
}
|
|
226
|
+
function findLastIndex(values, predicate) {
|
|
227
|
+
for (let index = values.length - 1; index >= 0; index -= 1) {
|
|
228
|
+
if (predicate(values[index])) return index;
|
|
229
|
+
}
|
|
230
|
+
return -1;
|
|
231
|
+
}
|
|
232
|
+
function piEntry(message, sessionId, requester) {
|
|
233
|
+
return {
|
|
234
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
235
|
+
type: "pi_message",
|
|
236
|
+
sessionId,
|
|
237
|
+
message,
|
|
238
|
+
...requester ? { requester } : {}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function resetEntry(messages, sessionId, requester) {
|
|
242
|
+
return {
|
|
243
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
244
|
+
type: "projection_reset",
|
|
245
|
+
sessionId,
|
|
246
|
+
messages,
|
|
247
|
+
...requester ? { requester } : {}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
function requesterRecordedEntry(requester, sessionId) {
|
|
251
|
+
return {
|
|
252
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
253
|
+
type: "requester_recorded",
|
|
254
|
+
sessionId,
|
|
255
|
+
requester
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
function mcpProviderConnectedEntry(provider, sessionId) {
|
|
259
|
+
return {
|
|
260
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
261
|
+
type: "mcp_provider_connected",
|
|
262
|
+
sessionId,
|
|
263
|
+
provider
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function authorizationObservationMessage(entry) {
|
|
267
|
+
const label = entry.kind === "mcp" ? "MCP authorization" : "Authorization";
|
|
268
|
+
return {
|
|
269
|
+
role: "user",
|
|
270
|
+
content: [
|
|
271
|
+
{
|
|
272
|
+
type: "text",
|
|
273
|
+
text: `${label} completed for provider "${entry.provider}". Continue the blocked request and retry the provider operation if needed.`
|
|
274
|
+
}
|
|
275
|
+
],
|
|
276
|
+
timestamp: entry.createdAtMs
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function authorizationRequestedEntry(args) {
|
|
280
|
+
return {
|
|
281
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
282
|
+
type: "authorization_requested",
|
|
283
|
+
sessionId: args.sessionId,
|
|
284
|
+
createdAtMs: args.createdAtMs,
|
|
285
|
+
kind: args.kind,
|
|
286
|
+
provider: args.provider,
|
|
287
|
+
requesterId: args.requesterId,
|
|
288
|
+
authorizationId: args.authorizationId,
|
|
289
|
+
delivery: args.delivery
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
function authorizationCompletedEntry(args) {
|
|
293
|
+
return {
|
|
294
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
295
|
+
type: "authorization_completed",
|
|
296
|
+
sessionId: args.sessionId,
|
|
297
|
+
createdAtMs: args.createdAtMs,
|
|
298
|
+
kind: args.kind,
|
|
299
|
+
provider: args.provider,
|
|
300
|
+
requesterId: args.requesterId,
|
|
301
|
+
authorizationId: args.authorizationId
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
function toolExecutionStartedEntry(args) {
|
|
305
|
+
return {
|
|
306
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
307
|
+
type: "tool_execution_started",
|
|
308
|
+
sessionId: args.sessionId,
|
|
309
|
+
createdAtMs: args.createdAtMs,
|
|
310
|
+
toolCallId: args.toolCallId,
|
|
311
|
+
toolName: args.toolName,
|
|
312
|
+
...args.args !== void 0 ? { args: args.args } : {}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function subagentStartedEntry(args) {
|
|
316
|
+
return {
|
|
317
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
318
|
+
type: "subagent_started",
|
|
319
|
+
sessionId: args.sessionId,
|
|
320
|
+
subagentInvocationId: args.subagentInvocationId,
|
|
321
|
+
subagentKind: args.subagentKind,
|
|
322
|
+
...args.parentToolCallId ? { parentToolCallId: args.parentToolCallId } : {},
|
|
323
|
+
parentConversationId: args.parentConversationId,
|
|
324
|
+
...args.parentSessionId ? { parentSessionId: args.parentSessionId } : {},
|
|
325
|
+
transcriptRef: args.transcriptRef,
|
|
326
|
+
historyMode: args.historyMode,
|
|
327
|
+
createdAtMs: args.createdAtMs
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
function subagentEndedEntry(args) {
|
|
331
|
+
return {
|
|
332
|
+
schemaVersion: AGENT_SESSION_LOG_SCHEMA_VERSION,
|
|
333
|
+
type: "subagent_ended",
|
|
334
|
+
sessionId: args.sessionId,
|
|
335
|
+
subagentInvocationId: args.subagentInvocationId,
|
|
336
|
+
outcome: args.outcome,
|
|
337
|
+
...args.errorCode ? { errorCode: args.errorCode } : {},
|
|
338
|
+
...args.transcriptEndMessageIndex !== void 0 ? { transcriptEndMessageIndex: args.transcriptEndMessageIndex } : {},
|
|
339
|
+
...args.transcriptStartMessageIndex !== void 0 ? { transcriptStartMessageIndex: args.transcriptStartMessageIndex } : {},
|
|
340
|
+
createdAtMs: args.createdAtMs
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function decode(value) {
|
|
344
|
+
if (typeof value === "string") {
|
|
345
|
+
return decode(JSON.parse(value));
|
|
346
|
+
}
|
|
347
|
+
const parsed = sessionLogEntrySchema.safeParse(value);
|
|
348
|
+
if (parsed.success) {
|
|
349
|
+
return parsed.data;
|
|
350
|
+
}
|
|
351
|
+
return piEntry(piMessageSchema.parse(value), INITIAL_SESSION_ID);
|
|
352
|
+
}
|
|
353
|
+
function project(entries, sessionId) {
|
|
354
|
+
let messages = [];
|
|
355
|
+
let requester;
|
|
356
|
+
for (const entry of projectionEntries(entries, sessionId)) {
|
|
357
|
+
if (entry.type === "pi_message") {
|
|
358
|
+
messages.push(entry.message);
|
|
359
|
+
if (entry.message.role === "user" && entry.requester) {
|
|
360
|
+
requester = entry.requester;
|
|
361
|
+
}
|
|
362
|
+
continue;
|
|
363
|
+
}
|
|
364
|
+
if (entry.type === "requester_recorded") {
|
|
365
|
+
requester = entry.requester;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
if (entry.type === "authorization_completed") {
|
|
369
|
+
messages.push(authorizationObservationMessage(entry));
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (entry.type === "projection_reset") {
|
|
373
|
+
messages = [...entry.messages];
|
|
374
|
+
if (entry.requester) {
|
|
375
|
+
requester = entry.requester;
|
|
376
|
+
}
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
return { messages, requester };
|
|
381
|
+
}
|
|
382
|
+
function projectMessages(entries, sessionId) {
|
|
383
|
+
return project(entries, sessionId).messages;
|
|
384
|
+
}
|
|
385
|
+
function connectedMcpProviders(entries, sessionId) {
|
|
386
|
+
const providers = /* @__PURE__ */ new Set();
|
|
387
|
+
for (const entry of projectionEntries(entries, sessionId)) {
|
|
388
|
+
if (entry.type === "mcp_provider_connected") {
|
|
389
|
+
providers.add(entry.provider);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return [...providers].sort((left, right) => left.localeCompare(right));
|
|
393
|
+
}
|
|
394
|
+
function commitEntries(existingMessages, nextMessages, sessionId, entries, existingRequester, requester) {
|
|
395
|
+
const matchingPrefix = countMatchingPrefix(existingMessages, nextMessages);
|
|
396
|
+
if (matchingPrefix === existingMessages.length) {
|
|
397
|
+
const newMessages = nextMessages.slice(matchingPrefix);
|
|
398
|
+
if (newMessages.length === 0 && requester && !isDeepStrictEqual(existingRequester, requester)) {
|
|
399
|
+
return {
|
|
400
|
+
entries: [requesterRecordedEntry(requester, sessionId)],
|
|
401
|
+
sessionId
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
const requesterIndex = requester ? findLastIndex(newMessages, (m) => m.role === "user") : -1;
|
|
405
|
+
return {
|
|
406
|
+
entries: newMessages.map(
|
|
407
|
+
(message, index) => piEntry(
|
|
408
|
+
message,
|
|
409
|
+
sessionId,
|
|
410
|
+
index === requesterIndex ? requester : void 0
|
|
411
|
+
)
|
|
412
|
+
),
|
|
413
|
+
sessionId
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
const resetSessionId = nextSessionId(entries);
|
|
417
|
+
return {
|
|
418
|
+
entries: [
|
|
419
|
+
resetEntry(nextMessages, resetSessionId, requester ?? existingRequester)
|
|
420
|
+
],
|
|
421
|
+
sessionId: resetSessionId
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
function redisStore(redisStateAdapter) {
|
|
425
|
+
const client = redisStateAdapter.getClient();
|
|
426
|
+
return {
|
|
427
|
+
async append({ entries, scope, ttlMs }) {
|
|
428
|
+
const listKey = key(scope);
|
|
429
|
+
if (entries.length > 0) {
|
|
430
|
+
await client.rPush(
|
|
431
|
+
listKey,
|
|
432
|
+
entries.map((entry) => JSON.stringify(entry))
|
|
433
|
+
);
|
|
434
|
+
}
|
|
435
|
+
await client.pExpire(listKey, Math.max(1, ttlMs));
|
|
436
|
+
},
|
|
437
|
+
async read(scope) {
|
|
438
|
+
const values = await client.lRange(key(scope), 0, -1);
|
|
439
|
+
return values.map(decode);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function stateStore() {
|
|
444
|
+
const stateAdapter = getStateAdapter();
|
|
445
|
+
return {
|
|
446
|
+
async append({ entries, scope, ttlMs }) {
|
|
447
|
+
const listKey = rawKey(scope);
|
|
448
|
+
const lock = await stateAdapter.acquireLock(
|
|
449
|
+
`${listKey}:commit`,
|
|
450
|
+
STATE_STORE_LOCK_TTL_MS
|
|
451
|
+
);
|
|
452
|
+
if (!lock) {
|
|
453
|
+
throw new Error("Could not acquire session log commit lock");
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
const existingValue = await stateAdapter.get(listKey);
|
|
457
|
+
const existingEntries = Array.isArray(existingValue) ? existingValue.map(decode) : (await stateAdapter.getList(listKey)).map(decode);
|
|
458
|
+
await stateAdapter.set(
|
|
459
|
+
listKey,
|
|
460
|
+
[...existingEntries, ...entries],
|
|
461
|
+
Math.max(1, ttlMs)
|
|
462
|
+
);
|
|
463
|
+
} finally {
|
|
464
|
+
await stateAdapter.releaseLock(lock);
|
|
465
|
+
}
|
|
466
|
+
},
|
|
467
|
+
async read(scope) {
|
|
468
|
+
const listKey = rawKey(scope);
|
|
469
|
+
const value = await stateAdapter.get(listKey);
|
|
470
|
+
if (Array.isArray(value)) {
|
|
471
|
+
return value.map(decode);
|
|
472
|
+
}
|
|
473
|
+
const values = await stateAdapter.getList(listKey);
|
|
474
|
+
return values.map(decode);
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
async function defaultStore() {
|
|
479
|
+
const { redisStateAdapter, stateAdapter } = await getConnectedStateContext();
|
|
480
|
+
if (redisStateAdapter) {
|
|
481
|
+
return redisStore(redisStateAdapter);
|
|
482
|
+
}
|
|
483
|
+
await stateAdapter.connect();
|
|
484
|
+
return stateStore();
|
|
485
|
+
}
|
|
486
|
+
async function loadEntries(args) {
|
|
487
|
+
const store = args.store ?? await defaultStore();
|
|
488
|
+
return await store.read(args);
|
|
489
|
+
}
|
|
490
|
+
async function loadActivityEntries(args) {
|
|
491
|
+
const entries = await loadEntries(args);
|
|
492
|
+
return projectionEntries(entries, args.sessionId).filter(isActivityEntry);
|
|
493
|
+
}
|
|
494
|
+
async function loadMessages(args) {
|
|
495
|
+
const messageCount = normalizeMessageCount(args.messageCount);
|
|
496
|
+
if (messageCount === 0) {
|
|
497
|
+
return [];
|
|
498
|
+
}
|
|
499
|
+
const store = args.store ?? await defaultStore();
|
|
500
|
+
const messages = projectMessages(await store.read(args), args.sessionId);
|
|
501
|
+
return messages.length >= messageCount ? messages.slice(0, messageCount) : void 0;
|
|
502
|
+
}
|
|
503
|
+
async function loadProjection(args) {
|
|
504
|
+
const store = args.store ?? await defaultStore();
|
|
505
|
+
return project(await store.read(args), args.sessionId).messages;
|
|
506
|
+
}
|
|
507
|
+
async function loadConnectedMcpProviders(args) {
|
|
508
|
+
return connectedMcpProviders(await loadEntries(args));
|
|
509
|
+
}
|
|
510
|
+
async function recordMcpProviderConnected(args) {
|
|
511
|
+
const store = args.store ?? await defaultStore();
|
|
512
|
+
const entries = await store.read(args);
|
|
513
|
+
const sessionId = currentSessionId(entries);
|
|
514
|
+
if (connectedMcpProviders(entries).includes(args.provider)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
await store.append({
|
|
518
|
+
scope: args,
|
|
519
|
+
entries: [mcpProviderConnectedEntry(args.provider, sessionId)],
|
|
520
|
+
ttlMs: args.ttlMs
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
async function recordAuthorizationRequested(args) {
|
|
524
|
+
const store = args.store ?? await defaultStore();
|
|
525
|
+
const entries = await store.read(args);
|
|
526
|
+
const sessionId = currentSessionId(entries);
|
|
527
|
+
if (projectionEntries(entries).some(
|
|
528
|
+
(entry) => entry.type === "authorization_requested" && entry.authorizationId === args.authorizationId
|
|
529
|
+
)) {
|
|
530
|
+
return;
|
|
531
|
+
}
|
|
532
|
+
await store.append({
|
|
533
|
+
scope: args,
|
|
534
|
+
entries: [
|
|
535
|
+
authorizationRequestedEntry({
|
|
536
|
+
createdAtMs: Date.now(),
|
|
537
|
+
kind: args.kind,
|
|
538
|
+
sessionId,
|
|
539
|
+
provider: args.provider,
|
|
540
|
+
requesterId: args.requesterId,
|
|
541
|
+
authorizationId: args.authorizationId,
|
|
542
|
+
delivery: args.delivery
|
|
543
|
+
})
|
|
544
|
+
],
|
|
545
|
+
ttlMs: args.ttlMs
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
async function recordAuthorizationCompleted(args) {
|
|
549
|
+
const store = args.store ?? await defaultStore();
|
|
550
|
+
const entries = await store.read(args);
|
|
551
|
+
const sessionId = currentSessionId(entries);
|
|
552
|
+
if (projectionEntries(entries).some(
|
|
553
|
+
(entry) => entry.type === "authorization_completed" && entry.authorizationId === args.authorizationId
|
|
554
|
+
)) {
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
await store.append({
|
|
558
|
+
scope: args,
|
|
559
|
+
entries: [
|
|
560
|
+
authorizationCompletedEntry({
|
|
561
|
+
createdAtMs: Date.now(),
|
|
562
|
+
kind: args.kind,
|
|
563
|
+
sessionId,
|
|
564
|
+
provider: args.provider,
|
|
565
|
+
requesterId: args.requesterId,
|
|
566
|
+
authorizationId: args.authorizationId
|
|
567
|
+
})
|
|
568
|
+
],
|
|
569
|
+
ttlMs: args.ttlMs
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
async function recordToolExecutionStarted(args) {
|
|
573
|
+
const store = args.store ?? await defaultStore();
|
|
574
|
+
const entries = await store.read(args);
|
|
575
|
+
const sessionId = args.sessionId ?? currentSessionId(entries);
|
|
576
|
+
await store.append({
|
|
577
|
+
scope: args,
|
|
578
|
+
entries: [
|
|
579
|
+
toolExecutionStartedEntry({
|
|
580
|
+
args: args.args,
|
|
581
|
+
createdAtMs: args.createdAtMs ?? Date.now(),
|
|
582
|
+
sessionId,
|
|
583
|
+
toolCallId: args.toolCallId,
|
|
584
|
+
toolName: args.toolName
|
|
585
|
+
})
|
|
586
|
+
],
|
|
587
|
+
ttlMs: args.ttlMs
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
async function recordSubagentStarted(args) {
|
|
591
|
+
const store = args.store ?? await defaultStore();
|
|
592
|
+
const entries = await store.read(args);
|
|
593
|
+
const sessionId = args.sessionId ?? currentSessionId(entries);
|
|
594
|
+
await store.append({
|
|
595
|
+
scope: args,
|
|
596
|
+
entries: [
|
|
597
|
+
subagentStartedEntry({
|
|
598
|
+
createdAtMs: args.createdAtMs ?? Date.now(),
|
|
599
|
+
historyMode: args.historyMode,
|
|
600
|
+
parentConversationId: args.parentConversationId,
|
|
601
|
+
parentSessionId: args.parentSessionId,
|
|
602
|
+
parentToolCallId: args.parentToolCallId,
|
|
603
|
+
sessionId,
|
|
604
|
+
subagentInvocationId: args.subagentInvocationId,
|
|
605
|
+
subagentKind: args.subagentKind,
|
|
606
|
+
transcriptRef: args.transcriptRef
|
|
607
|
+
})
|
|
608
|
+
],
|
|
609
|
+
ttlMs: args.ttlMs
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
async function recordSubagentEnded(args) {
|
|
613
|
+
const store = args.store ?? await defaultStore();
|
|
614
|
+
const entries = await store.read(args);
|
|
615
|
+
const sessionId = args.sessionId ?? currentSessionId(entries);
|
|
616
|
+
await store.append({
|
|
617
|
+
scope: args,
|
|
618
|
+
entries: [
|
|
619
|
+
subagentEndedEntry({
|
|
620
|
+
createdAtMs: args.createdAtMs ?? Date.now(),
|
|
621
|
+
errorCode: args.errorCode,
|
|
622
|
+
outcome: args.outcome,
|
|
623
|
+
sessionId,
|
|
624
|
+
subagentInvocationId: args.subagentInvocationId,
|
|
625
|
+
transcriptEndMessageIndex: args.transcriptEndMessageIndex,
|
|
626
|
+
transcriptStartMessageIndex: args.transcriptStartMessageIndex
|
|
627
|
+
})
|
|
628
|
+
],
|
|
629
|
+
ttlMs: args.ttlMs
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
async function commitMessages(args) {
|
|
633
|
+
const store = args.store ?? await defaultStore();
|
|
634
|
+
const entries = await store.read(args);
|
|
635
|
+
const existingProjection = project(entries);
|
|
636
|
+
const currentId = currentSessionId(entries);
|
|
637
|
+
const commit = commitEntries(
|
|
638
|
+
existingProjection.messages,
|
|
639
|
+
args.messages,
|
|
640
|
+
currentId,
|
|
641
|
+
entries,
|
|
642
|
+
existingProjection.requester,
|
|
643
|
+
args.requester
|
|
644
|
+
);
|
|
645
|
+
await store.append({
|
|
646
|
+
scope: args,
|
|
647
|
+
entries: commit.entries,
|
|
648
|
+
ttlMs: args.ttlMs
|
|
649
|
+
});
|
|
650
|
+
return {
|
|
651
|
+
sessionId: commit.sessionId
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/chat/xml.ts
|
|
656
|
+
function escapeXml(value) {
|
|
657
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// src/chat/state/turn-session.ts
|
|
661
|
+
import { THREAD_STATE_TTL_MS } from "chat";
|
|
662
|
+
import {
|
|
663
|
+
sourceSchema
|
|
664
|
+
} from "@sentry/junior-plugin-api";
|
|
665
|
+
var AGENT_TURN_SESSION_PREFIX = "junior:agent_turn_session";
|
|
666
|
+
var AGENT_TURN_SESSION_INDEX_KEY = `${AGENT_TURN_SESSION_PREFIX}:index`;
|
|
667
|
+
var AGENT_TURN_SESSION_INDEX_MAX_LENGTH = 5e3;
|
|
668
|
+
var AGENT_TURN_SESSION_TTL_MS = THREAD_STATE_TTL_MS;
|
|
669
|
+
function agentTurnSessionKey(conversationId, sessionId) {
|
|
670
|
+
return `${AGENT_TURN_SESSION_PREFIX}:${conversationId}:${sessionId}`;
|
|
671
|
+
}
|
|
672
|
+
function agentTurnSessionConversationIndexKey(conversationId) {
|
|
673
|
+
return `${AGENT_TURN_SESSION_PREFIX}:conversation:${conversationId}:index`;
|
|
674
|
+
}
|
|
675
|
+
function toFiniteNonNegativeNumber(value) {
|
|
676
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.floor(value)) : void 0;
|
|
677
|
+
}
|
|
678
|
+
function toNonNegativeInteger(value) {
|
|
679
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : void 0;
|
|
680
|
+
}
|
|
681
|
+
function parseAgentTurnUsage(value) {
|
|
682
|
+
if (!isRecord(value)) {
|
|
683
|
+
return void 0;
|
|
684
|
+
}
|
|
685
|
+
const usage = {};
|
|
686
|
+
for (const field of [
|
|
687
|
+
"inputTokens",
|
|
688
|
+
"outputTokens",
|
|
689
|
+
"cachedInputTokens",
|
|
690
|
+
"cacheCreationTokens",
|
|
691
|
+
"totalTokens"
|
|
692
|
+
]) {
|
|
693
|
+
const count = toFiniteNonNegativeNumber(value[field]);
|
|
694
|
+
if (count !== void 0) {
|
|
695
|
+
usage[field] = count;
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return Object.keys(usage).length > 0 ? usage : void 0;
|
|
699
|
+
}
|
|
700
|
+
function parseStoredRecord(value) {
|
|
701
|
+
if (isRecord(value)) {
|
|
702
|
+
return value;
|
|
703
|
+
}
|
|
704
|
+
if (typeof value !== "string") {
|
|
705
|
+
return void 0;
|
|
706
|
+
}
|
|
707
|
+
try {
|
|
708
|
+
const parsed = JSON.parse(value);
|
|
709
|
+
return isRecord(parsed) ? parsed : void 0;
|
|
710
|
+
} catch {
|
|
711
|
+
return void 0;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
function parseAgentTurnSessionStatus(parsed) {
|
|
715
|
+
const status = parsed.state;
|
|
716
|
+
if (status === "running" || status === "awaiting_resume" || status === "completed" || status === "failed" || status === "abandoned") {
|
|
717
|
+
return status;
|
|
718
|
+
}
|
|
719
|
+
return void 0;
|
|
720
|
+
}
|
|
721
|
+
function parseAgentTurnSurface(value) {
|
|
722
|
+
return value === "slack" || value === "api" || value === "scheduler" || value === "internal" ? value : void 0;
|
|
723
|
+
}
|
|
724
|
+
function conversationExecutionFromSummary(summary) {
|
|
725
|
+
const status = summary.state === "completed" || summary.state === "abandoned" ? "idle" : summary.state;
|
|
726
|
+
return {
|
|
727
|
+
status,
|
|
728
|
+
runId: summary.sessionId,
|
|
729
|
+
updatedAtMs: summary.updatedAtMs
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
function parseSource(value) {
|
|
733
|
+
const result = sourceSchema.safeParse(value);
|
|
734
|
+
return result.success ? result.data : void 0;
|
|
735
|
+
}
|
|
736
|
+
function sessionLogRequester(requester) {
|
|
737
|
+
return requester?.platform === "slack" ? toStoredSlackRequester(requester) : void 0;
|
|
738
|
+
}
|
|
739
|
+
function parseAgentTurnSessionFields(parsed) {
|
|
740
|
+
const status = parseAgentTurnSessionStatus(parsed);
|
|
741
|
+
if (!status) {
|
|
742
|
+
return void 0;
|
|
743
|
+
}
|
|
744
|
+
const channelName = typeof parsed.channelName === "string" && parsed.channelName.trim() ? parsed.channelName.trim() : void 0;
|
|
745
|
+
const conversationId = parsed.conversationId;
|
|
746
|
+
const sessionId = parsed.sessionId;
|
|
747
|
+
const sliceId = toFiniteNonNegativeNumber(parsed.sliceId);
|
|
748
|
+
const version = toFiniteNonNegativeNumber(parsed.version);
|
|
749
|
+
const updatedAtMs = toFiniteNonNegativeNumber(parsed.updatedAtMs);
|
|
750
|
+
const cumulativeDurationMs = toFiniteNonNegativeNumber(parsed.cumulativeDurationMs) ?? 0;
|
|
751
|
+
const cumulativeUsage = parseAgentTurnUsage(parsed.cumulativeUsage);
|
|
752
|
+
const lastProgressAtMs = toFiniteNonNegativeNumber(parsed.lastProgressAtMs);
|
|
753
|
+
const logSessionId = typeof parsed.logSessionId === "string" ? parsed.logSessionId : void 0;
|
|
754
|
+
const requester = parsed.requester === void 0 ? void 0 : parseRequester(parsed.requester);
|
|
755
|
+
const startedAtMs = toFiniteNonNegativeNumber(parsed.startedAtMs);
|
|
756
|
+
const surface = parseAgentTurnSurface(parsed.surface);
|
|
757
|
+
const turnStartMessageIndex = toNonNegativeInteger(
|
|
758
|
+
parsed.turnStartMessageIndex
|
|
759
|
+
);
|
|
760
|
+
const destination = parsed.destination === void 0 ? void 0 : parseDestination(parsed.destination);
|
|
761
|
+
const source = parsed.source === void 0 ? void 0 : parseSource(parsed.source);
|
|
762
|
+
if (typeof conversationId !== "string" || typeof sessionId !== "string" || sliceId === void 0 || version === void 0 || updatedAtMs === void 0 || parsed.destination !== void 0 && !destination || parsed.source !== void 0 && !source || parsed.requester !== void 0 && !requester) {
|
|
763
|
+
return void 0;
|
|
764
|
+
}
|
|
765
|
+
return {
|
|
766
|
+
version,
|
|
767
|
+
...channelName ? { channelName } : {},
|
|
768
|
+
conversationId,
|
|
769
|
+
sessionId,
|
|
770
|
+
sliceId,
|
|
771
|
+
state: status,
|
|
772
|
+
startedAtMs: startedAtMs ?? updatedAtMs,
|
|
773
|
+
lastProgressAtMs: lastProgressAtMs ?? updatedAtMs,
|
|
774
|
+
updatedAtMs,
|
|
775
|
+
cumulativeDurationMs,
|
|
776
|
+
...logSessionId ? { logSessionId } : {},
|
|
777
|
+
...cumulativeUsage ? { cumulativeUsage } : {},
|
|
778
|
+
...destination ? { destination } : {},
|
|
779
|
+
...source ? { source } : {},
|
|
780
|
+
...requester ? { requester } : {},
|
|
781
|
+
...Array.isArray(parsed.loadedSkillNames) ? {
|
|
782
|
+
loadedSkillNames: parsed.loadedSkillNames.filter(
|
|
783
|
+
(value) => typeof value === "string"
|
|
784
|
+
)
|
|
785
|
+
} : {},
|
|
786
|
+
...parsed.resumeReason === "timeout" || parsed.resumeReason === "auth" || parsed.resumeReason === "yield" ? { resumeReason: parsed.resumeReason } : {},
|
|
787
|
+
...typeof parsed.errorMessage === "string" ? { errorMessage: parsed.errorMessage } : {},
|
|
788
|
+
...typeof parsed.resumedFromSliceId === "number" ? { resumedFromSliceId: parsed.resumedFromSliceId } : {},
|
|
789
|
+
...surface ? { surface } : {},
|
|
790
|
+
...turnStartMessageIndex !== void 0 ? { turnStartMessageIndex } : {},
|
|
791
|
+
...typeof parsed.traceId === "string" ? { traceId: parsed.traceId } : {}
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
function parseAgentTurnSessionRecord(value) {
|
|
795
|
+
const parsed = parseStoredRecord(value);
|
|
796
|
+
if (!parsed) {
|
|
797
|
+
return void 0;
|
|
798
|
+
}
|
|
799
|
+
const fields = parseAgentTurnSessionFields(parsed);
|
|
800
|
+
const committedMessageCount = toFiniteNonNegativeNumber(
|
|
801
|
+
parsed.committedMessageCount
|
|
802
|
+
);
|
|
803
|
+
if (!fields || committedMessageCount === void 0) {
|
|
804
|
+
return void 0;
|
|
805
|
+
}
|
|
806
|
+
return {
|
|
807
|
+
...fields,
|
|
808
|
+
committedMessageCount
|
|
809
|
+
};
|
|
810
|
+
}
|
|
811
|
+
function parseAgentTurnSessionSummary(value) {
|
|
812
|
+
const stored = parseStoredRecord(value);
|
|
813
|
+
if (!stored) {
|
|
814
|
+
return void 0;
|
|
815
|
+
}
|
|
816
|
+
const parsed = parseAgentTurnSessionFields(stored);
|
|
817
|
+
if (!parsed) {
|
|
818
|
+
return void 0;
|
|
819
|
+
}
|
|
820
|
+
const {
|
|
821
|
+
errorMessage: _errorMessage,
|
|
822
|
+
logSessionId: _logSessionId,
|
|
823
|
+
turnStartMessageIndex: _turnStartMessageIndex,
|
|
824
|
+
...summary
|
|
825
|
+
} = parsed;
|
|
826
|
+
return summary;
|
|
827
|
+
}
|
|
828
|
+
async function appendAgentTurnSessionSummary(summary, ttlMs) {
|
|
829
|
+
const stateAdapter = getStateAdapter();
|
|
830
|
+
await Promise.all([
|
|
831
|
+
stateAdapter.appendToList(AGENT_TURN_SESSION_INDEX_KEY, summary, {
|
|
832
|
+
maxLength: AGENT_TURN_SESSION_INDEX_MAX_LENGTH,
|
|
833
|
+
ttlMs
|
|
834
|
+
}),
|
|
835
|
+
stateAdapter.appendToList(
|
|
836
|
+
agentTurnSessionConversationIndexKey(summary.conversationId),
|
|
837
|
+
summary,
|
|
838
|
+
{ ttlMs }
|
|
839
|
+
)
|
|
840
|
+
]);
|
|
841
|
+
}
|
|
842
|
+
async function recordConversationActivityMetadata(args) {
|
|
843
|
+
const conversationStore = args.conversationStore ?? getConversationStore();
|
|
844
|
+
const source = args.summary.destination?.platform === "local" ? "local" : args.summary.surface;
|
|
845
|
+
try {
|
|
846
|
+
await conversationStore.recordActivity({
|
|
847
|
+
activityAtMs: args.summary.updatedAtMs,
|
|
848
|
+
channelName: args.summary.channelName,
|
|
849
|
+
conversationId: args.summary.conversationId,
|
|
850
|
+
destination: args.summary.destination,
|
|
851
|
+
nowMs: args.nowMs,
|
|
852
|
+
requester: sessionLogRequester(args.summary.requester),
|
|
853
|
+
source,
|
|
854
|
+
visibility: args.destinationVisibility
|
|
855
|
+
});
|
|
856
|
+
await conversationStore.recordExecution({
|
|
857
|
+
channelName: args.summary.channelName,
|
|
858
|
+
conversationId: args.summary.conversationId,
|
|
859
|
+
createdAtMs: args.summary.startedAtMs,
|
|
860
|
+
destination: args.summary.destination,
|
|
861
|
+
execution: conversationExecutionFromSummary(args.summary),
|
|
862
|
+
lastActivityAtMs: args.summary.updatedAtMs,
|
|
863
|
+
requester: sessionLogRequester(args.summary.requester),
|
|
864
|
+
source,
|
|
865
|
+
updatedAtMs: args.nowMs,
|
|
866
|
+
visibility: args.destinationVisibility
|
|
867
|
+
});
|
|
868
|
+
} catch (error) {
|
|
869
|
+
logWarn(
|
|
870
|
+
"conversation_activity_metadata_update_failed",
|
|
871
|
+
{ conversationId: args.summary.conversationId },
|
|
872
|
+
{
|
|
873
|
+
"exception.message": error instanceof Error ? error.message : String(error)
|
|
874
|
+
},
|
|
875
|
+
"Failed to update conversation activity metadata"
|
|
876
|
+
);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
function materializePiMessages(committedMessageCount, includeProjectionTail, sessionMessages, sessionProjection) {
|
|
880
|
+
if (committedMessageCount === 0) {
|
|
881
|
+
return sessionProjection;
|
|
882
|
+
}
|
|
883
|
+
if (includeProjectionTail && sessionProjection.length >= committedMessageCount) {
|
|
884
|
+
return sessionProjection;
|
|
885
|
+
}
|
|
886
|
+
if (sessionMessages) {
|
|
887
|
+
return sessionMessages;
|
|
888
|
+
}
|
|
889
|
+
if (sessionProjection.length >= committedMessageCount) {
|
|
890
|
+
return sessionProjection.slice(0, committedMessageCount);
|
|
891
|
+
}
|
|
892
|
+
return void 0;
|
|
893
|
+
}
|
|
894
|
+
function materializeAgentTurnSessionRecord(stored, piMessages) {
|
|
895
|
+
return {
|
|
896
|
+
version: stored.version,
|
|
897
|
+
...stored.channelName ? { channelName: stored.channelName } : {},
|
|
898
|
+
conversationId: stored.conversationId,
|
|
899
|
+
sessionId: stored.sessionId,
|
|
900
|
+
sliceId: stored.sliceId,
|
|
901
|
+
state: stored.state,
|
|
902
|
+
startedAtMs: stored.startedAtMs,
|
|
903
|
+
lastProgressAtMs: stored.lastProgressAtMs,
|
|
904
|
+
updatedAtMs: stored.updatedAtMs,
|
|
905
|
+
piMessages,
|
|
906
|
+
cumulativeDurationMs: stored.cumulativeDurationMs,
|
|
907
|
+
...stored.destination ? { destination: stored.destination } : {},
|
|
908
|
+
...stored.source ? { source: stored.source } : {},
|
|
909
|
+
...stored.cumulativeUsage ? { cumulativeUsage: stored.cumulativeUsage } : {},
|
|
910
|
+
...stored.resumeReason ? { resumeReason: stored.resumeReason } : {},
|
|
911
|
+
...stored.errorMessage ? { errorMessage: stored.errorMessage } : {},
|
|
912
|
+
...stored.loadedSkillNames ? { loadedSkillNames: stored.loadedSkillNames } : {},
|
|
913
|
+
...stored.requester ? { requester: stored.requester } : {},
|
|
914
|
+
...stored.resumedFromSliceId !== void 0 ? { resumedFromSliceId: stored.resumedFromSliceId } : {},
|
|
915
|
+
...stored.surface ? { surface: stored.surface } : {},
|
|
916
|
+
...stored.traceId ? { traceId: stored.traceId } : {},
|
|
917
|
+
...stored.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: stored.turnStartMessageIndex } : {}
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
async function getStoredAgentTurnSessionRecord(conversationId, sessionId) {
|
|
921
|
+
const stateAdapter = getStateAdapter();
|
|
922
|
+
await stateAdapter.connect();
|
|
923
|
+
const value = await stateAdapter.get(
|
|
924
|
+
agentTurnSessionKey(conversationId, sessionId)
|
|
925
|
+
);
|
|
926
|
+
return parseAgentTurnSessionRecord(value);
|
|
927
|
+
}
|
|
928
|
+
async function getAgentTurnSessionRecord(conversationId, sessionId) {
|
|
929
|
+
const parsed = await getStoredAgentTurnSessionRecord(
|
|
930
|
+
conversationId,
|
|
931
|
+
sessionId
|
|
932
|
+
);
|
|
933
|
+
if (!parsed) {
|
|
934
|
+
return void 0;
|
|
935
|
+
}
|
|
936
|
+
const sessionMessages = await loadMessages({
|
|
937
|
+
conversationId,
|
|
938
|
+
messageCount: parsed.committedMessageCount,
|
|
939
|
+
...parsed.logSessionId ? { sessionId: parsed.logSessionId } : {}
|
|
940
|
+
});
|
|
941
|
+
const sessionProjection = await loadProjection({
|
|
942
|
+
conversationId,
|
|
943
|
+
...parsed.logSessionId ? { sessionId: parsed.logSessionId } : {}
|
|
944
|
+
});
|
|
945
|
+
const piMessages = materializePiMessages(
|
|
946
|
+
parsed.committedMessageCount,
|
|
947
|
+
parsed.state === "running" || parsed.state === "awaiting_resume",
|
|
948
|
+
sessionMessages,
|
|
949
|
+
sessionProjection
|
|
950
|
+
);
|
|
951
|
+
if (!piMessages) {
|
|
952
|
+
return void 0;
|
|
953
|
+
}
|
|
954
|
+
return materializeAgentTurnSessionRecord(parsed, piMessages);
|
|
955
|
+
}
|
|
956
|
+
function buildStoredRecord(args) {
|
|
957
|
+
const nowMs = Date.now();
|
|
958
|
+
return {
|
|
959
|
+
version: (args.previousVersion ?? 0) + 1,
|
|
960
|
+
...args.channelName ? { channelName: args.channelName } : {},
|
|
961
|
+
conversationId: args.conversationId,
|
|
962
|
+
sessionId: args.sessionId,
|
|
963
|
+
sliceId: args.sliceId,
|
|
964
|
+
state: args.state,
|
|
965
|
+
startedAtMs: args.startedAtMs ?? nowMs,
|
|
966
|
+
lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
|
|
967
|
+
updatedAtMs: nowMs,
|
|
968
|
+
committedMessageCount: args.committedMessageCount,
|
|
969
|
+
...args.logSessionId ? { logSessionId: args.logSessionId } : {},
|
|
970
|
+
cumulativeDurationMs: args.cumulativeDurationMs,
|
|
971
|
+
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
972
|
+
...args.destination ? { destination: args.destination } : {},
|
|
973
|
+
...args.source ? { source: args.source } : {},
|
|
974
|
+
...args.requester ? { requester: args.requester } : {},
|
|
975
|
+
...Array.isArray(args.loadedSkillNames) ? {
|
|
976
|
+
loadedSkillNames: args.loadedSkillNames.filter(
|
|
977
|
+
(value) => typeof value === "string"
|
|
978
|
+
)
|
|
979
|
+
} : {},
|
|
980
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
981
|
+
...args.errorMessage ? { errorMessage: args.errorMessage } : {},
|
|
982
|
+
...typeof args.resumedFromSliceId === "number" ? { resumedFromSliceId: args.resumedFromSliceId } : {},
|
|
983
|
+
...args.surface ? { surface: args.surface } : {},
|
|
984
|
+
...args.traceId ? { traceId: args.traceId } : {},
|
|
985
|
+
...args.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.turnStartMessageIndex } : {}
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
async function setStoredRecord(args) {
|
|
989
|
+
const stateAdapter = getStateAdapter();
|
|
990
|
+
await stateAdapter.connect();
|
|
991
|
+
await stateAdapter.set(
|
|
992
|
+
agentTurnSessionKey(args.record.conversationId, args.record.sessionId),
|
|
993
|
+
args.record,
|
|
994
|
+
args.ttlMs
|
|
995
|
+
);
|
|
996
|
+
const {
|
|
997
|
+
committedMessageCount: _committedMessageCount,
|
|
998
|
+
errorMessage: _errorMessage,
|
|
999
|
+
logSessionId: _logSessionId,
|
|
1000
|
+
turnStartMessageIndex: _turnStartMessageIndex,
|
|
1001
|
+
...summary
|
|
1002
|
+
} = args.record;
|
|
1003
|
+
await appendAgentTurnSessionSummary(summary, args.ttlMs);
|
|
1004
|
+
await recordConversationActivityMetadata({
|
|
1005
|
+
conversationStore: args.conversationStore,
|
|
1006
|
+
destinationVisibility: args.destinationVisibility,
|
|
1007
|
+
nowMs: Date.now(),
|
|
1008
|
+
summary
|
|
1009
|
+
});
|
|
1010
|
+
return materializeAgentTurnSessionRecord(args.record, [...args.piMessages]);
|
|
1011
|
+
}
|
|
1012
|
+
async function updateAgentTurnSessionState(args) {
|
|
1013
|
+
const parsed = await getStoredAgentTurnSessionRecord(
|
|
1014
|
+
args.existing.conversationId,
|
|
1015
|
+
args.existing.sessionId
|
|
1016
|
+
);
|
|
1017
|
+
if (!parsed || parsed.version !== args.existing.version) {
|
|
1018
|
+
return void 0;
|
|
1019
|
+
}
|
|
1020
|
+
return await setStoredRecord({
|
|
1021
|
+
piMessages: args.existing.piMessages,
|
|
1022
|
+
ttlMs: AGENT_TURN_SESSION_TTL_MS,
|
|
1023
|
+
record: buildStoredRecord({
|
|
1024
|
+
conversationId: args.existing.conversationId,
|
|
1025
|
+
sessionId: args.existing.sessionId,
|
|
1026
|
+
sliceId: args.existing.sliceId,
|
|
1027
|
+
state: args.state,
|
|
1028
|
+
committedMessageCount: parsed.committedMessageCount,
|
|
1029
|
+
...parsed.channelName ? { channelName: parsed.channelName } : {},
|
|
1030
|
+
startedAtMs: parsed.startedAtMs,
|
|
1031
|
+
lastProgressAtMs: parsed.lastProgressAtMs,
|
|
1032
|
+
previousVersion: parsed.version,
|
|
1033
|
+
...parsed.logSessionId ? { logSessionId: parsed.logSessionId } : {},
|
|
1034
|
+
cumulativeDurationMs: args.existing.cumulativeDurationMs,
|
|
1035
|
+
...args.existing.cumulativeUsage ? { cumulativeUsage: args.existing.cumulativeUsage } : {},
|
|
1036
|
+
...args.existing.destination ? { destination: args.existing.destination } : {},
|
|
1037
|
+
...args.existing.source ? { source: args.existing.source } : {},
|
|
1038
|
+
...args.existing.loadedSkillNames ? { loadedSkillNames: args.existing.loadedSkillNames } : {},
|
|
1039
|
+
...args.existing.requester ? { requester: args.existing.requester } : {},
|
|
1040
|
+
...args.existing.resumeReason ? { resumeReason: args.existing.resumeReason } : {},
|
|
1041
|
+
...args.existing.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.existing.resumedFromSliceId } : {},
|
|
1042
|
+
...args.existing.surface ? { surface: args.existing.surface } : {},
|
|
1043
|
+
...args.existing.traceId ? { traceId: args.existing.traceId } : {},
|
|
1044
|
+
...args.existing.turnStartMessageIndex !== void 0 ? { turnStartMessageIndex: args.existing.turnStartMessageIndex } : {},
|
|
1045
|
+
...args.errorMessage ?? args.existing.errorMessage ? { errorMessage: args.errorMessage ?? args.existing.errorMessage } : {}
|
|
1046
|
+
})
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
async function upsertAgentTurnSessionRecord(args) {
|
|
1050
|
+
const existingRecord = await getStoredAgentTurnSessionRecord(
|
|
1051
|
+
args.conversationId,
|
|
1052
|
+
args.sessionId
|
|
1053
|
+
);
|
|
1054
|
+
const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
|
|
1055
|
+
const commit = await commitMessages({
|
|
1056
|
+
conversationId: args.conversationId,
|
|
1057
|
+
messages: args.piMessages,
|
|
1058
|
+
requester: sessionLogRequester(args.requester ?? existingRecord?.requester),
|
|
1059
|
+
ttlMs
|
|
1060
|
+
});
|
|
1061
|
+
return await setStoredRecord({
|
|
1062
|
+
conversationStore: args.conversationStore,
|
|
1063
|
+
destinationVisibility: args.destinationVisibility,
|
|
1064
|
+
piMessages: args.piMessages,
|
|
1065
|
+
ttlMs,
|
|
1066
|
+
record: buildStoredRecord({
|
|
1067
|
+
...args.channelName ?? existingRecord?.channelName ? { channelName: args.channelName ?? existingRecord?.channelName } : {},
|
|
1068
|
+
conversationId: args.conversationId,
|
|
1069
|
+
sessionId: args.sessionId,
|
|
1070
|
+
sliceId: args.sliceId,
|
|
1071
|
+
state: args.state,
|
|
1072
|
+
...existingRecord?.startedAtMs !== void 0 ? { startedAtMs: existingRecord.startedAtMs } : {},
|
|
1073
|
+
...args.lastProgressAtMs !== void 0 ? { lastProgressAtMs: args.lastProgressAtMs } : {},
|
|
1074
|
+
committedMessageCount: args.piMessages.length,
|
|
1075
|
+
logSessionId: commit.sessionId,
|
|
1076
|
+
previousVersion: existingRecord?.version,
|
|
1077
|
+
cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existingRecord?.cumulativeDurationMs ?? 0,
|
|
1078
|
+
...args.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage } : {},
|
|
1079
|
+
...args.destination ?? existingRecord?.destination ? { destination: args.destination ?? existingRecord?.destination } : {},
|
|
1080
|
+
...args.source ?? existingRecord?.source ? { source: args.source ?? existingRecord?.source } : {},
|
|
1081
|
+
...args.loadedSkillNames ? { loadedSkillNames: args.loadedSkillNames } : {},
|
|
1082
|
+
...args.requester ?? existingRecord?.requester ? { requester: args.requester ?? existingRecord?.requester } : {},
|
|
1083
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
1084
|
+
...args.errorMessage ? { errorMessage: args.errorMessage } : {},
|
|
1085
|
+
...args.resumedFromSliceId !== void 0 ? { resumedFromSliceId: args.resumedFromSliceId } : {},
|
|
1086
|
+
...args.surface ?? existingRecord?.surface ? { surface: args.surface ?? existingRecord?.surface } : {},
|
|
1087
|
+
...args.traceId ?? existingRecord?.traceId ? { traceId: args.traceId ?? existingRecord?.traceId } : {},
|
|
1088
|
+
...(args.turnStartMessageIndex ?? existingRecord?.turnStartMessageIndex) !== void 0 ? {
|
|
1089
|
+
turnStartMessageIndex: args.turnStartMessageIndex ?? existingRecord?.turnStartMessageIndex
|
|
1090
|
+
} : {}
|
|
1091
|
+
})
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
1094
|
+
async function recordAgentTurnSessionSummary(args) {
|
|
1095
|
+
const existing = await getStoredAgentTurnSessionRecord(
|
|
1096
|
+
args.conversationId,
|
|
1097
|
+
args.sessionId
|
|
1098
|
+
);
|
|
1099
|
+
const nowMs = Date.now();
|
|
1100
|
+
const ttlMs = Math.max(1, args.ttlMs ?? AGENT_TURN_SESSION_TTL_MS);
|
|
1101
|
+
const summary = {
|
|
1102
|
+
version: existing?.version ?? 0,
|
|
1103
|
+
...args.channelName ?? existing?.channelName ? { channelName: args.channelName ?? existing?.channelName } : {},
|
|
1104
|
+
conversationId: args.conversationId,
|
|
1105
|
+
sessionId: args.sessionId,
|
|
1106
|
+
sliceId: args.sliceId,
|
|
1107
|
+
startedAtMs: existing?.startedAtMs ?? args.startedAtMs ?? nowMs,
|
|
1108
|
+
lastProgressAtMs: args.lastProgressAtMs ?? nowMs,
|
|
1109
|
+
state: args.state,
|
|
1110
|
+
updatedAtMs: nowMs,
|
|
1111
|
+
cumulativeDurationMs: toFiniteNonNegativeNumber(args.cumulativeDurationMs) ?? existing?.cumulativeDurationMs ?? 0,
|
|
1112
|
+
...args.cumulativeUsage ?? existing?.cumulativeUsage ? { cumulativeUsage: args.cumulativeUsage ?? existing?.cumulativeUsage } : {},
|
|
1113
|
+
...args.destination ?? existing?.destination ? { destination: args.destination ?? existing?.destination } : {},
|
|
1114
|
+
...args.source ?? existing?.source ? { source: args.source ?? existing?.source } : {},
|
|
1115
|
+
...args.requester ?? existing?.requester ? { requester: args.requester ?? existing?.requester } : {},
|
|
1116
|
+
...Array.isArray(args.loadedSkillNames) ? {
|
|
1117
|
+
loadedSkillNames: args.loadedSkillNames.filter(
|
|
1118
|
+
(value) => typeof value === "string"
|
|
1119
|
+
)
|
|
1120
|
+
} : existing?.loadedSkillNames ? { loadedSkillNames: existing.loadedSkillNames } : {},
|
|
1121
|
+
...args.resumeReason ? { resumeReason: args.resumeReason } : {},
|
|
1122
|
+
...args.surface ?? existing?.surface ? { surface: args.surface ?? existing?.surface } : {},
|
|
1123
|
+
...args.traceId ?? existing?.traceId ? { traceId: args.traceId ?? existing?.traceId } : {}
|
|
1124
|
+
};
|
|
1125
|
+
await appendAgentTurnSessionSummary(summary, ttlMs);
|
|
1126
|
+
await recordConversationActivityMetadata({
|
|
1127
|
+
conversationStore: args.conversationStore,
|
|
1128
|
+
destinationVisibility: args.destinationVisibility,
|
|
1129
|
+
nowMs,
|
|
1130
|
+
summary
|
|
1131
|
+
});
|
|
1132
|
+
}
|
|
1133
|
+
async function readAgentTurnSessionSummariesFromIndex(key2) {
|
|
1134
|
+
const stateAdapter = getStateAdapter();
|
|
1135
|
+
await stateAdapter.connect();
|
|
1136
|
+
const values = await stateAdapter.getList(key2);
|
|
1137
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
1138
|
+
for (const value of [...values].reverse()) {
|
|
1139
|
+
const summary = parseAgentTurnSessionSummary(value);
|
|
1140
|
+
if (!summary) {
|
|
1141
|
+
continue;
|
|
1142
|
+
}
|
|
1143
|
+
const key3 = `${summary.conversationId}:${summary.sessionId}`;
|
|
1144
|
+
if (!summaries.has(key3)) {
|
|
1145
|
+
summaries.set(key3, summary);
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
return [...summaries.values()].sort(
|
|
1149
|
+
(left, right) => right.updatedAtMs - left.updatedAtMs
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
async function listAgentTurnSessionSummariesForConversation(conversationId) {
|
|
1153
|
+
const summaries = await readAgentTurnSessionSummariesFromIndex(
|
|
1154
|
+
agentTurnSessionConversationIndexKey(conversationId)
|
|
1155
|
+
);
|
|
1156
|
+
if (summaries.length > 0) {
|
|
1157
|
+
return summaries;
|
|
1158
|
+
}
|
|
1159
|
+
return (await readAgentTurnSessionSummariesFromIndex(AGENT_TURN_SESSION_INDEX_KEY)).filter((summary) => summary.conversationId === conversationId);
|
|
1160
|
+
}
|
|
1161
|
+
async function abandonAgentTurnSessionRecord(args) {
|
|
1162
|
+
const existing = await getAgentTurnSessionRecord(
|
|
1163
|
+
args.conversationId,
|
|
1164
|
+
args.sessionId
|
|
1165
|
+
);
|
|
1166
|
+
if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned") {
|
|
1167
|
+
return void 0;
|
|
1168
|
+
}
|
|
1169
|
+
return await updateAgentTurnSessionState({
|
|
1170
|
+
existing,
|
|
1171
|
+
state: "abandoned",
|
|
1172
|
+
errorMessage: args.errorMessage ?? existing.errorMessage
|
|
1173
|
+
});
|
|
1174
|
+
}
|
|
1175
|
+
async function failAgentTurnSessionRecord(args) {
|
|
1176
|
+
const existing = await getAgentTurnSessionRecord(
|
|
1177
|
+
args.conversationId,
|
|
1178
|
+
args.sessionId
|
|
1179
|
+
);
|
|
1180
|
+
if (!existing || existing.state === "completed" || existing.state === "failed" || existing.state === "abandoned" || existing.version !== args.expectedVersion) {
|
|
1181
|
+
return void 0;
|
|
1182
|
+
}
|
|
1183
|
+
return await updateAgentTurnSessionState({
|
|
1184
|
+
existing,
|
|
1185
|
+
state: "failed",
|
|
1186
|
+
errorMessage: args.errorMessage ?? existing.errorMessage
|
|
1187
|
+
});
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
// src/chat/interruption-marker.ts
|
|
1191
|
+
var INTERRUPTED_MARKER = "\n\n[Response interrupted before completion]";
|
|
1192
|
+
function getInterruptionMarker() {
|
|
1193
|
+
return INTERRUPTED_MARKER;
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
export {
|
|
1197
|
+
piContentMessageSchema,
|
|
1198
|
+
loadActivityEntries,
|
|
1199
|
+
loadProjection,
|
|
1200
|
+
loadConnectedMcpProviders,
|
|
1201
|
+
recordMcpProviderConnected,
|
|
1202
|
+
recordAuthorizationRequested,
|
|
1203
|
+
recordAuthorizationCompleted,
|
|
1204
|
+
recordToolExecutionStarted,
|
|
1205
|
+
recordSubagentStarted,
|
|
1206
|
+
recordSubagentEnded,
|
|
1207
|
+
commitMessages,
|
|
1208
|
+
escapeXml,
|
|
1209
|
+
getAgentTurnSessionRecord,
|
|
1210
|
+
upsertAgentTurnSessionRecord,
|
|
1211
|
+
recordAgentTurnSessionSummary,
|
|
1212
|
+
listAgentTurnSessionSummariesForConversation,
|
|
1213
|
+
abandonAgentTurnSessionRecord,
|
|
1214
|
+
failAgentTurnSessionRecord,
|
|
1215
|
+
getInterruptionMarker
|
|
1216
|
+
};
|