@mduan/paseo-cli 0.11.0-fork.1 → 0.11.0-fork.3
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/node_modules/@getpaseo/client/package.json +3 -3
- package/node_modules/@getpaseo/highlight/package.json +1 -1
- package/node_modules/@getpaseo/plugin/package.json +3 -3
- package/node_modules/@getpaseo/protocol/dist/agent-types.d.ts +3 -0
- package/node_modules/@getpaseo/protocol/dist/generated/validation/ws-outbound.aot.js +337 -1
- package/node_modules/@getpaseo/protocol/dist/messages.js +4 -0
- package/node_modules/@getpaseo/protocol/package.json +1 -1
- package/node_modules/@getpaseo/relay/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/builtin-plugins/package.json +1 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-manager.d.ts +2 -2
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-manager.js +5 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-projections.js +4 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-sdk-types.d.ts +8 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.d.ts +2 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/agent-storage.js +2 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/cost.d.ts +17 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/cost.js +25 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.d.ts +8 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/provider-subagents/subtitle-format.js +22 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.d.ts +20 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/appended-lines-reader.js +59 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/agent.js +147 -4
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.d.ts +6 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/live-source.js +33 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.d.ts +4 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/presentation.js +6 -8
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/replay-source.d.ts +13 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/replay-source.js +44 -22
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.d.ts +18 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/claude/subagents/transcript-cost.js +50 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.d.ts +15 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/pricing.js +32 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.d.ts +4 -8
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.js +11 -51
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.d.ts +7 -1
- package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.js +119 -17
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.d.ts +14 -0
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/snapshot.js +91 -4
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.d.ts +3 -3
- package/node_modules/@getpaseo/server/dist/server/server/agent/turn-diffs/store.js +24 -18
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js → desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js} +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js.br +4 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-6eaa3854bb0e0bf2260c50ed5acac196.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-46b63a296048f752e9cace2869e65020.js → desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js} +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{desktop-attachment-store-46b63a296048f752e9cace2869e65020.js.br → desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js.br} +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-f093e6af17b9293a6d18bd73214b3172.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{index-9489c4e1587c4252f0bd3b6e4b1abab3.js → index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js} +748 -747
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-ac557a7bf2f9db15fc71b6d2cbb3fcf7.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js → indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js} +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js.br → indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js.br} +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-c1b8c035b248805cc62bb0f7b8e50acc.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/{native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js → native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js} +3 -3
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-c3b75054cb85e7c8b21aedadaf7d54f3.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html +1 -1
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/index.html.gz +0 -0
- package/node_modules/@getpaseo/server/package.json +6 -6
- package/package.json +7 -7
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-bridge-930503b4f858c84de293b25a88bddcd5.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/desktop-attachment-store-46b63a296048f752e9cace2869e65020.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-9489c4e1587c4252f0bd3b6e4b1abab3.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/index-9489c4e1587c4252f0bd3b6e4b1abab3.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/indexeddb-attachment-store-4443393854050b1919467b89f1cbafc4.js.gz +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js.br +0 -0
- package/node_modules/@getpaseo/server/dist/server/web-ui/_expo/static/js/web/native-file-attachment-store-d5f9e56b2ce163fcb45fa34b52e2c3d1.js.gz +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { rollupProviderSubagentCosts } from "../../../provider-subagents/cost.js";
|
|
1
2
|
import { resolveObservedClaudeModelId } from "../models.js";
|
|
2
3
|
import { buildClaudeSubagentSubtitle, } from "./presentation.js";
|
|
3
4
|
/** Task-tool subagents. Backgrounded shell commands announce as `local_bash`. */
|
|
@@ -85,6 +86,8 @@ export class ClaudeTaskProtocolSource {
|
|
|
85
86
|
this.lastStatusById = new Map();
|
|
86
87
|
/** Claude facts stay inside the provider boundary; clients receive one compact subtitle. */
|
|
87
88
|
this.presentationById = new Map();
|
|
89
|
+
this.parentSubagentIdById = new Map();
|
|
90
|
+
this.directCostUsdById = new Map();
|
|
88
91
|
this.lastSubtitleById = new Map();
|
|
89
92
|
this.sawTaskStarted = false;
|
|
90
93
|
this.sawAnyTask = false;
|
|
@@ -111,6 +114,9 @@ export class ClaudeTaskProtocolSource {
|
|
|
111
114
|
get announcesTasks() {
|
|
112
115
|
return this.sawAnyTask;
|
|
113
116
|
}
|
|
117
|
+
get costTaskIds() {
|
|
118
|
+
return new Set(this.subagentIdByTaskId.keys());
|
|
119
|
+
}
|
|
114
120
|
/**
|
|
115
121
|
* Whether this source declared the given subagent. Callers route frames through this before
|
|
116
122
|
* attributing anything to an id: a frame for a task that was never declared belongs to work
|
|
@@ -172,6 +178,8 @@ export class ClaudeTaskProtocolSource {
|
|
|
172
178
|
this.backgroundedIds.clear();
|
|
173
179
|
this.lastStatusById.clear();
|
|
174
180
|
this.presentationById.clear();
|
|
181
|
+
this.parentSubagentIdById.clear();
|
|
182
|
+
this.directCostUsdById.clear();
|
|
175
183
|
this.lastSubtitleById.clear();
|
|
176
184
|
this.sawTaskStarted = false;
|
|
177
185
|
this.sawAnyTask = false;
|
|
@@ -252,6 +260,8 @@ export class ClaudeTaskProtocolSource {
|
|
|
252
260
|
this.canonicalIdByToolUseId.set(id, id);
|
|
253
261
|
this.declaredIds.add(id);
|
|
254
262
|
this.lastStatusById.set(id, "running");
|
|
263
|
+
if (parentSubagentId)
|
|
264
|
+
this.parentSubagentIdById.set(id, parentSubagentId);
|
|
255
265
|
// An explicit `name` on the Task call wins over the agent type, matching how replay titles the
|
|
256
266
|
// same subagent. Without it a fan-out of five Explores reads as five identical rows.
|
|
257
267
|
const isWorkflow = message.task_type === CLAUDE_WORKFLOW_TASK_TYPE;
|
|
@@ -335,6 +345,29 @@ export class ClaudeTaskProtocolSource {
|
|
|
335
345
|
return [];
|
|
336
346
|
return this.updatePresentation(id, { usage });
|
|
337
347
|
}
|
|
348
|
+
/** Cost estimated from the subagent's transcript, which the session reads as usage grows. */
|
|
349
|
+
observeCost(taskId, costUsd) {
|
|
350
|
+
const id = this.subagentIdByTaskId.get(taskId);
|
|
351
|
+
if (!id)
|
|
352
|
+
return [];
|
|
353
|
+
this.directCostUsdById.set(id, costUsd);
|
|
354
|
+
const costs = this.costRollup();
|
|
355
|
+
const observations = [];
|
|
356
|
+
for (const [subagentId, cost] of costs.byId) {
|
|
357
|
+
observations.push(...this.updatePresentation(subagentId, {
|
|
358
|
+
costUsd: this.directCostUsdById.get(subagentId),
|
|
359
|
+
subagentCostUsd: cost.subagentCostUsd,
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
return observations;
|
|
363
|
+
}
|
|
364
|
+
costRollup() {
|
|
365
|
+
return rollupProviderSubagentCosts([...this.declaredIds].map((id) => ({
|
|
366
|
+
id,
|
|
367
|
+
parentSubagentId: this.parentSubagentIdById.get(id) ?? null,
|
|
368
|
+
ownCostUsd: this.directCostUsdById.get(id) ?? 0,
|
|
369
|
+
})));
|
|
370
|
+
}
|
|
338
371
|
/**
|
|
339
372
|
* Effort as reported by a hook firing inside a subagent.
|
|
340
373
|
*
|
|
@@ -6,6 +6,10 @@ export interface ClaudeSubagentPresentationFacts {
|
|
|
6
6
|
model?: string;
|
|
7
7
|
effort?: string;
|
|
8
8
|
usage?: ClaudeSubagentUsage;
|
|
9
|
+
/** Estimated from list prices; Claude reports no cost per subagent. */
|
|
10
|
+
costUsd?: number;
|
|
11
|
+
/** Recursive cost of provider-native descendants, excluding this subagent. */
|
|
12
|
+
subagentCostUsd?: number;
|
|
9
13
|
}
|
|
10
14
|
/** Build the complete compact subtitle Claude exposes to provider-neutral clients. */
|
|
11
15
|
export declare function buildClaudeSubagentSubtitle(facts: ClaudeSubagentPresentationFacts): string | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatSubagentCosts, formatSubagentTokens, } from "../../../provider-subagents/subtitle-format.js";
|
|
1
2
|
import { findClaudeModel } from "../models.js";
|
|
2
3
|
/** Build the complete compact subtitle Claude exposes to provider-neutral clients. */
|
|
3
4
|
export function buildClaudeSubagentSubtitle(facts) {
|
|
@@ -5,7 +6,11 @@ export function buildClaudeSubagentSubtitle(facts) {
|
|
|
5
6
|
readPart(facts.title),
|
|
6
7
|
formatModel(facts.model),
|
|
7
8
|
formatEffort(facts.effort),
|
|
8
|
-
|
|
9
|
+
formatSubagentTokens(facts.usage?.totalTokens),
|
|
10
|
+
...formatSubagentCosts({
|
|
11
|
+
ownCostUsd: facts.costUsd,
|
|
12
|
+
subagentCostUsd: facts.subagentCostUsd,
|
|
13
|
+
}),
|
|
9
14
|
].filter((part) => part !== undefined);
|
|
10
15
|
return parts.length > 0 ? parts.join(" · ") : undefined;
|
|
11
16
|
}
|
|
@@ -31,11 +36,4 @@ function formatEffort(effort) {
|
|
|
31
36
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
32
37
|
.join(" ");
|
|
33
38
|
}
|
|
34
|
-
function formatTokens(totalTokens) {
|
|
35
|
-
if (typeof totalTokens !== "number" || totalTokens <= 0)
|
|
36
|
-
return undefined;
|
|
37
|
-
if (totalTokens < 1000)
|
|
38
|
-
return `${Math.round(totalTokens)} tokens`;
|
|
39
|
-
return `${Math.round(totalTokens / 100) / 10}k tokens`;
|
|
40
|
-
}
|
|
41
39
|
//# sourceMappingURL=presentation.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { AgentTimelineItem } from "../../../agent-sdk-types.js";
|
|
3
3
|
import type { SubagentObservation } from "./observation.js";
|
|
4
|
+
import { type ClaudeSubagentPresentationFacts } from "./presentation.js";
|
|
4
5
|
/**
|
|
5
6
|
* Rebuilds subagent observations from a persisted session, producing the same vocabulary the
|
|
6
7
|
* live task-protocol source produces. Identical observations in means identical descriptor
|
|
@@ -58,13 +59,25 @@ export interface ClaudeReplayParentFacts {
|
|
|
58
59
|
failed: boolean;
|
|
59
60
|
}>;
|
|
60
61
|
}
|
|
62
|
+
/** A replayed subagent whose subtitle gains a cost once its transcript is priced. */
|
|
63
|
+
export interface ClaudeReplaySubagentCostTarget {
|
|
64
|
+
id: string;
|
|
65
|
+
taskId: string;
|
|
66
|
+
parentSubagentId?: string;
|
|
67
|
+
facts: ClaudeSubagentPresentationFacts;
|
|
68
|
+
timestamp?: string;
|
|
69
|
+
}
|
|
70
|
+
/** Rebuild replayed subtitles with each transcript's own cost and its descendants' rollup. */
|
|
71
|
+
export declare function observeReplaySubagentCosts(targets: readonly ClaudeReplaySubagentCostTarget[], costUsdByTaskId: ReadonlyMap<string, number>): SubagentObservation[];
|
|
61
72
|
export declare function observeReplaySubagents(input: {
|
|
62
73
|
subagents: readonly ClaudeReplaySubagentInput[];
|
|
63
74
|
parent: ClaudeReplayParentFacts;
|
|
64
75
|
convertEntry: (entry: ClaudeReplayEntry) => AgentTimelineItem[];
|
|
65
76
|
}): {
|
|
66
77
|
observations: SubagentObservation[];
|
|
78
|
+
taskIds: ReadonlySet<string>;
|
|
67
79
|
toolOwners: ReadonlyMap<string, string>;
|
|
80
|
+
costTargets: readonly ClaudeReplaySubagentCostTarget[];
|
|
68
81
|
};
|
|
69
82
|
export {};
|
|
70
83
|
//# sourceMappingURL=replay-source.d.ts.map
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { normalizeProviderReplayTimestamp } from "../../../provider-history-timestamps.js";
|
|
3
3
|
import { resolveObservedClaudeModelId } from "../models.js";
|
|
4
|
-
import {
|
|
4
|
+
import { rollupProviderSubagentCosts } from "../../../provider-subagents/cost.js";
|
|
5
|
+
import { buildClaudeSubagentSubtitle, } from "./presentation.js";
|
|
5
6
|
/**
|
|
6
7
|
* Rebuilds subagent observations from a persisted session, producing the same vocabulary the
|
|
7
8
|
* live task-protocol source produces. Identical observations in means identical descriptor
|
|
@@ -191,30 +192,39 @@ function declareSubagent(subagent, link, toolCall, parentSubagentId) {
|
|
|
191
192
|
...(firstTimestamp ? { timestamp: firstTimestamp } : {}),
|
|
192
193
|
};
|
|
193
194
|
}
|
|
194
|
-
function
|
|
195
|
-
const runtime = readRuntime(subagent.entries);
|
|
195
|
+
function readSubtitleFacts(subagent, title) {
|
|
196
196
|
const usage = readUsage(subagent.entries);
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
return { title, ...readRuntime(subagent.entries), ...(usage ? { usage } : {}) };
|
|
198
|
+
}
|
|
199
|
+
function buildSubtitleObservation(id, facts, timestamp) {
|
|
200
|
+
const hasDetails = facts.model !== undefined ||
|
|
201
|
+
facts.effort !== undefined ||
|
|
202
|
+
(facts.usage?.totalTokens !== undefined && facts.usage.totalTokens > 0) ||
|
|
203
|
+
facts.costUsd !== undefined;
|
|
200
204
|
if (!hasDetails)
|
|
201
205
|
return null;
|
|
202
|
-
const subtitle = buildClaudeSubagentSubtitle(
|
|
203
|
-
title,
|
|
204
|
-
...runtime,
|
|
205
|
-
...(usage ? { usage } : {}),
|
|
206
|
-
});
|
|
206
|
+
const subtitle = buildClaudeSubagentSubtitle(facts);
|
|
207
207
|
if (!subtitle)
|
|
208
208
|
return null;
|
|
209
|
-
|
|
210
|
-
return {
|
|
211
|
-
kind: "subtitle",
|
|
212
|
-
id: link.id,
|
|
213
|
-
subtitle,
|
|
214
|
-
...(timestamp ? { timestamp } : {}),
|
|
215
|
-
};
|
|
209
|
+
return { kind: "subtitle", id, subtitle, ...(timestamp ? { timestamp } : {}) };
|
|
216
210
|
}
|
|
217
|
-
|
|
211
|
+
/** Rebuild replayed subtitles with each transcript's own cost and its descendants' rollup. */
|
|
212
|
+
export function observeReplaySubagentCosts(targets, costUsdByTaskId) {
|
|
213
|
+
const costs = rollupProviderSubagentCosts(targets.map((target) => ({
|
|
214
|
+
id: target.id,
|
|
215
|
+
parentSubagentId: target.parentSubagentId ?? null,
|
|
216
|
+
ownCostUsd: costUsdByTaskId.get(target.taskId) ?? 0,
|
|
217
|
+
})));
|
|
218
|
+
return targets.flatMap((target) => {
|
|
219
|
+
const costUsd = costUsdByTaskId.get(target.taskId);
|
|
220
|
+
const subagentCostUsd = costs.byId.get(target.id)?.subagentCostUsd ?? 0;
|
|
221
|
+
if (costUsd === undefined && subagentCostUsd <= 0)
|
|
222
|
+
return [];
|
|
223
|
+
const observation = buildSubtitleObservation(target.id, { ...target.facts, costUsd: costUsd ?? 0, subagentCostUsd }, target.timestamp);
|
|
224
|
+
return observation ? [observation] : [];
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function observeSubagent(subagent, parent, convertEntry, costTargets, parentSubagentId) {
|
|
218
228
|
const link = resolveParentLink(subagent, parent);
|
|
219
229
|
if (!link)
|
|
220
230
|
return [];
|
|
@@ -222,9 +232,18 @@ function observeSubagent(subagent, parent, convertEntry, parentSubagentId) {
|
|
|
222
232
|
const observations = [
|
|
223
233
|
declareSubagent(subagent, link, toolCall, parentSubagentId),
|
|
224
234
|
];
|
|
225
|
-
const
|
|
235
|
+
const facts = readSubtitleFacts(subagent, toolCall?.title ?? subagent.meta?.agentType);
|
|
236
|
+
const subtitleTimestamp = normalizeProviderReplayTimestamp(subagent.entries.at(-1)?.timestamp) ?? undefined;
|
|
237
|
+
const subtitle = buildSubtitleObservation(link.id, facts, subtitleTimestamp);
|
|
226
238
|
if (subtitle)
|
|
227
239
|
observations.push(subtitle);
|
|
240
|
+
costTargets.push({
|
|
241
|
+
id: link.id,
|
|
242
|
+
taskId: subagent.agentId,
|
|
243
|
+
...(parentSubagentId ? { parentSubagentId } : {}),
|
|
244
|
+
facts,
|
|
245
|
+
...(subtitleTimestamp ? { timestamp: subtitleTimestamp } : {}),
|
|
246
|
+
});
|
|
228
247
|
for (const entry of subagent.entries) {
|
|
229
248
|
const timestamp = normalizeProviderReplayTimestamp(entry.timestamp);
|
|
230
249
|
for (const item of convertEntry(entry)) {
|
|
@@ -263,6 +282,8 @@ function recordReplayToolOwners(owners, entries, subagentId) {
|
|
|
263
282
|
}
|
|
264
283
|
export function observeReplaySubagents(input) {
|
|
265
284
|
const observations = [];
|
|
285
|
+
const costTargets = [];
|
|
286
|
+
const taskIds = new Set();
|
|
266
287
|
const toolOwners = new Map();
|
|
267
288
|
const unresolved = [...input.subagents].sort((left, right) => (left.meta?.spawnDepth ?? 1) - (right.meta?.spawnDepth ?? 1));
|
|
268
289
|
const resolvedParents = new Map();
|
|
@@ -281,15 +302,16 @@ export function observeReplaySubagents(input) {
|
|
|
281
302
|
continue;
|
|
282
303
|
const { ownerId, parent, link } = resolved;
|
|
283
304
|
// Only proven descendants may own notifications; ambient sidecars cannot claim them.
|
|
305
|
+
taskIds.add(subagent.agentId);
|
|
284
306
|
recordReplayToolOwners(toolOwners, subagent.entries, link.id);
|
|
285
|
-
observations.push(...observeSubagent(subagent, parent, input.convertEntry, ownerId));
|
|
307
|
+
observations.push(...observeSubagent(subagent, parent, input.convertEntry, costTargets, ownerId));
|
|
286
308
|
if (subagent.parentFacts)
|
|
287
309
|
resolvedParents.set(link.id, subagent.parentFacts);
|
|
288
310
|
unresolved.splice(index, 1);
|
|
289
311
|
madeProgress = true;
|
|
290
312
|
}
|
|
291
313
|
}
|
|
292
|
-
return { observations, toolOwners };
|
|
314
|
+
return { observations, taskIds, toolOwners, costTargets };
|
|
293
315
|
}
|
|
294
316
|
function resolveReplayOwner(subagent, rootParent, resolvedParents) {
|
|
295
317
|
const rootLink = resolveParentLink(subagent, rootParent);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { CodexPrices } from "../../codex/pricing.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sums the estimated cost of every model request recorded in a Claude subagent transcript.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code reports only a token count per subagent, but its transcript records each request's
|
|
6
|
+
* model and usage split into input, cache writes, cache reads, and output, which is what a price
|
|
7
|
+
* needs. One request can span several entries that share a message id, so each id is priced once,
|
|
8
|
+
* from its latest entry.
|
|
9
|
+
*/
|
|
10
|
+
export declare class ClaudeTranscriptCost {
|
|
11
|
+
private readonly lines;
|
|
12
|
+
private readonly costByMessageId;
|
|
13
|
+
constructor(filePath: string);
|
|
14
|
+
/** Returns the cost so far, or undefined when no request used a priced model. */
|
|
15
|
+
read(prices: CodexPrices): Promise<number | undefined>;
|
|
16
|
+
private applyLine;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=transcript-cost.d.ts.map
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { AppendedLinesReader, parseRecordLine, readCount, toRecord, } from "../../appended-lines-reader.js";
|
|
2
|
+
/**
|
|
3
|
+
* Sums the estimated cost of every model request recorded in a Claude subagent transcript.
|
|
4
|
+
*
|
|
5
|
+
* Claude Code reports only a token count per subagent, but its transcript records each request's
|
|
6
|
+
* model and usage split into input, cache writes, cache reads, and output, which is what a price
|
|
7
|
+
* needs. One request can span several entries that share a message id, so each id is priced once,
|
|
8
|
+
* from its latest entry.
|
|
9
|
+
*/
|
|
10
|
+
export class ClaudeTranscriptCost {
|
|
11
|
+
constructor(filePath) {
|
|
12
|
+
this.costByMessageId = new Map();
|
|
13
|
+
this.lines = new AppendedLinesReader(filePath);
|
|
14
|
+
}
|
|
15
|
+
/** Returns the cost so far, or undefined when no request used a priced model. */
|
|
16
|
+
async read(prices) {
|
|
17
|
+
await this.lines.read((line) => this.applyLine(line, prices));
|
|
18
|
+
if (this.costByMessageId.size === 0)
|
|
19
|
+
return undefined;
|
|
20
|
+
let total = 0;
|
|
21
|
+
for (const cost of this.costByMessageId.values())
|
|
22
|
+
total += cost;
|
|
23
|
+
return total;
|
|
24
|
+
}
|
|
25
|
+
applyLine(line, prices) {
|
|
26
|
+
// Skip user entries and tool results without parsing them.
|
|
27
|
+
if (!line.includes('"assistant"') || !line.includes('"usage"'))
|
|
28
|
+
return;
|
|
29
|
+
const entry = parseRecordLine(line);
|
|
30
|
+
if (entry?.type !== "assistant")
|
|
31
|
+
return;
|
|
32
|
+
const message = toRecord(entry.message);
|
|
33
|
+
const usage = toRecord(message?.usage);
|
|
34
|
+
if (typeof message?.id !== "string" || !usage)
|
|
35
|
+
return;
|
|
36
|
+
const cacheWrite = readCount(usage.cache_creation_input_tokens);
|
|
37
|
+
const cacheWrite1h = readCount(toRecord(usage.cache_creation)?.ephemeral_1h_input_tokens);
|
|
38
|
+
const cost = prices.claudeRequestCostUsd({
|
|
39
|
+
model: typeof message.model === "string" ? message.model : undefined,
|
|
40
|
+
inputTokens: readCount(usage.input_tokens),
|
|
41
|
+
cacheWrite5mTokens: Math.max(0, cacheWrite - cacheWrite1h),
|
|
42
|
+
cacheWrite1hTokens: cacheWrite1h,
|
|
43
|
+
cacheReadTokens: readCount(usage.cache_read_input_tokens),
|
|
44
|
+
outputTokens: readCount(usage.output_tokens),
|
|
45
|
+
});
|
|
46
|
+
if (cost !== undefined)
|
|
47
|
+
this.costByMessageId.set(message.id, cost);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=transcript-cost.js.map
|
|
@@ -6,12 +6,25 @@ export interface CodexRequestUsage {
|
|
|
6
6
|
cachedInputTokens: number;
|
|
7
7
|
outputTokens: number;
|
|
8
8
|
}
|
|
9
|
-
|
|
9
|
+
export interface ClaudeRequestUsage {
|
|
10
|
+
model: string | undefined;
|
|
11
|
+
inputTokens: number;
|
|
12
|
+
cacheWrite5mTokens: number;
|
|
13
|
+
cacheWrite1hTokens: number;
|
|
14
|
+
cacheReadTokens: number;
|
|
15
|
+
outputTokens: number;
|
|
16
|
+
}
|
|
17
|
+
/** List prices for one model request, keyed by Codex model slug or Claude model id. */
|
|
10
18
|
export declare class CodexPrices {
|
|
11
19
|
private readonly entries;
|
|
12
20
|
constructor(entries: Record<string, unknown>);
|
|
13
21
|
/** Returns undefined for a model missing from the price list. */
|
|
14
22
|
requestCostUsd({ model, serviceTier, inputTokens, cachedInputTokens, outputTokens, }: CodexRequestUsage): number | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Returns undefined for a model missing from the price list.
|
|
25
|
+
* ponytail: ignores Anthropic's long-context rate, which LiteLLM lists only for some models.
|
|
26
|
+
*/
|
|
27
|
+
claudeRequestCostUsd({ model, inputTokens, cacheWrite5mTokens, cacheWrite1hTokens, cacheReadTokens, outputTokens, }: ClaudeRequestUsage): number | undefined;
|
|
15
28
|
}
|
|
16
29
|
export interface CodexPriceListOptions {
|
|
17
30
|
logger: Logger;
|
|
@@ -39,4 +52,5 @@ export declare class CodexPriceList {
|
|
|
39
52
|
private load;
|
|
40
53
|
private readSavedCopy;
|
|
41
54
|
}
|
|
55
|
+
export declare function getSharedCodexPriceList(logger: Logger): CodexPriceList;
|
|
42
56
|
//# sourceMappingURL=pricing.d.ts.map
|
|
@@ -13,7 +13,7 @@ const FETCH_TIMEOUT_MS = 15000;
|
|
|
13
13
|
const LONG_CONTEXT_THRESHOLD_TOKENS = 272000;
|
|
14
14
|
const LONG_CONTEXT_SUFFIX = "_above_272k_tokens";
|
|
15
15
|
const PRIORITY_SUFFIX = "_priority";
|
|
16
|
-
/**
|
|
16
|
+
/** List prices for one model request, keyed by Codex model slug or Claude model id. */
|
|
17
17
|
export class CodexPrices {
|
|
18
18
|
constructor(entries) {
|
|
19
19
|
this.entries = entries;
|
|
@@ -38,6 +38,31 @@ export class CodexPrices {
|
|
|
38
38
|
cachedInputTokens * cachedInputRate +
|
|
39
39
|
outputTokens * outputRate);
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Returns undefined for a model missing from the price list.
|
|
43
|
+
* ponytail: ignores Anthropic's long-context rate, which LiteLLM lists only for some models.
|
|
44
|
+
*/
|
|
45
|
+
claudeRequestCostUsd({ model, inputTokens, cacheWrite5mTokens, cacheWrite1hTokens, cacheReadTokens, outputTokens, }) {
|
|
46
|
+
const entry = model ? toRecord(this.entries[model]) : undefined;
|
|
47
|
+
if (!entry)
|
|
48
|
+
return undefined;
|
|
49
|
+
const inputRate = readNumber(entry.input_cost_per_token);
|
|
50
|
+
const outputRate = readNumber(entry.output_cost_per_token);
|
|
51
|
+
if (inputRate === undefined || outputRate === undefined)
|
|
52
|
+
return undefined;
|
|
53
|
+
const cacheWrite5mRate = readNumber(entry.cache_creation_input_token_cost) ?? inputRate;
|
|
54
|
+
const cacheWrite1hRate = readNumber(entry.cache_creation_input_token_cost_above_1hr) ?? cacheWrite5mRate;
|
|
55
|
+
const cacheReadRate = readNumber(entry.cache_read_input_token_cost) ?? inputRate;
|
|
56
|
+
// Anthropic counts cache reads and writes apart from input tokens.
|
|
57
|
+
return (inputTokens * inputRate +
|
|
58
|
+
cacheWrite5mTokens * cacheWrite5mRate +
|
|
59
|
+
cacheWrite1hTokens * cacheWrite1hRate +
|
|
60
|
+
cacheReadTokens * cacheReadRate +
|
|
61
|
+
outputTokens * outputRate);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function readNumber(value) {
|
|
65
|
+
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
41
66
|
}
|
|
42
67
|
// Prefer the most specific rate LiteLLM lists: a model without a long-context or priority variant
|
|
43
68
|
// bills that request at its plain rate.
|
|
@@ -123,6 +148,12 @@ export class CodexPriceList {
|
|
|
123
148
|
}
|
|
124
149
|
}
|
|
125
150
|
}
|
|
151
|
+
let sharedCodexPriceList;
|
|
152
|
+
// One price list per daemon, so every session that estimates cost shares one fetch.
|
|
153
|
+
export function getSharedCodexPriceList(logger) {
|
|
154
|
+
sharedCodexPriceList ?? (sharedCodexPriceList = new CodexPriceList({ logger }));
|
|
155
|
+
return sharedCodexPriceList;
|
|
156
|
+
}
|
|
126
157
|
function parsePriceList(text) {
|
|
127
158
|
const entries = toRecord(JSON.parse(text));
|
|
128
159
|
if (!entries) {
|
package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.d.ts
CHANGED
|
@@ -5,19 +5,16 @@ import type { CodexPrices } from "./pricing.js";
|
|
|
5
5
|
* Codex writes each request's token counts and the model of each turn to the rollout, and the file
|
|
6
6
|
* survives compaction, resume, and daemon restarts. Pricing request by request applies the
|
|
7
7
|
* long-context rate and mid-session model switches, which pricing the thread total cannot.
|
|
8
|
-
* Each read parses only the bytes appended since the previous read.
|
|
9
8
|
*/
|
|
10
9
|
export declare class CodexRolloutCost {
|
|
11
|
-
private readonly
|
|
12
|
-
private
|
|
13
|
-
private readonly decoder;
|
|
14
|
-
private pendingLine;
|
|
15
|
-
private model;
|
|
10
|
+
private readonly lines;
|
|
11
|
+
private currentModel;
|
|
16
12
|
private highestTotalTokens;
|
|
17
13
|
private costUsd;
|
|
18
14
|
private pricedRequests;
|
|
19
|
-
private queue;
|
|
20
15
|
constructor(filePath: string);
|
|
16
|
+
/** The model of the latest turn read so far. */
|
|
17
|
+
get model(): string | undefined;
|
|
21
18
|
/**
|
|
22
19
|
* Returns the session cost so far, or undefined when no request used a priced model.
|
|
23
20
|
* ponytail: prices every request at the current service tier; the rollout does not record it.
|
|
@@ -26,7 +23,6 @@ export declare class CodexRolloutCost {
|
|
|
26
23
|
prices: CodexPrices;
|
|
27
24
|
serviceTier: string | null;
|
|
28
25
|
}): Promise<number | undefined>;
|
|
29
|
-
private readAppended;
|
|
30
26
|
private applyLine;
|
|
31
27
|
}
|
|
32
28
|
//# sourceMappingURL=rollout-cost.d.ts.map
|
package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex/rollout-cost.js
CHANGED
|
@@ -1,62 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { StringDecoder } from "node:string_decoder";
|
|
1
|
+
import { AppendedLinesReader, parseRecordLine, readCount, toRecord, } from "../appended-lines-reader.js";
|
|
3
2
|
/**
|
|
4
3
|
* Sums the estimated cost of every model request recorded in a Codex rollout file.
|
|
5
4
|
*
|
|
6
5
|
* Codex writes each request's token counts and the model of each turn to the rollout, and the file
|
|
7
6
|
* survives compaction, resume, and daemon restarts. Pricing request by request applies the
|
|
8
7
|
* long-context rate and mid-session model switches, which pricing the thread total cannot.
|
|
9
|
-
* Each read parses only the bytes appended since the previous read.
|
|
10
8
|
*/
|
|
11
9
|
export class CodexRolloutCost {
|
|
12
10
|
constructor(filePath) {
|
|
13
|
-
this.filePath = filePath;
|
|
14
|
-
this.offset = 0;
|
|
15
|
-
this.decoder = new StringDecoder("utf8");
|
|
16
|
-
this.pendingLine = "";
|
|
17
11
|
this.highestTotalTokens = -1;
|
|
18
12
|
this.costUsd = 0;
|
|
19
13
|
this.pricedRequests = 0;
|
|
20
|
-
this.
|
|
14
|
+
this.lines = new AppendedLinesReader(filePath);
|
|
15
|
+
}
|
|
16
|
+
/** The model of the latest turn read so far. */
|
|
17
|
+
get model() {
|
|
18
|
+
return this.currentModel;
|
|
21
19
|
}
|
|
22
20
|
/**
|
|
23
21
|
* Returns the session cost so far, or undefined when no request used a priced model.
|
|
24
22
|
* ponytail: prices every request at the current service tier; the rollout does not record it.
|
|
25
23
|
*/
|
|
26
|
-
read({ prices, serviceTier, }) {
|
|
27
|
-
|
|
28
|
-
this.queue = result.catch(() => undefined);
|
|
29
|
-
return result;
|
|
30
|
-
}
|
|
31
|
-
async readAppended(prices, serviceTier) {
|
|
32
|
-
const handle = await fs.open(this.filePath, "r");
|
|
33
|
-
try {
|
|
34
|
-
const { size } = await handle.stat();
|
|
35
|
-
if (size > this.offset) {
|
|
36
|
-
const buffer = Buffer.alloc(size - this.offset);
|
|
37
|
-
const { bytesRead } = await handle.read(buffer, 0, buffer.length, this.offset);
|
|
38
|
-
this.offset += bytesRead;
|
|
39
|
-
const lines = (this.pendingLine + this.decoder.write(buffer.subarray(0, bytesRead))).split("\n");
|
|
40
|
-
this.pendingLine = lines.pop() ?? "";
|
|
41
|
-
for (const line of lines) {
|
|
42
|
-
this.applyLine(line, prices, serviceTier);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
finally {
|
|
47
|
-
await handle.close();
|
|
48
|
-
}
|
|
24
|
+
async read({ prices, serviceTier, }) {
|
|
25
|
+
await this.lines.read((line) => this.applyLine(line, prices, serviceTier));
|
|
49
26
|
return this.pricedRequests > 0 ? this.costUsd : undefined;
|
|
50
27
|
}
|
|
51
28
|
applyLine(line, prices, serviceTier) {
|
|
52
29
|
// Skip the bulk of the rollout (messages, tool output) without parsing it.
|
|
53
30
|
if (!line.includes('"turn_context"') && !line.includes('"token_count"'))
|
|
54
31
|
return;
|
|
55
|
-
const entry =
|
|
32
|
+
const entry = parseRecordLine(line);
|
|
56
33
|
const payload = toRecord(entry?.payload);
|
|
57
34
|
if (entry?.type === "turn_context") {
|
|
58
35
|
if (typeof payload?.model === "string")
|
|
59
|
-
this.
|
|
36
|
+
this.currentModel = payload.model;
|
|
60
37
|
return;
|
|
61
38
|
}
|
|
62
39
|
if (payload?.type !== "token_count")
|
|
@@ -71,7 +48,7 @@ export class CodexRolloutCost {
|
|
|
71
48
|
return;
|
|
72
49
|
this.highestTotalTokens = totalTokens;
|
|
73
50
|
const cost = prices.requestCostUsd({
|
|
74
|
-
model: this.
|
|
51
|
+
model: this.currentModel,
|
|
75
52
|
serviceTier,
|
|
76
53
|
inputTokens: readCount(last.input_tokens),
|
|
77
54
|
cachedInputTokens: readCount(last.cached_input_tokens),
|
|
@@ -83,21 +60,4 @@ export class CodexRolloutCost {
|
|
|
83
60
|
this.pricedRequests += 1;
|
|
84
61
|
}
|
|
85
62
|
}
|
|
86
|
-
function parseRecord(line) {
|
|
87
|
-
try {
|
|
88
|
-
return toRecord(JSON.parse(line));
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
// A torn or foreign line only drops that line from an estimate.
|
|
92
|
-
return undefined;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
function toRecord(value) {
|
|
96
|
-
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
97
|
-
? value
|
|
98
|
-
: undefined;
|
|
99
|
-
}
|
|
100
|
-
function readCount(value) {
|
|
101
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
102
|
-
}
|
|
103
63
|
//# sourceMappingURL=rollout-cost.js.map
|
package/node_modules/@getpaseo/server/dist/server/server/agent/providers/codex-app-server-agent.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { type AgentCapabilityFlags, type AgentClient, type AgentCreateSessionOpt
|
|
|
2
2
|
import type { Logger } from "pino";
|
|
3
3
|
import type { ChildProcessWithoutNullStreams } from "node:child_process";
|
|
4
4
|
import { Dirent } from "node:fs";
|
|
5
|
-
import { CodexPriceList } from "./codex/pricing.js";
|
|
5
|
+
import { type CodexPriceList } from "./codex/pricing.js";
|
|
6
6
|
import { type ProviderRuntimeSettings } from "../provider-launch-config.js";
|
|
7
7
|
import { type CodexThreadForkParams, type CodexThreadForkResponse, type CodexThreadRollbackParams, type CodexThreadRollbackResponse, type CodexAppServerTraceContext } from "./codex/app-server-transport.js";
|
|
8
8
|
import type { WorkspaceGitService } from "../../workspace-git-service.js";
|
|
@@ -173,6 +173,7 @@ export declare class CodexAppServerAgentSession implements AgentSession {
|
|
|
173
173
|
private emittedProviderSubagentUserMessageKeys;
|
|
174
174
|
private subAgentCallsByCallId;
|
|
175
175
|
private subAgentCallIdByChildThreadId;
|
|
176
|
+
private subAgentUsageByThreadId;
|
|
176
177
|
private pendingSubAgentNotificationsByThreadId;
|
|
177
178
|
private warnedUnknownNotificationMethods;
|
|
178
179
|
private warnedInvalidNotificationPayloads;
|
|
@@ -336,6 +337,11 @@ export declare class CodexAppServerAgentSession implements AgentSession {
|
|
|
336
337
|
private resetTurnTrackingState;
|
|
337
338
|
private handlePlanUpdatedNotification;
|
|
338
339
|
private handleTokenUsageUpdatedNotification;
|
|
340
|
+
private handleSubAgentTokenUsage;
|
|
341
|
+
private refreshSubAgentCost;
|
|
342
|
+
private emitSubAgentSubtitle;
|
|
343
|
+
private subagentCostRollup;
|
|
344
|
+
private refreshCostPresentation;
|
|
339
345
|
private refreshRolloutCost;
|
|
340
346
|
private applyCostEstimate;
|
|
341
347
|
private openRolloutCost;
|