@tangle-network/agent-interface 1.2.0 → 1.4.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.
@@ -113,6 +113,10 @@ export function agentNativeContextContinuationResultMatchesRequest(request, outc
113
113
  (exactOutcome.result.sessionId === undefined ||
114
114
  exactOutcome.result.sessionId === current.sessionId));
115
115
  }
116
+ export const AgentEnvironmentCreationSchema = z.enum([
117
+ "created",
118
+ "replayed",
119
+ ]);
116
120
  /** Strict runtime validator for provider capability negotiation. */
117
121
  export const AgentEnvironmentCapabilitiesSchema = z
118
122
  .strictObject({
@@ -325,12 +329,34 @@ export function agentEnvironmentCreateInputDigest(input) {
325
329
  input: material,
326
330
  });
327
331
  }
332
+ /**
333
+ * Return the per-call view of an environment that a same-key create replayed.
334
+ *
335
+ * The view shares every member of the environment, so operations act on the
336
+ * one environment, and it states `creation: "replayed"` because this call
337
+ * provisioned nothing. The copy is shallow, so the environment must be a plain
338
+ * object whose members do not read `this`; a class instance loses its
339
+ * prototype members in a copy and is rejected.
340
+ * @internal
341
+ */
342
+ export function replayedAgentEnvironmentView(environment) {
343
+ const prototype = Object.getPrototypeOf(environment);
344
+ if (prototype !== Object.prototype && prototype !== null) {
345
+ throw new Error("a replayed agent environment view requires a plain object environment");
346
+ }
347
+ return { ...environment, creation: "replayed" };
348
+ }
328
349
  /**
329
350
  * Apply the generic create contract to one provider adapter's keyed requests.
330
351
  *
331
352
  * The provider's backing service remains responsible for retaining the key
332
353
  * across adapter reconstruction. This helper coalesces concurrent retries and
333
354
  * rejects collisions before the provider performs another create effect.
355
+ *
356
+ * The call that runs `create` receives the environment the provider built,
357
+ * with the creation verdict the provider could prove. Every same-key call
358
+ * after it, including one that awaited the same pending create, receives
359
+ * {@link replayedAgentEnvironmentView} of that environment.
334
360
  * @internal
335
361
  */
