@nodetool-ai/execution 0.8.1
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 +129 -0
- package/dist/.nodetool-build-stamp +1 -0
- package/dist/app-debug/app-spec.d.ts +94 -0
- package/dist/app-debug/app-spec.d.ts.map +1 -0
- package/dist/app-debug/app-spec.js +710 -0
- package/dist/app-debug/app-spec.js.map +1 -0
- package/dist/app-debug/application-target.d.ts +53 -0
- package/dist/app-debug/application-target.d.ts.map +1 -0
- package/dist/app-debug/application-target.js +126 -0
- package/dist/app-debug/application-target.js.map +1 -0
- package/dist/app-debug/bundle-target.d.ts +21 -0
- package/dist/app-debug/bundle-target.d.ts.map +1 -0
- package/dist/app-debug/bundle-target.js +51 -0
- package/dist/app-debug/bundle-target.js.map +1 -0
- package/dist/app-debug/graph-shape.d.ts +14 -0
- package/dist/app-debug/graph-shape.d.ts.map +1 -0
- package/dist/app-debug/graph-shape.js +23 -0
- package/dist/app-debug/graph-shape.js.map +1 -0
- package/dist/app-debug/index.d.ts +26 -0
- package/dist/app-debug/index.d.ts.map +1 -0
- package/dist/app-debug/index.js +19 -0
- package/dist/app-debug/index.js.map +1 -0
- package/dist/app-debug/markdown.d.ts +6 -0
- package/dist/app-debug/markdown.d.ts.map +1 -0
- package/dist/app-debug/markdown.js +133 -0
- package/dist/app-debug/markdown.js.map +1 -0
- package/dist/app-debug/runtime.d.ts +267 -0
- package/dist/app-debug/runtime.d.ts.map +1 -0
- package/dist/app-debug/runtime.js +633 -0
- package/dist/app-debug/runtime.js.map +1 -0
- package/dist/app-debug/script-operation.d.ts +58 -0
- package/dist/app-debug/script-operation.d.ts.map +1 -0
- package/dist/app-debug/script-operation.js +44 -0
- package/dist/app-debug/script-operation.js.map +1 -0
- package/dist/app-debug/simulate.d.ts +85 -0
- package/dist/app-debug/simulate.d.ts.map +1 -0
- package/dist/app-debug/simulate.js +991 -0
- package/dist/app-debug/simulate.js.map +1 -0
- package/dist/app-debug/summarize.d.ts +64 -0
- package/dist/app-debug/summarize.d.ts.map +1 -0
- package/dist/app-debug/summarize.js +65 -0
- package/dist/app-debug/summarize.js.map +1 -0
- package/dist/app-debug/types.d.ts +343 -0
- package/dist/app-debug/types.d.ts.map +1 -0
- package/dist/app-debug/types.js +2 -0
- package/dist/app-debug/types.js.map +1 -0
- package/dist/cost-ledger.d.ts +147 -0
- package/dist/cost-ledger.d.ts.map +1 -0
- package/dist/cost-ledger.js +288 -0
- package/dist/cost-ledger.js.map +1 -0
- package/dist/debug/collector.d.ts +28 -0
- package/dist/debug/collector.d.ts.map +1 -0
- package/dist/debug/collector.js +284 -0
- package/dist/debug/collector.js.map +1 -0
- package/dist/debug/index.d.ts +15 -0
- package/dist/debug/index.d.ts.map +1 -0
- package/dist/debug/index.js +16 -0
- package/dist/debug/index.js.map +1 -0
- package/dist/debug/types.d.ts +179 -0
- package/dist/debug/types.d.ts.map +1 -0
- package/dist/debug/types.js +11 -0
- package/dist/debug/types.js.map +1 -0
- package/dist/debug/verdict.d.ts +27 -0
- package/dist/debug/verdict.d.ts.map +1 -0
- package/dist/debug/verdict.js +51 -0
- package/dist/debug/verdict.js.map +1 -0
- package/dist/executor-resolver.d.ts +13 -0
- package/dist/executor-resolver.d.ts.map +1 -0
- package/dist/executor-resolver.js +13 -0
- package/dist/executor-resolver.js.map +1 -0
- package/dist/fal-output-decoder.d.ts +36 -0
- package/dist/fal-output-decoder.d.ts.map +1 -0
- package/dist/fal-output-decoder.js +129 -0
- package/dist/fal-output-decoder.js.map +1 -0
- package/dist/generation-lifecycle.d.ts +54 -0
- package/dist/generation-lifecycle.d.ts.map +1 -0
- package/dist/generation-lifecycle.js +431 -0
- package/dist/generation-lifecycle.js.map +1 -0
- package/dist/generation-recovery-worker.d.ts +100 -0
- package/dist/generation-recovery-worker.d.ts.map +1 -0
- package/dist/generation-recovery-worker.js +995 -0
- package/dist/generation-recovery-worker.js.map +1 -0
- package/dist/generation-tracker.d.ts +83 -0
- package/dist/generation-tracker.d.ts.map +1 -0
- package/dist/generation-tracker.js +436 -0
- package/dist/generation-tracker.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/js-script-debug/index.d.ts +13 -0
- package/dist/js-script-debug/index.d.ts.map +1 -0
- package/dist/js-script-debug/index.js +12 -0
- package/dist/js-script-debug/index.js.map +1 -0
- package/dist/js-script-debug/markdown.d.ts +6 -0
- package/dist/js-script-debug/markdown.d.ts.map +1 -0
- package/dist/js-script-debug/markdown.js +62 -0
- package/dist/js-script-debug/markdown.js.map +1 -0
- package/dist/js-script-debug/outputs.d.ts +20 -0
- package/dist/js-script-debug/outputs.d.ts.map +1 -0
- package/dist/js-script-debug/outputs.js +30 -0
- package/dist/js-script-debug/outputs.js.map +1 -0
- package/dist/js-script-debug/report.d.ts +15 -0
- package/dist/js-script-debug/report.d.ts.map +1 -0
- package/dist/js-script-debug/report.js +90 -0
- package/dist/js-script-debug/report.js.map +1 -0
- package/dist/js-script-debug/types.d.ts +63 -0
- package/dist/js-script-debug/types.d.ts.map +1 -0
- package/dist/js-script-debug/types.js +10 -0
- package/dist/js-script-debug/types.js.map +1 -0
- package/dist/js-script-debug/validate.d.ts +38 -0
- package/dist/js-script-debug/validate.d.ts.map +1 -0
- package/dist/js-script-debug/validate.js +137 -0
- package/dist/js-script-debug/validate.js.map +1 -0
- package/dist/message-stream.d.ts +33 -0
- package/dist/message-stream.d.ts.map +1 -0
- package/dist/message-stream.js +58 -0
- package/dist/message-stream.js.map +1 -0
- package/dist/normalize-graph.d.ts +13 -0
- package/dist/normalize-graph.d.ts.map +1 -0
- package/dist/normalize-graph.js +63 -0
- package/dist/normalize-graph.js.map +1 -0
- package/dist/output-names.d.ts +13 -0
- package/dist/output-names.d.ts.map +1 -0
- package/dist/output-names.js +13 -0
- package/dist/output-names.js.map +1 -0
- package/dist/predicates.d.ts +6 -0
- package/dist/predicates.d.ts.map +1 -0
- package/dist/predicates.js +6 -0
- package/dist/predicates.js.map +1 -0
- package/dist/preflight.d.ts +87 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +139 -0
- package/dist/preflight.js.map +1 -0
- package/dist/provider-secret-key.d.ts +3 -0
- package/dist/provider-secret-key.d.ts.map +1 -0
- package/dist/provider-secret-key.js +7 -0
- package/dist/provider-secret-key.js.map +1 -0
- package/dist/service/app-debug-service.d.ts +78 -0
- package/dist/service/app-debug-service.d.ts.map +1 -0
- package/dist/service/app-debug-service.js +201 -0
- package/dist/service/app-debug-service.js.map +1 -0
- package/dist/service/app-run-server.d.ts +28 -0
- package/dist/service/app-run-server.d.ts.map +1 -0
- package/dist/service/app-run-server.js +104 -0
- package/dist/service/app-run-server.js.map +1 -0
- package/dist/service/debug-sessions.d.ts +158 -0
- package/dist/service/debug-sessions.d.ts.map +1 -0
- package/dist/service/debug-sessions.js +358 -0
- package/dist/service/debug-sessions.js.map +1 -0
- package/dist/service/index.d.ts +22 -0
- package/dist/service/index.d.ts.map +1 -0
- package/dist/service/index.js +17 -0
- package/dist/service/index.js.map +1 -0
- package/dist/service/job-progress.d.ts +40 -0
- package/dist/service/job-progress.d.ts.map +1 -0
- package/dist/service/job-progress.js +53 -0
- package/dist/service/job-progress.js.map +1 -0
- package/dist/service/workflow-run.d.ts +279 -0
- package/dist/service/workflow-run.d.ts.map +1 -0
- package/dist/service/workflow-run.js +598 -0
- package/dist/service/workflow-run.js.map +1 -0
- package/dist/service/workflow-workspace.d.ts +89 -0
- package/dist/service/workflow-workspace.d.ts.map +1 -0
- package/dist/service/workflow-workspace.js +160 -0
- package/dist/service/workflow-workspace.js.map +1 -0
- package/dist/session.d.ts +62 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +353 -0
- package/dist/session.js.map +1 -0
- package/dist/sketch-debug/index.d.ts +11 -0
- package/dist/sketch-debug/index.d.ts.map +1 -0
- package/dist/sketch-debug/index.js +10 -0
- package/dist/sketch-debug/index.js.map +1 -0
- package/dist/sketch-debug/markdown.d.ts +6 -0
- package/dist/sketch-debug/markdown.d.ts.map +1 -0
- package/dist/sketch-debug/markdown.js +93 -0
- package/dist/sketch-debug/markdown.js.map +1 -0
- package/dist/sketch-debug/report.d.ts +15 -0
- package/dist/sketch-debug/report.d.ts.map +1 -0
- package/dist/sketch-debug/report.js +98 -0
- package/dist/sketch-debug/report.js.map +1 -0
- package/dist/sketch-debug/types.d.ts +62 -0
- package/dist/sketch-debug/types.d.ts.map +1 -0
- package/dist/sketch-debug/types.js +10 -0
- package/dist/sketch-debug/types.js.map +1 -0
- package/dist/sketch-debug/validate.d.ts +14 -0
- package/dist/sketch-debug/validate.d.ts.map +1 -0
- package/dist/sketch-debug/validate.js +478 -0
- package/dist/sketch-debug/validate.js.map +1 -0
- package/dist/supervisor.d.ts +45 -0
- package/dist/supervisor.d.ts.map +1 -0
- package/dist/supervisor.js +97 -0
- package/dist/supervisor.js.map +1 -0
- package/dist/timeline-debug/index.d.ts +11 -0
- package/dist/timeline-debug/index.d.ts.map +1 -0
- package/dist/timeline-debug/index.js +10 -0
- package/dist/timeline-debug/index.js.map +1 -0
- package/dist/timeline-debug/legibility.d.ts +23 -0
- package/dist/timeline-debug/legibility.d.ts.map +1 -0
- package/dist/timeline-debug/legibility.js +240 -0
- package/dist/timeline-debug/legibility.js.map +1 -0
- package/dist/timeline-debug/markdown.d.ts +6 -0
- package/dist/timeline-debug/markdown.d.ts.map +1 -0
- package/dist/timeline-debug/markdown.js +103 -0
- package/dist/timeline-debug/markdown.js.map +1 -0
- package/dist/timeline-debug/motion.d.ts +20 -0
- package/dist/timeline-debug/motion.d.ts.map +1 -0
- package/dist/timeline-debug/motion.js +362 -0
- package/dist/timeline-debug/motion.js.map +1 -0
- package/dist/timeline-debug/report.d.ts +16 -0
- package/dist/timeline-debug/report.d.ts.map +1 -0
- package/dist/timeline-debug/report.js +100 -0
- package/dist/timeline-debug/report.js.map +1 -0
- package/dist/timeline-debug/showcase.d.ts +7 -0
- package/dist/timeline-debug/showcase.d.ts.map +1 -0
- package/dist/timeline-debug/showcase.js +347 -0
- package/dist/timeline-debug/showcase.js.map +1 -0
- package/dist/timeline-debug/types.d.ts +64 -0
- package/dist/timeline-debug/types.d.ts.map +1 -0
- package/dist/timeline-debug/types.js +10 -0
- package/dist/timeline-debug/types.js.map +1 -0
- package/dist/timeline-debug/validate.d.ts +24 -0
- package/dist/timeline-debug/validate.d.ts.map +1 -0
- package/dist/timeline-debug/validate.js +1432 -0
- package/dist/timeline-debug/validate.js.map +1 -0
- package/dist/types.d.ts +211 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-spend ledger — the write half of `nodetool costs`.
|
|
3
|
+
*
|
|
4
|
+
* `BaseProvider` accounts for chat and stream in tokens, and the host writes
|
|
5
|
+
* that row. Image, video and audio generation had no equivalent: the money went
|
|
6
|
+
* out and nothing reached the `predictions` table, so a render session read as
|
|
7
|
+
* free.
|
|
8
|
+
*
|
|
9
|
+
* Two kinds of generation reach a ledger row here:
|
|
10
|
+
*
|
|
11
|
+
* - A node that knows its own charge calls `context.setProviderCost()`, which
|
|
12
|
+
* rides out on the completed `node_update` as `provider_cost`. FAL and kie do
|
|
13
|
+
* this — the number comes from the provider, so it wins. When the provider
|
|
14
|
+
* also exposes a request-keyed billing API, the estimate is reconciled to the
|
|
15
|
+
* actual charge in the background.
|
|
16
|
+
* - Everything else goes through `ProcessingContext.runProviderPrediction` (and
|
|
17
|
+
* its streaming/encoded siblings), which emits a `prediction` message
|
|
18
|
+
* carrying provider, model, capability and the job's parameters. That is
|
|
19
|
+
* priced here against `@nodetool-ai/model-pricing` — the same catalog the
|
|
20
|
+
* editor's cost preview and the pre-run budget gate read.
|
|
21
|
+
*
|
|
22
|
+
* A model in no catalog still gets a row, with `cost` left null rather than set
|
|
23
|
+
* to zero: the call is visible in `nodetool costs`, and a null is countable as
|
|
24
|
+
* unpriced instead of summing as free. The units behind a price are recorded
|
|
25
|
+
* next to it (`billing_unit`, `quantity`, `unit_price`, `currency`, plus the
|
|
26
|
+
* catalog's own breakdown in `metadata`) so a per-second or per-megapixel row
|
|
27
|
+
* is auditable even when the estimate is imperfect.
|
|
28
|
+
*/
|
|
29
|
+
import { Prediction } from "@nodetool-ai/models";
|
|
30
|
+
import type { ProcessingMessage, ProviderCost } from "@nodetool-ai/protocol";
|
|
31
|
+
import { type GenerationTrackerState } from "./generation-tracker.js";
|
|
32
|
+
/** Whether a capability is billed per unit of output (and so belongs here). */
|
|
33
|
+
export declare function isUnitBilledCapability(capability: string | null | undefined): boolean;
|
|
34
|
+
/** One generation to price and record. */
|
|
35
|
+
export interface GenerationSpend {
|
|
36
|
+
userId: string;
|
|
37
|
+
provider: string;
|
|
38
|
+
model: string;
|
|
39
|
+
capability?: string | null;
|
|
40
|
+
/** Outputs produced — the multiplier on the catalog's per-run price. */
|
|
41
|
+
quantity?: number;
|
|
42
|
+
/** What the job stated, in provider parameter spelling (`duration_seconds`, `resolution`, …). */
|
|
43
|
+
params?: Record<string, unknown> | null;
|
|
44
|
+
nodeId?: string;
|
|
45
|
+
nodeType?: string;
|
|
46
|
+
workflowId?: string | null;
|
|
47
|
+
/** The project this run belongs to, when it has one. */
|
|
48
|
+
projectId?: string | null;
|
|
49
|
+
/** The project document this run is producing, when it names one. */
|
|
50
|
+
documentId?: string | null;
|
|
51
|
+
durationMs?: number | null;
|
|
52
|
+
}
|
|
53
|
+
/** What the catalog answered for a generation, or `null` when it knows no price. */
|
|
54
|
+
export interface PricedGeneration {
|
|
55
|
+
cost: number;
|
|
56
|
+
unit_price: number;
|
|
57
|
+
quantity: number;
|
|
58
|
+
billing_unit: string;
|
|
59
|
+
currency: string;
|
|
60
|
+
/** The catalog's own reasoning, e.g. "5 s × $0.205/s at 720p". */
|
|
61
|
+
breakdown?: string;
|
|
62
|
+
/** What the catalog filled in because the job did not state it. */
|
|
63
|
+
assumptions?: string[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Price a generation against the model catalogs. Returns `null` when no catalog
|
|
67
|
+
* carries the model, or when the catalog declines to extrapolate — a refusal is
|
|
68
|
+
* an answer, and inventing a number would be worse than recording none.
|
|
69
|
+
*/
|
|
70
|
+
export declare function priceGeneration(spend: GenerationSpend): PricedGeneration | null;
|
|
71
|
+
/**
|
|
72
|
+
* Write one generation to the ledger. Best-effort: a host with no database
|
|
73
|
+
* (a hermetic run, an eval) must not fail because accounting could not be
|
|
74
|
+
* persisted — the generation already happened and was already billed.
|
|
75
|
+
*/
|
|
76
|
+
export declare function recordGenerationSpend(spend: GenerationSpend): Promise<Prediction | null>;
|
|
77
|
+
/** A charge a node reported for itself, as it rides out on `node_update`. */
|
|
78
|
+
export interface NodeCostSpend {
|
|
79
|
+
userId: string;
|
|
80
|
+
cost: ProviderCost;
|
|
81
|
+
nodeId: string;
|
|
82
|
+
nodeType: string;
|
|
83
|
+
workflowId: string | null;
|
|
84
|
+
/** The project this run belongs to, when it has one. */
|
|
85
|
+
projectId?: string | null;
|
|
86
|
+
/** The project document this run is producing, when it names one. */
|
|
87
|
+
documentId?: string | null;
|
|
88
|
+
/** Resolves the provider API key used to look the actual charge up, when one exists. */
|
|
89
|
+
resolveSecret?: (key: string) => Promise<string | null | undefined>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Write a node-reported provider charge to the ledger, then refine it into the
|
|
93
|
+
* provider's actual billed amount in the background when that provider
|
|
94
|
+
* registered a reconciler. Best-effort throughout.
|
|
95
|
+
*/
|
|
96
|
+
export declare function recordNodeProviderCost(spend: NodeCostSpend): Promise<Prediction | null>;
|
|
97
|
+
export interface RunCostLedgerOptions {
|
|
98
|
+
userId: string;
|
|
99
|
+
workflowId: string | null;
|
|
100
|
+
/**
|
|
101
|
+
* The project this run belongs to. Left unset outside a project, and the row
|
|
102
|
+
* then carries a null rather than being attributed to the loose bucket — a
|
|
103
|
+
* project's total counts only what named it.
|
|
104
|
+
*/
|
|
105
|
+
projectId?: string | null;
|
|
106
|
+
/** The project document this run is producing, when the host names one. */
|
|
107
|
+
documentId?: string | null;
|
|
108
|
+
/** Node type for a node id, so a row names the node that spent the money. */
|
|
109
|
+
nodeType?: (nodeId: string) => string;
|
|
110
|
+
resolveSecret?: (key: string) => Promise<string | null | undefined>;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* A `nodeType` lookup built once per run. Scanning the node list per message
|
|
114
|
+
* would be O(nodes × messages), which a 20 000-node graph feels.
|
|
115
|
+
*/
|
|
116
|
+
export declare function nodeTypeLookup(nodes: ReadonlyArray<{
|
|
117
|
+
id: string;
|
|
118
|
+
type: string;
|
|
119
|
+
}>): (nodeId: string) => string;
|
|
120
|
+
/** The slice of `ProcessingContext` the ledger listens on. */
|
|
121
|
+
export interface CostLedgerSource {
|
|
122
|
+
addMessageListener(listener: (msg: ProcessingMessage) => void): () => void;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Record every generation a run pays for. Returns the detach function.
|
|
126
|
+
*
|
|
127
|
+
* Listens on the context rather than on a host's outbound message loop so each
|
|
128
|
+
* surface — CLI, ws server, app runtime, debug harness — records once, from the
|
|
129
|
+
* same seam, and cannot drift.
|
|
130
|
+
*/
|
|
131
|
+
export interface RunCostLedgerHandle {
|
|
132
|
+
/** Detach the listener. */
|
|
133
|
+
(): void;
|
|
134
|
+
/**
|
|
135
|
+
* Resolve once every write the listener has started so far has landed.
|
|
136
|
+
* The listener fires and forgets; a caller that reads the row right after
|
|
137
|
+
* the generation returned (a direct RPC answering its client) waits here.
|
|
138
|
+
*/
|
|
139
|
+
settled(): Promise<void>;
|
|
140
|
+
}
|
|
141
|
+
export declare function attachRunCostLedger(context: CostLedgerSource, options: RunCostLedgerOptions): RunCostLedgerHandle;
|
|
142
|
+
/**
|
|
143
|
+
* Ledger one run message: a node's self-reported charge, or a completed
|
|
144
|
+
* unit-billed prediction. Anything else is not spend and writes nothing.
|
|
145
|
+
*/
|
|
146
|
+
export declare function recordFromMessage(msg: ProcessingMessage, options: RunCostLedgerOptions, state?: GenerationTrackerState): Promise<void>;
|
|
147
|
+
//# sourceMappingURL=cost-ledger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-ledger.d.ts","sourceRoot":"","sources":["../src/cost-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-spend ledger — the write half of `nodetool costs`.
|
|
3
|
+
*
|
|
4
|
+
* `BaseProvider` accounts for chat and stream in tokens, and the host writes
|
|
5
|
+
* that row. Image, video and audio generation had no equivalent: the money went
|
|
6
|
+
* out and nothing reached the `predictions` table, so a render session read as
|
|
7
|
+
* free.
|
|
8
|
+
*
|
|
9
|
+
* Two kinds of generation reach a ledger row here:
|
|
10
|
+
*
|
|
11
|
+
* - A node that knows its own charge calls `context.setProviderCost()`, which
|
|
12
|
+
* rides out on the completed `node_update` as `provider_cost`. FAL and kie do
|
|
13
|
+
* this — the number comes from the provider, so it wins. When the provider
|
|
14
|
+
* also exposes a request-keyed billing API, the estimate is reconciled to the
|
|
15
|
+
* actual charge in the background.
|
|
16
|
+
* - Everything else goes through `ProcessingContext.runProviderPrediction` (and
|
|
17
|
+
* its streaming/encoded siblings), which emits a `prediction` message
|
|
18
|
+
* carrying provider, model, capability and the job's parameters. That is
|
|
19
|
+
* priced here against `@nodetool-ai/model-pricing` — the same catalog the
|
|
20
|
+
* editor's cost preview and the pre-run budget gate read.
|
|
21
|
+
*
|
|
22
|
+
* A model in no catalog still gets a row, with `cost` left null rather than set
|
|
23
|
+
* to zero: the call is visible in `nodetool costs`, and a null is countable as
|
|
24
|
+
* unpriced instead of summing as free. The units behind a price are recorded
|
|
25
|
+
* next to it (`billing_unit`, `quantity`, `unit_price`, `currency`, plus the
|
|
26
|
+
* catalog's own breakdown in `metadata`) so a per-second or per-megapixel row
|
|
27
|
+
* is auditable even when the estimate is imperfect.
|
|
28
|
+
*/
|
|
29
|
+
import { createLogger } from "@nodetool-ai/config";
|
|
30
|
+
import { Prediction } from "@nodetool-ai/models";
|
|
31
|
+
import { getModelUnitPrice } from "@nodetool-ai/model-pricing";
|
|
32
|
+
import { extractPricingParams } from "@nodetool-ai/node-sdk";
|
|
33
|
+
import { getCostReconciler } from "@nodetool-ai/runtime";
|
|
34
|
+
import { createTrackerState, trackPredictionMessage } from "./generation-tracker.js";
|
|
35
|
+
import { providerBillingSecretKey } from "./provider-secret-key.js";
|
|
36
|
+
const log = createLogger("nodetool.execution.cost-ledger");
|
|
37
|
+
/**
|
|
38
|
+
* Capabilities a provider bills per output rather than per token. Chat,
|
|
39
|
+
* streaming chat and embeddings are absent on purpose: a token-billed call
|
|
40
|
+
* reaches this ledger by a different road, so admitting it here would book it
|
|
41
|
+
* twice. A chat turn writes the provider instance's running total through
|
|
42
|
+
* `ChatTurn._logProviderCall`; a workflow node reports its own delta through
|
|
43
|
+
* `meterProviderSpend` -> `setProviderCost` -> `recordNodeProviderCost`.
|
|
44
|
+
*/
|
|
45
|
+
const UNIT_BILLED_CAPABILITIES = new Set([
|
|
46
|
+
"text_to_image",
|
|
47
|
+
"image_to_image",
|
|
48
|
+
"inpainting",
|
|
49
|
+
"outpaint_image",
|
|
50
|
+
"text_to_video",
|
|
51
|
+
"image_to_video",
|
|
52
|
+
"reference_to_video",
|
|
53
|
+
"video_to_video",
|
|
54
|
+
"upscale_video",
|
|
55
|
+
"interpolate_video",
|
|
56
|
+
"outpaint_video",
|
|
57
|
+
"upscale_image",
|
|
58
|
+
"remove_background",
|
|
59
|
+
"relight_image",
|
|
60
|
+
"segment_image",
|
|
61
|
+
"vectorize_image",
|
|
62
|
+
"lip_sync",
|
|
63
|
+
"text_to_speech",
|
|
64
|
+
"text_to_music",
|
|
65
|
+
"audio_to_audio",
|
|
66
|
+
"video_to_audio",
|
|
67
|
+
"automatic_speech_recognition",
|
|
68
|
+
"text_to_3d",
|
|
69
|
+
"image_to_3d",
|
|
70
|
+
"render_model3d"
|
|
71
|
+
]);
|
|
72
|
+
/** Whether a capability is billed per unit of output (and so belongs here). */
|
|
73
|
+
export function isUnitBilledCapability(capability) {
|
|
74
|
+
return capability != null && UNIT_BILLED_CAPABILITIES.has(capability);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Price a generation against the model catalogs. Returns `null` when no catalog
|
|
78
|
+
* carries the model, or when the catalog declines to extrapolate — a refusal is
|
|
79
|
+
* an answer, and inventing a number would be worse than recording none.
|
|
80
|
+
*/
|
|
81
|
+
export function priceGeneration(spend) {
|
|
82
|
+
const quantity = spend.quantity ?? 1;
|
|
83
|
+
if (!Number.isFinite(quantity) || quantity <= 0)
|
|
84
|
+
return null;
|
|
85
|
+
const price = getModelUnitPrice({ id: spend.model, provider: spend.provider }, extractPricingParams(spend.params));
|
|
86
|
+
if (!price || price.declined)
|
|
87
|
+
return null;
|
|
88
|
+
if (!Number.isFinite(price.unit_price))
|
|
89
|
+
return null;
|
|
90
|
+
const priced = {
|
|
91
|
+
cost: price.unit_price * quantity,
|
|
92
|
+
unit_price: price.unit_price,
|
|
93
|
+
quantity,
|
|
94
|
+
billing_unit: price.billing_unit || (spend.capability ?? "run"),
|
|
95
|
+
currency: price.currency || "USD"
|
|
96
|
+
};
|
|
97
|
+
if (price.breakdown)
|
|
98
|
+
priced.breakdown = price.breakdown;
|
|
99
|
+
if (price.assumptions?.length)
|
|
100
|
+
priced.assumptions = price.assumptions;
|
|
101
|
+
return priced;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Write one generation to the ledger. Best-effort: a host with no database
|
|
105
|
+
* (a hermetic run, an eval) must not fail because accounting could not be
|
|
106
|
+
* persisted — the generation already happened and was already billed.
|
|
107
|
+
*/
|
|
108
|
+
export async function recordGenerationSpend(spend) {
|
|
109
|
+
const priced = priceGeneration(spend);
|
|
110
|
+
const metadata = {
|
|
111
|
+
capability: spend.capability ?? null
|
|
112
|
+
};
|
|
113
|
+
if (priced) {
|
|
114
|
+
metadata.price_source = "model-catalog";
|
|
115
|
+
if (priced.breakdown)
|
|
116
|
+
metadata.price_breakdown = priced.breakdown;
|
|
117
|
+
if (priced.assumptions)
|
|
118
|
+
metadata.price_assumptions = priced.assumptions;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
metadata.unpriced_reason = `No unit price for ${spend.provider}/${spend.model} in the model catalogs`;
|
|
122
|
+
}
|
|
123
|
+
try {
|
|
124
|
+
return await Prediction.create({
|
|
125
|
+
user_id: spend.userId,
|
|
126
|
+
provider: spend.provider,
|
|
127
|
+
model: spend.model,
|
|
128
|
+
node_id: spend.nodeId ?? "",
|
|
129
|
+
node_type: spend.nodeType ?? "",
|
|
130
|
+
workflow_id: spend.workflowId ?? null,
|
|
131
|
+
project_id: spend.projectId ?? null,
|
|
132
|
+
document_id: spend.documentId ?? null,
|
|
133
|
+
status: "completed",
|
|
134
|
+
cost: priced ? priced.cost : null,
|
|
135
|
+
billing_unit: priced ? priced.billing_unit : (spend.capability ?? null),
|
|
136
|
+
quantity: priced ? priced.quantity : (spend.quantity ?? 1),
|
|
137
|
+
unit_price: priced ? priced.unit_price : null,
|
|
138
|
+
currency: priced ? priced.currency : null,
|
|
139
|
+
duration: spend.durationMs != null ? spend.durationMs / 1000 : null,
|
|
140
|
+
metadata
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
catch (err) {
|
|
144
|
+
log.debug("Generation spend not recorded", {
|
|
145
|
+
provider: spend.provider,
|
|
146
|
+
model: spend.model,
|
|
147
|
+
error: err instanceof Error ? err.message : String(err)
|
|
148
|
+
});
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Write a node-reported provider charge to the ledger, then refine it into the
|
|
154
|
+
* provider's actual billed amount in the background when that provider
|
|
155
|
+
* registered a reconciler. Best-effort throughout.
|
|
156
|
+
*/
|
|
157
|
+
export async function recordNodeProviderCost(spend) {
|
|
158
|
+
const { cost } = spend;
|
|
159
|
+
// A NaN/Infinity amount from a buggy provider call can't be stored: SQLite
|
|
160
|
+
// has no representation for it and JSON turns it into `null`.
|
|
161
|
+
if (!Number.isFinite(cost.amount))
|
|
162
|
+
return null;
|
|
163
|
+
try {
|
|
164
|
+
const prediction = await Prediction.create({
|
|
165
|
+
user_id: spend.userId,
|
|
166
|
+
provider: cost.provider,
|
|
167
|
+
model: cost.model ?? spend.nodeType,
|
|
168
|
+
node_type: spend.nodeType,
|
|
169
|
+
node_id: spend.nodeId,
|
|
170
|
+
workflow_id: spend.workflowId,
|
|
171
|
+
project_id: spend.projectId ?? null,
|
|
172
|
+
document_id: spend.documentId ?? null,
|
|
173
|
+
status: "completed",
|
|
174
|
+
cost: cost.amount,
|
|
175
|
+
currency: cost.currency ?? cost.unit ?? null,
|
|
176
|
+
billing_unit: cost.billing_unit ?? null,
|
|
177
|
+
quantity: cost.quantity ?? null,
|
|
178
|
+
unit_price: cost.unit_price ?? null,
|
|
179
|
+
provider_request_id: cost.provider_request_id ?? null,
|
|
180
|
+
// Set by a token-billed call (an LLM node reporting a `generateLoop`
|
|
181
|
+
// delta), left null by a per-output generation that counts no tokens.
|
|
182
|
+
input_tokens: cost.input_tokens ?? null,
|
|
183
|
+
output_tokens: cost.output_tokens ?? null,
|
|
184
|
+
cached_tokens: cost.cached_tokens ?? null
|
|
185
|
+
});
|
|
186
|
+
if (cost.provider_request_id) {
|
|
187
|
+
void reconcileProviderCost(prediction, spend);
|
|
188
|
+
}
|
|
189
|
+
return prediction;
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
log.debug("Node provider cost not recorded", {
|
|
193
|
+
provider: cost.provider,
|
|
194
|
+
error: err instanceof Error ? err.message : String(err)
|
|
195
|
+
});
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Replace an estimated charge with the provider's actual billed amount, looked
|
|
201
|
+
* up by request id. Runs detached; leaves the estimate in place when no actual
|
|
202
|
+
* is available.
|
|
203
|
+
*/
|
|
204
|
+
async function reconcileProviderCost(prediction, spend) {
|
|
205
|
+
const reconciler = getCostReconciler(spend.cost.provider);
|
|
206
|
+
if (!reconciler || !spend.cost.provider_request_id)
|
|
207
|
+
return;
|
|
208
|
+
try {
|
|
209
|
+
const secretKey = providerBillingSecretKey(spend.cost.provider);
|
|
210
|
+
const apiKey = await spend.resolveSecret?.(secretKey);
|
|
211
|
+
const actual = await reconciler({
|
|
212
|
+
requestId: spend.cost.provider_request_id,
|
|
213
|
+
endpointId: spend.cost.model ?? null,
|
|
214
|
+
secrets: apiKey ? { [secretKey]: apiKey } : {}
|
|
215
|
+
});
|
|
216
|
+
if (!actual)
|
|
217
|
+
return;
|
|
218
|
+
await prediction.update({
|
|
219
|
+
cost: actual.cost,
|
|
220
|
+
currency: actual.currency ?? prediction.currency,
|
|
221
|
+
quantity: actual.quantity ?? prediction.quantity,
|
|
222
|
+
unit_price: actual.unit_price ?? prediction.unit_price
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
log.warn("Failed to reconcile provider cost", {
|
|
227
|
+
provider: spend.cost.provider,
|
|
228
|
+
error: err instanceof Error ? err.message : String(err)
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* A `nodeType` lookup built once per run. Scanning the node list per message
|
|
234
|
+
* would be O(nodes × messages), which a 20 000-node graph feels.
|
|
235
|
+
*/
|
|
236
|
+
export function nodeTypeLookup(nodes) {
|
|
237
|
+
const types = new Map(nodes.map((node) => [node.id, node.type]));
|
|
238
|
+
return (nodeId) => types.get(nodeId) ?? "";
|
|
239
|
+
}
|
|
240
|
+
export function attachRunCostLedger(context, options) {
|
|
241
|
+
const state = createTrackerState();
|
|
242
|
+
const pending = new Set();
|
|
243
|
+
const detach = context.addMessageListener((msg) => {
|
|
244
|
+
const write = recordFromMessage(msg, options, state)
|
|
245
|
+
.catch(() => undefined)
|
|
246
|
+
.finally(() => pending.delete(write));
|
|
247
|
+
pending.add(write);
|
|
248
|
+
});
|
|
249
|
+
return Object.assign(detach, {
|
|
250
|
+
settled: async () => {
|
|
251
|
+
await Promise.all([...pending]);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Ledger one run message: a node's self-reported charge, or a completed
|
|
257
|
+
* unit-billed prediction. Anything else is not spend and writes nothing.
|
|
258
|
+
*/
|
|
259
|
+
export async function recordFromMessage(msg, options, state = createTrackerState()) {
|
|
260
|
+
if (msg.type === "node_update" && msg.status === "completed") {
|
|
261
|
+
if (!msg.provider_cost)
|
|
262
|
+
return;
|
|
263
|
+
// A node that went through the generation seam and whose provider stated
|
|
264
|
+
// its charge already has a row with that charge (design § 6.5). Its own
|
|
265
|
+
// `provider_cost` is the same money a second time.
|
|
266
|
+
if (state.receiptCostNodes.has(msg.node_id)) {
|
|
267
|
+
state.receiptCostNodes.delete(msg.node_id);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
await recordNodeProviderCost({
|
|
271
|
+
userId: options.userId,
|
|
272
|
+
cost: msg.provider_cost,
|
|
273
|
+
nodeId: msg.node_id,
|
|
274
|
+
nodeType: msg.node_type || options.nodeType?.(msg.node_id) || "",
|
|
275
|
+
workflowId: options.workflowId,
|
|
276
|
+
projectId: options.projectId,
|
|
277
|
+
documentId: options.documentId,
|
|
278
|
+
resolveSecret: options.resolveSecret
|
|
279
|
+
});
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
if (msg.type !== "prediction")
|
|
283
|
+
return;
|
|
284
|
+
// The tracker opens the row on `running` and closes it on the terminal
|
|
285
|
+
// message, so every state of a generation is a row state.
|
|
286
|
+
await trackPredictionMessage(msg, options, state);
|
|
287
|
+
}
|
|
288
|
+
//# sourceMappingURL=cost-ledger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost-ledger.js","sourceRoot":"","sources":["../src/cost-ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Folds a workflow run's processing-message stream into an `ExecutionSummary`.
|
|
3
|
+
*
|
|
4
|
+
* Pure and surface-agnostic: the same reducer distills the server runner's
|
|
5
|
+
* `RunResult.messages` and the browser harness's raw event log, so both surfaces
|
|
6
|
+
* report identically. Only `import type` is used here so the module stays free of
|
|
7
|
+
* runtime workspace dependencies (testable under the CLI vitest stub setup).
|
|
8
|
+
*/
|
|
9
|
+
import type { ProcessingMessage } from "@nodetool-ai/protocol";
|
|
10
|
+
import type { ExecutionSummary } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* Make a value safe to embed in a JSON debug report: truncate long strings,
|
|
13
|
+
* collapse binary and base64 blobs, and cap array/object fan-out. Keeps enough
|
|
14
|
+
* to debug (shape, prefixes, sizes) without dumping megabytes of media bytes.
|
|
15
|
+
*/
|
|
16
|
+
/** A value reduced to what a JSON debug report can carry. */
|
|
17
|
+
export type PreviewValue = string | number | boolean | null | undefined | PreviewValue[] | {
|
|
18
|
+
[key: string]: PreviewValue;
|
|
19
|
+
};
|
|
20
|
+
export declare function previewValue(value: unknown, maxLen?: number): PreviewValue;
|
|
21
|
+
/**
|
|
22
|
+
* Reduce a processing-message stream into a structured execution summary.
|
|
23
|
+
*
|
|
24
|
+
* Accepts loosely-typed messages (the browser harness decodes JSON into bags of
|
|
25
|
+
* unknown fields) and reads only the fields each `type` is known to carry.
|
|
26
|
+
*/
|
|
27
|
+
export declare function collectExecutionSummary(messages: ReadonlyArray<ProcessingMessage | Record<string, unknown>>): ExecutionSummary;
|
|
28
|
+
//# sourceMappingURL=collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/debug/collector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAgB,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAEV,gBAAgB,EAKjB,MAAM,YAAY,CAAC;AA6BpB;;;;GAIG;AACH,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GACpB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,GACT,YAAY,EAAE,GACd;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAEpC,wBAAgB,YAAY,CAC1B,KAAK,EAAE,OAAO,EACd,MAAM,GAAE,MAA2B,GAClC,YAAY,CA+Bd;AAcD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,aAAa,CAAC,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACnE,gBAAgB,CAiLlB"}
|