@clocknext/sdk 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -5
- package/dist/index.cjs +18 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +134 -15
- package/dist/index.d.ts +134 -15
- package/dist/index.js +18 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,10 +55,45 @@ await cnk.signals.credit({ customerId, model: "llama-3.3-70b-versatile", agentKe
|
|
|
55
55
|
// Wallet — debits the customer's USD wallet at model cost
|
|
56
56
|
await cnk.signals.wallet({ customerId, model: "openai/gpt-oss-120b", tokens: { input: 800, output: 5000 } });
|
|
57
57
|
|
|
58
|
-
// Outcome —
|
|
59
|
-
await cnk.signals.outcome({ customerId, model: "llama-3.3-70b-versatile", agentKey: "resolved_ticket.triage" });
|
|
58
|
+
// Outcome — one step of a run (agentKey = the OutcomeStep's agent key)
|
|
59
|
+
await cnk.signals.outcome({ customerId, model: "llama-3.3-70b-versatile", agentKey: "resolved_ticket.triage", runId: "ticket_9021", tokens: { input: 600, output: 150 } });
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
+
### Outcome runs
|
|
63
|
+
|
|
64
|
+
An outcome is billed per **run**, not per step. Every signal for one run shares a
|
|
65
|
+
`runId` (opaque — any id you can correlate, e.g. your ticket/session id), so a
|
|
66
|
+
step can fire as many times as it needs to. The run bills **once**, when you mark
|
|
67
|
+
the final step `complete: true` — completion is never inferred from step
|
|
68
|
+
coverage. Sending `complete` twice is a safe no-op.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
const runId = "ticket_9021";
|
|
72
|
+
// each step of the run carries the same runId…
|
|
73
|
+
await cnk.signals.outcome({ customerId, model, agentKey: "resolved_ticket.triage", runId, tokens: { input: 600, output: 150 } });
|
|
74
|
+
await cnk.signals.outcome({ customerId, model, agentKey: "resolved_ticket.verify", runId, tokens: { input: 200, output: 80 } }); // may repeat
|
|
75
|
+
// …and the last one closes (and bills) the run:
|
|
76
|
+
await cnk.signals.outcome({ customerId, model, agentKey: "resolved_ticket.resolve", runId, complete: true, tokens: { input: 500, output: 200 } });
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Pricing metrics
|
|
80
|
+
|
|
81
|
+
Tag any credit or outcome signal with a **pricing metric** for reporting. `ref`
|
|
82
|
+
is the metric's ref ID (Settings → Pricing metrics) and `value` is your own
|
|
83
|
+
correlation id; the metric rolls usage up one row per distinct value.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
await cnk.signals.credit({
|
|
87
|
+
customerId, model: "llama-3.3-70b-versatile", agentKey: "api_credit",
|
|
88
|
+
tokens: { input: 1200, output: 340 },
|
|
89
|
+
metric: { ref: "voice_ai", value: "call_5f3a" },
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Metric tags are **reporting only** — they never change what's billed, a tag that
|
|
94
|
+
names no live metric is silently ignored, and a bad tag never fails the signal.
|
|
95
|
+
Tags on wallet signals are ignored.
|
|
96
|
+
|
|
62
97
|
### Async vs sync
|
|
63
98
|
|
|
64
99
|
By default the client is in **`async`** mode: `track()` buffers the signal and
|
|
@@ -71,17 +106,27 @@ path.
|
|
|
71
106
|
> how many run at once (`batch.maxConcurrency`). There is no single bulk-ingest
|
|
72
107
|
> call, so size your request budget per signal.
|
|
73
108
|
|
|
74
|
-
To
|
|
109
|
+
To await the request itself (rather than buffering it), either:
|
|
75
110
|
|
|
76
111
|
```ts
|
|
77
112
|
// per call
|
|
78
113
|
const res = await cnk.signals.credit({ … }, { wait: true });
|
|
79
|
-
console.log(res.usageLog);
|
|
80
114
|
|
|
81
115
|
// or globally
|
|
82
116
|
const cnk = new ClockNext({ apiKey, mode: "sync" });
|
|
83
117
|
```
|
|
84
118
|
|
|
119
|
+
> **Awaiting is not the same as billed.** Where the server has a durable queue
|
|
120
|
+
> configured it answers `202` and prices the signal in a worker, so you get
|
|
121
|
+
> `{ queued: true, messageId, usageLog: null }` — accepted, not yet recorded, and
|
|
122
|
+
> validated only later (a bad `agentKey` is dropped there, silently). Only when
|
|
123
|
+
> the server prices inline do you get `{ queued: false, usageLog }`. Branch on
|
|
124
|
+
> `queued`; never assume `usageLog` is populated.
|
|
125
|
+
>
|
|
126
|
+
> To validate and price a signal synchronously, use `signals.verify()` (a dry
|
|
127
|
+
> run — it always returns the projected log). To confirm a real signal landed,
|
|
128
|
+
> read it back with `signals.list({ customerId })`.
|
|
129
|
+
|
|
85
130
|
> In `async` mode, server-side rejections (e.g. insufficient allowance, `422`)
|
|
86
131
|
> surface via the `onError` hook or `flush()`, not from the `track()` call.
|
|
87
132
|
|
|
@@ -195,9 +240,12 @@ Define the billable *types*; record usage against them with `signals.*`.
|
|
|
195
240
|
await cnk.credits.create({ name: "API", agentKey: "api_credit", basePrice: 1, marginPercent: 20, pricePerCredit: 0.01 });
|
|
196
241
|
await cnk.credits.list({ active: true });
|
|
197
242
|
|
|
198
|
-
// outcome type — a multi-step workflow
|
|
243
|
+
// outcome type — a multi-step workflow. TWO kinds of agentKey, both required and
|
|
244
|
+
// both unique per org: the outcome's own (its identity) and each step's (what
|
|
245
|
+
// signals.outcome() reports against). They are separate namespaces.
|
|
199
246
|
await cnk.outcomes.create({
|
|
200
247
|
name: "Resolved ticket",
|
|
248
|
+
agentKey: "resolved_ticket",
|
|
201
249
|
basePrice: 1, marginPercent: 20, pricePerOutcome: 2,
|
|
202
250
|
steps: [{ name: "Triage", agentKey: "resolved_ticket.triage", basePrice: 0.5 }],
|
|
203
251
|
});
|
package/dist/index.cjs
CHANGED
|
@@ -229,7 +229,7 @@ function sleep(ms) {
|
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
// src/http.ts
|
|
232
|
-
var SDK_VERSION = "0.
|
|
232
|
+
var SDK_VERSION = "0.8.0" ;
|
|
233
233
|
var Transport = class {
|
|
234
234
|
constructor(cfg) {
|
|
235
235
|
this.cfg = cfg;
|
|
@@ -870,6 +870,13 @@ function signalToWire(signal) {
|
|
|
870
870
|
if (signal.type === "credit" || signal.type === "outcome") {
|
|
871
871
|
body.agentKey = signal.agentKey;
|
|
872
872
|
}
|
|
873
|
+
if (signal.type === "outcome") {
|
|
874
|
+
body.runId = signal.runId;
|
|
875
|
+
if (signal.complete != null) body.complete = signal.complete;
|
|
876
|
+
}
|
|
877
|
+
if (signal.type !== "wallet" && signal.metric) {
|
|
878
|
+
body[signal.metric.ref] = signal.metric.value;
|
|
879
|
+
}
|
|
873
880
|
if (signal.idempotencyKey) body.idempotencyKey = signal.idempotencyKey;
|
|
874
881
|
return body;
|
|
875
882
|
}
|
|
@@ -882,6 +889,13 @@ var Signals = class {
|
|
|
882
889
|
transport;
|
|
883
890
|
flusher;
|
|
884
891
|
cfg;
|
|
892
|
+
/**
|
|
893
|
+
* Record one usage signal. `POST /api/v1/usage`.
|
|
894
|
+
*
|
|
895
|
+
* Returns as soon as the signal is buffered (async mode) or the request has
|
|
896
|
+
* been answered (`{ wait: true }` / sync mode). See {@link TrackResult}: a
|
|
897
|
+
* resolved promise means "accepted", which is not the same as "billed".
|
|
898
|
+
*/
|
|
885
899
|
async track(signal, opts = {}) {
|
|
886
900
|
const body = signalToWire(signal);
|
|
887
901
|
if (body.idempotencyKey == null) body.idempotencyKey = newKey();
|
|
@@ -898,8 +912,9 @@ var Signals = class {
|
|
|
898
912
|
retry: true
|
|
899
913
|
});
|
|
900
914
|
return {
|
|
901
|
-
queued:
|
|
902
|
-
usageLog: res.usageLog ?? null
|
|
915
|
+
queued: res.queued === true,
|
|
916
|
+
usageLog: res.usageLog ?? null,
|
|
917
|
+
...res.messageId != null ? { messageId: res.messageId } : {}
|
|
903
918
|
};
|
|
904
919
|
}
|
|
905
920
|
/**
|