336
362
  export async function createAgentEnvironmentWithIdempotency(records, input, create) {
@@ -344,7 +370,7 @@ export async function createAgentEnvironmentWithIdempotency(records, input, crea
344
370
  if (existing.digest !== digest) {
345
371
  throw new Error("agent environment create idempotency key conflicts with a different create input");
346
372
  }
347
- return existing.environment ?? existing.pending;
373
+ return replayedAgentEnvironmentView(existing.environment ?? (await existing.pending));
348
374
  }
349
375
  const pending = Promise.resolve().then(create);
350
376
  const record = {
package/dist/index.d.ts CHANGED
@@ -8,7 +8,7 @@ export * from "./host-services.js";
8
8
  export * from "./mcp.js";
9
9
  export * from "./provider-adapter.js";
10
10
  export type * from "./environment-provider.js";
11
- export { AgentEnvironmentCapabilitiesSchema, AgentNativeContextContinuationResultSchema, AgentTurnInputSchema, AgentTurnResultSchema, agentEnvironmentCreateInputDigest, agentNativeContextContinuationResultMatchesRequest, AccountUsageSchema, AgentEnvironmentObservationSchema, AgentEnvironmentStatusSchema, ComputeBillingSchema, EnvironmentLifecycleSchema, ModelUsageSchema, ObservationProvenanceSchema, ObservationStateSchema, PlacementDescriptorSchema, ProviderIdentitySchema, ResourceProfileSchema, ResourceUseSampleSchema, SafeEndpointSchema, agentEnvironmentObservationIdentityMatches, assertObservationCredentialFree, observationContainsCredential, observationOf, AgentInteractiveSessionAttachSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimRequestSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionPromptCommandSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStartSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentInteractiveSessionStopCommandSchema, AgentInteractiveSessionStatusSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimRequestDigest, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionControlClaimIsNewer, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionPromptRequestDigest, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentInteractiveSessionStopRequestDigest, agentInteractiveSessionRequestDigest, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionRunRef, agentInteractiveSessionStatusMatchesRef, exactAgentInteractiveSessionStart, createAgentEnvironmentWithIdempotency, TerminalAttachRequestSchema, TerminalAttachResultSchema, TerminalDetachAckSchema, TerminalInputSchema, TerminalOutputEventSchema, TerminalReplayWindowSchema, TerminalResizeSchema, TerminalSessionRefSchema, terminalAttachResultMatchesRequest, terminalSessionUsable, } from "./environment-provider.js";
11
+ export { AgentEnvironmentCapabilitiesSchema, AgentNativeContextContinuationResultSchema, AgentTurnInputSchema, AgentTurnResultSchema, agentEnvironmentCreateInputDigest, agentNativeContextContinuationResultMatchesRequest, AccountUsageSchema, AgentEnvironmentObservationSchema, AgentEnvironmentStatusSchema, ComputeBillingSchema, EnvironmentLifecycleSchema, ModelUsageSchema, ObservationProvenanceSchema, ObservationStateSchema, PlacementDescriptorSchema, ProviderIdentitySchema, ResourceProfileSchema, ResourceUseSampleSchema, SafeEndpointSchema, agentEnvironmentObservationIdentityMatches, assertObservationCredentialFree, observationContainsCredential, observationOf, AgentInteractiveSessionAttachSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimRequestSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionPromptCommandSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStartSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentInteractiveSessionStopCommandSchema, AgentInteractiveSessionStatusSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimRequestDigest, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionControlClaimIsNewer, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionPromptRequestDigest, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentInteractiveSessionStopRequestDigest, agentInteractiveSessionRequestDigest, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionRunRef, agentInteractiveSessionStatusMatchesRef, exactAgentInteractiveSessionStart, AgentEnvironmentCreationSchema, createAgentEnvironmentWithIdempotency, replayedAgentEnvironmentView, TerminalAttachRequestSchema, TerminalAttachResultSchema, TerminalDetachAckSchema, TerminalInputSchema, TerminalOutputEventSchema, TerminalReplayWindowSchema, TerminalResizeSchema, TerminalSessionRefSchema, terminalAttachResultMatchesRequest, terminalSessionUsable, } from "./environment-provider.js";
12
12
  export * from "./plan.js";
13
13
  export * from "./runtime-control.js";
14
14
  export * from "./portable-context.js";
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ export * from "./provider-config.js";
7
7
  export * from "./host-services.js";
8
8
  export * from "./mcp.js";
9
9
  export * from "./provider-adapter.js";
10
- export { AgentEnvironmentCapabilitiesSchema, AgentNativeContextContinuationResultSchema, AgentTurnInputSchema, AgentTurnResultSchema, agentEnvironmentCreateInputDigest, agentNativeContextContinuationResultMatchesRequest, AccountUsageSchema, AgentEnvironmentObservationSchema, AgentEnvironmentStatusSchema, ComputeBillingSchema, EnvironmentLifecycleSchema, ModelUsageSchema, ObservationProvenanceSchema, ObservationStateSchema, PlacementDescriptorSchema, ProviderIdentitySchema, ResourceProfileSchema, ResourceUseSampleSchema, SafeEndpointSchema, agentEnvironmentObservationIdentityMatches, assertObservationCredentialFree, observationContainsCredential, observationOf, AgentInteractiveSessionAttachSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimRequestSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionPromptCommandSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStartSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentInteractiveSessionStopCommandSchema, AgentInteractiveSessionStatusSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimRequestDigest, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionControlClaimIsNewer, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionPromptRequestDigest, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentInteractiveSessionStopRequestDigest, agentInteractiveSessionRequestDigest, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionRunRef, agentInteractiveSessionStatusMatchesRef, exactAgentInteractiveSessionStart, createAgentEnvironmentWithIdempotency, TerminalAttachRequestSchema, TerminalAttachResultSchema, TerminalDetachAckSchema, TerminalInputSchema, TerminalOutputEventSchema, TerminalReplayWindowSchema, TerminalResizeSchema, TerminalSessionRefSchema, terminalAttachResultMatchesRequest, terminalSessionUsable, } from "./environment-provider.js";
10
+ export { AgentEnvironmentCapabilitiesSchema, AgentNativeContextContinuationResultSchema, AgentTurnInputSchema, AgentTurnResultSchema, agentEnvironmentCreateInputDigest, agentNativeContextContinuationResultMatchesRequest, AccountUsageSchema, AgentEnvironmentObservationSchema, AgentEnvironmentStatusSchema, ComputeBillingSchema, EnvironmentLifecycleSchema, ModelUsageSchema, ObservationProvenanceSchema, ObservationStateSchema, PlacementDescriptorSchema, ProviderIdentitySchema, ResourceProfileSchema, ResourceUseSampleSchema, SafeEndpointSchema, agentEnvironmentObservationIdentityMatches, assertObservationCredentialFree, observationContainsCredential, observationOf, AgentInteractiveSessionAttachSchema, AgentInteractiveSessionControlClaimAcknowledgementSchema, AgentInteractiveSessionControlClaimRequestSchema, AgentInteractiveSessionControlClaimSchema, AgentInteractiveSessionPromptAcknowledgementSchema, AgentInteractiveSessionPromptCommandSchema, AgentInteractiveSessionRefSchema, AgentInteractiveSessionStartSchema, AgentInteractiveSessionStopAcknowledgementSchema, AgentInteractiveSessionStopCommandSchema, AgentInteractiveSessionStatusSchema, agentInteractiveSessionControlClaimAcknowledgementMatchesRequest, agentInteractiveSessionControlClaimRequestDigest, agentInteractiveSessionControlClaimMatchesRef, agentInteractiveSessionControlClaimIsNewer, agentInteractiveSessionPromptAcknowledgementMatchesCommand, agentInteractiveSessionPromptRequestDigest, agentInteractiveSessionStopAcknowledgementMatchesCommand, agentInteractiveSessionStopRequestDigest, agentInteractiveSessionRequestDigest, agentInteractiveSessionRefMatchesStart, agentInteractiveSessionRunRef, agentInteractiveSessionStatusMatchesRef, exactAgentInteractiveSessionStart, AgentEnvironmentCreationSchema, createAgentEnvironmentWithIdempotency, replayedAgentEnvironmentView, TerminalAttachRequestSchema, TerminalAttachResultSchema, TerminalDetachAckSchema, TerminalInputSchema, TerminalOutputEventSchema, TerminalReplayWindowSchema, TerminalResizeSchema, TerminalSessionRefSchema, terminalAttachResultMatchesRequest, terminalSessionUsable, } from "./environment-provider.js";
11
11
  export * from "./plan.js";
12
12
  export * from "./runtime-control.js";
13
13
  export * from "./portable-context.js";
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { canonicalCandidateDigest, sha256DigestSchema, } from "./agent-candidate-schema-common.js";
3
3
  import { boundedIdentifierSchema, boundedJsonRecordSchema, boundedJsonSchema, boundedStringSchema, } from "./contract-limits.js";
4
+ import { ModelUsageSchema } from "./environment-observation.js";
4
5
  import { InteractionRequestSchema } from "./interaction.js";
5
6
  import { DurablePlanSchema } from "./plan.js";
6
7
  const stableIdSchema = boundedIdentifierSchema;
@@ -263,6 +264,70 @@ const partSchema = z.discriminatedUnion("type", [
263
264
  agent: stableIdSchema,
264
265
  }),
265
266
  ]);
