@tangle-network/agent-gateway 0.7.1 → 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.
Files changed (64) hide show
  1. package/README.md +90 -3
  2. package/dist/chunk-C7Z2BRYV.js +5693 -0
  3. package/dist/chunk-C7Z2BRYV.js.map +1 -0
  4. package/dist/chunk-GITV7CPT.js +84 -0
  5. package/dist/chunk-GITV7CPT.js.map +1 -0
  6. package/dist/chunk-J5SDVHOL.js +104 -0
  7. package/dist/chunk-J5SDVHOL.js.map +1 -0
  8. package/dist/index.d.ts +70 -10
  9. package/dist/index.js +303 -21
  10. package/dist/index.js.map +1 -1
  11. package/dist/middleware.d.ts +7 -2
  12. package/dist/middleware.js +3 -2
  13. package/dist/nonce-store.d.ts +47 -11
  14. package/dist/nonce-store.js +9 -3
  15. package/dist/observer-types-A0RtA8uL.d.ts +95 -0
  16. package/dist/observer.d.ts +79 -0
  17. package/dist/observer.js +11 -0
  18. package/dist/observer.js.map +1 -0
  19. package/dist/{types-DEsMmS-X.d.ts → types-oQ58UakD.d.ts} +447 -172
  20. package/dist/types.d.ts +2 -1
  21. package/package.json +1 -1
  22. package/src/a2a/execution-fence.ts +162 -0
  23. package/src/a2a/handler.ts +506 -560
  24. package/src/a2a/message-send-execution.ts +241 -0
  25. package/src/a2a/message-stream-execution.ts +392 -0
  26. package/src/a2a/payment-recovery.ts +431 -0
  27. package/src/a2a/push-config-methods.ts +158 -0
  28. package/src/a2a/push-notifications.ts +172 -22
  29. package/src/a2a/task-cancellation.ts +50 -0
  30. package/src/a2a/task-finalization.ts +451 -0
  31. package/src/a2a/task-lifecycle.ts +54 -0
  32. package/src/a2a/task-methods.ts +163 -0
  33. package/src/a2a/task-push-delivery.ts +119 -0
  34. package/src/a2a/task-recovery.ts +11 -0
  35. package/src/a2a/task-state.ts +99 -0
  36. package/src/a2a/task-store-sql.ts +222 -24
  37. package/src/a2a/task-store.ts +58 -1
  38. package/src/a2a/task-submission-recovery.ts +178 -0
  39. package/src/a2a/types.ts +1 -0
  40. package/src/dispatch-authorization.ts +468 -0
  41. package/src/dispatch-payment-recovery.ts +248 -0
  42. package/src/dispatch-payment.ts +425 -0
  43. package/src/dispatch-pricing.ts +108 -0
  44. package/src/dispatch-sandbox.ts +424 -0
  45. package/src/dispatch-settlement.ts +139 -0
  46. package/src/dispatch-types.ts +84 -0
  47. package/src/dispatch.ts +35 -483
  48. package/src/index.ts +59 -1
  49. package/src/middleware.ts +339 -35
  50. package/src/mpp-payment.ts +117 -0
  51. package/src/nonce-store.ts +122 -20
  52. package/src/observer-types.ts +63 -0
  53. package/src/observer.ts +3 -63
  54. package/src/payment-operations.ts +485 -0
  55. package/src/payment-recovery-sql.ts +108 -0
  56. package/src/payment-recovery-worker.ts +488 -0
  57. package/src/payment-recovery.ts +331 -0
  58. package/src/payment-types.ts +48 -0
  59. package/src/types.ts +188 -49
  60. package/src/verify.ts +240 -71
  61. package/dist/chunk-M7ZJAK4K.js +0 -53
  62. package/dist/chunk-M7ZJAK4K.js.map +0 -1
  63. package/dist/chunk-Q4YAIEZY.js +0 -1763
  64. package/dist/chunk-Q4YAIEZY.js.map +0 -1
