@atcn/sdk 1.4.0 → 1.5.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 +24 -8
- package/dist/builders.d.ts +7 -1
- package/dist/builders.js +4 -1
- package/dist/client.d.ts +53 -8
- package/dist/client.js +7 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/otel.d.ts +48 -0
- package/dist/otel.js +116 -0
- package/dist/subledger.d.ts +302 -19
- package/dist/subledger.js +11 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,25 +1,41 @@
|
|
|
1
1
|
# @atcn/sdk
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The TypeScript SDK for [ATCN](https://github.com/fadnisnikhil/atcn), a cost record for AI agent jobs that anyone can verify. Use it to:
|
|
4
4
|
|
|
5
|
-
- **
|
|
6
|
-
- **
|
|
7
|
-
- **
|
|
8
|
-
|
|
5
|
+
- **check signed documents offline:** task closures, provider receipts and closure packages, with no network calls;
|
|
6
|
+
- **record jobs** (tasks, delegations, charges, estimates, holds) through a hosted ATCN API;
|
|
7
|
+
- **sign** obligation events, provider response statements and webhooks.
|
|
8
|
+
|
|
9
|
+
The same package is also published as [`atcn-sdk`](https://www.npmjs.com/package/atcn-sdk).
|
|
9
10
|
|
|
10
11
|
```bash
|
|
11
12
|
npm install @atcn/sdk
|
|
12
13
|
```
|
|
13
14
|
|
|
15
|
+
## Verify a closure someone sent you
|
|
16
|
+
|
|
14
17
|
```ts
|
|
18
|
+
import { readFileSync } from "node:fs";
|
|
15
19
|
import { verifySubledgerDocument } from "@atcn/sdk";
|
|
16
20
|
|
|
21
|
+
const closure = JSON.parse(readFileSync("task-closure.json", "utf8"));
|
|
22
|
+
const trustedKeys = JSON.parse(readFileSync("keys.json", "utf8")).items;
|
|
23
|
+
|
|
17
24
|
const report = verifySubledgerDocument(closure, { trustedKeys });
|
|
18
25
|
console.log(report.valid ? "VALID" : report.checks.filter((c) => !c.ok));
|
|
19
26
|
```
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
`report.checks` lists every check by name with its details, so a failure says exactly what doesn't add up. To try it without writing a closure first, run `npx @atcn/local-runner demo` and point this at the files it prints.
|
|
29
|
+
|
|
30
|
+
## What's inside
|
|
31
|
+
|
|
32
|
+
- **Offline verifiers.** `verifySubledgerDocument` checks task closures and receipts, and `verifyClosurePackage` checks obligation closure packages. Clearing verdicts are checked by `verifyClearingVerdict` in [`@atcn/core`](https://www.npmjs.com/package/@atcn/core).
|
|
33
|
+
- **Signed estimates and outcomes.** `buildExpectationStatement` and `signExpectation` let a provider sign its estimate or hold; `buildOutcomeStatement` and `signOutcomeStatement` let it sign how a task ended.
|
|
34
|
+
- **API clients.** `SubledgerClient` and its `CaptureQueue` record tasks, delegations and charges. `AtcnClient` is for obligations, and `ReceiptLinkClient` is for providers. They need an ATCN API at `baseUrl`; the hosted API is not open for signup yet.
|
|
35
|
+
- **Signing.** `EventSigner` signs obligation events. `buildTerms`, `termsData`, `acceptanceData` and `buildEvidenceEnvelope` build their contents.
|
|
36
|
+
- **Webhooks and response statements.** `verifyWebhook` and `signWebhook` handle webhook signatures. `buildResponseStatement`, `signStatement` and `verifyStatementSignature` handle provider response statements.
|
|
37
|
+
- **Agent traces.** `traceFromOtelSpans` turns an OpenTelemetry GenAI span export into an ATCN trace.
|
|
22
38
|
|
|
23
|
-
`npx atcn init` records whether this machine shares anonymous usage metrics. Reporting is off by default and needs `ATCN_USAGE_URL`; see [
|
|
39
|
+
`npx atcn init` records whether this machine shares anonymous usage metrics. Reporting is off by default and needs `ATCN_USAGE_URL`; see [usage data](https://github.com/fadnisnikhil/atcn/blob/main/docs/USAGE_DATA.md).
|
|
24
40
|
|
|
25
|
-
|
|
41
|
+
Source, docs and examples: [github.com/fadnisnikhil/atcn](https://github.com/fadnisnikhil/atcn). Apache-2.0.
|
package/dist/builders.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Deliverable, type EvidenceEnvelope, type ObligationTerms, type PolicyTemplate, type SkillRef } from "@atcn/schema";
|
|
1
|
+
import { type Deliverable, type EvidenceEnvelope, type ObligationTerms, type PolicyTemplate, type Pricing, type RefundTerms, type SkillRef, type WitnessPolicy } from "@atcn/schema";
|
|
2
2
|
export interface TermsInput {
|
|
3
3
|
parentObligationId?: string | null;
|
|
4
4
|
principalId: string;
|
|
@@ -24,6 +24,12 @@ export interface TermsInput {
|
|
|
24
24
|
verifierAgentIds?: string[];
|
|
25
25
|
/** The skill the counterparty performs (for A2A, the AgentSkill id). Produces schema_version 1.1 terms. */
|
|
26
26
|
skill?: SkillRef;
|
|
27
|
+
/** Usage prices for the usage_cost verifier. Produces schema_version 1.2 terms. */
|
|
28
|
+
pricing?: Pricing;
|
|
29
|
+
/** What happens on failure or timeout, and the post-settlement refund budget. Produces schema_version 1.2 terms. */
|
|
30
|
+
refundTerms?: RefundTerms;
|
|
31
|
+
/** Independent witnesses the witness_quorum verifier requires. Produces schema_version 1.2 terms. */
|
|
32
|
+
witnessPolicy?: WitnessPolicy;
|
|
27
33
|
}
|
|
28
34
|
/** Builds version-1 obligation terms with sensible defaults (7-day deadline, 1-day offer window). */
|
|
29
35
|
export declare function buildTerms(input: TermsInput): ObligationTerms;
|
package/dist/builders.js
CHANGED
|
@@ -4,7 +4,7 @@ const DAY_MS = 24 * 3600 * 1000;
|
|
|
4
4
|
export function buildTerms(input) {
|
|
5
5
|
const now = Date.now();
|
|
6
6
|
return {
|
|
7
|
-
schema_version: input.skill ? "1.1" : "1.0",
|
|
7
|
+
schema_version: input.pricing || input.refundTerms || input.witnessPolicy ? "1.2" : input.skill ? "1.1" : "1.0",
|
|
8
8
|
obligation_id: newId("obligation"),
|
|
9
9
|
terms_version: 1,
|
|
10
10
|
parent_obligation_id: input.parentObligationId ?? null,
|
|
@@ -28,6 +28,9 @@ export function buildTerms(input) {
|
|
|
28
28
|
verifier_agent_ids: input.verifierAgentIds ?? [],
|
|
29
29
|
issued_at: new Date(now).toISOString(),
|
|
30
30
|
...(input.skill ? { skill: input.skill } : {}),
|
|
31
|
+
...(input.pricing ? { pricing: input.pricing } : {}),
|
|
32
|
+
...(input.refundTerms ? { refund_terms: input.refundTerms } : {}),
|
|
33
|
+
...(input.witnessPolicy ? { witness_policy: input.witnessPolicy } : {}),
|
|
31
34
|
};
|
|
32
35
|
}
|
|
33
36
|
/** Data for obligation.created / obligation.offered / obligation.amended events. */
|
package/dist/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ClearingDecision, EventPayload, PublicKeyRecord, Signed } from "@atcn/schema";
|
|
1
|
+
import type { ClearingDecision, ClearingVerdict, ClosurePackage, EventPayload, PublicKeyRecord, Signed } from "@atcn/schema";
|
|
2
2
|
export declare class AtcnApiError extends Error {
|
|
3
3
|
readonly status: number;
|
|
4
4
|
readonly code: string;
|
|
@@ -9,7 +9,7 @@ export declare class AtcnApiError extends Error {
|
|
|
9
9
|
constructor(status: number, code: string, message: string, reason: string | undefined, retryable: boolean, correlationId: string | undefined, details: unknown);
|
|
10
10
|
}
|
|
11
11
|
/** Must equal this package's version in package.json (checked by a test). */
|
|
12
|
-
export declare const SDK_VERSION = "1.
|
|
12
|
+
export declare const SDK_VERSION = "1.5.0";
|
|
13
13
|
/** Names the SDK and its version on every request, so the API operator can count SDK versions in use. Nothing else is sent. */
|
|
14
14
|
export declare const SDK_HEADER = "atcn-sdk";
|
|
15
15
|
export interface ClientOptions {
|
|
@@ -105,6 +105,14 @@ export declare class AtcnClient {
|
|
|
105
105
|
listDecisions(obligationId: string): Promise<{
|
|
106
106
|
items: ClearingDecision[];
|
|
107
107
|
}>;
|
|
108
|
+
/** The decision in effect as a signed, record-only verdict, with the closure package it was read from (verifyClearingVerdict). */
|
|
109
|
+
clearingVerdict(obligationId: string, escrow?: {
|
|
110
|
+
rail: string;
|
|
111
|
+
escrow_ref: string;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
verdict: ClearingVerdict;
|
|
114
|
+
closure_package: ClosurePackage;
|
|
115
|
+
}>;
|
|
108
116
|
finalize(decisionId: string, idempotencyKey?: string): Promise<Json>;
|
|
109
117
|
openDispute(decisionId: string, signed: SignedEvent): Promise<Json>;
|
|
110
118
|
reviewDispute(disputeId: string, signed: SignedEvent): Promise<Json>;
|
|
@@ -131,7 +139,7 @@ export declare class AtcnClient {
|
|
|
131
139
|
}>;
|
|
132
140
|
exportClosurePackage(obligationId: string): Promise<{
|
|
133
141
|
payload: {
|
|
134
|
-
package_version: "1.0";
|
|
142
|
+
package_version: "1.0" | "1.1";
|
|
135
143
|
generated_at: string;
|
|
136
144
|
root_obligation_id: string;
|
|
137
145
|
requested_obligation_id: string;
|
|
@@ -140,7 +148,7 @@ export declare class AtcnClient {
|
|
|
140
148
|
parent_obligation_id: string | null;
|
|
141
149
|
redacted: boolean;
|
|
142
150
|
effective_terms: {
|
|
143
|
-
schema_version: "1.0" | "1.1";
|
|
151
|
+
schema_version: "1.0" | "1.1" | "1.2";
|
|
144
152
|
obligation_id: string;
|
|
145
153
|
terms_version: number;
|
|
146
154
|
parent_obligation_id: string | null;
|
|
@@ -186,6 +194,33 @@ export declare class AtcnClient {
|
|
|
186
194
|
skill_id: string;
|
|
187
195
|
agent_card_url?: string | undefined;
|
|
188
196
|
} | undefined;
|
|
197
|
+
pricing?: {
|
|
198
|
+
rates: {
|
|
199
|
+
meter: "input_tokens" | "output_tokens" | "cache_read_input_tokens" | "model_call" | "tool_call" | "a2a_call";
|
|
200
|
+
price_numerator: number;
|
|
201
|
+
price_denominator: number;
|
|
202
|
+
model?: {
|
|
203
|
+
provider: string;
|
|
204
|
+
name: string;
|
|
205
|
+
} | undefined;
|
|
206
|
+
tool_name?: string | undefined;
|
|
207
|
+
}[];
|
|
208
|
+
tolerance_bps: number;
|
|
209
|
+
fixed_minor?: number | undefined;
|
|
210
|
+
} | undefined;
|
|
211
|
+
refund_terms?: {
|
|
212
|
+
on_failure: "dispute" | "refund";
|
|
213
|
+
on_timeout: "dispute" | "refund";
|
|
214
|
+
after_settlement: {
|
|
215
|
+
cap_minor: number;
|
|
216
|
+
window_seconds: number;
|
|
217
|
+
};
|
|
218
|
+
} | undefined;
|
|
219
|
+
witness_policy?: {
|
|
220
|
+
min_independent_witnesses: number;
|
|
221
|
+
independence: "distinct_verified_domain";
|
|
222
|
+
witness_agent_ids?: string[] | undefined;
|
|
223
|
+
} | undefined;
|
|
189
224
|
} | null;
|
|
190
225
|
effective_terms_digest: string | null;
|
|
191
226
|
state: string;
|
|
@@ -228,7 +263,7 @@ export declare class AtcnClient {
|
|
|
228
263
|
task_type: string;
|
|
229
264
|
description: string;
|
|
230
265
|
evidence_admissibility: {
|
|
231
|
-
allowed_producers: ("issuer" | "counterparty" | "verifier")[];
|
|
266
|
+
allowed_producers: ("issuer" | "counterparty" | "verifier" | "witness")[];
|
|
232
267
|
require_digest_match: boolean;
|
|
233
268
|
};
|
|
234
269
|
required_evidence: string[];
|
|
@@ -313,7 +348,7 @@ export declare class AtcnClient {
|
|
|
313
348
|
amount_minor: number;
|
|
314
349
|
outcome: "insufficient_evidence" | "disputed" | "accepted" | "rejected";
|
|
315
350
|
reasons: {
|
|
316
|
-
code: "invalid_evidence" | "missing_evidence" | "failed_criteria" | "verifier_unavailable" | "probabilistic_review_required" | "partial_not_permitted" | "passed" | "dispute_amended" | "dispute_upheld";
|
|
351
|
+
code: "invalid_evidence" | "missing_evidence" | "failed_criteria" | "verifier_unavailable" | "probabilistic_review_required" | "partial_not_permitted" | "passed" | "dispute_amended" | "dispute_upheld" | "failure_terms_dispute" | "conflicting_attestations" | "witness_quorum_not_met";
|
|
317
352
|
check_id?: string | undefined;
|
|
318
353
|
evidence_type?: string | undefined;
|
|
319
354
|
detail?: string | undefined;
|
|
@@ -366,7 +401,7 @@ export declare class AtcnClient {
|
|
|
366
401
|
adapter: "manual" | "sandbox" | "stripe";
|
|
367
402
|
idempotency_key: string;
|
|
368
403
|
expires_at: string;
|
|
369
|
-
status: "unknown" | "failed" | "refunded" | "settled" | "returned" | "submitted" | "processing";
|
|
404
|
+
status: "unknown" | "pending_finality" | "failed" | "refunded" | "settled" | "returned" | "submitted" | "processing";
|
|
370
405
|
created_at: string;
|
|
371
406
|
}[];
|
|
372
407
|
settlement_events: {
|
|
@@ -376,12 +411,22 @@ export declare class AtcnClient {
|
|
|
376
411
|
provider_event_id: string;
|
|
377
412
|
provider_reference: string;
|
|
378
413
|
provider_status: string;
|
|
379
|
-
normalized_status: "unknown" | "failed" | "refunded" | "settled" | "returned" | "submitted" | "processing";
|
|
414
|
+
normalized_status: "unknown" | "pending_finality" | "failed" | "refunded" | "settled" | "returned" | "submitted" | "processing";
|
|
380
415
|
currency: string;
|
|
381
416
|
amount_minor: number;
|
|
382
417
|
raw_json: string;
|
|
383
418
|
reported_at: string;
|
|
384
419
|
}[];
|
|
420
|
+
attestations?: {
|
|
421
|
+
evidence_id: string;
|
|
422
|
+
content: string;
|
|
423
|
+
}[] | undefined;
|
|
424
|
+
attestation_conflicts?: {
|
|
425
|
+
kind: "disputed" | "equivocation" | "disagreement" | "execution_mismatch";
|
|
426
|
+
subject: string;
|
|
427
|
+
attestation_digests: string[];
|
|
428
|
+
signers: string[];
|
|
429
|
+
}[] | undefined;
|
|
385
430
|
};
|
|
386
431
|
signature: {
|
|
387
432
|
key_id: string;
|
package/dist/client.js
CHANGED
|
@@ -16,7 +16,7 @@ export class AtcnApiError extends Error {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
/** Must equal this package's version in package.json (checked by a test). */
|
|
19
|
-
export const SDK_VERSION = "1.
|
|
19
|
+
export const SDK_VERSION = "1.5.0";
|
|
20
20
|
/** Names the SDK and its version on every request, so the API operator can count SDK versions in use. Nothing else is sent. */
|
|
21
21
|
export const SDK_HEADER = "atcn-sdk";
|
|
22
22
|
/** Thin HTTP client for the ATCN API. Every mutating call carries an Idempotency-Key. */
|
|
@@ -126,6 +126,12 @@ export class AtcnClient {
|
|
|
126
126
|
listDecisions(obligationId) {
|
|
127
127
|
return this.request("GET", `/v1/obligations/${obligationId}/decisions`);
|
|
128
128
|
}
|
|
129
|
+
/** The decision in effect as a signed, record-only verdict, with the closure package it was read from (verifyClearingVerdict). */
|
|
130
|
+
clearingVerdict(obligationId, escrow) {
|
|
131
|
+
return this.request("GET", `/v1/obligations/${obligationId}/verdict`, undefined, {
|
|
132
|
+
query: { rail: escrow?.rail, escrow_ref: escrow?.escrow_ref },
|
|
133
|
+
});
|
|
134
|
+
}
|
|
129
135
|
finalize(decisionId, idempotencyKey) {
|
|
130
136
|
return this.request("POST", `/v1/decisions/${decisionId}/finalize`, undefined, { idempotencyKey });
|
|
131
137
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export { EventSigner, type SignerIdentity } from "./signer.js";
|
|
2
2
|
export { buildTerms, termsData, acceptanceData, buildEvidenceEnvelope, type TermsInput, type EnvelopeInput } from "./builders.js";
|
|
3
3
|
export { AtcnClient, AtcnApiError, SDK_HEADER, SDK_VERSION, type ClientOptions, type RequestOptions } from "./client.js";
|
|
4
|
-
export { verifyClosurePackage, REFERENCE_POLICIES, CODE_CHANGE_POLICY_V1, CODE_CHANGE_POLICY_V1_1, CODE_CHANGE_SUBTASK_POLICY_V1 } from "@atcn/core";
|
|
4
|
+
export { verifyClosurePackage, REFERENCE_POLICIES, CODE_CHANGE_POLICY_V1, CODE_CHANGE_POLICY_V1_1, CODE_CHANGE_SUBTASK_POLICY_V1, AGENT_USAGE_POLICY_V1 } from "@atcn/core";
|
|
5
5
|
export { SubledgerClient, ReceiptLinkClient, CaptureQueue, ext, stableKey, type CaptureOperation, type CaptureQueueOptions, type FlushResult } from "./subledger.js";
|
|
6
6
|
export { verifySubledgerDocument, buildResponseStatement, signStatement, verifyStatementSignature } from "@atcn/subledger";
|
|
7
|
+
export { buildExpectationStatement, signExpectation, verifyExpectationSignature, type ExpectationStatement, type ExpectationStatementInput } from "@atcn/subledger";
|
|
8
|
+
export { buildOutcomeStatement, signOutcomeStatement, verifyOutcomeSignature, type EvidenceRef, type OutcomeStatement, type SignedClaimType } from "@atcn/subledger";
|
|
7
9
|
export { verifyWebhook, signWebhook, WEBHOOK_SIGNATURE_HEADER, generateKeyPair, digestOf, sha256Digest, canonicalize, executionBinding } from "@atcn/schema";
|
|
10
|
+
export { traceDigest, summarizeTrace, traceProblems, checkTrace, expectedCostFromUsage, allowedDifference, usageCostDetails, type AgentTrace, type UsageSummary, type Pricing, type ExecutionDescriptor } from "@atcn/schema";
|
|
11
|
+
export { traceFromOtelSpans, OTEL_GENAI_CONVENTIONS, A2A_TASK_ID_ATTRIBUTE, type OtlpTraceExport, type OtelImportResult, type SkippedSpan } from "./otel.js";
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
export { EventSigner } from "./signer.js";
|
|
2
2
|
export { buildTerms, termsData, acceptanceData, buildEvidenceEnvelope } from "./builders.js";
|
|
3
3
|
export { AtcnClient, AtcnApiError, SDK_HEADER, SDK_VERSION } from "./client.js";
|
|
4
|
-
export { verifyClosurePackage, REFERENCE_POLICIES, CODE_CHANGE_POLICY_V1, CODE_CHANGE_POLICY_V1_1, CODE_CHANGE_SUBTASK_POLICY_V1 } from "@atcn/core";
|
|
4
|
+
export { verifyClosurePackage, REFERENCE_POLICIES, CODE_CHANGE_POLICY_V1, CODE_CHANGE_POLICY_V1_1, CODE_CHANGE_SUBTASK_POLICY_V1, AGENT_USAGE_POLICY_V1 } from "@atcn/core";
|
|
5
5
|
export { SubledgerClient, ReceiptLinkClient, CaptureQueue, ext, stableKey } from "./subledger.js";
|
|
6
6
|
export { verifySubledgerDocument, buildResponseStatement, signStatement, verifyStatementSignature } from "@atcn/subledger";
|
|
7
|
+
export { buildExpectationStatement, signExpectation, verifyExpectationSignature } from "@atcn/subledger";
|
|
8
|
+
export { buildOutcomeStatement, signOutcomeStatement, verifyOutcomeSignature } from "@atcn/subledger";
|
|
7
9
|
export { verifyWebhook, signWebhook, WEBHOOK_SIGNATURE_HEADER, generateKeyPair, digestOf, sha256Digest, canonicalize, executionBinding } from "@atcn/schema";
|
|
10
|
+
export { traceDigest, summarizeTrace, traceProblems, checkTrace, expectedCostFromUsage, allowedDifference, usageCostDetails } from "@atcn/schema";
|
|
11
|
+
export { traceFromOtelSpans, OTEL_GENAI_CONVENTIONS, A2A_TASK_ID_ATTRIBUTE } from "./otel.js";
|
package/dist/otel.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { type AgentTrace, type ExecutionBinding } from "@atcn/schema";
|
|
2
|
+
/**
|
|
3
|
+
* The OpenTelemetry GenAI conventions this mapping was written against. They are at "Development" status, so names may
|
|
4
|
+
* change; every attribute name used below is in this file only.
|
|
5
|
+
*/
|
|
6
|
+
export declare const OTEL_GENAI_CONVENTIONS = "OpenTelemetry semantic conventions 1.41.0, GenAI spans";
|
|
7
|
+
/** Not an OpenTelemetry attribute: set it on invoke_agent spans that call another agent over A2A, with the A2A task id. */
|
|
8
|
+
export declare const A2A_TASK_ID_ATTRIBUTE = "atcn.a2a.task_id";
|
|
9
|
+
interface OtlpAnyValue {
|
|
10
|
+
stringValue?: string;
|
|
11
|
+
intValue?: string | number;
|
|
12
|
+
doubleValue?: number;
|
|
13
|
+
boolValue?: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface OtlpSpan {
|
|
16
|
+
spanId?: string;
|
|
17
|
+
name?: string;
|
|
18
|
+
startTimeUnixNano?: string | number;
|
|
19
|
+
endTimeUnixNano?: string | number;
|
|
20
|
+
attributes?: {
|
|
21
|
+
key: string;
|
|
22
|
+
value?: OtlpAnyValue;
|
|
23
|
+
}[];
|
|
24
|
+
}
|
|
25
|
+
/** An OTLP JSON trace export: resourceSpans[].scopeSpans[].spans[]. */
|
|
26
|
+
export interface OtlpTraceExport {
|
|
27
|
+
resourceSpans?: {
|
|
28
|
+
scopeSpans?: {
|
|
29
|
+
spans?: OtlpSpan[];
|
|
30
|
+
}[];
|
|
31
|
+
}[];
|
|
32
|
+
}
|
|
33
|
+
export interface SkippedSpan {
|
|
34
|
+
span_id: string;
|
|
35
|
+
name: string;
|
|
36
|
+
reason: string;
|
|
37
|
+
}
|
|
38
|
+
export interface OtelImportResult {
|
|
39
|
+
trace: AgentTrace;
|
|
40
|
+
/** Spans that did not become steps, with the reason, so nothing is dropped silently. */
|
|
41
|
+
skipped: SkippedSpan[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Builds an AgentTrace for one run from an OTLP JSON export of GenAI spans. Steps are ordered by start time, then span
|
|
45
|
+
* id. Spans that are not model calls, tool calls or A2A calls are returned in `skipped` with the reason.
|
|
46
|
+
*/
|
|
47
|
+
export declare function traceFromOtelSpans(otlp: OtlpTraceExport, execution: ExecutionBinding): OtelImportResult;
|
|
48
|
+
export {};
|
package/dist/otel.js
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { AgentTraceSchema, TRACE_VERSION } from "@atcn/schema";
|
|
2
|
+
/**
|
|
3
|
+
* The OpenTelemetry GenAI conventions this mapping was written against. They are at "Development" status, so names may
|
|
4
|
+
* change; every attribute name used below is in this file only.
|
|
5
|
+
*/
|
|
6
|
+
export const OTEL_GENAI_CONVENTIONS = "OpenTelemetry semantic conventions 1.41.0, GenAI spans";
|
|
7
|
+
const MODEL_OPERATIONS = ["chat", "generate_content", "text_completion", "embeddings"];
|
|
8
|
+
/** Not an OpenTelemetry attribute: set it on invoke_agent spans that call another agent over A2A, with the A2A task id. */
|
|
9
|
+
export const A2A_TASK_ID_ATTRIBUTE = "atcn.a2a.task_id";
|
|
10
|
+
function attributes(span) {
|
|
11
|
+
const map = new Map();
|
|
12
|
+
for (const a of span.attributes ?? []) {
|
|
13
|
+
const v = a.value ?? {};
|
|
14
|
+
if (v.stringValue !== undefined)
|
|
15
|
+
map.set(a.key, v.stringValue);
|
|
16
|
+
else if (v.intValue !== undefined)
|
|
17
|
+
map.set(a.key, Number(v.intValue));
|
|
18
|
+
else if (v.doubleValue !== undefined)
|
|
19
|
+
map.set(a.key, v.doubleValue);
|
|
20
|
+
else if (v.boolValue !== undefined)
|
|
21
|
+
map.set(a.key, v.boolValue);
|
|
22
|
+
}
|
|
23
|
+
return map;
|
|
24
|
+
}
|
|
25
|
+
function text(attrs, key) {
|
|
26
|
+
const value = attrs.get(key);
|
|
27
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
28
|
+
}
|
|
29
|
+
function count(attrs, key) {
|
|
30
|
+
const value = attrs.get(key);
|
|
31
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
32
|
+
}
|
|
33
|
+
function isoFromNanos(nanos) {
|
|
34
|
+
if (nanos === undefined)
|
|
35
|
+
return undefined;
|
|
36
|
+
return new Date(Number(BigInt(nanos) / 1000000n)).toISOString();
|
|
37
|
+
}
|
|
38
|
+
function nanosOf(span) {
|
|
39
|
+
return span.startTimeUnixNano === undefined ? 0n : BigInt(span.startTimeUnixNano);
|
|
40
|
+
}
|
|
41
|
+
function stepFromSpan(span) {
|
|
42
|
+
const attrs = attributes(span);
|
|
43
|
+
const operation = text(attrs, "gen_ai.operation.name");
|
|
44
|
+
if (operation === undefined)
|
|
45
|
+
return "no gen_ai.operation.name";
|
|
46
|
+
const started_at = isoFromNanos(span.startTimeUnixNano);
|
|
47
|
+
const ended_at = isoFromNanos(span.endTimeUnixNano);
|
|
48
|
+
if (started_at === undefined || ended_at === undefined)
|
|
49
|
+
return "missing start or end time";
|
|
50
|
+
if (MODEL_OPERATIONS.includes(operation)) {
|
|
51
|
+
const provider = text(attrs, "gen_ai.provider.name");
|
|
52
|
+
const name = text(attrs, "gen_ai.response.model") ?? text(attrs, "gen_ai.request.model");
|
|
53
|
+
if (provider === undefined)
|
|
54
|
+
return "model call without gen_ai.provider.name";
|
|
55
|
+
if (name === undefined)
|
|
56
|
+
return "model call without gen_ai.response.model or gen_ai.request.model";
|
|
57
|
+
const input = count(attrs, "gen_ai.usage.input_tokens");
|
|
58
|
+
const output = count(attrs, "gen_ai.usage.output_tokens");
|
|
59
|
+
const cached = count(attrs, "gen_ai.usage.cache_read.input_tokens");
|
|
60
|
+
const upstream = text(attrs, "gen_ai.response.id");
|
|
61
|
+
return {
|
|
62
|
+
kind: "model_call",
|
|
63
|
+
started_at,
|
|
64
|
+
ended_at,
|
|
65
|
+
model: { provider, name },
|
|
66
|
+
...(input !== undefined || output !== undefined
|
|
67
|
+
? { usage: { input_tokens: input ?? 0, output_tokens: output ?? 0, ...(cached !== undefined ? { cache_read_input_tokens: cached } : {}) } }
|
|
68
|
+
: {}),
|
|
69
|
+
...(upstream !== undefined ? { upstream_ref: upstream } : {}),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
if (operation === "execute_tool") {
|
|
73
|
+
const name = text(attrs, "gen_ai.tool.name");
|
|
74
|
+
if (name === undefined)
|
|
75
|
+
return "tool call without gen_ai.tool.name";
|
|
76
|
+
const upstream = text(attrs, "gen_ai.tool.call.id");
|
|
77
|
+
return { kind: "tool_call", started_at, ended_at, tool: { name }, ...(upstream !== undefined ? { upstream_ref: upstream } : {}) };
|
|
78
|
+
}
|
|
79
|
+
if (operation === "invoke_agent") {
|
|
80
|
+
const taskId = text(attrs, A2A_TASK_ID_ATTRIBUTE);
|
|
81
|
+
if (taskId === undefined)
|
|
82
|
+
return `invoke_agent without ${A2A_TASK_ID_ATTRIBUTE}`;
|
|
83
|
+
const agentId = text(attrs, "gen_ai.agent.id");
|
|
84
|
+
return { kind: "a2a_call", started_at, ended_at, remote: { ...(agentId !== undefined ? { agent_id: agentId } : {}), task_id: taskId } };
|
|
85
|
+
}
|
|
86
|
+
return `operation ${operation} is not mapped`;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Builds an AgentTrace for one run from an OTLP JSON export of GenAI spans. Steps are ordered by start time, then span
|
|
90
|
+
* id. Spans that are not model calls, tool calls or A2A calls are returned in `skipped` with the reason.
|
|
91
|
+
*/
|
|
92
|
+
export function traceFromOtelSpans(otlp, execution) {
|
|
93
|
+
const spans = (otlp.resourceSpans ?? []).flatMap((r) => (r.scopeSpans ?? []).flatMap((s) => s.spans ?? []));
|
|
94
|
+
const ordered = [...spans].sort((a, b) => {
|
|
95
|
+
const at = nanosOf(a);
|
|
96
|
+
const bt = nanosOf(b);
|
|
97
|
+
if (at !== bt)
|
|
98
|
+
return at < bt ? -1 : 1;
|
|
99
|
+
const aid = a.spanId ?? "";
|
|
100
|
+
const bid = b.spanId ?? "";
|
|
101
|
+
return aid < bid ? -1 : aid > bid ? 1 : 0;
|
|
102
|
+
});
|
|
103
|
+
const steps = [];
|
|
104
|
+
const skipped = [];
|
|
105
|
+
for (const span of ordered) {
|
|
106
|
+
const step = stepFromSpan(span);
|
|
107
|
+
if (typeof step === "string")
|
|
108
|
+
skipped.push({ span_id: span.spanId ?? "", name: span.name ?? "", reason: step });
|
|
109
|
+
else
|
|
110
|
+
steps.push({ seq: steps.length, ...step });
|
|
111
|
+
}
|
|
112
|
+
if (steps.length === 0)
|
|
113
|
+
throw new Error("the export has no GenAI model, tool or A2A spans");
|
|
114
|
+
const trace = AgentTraceSchema.parse({ trace_version: TRACE_VERSION, execution, steps });
|
|
115
|
+
return { trace, skipped };
|
|
116
|
+
}
|
package/dist/subledger.d.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
|
-
import { type AllocationInputSchema, type AllocationRuleInputSchema, type AttestableField, type Correction, type DelegationEventInputSchema, type DelegationInputSchema, type EvidenceRef, type FinancialEventInput, type OperatorKeyRecord, type ProviderInputSchema, type ResponseType, type SignedClosure, type SignedReceipt, type TaskInputSchema } from "@atcn/subledger";
|
|
2
|
+
import { type AllocationInputSchema, type AllocationRuleInputSchema, type AttestableField, type CaptureGapInput, type Correction, type DelegationEventInputSchema, type DelegationInputSchema, type EvidenceRef, type ExpectationIssuer, type FinancialEventInput, type ImportField, type OperatorKeyRecord, type ProviderInputSchema, type RailAttestation, type ResponseType, type SignedClosure, type SignedReceipt, type TaskInputSchema } from "@atcn/subledger";
|
|
3
3
|
import { type AttestationRef, type ExecutionBinding } from "@atcn/schema";
|
|
4
4
|
import { AtcnClient, type ClientOptions } from "./client.js";
|
|
5
5
|
type Json = Record<string, unknown>;
|
|
6
6
|
type Opts = {
|
|
7
7
|
idempotencyKey?: string;
|
|
8
8
|
};
|
|
9
|
+
/**
|
|
10
|
+
* How the hosted importer reads a CSV export: key_columns is a comma-separated list of columns that identify a row,
|
|
11
|
+
* map names the export's column for an import field, and minor_digits is the decimal places of amount_major (default 2).
|
|
12
|
+
*/
|
|
13
|
+
type CsvImportOptions = {
|
|
14
|
+
kind?: "charge" | "invoice" | "estimate" | "hold";
|
|
15
|
+
source?: string;
|
|
16
|
+
key_columns?: string;
|
|
17
|
+
currency?: string;
|
|
18
|
+
issued_by?: ExpectationIssuer;
|
|
19
|
+
map?: Partial<Record<ImportField, string>>;
|
|
20
|
+
minor_digits?: number;
|
|
21
|
+
};
|
|
9
22
|
/** Caller-supplied references address records before their server IDs are known: ext("job-42"). */
|
|
10
23
|
export declare const ext: (externalRef: string) => string;
|
|
11
24
|
/** Idempotency key derived from the caller's stable references; long references are hashed to fit 8-200 chars. */
|
|
@@ -43,7 +56,20 @@ export declare class SubledgerClient {
|
|
|
43
56
|
match_id: string | null;
|
|
44
57
|
exception_ids: string[];
|
|
45
58
|
}>;
|
|
46
|
-
|
|
59
|
+
recordRailAttestation(input: {
|
|
60
|
+
attestation: RailAttestation;
|
|
61
|
+
source: string;
|
|
62
|
+
match?: Record<string, string>;
|
|
63
|
+
event_date?: string;
|
|
64
|
+
}, opts?: Opts): Promise<{
|
|
65
|
+
financial_event: Json;
|
|
66
|
+
deduplicated: boolean;
|
|
67
|
+
attributed?: boolean;
|
|
68
|
+
attribution: Json | null;
|
|
69
|
+
match_id: string | null;
|
|
70
|
+
exception_ids: string[];
|
|
71
|
+
}>;
|
|
72
|
+
importCsv(csv: string, opts?: Opts & CsvImportOptions): Promise<{
|
|
47
73
|
imported: number;
|
|
48
74
|
deduplicated: number;
|
|
49
75
|
rejected: number;
|
|
@@ -80,7 +106,7 @@ export declare class SubledgerClient {
|
|
|
80
106
|
}, opts?: Opts): Promise<Json>;
|
|
81
107
|
reportCaptureGap(taskId: string, gap: {
|
|
82
108
|
delegation_id?: string | null;
|
|
83
|
-
kind: "
|
|
109
|
+
kind: CaptureGapInput["kind"];
|
|
84
110
|
detail: string;
|
|
85
111
|
}, opts?: Opts): Promise<Json>;
|
|
86
112
|
closeTask(taskId: string, opts?: Opts): Promise<{
|
|
@@ -90,7 +116,7 @@ export declare class SubledgerClient {
|
|
|
90
116
|
getClosure(taskId: string, version?: number): Promise<{
|
|
91
117
|
payload: {
|
|
92
118
|
document_type: "atcn.subledger.closure";
|
|
93
|
-
schema_version: "1.
|
|
119
|
+
schema_version: "1.2" | "1.3" | "1.4" | "1.5";
|
|
94
120
|
closure_id: string;
|
|
95
121
|
version: number;
|
|
96
122
|
previous_closure_id: string | null;
|
|
@@ -112,6 +138,7 @@ export declare class SubledgerClient {
|
|
|
112
138
|
scope_ref: string | null;
|
|
113
139
|
retrospective: boolean;
|
|
114
140
|
created_at: string;
|
|
141
|
+
estimate_tolerance_bps?: number | undefined;
|
|
115
142
|
};
|
|
116
143
|
delegations: {
|
|
117
144
|
delegation_id: string;
|
|
@@ -145,6 +172,11 @@ export declare class SubledgerClient {
|
|
|
145
172
|
name: string;
|
|
146
173
|
version: string;
|
|
147
174
|
} | undefined;
|
|
175
|
+
additional_models?: {
|
|
176
|
+
provider: string;
|
|
177
|
+
name: string;
|
|
178
|
+
version: string;
|
|
179
|
+
}[] | undefined;
|
|
148
180
|
config_digest?: string | undefined;
|
|
149
181
|
};
|
|
150
182
|
protocol?: {
|
|
@@ -158,13 +190,40 @@ export declare class SubledgerClient {
|
|
|
158
190
|
agent_card_url?: string | undefined;
|
|
159
191
|
} | undefined;
|
|
160
192
|
} | undefined;
|
|
193
|
+
pricing?: {
|
|
194
|
+
rates: {
|
|
195
|
+
meter: "input_tokens" | "output_tokens" | "cache_read_input_tokens" | "model_call" | "tool_call" | "a2a_call";
|
|
196
|
+
price_numerator: number;
|
|
197
|
+
price_denominator: number;
|
|
198
|
+
model?: {
|
|
199
|
+
provider: string;
|
|
200
|
+
name: string;
|
|
201
|
+
} | undefined;
|
|
202
|
+
tool_name?: string | undefined;
|
|
203
|
+
}[];
|
|
204
|
+
tolerance_bps: number;
|
|
205
|
+
fixed_minor?: number | undefined;
|
|
206
|
+
} | undefined;
|
|
207
|
+
refund_terms?: {
|
|
208
|
+
on_failure: "dispute" | "refund";
|
|
209
|
+
on_timeout: "dispute" | "refund";
|
|
210
|
+
after_settlement: {
|
|
211
|
+
cap_minor: number;
|
|
212
|
+
window_seconds: number;
|
|
213
|
+
};
|
|
214
|
+
} | undefined;
|
|
215
|
+
witness_policy?: {
|
|
216
|
+
min_independent_witnesses: number;
|
|
217
|
+
independence: "distinct_verified_domain";
|
|
218
|
+
witness_provider_ids?: string[] | undefined;
|
|
219
|
+
} | undefined;
|
|
161
220
|
}[];
|
|
162
221
|
delivery_claims: {
|
|
163
222
|
event_id: string;
|
|
164
223
|
delegation_id: string;
|
|
165
224
|
type: "acceptance" | "completion" | "partial_completion" | "cancellation" | "provider_failure" | "terms_update" | "correction";
|
|
166
225
|
asserted_by: "provider" | "buyer" | "clearing_policy" | "dispute_reviewer" | "clearing_network";
|
|
167
|
-
assurance: ("expired" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked")[];
|
|
226
|
+
assurance: ("expired" | "rail_attested" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked" | "gateway_signed")[];
|
|
168
227
|
note: string | null;
|
|
169
228
|
evidence: {
|
|
170
229
|
uri: string;
|
|
@@ -176,11 +235,35 @@ export declare class SubledgerClient {
|
|
|
176
235
|
retrospective: boolean;
|
|
177
236
|
occurred_at: string;
|
|
178
237
|
recorded_at: string;
|
|
238
|
+
usage?: {
|
|
239
|
+
trace_digest: string;
|
|
240
|
+
summary: {
|
|
241
|
+
models: {
|
|
242
|
+
provider: string;
|
|
243
|
+
name: string;
|
|
244
|
+
calls: number;
|
|
245
|
+
input_tokens: number;
|
|
246
|
+
output_tokens: number;
|
|
247
|
+
cache_read_input_tokens: number;
|
|
248
|
+
}[];
|
|
249
|
+
tools: {
|
|
250
|
+
name: string;
|
|
251
|
+
calls: number;
|
|
252
|
+
}[];
|
|
253
|
+
a2a_calls: number;
|
|
254
|
+
};
|
|
255
|
+
} | undefined;
|
|
256
|
+
signer?: {
|
|
257
|
+
provider_id: string;
|
|
258
|
+
binding_id: string;
|
|
259
|
+
key_id: string;
|
|
260
|
+
value: string;
|
|
261
|
+
} | undefined;
|
|
179
262
|
}[];
|
|
180
263
|
financial_events: {
|
|
181
264
|
record: {
|
|
182
265
|
financial_event_id: string;
|
|
183
|
-
type: "
|
|
266
|
+
type: "refund" | "charge" | "invoice" | "estimate" | "hold" | "quote" | "payment_reported" | "reversal" | "fee" | "credit" | "adjustment" | "fx_rate";
|
|
184
267
|
source: string;
|
|
185
268
|
source_event_id: string;
|
|
186
269
|
provider_id: string | null;
|
|
@@ -190,7 +273,7 @@ export declare class SubledgerClient {
|
|
|
190
273
|
event_date: string;
|
|
191
274
|
imported_at: string;
|
|
192
275
|
provider_status: string | null;
|
|
193
|
-
normalized_status: "unknown" | "quoted" | "issued" | "pending" | "reported_paid" | "failed" | "refunded" | "reversed" | "void";
|
|
276
|
+
normalized_status: "unknown" | "quoted" | "issued" | "pending" | "reported_paid" | "pending_finality" | "failed" | "refunded" | "reversed" | "void";
|
|
194
277
|
evidence: {
|
|
195
278
|
uri: string;
|
|
196
279
|
digest: string | null;
|
|
@@ -210,6 +293,29 @@ export declare class SubledgerClient {
|
|
|
210
293
|
rate_denominator: number;
|
|
211
294
|
} | null;
|
|
212
295
|
reason: string | null;
|
|
296
|
+
skill?: {
|
|
297
|
+
namespace: string;
|
|
298
|
+
skill_id: string;
|
|
299
|
+
agent_card_url?: string | undefined;
|
|
300
|
+
} | undefined;
|
|
301
|
+
expectation?: {
|
|
302
|
+
issued_by: "agent" | "gateway" | "operator";
|
|
303
|
+
source_ref: string | null;
|
|
304
|
+
basis: string | null;
|
|
305
|
+
expires_at: string | null;
|
|
306
|
+
supersedes: string | null;
|
|
307
|
+
hold_status?: "expired" | "open" | "captured" | "released" | undefined;
|
|
308
|
+
signer?: {
|
|
309
|
+
provider_id: string;
|
|
310
|
+
binding_id: string;
|
|
311
|
+
key_id: string;
|
|
312
|
+
value: string;
|
|
313
|
+
} | undefined;
|
|
314
|
+
} | undefined;
|
|
315
|
+
rail_attestation?: {
|
|
316
|
+
scheme: string;
|
|
317
|
+
record: Record<string, unknown>;
|
|
318
|
+
} | undefined;
|
|
213
319
|
};
|
|
214
320
|
event_digest: string;
|
|
215
321
|
attributed_to: string;
|
|
@@ -348,7 +454,7 @@ export declare class SubledgerClient {
|
|
|
348
454
|
receipt_revision: number;
|
|
349
455
|
issuer_operator_id: string;
|
|
350
456
|
response_type: "acknowledge_view" | "acknowledge_delivery" | "submit_evidence" | "propose_correction" | "signed_attestation";
|
|
351
|
-
fields: ("delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status")[];
|
|
457
|
+
fields: ("delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status" | "delivery.usage")[];
|
|
352
458
|
note: string | null;
|
|
353
459
|
evidence: {
|
|
354
460
|
uri: string;
|
|
@@ -356,7 +462,7 @@ export declare class SubledgerClient {
|
|
|
356
462
|
evidence_type: string;
|
|
357
463
|
}[];
|
|
358
464
|
corrections: {
|
|
359
|
-
field: "delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status";
|
|
465
|
+
field: "delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status" | "delivery.usage";
|
|
360
466
|
proposed_value: string;
|
|
361
467
|
reason: string;
|
|
362
468
|
}[];
|
|
@@ -371,6 +477,7 @@ export declare class SubledgerClient {
|
|
|
371
477
|
attestation_digest: string;
|
|
372
478
|
reason: string;
|
|
373
479
|
}[] | undefined;
|
|
480
|
+
role?: "witness" | undefined;
|
|
374
481
|
};
|
|
375
482
|
statement_digest: string;
|
|
376
483
|
provider_signature: {
|
|
@@ -378,7 +485,7 @@ export declare class SubledgerClient {
|
|
|
378
485
|
binding_id: string;
|
|
379
486
|
value: string;
|
|
380
487
|
} | null;
|
|
381
|
-
assurance: ("expired" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked")[];
|
|
488
|
+
assurance: ("expired" | "rail_attested" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked" | "gateway_signed")[];
|
|
382
489
|
decision: {
|
|
383
490
|
status: "accepted" | "rejected";
|
|
384
491
|
reason: string;
|
|
@@ -422,6 +529,81 @@ export declare class SubledgerClient {
|
|
|
422
529
|
decision_id: string | null;
|
|
423
530
|
decision_digest: string | null;
|
|
424
531
|
}[] | undefined;
|
|
532
|
+
usage_checks?: {
|
|
533
|
+
delegation_id: string;
|
|
534
|
+
currency: string;
|
|
535
|
+
expected_minor: number | null;
|
|
536
|
+
lines: {
|
|
537
|
+
meter: "input_tokens" | "output_tokens" | "cache_read_input_tokens" | "model_call" | "tool_call" | "a2a_call";
|
|
538
|
+
units: number;
|
|
539
|
+
cost_minor: number;
|
|
540
|
+
model?: {
|
|
541
|
+
provider: string;
|
|
542
|
+
name: string;
|
|
543
|
+
} | undefined;
|
|
544
|
+
tool_name?: string | undefined;
|
|
545
|
+
}[];
|
|
546
|
+
billed_minor: number;
|
|
547
|
+
difference_minor: number | null;
|
|
548
|
+
allowed_difference_minor: number | null;
|
|
549
|
+
within_tolerance: boolean | null;
|
|
550
|
+
unpriced: string[];
|
|
551
|
+
trace_digests: string[];
|
|
552
|
+
assurance: ("expired" | "rail_attested" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked" | "gateway_signed")[];
|
|
553
|
+
}[] | undefined;
|
|
554
|
+
expectation_report?: {
|
|
555
|
+
currency: string;
|
|
556
|
+
task: {
|
|
557
|
+
estimated_minor: number | null;
|
|
558
|
+
held_minor: number;
|
|
559
|
+
actual_minor: number;
|
|
560
|
+
variance_vs_estimate_minor: number | null;
|
|
561
|
+
variance_vs_estimate_bps: number | null;
|
|
562
|
+
variance_vs_hold_minor: number | null;
|
|
563
|
+
variance_vs_hold_bps: number | null;
|
|
564
|
+
unestimated_minor: number;
|
|
565
|
+
};
|
|
566
|
+
nodes: {
|
|
567
|
+
estimated_minor: number | null;
|
|
568
|
+
held_minor: number;
|
|
569
|
+
actual_minor: number;
|
|
570
|
+
variance_vs_estimate_minor: number | null;
|
|
571
|
+
variance_vs_estimate_bps: number | null;
|
|
572
|
+
variance_vs_hold_minor: number | null;
|
|
573
|
+
variance_vs_hold_bps: number | null;
|
|
574
|
+
node_id: string;
|
|
575
|
+
estimate_event_id: string | null;
|
|
576
|
+
}[];
|
|
577
|
+
records: {
|
|
578
|
+
financial_event_id: string;
|
|
579
|
+
node_id: string;
|
|
580
|
+
type: "estimate" | "hold";
|
|
581
|
+
issued_by: "agent" | "gateway" | "operator";
|
|
582
|
+
status: "superseded" | "current" | "not_latest" | "after_charge" | "other_currency";
|
|
583
|
+
hold_status: "expired" | "open" | "captured" | "released" | null;
|
|
584
|
+
assurance: ("expired" | "rail_attested" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked" | "gateway_signed")[];
|
|
585
|
+
}[];
|
|
586
|
+
} | undefined;
|
|
587
|
+
rail_attestations?: {
|
|
588
|
+
financial_event_id: string;
|
|
589
|
+
scheme: string;
|
|
590
|
+
rail: string;
|
|
591
|
+
rail_ref: string;
|
|
592
|
+
anchor: string;
|
|
593
|
+
assurance: ["rail_attested"];
|
|
594
|
+
}[] | undefined;
|
|
595
|
+
resolved_exceptions?: {
|
|
596
|
+
exception_id: string;
|
|
597
|
+
kind: string;
|
|
598
|
+
status: "open" | "dismissed" | "resolved";
|
|
599
|
+
delegation_id: string | null;
|
|
600
|
+
financial_event_id: string | null;
|
|
601
|
+
detail: string;
|
|
602
|
+
created_at: string;
|
|
603
|
+
resolved_by: string;
|
|
604
|
+
resolved_at: string;
|
|
605
|
+
resolution: string | null;
|
|
606
|
+
}[] | undefined;
|
|
425
607
|
};
|
|
426
608
|
signature: {
|
|
427
609
|
key_id: string;
|
|
@@ -443,7 +625,7 @@ export declare class SubledgerClient {
|
|
|
443
625
|
getReceipt(receiptId: string): Promise<{
|
|
444
626
|
payload: {
|
|
445
627
|
document_type: "atcn.subledger.receipt";
|
|
446
|
-
schema_version: "1.
|
|
628
|
+
schema_version: "1.2" | "1.3" | "1.4" | "1.5";
|
|
447
629
|
receipt_id: string;
|
|
448
630
|
revision: number;
|
|
449
631
|
previous_receipt_id: string | null;
|
|
@@ -480,6 +662,11 @@ export declare class SubledgerClient {
|
|
|
480
662
|
name: string;
|
|
481
663
|
version: string;
|
|
482
664
|
} | undefined;
|
|
665
|
+
additional_models?: {
|
|
666
|
+
provider: string;
|
|
667
|
+
name: string;
|
|
668
|
+
version: string;
|
|
669
|
+
}[] | undefined;
|
|
483
670
|
config_digest?: string | undefined;
|
|
484
671
|
};
|
|
485
672
|
protocol?: {
|
|
@@ -493,6 +680,33 @@ export declare class SubledgerClient {
|
|
|
493
680
|
agent_card_url?: string | undefined;
|
|
494
681
|
} | undefined;
|
|
495
682
|
} | undefined;
|
|
683
|
+
pricing?: {
|
|
684
|
+
rates: {
|
|
685
|
+
meter: "input_tokens" | "output_tokens" | "cache_read_input_tokens" | "model_call" | "tool_call" | "a2a_call";
|
|
686
|
+
price_numerator: number;
|
|
687
|
+
price_denominator: number;
|
|
688
|
+
model?: {
|
|
689
|
+
provider: string;
|
|
690
|
+
name: string;
|
|
691
|
+
} | undefined;
|
|
692
|
+
tool_name?: string | undefined;
|
|
693
|
+
}[];
|
|
694
|
+
tolerance_bps: number;
|
|
695
|
+
fixed_minor?: number | undefined;
|
|
696
|
+
} | undefined;
|
|
697
|
+
refund_terms?: {
|
|
698
|
+
on_failure: "dispute" | "refund";
|
|
699
|
+
on_timeout: "dispute" | "refund";
|
|
700
|
+
after_settlement: {
|
|
701
|
+
cap_minor: number;
|
|
702
|
+
window_seconds: number;
|
|
703
|
+
};
|
|
704
|
+
} | undefined;
|
|
705
|
+
witness_policy?: {
|
|
706
|
+
min_independent_witnesses: number;
|
|
707
|
+
independence: "distinct_verified_domain";
|
|
708
|
+
witness_provider_ids?: string[] | undefined;
|
|
709
|
+
} | undefined;
|
|
496
710
|
};
|
|
497
711
|
provider: {
|
|
498
712
|
provider_id: string | null;
|
|
@@ -514,14 +728,38 @@ export declare class SubledgerClient {
|
|
|
514
728
|
supersedes_event_id: string | null;
|
|
515
729
|
reason: string | null;
|
|
516
730
|
event_id: string;
|
|
517
|
-
assurance: ("expired" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked")[];
|
|
731
|
+
assurance: ("expired" | "rail_attested" | "contested" | "issuer_signed" | "buyer_recorded" | "network_recorded" | "recipient_viewed" | "link_authenticated_response" | "provider_identity_bound" | "provider_key_signed" | "superseded" | "revoked" | "gateway_signed")[];
|
|
518
732
|
recorded_at: string;
|
|
733
|
+
signer?: {
|
|
734
|
+
provider_id: string;
|
|
735
|
+
binding_id: string;
|
|
736
|
+
key_id: string;
|
|
737
|
+
value: string;
|
|
738
|
+
} | undefined;
|
|
739
|
+
usage?: {
|
|
740
|
+
trace_digest: string;
|
|
741
|
+
summary: {
|
|
742
|
+
models: {
|
|
743
|
+
provider: string;
|
|
744
|
+
name: string;
|
|
745
|
+
calls: number;
|
|
746
|
+
input_tokens: number;
|
|
747
|
+
output_tokens: number;
|
|
748
|
+
cache_read_input_tokens: number;
|
|
749
|
+
}[];
|
|
750
|
+
tools: {
|
|
751
|
+
name: string;
|
|
752
|
+
calls: number;
|
|
753
|
+
}[];
|
|
754
|
+
a2a_calls: number;
|
|
755
|
+
};
|
|
756
|
+
} | undefined;
|
|
519
757
|
}[];
|
|
520
758
|
financial_events: {
|
|
521
|
-
type: "
|
|
759
|
+
type: "refund" | "charge" | "invoice" | "estimate" | "hold" | "quote" | "payment_reported" | "reversal" | "fee" | "credit" | "adjustment" | "fx_rate";
|
|
760
|
+
provider_id: string | null;
|
|
522
761
|
currency: string;
|
|
523
762
|
retrospective: boolean;
|
|
524
|
-
provider_id: string | null;
|
|
525
763
|
evidence: {
|
|
526
764
|
uri: string;
|
|
527
765
|
digest: string | null;
|
|
@@ -534,7 +772,7 @@ export declare class SubledgerClient {
|
|
|
534
772
|
source_event_id: string;
|
|
535
773
|
provider_reference: string | null;
|
|
536
774
|
provider_status: string | null;
|
|
537
|
-
normalized_status: "unknown" | "quoted" | "issued" | "pending" | "reported_paid" | "failed" | "refunded" | "reversed" | "void";
|
|
775
|
+
normalized_status: "unknown" | "quoted" | "issued" | "pending" | "reported_paid" | "pending_finality" | "failed" | "refunded" | "reversed" | "void";
|
|
538
776
|
payer: "provider" | "buyer" | "other";
|
|
539
777
|
included_in_event_id: string | null;
|
|
540
778
|
reverses_event_id: string | null;
|
|
@@ -542,6 +780,29 @@ export declare class SubledgerClient {
|
|
|
542
780
|
imported_at: string;
|
|
543
781
|
financial_event_id: string;
|
|
544
782
|
allocation_version: number;
|
|
783
|
+
skill?: {
|
|
784
|
+
namespace: string;
|
|
785
|
+
skill_id: string;
|
|
786
|
+
agent_card_url?: string | undefined;
|
|
787
|
+
} | undefined;
|
|
788
|
+
expectation?: {
|
|
789
|
+
issued_by: "agent" | "gateway" | "operator";
|
|
790
|
+
source_ref: string | null;
|
|
791
|
+
basis: string | null;
|
|
792
|
+
expires_at: string | null;
|
|
793
|
+
supersedes: string | null;
|
|
794
|
+
hold_status?: "expired" | "open" | "captured" | "released" | undefined;
|
|
795
|
+
signer?: {
|
|
796
|
+
provider_id: string;
|
|
797
|
+
binding_id: string;
|
|
798
|
+
key_id: string;
|
|
799
|
+
value: string;
|
|
800
|
+
} | undefined;
|
|
801
|
+
} | undefined;
|
|
802
|
+
rail_attestation?: {
|
|
803
|
+
scheme: string;
|
|
804
|
+
record: Record<string, unknown>;
|
|
805
|
+
} | undefined;
|
|
545
806
|
}[];
|
|
546
807
|
totals: Record<string, {
|
|
547
808
|
quoted: number;
|
|
@@ -557,23 +818,34 @@ export declare class SubledgerClient {
|
|
|
557
818
|
unresolved: number;
|
|
558
819
|
downstream_reported: number;
|
|
559
820
|
}>;
|
|
560
|
-
field_status: Record<"delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status", "contested" | "missing" | "imported" | "buyer_asserted" | "provider_reported"
|
|
561
|
-
unverified_fields: ("delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status")[];
|
|
821
|
+
field_status: Partial<Record<"delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status" | "delivery.usage", "contested" | "missing" | "imported" | "buyer_asserted" | "provider_reported">>;
|
|
822
|
+
unverified_fields: ("delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status" | "delivery.usage")[];
|
|
562
823
|
corrections: {
|
|
563
824
|
response_id: string;
|
|
564
825
|
receipt_revision: number;
|
|
565
|
-
fields: ("delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status")[];
|
|
826
|
+
fields: ("delivery.status" | "delivery.evidence" | "scope.terms_digest" | "financial.amounts" | "financial.status" | "delivery.usage")[];
|
|
566
827
|
decision: "accepted" | "rejected" | "open";
|
|
567
828
|
}[];
|
|
568
829
|
lineage: {
|
|
569
830
|
complete: boolean;
|
|
570
831
|
capture_gaps: {
|
|
832
|
+
kind: string;
|
|
571
833
|
detail: string;
|
|
572
834
|
reported_at: string;
|
|
573
835
|
gap_id: string;
|
|
574
|
-
kind: string;
|
|
575
836
|
}[];
|
|
576
837
|
};
|
|
838
|
+
key_bindings?: {
|
|
839
|
+
binding_id: string;
|
|
840
|
+
provider_id: string;
|
|
841
|
+
key_id: string;
|
|
842
|
+
public_key: string;
|
|
843
|
+
method: "operator_configured" | "domain_challenge";
|
|
844
|
+
created_by: string;
|
|
845
|
+
created_at: string;
|
|
846
|
+
revoked_at: string | null;
|
|
847
|
+
domain?: string | null | undefined;
|
|
848
|
+
}[] | undefined;
|
|
577
849
|
};
|
|
578
850
|
signature: {
|
|
579
851
|
key_id: string;
|
|
@@ -596,6 +868,15 @@ export declare class SubledgerClient {
|
|
|
596
868
|
expires_at: string;
|
|
597
869
|
allowed_actions: string[];
|
|
598
870
|
}>;
|
|
871
|
+
/** A witness link: lets another provider (not the delegation's own) sign that it observed the run. It allows only viewing and witnessing. */
|
|
872
|
+
createWitnessShare(receiptId: string, witnessProviderId: string, ttlHours?: number, opts?: Opts): Promise<{
|
|
873
|
+
share_id: string;
|
|
874
|
+
token: string;
|
|
875
|
+
url: string;
|
|
876
|
+
expires_at: string;
|
|
877
|
+
allowed_actions: string[];
|
|
878
|
+
witness_provider_id: string;
|
|
879
|
+
}>;
|
|
599
880
|
revokeReceiptShare(shareId: string, opts?: Opts): Promise<Json>;
|
|
600
881
|
listResponses(receiptId: string): Promise<{
|
|
601
882
|
items: Json[];
|
|
@@ -664,6 +945,8 @@ export declare class ReceiptLinkClient {
|
|
|
664
945
|
issued_at?: string;
|
|
665
946
|
expires_at?: string;
|
|
666
947
|
refs?: AttestationRef[];
|
|
948
|
+
/** Schema 1.5: a witness statement, sent through a witness link. */
|
|
949
|
+
role?: "witness";
|
|
667
950
|
}, signing?: {
|
|
668
951
|
bindingId: string;
|
|
669
952
|
keyId: string;
|
package/dist/subledger.js
CHANGED
|
@@ -46,9 +46,14 @@ export class SubledgerClient {
|
|
|
46
46
|
recordFinancialEvent(input, opts = {}) {
|
|
47
47
|
return this.http.request("POST", "/v1/financial-events", input, { idempotencyKey: opts.idempotencyKey ?? stableKey("financial", input.source, input.source_event_id) });
|
|
48
48
|
}
|
|
49
|
+
recordRailAttestation(input, opts = {}) {
|
|
50
|
+
return this.http.request("POST", "/v1/financial-events/rail-attestations", input, opts);
|
|
51
|
+
}
|
|
49
52
|
importCsv(csv, opts = {}) {
|
|
53
|
+
const { idempotencyKey, map, ...query } = opts;
|
|
50
54
|
return this.http.request("POST", "/v1/financial-events/import", undefined, {
|
|
51
|
-
idempotencyKey
|
|
55
|
+
idempotencyKey,
|
|
56
|
+
query: { ...query, map: map === undefined ? undefined : JSON.stringify(map) },
|
|
52
57
|
textBody: { contentType: "text/csv", text: csv },
|
|
53
58
|
});
|
|
54
59
|
}
|
|
@@ -97,6 +102,10 @@ export class SubledgerClient {
|
|
|
97
102
|
createReceiptShare(receiptId, allowedActions = ["view"], ttlHours, opts = {}) {
|
|
98
103
|
return this.http.request("POST", "/v1/receipt-shares", { receipt_id: receiptId, allowed_actions: allowedActions, ttl_hours: ttlHours }, opts);
|
|
99
104
|
}
|
|
105
|
+
/** A witness link: lets another provider (not the delegation's own) sign that it observed the run. It allows only viewing and witnessing. */
|
|
106
|
+
createWitnessShare(receiptId, witnessProviderId, ttlHours, opts = {}) {
|
|
107
|
+
return this.http.request("POST", "/v1/receipt-shares", { receipt_id: receiptId, allowed_actions: ["view", "witness_attestation"], ttl_hours: ttlHours, witness_provider_id: witnessProviderId }, opts);
|
|
108
|
+
}
|
|
100
109
|
revokeReceiptShare(shareId, opts = {}) {
|
|
101
110
|
return this.http.request("DELETE", `/v1/receipt-shares/${shareId}`, undefined, opts);
|
|
102
111
|
}
|
|
@@ -179,6 +188,7 @@ export class ReceiptLinkClient {
|
|
|
179
188
|
issued_at: response.issued_at,
|
|
180
189
|
expires_at: response.expires_at,
|
|
181
190
|
refs: response.refs,
|
|
191
|
+
role: response.role,
|
|
182
192
|
});
|
|
183
193
|
provider_signature = { binding_id: signing.bindingId, key_id: signing.keyId, value: signStatement(statement, signing.privateKey) };
|
|
184
194
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atcn/sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "TypeScript SDK for ATCN
|
|
3
|
+
"version": "1.5.0",
|
|
4
|
+
"description": "TypeScript SDK for ATCN, a cost record for AI agent jobs that anyone can verify: record tasks and charges, sign events, verify closures offline",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -36,10 +36,10 @@
|
|
|
36
36
|
"build": "tsc -p tsconfig.build.json"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@atcn/core": "1.
|
|
40
|
-
"@atcn/schema": "1.
|
|
41
|
-
"@atcn/subledger": "1.
|
|
42
|
-
"@atcn/usage": "1.
|
|
39
|
+
"@atcn/core": "1.5.0",
|
|
40
|
+
"@atcn/schema": "1.5.0",
|
|
41
|
+
"@atcn/subledger": "1.5.0",
|
|
42
|
+
"@atcn/usage": "1.5.0",
|
|
43
43
|
"zod": "^4.1.0"
|
|
44
44
|
}
|
|
45
45
|
}
|