267
+ const TERMINAL_CHILD_TASK_STATUSES = new Set(["completed", "failed", "cancelled"]);
268
+ const epochMillisecondsSchema = z.number().finite().nonnegative();
269
+ /**
270
+ * Provider-native child task lifecycle. Identity comes only from `childId`,
271
+ * `parentChildId`, and `sourceEventId`; `raw` is opaque and bounded. A provider
272
+ * without a stable `childId` emits no `child-task` event.
273
+ */
274
+ const ChildTaskEventSchema = z
275
+ .strictObject({
276
+ type: z.literal("child-task"),
277
+ childId: stableIdSchema,
278
+ parentChildId: stableIdSchema.optional(),
279
+ status: z.enum(["started", "running", "completed", "failed", "cancelled"]),
280
+ title: boundedStringSchema.optional(),
281
+ time: z.strictObject({
282
+ started: epochMillisecondsSchema,
283
+ updated: epochMillisecondsSchema,
284
+ ended: epochMillisecondsSchema.optional(),
285
+ }),
286
+ runner: stableIdSchema.optional(),
287
+ model: stableIdSchema.optional(),
288
+ usage: ModelUsageSchema.optional(),
289
+ terminalReason: boundedStringSchema.optional(),
290
+ sourceEventId: stableIdSchema,
291
+ raw: boundedJsonRecordSchema.optional(),
292
+ })
293
+ .superRefine((event, refinement) => {
294
+ const terminal = TERMINAL_CHILD_TASK_STATUSES.has(event.status);
295
+ if (!terminal && event.time.ended !== undefined) {
296
+ refinement.addIssue({
297
+ code: "custom",
298
+ path: ["time", "ended"],
299
+ message: "only a terminal child task status may carry an end time",
300
+ });
301
+ }
302
+ if (!terminal && event.terminalReason !== undefined) {
303
+ refinement.addIssue({
304
+ code: "custom",
305
+ path: ["terminalReason"],
306
+ message: "only a terminal child task status may carry a terminal reason",
307
+ });
308
+ }
309
+ if (event.time.updated < event.time.started) {
310
+ refinement.addIssue({
311
+ code: "custom",
312
+ path: ["time", "updated"],
313
+ message: "a child task update time cannot precede its start time",
314
+ });
315
+ }
316
+ if (event.time.ended !== undefined && event.time.ended < event.time.started) {
317
+ refinement.addIssue({
318
+ code: "custom",
319
+ path: ["time", "ended"],
320
+ message: "a child task end time cannot precede its start time",
321
+ });
322
+ }
323
+ if (event.parentChildId === event.childId) {
324
+ refinement.addIssue({
325
+ code: "custom",
326
+ path: ["parentChildId"],
327
+ message: "a child task cannot be its own parent",
328
+ });
329
+ }
330
+ });
266
331
  /** Runtime validator for every member of the existing canonical event union. */
