@sentry/junior 0.193.0 → 0.195.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-DWY3MZZ7.js → agent-hooks-VIBTIP5F.js} +11 -11
- package/dist/api/activity.d.ts +9 -1
- package/dist/api/code/overview.d.ts +12 -0
- package/dist/api/conversations/aggregate.d.ts +2 -0
- package/dist/api/conversations/list.d.ts +1 -1
- package/dist/api/conversations/projection.d.ts +1 -1
- package/dist/api/locations/detail.d.ts +9 -1
- package/dist/api/locations/list.d.ts +5 -0
- package/dist/api/people/code.d.ts +6 -0
- package/dist/api/people/shared.d.ts +9 -1
- package/dist/api/reporting-window.d.ts +39 -1
- package/dist/api/schema/code.d.ts +12 -0
- package/dist/api/schema/conversation.d.ts +28 -3
- package/dist/api/schema/location.d.ts +14 -1
- package/dist/api/schema/person.d.ts +15 -1
- package/dist/api/schema/task.d.ts +83 -8
- package/dist/api/schema.d.ts +2 -2
- package/dist/api/schema.js +3 -1
- package/dist/api.js +320 -222
- package/dist/app.js +108 -39
- package/dist/{catalog-runtime-NAD44W5K.js → catalog-runtime-6E6SGRZK.js} +4 -4
- package/dist/chat/agent/resume.d.ts +2 -0
- package/dist/chat/config.d.ts +2 -0
- package/dist/chat/conversations/history.d.ts +4 -2
- package/dist/chat/event-tasks/store.d.ts +27 -17
- package/dist/chat/resource-events/notification.d.ts +2 -1
- package/dist/chat/services/automated-turn-limit.d.ts +110 -0
- package/dist/chat/services/turn-limit.d.ts +11 -1
- package/dist/chat/slack/automated-turn-limit-notice.d.ts +38 -0
- package/dist/chat/slack/{source-link.d.ts → location-url.d.ts} +1 -1
- package/dist/chat/task-execution/checkpoint.d.ts +2 -0
- package/dist/chat/task-execution/turn-cursor.d.ts +3 -0
- package/dist/chat/tasks/execution-stats.d.ts +15 -2
- package/dist/chat/tasks/read.d.ts +5 -2
- package/dist/chat/usage.d.ts +4 -0
- package/dist/{chunk-GUKGU6R7.js → chunk-3VWIZVK7.js} +1 -1
- package/dist/{chunk-THYNA2QN.js → chunk-5HNXLP4W.js} +1 -1
- package/dist/{chunk-GUMBIDDL.js → chunk-5NR7N567.js} +194 -43
- package/dist/{chunk-N6Q2PNSI.js → chunk-6GGDBXXP.js} +3 -3
- package/dist/{chunk-HMBTX5RK.js → chunk-6TRQLG3D.js} +1 -1
- package/dist/{chunk-IOUUS6H4.js → chunk-7MYXH5LA.js} +1 -1
- package/dist/{chunk-WH5VV2RW.js → chunk-7PQMTME5.js} +1 -1
- package/dist/{chunk-5E5SLAVD.js → chunk-7UED4D5T.js} +23 -25
- package/dist/{chunk-4UA5C7AM.js → chunk-BJZML4RT.js} +8 -8
- package/dist/{chunk-QDU5MW2R.js → chunk-C4NY6L7S.js} +1 -1
- package/dist/{chunk-DVU734PI.js → chunk-CE2P6TOV.js} +3 -3
- package/dist/{chunk-BFP3ZKG6.js → chunk-DTYOEHUP.js} +148 -19
- package/dist/{chunk-S5HS6WRH.js → chunk-FE3Y4KES.js} +5 -5
- package/dist/{chunk-PYBFVK6K.js → chunk-FEZIEEOP.js} +985 -569
- package/dist/{chunk-5S6AQFNG.js → chunk-FPQPYJEG.js} +23 -29
- package/dist/{chunk-42N6CDWF.js → chunk-HE5PZAPS.js} +4 -4
- package/dist/{chunk-QY2IU47O.js → chunk-HUQOXMDG.js} +1 -1
- package/dist/{chunk-IQCL5JGL.js → chunk-I4RH3KLJ.js} +1 -1
- package/dist/{chunk-LXRTHE43.js → chunk-JBSCMOLR.js} +5 -5
- package/dist/{chunk-OICYQPKP.js → chunk-KBPWC7NU.js} +1 -1
- package/dist/{chunk-2CYWEVOP.js → chunk-KQ3GZGBK.js} +88 -68
- package/dist/{chunk-GTXQHZ2O.js → chunk-KUQRWV53.js} +5 -5
- package/dist/{chunk-IBXXTO3J.js → chunk-L62JVQPL.js} +3 -3
- package/dist/{chunk-KWXZMHJS.js → chunk-LM7UE523.js} +3 -3
- package/dist/{chunk-WJJDQLVL.js → chunk-LMYRF6HX.js} +6 -2
- package/dist/{chunk-AZVDODSP.js → chunk-N67T4VY3.js} +9 -9
- package/dist/{chunk-D4XQZOHB.js → chunk-OQHO62VA.js} +8 -8
- package/dist/{chunk-FQ5HFSFR.js → chunk-PFQRZ4IB.js} +9 -6
- package/dist/{chunk-LG7Q4OW4.js → chunk-PYTRZZ4V.js} +8 -8
- package/dist/{chunk-THFNL3TL.js → chunk-QHJZSYKY.js} +2 -2
- package/dist/{chunk-5LEVZYXF.js → chunk-QKHZF2LH.js} +4 -4
- package/dist/{chunk-EYIMZY5O.js → chunk-QPZL2IYT.js} +100 -9
- package/dist/{chunk-D5YQPCEG.js → chunk-R5BGW4WR.js} +24 -2
- package/dist/{chunk-COCVPDWX.js → chunk-R5OHONYU.js} +6 -6
- package/dist/{chunk-DXFUYLHX.js → chunk-RKA22BQP.js} +1 -1
- package/dist/{chunk-3YZ2Q6AW.js → chunk-RQO67SAO.js} +2 -2
- package/dist/{chunk-ZFPEPWOO.js → chunk-RZ3PBNDV.js} +60 -29
- package/dist/{chunk-K47OVEO4.js → chunk-VYDIA2UL.js} +1 -1
- package/dist/{chunk-QWY4KI2V.js → chunk-X3PBQ4BK.js} +1 -1
- package/dist/cli/chat.js +33 -33
- package/dist/cli/check.js +5 -5
- package/dist/cli/plugins.js +12 -12
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +6 -6
- package/dist/db/schema/event-tasks.d.ts +21 -0
- package/dist/db/schema.d.ts +19 -0
- package/dist/{db-H5MDRQEY.js → db-FVCSDROR.js} +6 -6
- package/dist/instrumentation.js +3 -3
- package/dist/nitro.js +6 -6
- package/dist/{oauth-callback-server-IOU3NUHT.js → oauth-callback-server-Z5PXTDOE.js} +29 -29
- package/dist/{runner-FZ5ZHLFG.js → runner-RHYU7OGV.js} +21 -21
- package/dist/{skills-AR3WD6BX.js → skills-QTN73DN5.js} +5 -5
- package/dist/spawn-R56OWLUH.js +42 -0
- package/dist/task-runner-LLJZTLRP.js +36 -0
- package/dist/{validation-VYE7TQY7.js → validation-2ZK7GA6N.js} +5 -5
- package/dist/version.js +1 -1
- package/dist/{work-CTQFWYKE.js → work-7IBKSZRU.js} +21 -21
- package/dist/{worker-6WQU3IT5.js → worker-RNVQVCO7.js} +10 -10
- package/migrations/0038_event_task_status.sql +5 -0
- package/migrations/meta/0038_snapshot.json +3323 -0
- package/migrations/meta/_journal.json +8 -1
- package/package.json +4 -4
- package/dist/spawn-ZU6JABR7.js +0 -42
- package/dist/task-runner-EEGGG2PM.js +0 -36
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Destination-visible pause notice for the consecutive automated-turn limit.
|
|
3
|
+
*
|
|
4
|
+
* Best-effort: a failed post must not fail the Turn or re-enable event wakes.
|
|
5
|
+
* The consecutive-turn limit claims the notice slot before this post. Clear that
|
|
6
|
+
* claim when the post fails or is skipped so a later paused wake can try again.
|
|
7
|
+
*/
|
|
8
|
+
import type { Destination } from "@sentry/junior-plugin-api";
|
|
9
|
+
import { type AutomatedTurnLimitScope, type AutomatedTurnLimitUpdate } from "@/chat/services/automated-turn-limit";
|
|
10
|
+
/** Post the pause notice for one Conversation Location when known. */
|
|
11
|
+
export declare function postAutomatedTurnLimitNoticeForConversation(args: {
|
|
12
|
+
conversationId: string;
|
|
13
|
+
maxTurns: number;
|
|
14
|
+
nowMs?: number;
|
|
15
|
+
resumeIn?: "thread" | "channel";
|
|
16
|
+
scope?: AutomatedTurnLimitScope;
|
|
17
|
+
}): Promise<boolean>;
|
|
18
|
+
/** Post the pause notice for one Slack Destination. */
|
|
19
|
+
export declare function postAutomatedTurnLimitNoticeForDestination(args: {
|
|
20
|
+
destination: Destination;
|
|
21
|
+
maxTurns: number;
|
|
22
|
+
nowMs?: number;
|
|
23
|
+
resumeIn?: "thread" | "channel";
|
|
24
|
+
scope?: AutomatedTurnLimitScope;
|
|
25
|
+
threadTs?: string;
|
|
26
|
+
}): Promise<boolean>;
|
|
27
|
+
/**
|
|
28
|
+
* Post the pause notice after a finished Turn hits the limit.
|
|
29
|
+
* Prefer the Conversation Location so thread watches stay in-thread.
|
|
30
|
+
*/
|
|
31
|
+
export declare function maybePostAutomatedTurnLimitNotice(args: {
|
|
32
|
+
conversationId: string;
|
|
33
|
+
destination?: Destination;
|
|
34
|
+
maxTurns: number;
|
|
35
|
+
nowMs?: number;
|
|
36
|
+
threadTs?: string;
|
|
37
|
+
update: AutomatedTurnLimitUpdate | undefined;
|
|
38
|
+
}): Promise<void>;
|
|
@@ -4,7 +4,7 @@ export declare function parseSlackTeamDomain(value: unknown): string | undefined
|
|
|
4
4
|
* Build a direct Slack archive URL for a thread when the workspace domain is
|
|
5
5
|
* known. Omits a link rather than falling back to `app_redirect`.
|
|
6
6
|
*/
|
|
7
|
-
export declare function
|
|
7
|
+
export declare function buildSlackLocationUrl(args: {
|
|
8
8
|
channelId: string;
|
|
9
9
|
teamDomain: string;
|
|
10
10
|
threadTs: string;
|
|
@@ -49,6 +49,8 @@ interface TurnCheckpointWrite {
|
|
|
49
49
|
source?: Source;
|
|
50
50
|
surface?: AgentTurnSurface;
|
|
51
51
|
turnStartMessageIndex?: number;
|
|
52
|
+
/** Tool calls charged to this turn; survives history replacement. */
|
|
53
|
+
cumulativeToolCallCount?: number;
|
|
52
54
|
trailingMessageProvenance?: ConversationMessageProvenance[];
|
|
53
55
|
turnContexts?: PluginTurnContext[];
|
|
54
56
|
durationMs?: number;
|
|
@@ -32,6 +32,8 @@ export interface TurnRecord {
|
|
|
32
32
|
version: number;
|
|
33
33
|
conversationId: string;
|
|
34
34
|
cumulativeDurationMs: number;
|
|
35
|
+
/** Tool calls charged to this turn; survives history replacement. */
|
|
36
|
+
cumulativeToolCallCount?: number;
|
|
35
37
|
cumulativeUsage?: AgentTurnUsage;
|
|
36
38
|
dispatchId?: string;
|
|
37
39
|
dispatchOutcome?: AgentDispatchOutcome;
|
|
@@ -86,6 +88,7 @@ export declare function upsertTurnRecord(args: {
|
|
|
86
88
|
channelName?: string;
|
|
87
89
|
conversationId: string;
|
|
88
90
|
cumulativeDurationMs?: number;
|
|
91
|
+
cumulativeToolCallCount?: number;
|
|
89
92
|
cumulativeUsage?: AgentTurnUsage;
|
|
90
93
|
destination?: Destination;
|
|
91
94
|
dispatchId?: string;
|
|
@@ -3,22 +3,34 @@ export declare const TASK_EXECUTION_TYPES: readonly ["scheduled", "event"];
|
|
|
3
3
|
export declare const TASK_EXECUTION_STATUSES: readonly ["blocked", "completed", "failed"];
|
|
4
4
|
export type TaskExecutionType = (typeof TASK_EXECUTION_TYPES)[number];
|
|
5
5
|
export type TaskExecutionDay = {
|
|
6
|
+
costUsd: number;
|
|
6
7
|
date: string;
|
|
7
8
|
event: number;
|
|
8
9
|
scheduled: number;
|
|
9
10
|
};
|
|
11
|
+
export type TaskRunWindows = {
|
|
12
|
+
1: number;
|
|
13
|
+
7: number;
|
|
14
|
+
30: number;
|
|
15
|
+
90: number;
|
|
16
|
+
};
|
|
10
17
|
export type TaskExecutionSummary = {
|
|
11
18
|
lastConversationId?: string;
|
|
12
19
|
lastExecutedAtMs?: number;
|
|
13
|
-
|
|
20
|
+
runs: TaskRunWindows;
|
|
14
21
|
totalRuns: number;
|
|
15
22
|
};
|
|
23
|
+
/** Empty run windows for tasks with no execution history. */
|
|
24
|
+
export declare function emptyTaskRunWindows(): TaskRunWindows;
|
|
16
25
|
export type TaskExecutionRecord = {
|
|
17
26
|
conversationId?: string;
|
|
27
|
+
costUsd?: number;
|
|
28
|
+
durationMs?: number;
|
|
18
29
|
executedAt: string;
|
|
19
30
|
executionId: string;
|
|
20
31
|
status: TaskExecutionStatus;
|
|
21
32
|
title?: string;
|
|
33
|
+
totalTokens?: number;
|
|
22
34
|
};
|
|
23
35
|
export type TaskRunRecord = TaskExecutionRecord & {
|
|
24
36
|
kind: TaskExecutionType;
|
|
@@ -67,9 +79,10 @@ export declare function readTaskExecutions(args: {
|
|
|
67
79
|
}): Promise<TaskExecutionRecord[]>;
|
|
68
80
|
/** Load newest-first executions for the supplied viewer-visible tasks. */
|
|
69
81
|
export declare function readTaskRuns(args: {
|
|
82
|
+
conversationIds?: string[];
|
|
70
83
|
limit: number;
|
|
71
84
|
namespace?: string;
|
|
72
|
-
tasks
|
|
85
|
+
tasks?: Array<{
|
|
73
86
|
kind: TaskExecutionType;
|
|
74
87
|
taskId: string;
|
|
75
88
|
}>;
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { User } from "@sentry/junior-plugin-api";
|
|
2
2
|
import type { ConversationSourceTask } from "@/api/schema/conversation";
|
|
3
3
|
import type { TaskExecutionList, TaskList, TaskRunList } from "@/api/schema/task";
|
|
4
|
-
/** Read viewer-owned and public-workspace tasks as one bounded newest-first projection. */
|
|
5
4
|
export declare function readViewerTasks(user: User): Promise<TaskList>;
|
|
6
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* Read newest runs across live viewer-visible tasks and deleted tasks the
|
|
7
|
+
* viewer owns. Deleted task rows stay available so history does not depend on
|
|
8
|
+
* conversation actor membership.
|
|
9
|
+
*/
|
|
7
10
|
export declare function readViewerTaskRuns(user: User): Promise<TaskRunList>;
|
|
8
11
|
export declare class ViewerTaskNotFoundError extends Error {
|
|
9
12
|
constructor();
|
package/dist/chat/usage.d.ts
CHANGED
|
@@ -34,5 +34,9 @@ export declare const agentTurnUsageSchema: import("zod").ZodObject<{
|
|
|
34
34
|
export type AgentTurnUsage = Usage;
|
|
35
35
|
/** Return whether any token counter is present on a usage record. */
|
|
36
36
|
export declare function hasAgentTurnUsage(usage: AgentTurnUsage | undefined): usage is AgentTurnUsage;
|
|
37
|
+
/** Estimated total USD cost from one usage record, when any cost field is present. */
|
|
38
|
+
export declare function agentTurnCostUsd(usage: AgentTurnUsage | undefined): number | undefined;
|
|
39
|
+
/** Total token count from one usage record, preferring component counters. */
|
|
40
|
+
export declare function agentTurnTotalTokens(usage: AgentTurnUsage | undefined): number | undefined;
|
|
37
41
|
/** Aggregate token usage across slices without double-counting provider totals. */
|
|
38
42
|
export declare function addAgentTurnUsage(...usages: Array<AgentTurnUsage | undefined>): AgentTurnUsage | undefined;
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
agentTurnCostUsd,
|
|
3
|
+
agentTurnTotalTokens
|
|
4
|
+
} from "./chunk-R5BGW4WR.js";
|
|
1
5
|
import {
|
|
2
6
|
getDb
|
|
3
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-KQ3GZGBK.js";
|
|
4
8
|
import {
|
|
5
9
|
juniorConversations,
|
|
6
10
|
juniorTaskExecutions
|
|
7
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-FPQPYJEG.js";
|
|
8
12
|
import {
|
|
9
13
|
logWarn
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-HUQOXMDG.js";
|
|
11
15
|
|
|
12
16
|
// src/chat/tasks/execution-stats.ts
|
|
13
17
|
import {
|
|
@@ -21,19 +25,111 @@ import {
|
|
|
21
25
|
lte,
|
|
22
26
|
max,
|
|
23
27
|
or,
|
|
24
|
-
sql
|
|
28
|
+
sql as sql2
|
|
25
29
|
} from "drizzle-orm";
|
|
30
|
+
|
|
31
|
+
// src/api/conversations/aggregate.ts
|
|
32
|
+
import { sql } from "drizzle-orm";
|
|
33
|
+
function usageTokenValue(source, field) {
|
|
34
|
+
return sql`CASE
|
|
35
|
+
WHEN ${source.usage}->>${field} IS NOT NULL
|
|
36
|
+
THEN (${source.usage}->>${field})::double precision
|
|
37
|
+
ELSE NULL
|
|
38
|
+
END`;
|
|
39
|
+
}
|
|
40
|
+
function tokenValue(source) {
|
|
41
|
+
return sql`
|
|
42
|
+
CASE
|
|
43
|
+
WHEN COALESCE(
|
|
44
|
+
${source.usage}->>'inputTokens',
|
|
45
|
+
${source.usage}->>'outputTokens',
|
|
46
|
+
${source.usage}->>'cachedInputTokens',
|
|
47
|
+
${source.usage}->>'cacheCreationTokens'
|
|
48
|
+
) IS NOT NULL
|
|
49
|
+
THEN COALESCE((${source.usage}->>'inputTokens')::double precision, 0)
|
|
50
|
+
+ COALESCE((${source.usage}->>'outputTokens')::double precision, 0)
|
|
51
|
+
+ COALESCE((${source.usage}->>'cachedInputTokens')::double precision, 0)
|
|
52
|
+
+ COALESCE((${source.usage}->>'cacheCreationTokens')::double precision, 0)
|
|
53
|
+
WHEN ${source.usage}->>'totalTokens' IS NOT NULL
|
|
54
|
+
THEN (${source.usage}->>'totalTokens')::double precision
|
|
55
|
+
ELSE NULL
|
|
56
|
+
END
|
|
57
|
+
`;
|
|
58
|
+
}
|
|
59
|
+
function costValue(source) {
|
|
60
|
+
return conversationUsageCostExpr(source.usage);
|
|
61
|
+
}
|
|
62
|
+
function conversationUsageCostExpr(usage) {
|
|
63
|
+
return sql`
|
|
64
|
+
CASE
|
|
65
|
+
WHEN ${usage}->'cost'->>'total' IS NOT NULL
|
|
66
|
+
THEN (${usage}->'cost'->>'total')::double precision
|
|
67
|
+
WHEN COALESCE(
|
|
68
|
+
${usage}->'cost'->>'input',
|
|
69
|
+
${usage}->'cost'->>'output',
|
|
70
|
+
${usage}->'cost'->>'cacheRead',
|
|
71
|
+
${usage}->'cost'->>'cacheWrite'
|
|
72
|
+
) IS NOT NULL
|
|
73
|
+
THEN COALESCE((${usage}->'cost'->>'input')::double precision, 0)
|
|
74
|
+
+ COALESCE((${usage}->'cost'->>'output')::double precision, 0)
|
|
75
|
+
+ COALESCE((${usage}->'cost'->>'cacheRead')::double precision, 0)
|
|
76
|
+
+ COALESCE((${usage}->'cost'->>'cacheWrite')::double precision, 0)
|
|
77
|
+
ELSE NULL
|
|
78
|
+
END
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
function conversationAggregateColumns(sources) {
|
|
82
|
+
const metrics = sources?.metrics ?? juniorConversations;
|
|
83
|
+
const roots = sources?.roots ?? juniorConversations;
|
|
84
|
+
const conversationCount = sources ? sql`COUNT(DISTINCT ${roots.conversationId})` : sql`COUNT(*)`;
|
|
85
|
+
return {
|
|
86
|
+
active: sql`${conversationCount} FILTER (
|
|
87
|
+
WHERE ${roots.executionStatus} NOT IN ('idle', 'failed')
|
|
88
|
+
)::integer`,
|
|
89
|
+
conversations: sql`${conversationCount}::integer`,
|
|
90
|
+
cachedInputTokens: sql`SUM(${usageTokenValue(metrics, "cachedInputTokens")})::double precision`,
|
|
91
|
+
costUsd: sql`SUM(${costValue(metrics)})::double precision`,
|
|
92
|
+
durationMs: sql`COALESCE(SUM(${metrics.durationMs}), 0)::double precision`,
|
|
93
|
+
failed: sql`${conversationCount} FILTER (
|
|
94
|
+
WHERE ${roots.executionStatus} = 'failed'
|
|
95
|
+
)::integer`,
|
|
96
|
+
inputTokens: sql`SUM(${usageTokenValue(metrics, "inputTokens")})::double precision`,
|
|
97
|
+
tokens: sql`SUM(${tokenValue(metrics)})::double precision`
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function conversationRangeColumns() {
|
|
101
|
+
return {
|
|
102
|
+
firstSeenAt: sql`MIN(${juniorConversations.createdAt})`.mapWith(
|
|
103
|
+
juniorConversations.createdAt
|
|
104
|
+
),
|
|
105
|
+
lastSeenAt: sql`MAX(${juniorConversations.lastActivityAt})`.mapWith(
|
|
106
|
+
juniorConversations.lastActivityAt
|
|
107
|
+
)
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
function conversationActiveDaysColumn() {
|
|
111
|
+
return sql`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/chat/tasks/execution-stats.ts
|
|
26
115
|
var TASK_EXECUTION_TYPES = ["scheduled", "event"];
|
|
27
116
|
var TASK_EXECUTION_STATUSES = [
|
|
28
117
|
"blocked",
|
|
29
118
|
"completed",
|
|
30
119
|
"failed"
|
|
31
120
|
];
|
|
121
|
+
function addUsd(current, next) {
|
|
122
|
+
return Math.round((current + next) * 1e12) / 1e12;
|
|
123
|
+
}
|
|
124
|
+
var EMPTY_RUN_WINDOWS = { 1: 0, 7: 0, 30: 0, 90: 0 };
|
|
125
|
+
function emptyTaskRunWindows() {
|
|
126
|
+
return { ...EMPTY_RUN_WINDOWS };
|
|
127
|
+
}
|
|
32
128
|
function utcDate(nowMs) {
|
|
33
129
|
return new Date(nowMs).toISOString().slice(0, 10);
|
|
34
130
|
}
|
|
35
131
|
function emptyDay(date) {
|
|
36
|
-
return { date, event: 0, scheduled: 0 };
|
|
132
|
+
return { costUsd: 0, date, event: 0, scheduled: 0 };
|
|
37
133
|
}
|
|
38
134
|
function emptyStatusDay(date) {
|
|
39
135
|
return { blocked: 0, completed: 0, date, failed: 0 };
|
|
@@ -70,7 +166,11 @@ async function recordTaskExecution(type, taskId, options) {
|
|
|
70
166
|
}
|
|
71
167
|
}
|
|
72
168
|
async function readTaskExecutionSummaries(type, namespace, options = {}) {
|
|
73
|
-
const
|
|
169
|
+
const nowMs = options.nowMs ?? Date.now();
|
|
170
|
+
const oneDayAgoMs = nowMs - 1 * 24 * 60 * 60 * 1e3;
|
|
171
|
+
const sevenDaysAgoMs = nowMs - 7 * 24 * 60 * 60 * 1e3;
|
|
172
|
+
const thirtyDaysAgoMs = nowMs - 30 * 24 * 60 * 60 * 1e3;
|
|
173
|
+
const ninetyDaysAgoMs = nowMs - 90 * 24 * 60 * 60 * 1e3;
|
|
74
174
|
const db = getDb();
|
|
75
175
|
const latest = db.selectDistinctOn([juniorTaskExecutions.taskId], {
|
|
76
176
|
conversationId: juniorTaskExecutions.conversationId,
|
|
@@ -88,9 +188,12 @@ async function readTaskExecutionSummaries(type, namespace, options = {}) {
|
|
|
88
188
|
const rows = await db.select({
|
|
89
189
|
lastConversationId: latest.conversationId,
|
|
90
190
|
lastExecutedAtMs: max(juniorTaskExecutions.executedAtMs),
|
|
91
|
-
|
|
191
|
+
runsLast1Day: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${oneDayAgoMs})::int`,
|
|
192
|
+
runsLast7Days: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${sevenDaysAgoMs})::int`,
|
|
193
|
+
runsLast30Days: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${thirtyDaysAgoMs})::int`,
|
|
194
|
+
runsLast90Days: sql2`count(*) filter (where ${juniorTaskExecutions.executedAtMs} >= ${ninetyDaysAgoMs})::int`,
|
|
92
195
|
taskId: juniorTaskExecutions.taskId,
|
|
93
|
-
totalRuns:
|
|
196
|
+
totalRuns: sql2`count(*)::int`
|
|
94
197
|
}).from(juniorTaskExecutions).innerJoin(latest, eq(latest.taskId, juniorTaskExecutions.taskId)).where(
|
|
95
198
|
and(
|
|
96
199
|
eq(juniorTaskExecutions.kind, type),
|
|
@@ -103,7 +206,12 @@ async function readTaskExecutionSummaries(type, namespace, options = {}) {
|
|
|
103
206
|
{
|
|
104
207
|
...row.lastConversationId ? { lastConversationId: row.lastConversationId } : void 0,
|
|
105
208
|
...row.lastExecutedAtMs !== null ? { lastExecutedAtMs: row.lastExecutedAtMs } : void 0,
|
|
106
|
-
|
|
209
|
+
runs: {
|
|
210
|
+
1: row.runsLast1Day,
|
|
211
|
+
7: row.runsLast7Days,
|
|
212
|
+
30: row.runsLast30Days,
|
|
213
|
+
90: row.runsLast90Days
|
|
214
|
+
},
|
|
107
215
|
totalRuns: row.totalRuns
|
|
108
216
|
}
|
|
109
217
|
])
|
|
@@ -114,12 +222,20 @@ async function readTaskExecutionDays(dayCount = 90, options = {}) {
|
|
|
114
222
|
const end = utcDate(nowMs);
|
|
115
223
|
const endMs = Date.parse(`${end}T23:59:59.999Z`);
|
|
116
224
|
const startMs = Date.parse(`${end}T00:00:00.000Z`) - (dayCount - 1) * 864e5;
|
|
117
|
-
const executionDate =
|
|
225
|
+
const executionDate = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
|
|
226
|
+
const conversationCost = conversationUsageCostExpr(juniorConversations.usage);
|
|
118
227
|
const rows = await getDb().select({
|
|
119
228
|
count: count(),
|
|
229
|
+
costUsd: sql2`SUM(${conversationCost})::double precision`,
|
|
120
230
|
date: executionDate,
|
|
121
231
|
kind: juniorTaskExecutions.kind
|
|
122
|
-
}).from(juniorTaskExecutions).
|
|
232
|
+
}).from(juniorTaskExecutions).leftJoin(
|
|
233
|
+
juniorConversations,
|
|
234
|
+
eq(
|
|
235
|
+
juniorConversations.conversationId,
|
|
236
|
+
juniorTaskExecutions.conversationId
|
|
237
|
+
)
|
|
238
|
+
).where(
|
|
123
239
|
and(
|
|
124
240
|
gte(juniorTaskExecutions.executedAtMs, startMs),
|
|
125
241
|
lte(juniorTaskExecutions.executedAtMs, endMs),
|
|
@@ -136,21 +252,32 @@ async function readTaskExecutionDays(dayCount = 90, options = {}) {
|
|
|
136
252
|
if (!day) continue;
|
|
137
253
|
if (row.kind === "scheduled") day.scheduled = row.count;
|
|
138
254
|
else if (row.kind === "event") day.event = row.count;
|
|
255
|
+
if (row.costUsd !== null && row.costUsd > 0) {
|
|
256
|
+
day.costUsd = addUsd(day.costUsd, row.costUsd);
|
|
257
|
+
}
|
|
139
258
|
}
|
|
140
259
|
return [...byDate.values()];
|
|
141
260
|
}
|
|
142
|
-
async function readTaskExecutionHours(hourCount = 24, options = {}) {
|
|
261
|
+
async function readTaskExecutionHours(hourCount = 7 * 24, options = {}) {
|
|
143
262
|
const nowMs = options.nowMs ?? Date.now();
|
|
144
263
|
const end = new Date(nowMs);
|
|
145
264
|
end.setUTCMinutes(0, 0, 0);
|
|
146
265
|
const endMs = end.getTime() + 3599999;
|
|
147
266
|
const startMs = end.getTime() - (hourCount - 1) * 36e5;
|
|
148
|
-
const executionHour =
|
|
267
|
+
const executionHour = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
|
|
268
|
+
const conversationCost = conversationUsageCostExpr(juniorConversations.usage);
|
|
149
269
|
const rows = await getDb().select({
|
|
150
270
|
count: count(),
|
|
271
|
+
costUsd: sql2`SUM(${conversationCost})::double precision`,
|
|
151
272
|
date: executionHour,
|
|
152
273
|
kind: juniorTaskExecutions.kind
|
|
153
|
-
}).from(juniorTaskExecutions).
|
|
274
|
+
}).from(juniorTaskExecutions).leftJoin(
|
|
275
|
+
juniorConversations,
|
|
276
|
+
eq(
|
|
277
|
+
juniorConversations.conversationId,
|
|
278
|
+
juniorTaskExecutions.conversationId
|
|
279
|
+
)
|
|
280
|
+
).where(
|
|
154
281
|
and(
|
|
155
282
|
gte(juniorTaskExecutions.executedAtMs, startMs),
|
|
156
283
|
lte(juniorTaskExecutions.executedAtMs, endMs),
|
|
@@ -167,6 +294,9 @@ async function readTaskExecutionHours(hourCount = 24, options = {}) {
|
|
|
167
294
|
if (!hour) continue;
|
|
168
295
|
if (row.kind === "scheduled") hour.scheduled = row.count;
|
|
169
296
|
else if (row.kind === "event") hour.event = row.count;
|
|
297
|
+
if (row.costUsd !== null && row.costUsd > 0) {
|
|
298
|
+
hour.costUsd = addUsd(hour.costUsd, row.costUsd);
|
|
299
|
+
}
|
|
170
300
|
}
|
|
171
301
|
return [...byHour.values()];
|
|
172
302
|
}
|
|
@@ -194,10 +324,12 @@ async function readTaskExecutions(args) {
|
|
|
194
324
|
const namespace = args.namespace ?? "junior";
|
|
195
325
|
const rows = await getDb().select({
|
|
196
326
|
conversationId: juniorTaskExecutions.conversationId,
|
|
327
|
+
durationMs: juniorConversations.durationMs,
|
|
197
328
|
executedAtMs: juniorTaskExecutions.executedAtMs,
|
|
198
329
|
executionId: juniorTaskExecutions.executionId,
|
|
199
330
|
status: juniorTaskExecutions.status,
|
|
200
|
-
title: juniorConversations.title
|
|
331
|
+
title: juniorConversations.title,
|
|
332
|
+
usage: juniorConversations.usage
|
|
201
333
|
}).from(juniorTaskExecutions).leftJoin(
|
|
202
334
|
juniorConversations,
|
|
203
335
|
eq(
|
|
@@ -214,34 +346,38 @@ async function readTaskExecutions(args) {
|
|
|
214
346
|
desc(juniorTaskExecutions.executedAtMs),
|
|
215
347
|
desc(juniorTaskExecutions.executionId)
|
|
216
348
|
).limit(args.limit);
|
|
217
|
-
return rows.map((row) =>
|
|
218
|
-
const title = row.title?.trim();
|
|
219
|
-
return {
|
|
220
|
-
...row.conversationId ? { conversationId: row.conversationId } : void 0,
|
|
221
|
-
executedAt: new Date(row.executedAtMs).toISOString(),
|
|
222
|
-
executionId: row.executionId,
|
|
223
|
-
status: row.status,
|
|
224
|
-
...title ? { title } : void 0
|
|
225
|
-
};
|
|
226
|
-
});
|
|
349
|
+
return rows.map((row) => mapTaskExecutionRecord(row));
|
|
227
350
|
}
|
|
228
351
|
async function readTaskRuns(args) {
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
352
|
+
const tasks = args.tasks ?? [];
|
|
353
|
+
const conversationIds = [
|
|
354
|
+
...new Set(
|
|
355
|
+
(args.conversationIds ?? []).filter(
|
|
356
|
+
(conversationId) => conversationId.trim().length > 0
|
|
357
|
+
)
|
|
235
358
|
)
|
|
236
|
-
|
|
359
|
+
];
|
|
360
|
+
if (tasks.length === 0 && conversationIds.length === 0) return [];
|
|
361
|
+
const namespace = args.namespace ?? "junior";
|
|
362
|
+
const selectors = [
|
|
363
|
+
...tasks.map(
|
|
364
|
+
(task) => and(
|
|
365
|
+
eq(juniorTaskExecutions.kind, task.kind),
|
|
366
|
+
eq(juniorTaskExecutions.taskId, task.taskId)
|
|
367
|
+
)
|
|
368
|
+
),
|
|
369
|
+
...conversationIds.length > 0 ? [inArray(juniorTaskExecutions.conversationId, conversationIds)] : []
|
|
370
|
+
];
|
|
237
371
|
const rows = await getDb().select({
|
|
238
372
|
conversationId: juniorTaskExecutions.conversationId,
|
|
373
|
+
durationMs: juniorConversations.durationMs,
|
|
239
374
|
executedAtMs: juniorTaskExecutions.executedAtMs,
|
|
240
375
|
executionId: juniorTaskExecutions.executionId,
|
|
241
376
|
kind: juniorTaskExecutions.kind,
|
|
242
377
|
status: juniorTaskExecutions.status,
|
|
243
378
|
taskId: juniorTaskExecutions.taskId,
|
|
244
|
-
title: juniorConversations.title
|
|
379
|
+
title: juniorConversations.title,
|
|
380
|
+
usage: juniorConversations.usage
|
|
245
381
|
}).from(juniorTaskExecutions).leftJoin(
|
|
246
382
|
juniorConversations,
|
|
247
383
|
eq(
|
|
@@ -254,20 +390,31 @@ async function readTaskRuns(args) {
|
|
|
254
390
|
).limit(args.limit);
|
|
255
391
|
return rows.flatMap((row) => {
|
|
256
392
|
if (row.kind !== "scheduled" && row.kind !== "event") return [];
|
|
257
|
-
const title = row.title?.trim();
|
|
258
393
|
return [
|
|
259
394
|
{
|
|
260
|
-
...row
|
|
261
|
-
executedAt: new Date(row.executedAtMs).toISOString(),
|
|
262
|
-
executionId: row.executionId,
|
|
395
|
+
...mapTaskExecutionRecord(row),
|
|
263
396
|
kind: row.kind,
|
|
264
|
-
|
|
265
|
-
taskId: row.taskId,
|
|
266
|
-
...title ? { title } : void 0
|
|
397
|
+
taskId: row.taskId
|
|
267
398
|
}
|
|
268
399
|
];
|
|
269
400
|
});
|
|
270
401
|
}
|
|
402
|
+
function mapTaskExecutionRecord(row) {
|
|
403
|
+
const title = row.title?.trim();
|
|
404
|
+
const costUsd = agentTurnCostUsd(row.usage ?? void 0);
|
|
405
|
+
const totalTokens = agentTurnTotalTokens(row.usage ?? void 0);
|
|
406
|
+
const durationMs = typeof row.durationMs === "number" && Number.isFinite(row.durationMs) && row.durationMs > 0 ? row.durationMs : void 0;
|
|
407
|
+
return {
|
|
408
|
+
...row.conversationId ? { conversationId: row.conversationId } : void 0,
|
|
409
|
+
...costUsd !== void 0 ? { costUsd } : void 0,
|
|
410
|
+
...durationMs !== void 0 ? { durationMs } : void 0,
|
|
411
|
+
executedAt: new Date(row.executedAtMs).toISOString(),
|
|
412
|
+
executionId: row.executionId,
|
|
413
|
+
status: row.status,
|
|
414
|
+
...title ? { title } : void 0,
|
|
415
|
+
...totalTokens !== void 0 ? { totalTokens } : void 0
|
|
416
|
+
};
|
|
417
|
+
}
|
|
271
418
|
async function readTaskExecutionStatusDays(args) {
|
|
272
419
|
const dayCount = args.dayCount ?? 90;
|
|
273
420
|
const namespace = args.namespace ?? "junior";
|
|
@@ -275,7 +422,7 @@ async function readTaskExecutionStatusDays(args) {
|
|
|
275
422
|
const end = utcDate(nowMs);
|
|
276
423
|
const endMs = Date.parse(`${end}T23:59:59.999Z`);
|
|
277
424
|
const startMs = Date.parse(`${end}T00:00:00.000Z`) - (dayCount - 1) * 864e5;
|
|
278
|
-
const executionDate =
|
|
425
|
+
const executionDate = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD')`;
|
|
279
426
|
const rows = await getDb().select({
|
|
280
427
|
count: count(),
|
|
281
428
|
date: executionDate,
|
|
@@ -305,14 +452,14 @@ async function readTaskExecutionStatusDays(args) {
|
|
|
305
452
|
return [...byDate.values()];
|
|
306
453
|
}
|
|
307
454
|
async function readTaskExecutionStatusHours(args) {
|
|
308
|
-
const hourCount = args.hourCount ?? 24;
|
|
455
|
+
const hourCount = args.hourCount ?? 7 * 24;
|
|
309
456
|
const namespace = args.namespace ?? "junior";
|
|
310
457
|
const nowMs = args.nowMs ?? Date.now();
|
|
311
458
|
const end = new Date(nowMs);
|
|
312
459
|
end.setUTCMinutes(0, 0, 0);
|
|
313
460
|
const endMs = end.getTime() + 3599999;
|
|
314
461
|
const startMs = end.getTime() - (hourCount - 1) * 36e5;
|
|
315
|
-
const executionHour =
|
|
462
|
+
const executionHour = sql2`to_char(to_timestamp(${juniorTaskExecutions.executedAtMs} / 1000.0) at time zone 'UTC', 'YYYY-MM-DD"T"HH24')`;
|
|
316
463
|
const rows = await getDb().select({
|
|
317
464
|
count: count(),
|
|
318
465
|
date: executionHour,
|
|
@@ -343,6 +490,10 @@ async function readTaskExecutionStatusHours(args) {
|
|
|
343
490
|
}
|
|
344
491
|
|
|
345
492
|
export {
|
|
493
|
+
conversationAggregateColumns,
|
|
494
|
+
conversationRangeColumns,
|
|
495
|
+
conversationActiveDaysColumn,
|
|
496
|
+
emptyTaskRunWindows,
|
|
346
497
|
recordTaskExecution,
|
|
347
498
|
readTaskExecutionSummaries,
|
|
348
499
|
readTaskExecutionDays,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runWithTurnRequestDeadline
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-I4RH3KLJ.js";
|
|
4
4
|
import {
|
|
5
5
|
QUEUE_SIGNATURE_MAX_AGE_MS,
|
|
6
6
|
createVercelQueueClient,
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-7H2VZTWN.js";
|
|
10
10
|
import {
|
|
11
11
|
logWarn
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-HUQOXMDG.js";
|
|
13
13
|
|
|
14
14
|
// src/chat/plugins/task-queue.ts
|
|
15
15
|
import { createHash } from "crypto";
|
|
@@ -129,7 +129,7 @@ function pluginTaskCallback() {
|
|
|
129
129
|
onRejected: logPluginTaskQueueMessageRejected,
|
|
130
130
|
// Load the runner on first use so this module can send without a cycle.
|
|
131
131
|
run: async (message) => {
|
|
132
|
-
const { processPluginTask } = await import("./task-runner-
|
|
132
|
+
const { processPluginTask } = await import("./task-runner-LLJZTLRP.js");
|
|
133
133
|
await processPluginTask(message);
|
|
134
134
|
},
|
|
135
135
|
topic: PLUGIN_TASK_QUEUE_TOPIC,
|