@runuai/host 0.8.27 → 0.8.28
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/lib/agents/claude.ts +31 -2
- package/lib/agents/types.ts +21 -2
- package/lib/orchestrator.ts +1 -0
- package/package.json +1 -1
- package/src/protocol.ts +10 -0
package/lib/agents/claude.ts
CHANGED
|
@@ -28,6 +28,7 @@ import type {
|
|
|
28
28
|
AgentEventHandler,
|
|
29
29
|
AgentKind,
|
|
30
30
|
AgentSession,
|
|
31
|
+
AgentUsage,
|
|
31
32
|
RosterAgent,
|
|
32
33
|
} from "./types";
|
|
33
34
|
|
|
@@ -59,6 +60,32 @@ function isObj(v: unknown): v is Record<string, unknown> {
|
|
|
59
60
|
return typeof v === "object" && v !== null;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
function num(v: unknown): number | undefined {
|
|
64
|
+
return typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Token + cost accounting from a Claude `result` line. Claude Code reports the
|
|
69
|
+
* exact `total_cost_usd` (no estimation needed) plus a token `usage` breakdown
|
|
70
|
+
* and per-model `modelUsage`. The billed model is the single modelUsage key
|
|
71
|
+
* (or, on a multi-model turn, joined).
|
|
72
|
+
*/
|
|
73
|
+
function claudeUsage(json: Record<string, unknown>): AgentUsage | undefined {
|
|
74
|
+
const u = isObj(json.usage) ? json.usage : {};
|
|
75
|
+
const cost = num(json.total_cost_usd);
|
|
76
|
+
const models = isObj(json.modelUsage) ? Object.keys(json.modelUsage) : [];
|
|
77
|
+
const usage: AgentUsage = {
|
|
78
|
+
model: models.length ? models.join(", ") : undefined,
|
|
79
|
+
inputTokens: num(u.input_tokens),
|
|
80
|
+
outputTokens: num(u.output_tokens),
|
|
81
|
+
cacheReadTokens: num(u.cache_read_input_tokens),
|
|
82
|
+
cacheCreateTokens: num(u.cache_creation_input_tokens),
|
|
83
|
+
costUsd: cost,
|
|
84
|
+
};
|
|
85
|
+
// Nothing usable reported → omit rather than send an empty object.
|
|
86
|
+
return Object.values(usage).some((v) => v !== undefined) ? usage : undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
62
89
|
/**
|
|
63
90
|
* Map one stream-json stdout line to zero or more AgentEvents.
|
|
64
91
|
*
|
|
@@ -119,15 +146,17 @@ export function mapClaudeLine(raw: string): AgentEvent[] {
|
|
|
119
146
|
// --- turn result ------------------------------------------------------
|
|
120
147
|
if (type === "result") {
|
|
121
148
|
const text = typeof json.result === "string" ? json.result : "";
|
|
149
|
+
const usage = claudeUsage(json);
|
|
122
150
|
if (json.is_error === true) {
|
|
151
|
+
// An errored turn still cost tokens — meter it.
|
|
123
152
|
return [
|
|
124
153
|
{ type: "error", message: text || "claude returned an error" },
|
|
125
|
-
{ type: "turn_complete" },
|
|
154
|
+
{ type: "turn_complete", usage },
|
|
126
155
|
];
|
|
127
156
|
}
|
|
128
157
|
return [
|
|
129
158
|
{ type: "message_complete", text },
|
|
130
|
-
{ type: "turn_complete" },
|
|
159
|
+
{ type: "turn_complete", usage },
|
|
131
160
|
];
|
|
132
161
|
}
|
|
133
162
|
|
package/lib/agents/types.ts
CHANGED
|
@@ -82,6 +82,24 @@ export function parseRoster(raw: string): Roster {
|
|
|
82
82
|
// these to `uai_messages` and streams them to the browser.
|
|
83
83
|
// ---------------------------------------------------------------------------
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Token + cost accounting for one turn, extracted from the agent CLI's result
|
|
87
|
+
* envelope where it reports it (Claude Code gives `usage` + `total_cost_usd`
|
|
88
|
+
* directly). Powers per-task cost visibility for self-hosted users and the
|
|
89
|
+
* metering pipeline for managed Uai-provided AI. All fields optional — an
|
|
90
|
+
* engine that doesn't report a dimension omits it.
|
|
91
|
+
*/
|
|
92
|
+
export interface AgentUsage {
|
|
93
|
+
/** Model the CLI actually billed (may differ from the configured model, e.g. a sub-agent). */
|
|
94
|
+
model?: string;
|
|
95
|
+
inputTokens?: number;
|
|
96
|
+
outputTokens?: number;
|
|
97
|
+
cacheReadTokens?: number;
|
|
98
|
+
cacheCreateTokens?: number;
|
|
99
|
+
/** Total USD for the turn, as reported by the CLI (authoritative when present). */
|
|
100
|
+
costUsd?: number;
|
|
101
|
+
}
|
|
102
|
+
|
|
85
103
|
export type AgentEvent =
|
|
86
104
|
/** A chunk of streaming assistant text. Appended to the in-progress message. */
|
|
87
105
|
| { type: "message_delta"; text: string }
|
|
@@ -93,8 +111,9 @@ export type AgentEvent =
|
|
|
93
111
|
| { type: "permission_request"; id: string; title: string; detail: string }
|
|
94
112
|
/** The agent addressed another agent — uai routes this as a peer message. */
|
|
95
113
|
| { type: "peer_message"; toAgentId: string; text: string }
|
|
96
|
-
/** The turn (one request → response cycle) is done; agent is idle.
|
|
97
|
-
|
|
114
|
+
/** The turn (one request → response cycle) is done; agent is idle.
|
|
115
|
+
* `usage` carries this turn's token/cost accounting when the CLI reports it. */
|
|
116
|
+
| { type: "turn_complete"; usage?: AgentUsage }
|
|
98
117
|
/** A recoverable error surfaced by the agent. */
|
|
99
118
|
| { type: "error"; message: string }
|
|
100
119
|
/** The underlying process exited. */
|
package/lib/orchestrator.ts
CHANGED
package/package.json
CHANGED
package/src/protocol.ts
CHANGED
|
@@ -580,6 +580,16 @@ export type HostEvent =
|
|
|
580
580
|
taskId: string;
|
|
581
581
|
agentId: string;
|
|
582
582
|
aborted?: boolean;
|
|
583
|
+
/** Token/cost accounting for the turn, when the engine reports it
|
|
584
|
+
* (ADR-071 usage metering — powers per-task cost + managed AI billing). */
|
|
585
|
+
usage?: {
|
|
586
|
+
model?: string;
|
|
587
|
+
inputTokens?: number;
|
|
588
|
+
outputTokens?: number;
|
|
589
|
+
cacheReadTokens?: number;
|
|
590
|
+
cacheCreateTokens?: number;
|
|
591
|
+
costUsd?: number;
|
|
592
|
+
};
|
|
583
593
|
}
|
|
584
594
|
| {
|
|
585
595
|
kind: "agent.tool_call";
|