@sentry/junior 0.225.0 → 0.226.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-CRuRcOg9.js → agent-hooks-FUetyyLe.js} +22 -15
- package/dist/{agent-runner-Cad1RtWn.js → agent-runner-DEF7auSj.js} +2946 -247
- package/dist/api/schema.d.ts +353 -10
- package/dist/api/schema.js +4 -4
- package/dist/api.js +22 -18
- package/dist/{app-BbSD6EtD.d.ts → app-TVL42pGL.d.ts} +1 -1
- package/dist/app.d.ts +1 -1
- package/dist/app.js +889 -7675
- package/dist/{briefs-BtnkPWT5.js → briefs-Cb4T2BUI.js} +4 -4
- package/dist/{catalog-runtime-pv4grNNb.js → catalog-runtime-BYGR3Dr4.js} +1 -1
- package/dist/{checkpoint-6fkAdB3g.js → checkpoint-CJe-dZFF.js} +76 -10
- package/dist/cli/chat.js +13 -13
- package/dist/cli/check.js +3 -3
- package/dist/cli/main.js +1 -1
- package/dist/cli/plugins.js +3 -3
- package/dist/cli/snapshot-create.js +3 -3
- package/dist/cli/upgrade.js +3 -3
- package/dist/{client-ihmkx60d.js → client-C2WBBx7m.js} +2 -2
- package/dist/{config-DMg679BW.js → config-Bws6Rpsh.js} +2 -2
- package/dist/{conversation-Bygi39Xj.js → conversation-DPbmIwjy.js} +66 -5
- package/dist/{conversation-privacy-ZYy05Y3q.js → conversation-privacy-pCcW0a5Y.js} +1 -1
- package/dist/{credential-sync-DCB2SwnQ.js → credential-sync-ibuNsMyl.js} +14 -134
- package/dist/{executor-B9R4cHte.js → executor-D36FWjcf.js} +1 -1
- package/dist/{history-yaSjGMD_.d.ts → history-DI9KJT3J.d.ts} +38 -1
- package/dist/instrumentation.js +2 -2
- package/dist/{vercel-queue-DIkVcfK4.js → job-queue-2mFFDMHB.js} +61 -2
- package/dist/{logging-CcTvYQ8A.js → logging-CvjMHRvg.js} +1 -1
- package/dist/nitro.d.ts +1 -1
- package/dist/nitro.js +3 -4
- package/dist/{oauth-authorization-BS4vPJmu.js → oauth-authorization-l4O1rXsL.js} +1 -1
- package/dist/{oauth-callback-server-DnlQsGBJ.js → oauth-callback-server-Ds8M5FFX.js} +2 -2
- package/dist/pending-auth-DLNJbD8H.js +59 -0
- package/dist/{profile-CV97YuiL.js → profile-dvV7PB7u.js} +4 -4
- package/dist/{prompt-CL8zxsmm.js → prompt-DehgjkO5.js} +1 -1
- package/dist/{registry-C8I4IejN.js → registry-C6FHctIu.js} +1 -1
- package/dist/{resolve-DXVAzYa3.js → resolve-DqwGI9wq.js} +2 -2
- package/dist/{runner-Die1RJ_z.js → runner-CzYEcB73.js} +9 -9
- package/dist/{sandbox-egress-signals-BZepyVh1.js → sandbox-egress-signals-BZOv0fns.js} +1 -1
- package/dist/{schema-BE4uso4i.js → schema-BZg-xzfG.js} +2 -2
- package/dist/{skills-DUcDEgDI.js → skills-EhiVbjF4.js} +2 -2
- package/dist/{spawn-o15i3tJu.js → spawn-Ck3L0rEr.js} +2 -2
- package/dist/{task-queue-D3PLY59C.js → task-queue-TXhAWQwj.js} +3 -4
- package/dist/{task-runner-BMl2aM2v.js → task-runner-axUJS1No.js} +380 -11
- package/dist/{thread-state-CAR6gdAm.js → thread-state-CTuWhjru.js} +5 -5
- package/dist/{turn-failure-response-CZyoUMkD.js → turn-failure-response-csVoLOzx.js} +8 -9
- package/dist/{turn-lifecycle-DPDHKi2U.js → turn-lifecycle-C1S6vELh.js} +1 -1
- package/dist/{turn-session-routing-Jkmmxpp-.js → turn-session-routing-5RejBvit.js} +1 -1
- package/dist/{validation-BcGGxOa6.js → validation-q2PFxkTQ.js} +1 -1
- package/dist/{version-DYcuOFQb.js → version-ByLtIYyy.js} +1 -1
- package/dist/version.js +1 -1
- package/dist/web-authorization-Biy8nsS7.js +162 -0
- package/dist/web-input-DM9LaEdn.js +7774 -0
- package/dist/{reporting-window-DbUqng0P.js → web-message-id-xPI_EFSC.js} +11 -1
- package/dist/{work-Bm90pR9P.js → work-QrbHdXTc.js} +7 -8
- package/dist/{worker-BvHr6JhE.js → worker-r17aopXW.js} +5 -6
- package/package.json +4 -4
- package/dist/execution-stats-CR9CYpyj.js +0 -373
- package/dist/job-queue-D2SiTrnt.js +0 -63
- package/dist/short-title-3wYH3ipl.js +0 -71
- package/dist/stats-DawHjcTw.js +0 -2758
- package/dist/web-authorization-B09B8A8R.js +0 -38
- package/dist/web-input-CGE58TpK.js +0 -899
|
@@ -226,4 +226,14 @@ function sumUtcHoursIntoSixHours(args) {
|
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
228
|
//#endregion
|
|
229
|
-
|
|
229
|
+
//#region src/chat/conversations/web-message-id.ts
|
|
230
|
+
/**
|
|
231
|
+
* Build the retry-stable Message id shared by web ingress and browser sends.
|
|
232
|
+
* Keep the existing hash and prefix so retries still address stored Messages.
|
|
233
|
+
*/
|
|
234
|
+
async function webMessageId(args) {
|
|
235
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(`${args.conversationId}\u0000${args.idempotencyKey}`));
|
|
236
|
+
return `api-msg:${Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("").slice(0, 24)}`;
|
|
237
|
+
}
|
|
238
|
+
//#endregion
|
|
239
|
+
export { skillReportsSchema as C, skillReportSchema as S, pluginPackageContentItemReportSchema as _, fillUtcHours as a, pluginsSchema as b, sumUtcHoursIntoSixHours as c, trailingUtcSixHourWindow as d, utcDayKey as f, pluginOperationalReportSchema as g, pluginOperationalReportFeedSchema as h, fillUtcDays as i, trailingUtcDayWindow as l, healthReportSchema as m, DAY_MS as n, fillUtcSixHours as o, utcHourKey as p, HOUR_MS as r, startOfUtcHour as s, webMessageId as t, trailingUtcHourWindow as u, pluginPackageContentReportSchema as v, runtimeInfoReportSchema as x, pluginSchema as y };
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
|
|
2
|
-
import {
|
|
3
|
-
import { Jt as getSqlExecutor, Kt as getConversationStore, Wt as getConversationEventStore } from "./agent-hooks-
|
|
4
|
-
import { f as juniorAgentBindings, p as juniorAgentInvocations } from "./executor-
|
|
5
|
-
import { I as openConversationProjection, _ as getTerminalAssistantMessages, o as failTurnRecord, r as saveTurnCheckpoint, s as getTurnRecord } from "./checkpoint-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState } from "./thread-state-CAR6gdAm.js";
|
|
2
|
+
import { Ct as appendAndEnqueueInboundMessage, dt as createAgentInvocationSchema, ft as AgentInvocationBusyError, jn as AuthorizationFlowDisabledError, lt as agentBindingSchema, n as runAgentWithTimeout, pt as AgentInvocationLimitError, ut as agentInvocationSchema, v as PluginCredentialFailureError } from "./agent-runner-DEF7auSj.js";
|
|
3
|
+
import { Jt as getSqlExecutor, Kt as getConversationStore, Wt as getConversationEventStore } from "./agent-hooks-FUetyyLe.js";
|
|
4
|
+
import { f as juniorAgentBindings, p as juniorAgentInvocations } from "./executor-D36FWjcf.js";
|
|
5
|
+
import { I as openConversationProjection, _ as getTerminalAssistantMessages, o as failTurnRecord, r as saveTurnCheckpoint, s as getTurnRecord } from "./checkpoint-CJe-dZFF.js";
|
|
6
|
+
import { d as getConversationTurnBoundaryError, l as TurnInputCommitLostError, p as isTurnInputCommitLostError, r as getAssistantReplyText } from "./oauth-authorization-l4O1rXsL.js";
|
|
7
|
+
import { t as ConversationTurnLifecycleService } from "./turn-lifecycle-C1S6vELh.js";
|
|
8
|
+
import { n as getPersistedSandboxState, o as persistThreadStateById, r as getPersistedThreadState } from "./thread-state-CTuWhjru.js";
|
|
10
9
|
import { z } from "zod";
|
|
11
10
|
import { createHash } from "node:crypto";
|
|
12
11
|
import { and, asc, count, eq, inArray } from "drizzle-orm";
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B4FMCO8f.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { a as getTurnRequestDeadline } from "./job-queue-D2SiTrnt.js";
|
|
2
|
+
import { At as completeConversationWork, Bt as recordConversationRetry, Dt as clearConsumedConversationWake, Et as checkInConversationWork, Gt as startConversationWork, It as getConversationWorkState, Mt as deadLetterAttempt, Nt as drainConversationMailbox, Pt as ensureConversationWake, Qt as isInvalidConversationRecordError, Ut as requestAnotherSlice, Vt as releaseConversationWork, Yt as hasConversationStop, Zt as isFinalAttempt, jt as countPendingConversationMessages, kt as completeConversationStop, wt as beginConversationResume, xt as ackMessages, zt as recordAttemptFailure } from "./agent-runner-DEF7auSj.js";
|
|
3
|
+
import { b as isProviderRetryError } from "./client-C2WBBx7m.js";
|
|
4
|
+
import { C as withLogContext, d as logException, f as logInfo, p as logWarn } from "./logging-CvjMHRvg.js";
|
|
5
|
+
import { a as getChatConfig } from "./config-Bws6Rpsh.js";
|
|
6
|
+
import { f as getTurnRequestDeadline, m as ConversationQueueMessageRejectedError } from "./job-queue-2mFFDMHB.js";
|
|
8
7
|
//#region src/chat/task-execution/worker.ts
|
|
9
8
|
var worker_exports = /* @__PURE__ */ __exportAll({
|
|
10
9
|
CONVERSATION_WORK_DEFER_DELAY_MS: () => CONVERSATION_WORK_DEFER_DELAY_MS,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/junior",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.226.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"pg": "^8.16.3",
|
|
86
86
|
"yaml": "^2.9.0",
|
|
87
87
|
"zod": "^4.5.4",
|
|
88
|
-
"@sentry/junior-plugin-api": "0.
|
|
88
|
+
"@sentry/junior-plugin-api": "0.226.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
91
91
|
"@emnapi/core": "^1.10.0",
|
|
@@ -104,9 +104,9 @@
|
|
|
104
104
|
"typescript": "^6.0.3",
|
|
105
105
|
"vercel": "^54.4.0",
|
|
106
106
|
"vitest": "^4.1.7",
|
|
107
|
-
"@sentry/junior-github": "0.
|
|
107
|
+
"@sentry/junior-github": "0.226.0",
|
|
108
108
|
"@sentry/junior-testing": "0.0.0",
|
|
109
|
-
"@sentry/junior-memory": "0.
|
|
109
|
+
"@sentry/junior-memory": "0.226.0"
|
|
110
110
|
},
|
|
111
111
|
"scripts": {
|
|
112
112
|
"build": "tsdown",
|
|
@@ -1,373 +0,0 @@
|
|
|
1
|
-
import { p as logWarn } from "./logging-CcTvYQ8A.js";
|
|
2
|
-
import { in as agentTurnTotalTokens, qt as getDb, rn as agentTurnCostUsd } from "./agent-hooks-CRuRcOg9.js";
|
|
3
|
-
import { E as juniorConversations, s as juniorAutomationExecutions } from "./executor-B9R4cHte.js";
|
|
4
|
-
import { and, asc, count, desc, eq, gte, inArray, lte, max, or, sql } from "drizzle-orm";
|
|
5
|
-
//#region src/api/conversations/aggregate.ts
|
|
6
|
-
function usageTokenValue(source, field) {
|
|
7
|
-
return sql`CASE
|
|
8
|
-
WHEN ${source.usage}->>${field} IS NOT NULL
|
|
9
|
-
THEN (${source.usage}->>${field})::double precision
|
|
10
|
-
ELSE NULL
|
|
11
|
-
END`;
|
|
12
|
-
}
|
|
13
|
-
function tokenValue(source) {
|
|
14
|
-
return sql`
|
|
15
|
-
CASE
|
|
16
|
-
WHEN COALESCE(
|
|
17
|
-
${source.usage}->>'inputTokens',
|
|
18
|
-
${source.usage}->>'outputTokens',
|
|
19
|
-
${source.usage}->>'cachedInputTokens',
|
|
20
|
-
${source.usage}->>'cacheCreationTokens'
|
|
21
|
-
) IS NOT NULL
|
|
22
|
-
THEN COALESCE((${source.usage}->>'inputTokens')::double precision, 0)
|
|
23
|
-
+ COALESCE((${source.usage}->>'outputTokens')::double precision, 0)
|
|
24
|
-
+ COALESCE((${source.usage}->>'cachedInputTokens')::double precision, 0)
|
|
25
|
-
+ COALESCE((${source.usage}->>'cacheCreationTokens')::double precision, 0)
|
|
26
|
-
WHEN ${source.usage}->>'totalTokens' IS NOT NULL
|
|
27
|
-
THEN (${source.usage}->>'totalTokens')::double precision
|
|
28
|
-
ELSE NULL
|
|
29
|
-
END
|
|
30
|
-
`;
|
|
31
|
-
}
|
|
32
|
-
function costValue(source) {
|
|
33
|
-
return conversationUsageCostExpr(source.usage);
|
|
34
|
-
}
|
|
35
|
-
/** Read one conversation row's usage cost as a SQL expression. */
|
|
36
|
-
function conversationUsageCostExpr(usage) {
|
|
37
|
-
return sql`
|
|
38
|
-
CASE
|
|
39
|
-
WHEN ${usage}->'cost'->>'total' IS NOT NULL
|
|
40
|
-
THEN (${usage}->'cost'->>'total')::double precision
|
|
41
|
-
WHEN COALESCE(
|
|
42
|
-
${usage}->'cost'->>'input',
|
|
43
|
-
${usage}->'cost'->>'output',
|
|
44
|
-
${usage}->'cost'->>'cacheRead',
|
|
45
|
-
${usage}->'cost'->>'cacheWrite'
|
|
46
|
-
) IS NOT NULL
|
|
47
|
-
THEN COALESCE((${usage}->'cost'->>'input')::double precision, 0)
|
|
48
|
-
+ COALESCE((${usage}->'cost'->>'output')::double precision, 0)
|
|
49
|
-
+ COALESCE((${usage}->'cost'->>'cacheRead')::double precision, 0)
|
|
50
|
-
+ COALESCE((${usage}->'cost'->>'cacheWrite')::double precision, 0)
|
|
51
|
-
ELSE NULL
|
|
52
|
-
END
|
|
53
|
-
`;
|
|
54
|
-
}
|
|
55
|
-
/** Select complete conversation metrics inside the database instead of materializing source rows. */
|
|
56
|
-
function conversationAggregateColumns(sources) {
|
|
57
|
-
const metrics = sources?.metrics ?? juniorConversations;
|
|
58
|
-
const roots = sources?.roots ?? juniorConversations;
|
|
59
|
-
const conversationCount = sources ? sql`COUNT(DISTINCT ${roots.conversationId})` : sql`COUNT(*)`;
|
|
60
|
-
return {
|
|
61
|
-
active: sql`${conversationCount} FILTER (
|
|
62
|
-
WHERE ${roots.executionStatus} NOT IN ('idle', 'failed')
|
|
63
|
-
)::integer`,
|
|
64
|
-
conversations: sql`${conversationCount}::integer`,
|
|
65
|
-
cachedInputTokens: sql`SUM(${usageTokenValue(metrics, "cachedInputTokens")})::double precision`,
|
|
66
|
-
cacheCreationTokens: sql`SUM(${usageTokenValue(metrics, "cacheCreationTokens")})::double precision`,
|
|
67
|
-
costUsd: sql`SUM(${costValue(metrics)})::double precision`,
|
|
68
|
-
durationMs: sql`COALESCE(SUM(${metrics.durationMs}), 0)::double precision`,
|
|
69
|
-
failed: sql`${conversationCount} FILTER (
|
|
70
|
-
WHERE ${roots.executionStatus} = 'failed'
|
|
71
|
-
)::integer`,
|
|
72
|
-
inputTokens: sql`SUM(${usageTokenValue(metrics, "inputTokens")})::double precision`,
|
|
73
|
-
tokens: sql`SUM(${tokenValue(metrics)})::double precision`
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
/** Select the complete first/last activity range for a grouped conversation aggregate. */
|
|
77
|
-
function conversationRangeColumns() {
|
|
78
|
-
return {
|
|
79
|
-
firstSeenAt: sql`MIN(${juniorConversations.createdAt})`.mapWith(juniorConversations.createdAt),
|
|
80
|
-
lastSeenAt: sql`MAX(${juniorConversations.lastActivityAt})`.mapWith(juniorConversations.lastActivityAt)
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/** Count distinct UTC activity dates without loading conversation timestamps into the app. */
|
|
84
|
-
function conversationActiveDaysColumn() {
|
|
85
|
-
return sql`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
|
|
86
|
-
}
|
|
87
|
-
//#endregion
|
|
88
|
-
//#region src/chat/automations/execution-stats.ts
|
|
89
|
-
const AUTOMATION_EXECUTION_TYPES = ["scheduled", "event"];
|
|
90
|
-
const AUTOMATION_EXECUTION_STATUSES = [
|
|
91
|
-
"blocked",
|
|
92
|
-
"completed",
|
|
93
|
-
"failed"
|
|
94
|
-
];
|
|
95
|
-
function addUsd(current, next) {
|
|
96
|
-
return Math.round((current + next) * 0xe8d4a51000) / 0xe8d4a51000;
|
|
97
|
-
}
|
|
98
|
-
const EMPTY_RUN_WINDOWS = {
|
|
99
|
-
1: 0,
|
|
100
|
-
7: 0,
|
|
101
|
-
30: 0,
|
|
102
|
-
90: 0
|
|
103
|
-
};
|
|
104
|
-
/** Empty run windows for automations with no execution history. */
|
|
105
|
-
function emptyAutomationRunWindows() {
|
|
106
|
-
return { ...EMPTY_RUN_WINDOWS };
|
|
107
|
-
}
|
|
108
|
-
function utcDate(nowMs) {
|
|
109
|
-
return new Date(nowMs).toISOString().slice(0, 10);
|
|
110
|
-
}
|
|
111
|
-
function emptyDay(date) {
|
|
112
|
-
return {
|
|
113
|
-
costUsd: 0,
|
|
114
|
-
date,
|
|
115
|
-
event: 0,
|
|
116
|
-
scheduled: 0
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
function emptyStatusDay(date) {
|
|
120
|
-
return {
|
|
121
|
-
blocked: 0,
|
|
122
|
-
completed: 0,
|
|
123
|
-
date,
|
|
124
|
-
failed: 0
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
/** Record one terminal automation execution and its durable conversation when present. */
|
|
128
|
-
async function recordAutomationExecution(type, automationId, options) {
|
|
129
|
-
const namespace = options.namespace ?? "junior";
|
|
130
|
-
const nowMs = options.nowMs ?? Date.now();
|
|
131
|
-
const status = options.status ?? "completed";
|
|
132
|
-
try {
|
|
133
|
-
await getDb().insert(juniorAutomationExecutions).values({
|
|
134
|
-
...options.conversationId ? { conversationId: options.conversationId } : void 0,
|
|
135
|
-
executedAtMs: nowMs,
|
|
136
|
-
executionId: options.executionId,
|
|
137
|
-
kind: type,
|
|
138
|
-
namespace,
|
|
139
|
-
status,
|
|
140
|
-
automationId
|
|
141
|
-
}).onConflictDoNothing({ target: [
|
|
142
|
-
juniorAutomationExecutions.kind,
|
|
143
|
-
juniorAutomationExecutions.namespace,
|
|
144
|
-
juniorAutomationExecutions.executionId
|
|
145
|
-
] });
|
|
146
|
-
} catch (error) {
|
|
147
|
-
logWarn("task.execution.stat_failed", {
|
|
148
|
-
error,
|
|
149
|
-
"app.task.execution.id": options.executionId,
|
|
150
|
-
"app.task.execution.namespace": namespace,
|
|
151
|
-
"app.task.execution.status": status,
|
|
152
|
-
"app.task.execution.task_id": automationId,
|
|
153
|
-
"app.task.execution.type": type
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
/** Load usage analytics for all automations of one type and namespace. */
|
|
158
|
-
async function readAutomationExecutionSummaries(type, namespace, options = {}) {
|
|
159
|
-
const nowMs = options.nowMs ?? Date.now();
|
|
160
|
-
const oneDayAgoMs = nowMs - 864e5;
|
|
161
|
-
const sevenDaysAgoMs = nowMs - 6048e5;
|
|
162
|
-
const thirtyDaysAgoMs = nowMs - 2592e6;
|
|
163
|
-
const ninetyDaysAgoMs = nowMs - 7776e6;
|
|
164
|
-
const db = getDb();
|
|
165
|
-
const latest = db.selectDistinctOn([juniorAutomationExecutions.automationId], {
|
|
166
|
-
conversationId: juniorAutomationExecutions.conversationId,
|
|
167
|
-
automationId: juniorAutomationExecutions.automationId
|
|
168
|
-
}).from(juniorAutomationExecutions).where(and(eq(juniorAutomationExecutions.kind, type), eq(juniorAutomationExecutions.namespace, namespace))).orderBy(juniorAutomationExecutions.automationId, desc(juniorAutomationExecutions.executedAtMs), desc(juniorAutomationExecutions.executionId)).as("latest_task_execution");
|
|
169
|
-
const rows = await db.select({
|
|
170
|
-
lastConversationId: latest.conversationId,
|
|
171
|
-
lastExecutedAtMs: max(juniorAutomationExecutions.executedAtMs),
|
|
172
|
-
runsLast1Day: sql`count(*) filter (where ${juniorAutomationExecutions.executedAtMs} >= ${oneDayAgoMs})::int`,
|
|
173
|
-
runsLast7Days: sql`count(*) filter (where ${juniorAutomationExecutions.executedAtMs} >= ${sevenDaysAgoMs})::int`,
|
|
174
|
-
runsLast30Days: sql`count(*) filter (where ${juniorAutomationExecutions.executedAtMs} >= ${thirtyDaysAgoMs})::int`,
|
|
175
|
-
runsLast90Days: sql`count(*) filter (where ${juniorAutomationExecutions.executedAtMs} >= ${ninetyDaysAgoMs})::int`,
|
|
176
|
-
automationId: juniorAutomationExecutions.automationId,
|
|
177
|
-
totalRuns: sql`count(*)::int`
|
|
178
|
-
}).from(juniorAutomationExecutions).innerJoin(latest, eq(latest.automationId, juniorAutomationExecutions.automationId)).where(and(eq(juniorAutomationExecutions.kind, type), eq(juniorAutomationExecutions.namespace, namespace))).groupBy(juniorAutomationExecutions.automationId, latest.conversationId);
|
|
179
|
-
return new Map(rows.map((row) => [row.automationId, {
|
|
180
|
-
...row.lastConversationId ? { lastConversationId: row.lastConversationId } : void 0,
|
|
181
|
-
...row.lastExecutedAtMs !== null ? { lastExecutedAtMs: row.lastExecutedAtMs } : void 0,
|
|
182
|
-
runs: {
|
|
183
|
-
1: row.runsLast1Day,
|
|
184
|
-
7: row.runsLast7Days,
|
|
185
|
-
30: row.runsLast30Days,
|
|
186
|
-
90: row.runsLast90Days
|
|
187
|
-
},
|
|
188
|
-
totalRuns: row.totalRuns
|
|
189
|
-
}]));
|
|
190
|
-
}
|
|
191
|
-
/** Load a fixed trailing window of completed executions stacked by task type. */
|
|
192
|
-
async function readAutomationExecutionDays(dayCount = 90, options = {}) {
|
|
193
|
-
const end = utcDate(options.nowMs ?? Date.now());
|
|
194
|
-
const endMs = Date.parse(`${end}T23:59:59.999Z`);
|
|
195
|
-
const startMs = Date.parse(`${end}T00:00:00.000Z`) - (dayCount - 1) * 864e5;
|
|
196
|
-
const executionDate = sql`to_char(to_timestamp(${juniorAutomationExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
|
|
197
|
-
const conversationCost = conversationUsageCostExpr(juniorConversations.usage);
|
|
198
|
-
const rows = await getDb().select({
|
|
199
|
-
count: count(),
|
|
200
|
-
costUsd: sql`SUM(${conversationCost})::double precision`,
|
|
201
|
-
date: executionDate,
|
|
202
|
-
kind: juniorAutomationExecutions.kind
|
|
203
|
-
}).from(juniorAutomationExecutions).leftJoin(juniorConversations, eq(juniorConversations.conversationId, juniorAutomationExecutions.conversationId)).where(and(gte(juniorAutomationExecutions.executedAtMs, startMs), lte(juniorAutomationExecutions.executedAtMs, endMs), eq(juniorAutomationExecutions.status, "completed"))).groupBy(executionDate, juniorAutomationExecutions.kind).orderBy(asc(executionDate), asc(juniorAutomationExecutions.kind));
|
|
204
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
205
|
-
for (let offset = 0; offset < dayCount; offset += 1) {
|
|
206
|
-
const date = utcDate(startMs + offset * 864e5);
|
|
207
|
-
byDate.set(date, emptyDay(date));
|
|
208
|
-
}
|
|
209
|
-
for (const row of rows) {
|
|
210
|
-
const day = byDate.get(row.date);
|
|
211
|
-
if (!day) continue;
|
|
212
|
-
if (row.kind === "scheduled") day.scheduled = row.count;
|
|
213
|
-
else if (row.kind === "event") day.event = row.count;
|
|
214
|
-
if (row.costUsd !== null && row.costUsd > 0) day.costUsd = addUsd(day.costUsd, row.costUsd);
|
|
215
|
-
}
|
|
216
|
-
return [...byDate.values()];
|
|
217
|
-
}
|
|
218
|
-
/** Load a fixed trailing window of completed executions stacked by hour. */
|
|
219
|
-
async function readAutomationExecutionHours(hourCount = 168, options = {}) {
|
|
220
|
-
const nowMs = options.nowMs ?? Date.now();
|
|
221
|
-
const end = new Date(nowMs);
|
|
222
|
-
end.setUTCMinutes(0, 0, 0);
|
|
223
|
-
const endMs = end.getTime() + 3599999;
|
|
224
|
-
const startMs = end.getTime() - (hourCount - 1) * 36e5;
|
|
225
|
-
const executionHour = sql`to_char(to_timestamp(${juniorAutomationExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
|
|
226
|
-
const conversationCost = conversationUsageCostExpr(juniorConversations.usage);
|
|
227
|
-
const rows = await getDb().select({
|
|
228
|
-
count: count(),
|
|
229
|
-
costUsd: sql`SUM(${conversationCost})::double precision`,
|
|
230
|
-
date: executionHour,
|
|
231
|
-
kind: juniorAutomationExecutions.kind
|
|
232
|
-
}).from(juniorAutomationExecutions).leftJoin(juniorConversations, eq(juniorConversations.conversationId, juniorAutomationExecutions.conversationId)).where(and(gte(juniorAutomationExecutions.executedAtMs, startMs), lte(juniorAutomationExecutions.executedAtMs, endMs), eq(juniorAutomationExecutions.status, "completed"))).groupBy(executionHour, juniorAutomationExecutions.kind).orderBy(asc(executionHour), asc(juniorAutomationExecutions.kind));
|
|
233
|
-
const byHour = /* @__PURE__ */ new Map();
|
|
234
|
-
for (let offset = 0; offset < hourCount; offset += 1) {
|
|
235
|
-
const date = new Date(startMs + offset * 36e5).toISOString().slice(0, 13);
|
|
236
|
-
byHour.set(date, emptyDay(date));
|
|
237
|
-
}
|
|
238
|
-
for (const row of rows) {
|
|
239
|
-
const hour = byHour.get(row.date);
|
|
240
|
-
if (!hour) continue;
|
|
241
|
-
if (row.kind === "scheduled") hour.scheduled = row.count;
|
|
242
|
-
else if (row.kind === "event") hour.event = row.count;
|
|
243
|
-
if (row.costUsd !== null && row.costUsd > 0) hour.costUsd = addUsd(hour.costUsd, row.costUsd);
|
|
244
|
-
}
|
|
245
|
-
return [...byHour.values()];
|
|
246
|
-
}
|
|
247
|
-
/** Load the newest terminal automation execution linked to one conversation, if any. */
|
|
248
|
-
async function readAutomationExecutionByConversationId(args) {
|
|
249
|
-
const namespace = args.namespace ?? "junior";
|
|
250
|
-
const row = (await getDb().select({
|
|
251
|
-
kind: juniorAutomationExecutions.kind,
|
|
252
|
-
automationId: juniorAutomationExecutions.automationId
|
|
253
|
-
}).from(juniorAutomationExecutions).where(and(eq(juniorAutomationExecutions.conversationId, args.conversationId), eq(juniorAutomationExecutions.namespace, namespace), inArray(juniorAutomationExecutions.kind, [...AUTOMATION_EXECUTION_TYPES]))).orderBy(desc(juniorAutomationExecutions.executedAtMs), desc(juniorAutomationExecutions.executionId)).limit(1))[0];
|
|
254
|
-
if (!row) return void 0;
|
|
255
|
-
if (row.kind !== "scheduled" && row.kind !== "event") return void 0;
|
|
256
|
-
return {
|
|
257
|
-
kind: row.kind,
|
|
258
|
-
automationId: row.automationId
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
/** Load newest-first executions for one automation, with conversation titles when present. */
|
|
262
|
-
async function readAutomationExecutions(args) {
|
|
263
|
-
const namespace = args.namespace ?? "junior";
|
|
264
|
-
return (await getDb().select({
|
|
265
|
-
conversationId: juniorAutomationExecutions.conversationId,
|
|
266
|
-
durationMs: juniorConversations.durationMs,
|
|
267
|
-
executedAtMs: juniorAutomationExecutions.executedAtMs,
|
|
268
|
-
executionId: juniorAutomationExecutions.executionId,
|
|
269
|
-
status: juniorAutomationExecutions.status,
|
|
270
|
-
title: juniorConversations.title,
|
|
271
|
-
usage: juniorConversations.usage
|
|
272
|
-
}).from(juniorAutomationExecutions).leftJoin(juniorConversations, eq(juniorConversations.conversationId, juniorAutomationExecutions.conversationId)).where(and(eq(juniorAutomationExecutions.kind, args.kind), eq(juniorAutomationExecutions.namespace, namespace), eq(juniorAutomationExecutions.automationId, args.automationId))).orderBy(desc(juniorAutomationExecutions.executedAtMs), desc(juniorAutomationExecutions.executionId)).limit(args.limit)).map((row) => mapAutomationExecutionRecord(row));
|
|
273
|
-
}
|
|
274
|
-
/** Load newest-first executions for the supplied viewer-visible tasks. */
|
|
275
|
-
async function readAutomationRuns(args) {
|
|
276
|
-
const automations = args.automations ?? [];
|
|
277
|
-
const conversationIds = [...new Set((args.conversationIds ?? []).filter((conversationId) => conversationId.trim().length > 0))];
|
|
278
|
-
if (automations.length === 0 && conversationIds.length === 0) return [];
|
|
279
|
-
const namespace = args.namespace ?? "junior";
|
|
280
|
-
const selectors = [...automations.map((task) => and(eq(juniorAutomationExecutions.kind, task.kind), eq(juniorAutomationExecutions.automationId, task.automationId))), ...conversationIds.length > 0 ? [inArray(juniorAutomationExecutions.conversationId, conversationIds)] : []];
|
|
281
|
-
return (await getDb().select({
|
|
282
|
-
conversationId: juniorAutomationExecutions.conversationId,
|
|
283
|
-
durationMs: juniorConversations.durationMs,
|
|
284
|
-
executedAtMs: juniorAutomationExecutions.executedAtMs,
|
|
285
|
-
executionId: juniorAutomationExecutions.executionId,
|
|
286
|
-
kind: juniorAutomationExecutions.kind,
|
|
287
|
-
status: juniorAutomationExecutions.status,
|
|
288
|
-
automationId: juniorAutomationExecutions.automationId,
|
|
289
|
-
title: juniorConversations.title,
|
|
290
|
-
usage: juniorConversations.usage
|
|
291
|
-
}).from(juniorAutomationExecutions).leftJoin(juniorConversations, eq(juniorConversations.conversationId, juniorAutomationExecutions.conversationId)).where(and(eq(juniorAutomationExecutions.namespace, namespace), or(...selectors))).orderBy(desc(juniorAutomationExecutions.executedAtMs), desc(juniorAutomationExecutions.executionId)).limit(args.limit)).flatMap((row) => {
|
|
292
|
-
if (row.kind !== "scheduled" && row.kind !== "event") return [];
|
|
293
|
-
return [{
|
|
294
|
-
...mapAutomationExecutionRecord(row),
|
|
295
|
-
kind: row.kind,
|
|
296
|
-
automationId: row.automationId
|
|
297
|
-
}];
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
function mapAutomationExecutionRecord(row) {
|
|
301
|
-
const title = row.title?.trim();
|
|
302
|
-
const costUsd = agentTurnCostUsd(row.usage ?? void 0);
|
|
303
|
-
const totalTokens = agentTurnTotalTokens(row.usage ?? void 0);
|
|
304
|
-
const durationMs = typeof row.durationMs === "number" && Number.isFinite(row.durationMs) && row.durationMs > 0 ? row.durationMs : void 0;
|
|
305
|
-
return {
|
|
306
|
-
...row.conversationId ? { conversationId: row.conversationId } : void 0,
|
|
307
|
-
...costUsd !== void 0 ? { costUsd } : void 0,
|
|
308
|
-
...durationMs !== void 0 ? { durationMs } : void 0,
|
|
309
|
-
executedAt: new Date(row.executedAtMs).toISOString(),
|
|
310
|
-
executionId: row.executionId,
|
|
311
|
-
status: row.status,
|
|
312
|
-
...title ? { title } : void 0,
|
|
313
|
-
...totalTokens !== void 0 ? { totalTokens } : void 0
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
/** Load a fixed trailing window of terminal executions for one automation by status. */
|
|
317
|
-
async function readAutomationExecutionStatusDays(args) {
|
|
318
|
-
const dayCount = args.dayCount ?? 90;
|
|
319
|
-
const namespace = args.namespace ?? "junior";
|
|
320
|
-
const end = utcDate(args.nowMs ?? Date.now());
|
|
321
|
-
const endMs = Date.parse(`${end}T23:59:59.999Z`);
|
|
322
|
-
const startMs = Date.parse(`${end}T00:00:00.000Z`) - (dayCount - 1) * 864e5;
|
|
323
|
-
const executionDate = sql`to_char(to_timestamp(${juniorAutomationExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
|
|
324
|
-
const rows = await getDb().select({
|
|
325
|
-
count: count(),
|
|
326
|
-
date: executionDate,
|
|
327
|
-
status: juniorAutomationExecutions.status
|
|
328
|
-
}).from(juniorAutomationExecutions).where(and(eq(juniorAutomationExecutions.kind, args.kind), eq(juniorAutomationExecutions.namespace, namespace), eq(juniorAutomationExecutions.automationId, args.automationId), gte(juniorAutomationExecutions.executedAtMs, startMs), lte(juniorAutomationExecutions.executedAtMs, endMs), inArray(juniorAutomationExecutions.status, [...AUTOMATION_EXECUTION_STATUSES]))).groupBy(executionDate, juniorAutomationExecutions.status).orderBy(asc(executionDate), asc(juniorAutomationExecutions.status));
|
|
329
|
-
const byDate = /* @__PURE__ */ new Map();
|
|
330
|
-
for (let offset = 0; offset < dayCount; offset += 1) {
|
|
331
|
-
const date = utcDate(startMs + offset * 864e5);
|
|
332
|
-
byDate.set(date, emptyStatusDay(date));
|
|
333
|
-
}
|
|
334
|
-
for (const row of rows) {
|
|
335
|
-
const day = byDate.get(row.date);
|
|
336
|
-
if (!day) continue;
|
|
337
|
-
if (row.status === "completed") day.completed = row.count;
|
|
338
|
-
else if (row.status === "failed") day.failed = row.count;
|
|
339
|
-
else if (row.status === "blocked") day.blocked = row.count;
|
|
340
|
-
}
|
|
341
|
-
return [...byDate.values()];
|
|
342
|
-
}
|
|
343
|
-
/** Load a fixed trailing window of terminal executions for one automation by hour. */
|
|
344
|
-
async function readAutomationExecutionStatusHours(args) {
|
|
345
|
-
const hourCount = args.hourCount ?? 168;
|
|
346
|
-
const namespace = args.namespace ?? "junior";
|
|
347
|
-
const nowMs = args.nowMs ?? Date.now();
|
|
348
|
-
const end = new Date(nowMs);
|
|
349
|
-
end.setUTCMinutes(0, 0, 0);
|
|
350
|
-
const endMs = end.getTime() + 3599999;
|
|
351
|
-
const startMs = end.getTime() - (hourCount - 1) * 36e5;
|
|
352
|
-
const executionHour = sql`to_char(to_timestamp(${juniorAutomationExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
|
|
353
|
-
const rows = await getDb().select({
|
|
354
|
-
count: count(),
|
|
355
|
-
date: executionHour,
|
|
356
|
-
status: juniorAutomationExecutions.status
|
|
357
|
-
}).from(juniorAutomationExecutions).where(and(eq(juniorAutomationExecutions.kind, args.kind), eq(juniorAutomationExecutions.namespace, namespace), eq(juniorAutomationExecutions.automationId, args.automationId), gte(juniorAutomationExecutions.executedAtMs, startMs), lte(juniorAutomationExecutions.executedAtMs, endMs), inArray(juniorAutomationExecutions.status, [...AUTOMATION_EXECUTION_STATUSES]))).groupBy(executionHour, juniorAutomationExecutions.status).orderBy(asc(executionHour), asc(juniorAutomationExecutions.status));
|
|
358
|
-
const byHour = /* @__PURE__ */ new Map();
|
|
359
|
-
for (let offset = 0; offset < hourCount; offset += 1) {
|
|
360
|
-
const date = new Date(startMs + offset * 36e5).toISOString().slice(0, 13);
|
|
361
|
-
byHour.set(date, emptyStatusDay(date));
|
|
362
|
-
}
|
|
363
|
-
for (const row of rows) {
|
|
364
|
-
const hour = byHour.get(row.date);
|
|
365
|
-
if (!hour) continue;
|
|
366
|
-
if (row.status === "completed") hour.completed = row.count;
|
|
367
|
-
else if (row.status === "failed") hour.failed = row.count;
|
|
368
|
-
else if (row.status === "blocked") hour.blocked = row.count;
|
|
369
|
-
}
|
|
370
|
-
return [...byHour.values()];
|
|
371
|
-
}
|
|
372
|
-
//#endregion
|
|
373
|
-
export { readAutomationExecutionStatusDays as a, readAutomationExecutions as c, conversationActiveDaysColumn as d, conversationAggregateColumns as f, readAutomationExecutionHours as i, readAutomationRuns as l, readAutomationExecutionByConversationId as n, readAutomationExecutionStatusHours as o, conversationRangeColumns as p, readAutomationExecutionDays as r, readAutomationExecutionSummaries as s, emptyAutomationRunWindows as t, recordAutomationExecution as u };
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { a as getChatConfig } from "./config-DMg679BW.js";
|
|
2
|
-
import { a as signQueueMessage, i as QUEUE_SIGNATURE_MAX_AGE_MS, o as verifyQueueMessage, s as createVercelQueueClient } from "./vercel-queue-DIkVcfK4.js";
|
|
3
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
-
import { z } from "zod";
|
|
5
|
-
import { createHash } from "node:crypto";
|
|
6
|
-
//#region src/chat/runtime/request-deadline.ts
|
|
7
|
-
const requestDeadlineStorage = new AsyncLocalStorage();
|
|
8
|
-
function createTurnRequestDeadline(startedAtMs) {
|
|
9
|
-
return {
|
|
10
|
-
startedAtMs,
|
|
11
|
-
deadlineAtMs: startedAtMs + Math.max(1, getChatConfig().functionMaxDurationSeconds * 1e3 - 2e4)
|
|
12
|
-
};
|
|
13
|
-
}
|
|
14
|
-
/** Return the host request deadline inherited by the current async turn. */
|
|
15
|
-
function getTurnRequestDeadline() {
|
|
16
|
-
return requestDeadlineStorage.getStore();
|
|
17
|
-
}
|
|
18
|
-
/** Run work with one host request deadline shared by nested queued turns. */
|
|
19
|
-
function runWithTurnRequestDeadline(callback, startedAtMs = Date.now()) {
|
|
20
|
-
if (requestDeadlineStorage.getStore()) return callback();
|
|
21
|
-
return requestDeadlineStorage.run(createTurnRequestDeadline(startedAtMs), callback);
|
|
22
|
-
}
|
|
23
|
-
//#endregion
|
|
24
|
-
//#region src/chat/sandbox/snapshot/job-queue.ts
|
|
25
|
-
/** Send Workspace snapshot build messages. */
|
|
26
|
-
const SIGNATURE_CONTEXT = "junior.workspace_snapshot_queue.v1";
|
|
27
|
-
const SIGNATURE_VERSION = "v1";
|
|
28
|
-
const WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC = "junior_workspace_snapshots";
|
|
29
|
-
const workspaceSnapshotJobSign = {
|
|
30
|
-
context: SIGNATURE_CONTEXT,
|
|
31
|
-
schema: z.object({
|
|
32
|
-
workspaceId: z.string().uuid(),
|
|
33
|
-
profileHash: z.string().min(1)
|
|
34
|
-
}).strict(),
|
|
35
|
-
signatureVersion: SIGNATURE_VERSION,
|
|
36
|
-
parts: (message) => [message.workspaceId, message.profileHash]
|
|
37
|
-
};
|
|
38
|
-
function jobId(message) {
|
|
39
|
-
return `workspace-snapshot_${createHash("sha256").update(message.workspaceId).update("\0").update(message.profileHash).digest("hex").slice(0, 32)}`;
|
|
40
|
-
}
|
|
41
|
-
/** Sign a Workspace snapshot job for tests and local checks. */
|
|
42
|
-
function signWorkspaceSnapshotJobMessage(message, nowMs = Date.now()) {
|
|
43
|
-
return signQueueMessage(workspaceSnapshotJobSign, message, nowMs);
|
|
44
|
-
}
|
|
45
|
-
/** Check that a recent queue message came from Junior. */
|
|
46
|
-
function verifyWorkspaceSnapshotJobMessage(value, nowMs = Date.now()) {
|
|
47
|
-
return verifyQueueMessage(workspaceSnapshotJobSign, value, nowMs);
|
|
48
|
-
}
|
|
49
|
-
async function send(message, idempotencyKey) {
|
|
50
|
-
const options = { retentionSeconds: QUEUE_SIGNATURE_MAX_AGE_MS / 1e3 };
|
|
51
|
-
if (idempotencyKey) options.idempotencyKey = idempotencyKey;
|
|
52
|
-
await createVercelQueueClient().send(WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC, signWorkspaceSnapshotJobMessage(message), options);
|
|
53
|
-
}
|
|
54
|
-
/** Send a job unless the same Workspace build already has one. */
|
|
55
|
-
async function sendWorkspaceSnapshotJob(message) {
|
|
56
|
-
await send(message, jobId(message));
|
|
57
|
-
}
|
|
58
|
-
/** Send the next job for a Workspace build that is still running. */
|
|
59
|
-
async function sendNextWorkspaceSnapshotJob(message) {
|
|
60
|
-
await send(message);
|
|
61
|
-
}
|
|
62
|
-
//#endregion
|
|
63
|
-
export { getTurnRequestDeadline as a, verifyWorkspaceSnapshotJobMessage as i, sendNextWorkspaceSnapshotJob as n, runWithTurnRequestDeadline as o, sendWorkspaceSnapshotJob as r, WORKSPACE_SNAPSHOT_JOB_QUEUE_TOPIC as t };
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { p as logWarn } from "./logging-CcTvYQ8A.js";
|
|
2
|
-
import { n as botConfig } from "./config-DMg679BW.js";
|
|
3
|
-
const TITLE_PROMPTS = {
|
|
4
|
-
conversation: [
|
|
5
|
-
"Generate a concise 5-8 word conversation title from the first user message below.",
|
|
6
|
-
"Capture the user's main request.",
|
|
7
|
-
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
8
|
-
],
|
|
9
|
-
task: [
|
|
10
|
-
"Generate a concise 5-8 word task title from the task instruction below.",
|
|
11
|
-
"Capture the task's main purpose.",
|
|
12
|
-
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
13
|
-
]
|
|
14
|
-
};
|
|
15
|
-
/** Collapse whitespace and cap a candidate short title. */
|
|
16
|
-
function normalizeShortTitle(value) {
|
|
17
|
-
return value.replace(/\s+/g, " ").trim().slice(0, 60);
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Deterministic display title when no generated title is stored.
|
|
21
|
-
* Uses the first non-empty line of the source text, capped like generated titles.
|
|
22
|
-
*/
|
|
23
|
-
function fallbackShortTitle(sourceText, fallback = "Untitled") {
|
|
24
|
-
return normalizeShortTitle(sourceText.split(/\r?\n/).map((line) => line.trim()).find((line) => line.length > 0) ?? "") || fallback;
|
|
25
|
-
}
|
|
26
|
-
/** Generate a short title with the fast model, or return undefined on failure. */
|
|
27
|
-
async function generateShortTitle(args) {
|
|
28
|
-
args.signal?.throwIfAborted();
|
|
29
|
-
const sourceText = args.sourceText.trim();
|
|
30
|
-
if (!sourceText) return void 0;
|
|
31
|
-
try {
|
|
32
|
-
const result = await args.completeText({
|
|
33
|
-
signal: args.signal,
|
|
34
|
-
modelId: botConfig.fastModelId,
|
|
35
|
-
temperature: 0,
|
|
36
|
-
promptName: `junior.${args.kind}_title`,
|
|
37
|
-
messages: [{
|
|
38
|
-
role: "user",
|
|
39
|
-
content: [
|
|
40
|
-
...TITLE_PROMPTS[args.kind],
|
|
41
|
-
"",
|
|
42
|
-
args.kind === "conversation" ? `First user message: ${sourceText.slice(0, 500)}` : `Task instruction: ${sourceText.slice(0, 500)}`
|
|
43
|
-
].join("\n"),
|
|
44
|
-
timestamp: Date.now()
|
|
45
|
-
}],
|
|
46
|
-
metadata: { modelId: botConfig.fastModelId }
|
|
47
|
-
});
|
|
48
|
-
args.signal?.throwIfAborted();
|
|
49
|
-
return normalizeShortTitle(result.text) || void 0;
|
|
50
|
-
} catch (error) {
|
|
51
|
-
args.signal?.throwIfAborted();
|
|
52
|
-
logWarn(`${args.kind}.title.generation.failed`, { "exception.message": error instanceof Error ? error.message : String(error) });
|
|
53
|
-
return;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Prefer an explicit task title when provided; otherwise generate one from the
|
|
58
|
-
* instruction with the fast model.
|
|
59
|
-
*/
|
|
60
|
-
async function resolveTaskTitle(args) {
|
|
61
|
-
const explicit = normalizeShortTitle(args.title ?? "");
|
|
62
|
-
if (explicit) return explicit;
|
|
63
|
-
return generateShortTitle({
|
|
64
|
-
completeText: args.completeText,
|
|
65
|
-
kind: "task",
|
|
66
|
-
sourceText: args.instruction,
|
|
67
|
-
signal: args.signal
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
//#endregion
|
|
71
|
-
export { generateShortTitle as n, resolveTaskTitle as r, fallbackShortTitle as t };
|