@tangle-network/agent-interface 2.3.0 → 2.3.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.
@@ -1087,6 +1087,8 @@ export interface CreateAgentEnvironmentInput {
1087
1087
  * The operation key names the request and the abort signal controls one
1088
1088
  * attempt, so neither belongs in the input identity. Every other field is
1089
1089
  * canonicalized with the shared RFC 8785 JSON representation.
1090
+ * A keyed create therefore accepts only canonical JSON material.
1091
+ * Unkeyed creates can retain opaque provider-native mapper values.
1090
1092
  * @internal
1091
1093
  */
1092
1094
  export declare function agentEnvironmentCreateInputDigest(input: CreateAgentEnvironmentInput): Sha256Digest;
@@ -1118,9 +1120,15 @@ export declare function replayedAgentEnvironmentView<T extends object>(environme
1118
1120
  * with the creation verdict the provider could prove. Every same-key call
1119
1121
  * after it, including one that awaited the same pending create, receives
1120
1122
  * {@link replayedAgentEnvironmentView} of that environment.
1123
+ *
1124
+ * A keyed create callback receives one immutable canonical JSON snapshot.
1125
+ * Its digest and provider therefore read identical request bytes even when
1126
+ * the caller mutates its original object after this function returns.
1127
+ * An unkeyed create retains its original input so opaque provider-native
1128
+ * mapper values retain their public identity.
1121
1129
  * @internal
1122
1130
  */
1123
- export declare function createAgentEnvironmentWithIdempotency<T extends object>(records: Map<string, AgentEnvironmentCreateIdempotencyRecord<T>>, input: CreateAgentEnvironmentInput, create: () => Promise<T>): Promise<T>;
1131
+ export declare function createAgentEnvironmentWithIdempotency<T extends object>(records: Map<string, AgentEnvironmentCreateIdempotencyRecord<T>>, input: CreateAgentEnvironmentInput, create: (input: CreateAgentEnvironmentInput) => Promise<T>): Promise<T>;
1124
1132
  export interface AgentEnvironmentProvider {
1125
1133
  readonly name: string;
1126
1134
  readonly exactProcess?: AgentExactProcessProvider;
@@ -1,11 +1,12 @@
1
1
  import { z } from "zod";
2
- import { canonicalCandidateDigest } from "./agent-candidate-schema-common.js";
2
+ import { canonicalCandidateDigest, canonicalCandidateJson, } from "./agent-candidate-schema-common.js";
3
3
  import { InteractionCapabilitiesSchema, RequestedInteractionsSchema } from "./interaction.js";
4
4
  import { ContextTransferReceiptSchema, ContextTransferRequestSchema, NativeContextBoundaryProofSchema, NativeContextContinuationAcknowledgementSchema, NativeContextContinuationRequestSchema, nativeContextContinuationAcknowledgementMatches } from "./portable-context.js";
5
5
  import { AgentExactRunControlRefSchema, AgentRunControlRefSchema, CanonicalStreamEventSchema } from "./runtime-control.js";
6
6
  import { AgentProfileCapabilitiesSchema } from "./environment-profile-capabilities.js";
7
7
  import { boundedIdentifierSchema, boundedJsonRecordSchema, boundedJsonSchema, boundedStringSchema, CONTRACT_MAX_ARRAY_LENGTH } from "./contract-limits.js";
8
8
  import { InputPartSchema } from "./portable-context-shared.js";
9
+ import { deepFreeze } from "./deep-freeze.js";
9
10
  export const AgentTurnInputSchema = z.strictObject({
10
11
  prompt: boundedStringSchema.optional(),
11
12
  parts: z.array(InputPartSchema).max(CONTRACT_MAX_ARRAY_LENGTH).optional(),
@@ -423,6 +424,8 @@ export const AgentEnvironmentCapabilitiesSchema = z
423
424
  * The operation key names the request and the abort signal controls one
424
425
  * attempt, so neither belongs in the input identity. Every other field is
425
426
  * canonicalized with the shared RFC 8785 JSON representation.
427
+ * A keyed create therefore accepts only canonical JSON material.
428
+ * Unkeyed creates can retain opaque provider-native mapper values.
426
429
  * @internal
427
430
  */
428
431
  export function agentEnvironmentCreateInputDigest(input) {
@@ -460,14 +463,26 @@ export function replayedAgentEnvironmentView(environment) {
460
463
  * with the creation verdict the provider could prove. Every same-key call
461
464
  * after it, including one that awaited the same pending create, receives
462
465
  * {@link replayedAgentEnvironmentView} of that environment.
466
+ *
467
+ * A keyed create callback receives one immutable canonical JSON snapshot.
468
+ * Its digest and provider therefore read identical request bytes even when
469
+ * the caller mutates its original object after this function returns.
470
+ * An unkeyed create retains its original input so opaque provider-native
471
+ * mapper values retain their public identity.
463
472
  * @internal
464
473
  */
465
474
  export async function createAgentEnvironmentWithIdempotency(records, input, create) {
466
- input.signal?.throwIfAborted();
467
- const key = input.idempotencyKey;
475
+ const { idempotencyKey: key, signal, ...material } = input;
476
+ signal?.throwIfAborted();
468
477
  if (key === undefined)
469
- return create();
470
- const digest = agentEnvironmentCreateInputDigest(input);
478
+ return create(input);
479
+ const snapshot = deepFreeze(JSON.parse(canonicalCandidateJson(material)));
480
+ const acceptedInput = Object.freeze({
481
+ ...snapshot,
482
+ idempotencyKey: key,
483
+ ...(signal === undefined ? {} : { signal }),
484
+ });
485
+ const digest = agentEnvironmentCreateInputDigest(acceptedInput);
471
486
  const existing = records.get(key);
472
487
  if (existing !== undefined) {
473
488
  if (existing.digest !== digest) {
@@ -475,7 +490,7 @@ export async function createAgentEnvironmentWithIdempotency(records, input, crea
475
490
  }
476
491
  return replayedAgentEnvironmentView(existing.environment ?? (await existing.pending));
477
492
  }
478
- const pending = Promise.resolve().then(create);
493
+ const pending = Promise.resolve().then(() => create(acceptedInput));
479
494
  const record = {
480
495
  digest,
481
496
  pending,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-interface",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -88,7 +88,7 @@
88
88
  "zod": "4.5.4"
89
89
  },
90
90
  "devDependencies": {
91
- "@types/node": "26.4.0",
91
+ "@types/node": "26.4.1",
92
92
  "@types/spdx-expression-parse": "4.0.0",
93
93
  "typescript": "7.0.2",
94
94
  "vitest": "4.1.11"