@agent-relay/factory 0.1.56 → 0.1.57
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/README.md +9 -1
- package/dist/cost/index.d.ts +3 -0
- package/dist/cost/index.d.ts.map +1 -0
- package/dist/cost/index.js +3 -0
- package/dist/cost/index.js.map +1 -0
- package/dist/cost/ledger.d.ts +69 -0
- package/dist/cost/ledger.d.ts.map +1 -0
- package/dist/cost/ledger.js +162 -0
- package/dist/cost/ledger.js.map +1 -0
- package/dist/cost/pricing.d.ts +18 -0
- package/dist/cost/pricing.d.ts.map +1 -0
- package/dist/cost/pricing.js +54 -0
- package/dist/cost/pricing.js.map +1 -0
- package/dist/fleet/internal-fleet-client.d.ts +3 -1
- package/dist/fleet/internal-fleet-client.d.ts.map +1 -1
- package/dist/fleet/internal-fleet-client.js +81 -0
- package/dist/fleet/internal-fleet-client.js.map +1 -1
- package/dist/fleet/relay-fleet-client.d.ts +3 -1
- package/dist/fleet/relay-fleet-client.d.ts.map +1 -1
- package/dist/fleet/relay-fleet-client.js +48 -0
- package/dist/fleet/relay-fleet-client.js.map +1 -1
- package/dist/hosted/index.d.ts +1 -1
- package/dist/hosted/index.d.ts.map +1 -1
- package/dist/hosted/index.js +1 -1
- package/dist/hosted/index.js.map +1 -1
- package/dist/hosted/orchestrator.d.ts +1 -0
- package/dist/hosted/orchestrator.d.ts.map +1 -1
- package/dist/hosted/orchestrator.js +190 -1
- package/dist/hosted/orchestrator.js.map +1 -1
- package/dist/hosted/types.d.ts +4 -0
- package/dist/hosted/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/observability/events.d.ts +683 -15
- package/dist/observability/events.d.ts.map +1 -1
- package/dist/observability/events.js +41 -0
- package/dist/observability/events.js.map +1 -1
- package/dist/orchestrator/factory.d.ts.map +1 -1
- package/dist/orchestrator/factory.js +311 -33
- package/dist/orchestrator/factory.js.map +1 -1
- package/dist/ports/fleet.d.ts +11 -0
- package/dist/ports/fleet.d.ts.map +1 -1
- package/dist/ports/index.d.ts +1 -1
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/ports/state.d.ts +21 -5
- package/dist/ports/state.d.ts.map +1 -1
- package/dist/telemetry.d.ts +9 -0
- package/dist/telemetry.d.ts.map +1 -0
- package/dist/telemetry.js +8 -0
- package/dist/telemetry.js.map +1 -0
- package/dist/testing/fakes.d.ts +4 -1
- package/dist/testing/fakes.d.ts.map +1 -1
- package/dist/testing/fakes.js +12 -0
- package/dist/testing/fakes.js.map +1 -1
- package/dist/triage/schema.d.ts +42 -42
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -434,12 +434,20 @@ import {
|
|
|
434
434
|
const state = new DurableObjectHostedFactoryStateStore(durableObjectState.storage)
|
|
435
435
|
const factory = createHostedFactory(
|
|
436
436
|
{ workspaceId, ownerId: isolateId, config },
|
|
437
|
-
{ state, discovery, fleet, completions, mergeGate, writeback },
|
|
437
|
+
{ state, discovery, fleet, completions, mergeGate, writeback, reporter },
|
|
438
438
|
)
|
|
439
439
|
|
|
440
440
|
await factory.runOnce() // invoke from cron/alarm and safe webhook wakeups
|
|
441
441
|
```
|
|
442
442
|
|
|
443
|
+
The optional `reporter` implements the canonical `FactoryEventReporter`.
|
|
444
|
+
Hosted runs persist a deterministic run ID per workspace and issue, then emit
|
|
445
|
+
lifecycle events only after the corresponding fenced state write. Worker hosts
|
|
446
|
+
that only need the Factory-owned wire schema, event creator, and reporter types
|
|
447
|
+
should import `@agent-relay/factory/telemetry`; unlike the broader
|
|
448
|
+
`@agent-relay/factory/observability` surface, it does not export the
|
|
449
|
+
filesystem-backed outbox or instance identity helpers.
|
|
450
|
+
|
|
443
451
|
The Durable Object adapter stores each workspace independently and performs
|
|
444
452
|
lease claims plus lifecycle writes in storage transactions. Every mutation is
|
|
445
453
|
checked against the current owner and monotonically increasing lease epoch; an
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cost/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cost/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export declare const COST_LEDGER_ROLES: readonly ["implementer", "reviewer", "babysitter", "triage", "workflow"];
|
|
2
|
+
export type CostLedgerRole = (typeof COST_LEDGER_ROLES)[number];
|
|
3
|
+
/** Matches the closed cloud-event bound for one role's model breakdown. */
|
|
4
|
+
export declare const MAX_RUN_COST_MODELS_PER_ROLE = 32;
|
|
5
|
+
export declare const RUN_COST_OTHER_MODELS_ID = "factory/other-models";
|
|
6
|
+
export interface CostLedgerRecord {
|
|
7
|
+
runId: string;
|
|
8
|
+
role: CostLedgerRole;
|
|
9
|
+
model: string;
|
|
10
|
+
inputTokens: number | null;
|
|
11
|
+
outputTokens: number | null;
|
|
12
|
+
usd: number | null;
|
|
13
|
+
}
|
|
14
|
+
export type CostLedgerRecordInput = Omit<CostLedgerRecord, 'usd'>;
|
|
15
|
+
export interface CostModelBreakdown {
|
|
16
|
+
model: string;
|
|
17
|
+
inputTokens: number | null;
|
|
18
|
+
outputTokens: number | null;
|
|
19
|
+
usd: number | null;
|
|
20
|
+
}
|
|
21
|
+
export interface CostRoleBreakdown {
|
|
22
|
+
role: CostLedgerRole;
|
|
23
|
+
inputTokens: number | null;
|
|
24
|
+
outputTokens: number | null;
|
|
25
|
+
usd: number | null;
|
|
26
|
+
byModel: CostModelBreakdown[];
|
|
27
|
+
}
|
|
28
|
+
export interface RunCostTotal {
|
|
29
|
+
runId: string;
|
|
30
|
+
inputTokens: number | null;
|
|
31
|
+
outputTokens: number | null;
|
|
32
|
+
usd: number | null;
|
|
33
|
+
byRole: CostRoleBreakdown[];
|
|
34
|
+
}
|
|
35
|
+
export interface UnpricedModelCostRecord extends CostLedgerRecord {
|
|
36
|
+
usd: null;
|
|
37
|
+
}
|
|
38
|
+
export type UnpricedModelListener = (record: UnpricedModelCostRecord) => void;
|
|
39
|
+
export interface CostLedgerRecordOptions {
|
|
40
|
+
/**
|
|
41
|
+
* Deterministic logical identity for cumulative runtime updates. Factory uses
|
|
42
|
+
* run id + agent name, so a later usage report replaces rather than doubles
|
|
43
|
+
* the same spawned agent.
|
|
44
|
+
*/
|
|
45
|
+
entryId?: string;
|
|
46
|
+
/** Rehydrating durable usage must not emit a duplicate unpriced-model notice. */
|
|
47
|
+
notifyUnpriced?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* In-memory accounting seam for one Factory process. Durable run records retain
|
|
51
|
+
* the completion aggregate; this ledger keeps the detailed live attribution.
|
|
52
|
+
*/
|
|
53
|
+
export declare class CostLedger {
|
|
54
|
+
#private;
|
|
55
|
+
record(input: CostLedgerRecordInput, options?: CostLedgerRecordOptions): CostLedgerRecord;
|
|
56
|
+
hasEntry(entryId: string): boolean;
|
|
57
|
+
getRunRecords(runId: string): CostLedgerRecord[];
|
|
58
|
+
getRunTotal(runId: string): RunCostTotal;
|
|
59
|
+
getRunByRole(runId: string): CostRoleBreakdown[];
|
|
60
|
+
onUnpricedModel(listener: UnpricedModelListener): () => void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Produces the deterministic, privacy-safe shape persisted and emitted when a
|
|
64
|
+
* run completes. The detailed ledger remains available through
|
|
65
|
+
* getRunRecords(); excess model buckets are folded into one aggregate instead
|
|
66
|
+
* of making the bounded observability event invalid.
|
|
67
|
+
*/
|
|
68
|
+
export declare const boundedRunCostTotal: (total: RunCostTotal) => RunCostTotal;
|
|
69
|
+
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/cost/ledger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB,0EAMpB,CAAA;AAEV,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAA;AAE/D,2EAA2E;AAC3E,eAAO,MAAM,4BAA4B,KAAK,CAAA;AAC9C,eAAO,MAAM,wBAAwB,yBAAyB,CAAA;AAE9D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,cAAc,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,MAAM,qBAAqB,GAAG,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAA;AAEjE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,cAAc,CAAA;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,OAAO,EAAE,kBAAkB,EAAE,CAAA;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAClB,MAAM,EAAE,iBAAiB,EAAE,CAAA;CAC5B;AAED,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,GAAG,EAAE,IAAI,CAAA;CACV;AAED,MAAM,MAAM,qBAAqB,GAAG,CAAC,MAAM,EAAE,uBAAuB,KAAK,IAAI,CAAA;AAE7E,MAAM,WAAW,uBAAuB;IACtC;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,iFAAiF;IACjF,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED;;;GAGG;AACH,qBAAa,UAAU;;IAMrB,MAAM,CAAC,KAAK,EAAE,qBAAqB,EAAE,OAAO,GAAE,uBAA4B,GAAG,gBAAgB;IAc7F,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIlC,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,EAAE;IAMhD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY;IAWxC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,EAAE;IAkBhD,eAAe,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,IAAI;CAiB7D;AAiBD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,YAAY,KAAG,YAKxD,CAAA"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { estimateCostUsd, hasModelPricing, roundUsd } from './pricing.js';
|
|
2
|
+
export const COST_LEDGER_ROLES = [
|
|
3
|
+
'implementer',
|
|
4
|
+
'reviewer',
|
|
5
|
+
'babysitter',
|
|
6
|
+
'triage',
|
|
7
|
+
'workflow',
|
|
8
|
+
];
|
|
9
|
+
/** Matches the closed cloud-event bound for one role's model breakdown. */
|
|
10
|
+
export const MAX_RUN_COST_MODELS_PER_ROLE = 32;
|
|
11
|
+
export const RUN_COST_OTHER_MODELS_ID = 'factory/other-models';
|
|
12
|
+
/**
|
|
13
|
+
* In-memory accounting seam for one Factory process. Durable run records retain
|
|
14
|
+
* the completion aggregate; this ledger keeps the detailed live attribution.
|
|
15
|
+
*/
|
|
16
|
+
export class CostLedger {
|
|
17
|
+
#records = new Map();
|
|
18
|
+
#unpricedListeners = new Set();
|
|
19
|
+
#reportedUnpricedModels = new Set();
|
|
20
|
+
#nextEntry = 0;
|
|
21
|
+
record(input, options = {}) {
|
|
22
|
+
const normalized = normalizeRecordInput(input);
|
|
23
|
+
const unpriced = !hasModelPricing(normalized.model);
|
|
24
|
+
const usd = normalized.inputTokens === null || normalized.outputTokens === null
|
|
25
|
+
? null
|
|
26
|
+
: estimateCostUsd(normalized.model, normalized.inputTokens, normalized.outputTokens);
|
|
27
|
+
const record = { ...normalized, usd };
|
|
28
|
+
const entryId = options.entryId ?? `entry:${this.#nextEntry++}`;
|
|
29
|
+
this.#records.set(entryId, record);
|
|
30
|
+
if (unpriced && options.notifyUnpriced !== false)
|
|
31
|
+
this.#emitUnpriced(record);
|
|
32
|
+
return structuredClone(record);
|
|
33
|
+
}
|
|
34
|
+
hasEntry(entryId) {
|
|
35
|
+
return this.#records.has(entryId);
|
|
36
|
+
}
|
|
37
|
+
getRunRecords(runId) {
|
|
38
|
+
return [...this.#records.values()]
|
|
39
|
+
.filter((record) => record.runId === runId)
|
|
40
|
+
.map((record) => structuredClone(record));
|
|
41
|
+
}
|
|
42
|
+
getRunTotal(runId) {
|
|
43
|
+
const byRole = this.getRunByRole(runId);
|
|
44
|
+
return {
|
|
45
|
+
runId,
|
|
46
|
+
inputTokens: nullableSum(byRole.map((entry) => entry.inputTokens)),
|
|
47
|
+
outputTokens: nullableSum(byRole.map((entry) => entry.outputTokens)),
|
|
48
|
+
usd: nullableUsdSum(byRole.map((entry) => entry.usd)),
|
|
49
|
+
byRole,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
getRunByRole(runId) {
|
|
53
|
+
const records = this.getRunRecords(runId);
|
|
54
|
+
const roles = new Map();
|
|
55
|
+
for (const record of records) {
|
|
56
|
+
const current = roles.get(record.role) ?? [];
|
|
57
|
+
current.push(record);
|
|
58
|
+
roles.set(record.role, current);
|
|
59
|
+
}
|
|
60
|
+
return [...roles].map(([role, roleRecords]) => ({
|
|
61
|
+
role,
|
|
62
|
+
inputTokens: nullableSum(roleRecords.map((record) => record.inputTokens)),
|
|
63
|
+
outputTokens: nullableSum(roleRecords.map((record) => record.outputTokens)),
|
|
64
|
+
usd: nullableUsdSum(roleRecords.map((record) => record.usd)),
|
|
65
|
+
byModel: modelBreakdowns(roleRecords),
|
|
66
|
+
})).sort((left, right) => roleIndex(left.role) - roleIndex(right.role));
|
|
67
|
+
}
|
|
68
|
+
onUnpricedModel(listener) {
|
|
69
|
+
this.#unpricedListeners.add(listener);
|
|
70
|
+
return () => this.#unpricedListeners.delete(listener);
|
|
71
|
+
}
|
|
72
|
+
#emitUnpriced(record) {
|
|
73
|
+
const key = `${record.runId}\0${record.model}`;
|
|
74
|
+
if (this.#reportedUnpricedModels.has(key))
|
|
75
|
+
return;
|
|
76
|
+
this.#reportedUnpricedModels.add(key);
|
|
77
|
+
for (const listener of this.#unpricedListeners) {
|
|
78
|
+
try {
|
|
79
|
+
listener(structuredClone(record));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Cost accounting is an observability aid, never a run dependency.
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const modelBreakdowns = (records) => {
|
|
88
|
+
const models = new Map();
|
|
89
|
+
for (const record of records) {
|
|
90
|
+
const current = models.get(record.model) ?? [];
|
|
91
|
+
current.push(record);
|
|
92
|
+
models.set(record.model, current);
|
|
93
|
+
}
|
|
94
|
+
return [...models].map(([model, modelRecords]) => ({
|
|
95
|
+
model,
|
|
96
|
+
inputTokens: nullableSum(modelRecords.map((record) => record.inputTokens)),
|
|
97
|
+
outputTokens: nullableSum(modelRecords.map((record) => record.outputTokens)),
|
|
98
|
+
usd: nullableUsdSum(modelRecords.map((record) => record.usd)),
|
|
99
|
+
})).sort((left, right) => compareModelIds(left.model, right.model));
|
|
100
|
+
};
|
|
101
|
+
/**
|
|
102
|
+
* Produces the deterministic, privacy-safe shape persisted and emitted when a
|
|
103
|
+
* run completes. The detailed ledger remains available through
|
|
104
|
+
* getRunRecords(); excess model buckets are folded into one aggregate instead
|
|
105
|
+
* of making the bounded observability event invalid.
|
|
106
|
+
*/
|
|
107
|
+
export const boundedRunCostTotal = (total) => ({
|
|
108
|
+
...structuredClone(total),
|
|
109
|
+
byRole: total.byRole
|
|
110
|
+
.map((role) => ({ ...structuredClone(role), byModel: boundedModels(role.byModel) }))
|
|
111
|
+
.sort((left, right) => roleIndex(left.role) - roleIndex(right.role)),
|
|
112
|
+
});
|
|
113
|
+
const boundedModels = (models) => {
|
|
114
|
+
const sorted = structuredClone(models).sort((left, right) => compareModelIds(left.model, right.model));
|
|
115
|
+
if (sorted.length <= MAX_RUN_COST_MODELS_PER_ROLE)
|
|
116
|
+
return sorted;
|
|
117
|
+
const candidates = sorted.filter((entry) => entry.model !== RUN_COST_OTHER_MODELS_ID);
|
|
118
|
+
const overflow = [
|
|
119
|
+
...sorted.filter((entry) => entry.model === RUN_COST_OTHER_MODELS_ID),
|
|
120
|
+
...candidates.slice(MAX_RUN_COST_MODELS_PER_ROLE - 1),
|
|
121
|
+
];
|
|
122
|
+
return [
|
|
123
|
+
...candidates.slice(0, MAX_RUN_COST_MODELS_PER_ROLE - 1),
|
|
124
|
+
{
|
|
125
|
+
model: RUN_COST_OTHER_MODELS_ID,
|
|
126
|
+
inputTokens: nullableSum(overflow.map((entry) => entry.inputTokens)),
|
|
127
|
+
outputTokens: nullableSum(overflow.map((entry) => entry.outputTokens)),
|
|
128
|
+
usd: nullableUsdSum(overflow.map((entry) => entry.usd)),
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
};
|
|
132
|
+
const roleIndex = (role) => COST_LEDGER_ROLES.indexOf(role);
|
|
133
|
+
const compareModelIds = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
134
|
+
const normalizeRecordInput = (input) => ({
|
|
135
|
+
runId: boundedIdentifier(input.runId, 'unknown-run'),
|
|
136
|
+
role: COST_LEDGER_ROLES.includes(input.role) ? input.role : 'triage',
|
|
137
|
+
model: boundedModelId(input.model),
|
|
138
|
+
inputTokens: tokenCount(input.inputTokens),
|
|
139
|
+
outputTokens: tokenCount(input.outputTokens),
|
|
140
|
+
});
|
|
141
|
+
const boundedIdentifier = (value, fallback) => {
|
|
142
|
+
const normalized = typeof value === 'string' ? value.trim() : '';
|
|
143
|
+
return (normalized || fallback).slice(0, 256);
|
|
144
|
+
};
|
|
145
|
+
const boundedModelId = (value) => {
|
|
146
|
+
const normalized = boundedIdentifier(value, 'unknown');
|
|
147
|
+
return /^[a-zA-Z0-9][a-zA-Z0-9._:/-]{0,119}$/u.test(normalized)
|
|
148
|
+
? normalized
|
|
149
|
+
: 'unknown';
|
|
150
|
+
};
|
|
151
|
+
const tokenCount = (value) => value !== null && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
152
|
+
const nullableSum = (values) => {
|
|
153
|
+
const known = values.filter((value) => value !== null);
|
|
154
|
+
if (known.length === 0)
|
|
155
|
+
return null;
|
|
156
|
+
return known.reduce((sum, value) => sum >= Number.MAX_SAFE_INTEGER - value ? Number.MAX_SAFE_INTEGER : sum + value, 0);
|
|
157
|
+
};
|
|
158
|
+
const nullableUsdSum = (values) => {
|
|
159
|
+
const total = nullableSum(values);
|
|
160
|
+
return total === null ? null : roundUsd(total);
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../src/cost/ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface ModelPricing {
|
|
2
|
+
costPer1MInput: number;
|
|
3
|
+
costPer1MOutput: number;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Factory's metered model catalog. Keep the shape aligned with NightCTO's
|
|
7
|
+
* openrouter-client model ladder so model-routing work can share prices later.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MODEL_PRICING: Readonly<Record<string, ModelPricing>>;
|
|
10
|
+
export interface EstimateCostUsdOptions {
|
|
11
|
+
/** A bounded accounting notice; callback failures are deliberately ignored. */
|
|
12
|
+
onUnpricedModel?: (model: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export declare function hasModelPricing(model: string): boolean;
|
|
15
|
+
/** Estimate a metered model cost without ever making accounting control flow fatal. */
|
|
16
|
+
export declare function estimateCostUsd(model: string, inputTokens: number, outputTokens: number, options?: EstimateCostUsdOptions): number | null;
|
|
17
|
+
export declare const roundUsd: (value: number) => number;
|
|
18
|
+
//# sourceMappingURL=pricing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.d.ts","sourceRoot":"","sources":["../../src/cost/pricing.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;CACxB;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAyB/D,CAAA;AAEF,MAAM,WAAW,sBAAsB;IACrC,+EAA+E;IAC/E,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CAC1C;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,sBAA2B,GACnC,MAAM,GAAG,IAAI,CAef;AAED,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,MAAkC,CAAA"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory's metered model catalog. Keep the shape aligned with NightCTO's
|
|
3
|
+
* openrouter-client model ladder so model-routing work can share prices later.
|
|
4
|
+
*/
|
|
5
|
+
export const MODEL_PRICING = Object.freeze({
|
|
6
|
+
'deepseek/deepseek-chat-v3-0324': {
|
|
7
|
+
costPer1MInput: 0.27,
|
|
8
|
+
costPer1MOutput: 1.1,
|
|
9
|
+
},
|
|
10
|
+
'openai/gpt-4o-mini': {
|
|
11
|
+
costPer1MInput: 0.15,
|
|
12
|
+
costPer1MOutput: 0.6,
|
|
13
|
+
},
|
|
14
|
+
'anthropic/claude-haiku-4.5': {
|
|
15
|
+
costPer1MInput: 1,
|
|
16
|
+
costPer1MOutput: 5,
|
|
17
|
+
},
|
|
18
|
+
'anthropic/claude-sonnet-4.5': {
|
|
19
|
+
costPer1MInput: 3,
|
|
20
|
+
costPer1MOutput: 15,
|
|
21
|
+
},
|
|
22
|
+
'openai/gpt-5.4': {
|
|
23
|
+
costPer1MInput: 5,
|
|
24
|
+
costPer1MOutput: 15,
|
|
25
|
+
},
|
|
26
|
+
'openai/gpt-5.4-pro': {
|
|
27
|
+
costPer1MInput: 15,
|
|
28
|
+
costPer1MOutput: 60,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
export function hasModelPricing(model) {
|
|
32
|
+
return Object.prototype.hasOwnProperty.call(MODEL_PRICING, model);
|
|
33
|
+
}
|
|
34
|
+
/** Estimate a metered model cost without ever making accounting control flow fatal. */
|
|
35
|
+
export function estimateCostUsd(model, inputTokens, outputTokens, options = {}) {
|
|
36
|
+
if (!hasModelPricing(model)) {
|
|
37
|
+
try {
|
|
38
|
+
options.onUnpricedModel?.(model);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// Observability and accounting callbacks must never affect a run.
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const pricing = MODEL_PRICING[model];
|
|
46
|
+
if (!validTokenCount(inputTokens) || !validTokenCount(outputTokens))
|
|
47
|
+
return null;
|
|
48
|
+
const inputCost = (inputTokens / 1_000_000) * pricing.costPer1MInput;
|
|
49
|
+
const outputCost = (outputTokens / 1_000_000) * pricing.costPer1MOutput;
|
|
50
|
+
return roundUsd(inputCost + outputCost);
|
|
51
|
+
}
|
|
52
|
+
export const roundUsd = (value) => Number(value.toFixed(6));
|
|
53
|
+
const validTokenCount = (value) => Number.isSafeInteger(value) && value >= 0;
|
|
54
|
+
//# sourceMappingURL=pricing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../../src/cost/pricing.ts"],"names":[],"mappings":"AAKA;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAA2C,MAAM,CAAC,MAAM,CAAC;IACjF,gCAAgC,EAAE;QAChC,cAAc,EAAE,IAAI;QACpB,eAAe,EAAE,GAAG;KACrB;IACD,oBAAoB,EAAE;QACpB,cAAc,EAAE,IAAI;QACpB,eAAe,EAAE,GAAG;KACrB;IACD,4BAA4B,EAAE;QAC5B,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,CAAC;KACnB;IACD,6BAA6B,EAAE;QAC7B,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,EAAE;KACpB;IACD,gBAAgB,EAAE;QAChB,cAAc,EAAE,CAAC;QACjB,eAAe,EAAE,EAAE;KACpB;IACD,oBAAoB,EAAE;QACpB,cAAc,EAAE,EAAE;QAClB,eAAe,EAAE,EAAE;KACpB;CACF,CAAC,CAAA;AAOF,MAAM,UAAU,eAAe,CAAC,KAAa;IAC3C,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAA;AACnE,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,eAAe,CAC7B,KAAa,EACb,WAAmB,EACnB,YAAoB,EACpB,UAAkC,EAAE;IAEpC,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,CAAC,eAAe,EAAE,CAAC,KAAK,CAAC,CAAA;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,kEAAkE;QACpE,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,OAAO,GAAG,aAAa,CAAC,KAAK,CAAE,CAAA;IACrC,IAAI,CAAC,eAAe,CAAC,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAA;IAEhF,MAAM,SAAS,GAAG,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,cAAc,CAAA;IACpE,MAAM,UAAU,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,eAAe,CAAA;IACvE,OAAO,QAAQ,CAAC,SAAS,GAAG,UAAU,CAAC,CAAA;AACzC,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAE3E,MAAM,eAAe,GAAG,CAAC,KAAa,EAAW,EAAE,CACjD,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BrokerEvent, ListAgent, SendMessageInput, SpawnPtyInput } from '@agent-relay/harness-driver';
|
|
2
2
|
import type { PreviewConfig } from '../config/schema.js';
|
|
3
|
-
import type { AgentMessage, AgentPidResolution, Capability, FleetClient, FleetTrackedAgent, PreviewReference, PreviewStartInput, PreviewSweepInput, PreviewSweepResult, RosterEntry, SendInput, SpawnInput, SpawnResult } from '../ports/fleet.js';
|
|
3
|
+
import type { AgentMessage, AgentPidResolution, AgentUsage, Capability, FleetClient, FleetTrackedAgent, PreviewReference, PreviewStartInput, PreviewSweepInput, PreviewSweepResult, RosterEntry, SendInput, SpawnInput, SpawnResult } from '../ports/fleet.js';
|
|
4
4
|
import type { Logger } from '../ports/system.js';
|
|
5
5
|
import { type PreviewManager } from '../node/tailscale-preview.js';
|
|
6
6
|
type SpawnedHandleLike = {
|
|
@@ -70,6 +70,7 @@ type DeliveryFailedListener = (info: {
|
|
|
70
70
|
reason?: string;
|
|
71
71
|
}) => void;
|
|
72
72
|
type AgentMessageListener = (message: AgentMessage) => void;
|
|
73
|
+
type AgentUsageListener = (usage: AgentUsage) => void | Promise<void>;
|
|
73
74
|
export declare const capabilityCli: Record<Capability, string>;
|
|
74
75
|
export declare class InternalFleetClient implements FleetClient {
|
|
75
76
|
#private;
|
|
@@ -111,6 +112,7 @@ export declare class InternalFleetClient implements FleetClient {
|
|
|
111
112
|
sendInput(name: string, data: string): Promise<void>;
|
|
112
113
|
onDeliveryFailed(listener: DeliveryFailedListener): () => void;
|
|
113
114
|
onAgentMessage(listener: AgentMessageListener): () => void;
|
|
115
|
+
onAgentUsage(listener: AgentUsageListener): () => void;
|
|
114
116
|
onAgentExit(listener: AgentExitListener): () => void;
|
|
115
117
|
preserveInfrastructureOnDispose(): void;
|
|
116
118
|
dispose(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-fleet-client.d.ts","sourceRoot":"","sources":["../../src/fleet/internal-fleet-client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAA;AAE1G,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,kBAAkB,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;
|
|
1
|
+
{"version":3,"file":"internal-fleet-client.d.ts","sourceRoot":"","sources":["../../src/fleet/internal-fleet-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,6 +46,7 @@ export class InternalFleetClient {
|
|
|
46
46
|
#agentExitListeners = new Set();
|
|
47
47
|
#deliveryFailedListeners = new Set();
|
|
48
48
|
#agentMessageListeners = new Set();
|
|
49
|
+
#agentUsageListeners = new Set();
|
|
49
50
|
#eventUnsubscribers = [];
|
|
50
51
|
#seenEvents = [];
|
|
51
52
|
#seenEventKeys = new Set();
|
|
@@ -436,6 +437,13 @@ export class InternalFleetClient {
|
|
|
436
437
|
this.#agentMessageListeners.delete(listener);
|
|
437
438
|
};
|
|
438
439
|
}
|
|
440
|
+
onAgentUsage(listener) {
|
|
441
|
+
this.#ensureEventSubscription();
|
|
442
|
+
this.#agentUsageListeners.add(listener);
|
|
443
|
+
return () => {
|
|
444
|
+
this.#agentUsageListeners.delete(listener);
|
|
445
|
+
};
|
|
446
|
+
}
|
|
439
447
|
onAgentExit(listener) {
|
|
440
448
|
this.#ensureEventSubscription();
|
|
441
449
|
this.#agentExitListeners.add(listener);
|
|
@@ -474,6 +482,7 @@ export class InternalFleetClient {
|
|
|
474
482
|
this.#agentExitListeners.clear();
|
|
475
483
|
this.#deliveryFailedListeners.clear();
|
|
476
484
|
this.#agentMessageListeners.clear();
|
|
485
|
+
this.#agentUsageListeners.clear();
|
|
477
486
|
this.#failedDeliveries.clear();
|
|
478
487
|
this.#failedDeliveryIds.length = 0;
|
|
479
488
|
this.#readyAgentNames.clear();
|
|
@@ -521,6 +530,11 @@ export class InternalFleetClient {
|
|
|
521
530
|
this.#client.connectEvents?.();
|
|
522
531
|
}
|
|
523
532
|
#handleBrokerEvent(event) {
|
|
533
|
+
const usage = agentUsageFromRuntimeEvent(event);
|
|
534
|
+
if (usage) {
|
|
535
|
+
this.#emitAgentUsage(usage, eventIdentity(event));
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
524
538
|
if (event.kind === 'worker_ready') {
|
|
525
539
|
this.#markAgentReady(event.name);
|
|
526
540
|
return;
|
|
@@ -723,6 +737,26 @@ export class InternalFleetClient {
|
|
|
723
737
|
listener(message);
|
|
724
738
|
}
|
|
725
739
|
}
|
|
740
|
+
#emitAgentUsage(usage, identity) {
|
|
741
|
+
if (this.#rememberEvent(identity))
|
|
742
|
+
return;
|
|
743
|
+
for (const listener of this.#agentUsageListeners) {
|
|
744
|
+
try {
|
|
745
|
+
void Promise.resolve(listener({ ...usage })).catch((error) => {
|
|
746
|
+
this.#logger?.warn?.('[factory-sdk] agent usage listener rejected an update', {
|
|
747
|
+
name: usage.name,
|
|
748
|
+
error,
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
}
|
|
752
|
+
catch (error) {
|
|
753
|
+
this.#logger?.warn?.('[factory-sdk] agent usage listener rejected an update', {
|
|
754
|
+
name: usage.name,
|
|
755
|
+
error,
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
726
760
|
#emitAgentExit(name, reason, identity) {
|
|
727
761
|
if (this.#rememberEvent(identity)) {
|
|
728
762
|
return;
|
|
@@ -1062,6 +1096,53 @@ function messageInputFrom(input) {
|
|
|
1062
1096
|
...(input.mode ? { mode: input.mode } : {}),
|
|
1063
1097
|
};
|
|
1064
1098
|
}
|
|
1099
|
+
/**
|
|
1100
|
+
* Harness Driver versions predating the typed usage event still forward
|
|
1101
|
+
* provider events through onEvent. Normalize the stable field aliases here so
|
|
1102
|
+
* upgrading the runtime does not require an orchestration rewrite.
|
|
1103
|
+
*/
|
|
1104
|
+
function agentUsageFromRuntimeEvent(event) {
|
|
1105
|
+
const record = runtimeRecord(event);
|
|
1106
|
+
const kind = runtimeString(record, 'kind', 'type');
|
|
1107
|
+
if (!kind || !['agent_usage', 'usage_updated', 'usage.updated', 'token_usage'].includes(kind)) {
|
|
1108
|
+
return undefined;
|
|
1109
|
+
}
|
|
1110
|
+
const agent = runtimeRecord(record?.agent);
|
|
1111
|
+
const usage = runtimeRecord(record?.usage);
|
|
1112
|
+
const name = runtimeString(record, 'name', 'agent_name', 'agentName')
|
|
1113
|
+
?? runtimeString(agent, 'name', 'agent_name', 'agentName');
|
|
1114
|
+
if (!name)
|
|
1115
|
+
return undefined;
|
|
1116
|
+
const model = runtimeString(record, 'model', 'model_id', 'modelId')
|
|
1117
|
+
?? runtimeString(usage, 'model', 'model_id', 'modelId');
|
|
1118
|
+
return {
|
|
1119
|
+
name,
|
|
1120
|
+
...(model ? { model } : {}),
|
|
1121
|
+
inputTokens: runtimeTokenCount(runtimeValue(record, 'inputTokens', 'input_tokens', 'promptTokens', 'prompt_tokens')
|
|
1122
|
+
?? runtimeValue(usage, 'inputTokens', 'input_tokens', 'promptTokens', 'prompt_tokens')),
|
|
1123
|
+
outputTokens: runtimeTokenCount(runtimeValue(record, 'outputTokens', 'output_tokens', 'completionTokens', 'completion_tokens')
|
|
1124
|
+
?? runtimeValue(usage, 'outputTokens', 'output_tokens', 'completionTokens', 'completion_tokens')),
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
const runtimeRecord = (value) => value !== null && typeof value === 'object' && !Array.isArray(value)
|
|
1128
|
+
? value
|
|
1129
|
+
: undefined;
|
|
1130
|
+
const runtimeString = (record, ...keys) => {
|
|
1131
|
+
for (const key of keys) {
|
|
1132
|
+
const value = record?.[key];
|
|
1133
|
+
if (typeof value === 'string' && value.trim())
|
|
1134
|
+
return value.trim();
|
|
1135
|
+
}
|
|
1136
|
+
return undefined;
|
|
1137
|
+
};
|
|
1138
|
+
const runtimeValue = (record, ...keys) => {
|
|
1139
|
+
for (const key of keys) {
|
|
1140
|
+
if (record && Object.prototype.hasOwnProperty.call(record, key))
|
|
1141
|
+
return record[key];
|
|
1142
|
+
}
|
|
1143
|
+
return undefined;
|
|
1144
|
+
};
|
|
1145
|
+
const runtimeTokenCount = (value) => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : null;
|
|
1065
1146
|
function eventIdentity(event) {
|
|
1066
1147
|
const record = event;
|
|
1067
1148
|
const stable = record.event_id ?? record.delivery_id;
|