267
332
  export const CanonicalStreamEventSchema = z.discriminatedUnion("type", [
268
333
  z.strictObject({
@@ -332,6 +397,7 @@ export const CanonicalStreamEventSchema = z.discriminatedUnion("type", [
332
397
  type: z.literal("plan.submitted"),
333
398
  plan: DurablePlanSchema,
334
399
  }),
400
+ ChildTaskEventSchema,
335
401
  ]);
336
402
  export const RuntimeEventEnvelopeSchema = z.strictObject({
337
403
  runId: stableIdSchema,
@@ -1,3 +1,4 @@
1
+ import type { TokenUsage } from "./execution-types.js";
1
2
  import type { InteractionRequest } from "./interaction.js";
2
3
  import type { DurablePlan } from "./plan.js";
3
4
  import type { Part } from "./parts.js";
@@ -7,6 +8,63 @@ export type MessagePartUpdatedEvent = {
7
8
  delta?: string;
8
9
  };
9
10
  export type StreamStatus = "started" | "processing" | "completed" | "failed" | "cancelled";
11
+ export type ChildTaskStatus = "started" | "running" | "completed" | "failed" | "cancelled";
12
+ /**
13
+ * One observed update of a provider-native child task: a subagent, worker, or
14
+ * delegated task that the runner started inside the same run.
15
+ *
16
+ * Identity rules:
17
+ * - `childId` is the provider's stable identifier for the child task. Every
18
+ * update of one child repeats the same `childId`. A provider that cannot
19
+ * report a stable `childId` emits no `child-task` event.
20
+ * - `parentChildId` names the parent child task. It is absent when the parent
21
+ * is the run itself.
22
+ * - `sourceEventId` is the provider's identifier for this exact update. Two
23
+ * events with the same `sourceEventId` are the same update, so a consumer
24
+ * applies the first and ignores the rest during replay or reconnect.
25
+ * - Identity never depends on `raw`. `raw` is an opaque, bounded copy of
26
+ * provider fields that have no canonical position.
27
+ *
28
+ * Certainty rules:
29
+ * - `time.ended` and `terminalReason` are present only with a terminal status
30
+ * (`completed`, `failed`, `cancelled`).
31
+ * - `time.updated` and `time.ended` are never earlier than `time.started`.
32
+ *
33
+ * Dedupe example for a consumer that rebuilds the child tree from a replayed
34
+ * stream. Live and replayed streams produce the same tree because identity
35
+ * comes only from `childId`, `parentChildId`, and `sourceEventId`:
36
+ *
37
+ * ```ts
38
+ * const applied = new Set<string>();
39
+ * const children = new Map<string, ChildTaskEvent>();
40
+ * for (const event of events) {
41
+ * if (event.type !== "child-task") continue;
42
+ * if (applied.has(event.sourceEventId)) continue;
43
+ * applied.add(event.sourceEventId);
44
+ * children.set(event.childId, event);
45
+ * }
46
+ * ```
47
+ */
48
+ export type ChildTaskEvent = {
49
+ type: "child-task";
50
+ childId: string;
51
+ parentChildId?: string;
52
+ status: ChildTaskStatus;
53
+ title?: string;
54
+ /** Epoch milliseconds reported by the provider. */
55
+ time: {
56
+ started: number;
57
+ updated: number;
58
+ ended?: number;
59
+ };
60
+ /** Runner that executes the child, for example `claude-code`. */
61
+ runner?: string;
62
+ model?: string;
63
+ usage?: TokenUsage;
64
+ terminalReason?: string;
65
+ sourceEventId: string;
66
+ raw?: Record<string, unknown>;
67
+ };
10
68
  export type StreamEvent = MessagePartUpdatedEvent | {
11
69
  type: "tool-heartbeat";
12
70
  toolName: string;
@@ -53,4 +111,4 @@ export type StreamEvent = MessagePartUpdatedEvent | {
53
111
  } | {
54
112
  type: "plan.submitted";
55
113
  plan: DurablePlan;
56
- };
114
+ } | ChildTaskEvent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tangle-network/agent-interface",
3
- "version": "1.2.0",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -22,6 +22,11 @@
22
22
  "types": "./dist/environment-interactive.d.ts",
23
23
  "default": "./dist/environment-interactive.js"
24
24
  },
25
+ "./environment-interactive-control": {
26
+ "import": "./dist/environment-interactive-control.js",
27
+ "types": "./dist/environment-interactive-control.d.ts",
28
+ "default": "./dist/environment-interactive-control.js"
29
+ },
25
30
  "./profile": {
26
31
  "import": "./dist/agent-profile.js",
27
32
  "types": "./dist/agent-profile.d.ts",