@usagetap/sdk 1.4.0 → 1.7.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 +156 -18
- package/dist/adapters/anthropic.cjs +195 -235
- package/dist/adapters/anthropic.cjs.map +1 -1
- package/dist/adapters/anthropic.d.cts +1 -1
- package/dist/adapters/anthropic.d.ts +1 -1
- package/dist/adapters/anthropic.mjs +195 -235
- package/dist/adapters/anthropic.mjs.map +1 -1
- package/dist/adapters/openai.cjs +256 -274
- package/dist/adapters/openai.cjs.map +1 -1
- package/dist/adapters/openai.d.cts +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.mjs +256 -274
- package/dist/adapters/openai.mjs.map +1 -1
- package/dist/adapters/openrouter.cjs +256 -274
- package/dist/adapters/openrouter.cjs.map +1 -1
- package/dist/adapters/openrouter.d.cts +1 -1
- package/dist/adapters/openrouter.d.ts +1 -1
- package/dist/adapters/openrouter.mjs +256 -274
- package/dist/adapters/openrouter.mjs.map +1 -1
- package/dist/anthropic/index.cjs +195 -235
- package/dist/anthropic/index.cjs.map +1 -1
- package/dist/anthropic/index.d.cts +1 -1
- package/dist/anthropic/index.d.ts +1 -1
- package/dist/anthropic/index.mjs +195 -235
- package/dist/anthropic/index.mjs.map +1 -1
- package/dist/{client-CExQ8e1T.d.cts → client-C0UiaqVB.d.cts} +141 -61
- package/dist/{client-CExQ8e1T.d.ts → client-C0UiaqVB.d.ts} +141 -61
- package/dist/express/index.cjs +189 -246
- package/dist/express/index.cjs.map +1 -1
- package/dist/express/index.d.cts +1 -1
- package/dist/express/index.d.ts +1 -1
- package/dist/express/index.mjs +189 -246
- package/dist/express/index.mjs.map +1 -1
- package/dist/index.cjs +391 -175
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -4
- package/dist/index.d.ts +13 -4
- package/dist/index.mjs +391 -175
- package/dist/index.mjs.map +1 -1
- package/dist/openai/index.cjs +256 -274
- package/dist/openai/index.cjs.map +1 -1
- package/dist/openai/index.d.cts +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/openai/index.mjs +256 -274
- package/dist/openai/index.mjs.map +1 -1
- package/dist/openrouter/index.cjs +256 -274
- package/dist/openrouter/index.cjs.map +1 -1
- package/dist/openrouter/index.d.cts +1 -1
- package/dist/openrouter/index.d.ts +1 -1
- package/dist/openrouter/index.mjs +256 -274
- package/dist/openrouter/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Server-only JavaScript/TypeScript client for UsageTap. The SDK helps you instrument `call_begin → vendor call → call_end` flows with built-in retries, idempotency helpers, and vendor adapters.
|
|
4
4
|
|
|
5
|
+
For API requests and MCP tool calls, use the dedicated call meter without model or token fields:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
await client.incrementCustomMeter(
|
|
9
|
+
{ customerId, meterSlot: "AGENTIC_API", amount: 1, feature: "mcp.tools.call" },
|
|
10
|
+
{ idempotencyKey: `mcp:${requestId}` },
|
|
11
|
+
);
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Configure its included allocation and single-rate or graduated overage pricing in **More > Agentic & API** on the usage plan. It uses the same reporting, credit funding, and asynchronous PAYG settlement as custom meters. This does not reserve credit or impose a rolling rate limit. See [Agentic/API integration and limits](../../docs/agentic-api-meter.md).
|
|
15
|
+
|
|
5
16
|
## Module formats
|
|
6
17
|
|
|
7
18
|
`@usagetap/sdk` ships real dual ESM (`.mjs`) and CommonJS (`.cjs`) entrypoints. In ESM projects use `import { UsageTapClient } from "@usagetap/sdk";`. For CommonJS runtimes (including VS Code extensions) rely on `const { UsageTapClient } = require("@usagetap/sdk");`.
|
|
@@ -9,7 +20,7 @@ Server-only JavaScript/TypeScript client for UsageTap. The SDK helps you instrum
|
|
|
9
20
|
Optional adapters live behind subpath exports so their peer dependencies stay out of the core bundle:
|
|
10
21
|
|
|
11
22
|
- `@usagetap/sdk/openai` – OpenAI/OpenRouter helpers (`wrapOpenAI`, `streamOpenAIRoute`, etc.)
|
|
12
|
-
- `@usagetap/sdk/anthropic` – Anthropic
|
|
23
|
+
- `@usagetap/sdk/anthropic` – Anthropic helpers (`withMetering`, `wrapAnthropic`)
|
|
13
24
|
- `@usagetap/sdk/openrouter` – discoverable OpenRouter aliases for the OpenAI-compatible wrappers
|
|
14
25
|
- `@usagetap/sdk/express` – Express middleware
|
|
15
26
|
- `@usagetap/sdk/react` – React chat hook
|
|
@@ -123,6 +134,41 @@ const completion = await usageTap.gateway.chat.completions.create({
|
|
|
123
134
|
console.log(completion.choices[0].message?.content);
|
|
124
135
|
```
|
|
125
136
|
|
|
137
|
+
The typed Responses resource supports portable built-in web search, structured
|
|
138
|
+
output, verbosity, prompt caching, and Gateway compression. It is buffered in
|
|
139
|
+
this release, so omit `stream` or set it to `false`:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
const response = await usageTap.gateway.responses.create({
|
|
143
|
+
model: "usagetap/standard",
|
|
144
|
+
customerId: "cust_123",
|
|
145
|
+
feature: "answer.with.sources",
|
|
146
|
+
instructions: stablePolicy,
|
|
147
|
+
input: "Find the current answer and return it as JSON.",
|
|
148
|
+
tools: [{ type: "web_search" }],
|
|
149
|
+
text: {
|
|
150
|
+
verbosity: "low",
|
|
151
|
+
format: {
|
|
152
|
+
type: "json_schema",
|
|
153
|
+
name: "sourced_answer",
|
|
154
|
+
strict: true,
|
|
155
|
+
schema: {
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: { answer: { type: "string" } },
|
|
158
|
+
required: ["answer"],
|
|
159
|
+
additionalProperties: false,
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
prompt_cache_key: "answer-policy-v1",
|
|
164
|
+
prompt_cache_options: { mode: "implicit" },
|
|
165
|
+
compress: true,
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
console.log(response.output_text);
|
|
169
|
+
console.log(response.usage?.input_tokens_details?.cached_tokens);
|
|
170
|
+
```
|
|
171
|
+
|
|
126
172
|
The same resource exposes `models.list()` and the complete native batch
|
|
127
173
|
lifecycle. Batch creation generates the required idempotency key unless one is
|
|
128
174
|
provided:
|
|
@@ -368,6 +414,31 @@ export async function POST() {
|
|
|
368
414
|
|
|
369
415
|
`wrapOpenAI` preserves the model already supplied by the application. It does not invent a model mapping or fallback. Use the manual `withUsage` pattern when BLOCK or DOWNGRADE must control provider invocation, model selection, reasoning effort, or search tools.
|
|
370
416
|
|
|
417
|
+
Starting in `@usagetap/sdk` 1.6.0, the Anthropic adapter preserves both
|
|
418
|
+
streaming forms. Use
|
|
419
|
+
`messages.create({ stream: true })` for the lower-level async iterable, or use
|
|
420
|
+
the synchronous `messages.stream()` helper when the application relies on
|
|
421
|
+
events and final-message accumulation:
|
|
422
|
+
|
|
423
|
+
```ts
|
|
424
|
+
const stream = anthropic.messages
|
|
425
|
+
.stream({
|
|
426
|
+
model: "claude-sonnet-4-5",
|
|
427
|
+
max_tokens: 512,
|
|
428
|
+
messages: [{ role: "user", content: "Stream it" }],
|
|
429
|
+
})
|
|
430
|
+
.on("text", (text) => process.stdout.write(text));
|
|
431
|
+
|
|
432
|
+
const message = await stream.finalMessage();
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
`messages.stream()` still returns Anthropic's `MessageStream` immediately and
|
|
436
|
+
retains `.on()`, async iteration, `.abort()`, `.done()`, `.finalText()`, and
|
|
437
|
+
`.finalMessage()`. UsageTap begins metering before the provider request and
|
|
438
|
+
finalizes once when the underlying stream completes, fails, or is aborted.
|
|
439
|
+
Wrapped `messages.create()` results also retain Anthropic's `.withResponse()`
|
|
440
|
+
and `.asResponse()` helpers.
|
|
441
|
+
|
|
371
442
|
### Overriding usage context per request
|
|
372
443
|
|
|
373
444
|
You can override the UsageTap begin payload on a per-call basis via the `usageTap` option:
|
|
@@ -393,7 +464,12 @@ For streaming calls created with `{ stream: true }`, UsageTap automatically calc
|
|
|
393
464
|
|
|
394
465
|
### responses.create support
|
|
395
466
|
|
|
396
|
-
The wrapper also instruments `openai.responses.create`, preserves
|
|
467
|
+
The wrapper also instruments `openai.responses.create`, preserves text controls,
|
|
468
|
+
tools, prompt-cache controls and breakpoints through compression, and records
|
|
469
|
+
cache reads, cache writes, reasoning tokens, and completed web-search calls.
|
|
470
|
+
Install OpenAI SDK 7.5 or newer when you want its native TypeScript definitions
|
|
471
|
+
for the latest Responses fields; the UsageTap Gateway resource has its own types
|
|
472
|
+
and does not require the OpenAI package.
|
|
397
473
|
|
|
398
474
|
### OpenRouter support
|
|
399
475
|
|
|
@@ -540,6 +616,11 @@ const wrappedFetch = wrapFetch(usageTap, {
|
|
|
540
616
|
feature: "chat",
|
|
541
617
|
requested: { standard: true, premium: true, search: true, reasoningLevel: "MEDIUM" },
|
|
542
618
|
},
|
|
619
|
+
onMeteringError: ({ stage, callId, error }) => {
|
|
620
|
+
console.error("UsageTap metering failed", { stage, callId, error });
|
|
621
|
+
},
|
|
622
|
+
// Set true when an unmetered vendor response must fail the application call.
|
|
623
|
+
strictMetering: false,
|
|
543
624
|
});
|
|
544
625
|
|
|
545
626
|
const openai = new OpenAI({
|
|
@@ -557,7 +638,7 @@ const completion = await openai.chat.completions.create({
|
|
|
557
638
|
});
|
|
558
639
|
```
|
|
559
640
|
|
|
560
|
-
`wrapFetch` detects OpenAI API endpoints, handles streaming and non-streaming responses, and automatically extracts usage data. It preserves the application's model. If limits must control provider selection, use an explicit begin decision before this layer. You can override metering context per request using special headers:
|
|
641
|
+
`wrapFetch` detects OpenAI API endpoints, handles streaming and non-streaming responses, requests final usage for chat streams, and automatically extracts usage data. It preserves the application's model. If limits must control provider selection, use an explicit begin decision before this layer. Use `onMeteringError` to export request parsing, begin, or end failures after SDK retries are exhausted. Set `strictMetering` when those failures should reject the application call. You can override metering context per request using special headers; the wrapper consumes these headers and removes them before calling the provider:
|
|
561
642
|
|
|
562
643
|
```ts
|
|
563
644
|
await openai.chat.completions.create(
|
|
@@ -625,6 +706,48 @@ const { begin, end, vendor, endUsage } = envelope.data;
|
|
|
625
706
|
- Non-2xx vendor responses still trigger `call_end`; the envelope returns `CALL_VENDOR_WARNING` alongside vendor error metadata.
|
|
626
707
|
- The canonical media type `application/vnd.usagetap.v1+json` is required; the SDK already sends this header automatically when you rely on `UsageTapClient`.
|
|
627
708
|
|
|
709
|
+
### Retrieve finalized call pricing (API-only)
|
|
710
|
+
|
|
711
|
+
An external server can retrieve the stored result later with `GET
|
|
712
|
+
/calls/{callId}`. Use a server API key containing `usage:read`; do not expose
|
|
713
|
+
the key in browser code.
|
|
714
|
+
|
|
715
|
+
```ts
|
|
716
|
+
const response = await fetch(
|
|
717
|
+
`${baseUrl}/calls/${encodeURIComponent(callId)}`,
|
|
718
|
+
{
|
|
719
|
+
method: "GET",
|
|
720
|
+
headers: {
|
|
721
|
+
Authorization: `Bearer ${process.env.USAGETAP_API_KEY}`,
|
|
722
|
+
Accept: "application/vnd.usagetap.v1+json",
|
|
723
|
+
},
|
|
724
|
+
},
|
|
725
|
+
);
|
|
726
|
+
|
|
727
|
+
const envelope = await response.json();
|
|
728
|
+
if (!response.ok || envelope.result.status !== "ACCEPTED") {
|
|
729
|
+
throw new Error(`UsageTap call lookup failed: ${envelope.result.code}`);
|
|
730
|
+
}
|
|
731
|
+
if (envelope.data.pricingStatus !== "FINAL") {
|
|
732
|
+
throw new Error(`Call pricing is ${envelope.data.pricingStatus}`);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
const providerCostUsd = envelope.data.costUSD;
|
|
736
|
+
const customerChargeUsd = envelope.data.payg.chargedUsd;
|
|
737
|
+
const customerId = envelope.data.customerId;
|
|
738
|
+
const customerUserId = envelope.data.customerUserId; // string or null
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
`pricingStatus` is `PENDING` while the call is open and `UNAVAILABLE` when a
|
|
742
|
+
completed call could not resolve model pricing. Only treat `costUSD` as final
|
|
743
|
+
when the status is `FINAL`.
|
|
744
|
+
|
|
745
|
+
The response includes only the stable customer identifiers recorded on the
|
|
746
|
+
call: `customerId` and nullable `customerUserId`. Use opaque, non-PII values
|
|
747
|
+
for both. Customer and end-user names or emails, billing-provider identifiers,
|
|
748
|
+
`organizationId`, and the internal `orgIdCustomerId` composite key are not
|
|
749
|
+
returned.
|
|
750
|
+
|
|
628
751
|
## Exports
|
|
629
752
|
|
|
630
753
|
Key exports from `@usagetap/sdk`:
|
|
@@ -686,9 +809,9 @@ console.log("New subscription:", result.data.subscription);
|
|
|
686
809
|
```
|
|
687
810
|
|
|
688
811
|
**Strategy options:**
|
|
689
|
-
- `IMMEDIATE_RESET`: Switch plan
|
|
690
|
-
- `IMMEDIATE_PRORATED`: Switch
|
|
691
|
-
- `AT_NEXT_REPLENISH`:
|
|
812
|
+
- `IMMEDIATE_RESET`: Switch immediately, grant the target plan's full allowances, and start a new replenishment cycle (default when the SDK option is omitted)
|
|
813
|
+
- `IMMEDIATE_PRORATED`: Switch immediately, preserve usage already consumed, adjust remaining allowances to the target limits, and keep the current replenishment date
|
|
814
|
+
- `AT_NEXT_REPLENISH`: Keep the current plan until its existing scheduled replenishment, then switch
|
|
692
815
|
|
|
693
816
|
The response includes the updated subscription details, including the new plan version, limits, and next replenishment timestamp. If `strategy: "AT_NEXT_REPLENISH"` is used, the `subscription.pending` field will indicate the scheduled plan change.
|
|
694
817
|
|
|
@@ -715,7 +838,7 @@ Custom meters allow you to track usage beyond standard LLM metrics—ideal for a
|
|
|
715
838
|
const result = await usageTap.incrementCustomMeter({
|
|
716
839
|
customerId: "cust_123",
|
|
717
840
|
customerUserId: currentUser.id,
|
|
718
|
-
meterSlot: "CUSTOM1", // or "CUSTOM2"
|
|
841
|
+
meterSlot: "CUSTOM1", // or "CUSTOM2" or "AGENTIC_API"
|
|
719
842
|
amount: 5,
|
|
720
843
|
feature: "agent_actions",
|
|
721
844
|
tags: ["workflow_automation"],
|
|
@@ -735,13 +858,13 @@ console.log("Blocked:", result.data.blocked);
|
|
|
735
858
|
- `customerId` (string, required): Customer identifier
|
|
736
859
|
- `customerUserId` (string, optional): Stable identifier for the end user responsible for the event
|
|
737
860
|
- `customerUserName` and `customerUserEmail` (string, optional): Display fields for live activity
|
|
738
|
-
- `meterSlot` ("CUSTOM1" | "CUSTOM2", required): Which
|
|
861
|
+
- `meterSlot` ("CUSTOM1" | "CUSTOM2" | "AGENTIC_API", required): Which meter to increment
|
|
739
862
|
- `amount` (number, required): Positive number to decrement from quota
|
|
740
863
|
- `feature` (string, optional): Feature identifier for tracking
|
|
741
864
|
- `tags` (string[], optional): Tags for categorization
|
|
742
865
|
- `metadata` (object, optional): Additional metadata
|
|
743
866
|
|
|
744
|
-
The method returns the updated meter snapshot showing remaining quota, limits, and usage. If the
|
|
867
|
+
The method returns the updated meter snapshot showing remaining quota, limits, and usage. If usage exceeds the allocation and eligible overage funding, it returns `data.blocked: true`. The SDK does not throw for this accepted usage report; your application must enforce the flag.
|
|
745
868
|
|
|
746
869
|
**Use cases:**
|
|
747
870
|
|
|
@@ -749,10 +872,11 @@ The method returns the updated meter snapshot showing remaining quota, limits, a
|
|
|
749
872
|
// Track agent tool invocations
|
|
750
873
|
await usageTap.incrementCustomMeter({
|
|
751
874
|
customerId: "cust_123",
|
|
752
|
-
meterSlot: "
|
|
875
|
+
meterSlot: "AGENTIC_API",
|
|
753
876
|
amount: 1,
|
|
754
877
|
feature: "agent.tool_call",
|
|
755
878
|
tags: ["web_search"],
|
|
879
|
+
metadata: { kind: "mcp", serverName: "search", toolName: "web_search" },
|
|
756
880
|
});
|
|
757
881
|
|
|
758
882
|
// Track document processing (10 pages)
|
|
@@ -767,20 +891,26 @@ await usageTap.incrementCustomMeter({
|
|
|
767
891
|
// Track external API calls
|
|
768
892
|
await usageTap.incrementCustomMeter({
|
|
769
893
|
customerId: "cust_789",
|
|
770
|
-
meterSlot: "
|
|
894
|
+
meterSlot: "AGENTIC_API",
|
|
771
895
|
amount: 1,
|
|
772
896
|
feature: "external_api.maps",
|
|
773
897
|
tags: ["geocoding"],
|
|
898
|
+
metadata: { kind: "api", method: "GET", endpoint: "/v1/geocode" },
|
|
774
899
|
});
|
|
775
900
|
```
|
|
776
901
|
|
|
902
|
+
For Agentic & API Calls, use `metadata.toolName` (and optionally
|
|
903
|
+
`metadata.serverName`) for MCP operations, or `metadata.endpoint` and
|
|
904
|
+
`metadata.method` for HTTP APIs. Live View displays these values and removes URL
|
|
905
|
+
query strings from endpoint labels.
|
|
906
|
+
|
|
777
907
|
**Important notes:**
|
|
778
908
|
|
|
779
909
|
1. Custom meters must be enabled in the customer's usage plan
|
|
780
|
-
2.
|
|
781
|
-
3.
|
|
782
|
-
4.
|
|
783
|
-
5. Unlimited meters
|
|
910
|
+
2. Report a positive safe integer quantity. Usage consumes allocation, then eligible purchased meter credits and/or PAYG funding. The last included unit is allowed.
|
|
911
|
+
3. Unfunded usage is recorded with `blocked: true`; the application must enforce that flag. LLM `BLOCK`/`DOWNGRADE` policies do not apply to meter reports.
|
|
912
|
+
4. PAYG overages require enabled PAYG and a configured single or graduated price. Settlement is asynchronous and does not reserve dollar credit or impose a rolling rate limit.
|
|
913
|
+
5. Unlimited meters still record events for analytics but do not consume allocation or charge overages.
|
|
784
914
|
|
|
785
915
|
## Response envelope (canonical only)
|
|
786
916
|
|
|
@@ -875,7 +1005,7 @@ UsageTap responds exclusively with the canonical `{ result, data, correlationId
|
|
|
875
1005
|
- `meters` is a per-counter snapshot including remaining quotas, total limits, usage to date, and convenience ratios. `remainingRatios` mirrors the same information in a compact map for quick lookups.
|
|
876
1006
|
- `subscription` contains the active plan identity, versioning, and upcoming replenishment timestamps so you can render customer-facing UI without querying Dynamo yourself.
|
|
877
1007
|
- `models` surfaces per-organization vendor hints (e.g. standard vs. premium model shortlists).
|
|
878
|
-
- `idempotency` reveals the actual key that was persisted (`callId` mirrors this value). The SDK generates a unique key by default. With SDK auto-generation disabled, the backend derives a deterministic hash from organization, customer, feature, requested entitlements, call type,
|
|
1008
|
+
- `idempotency` reveals the actual key that was persisted (`callId` mirrors this value). The SDK generates a unique key by default. With SDK auto-generation disabled, the backend derives a deterministic hash from organization, customer, feature, requested entitlements, call type, and pricing mode; identical inputs can replay an earlier call.
|
|
879
1009
|
- `plan` and `balances` remain available alongside the core begin payload for backwards compatibility with earlier SDK versions.
|
|
880
1010
|
|
|
881
1011
|
### Example `call_end` success
|
|
@@ -898,7 +1028,7 @@ UsageTap responds exclusively with the canonical `{ result, data, correlationId
|
|
|
898
1028
|
"reasoningTokens": 0
|
|
899
1029
|
},
|
|
900
1030
|
"metered": {
|
|
901
|
-
"tokens":
|
|
1031
|
+
"tokens": 288,
|
|
902
1032
|
"calls": 1,
|
|
903
1033
|
"searches": 1
|
|
904
1034
|
},
|
|
@@ -939,7 +1069,15 @@ includes cache reads. Anthropic reports ordinary input, cache reads, and cache
|
|
|
939
1069
|
writes separately, so the Anthropic wrapper adds the three counters for
|
|
940
1070
|
`inputTokens` while retaining both cache subsets.
|
|
941
1071
|
|
|
942
|
-
`metered` is
|
|
1072
|
+
`metered.tokens` is the provider-reported output-token count. Input tokens,
|
|
1073
|
+
including cache reads and cache writes, remain recorded and part of provider
|
|
1074
|
+
cost but do not consume the plan's Standard Output Tokens or Premium Output
|
|
1075
|
+
Tokens allowance and are not sent to the corresponding Stripe token meters.
|
|
1076
|
+
Reasoning tokens are a breakdown of provider output and are not added again.
|
|
1077
|
+
|
|
1078
|
+
The persisted meter keys remain `standardTokens` and `premiumTokens` for API
|
|
1079
|
+
compatibility; they represent standard and premium output tokens in both plan
|
|
1080
|
+
limits and Stripe usage metering.
|
|
943
1081
|
|
|
944
1082
|
`spendVelocity` is aggregate-backed current UTC hour/day telemetry. UsageTap does not enforce limits from this section; `currentCallCostUsd` is included separately because aggregate updates are asynchronous.
|
|
945
1083
|
|