package/src/types.ts CHANGED
@@ -1,3 +1,25 @@
1
+ import type {
2
+ PaymentAuthorizationContext,
3
+ PaymentOperation,
4
+ PaymentOperations,
5
+ } from './payment-operations'
6
+ import type { MppAuthenticatedCredential, MppChargeLifecycle } from './mpp-payment'
7
+ import type { PaymentRecoveryConfig } from './payment-recovery'
8
+ import type { GatewayObserver } from './observer-types'
9
+ import type {
10
+ GatewayUsageEvent,
11
+ PaymentMethod,
12
+ SandboxExecutionBudget,
13
+ SandboxUsageReceipt,
14
+ } from './payment-types'
15
+
16
+ export type {
17
+ GatewayUsageEvent,
18
+ PaymentMethod,
19
+ SandboxExecutionBudget,
20
+ SandboxUsageReceipt,
21
+ } from './payment-types'
22
+
1
23
  // --- Agent resolution ---
2
24
 
3
25
  export interface AgentMeta {
@@ -71,8 +93,6 @@ export interface AgentMeta {
71
93
 
72
94
  // --- Payment ---
73
95
 
74
- export type PaymentMethod = 'x402' | 'mpp' | 'apikey' | 'none'
75
-
76
96
  export interface X402Config {
77
97
  /** Ethereum operator address for SpendAuth verification */
78
98
  operatorAddress: string
@@ -84,8 +104,35 @@ export interface X402Config {
84
104
  rpcUrl?: string
85
105
  /** Demo mode: skip signature verification (default: false). NEVER enable in production. */
86
106
  demoMode?: boolean
87
- /** Production signer verification. Called with the raw SpendAuth payload. Return true if signature is valid. */
88
- verifySigner?: (payload: Record<string, unknown>) => Promise<boolean>
107
+ /** Protocol version for new durable payment operations. Production version 1 is read-only. */
108
+ paymentProtocolVersion?: 1 | 2
109
+ /**
110
+ * Production signature verification. This callback must not reserve, claim,
111
+ * or mutate payment state.
112
+ */
113
+ verifySigner?: (
114
+ payload: Record<string, unknown>,
115
+ context?: { protocolVersion: 1 | 2; requestId?: string },
116
+ ) => Promise<boolean>
117
+ /**
118
+ * Claim the verified payment after all request checks pass and immediately
119
+ * before sandbox work starts. Version 2 returns durable operation ownership.
120
+ * A boolean return is the version 1 demo-only compatibility path.
121
+ * Production version 1 must omit this callback because it has no durable
122
+ * provider operation or recovery identity.
123
+ */
124
+ authorizePayment?: (
125
+ payload: Record<string, unknown>,
126
+ context: PaymentAuthorizationContext,
127
+ ) => Promise<boolean | PaymentOperation>
128
+ /** Version 2 operation store. It owns claim, settle, release, and reclaim. */
129
+ paymentOperations?: PaymentOperations
130
+ /**
131
+ * Number of base-unit decimals used by the payment token. Defaults to 6.
132
+ * The gateway uses this value to reject a payment that cannot cover the
133
+ * request's maximum token charge before it calls `verifySigner`.
134
+ */
135
+ currencyDecimals?: number
89
136
  }
90
137
 
91
138
  export interface MppConfig {
@@ -94,17 +141,24 @@ export interface MppConfig {
94
141
  /** MPP method name (default: "blueprintevm") */
95
142
  method?: string
96
143
  /**
97
- * Production verifier for the method-specific credential. Return the
98
- * authenticated consumer id, or null when the credential is invalid.
99
- * The callback receives the decoded JSON payload when one exists plus the
100
- * original decoded credential so non-JSON methods can verify their own form.
101
- * Omit only when x402.demoMode is explicitly enabled for local testing, or
102
- * when x402.verifySigner handles an x402-compatible MPP credential.
144
+ * Pure credential authentication. Return stable method-owned identity, or null.
145
+ * This callback must not consume a credential, create a processor object,
146
+ * reserve funds, confirm payment, or perform any other financial mutation.
147
+ */
148
+ authenticateCredential?: (
149
+ payload: Record<string, unknown>,
150
+ context: { method: string; credential: string },
151
+ ) => Promise<MppAuthenticatedCredential | null>
152
+ /**
153
+ * @deprecated Use authenticateCredential and return a stable payment identity.
154
+ * This 0.7.1 callback remains supported through an explicit compatibility adapter.
103
155
  */
104
156
  verifySigner?: (
105
157
  payload: Record<string, unknown>,
106
158
  context: { method: string; credential: string },
107
159
  ) => Promise<string | null>
160
+ /** Required immediate-charge lifecycle for every non-BlueprinTEVM method. */
161
+ charge?: MppChargeLifecycle
108
162
  }
109
163
 
110
164
  export interface PaymentResult {
@@ -133,30 +187,6 @@ export interface ApiKeyInfo {
133
187
  dailyLimit?: number
134
188
  }
135
189
 
136
- // --- Usage tracking ---
137
-
138
- export interface GatewayUsageEvent {
139
- /**
140
- * Per-request id (matches `RequestContext.requestId`). Lets
141
- * `recordUsage` correlate the usage row to the same request that
142
- * `settlePayment` settles, observability hooks observe, and
143
- * `onRequestComplete` reports — without re-deriving from a
144
- * synthetic key. Required field as of 0.4.0; the gateway always has
145
- * it in scope at the recordUsage call site.
146
- */
147
- requestId: string
148
- agentId: string
149
- agentSlug: string
150
- consumerId: string
151
- paymentMethod: PaymentMethod
152
- inputTokens: number
153
- outputTokens: number
154
- totalCostUsd: number
155
- ownerEarnedUsd: number
156
- platformFeeUsd: number
157
- durationMs: number
158
- }
159
-
160
190
  // --- Sandbox interface ---
161
191
 
162
192
  export interface SandboxStreamEvent {
@@ -174,11 +204,36 @@ export interface SandboxStreamEvent {
174
204
  * the caller (rendered as the input-required message body).
175
205
  */
176
206
  inputRequired?: { prompt?: string }
207
+ /** Provider receipt fields. Version 2 operations require every field. */
208
+ usage?: Partial<SandboxUsageReceipt>
209
+ /** Tool or reasoning events may carry hidden usage without visible text. */
210
+ tool?: { name?: string; inputTokens?: number; outputTokens?: number }
211
+ reasoning?: { tokens?: number }
177
212
  }
178
213
  }
179
214
 
180
215
  export interface SandboxBox {
181
- streamPrompt(message: string, opts?: { sessionId?: string; systemPrompt?: string }): AsyncIterable<SandboxStreamEvent>
216
+ streamPrompt(
217
+ message: string,
218
+ opts?: {
219
+ sessionId?: string
220
+ systemPrompt?: string
221
+ maxOutputTokens?: number
222
+ executionBudget?: SandboxExecutionBudget
223
+ signal?: AbortSignal
224
+ },
225
+ ): AsyncIterable<SandboxStreamEvent>
226
+ }
227
+
228
+ /** Authenticated request identity supplied when the host resolves a sandbox. */
229
+ export interface GatewaySandboxContext {
230
+ consumerId: string
231
+ paymentMethod: PaymentMethod
232
+ keyInfo: ApiKeyInfo | null
233
+ requestId: string
234
+ messages: ChatMessage[]
235
+ /** Stable UI conversation id when `conversationMode` is `thread`. */
236
+ threadId?: string
182
237
  }
183
238
 
184
239
  // --- Gateway config ---
@@ -187,8 +242,11 @@ export interface GatewayConfig {
187
242
  /** Resolve agent metadata by slug. Return null if not found or not published. */
188
243
  resolveAgent: (slug: string) => Promise<AgentMeta | null>
189
244
 
190
- /** Get a sandbox instance for the agent. Called after payment is verified. */
191
- getSandbox: (agent: AgentMeta) => Promise<SandboxBox>
245
+ /**
246
+ * Get the agent execution adapter after payment is verified.
247
+ * Hosts that use agent-app can drive their normal persisted chat route here.
248
+ */
249
+ getSandbox: (agent: AgentMeta, context?: GatewaySandboxContext) => Promise<SandboxBox>
192
250
 
193
251
  /**
194
252
  * Optional host authorization hook fired after payment verification
@@ -197,10 +255,22 @@ export interface GatewayConfig {
197
255
  */
198
256
  authorizeConsumer?: (
199
257
  agent: AgentMeta,
200
- consumer: { method: PaymentMethod; consumerId: string; keyId?: string; requestId: string },
258
+ consumer: {
259
+ method: PaymentMethod
260
+ consumerId: string
261
+ keyId?: string
262
+ requestId: string
263
+ /** Requested stable conversation id, after syntax validation. */
264
+ threadId?: string
265
+ },
201
266
  ) => Promise<{ allow: true } | { allow: false; reason: string; code: string }>
202
267
 
203
- /** Record a usage event after request completes. */
268
+ /**
269
+ * Record a usage event after request completes.
270
+ * The implementation must atomically upsert by requestId and return
271
+ * success when the row already exists. Recovery may retry after an
272
+ * acknowledgement is lost, so one request ID must produce one usage row.
273
+ */
204
274
  recordUsage: (event: GatewayUsageEvent) => Promise<void>
205
275
 
206
276
  /** x402 payment configuration */
@@ -209,6 +279,12 @@ export interface GatewayConfig {
209
279
  /** MPP (Machine Payments Protocol) configuration. It is advertised only when a production verifier or explicit demo mode is available. */
210
280
  mpp?: MppConfig
211
281
 
282
+ /**
283
+ * Durable payment recovery outbox. Production payment protocol version 2
284
+ * and generic MPP charge methods require this configuration.
285
+ */
286
+ paymentRecovery?: PaymentRecoveryConfig
287
+
212
288
  /**
213
289
  * Verify an API key. Return key info if valid, null if invalid.
214
290
  * In explicit x402 demo mode, the built-in verifier accepts `sk_agent_*` keys.
@@ -217,19 +293,53 @@ export interface GatewayConfig {
217
293
  verifyApiKey?: (authHeader: string) => Promise<ApiKeyInfo | null>
218
294
 
219
295
  /**
220
- * Settle payment after successful response.
221
- * For x402: call ShieldedCredits.claimPayment()
222
- * For API key: deduct from spending limit
223
- * Default: no-op (demo mode).
296
+ * Settle a legacy payment after usage attribution is recorded.
297
+ * Version 2 x402 operations use `x402.paymentOperations` instead.
298
+ * Production x402 version 1 rejects this callback before nonce claim.
299
+ * For API keys, deduct from the spending limit.
300
+ * Default: no-op in explicit demo mode.
224
301
  */
225
302
  settlePayment?: (payment: PaymentResult, cost: number) => Promise<void>
226
303
 
227
304
  /** Base URL for API key purchase links (e.g. "https://film.tangle.tools") */
228
305
  baseUrl?: string
229
306
 
307
+ /** Public API key prefix shown by discovery. Defaults to `sk_agent_`. */
308
+ apiKeyPrefix?: string
309
+
310
+ /**
311
+ * `consumer` keeps the historical session per API consumer.
312
+ * `thread` accepts `X-Tangle-Thread-Id` or creates one per request and returns
313
+ * it in the response, so a host can display the same conversation.
314
+ */
315
+ conversationMode?: 'consumer' | 'thread'
316
+
230
317
  /** Max message length in chars (default: 8000) */
231
318
  maxMessageLength?: number
232
319
 
320
+ /** Maximum output token request the gateway accepts. Defaults to 4096. */
321
+ maxOutputTokens?: number
322
+
323
+ /** Output token limit used when a request omits `max_tokens`. Defaults to 1024. */
324
+ defaultOutputTokens?: number
325
+
326
+ /**
327
+ * Return a safe upper bound for the complete provider input.
328
+ * Include system, chat framing, retained history, tools, harness, and workspace context.
329
+ */
330
+ inputTokenBound?: (input: {
331
+ agent: AgentMeta
332
+ messages: ChatMessage[]
333
+ }) => number
334
+
335
+ /** Hidden provider spend limits included in the pre-execution payment quote. */
336
+ executionBudget?: {
337
+ maxReasoningTokens?: number
338
+ maxToolTokens?: number
339
+ maxToolCalls?: number
340
+ maxProviderCostUsd?: number
341
+ }
342
+
233
343
  /** Required scope for chat endpoint (default: "chat"). API keys must include this scope. */
234
344
  requiredScope?: string
235
345
 
@@ -251,19 +361,33 @@ export interface GatewayConfig {
251
361
  * and settlement failures. See ./observer.ts for the interface and
252
362
  * ConsoleObserver / CompositeObserver implementations.
253
363
  */
254
- observer?: import('./observer').GatewayObserver
364
+ observer?: GatewayObserver
255
365
 
256
366
  /**
257
- * A2A protocol configuration. When set, the gateway exposes the A2A
258
- * surface alongside its OpenAI-compatible endpoints:
367
+ * A2A protocol configuration. The gateway exposes A2A with an in-memory
368
+ * task store by default. Set this object to provide durable storage or push:
259
369
  * GET /:slug/.well-known/agent.json — AgentCard discovery
260
370
  * POST /:slug — JSON-RPC 2.0 endpoint
261
371
  * methods: message/send, message/stream, tasks/get, tasks/cancel
262
372
  * Auth + rate-limit + injection-filter + authorization all share the
263
373
  * same pipeline as the OpenAI-compat path. `taskStore` defaults to
264
374
  * `InMemoryTaskStore`; swap in D1/postgres/DO for durable deployments.
265
- */
375
+ */
266
376
  a2a?: {
377
+ /**
378
+ * Authorize reads, cancellation, resubscription, and push configuration
379
+ * for an existing task. Production control methods fail closed when this
380
+ * hook is absent; explicit demo mode permits local tests.
381
+ */
382
+ authorizeTaskAccess?: (
383
+ task: import('./a2a/types').Task,
384
+ context: {
385
+ method: string
386
+ agentSlug: string
387
+ authorization: string
388
+ paymentSignature: string
389
+ },
390
+ ) => Promise<boolean>
267
391
  /**
268
392
  * Where tasks live. Defaults to `InMemoryTaskStore`; swap in
269
393
  * `SqlTaskStore` (D1, postgres, sqlite, libSQL) for durability across
@@ -282,8 +406,8 @@ export interface GatewayConfig {
282
406
  * Shared HMAC secret used to sign webhook deliveries (`X-A2A-Signature:
283
407
  * sha256=<hex>`). The consumer's webhook verifies the body against this
284
408
  * secret to confirm the call originated from this gateway. Required when
285
- * `pushStore` is set; without it, deliveries fire unsigned and a
286
- * malicious party that knows the webhook URL can forge deliveries.
409
+ * `pushStore` is set in production. Explicit demo mode may omit it for
410
+ * local tests; production deliveries never run unsigned.
287
411
  */
288
412
  webhookSecret?: string
289
413
  /**
@@ -291,9 +415,24 @@ export interface GatewayConfig {
291
415
  * `fetch`. Override for tests or to wire a queue-backed sender.
292
416
  */
293
417
  pushFetcher?: typeof fetch
418
+ /**
419
+ * DNS-aware policy for push destinations. Required when production
420
+ * push delivery is enabled so private DNS names cannot receive task data.
421
+ */
422
+ pushUrlValidator?: (url: URL) => boolean | Promise<boolean>
294
423
  }
295
424
  }
296
425
 
426
+ /** API-key-only gateway input. Payment transports stay disabled. */
427
+ export type ApiKeyGatewayConfig = Omit<GatewayConfig, 'mpp' | 'verifyApiKey' | 'x402'> & {
428
+ mpp?: never
429
+ verifyApiKey: NonNullable<GatewayConfig['verifyApiKey']>
430
+ x402?: never
431
+ }
432
+
433
+ /** Configuration accepted by `createAgentGateway`. */
434
+ export type CreateAgentGatewayConfig = GatewayConfig | ApiKeyGatewayConfig
435
+
297
436
  // --- Chat completion types (OpenAI-compatible) ---
298
437
 
299
438
  export interface ChatMessage {