@sentry/junior 0.97.1 → 0.98.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-XSUIVRQS.js → agent-hooks-OSW6C3CJ.js} +2 -2
- package/dist/api/conversations/detail.d.ts +1 -1
- package/dist/api/conversations/detail.query.d.ts +1 -1
- package/dist/api/conversations/projection.d.ts +0 -1
- package/dist/api/conversations/schema.d.ts +31 -8
- package/dist/api/people/schema.d.ts +0 -11
- package/dist/api/people/shared.d.ts +2 -4
- package/dist/api/schema.d.ts +1 -1
- package/dist/api/schema.js +2 -2
- package/dist/api-reference.d.ts +1 -1
- package/dist/api.js +10 -10
- package/dist/app.js +39 -28
- package/dist/chat/conversations/search.d.ts +24 -0
- package/dist/chat/conversations/sql/search.d.ts +4 -0
- package/dist/chat/db.d.ts +3 -0
- package/dist/chat/runtime/report-progress.d.ts +3 -0
- package/dist/chat/runtime/slack-resume.d.ts +2 -0
- package/dist/chat/slack/assistant-thread/status-scheduler.d.ts +4 -3
- package/dist/chat/slack/outbound.d.ts +6 -0
- package/dist/chat/slack/tools/conversation-search.d.ts +71 -0
- package/dist/chat/state/turn-session.d.ts +2 -0
- package/dist/chat/tool-support/zod-tool.d.ts +1 -1
- package/dist/chunk-6DTVCPLO.js +146 -0
- package/dist/{chunk-AUUCAFDE.js → chunk-6HHEZENZ.js} +126 -11
- package/dist/{chunk-VFH4ZKZT.js → chunk-CRQVIHDI.js} +1 -3
- package/dist/{chunk-6U26PYI5.js → chunk-CV22LUIV.js} +7 -17
- package/dist/{chunk-GUAP3H7O.js → chunk-DHHU2WSG.js} +2 -2
- package/dist/{chunk-XIRPQQVE.js → chunk-DPHWDS6I.js} +297 -171
- package/dist/{chunk-T533JLM3.js → chunk-ER45IV77.js} +8 -6
- package/dist/{chunk-LUAE4MGW.js → chunk-EUZ44ROE.js} +21 -4
- package/dist/{chunk-5HLDPVYS.js → chunk-FTTFV6DC.js} +1 -1
- package/dist/{chunk-3F4OPKGF.js → chunk-IO65E4ZD.js} +2 -2
- package/dist/{chunk-ON6YKIQ7.js → chunk-KJHAW6VE.js} +4 -10
- package/dist/{chunk-FBHZJFHI.js → chunk-NJEDJFK4.js} +1 -1
- package/dist/{chunk-35BNLDOJ.js → chunk-OGHXZ4KQ.js} +134 -57
- package/dist/{chunk-WJOSZOON.js → chunk-OL6XQ23W.js} +11 -150
- package/dist/{chunk-WGXMTFNU.js → chunk-WJ7STXT6.js} +5 -3
- package/dist/cli/chat.js +11 -10
- package/dist/cli/plugins.js +2 -2
- package/dist/cli/upgrade.js +9 -7
- package/dist/{db-BWXYIKFQ.js → db-GFSCDAHS.js} +3 -1
- package/dist/detail-W4ZSD45K.js +67 -0
- package/dist/{legacy-import-3NQJVGQL.js → legacy-import-6WWXMALY.js} +2 -2
- package/dist/{list-UXJI5Q5X.js → list-3KZNG3SJ.js} +3 -3
- package/dist/{list-A3WFRIYX.js → list-M5BRWW3D.js} +5 -6
- package/dist/{plugin-conversations-DDNGC35A.js → plugin-conversations-ZYRWZYEA.js} +2 -2
- package/dist/{profile-4RYDXWTF.js → profile-UEIRSVT3.js} +5 -5
- package/dist/{runner-JALSYH2P.js → runner-267ZRLZD.js} +8 -7
- package/dist/{stats-XKXH3PTY.js → stats-L62E4O4U.js} +7 -17
- package/dist/{subagent-TZ55XY37.js → subagent-5HZPQC7V.js} +6 -6
- package/migrations/0002_conversation_message_search.sql +1 -0
- package/migrations/meta/0002_snapshot.json +987 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/dist/detail-GA6NXWQJ.js +0 -43
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
import type { SlackMessageBlock } from "@/chat/slack/footer";
|
|
2
|
+
import { type SlackChannelId } from "@/chat/slack/ids";
|
|
2
3
|
import { type SlackMessageTs } from "@/chat/slack/timestamp";
|
|
4
|
+
/** Resolve a Slack message permalink without making read-only workflows fail on lookup errors. */
|
|
5
|
+
export declare function getSlackMessagePermalink(args: {
|
|
6
|
+
channelId: SlackChannelId;
|
|
7
|
+
messageTs: SlackMessageTs;
|
|
8
|
+
}): Promise<string | undefined>;
|
|
3
9
|
/** Post Slack `mrkdwn` text to a conversation or thread via the shared outbound boundary. */
|
|
4
10
|
export declare function postSlackMessage(input: {
|
|
5
11
|
blocks?: SlackMessageBlock[];
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ConversationSearchScope, ConversationSearchStore } from "@/chat/conversations/search";
|
|
2
|
+
import { getSlackMessagePermalink } from "@/chat/slack/outbound";
|
|
3
|
+
interface ConversationSearchToolDeps {
|
|
4
|
+
getPermalink?: typeof getSlackMessagePermalink;
|
|
5
|
+
store?: ConversationSearchStore;
|
|
6
|
+
}
|
|
7
|
+
/** Create a tool that searches retained public Junior threads across an authorized Slack workspace. */
|
|
8
|
+
export declare function createSlackConversationSearchTool(scope: ConversationSearchScope, currentConversationId: string, deps?: ConversationSearchToolDeps): Omit<import("../../tools/definition").AnyToolDefinition, "inputSchema" | "outputSchema" | "prepareArguments" | "execute"> & {
|
|
9
|
+
inputSchema: import("../../tools/definition").JsonSchemaObject;
|
|
10
|
+
outputSchema: import("../../tools/definition").JsonSchemaObject;
|
|
11
|
+
prepareArguments(args: unknown): {
|
|
12
|
+
query: string;
|
|
13
|
+
limit?: number | null | undefined;
|
|
14
|
+
};
|
|
15
|
+
execute?: ((input: unknown, options: import("../../tools/definition").ToolExecuteOptions) => {
|
|
16
|
+
[x: string]: unknown;
|
|
17
|
+
ok: boolean;
|
|
18
|
+
status: "error" | "success";
|
|
19
|
+
query: string;
|
|
20
|
+
count: number;
|
|
21
|
+
threads: {
|
|
22
|
+
conversation_id: string;
|
|
23
|
+
thread_ts: string;
|
|
24
|
+
message_id: string;
|
|
25
|
+
message_role: "assistant" | "user";
|
|
26
|
+
message_timestamp: string;
|
|
27
|
+
excerpt: string;
|
|
28
|
+
permalink?: string | undefined;
|
|
29
|
+
}[];
|
|
30
|
+
target?: string | undefined;
|
|
31
|
+
data?: unknown;
|
|
32
|
+
truncated?: boolean | undefined;
|
|
33
|
+
continuation?: {
|
|
34
|
+
arguments: Record<string, unknown>;
|
|
35
|
+
reason?: string | undefined;
|
|
36
|
+
} | undefined;
|
|
37
|
+
error?: string | {
|
|
38
|
+
kind: string;
|
|
39
|
+
message: string;
|
|
40
|
+
retryable?: boolean | undefined;
|
|
41
|
+
} | undefined;
|
|
42
|
+
} | Promise<{
|
|
43
|
+
[x: string]: unknown;
|
|
44
|
+
ok: boolean;
|
|
45
|
+
status: "error" | "success";
|
|
46
|
+
query: string;
|
|
47
|
+
count: number;
|
|
48
|
+
threads: {
|
|
49
|
+
conversation_id: string;
|
|
50
|
+
thread_ts: string;
|
|
51
|
+
message_id: string;
|
|
52
|
+
message_role: "assistant" | "user";
|
|
53
|
+
message_timestamp: string;
|
|
54
|
+
excerpt: string;
|
|
55
|
+
permalink?: string | undefined;
|
|
56
|
+
}[];
|
|
57
|
+
target?: string | undefined;
|
|
58
|
+
data?: unknown;
|
|
59
|
+
truncated?: boolean | undefined;
|
|
60
|
+
continuation?: {
|
|
61
|
+
arguments: Record<string, unknown>;
|
|
62
|
+
reason?: string | undefined;
|
|
63
|
+
} | undefined;
|
|
64
|
+
error?: string | {
|
|
65
|
+
kind: string;
|
|
66
|
+
message: string;
|
|
67
|
+
retryable?: boolean | undefined;
|
|
68
|
+
} | undefined;
|
|
69
|
+
}>) | undefined;
|
|
70
|
+
};
|
|
71
|
+
export {};
|
|
@@ -121,6 +121,8 @@ export declare function recordAgentTurnSessionSummary(args: {
|
|
|
121
121
|
export declare function listAgentTurnSessionSummaries(limit?: number): Promise<AgentTurnSessionSummary[]>;
|
|
122
122
|
/** List turn-session summaries for one conversation without the global feed cap. */
|
|
123
123
|
export declare function listAgentTurnSessionSummariesForConversation(conversationId: string): Promise<AgentTurnSessionSummary[]>;
|
|
124
|
+
/** List retained run summaries without falling back to global history. */
|
|
125
|
+
export declare function listBoundedAgentTurnSessionSummariesForConversation(conversationId: string): Promise<AgentTurnSessionSummary[]>;
|
|
124
126
|
/** Read complete per-conversation summary indexes with bounded backend load. */
|
|
125
127
|
export declare function listAgentTurnSessionSummariesForConversations(stateAdapter: StateAdapter, conversationIds: string[]): Promise<Map<string, AgentTurnSessionSummary[]>>;
|
|
126
128
|
/** Mark an unfinished turn session record as abandoned when a newer turn wins. */
|
|
@@ -2,7 +2,7 @@ import { z, type ZodType, type ZodTypeAny } from "zod";
|
|
|
2
2
|
import { type JuniorToolResult } from "@/chat/tool-support/structured-result";
|
|
3
3
|
import type { ImageContent, TextContent } from "@earendil-works/pi-ai";
|
|
4
4
|
import type { AnyToolDefinition, JsonSchemaObject, ToolExecuteOptions } from "@/chat/tools/definition";
|
|
5
|
-
type ZodToolDefinitionBase<TInputSchema extends ZodTypeAny> = Pick<AnyToolDefinition, "identity" | "description" | "exposure" | "annotations" | "promptSnippet" | "promptGuidelines" | "executionMode"> & {
|
|
5
|
+
type ZodToolDefinitionBase<TInputSchema extends ZodTypeAny> = Pick<AnyToolDefinition, "identity" | "source" | "description" | "exposure" | "annotations" | "promptSnippet" | "promptGuidelines" | "executionMode"> & {
|
|
6
6
|
inputSchema: TInputSchema;
|
|
7
7
|
prepareArguments?: (args: unknown) => z.input<TInputSchema>;
|
|
8
8
|
};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isRecord,
|
|
3
|
+
toOptionalNumber,
|
|
4
|
+
toOptionalString
|
|
5
|
+
} from "./chunk-OB42YVAE.js";
|
|
6
|
+
|
|
7
|
+
// src/chat/state/conversation.ts
|
|
8
|
+
function defaultConversationState() {
|
|
9
|
+
const nowMs = Date.now();
|
|
10
|
+
return {
|
|
11
|
+
schemaVersion: 1,
|
|
12
|
+
messages: [],
|
|
13
|
+
compactions: [],
|
|
14
|
+
backfill: {},
|
|
15
|
+
processing: {},
|
|
16
|
+
stats: {
|
|
17
|
+
estimatedContextTokens: 0,
|
|
18
|
+
totalMessageCount: 0,
|
|
19
|
+
compactedMessageCount: 0,
|
|
20
|
+
updatedAtMs: nowMs
|
|
21
|
+
},
|
|
22
|
+
vision: {
|
|
23
|
+
byFileId: {}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function coercePendingAuthState(value) {
|
|
28
|
+
if (!isRecord(value)) {
|
|
29
|
+
return void 0;
|
|
30
|
+
}
|
|
31
|
+
const kind = value.kind;
|
|
32
|
+
const provider = toOptionalString(value.provider);
|
|
33
|
+
const actorId = toOptionalString(value.actorId);
|
|
34
|
+
const scope = toOptionalString(value.scope);
|
|
35
|
+
const sessionId = toOptionalString(value.sessionId);
|
|
36
|
+
const linkSentAtMs = toOptionalNumber(value.linkSentAtMs);
|
|
37
|
+
if (kind !== "mcp" && kind !== "plugin" || !provider || !actorId || !sessionId || typeof linkSentAtMs !== "number") {
|
|
38
|
+
return void 0;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
kind,
|
|
42
|
+
provider,
|
|
43
|
+
actorId,
|
|
44
|
+
...scope ? { scope } : {},
|
|
45
|
+
sessionId,
|
|
46
|
+
linkSentAtMs
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function coerceThreadConversationState(value) {
|
|
50
|
+
if (!isRecord(value)) {
|
|
51
|
+
return defaultConversationState();
|
|
52
|
+
}
|
|
53
|
+
const root = value;
|
|
54
|
+
const rawConversation = isRecord(root.conversation) ? root.conversation : {};
|
|
55
|
+
const base = defaultConversationState();
|
|
56
|
+
const messages = [];
|
|
57
|
+
const rawCompactions = Array.isArray(rawConversation.compactions) ? rawConversation.compactions : [];
|
|
58
|
+
const compactions = [];
|
|
59
|
+
for (const item of rawCompactions) {
|
|
60
|
+
if (!isRecord(item)) continue;
|
|
61
|
+
const id = toOptionalString(item.id);
|
|
62
|
+
const summary = toOptionalString(item.summary);
|
|
63
|
+
const createdAtMs = toOptionalNumber(item.createdAtMs);
|
|
64
|
+
if (!id || !summary || !createdAtMs) continue;
|
|
65
|
+
const coveredMessageIds = Array.isArray(item.coveredMessageIds) ? item.coveredMessageIds.filter(
|
|
66
|
+
(entry) => typeof entry === "string" && entry.length > 0
|
|
67
|
+
) : [];
|
|
68
|
+
compactions.push({
|
|
69
|
+
id,
|
|
70
|
+
summary,
|
|
71
|
+
createdAtMs,
|
|
72
|
+
coveredMessageIds
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const rawBackfill = isRecord(rawConversation.backfill) ? rawConversation.backfill : {};
|
|
76
|
+
const backfill = {
|
|
77
|
+
completedAtMs: toOptionalNumber(rawBackfill.completedAtMs),
|
|
78
|
+
source: rawBackfill.source === "recent_messages" || rawBackfill.source === "thread_fetch" ? rawBackfill.source : void 0
|
|
79
|
+
};
|
|
80
|
+
const rawProcessing = isRecord(rawConversation.processing) ? rawConversation.processing : {};
|
|
81
|
+
const processing = {
|
|
82
|
+
activeTurnId: toOptionalString(rawProcessing.activeTurnId),
|
|
83
|
+
lastCompletedAtMs: toOptionalNumber(rawProcessing.lastCompletedAtMs),
|
|
84
|
+
pendingAuth: coercePendingAuthState(rawProcessing.pendingAuth)
|
|
85
|
+
};
|
|
86
|
+
const rawStats = isRecord(rawConversation.stats) ? rawConversation.stats : {};
|
|
87
|
+
const stats = {
|
|
88
|
+
estimatedContextTokens: toOptionalNumber(rawStats.estimatedContextTokens) ?? base.stats.estimatedContextTokens,
|
|
89
|
+
totalMessageCount: toOptionalNumber(rawStats.totalMessageCount) ?? messages.length,
|
|
90
|
+
compactedMessageCount: toOptionalNumber(rawStats.compactedMessageCount) ?? 0,
|
|
91
|
+
updatedAtMs: toOptionalNumber(rawStats.updatedAtMs) ?? base.stats.updatedAtMs
|
|
92
|
+
};
|
|
93
|
+
const rawVision = isRecord(rawConversation.vision) ? rawConversation.vision : {};
|
|
94
|
+
const rawVisionByFileId = isRecord(rawVision.byFileId) ? rawVision.byFileId : {};
|
|
95
|
+
const byFileId = {};
|
|
96
|
+
for (const [fileId, value2] of Object.entries(rawVisionByFileId)) {
|
|
97
|
+
if (typeof fileId !== "string" || fileId.trim().length === 0) continue;
|
|
98
|
+
if (!isRecord(value2)) continue;
|
|
99
|
+
const summary = toOptionalString(value2.summary);
|
|
100
|
+
const analyzedAtMs = toOptionalNumber(value2.analyzedAtMs);
|
|
101
|
+
if (!summary || !analyzedAtMs) continue;
|
|
102
|
+
byFileId[fileId] = {
|
|
103
|
+
summary,
|
|
104
|
+
analyzedAtMs
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
schemaVersion: 1,
|
|
109
|
+
messages,
|
|
110
|
+
compactions,
|
|
111
|
+
backfill,
|
|
112
|
+
processing,
|
|
113
|
+
stats,
|
|
114
|
+
vision: {
|
|
115
|
+
backfillCompletedAtMs: toOptionalNumber(rawVision.backfillCompletedAtMs),
|
|
116
|
+
byFileId
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function buildConversationStatePatch(conversation) {
|
|
121
|
+
const {
|
|
122
|
+
compactions: _compactions,
|
|
123
|
+
messages: _messages,
|
|
124
|
+
...scratch
|
|
125
|
+
} = conversation;
|
|
126
|
+
return {
|
|
127
|
+
conversation: {
|
|
128
|
+
...scratch,
|
|
129
|
+
schemaVersion: 1,
|
|
130
|
+
stats: {
|
|
131
|
+
...conversation.stats,
|
|
132
|
+
totalMessageCount: conversation.messages.length,
|
|
133
|
+
updatedAtMs: Date.now()
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/chat/state/ttl.ts
|
|
140
|
+
var JUNIOR_THREAD_STATE_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
141
|
+
|
|
142
|
+
export {
|
|
143
|
+
JUNIOR_THREAD_STATE_TTL_MS,
|
|
144
|
+
coerceThreadConversationState,
|
|
145
|
+
buildConversationStatePatch
|
|
146
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
conversationSummaryFromStoredConversation
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KJHAW6VE.js";
|
|
4
4
|
import {
|
|
5
5
|
buildSentryConversationUrl,
|
|
6
6
|
buildSentryTraceUrl
|
|
@@ -8,11 +8,11 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
loadProjection,
|
|
10
10
|
projectSteps
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DHHU2WSG.js";
|
|
12
12
|
import {
|
|
13
13
|
getAgentStepStore,
|
|
14
14
|
getConversationMessageStore
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-OGHXZ4KQ.js";
|
|
16
16
|
import {
|
|
17
17
|
unescapeXml,
|
|
18
18
|
unwrapCurrentInstruction
|
|
@@ -24,6 +24,9 @@ import {
|
|
|
24
24
|
isRecord
|
|
25
25
|
} from "./chunk-OB42YVAE.js";
|
|
26
26
|
|
|
27
|
+
// src/api/conversations/detail-projection.ts
|
|
28
|
+
import { isDeepStrictEqual } from "util";
|
|
29
|
+
|
|
27
30
|
// src/api/conversations/transcript.ts
|
|
28
31
|
var SAFE_METADATA_KEY_LIMIT = 20;
|
|
29
32
|
var LEGACY_ADVISOR_TASK_OPEN = "<advisor-task>\n";
|
|
@@ -64,6 +67,14 @@ function recordField(value, names) {
|
|
|
64
67
|
}
|
|
65
68
|
return void 0;
|
|
66
69
|
}
|
|
70
|
+
function thinkingOutput(part) {
|
|
71
|
+
const output = recordField(part, ["thinking", "text", "content", "output"]);
|
|
72
|
+
return isRecord(output) ? recordField(output, ["thinking", "text", "content", "output"]) : output;
|
|
73
|
+
}
|
|
74
|
+
function isDisplayableTranscriptPart(part) {
|
|
75
|
+
if (part.type !== "thinking") return true;
|
|
76
|
+
return typeof part.output === "string" && part.output.trim().length > 0;
|
|
77
|
+
}
|
|
67
78
|
function normalizeTranscriptPart(part, options = {}) {
|
|
68
79
|
const displayText = (text) => {
|
|
69
80
|
if (options.unwrapCurrentTask) {
|
|
@@ -107,7 +118,7 @@ function normalizeTranscriptPart(part, options = {}) {
|
|
|
107
118
|
if (rawType === "thinking") {
|
|
108
119
|
return {
|
|
109
120
|
type: "thinking",
|
|
110
|
-
output:
|
|
121
|
+
output: thinkingOutput(part)
|
|
111
122
|
};
|
|
112
123
|
}
|
|
113
124
|
return {
|
|
@@ -155,7 +166,7 @@ function normalizeMessage(message, options = {}) {
|
|
|
155
166
|
unwrapCurrentTask: role === "user",
|
|
156
167
|
unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
|
|
157
168
|
})
|
|
158
|
-
) : [
|
|
169
|
+
).filter(isDisplayableTranscriptPart) : [
|
|
159
170
|
normalizeTranscriptPart(content, {
|
|
160
171
|
unwrapCurrentTask: role === "user",
|
|
161
172
|
unwrapLegacyAdvisorTask: options.unwrapLegacyAdvisorTask && role === "user"
|
|
@@ -393,9 +404,112 @@ function subagentActivityFromSteps(start, end, options = {}) {
|
|
|
393
404
|
}
|
|
394
405
|
|
|
395
406
|
// src/api/conversations/detail-projection.ts
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
407
|
+
var COMPACTION_SUMMARY_PREFIXES = [
|
|
408
|
+
"Context compaction summary for future Junior turns:",
|
|
409
|
+
"Context handoff summary for future Junior turns:"
|
|
410
|
+
];
|
|
411
|
+
var MODEL_HANDOFF_SUMMARY_PREFIX = "Model handoff checkpoint. Continue the outstanding request now using this summary as the complete prior context:";
|
|
412
|
+
function messageText(message) {
|
|
413
|
+
return normalizeTranscriptMessage(message).parts.filter((part) => part.type === "text").map((part) => part.text ?? "").join("\n").trim();
|
|
414
|
+
}
|
|
415
|
+
function summaryAfterPrefix(message, prefixes) {
|
|
416
|
+
const text = messageText(message);
|
|
417
|
+
const prefix = prefixes.find((candidate) => text.startsWith(candidate));
|
|
418
|
+
if (!prefix) return void 0;
|
|
419
|
+
return text.slice(prefix.length).trim();
|
|
420
|
+
}
|
|
421
|
+
function summaryIndex(messages, provenance, prefixes) {
|
|
422
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
423
|
+
if (provenance[index]?.authority === "context" && summaryAfterPrefix(messages[index], prefixes) !== void 0) {
|
|
424
|
+
return index;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return -1;
|
|
428
|
+
}
|
|
429
|
+
function matchingPrefix(left, right) {
|
|
430
|
+
const limit = Math.min(left.length, right.length);
|
|
431
|
+
for (let index = 0; index < limit; index += 1) {
|
|
432
|
+
if (!isDeepStrictEqual(left[index], right[index])) return index;
|
|
433
|
+
}
|
|
434
|
+
return limit;
|
|
435
|
+
}
|
|
436
|
+
function historyContent(args) {
|
|
437
|
+
const contextEvents = [];
|
|
438
|
+
const messages = [];
|
|
439
|
+
const epochs = /* @__PURE__ */ new Map();
|
|
440
|
+
for (const step of args.steps) {
|
|
441
|
+
const epoch = epochs.get(step.contextEpoch);
|
|
442
|
+
if (epoch) epoch.push(step);
|
|
443
|
+
else epochs.set(step.contextEpoch, [step]);
|
|
444
|
+
}
|
|
445
|
+
let previousModelId;
|
|
446
|
+
let previousProjection = [];
|
|
447
|
+
for (const steps of epochs.values()) {
|
|
448
|
+
const marker = steps.find(
|
|
449
|
+
(step) => step.entry.type === "context_epoch_started"
|
|
450
|
+
);
|
|
451
|
+
const projection = projectSteps(steps);
|
|
452
|
+
const projected = projection.messages;
|
|
453
|
+
const replacementSummaryIndex = marker?.entry.reason === "compaction" ? summaryIndex(
|
|
454
|
+
projected,
|
|
455
|
+
projection.provenance,
|
|
456
|
+
COMPACTION_SUMMARY_PREFIXES
|
|
457
|
+
) : marker?.entry.reason === "handoff" ? summaryIndex(projected, projection.provenance, [
|
|
458
|
+
MODEL_HANDOFF_SUMMARY_PREFIX
|
|
459
|
+
]) : -1;
|
|
460
|
+
const summary = replacementSummaryIndex >= 0 ? summaryAfterPrefix(
|
|
461
|
+
projected[replacementSummaryIndex],
|
|
462
|
+
marker?.entry.reason === "handoff" ? [MODEL_HANDOFF_SUMMARY_PREFIX] : COMPACTION_SUMMARY_PREFIXES
|
|
463
|
+
) : void 0;
|
|
464
|
+
if (marker?.entry.reason === "compaction") {
|
|
465
|
+
contextEvents.push({
|
|
466
|
+
type: "context_compacted",
|
|
467
|
+
createdAt: new Date(marker.createdAtMs).toISOString(),
|
|
468
|
+
...marker.entry.modelId ? { modelId: marker.entry.modelId } : {},
|
|
469
|
+
...args.canExposePayload && summary ? { summary } : {},
|
|
470
|
+
transcriptIndex: messages.length
|
|
471
|
+
});
|
|
472
|
+
} else if (marker?.entry.reason === "handoff") {
|
|
473
|
+
contextEvents.push({
|
|
474
|
+
type: "model_handoff",
|
|
475
|
+
createdAt: new Date(marker.createdAtMs).toISOString(),
|
|
476
|
+
...previousModelId ? { fromModelId: previousModelId } : {},
|
|
477
|
+
toModelId: marker.entry.modelId,
|
|
478
|
+
...args.canExposePayload && summary ? { summary } : {},
|
|
479
|
+
transcriptIndex: messages.length
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
if (marker?.entry.reason === "rollback") {
|
|
483
|
+
messages.push(
|
|
484
|
+
...projected.slice(matchingPrefix(previousProjection, projected))
|
|
485
|
+
);
|
|
486
|
+
} else {
|
|
487
|
+
const copiedMessageIndexes = /* @__PURE__ */ new Set();
|
|
488
|
+
projected.forEach((message, index) => {
|
|
489
|
+
if (index === replacementSummaryIndex) return;
|
|
490
|
+
let copiedCompactionMessage = false;
|
|
491
|
+
if (marker?.entry.reason === "compaction" && replacementSummaryIndex >= 0 && index < replacementSummaryIndex) {
|
|
492
|
+
const copiedIndex = messages.findIndex(
|
|
493
|
+
(candidate, candidateIndex) => !copiedMessageIndexes.has(candidateIndex) && isDeepStrictEqual(candidate, message)
|
|
494
|
+
);
|
|
495
|
+
copiedCompactionMessage = copiedIndex >= 0;
|
|
496
|
+
if (copiedCompactionMessage) copiedMessageIndexes.add(copiedIndex);
|
|
497
|
+
}
|
|
498
|
+
if (!copiedCompactionMessage) messages.push(message);
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
previousModelId = marker?.entry.modelId ?? previousModelId;
|
|
502
|
+
previousProjection = projected;
|
|
503
|
+
}
|
|
504
|
+
return { contextEvents, messages };
|
|
505
|
+
}
|
|
506
|
+
async function conversationContent(args) {
|
|
507
|
+
const steps = await args.stepStore.loadHistory(args.conversationId);
|
|
508
|
+
const history = historyContent({
|
|
509
|
+
canExposePayload: args.canExposePayload,
|
|
510
|
+
steps
|
|
511
|
+
});
|
|
512
|
+
const messages = history.messages;
|
|
399
513
|
const transcript = messages.length > 0 ? messages.map((message) => normalizeTranscriptMessage(message)) : (await args.messageStore.list(args.conversationId)).map(
|
|
400
514
|
visibleMessageTranscript
|
|
401
515
|
);
|
|
@@ -405,6 +519,7 @@ async function currentRunContent(args) {
|
|
|
405
519
|
steps,
|
|
406
520
|
messages
|
|
407
521
|
}),
|
|
522
|
+
contextEvents: history.contextEvents,
|
|
408
523
|
transcript
|
|
409
524
|
};
|
|
410
525
|
}
|
|
@@ -427,12 +542,12 @@ async function buildConversationDetail(args) {
|
|
|
427
542
|
conversationId,
|
|
428
543
|
visibility: conversation.visibility
|
|
429
544
|
});
|
|
430
|
-
const currentContent = transcriptPurgedAtMs === void 0 ? await
|
|
545
|
+
const currentContent = transcriptPurgedAtMs === void 0 ? await conversationContent({
|
|
431
546
|
conversationId,
|
|
432
547
|
messageStore,
|
|
433
548
|
stepStore,
|
|
434
549
|
canExposePayload: canExposeSqlContent
|
|
435
|
-
}) : { activity: [], transcript: [] };
|
|
550
|
+
}) : { activity: [], contextEvents: [], transcript: [] };
|
|
436
551
|
const currentTranscript = currentContent.transcript;
|
|
437
552
|
const traceId = canExposeSqlContent ? traceIdFromTranscript(currentTranscript) : void 0;
|
|
438
553
|
const sentryTraceUrl = traceId ? buildSentryTraceUrl(traceId) : void 0;
|
|
@@ -441,12 +556,12 @@ async function buildConversationDetail(args) {
|
|
|
441
556
|
...conversationSummaryFromStoredConversation({
|
|
442
557
|
conversation,
|
|
443
558
|
durationMs: args.durationMs,
|
|
444
|
-
nowMs,
|
|
445
559
|
usage: args.usage
|
|
446
560
|
}),
|
|
447
561
|
...traceId ? { traceId } : {},
|
|
448
562
|
...sentryTraceUrl ? { sentryTraceUrl } : {},
|
|
449
563
|
activity: currentContent.activity,
|
|
564
|
+
contextEvents: currentContent.contextEvents,
|
|
450
565
|
transcriptAvailable: transcriptExpiredAt === void 0 && canExposeSqlContent && currentTranscript.length > 0,
|
|
451
566
|
...currentTranscript.length > 0 ? {
|
|
452
567
|
transcriptMessageCount: countConversationMessages(currentTranscript)
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
actorIdentitySchema,
|
|
3
3
|
conversationStatsItemSchema,
|
|
4
4
|
conversationSummaryReportSchema
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-EUZ44ROE.js";
|
|
6
6
|
|
|
7
7
|
// src/api/people/schema.ts
|
|
8
8
|
import { z } from "zod";
|
|
@@ -18,7 +18,6 @@ var actorActivityDayReportSchema = z.object({
|
|
|
18
18
|
date: z.string(),
|
|
19
19
|
durationMs: z.number(),
|
|
20
20
|
failed: z.number(),
|
|
21
|
-
hung: z.number(),
|
|
22
21
|
tokens: z.number().optional()
|
|
23
22
|
}).strict();
|
|
24
23
|
var actorTotalsReportSchema = z.object({
|
|
@@ -27,7 +26,6 @@ var actorTotalsReportSchema = z.object({
|
|
|
27
26
|
conversations: z.number(),
|
|
28
27
|
durationMs: z.number(),
|
|
29
28
|
failed: z.number(),
|
|
30
|
-
hung: z.number(),
|
|
31
29
|
tokens: z.number().optional()
|
|
32
30
|
}).strict();
|
|
33
31
|
var identifiedActorSchema = actorIdentitySchema.extend({ email: z.string().min(1) }).strict();
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
juniorDestinations,
|
|
5
5
|
juniorIdentities,
|
|
6
6
|
juniorUsers
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OGHXZ4KQ.js";
|
|
8
8
|
|
|
9
9
|
// src/api/people/shared.ts
|
|
10
10
|
import { and, asc, desc, eq, sql } from "drizzle-orm";
|
|
@@ -12,7 +12,6 @@ var PRIVATE_CONVERSATION_LABEL = "Private Conversation";
|
|
|
12
12
|
var SAMPLE_LIMIT = 5e3;
|
|
13
13
|
var RECENT_LIMIT = 25;
|
|
14
14
|
var ACTIVITY_DAYS = 366;
|
|
15
|
-
var HUNG_PROGRESS_MS = 5 * 60 * 1e3;
|
|
16
15
|
function normalizeEmail(email) {
|
|
17
16
|
const normalized = email?.trim().toLowerCase();
|
|
18
17
|
return normalized || void 0;
|
|
@@ -39,17 +38,13 @@ function surfaceFromRow(row) {
|
|
|
39
38
|
if (row.conversationId.startsWith("api:")) return "api";
|
|
40
39
|
return "internal";
|
|
41
40
|
}
|
|
42
|
-
function statusFromRow(row
|
|
41
|
+
function statusFromRow(row) {
|
|
43
42
|
if (row.executionStatus === "failed") {
|
|
44
43
|
return "failed";
|
|
45
44
|
}
|
|
46
45
|
if (row.executionStatus === "idle") {
|
|
47
46
|
return "completed";
|
|
48
47
|
}
|
|
49
|
-
const updatedAtMs = (row.executionUpdatedAt ?? row.updatedAt).getTime();
|
|
50
|
-
if (row.executionStatus === "running" && nowMs - updatedAtMs > HUNG_PROGRESS_MS) {
|
|
51
|
-
return "hung";
|
|
52
|
-
}
|
|
53
48
|
return "active";
|
|
54
49
|
}
|
|
55
50
|
function surfaceLabel(surface) {
|
|
@@ -89,7 +84,7 @@ function titleFromRow(row, surface) {
|
|
|
89
84
|
channelName: row.channelName ?? void 0
|
|
90
85
|
}) ?? surfaceLabel(surface);
|
|
91
86
|
}
|
|
92
|
-
function summaryFromRow(row
|
|
87
|
+
function summaryFromRow(row) {
|
|
93
88
|
const surface = surfaceFromRow(row);
|
|
94
89
|
const channel = channelFromConversationId(row.conversationId);
|
|
95
90
|
const channelName = channelNameFromRow(row);
|
|
@@ -103,7 +98,7 @@ function summaryFromRow(row, nowMs) {
|
|
|
103
98
|
).toISOString(),
|
|
104
99
|
lastSeenAt: row.lastActivityAt.toISOString(),
|
|
105
100
|
startedAt: row.createdAt.toISOString(),
|
|
106
|
-
status: statusFromRow(row
|
|
101
|
+
status: statusFromRow(row),
|
|
107
102
|
surface,
|
|
108
103
|
actorIdentity: {
|
|
109
104
|
email: row.email,
|
|
@@ -134,8 +129,7 @@ function emptyTotals() {
|
|
|
134
129
|
activeDays: 0,
|
|
135
130
|
conversations: 0,
|
|
136
131
|
durationMs: 0,
|
|
137
|
-
failed: 0
|
|
138
|
-
hung: 0
|
|
132
|
+
failed: 0
|
|
139
133
|
};
|
|
140
134
|
}
|
|
141
135
|
function emptyStatsItem(label) {
|
|
@@ -144,7 +138,6 @@ function emptyStatsItem(label) {
|
|
|
144
138
|
conversations: 0,
|
|
145
139
|
durationMs: 0,
|
|
146
140
|
failed: 0,
|
|
147
|
-
hung: 0,
|
|
148
141
|
label
|
|
149
142
|
};
|
|
150
143
|
}
|
|
@@ -154,21 +147,18 @@ function emptyActivityDay(date) {
|
|
|
154
147
|
conversations: 0,
|
|
155
148
|
date,
|
|
156
149
|
durationMs: 0,
|
|
157
|
-
failed: 0
|
|
158
|
-
hung: 0
|
|
150
|
+
failed: 0
|
|
159
151
|
};
|
|
160
152
|
}
|
|
161
153
|
function signals(summary) {
|
|
162
154
|
return {
|
|
163
155
|
active: summary.status === "active",
|
|
164
|
-
failed: summary.status === "failed"
|
|
165
|
-
hung: summary.status === "hung"
|
|
156
|
+
failed: summary.status === "failed"
|
|
166
157
|
};
|
|
167
158
|
}
|
|
168
159
|
function addSignals(target, value) {
|
|
169
160
|
target.active += value.active ? 1 : 0;
|
|
170
161
|
target.failed += value.failed ? 1 : 0;
|
|
171
|
-
target.hung += value.hung ? 1 : 0;
|
|
172
162
|
}
|
|
173
163
|
function identityWithEmail(actor) {
|
|
174
164
|
const email = normalizeEmail(actor?.email);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ensureLegacyConversationImport
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-IO65E4ZD.js";
|
|
4
4
|
import {
|
|
5
5
|
contextProvenance,
|
|
6
6
|
getAgentStepStore
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OGHXZ4KQ.js";
|
|
8
8
|
|
|
9
9
|
// src/chat/conversations/projection.ts
|
|
10
10
|
import { isDeepStrictEqual } from "util";
|