@agen-ai/agent-runtime 0.2.2 → 0.2.3

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.
@@ -1,6 +1,7 @@
1
- import type { AgentAuthenticationFlow, AgentError, AgentRequestResolution, AgentSessionBinding, AgentSessionBranchSource, AgentSessionConfiguration, AgentSessionId, AgentTurnId, AgentTurnInputContent, AgentTurnInteractionMode, AgentTurnInputPart, AgentTurnInterruptionReason } from "@agen-ai/agent-protocol";
1
+ import type { AgentAuthenticationFlow, AgentCollaborationControlInput, AgentCollaborationNode, AgentCollaborationSpawnInput, AgentConfigurationCatalog, AgentConfigurationSelectionInput, AgentError, AgentGeneratedResourceDescriptor, AgentGeneratedResourceId, AgentIntegrationCatalog, AgentManagedContentCatalog, AgentOperationCatalog, AgentOperationInvocation, AgentOperationResult, AgentRequestResolution, AgentSessionBinding, AgentSessionBranchSource, AgentSessionConfiguration, AgentSessionId, AgentTurnId, AgentTurnInputContent, AgentTurnInteractionMode, AgentTurnInputPart, AgentTurnInterruptionReason } from "@agen-ai/agent-protocol";
2
2
  import type { MaybePromise } from "./foundation.js";
3
3
  import type { AgentProviderOutput } from "./outputs.js";
4
+ import type { AgentArtifactCandidate } from "./artifacts.js";
4
5
  export interface AgentProviderSessionContext {
5
6
  readonly sessionId: AgentSessionId;
6
7
  readonly workingDirectory: string;
@@ -38,9 +39,36 @@ export interface AgentProviderInterruptTurnInput {
38
39
  readonly requestedAt?: string;
39
40
  readonly signal?: AbortSignal;
40
41
  }
41
- export interface AgentProviderApplyConfigurationInput {
42
- readonly configuration: AgentSessionConfiguration;
42
+ export interface AgentProviderListInput {
43
+ readonly signal?: AbortSignal;
44
+ }
45
+ export interface AgentProviderApplyConfigurationSelectionInput {
46
+ readonly selection: AgentConfigurationSelectionInput;
47
+ readonly signal?: AbortSignal;
48
+ readonly onProviderExecutionStarted?: AgentProviderExecutionStartedObserver;
49
+ }
50
+ export interface AgentProviderInvokeOperationInput {
51
+ readonly invocation: AgentOperationInvocation;
52
+ readonly signal?: AbortSignal;
53
+ readonly onProviderExecutionStarted?: AgentProviderExecutionStartedObserver;
54
+ }
55
+ export interface AgentProviderSpawnCollaborationInput {
56
+ readonly spawn: AgentCollaborationSpawnInput;
43
57
  readonly signal?: AbortSignal;
58
+ readonly onProviderExecutionStarted?: AgentProviderExecutionStartedObserver;
59
+ }
60
+ export interface AgentProviderControlCollaborationInput {
61
+ readonly control: AgentCollaborationControlInput;
62
+ readonly signal?: AbortSignal;
63
+ readonly onProviderExecutionStarted?: AgentProviderExecutionStartedObserver;
64
+ }
65
+ export interface AgentProviderGetGeneratedResourceInput {
66
+ readonly resourceId: AgentGeneratedResourceId;
67
+ readonly signal?: AbortSignal;
68
+ }
69
+ export interface AgentGeneratedResourceInspection {
70
+ readonly descriptor: AgentGeneratedResourceDescriptor;
71
+ readonly candidate?: AgentArtifactCandidate;
44
72
  }
45
73
  export interface AgentProviderSteerTurnInput extends AgentTurnInputContent {
46
74
  readonly turnId: AgentTurnId;
@@ -82,7 +110,40 @@ export type AgentSessionConfigurationControl = Readonly<{
82
110
  kind: "managed";
83
111
  }> | Readonly<{
84
112
  kind: "selectable";
85
- applyConfiguration: (input: AgentProviderApplyConfigurationInput) => MaybePromise<AgentProviderOperationResult>;
113
+ listConfiguration: (input?: AgentProviderListInput) => MaybePromise<AgentConfigurationCatalog>;
114
+ applyConfigurationSelection: (input: AgentProviderApplyConfigurationSelectionInput) => MaybePromise<AgentProviderOperationResult>;
115
+ }>;
116
+ export type AgentOperationControl = Readonly<{
117
+ kind: "unsupported";
118
+ }> | Readonly<{
119
+ kind: "supported";
120
+ listOperations: (input?: AgentProviderListInput) => MaybePromise<AgentOperationCatalog>;
121
+ invokeOperation: (input: AgentProviderInvokeOperationInput) => MaybePromise<AgentOperationResult>;
122
+ }>;
123
+ export type AgentManagedContentInventory = Readonly<{
124
+ kind: "unsupported";
125
+ }> | Readonly<{
126
+ kind: "supported";
127
+ listManagedContent: (input?: AgentProviderListInput) => MaybePromise<AgentManagedContentCatalog>;
128
+ }>;
129
+ export type AgentIntegrationObservation = Readonly<{
130
+ kind: "unsupported";
131
+ }> | Readonly<{
132
+ kind: "supported";
133
+ observeIntegrations: (input?: AgentProviderListInput) => MaybePromise<AgentIntegrationCatalog>;
134
+ }>;
135
+ export type AgentCollaborationControl = Readonly<{
136
+ kind: "unsupported";
137
+ }> | Readonly<{
138
+ kind: "supported";
139
+ spawnCollaboration: (input: AgentProviderSpawnCollaborationInput) => MaybePromise<AgentCollaborationNode>;
140
+ controlCollaboration: (input: AgentProviderControlCollaborationInput) => MaybePromise<AgentCollaborationNode>;
141
+ }>;
142
+ export type AgentGeneratedResourceAccess = Readonly<{
143
+ kind: "unsupported";
144
+ }> | Readonly<{
145
+ kind: "supported";
146
+ getGeneratedResource: (input: AgentProviderGetGeneratedResourceInput) => MaybePromise<AgentGeneratedResourceInspection>;
86
147
  }>;
87
148
  export interface AgentProviderSession {
88
149
  readonly binding: AgentSessionBinding;
@@ -91,6 +152,11 @@ export interface AgentProviderSession {
91
152
  readonly interruption: AgentTurnInterruption;
92
153
  readonly steering: AgentTurnSteering;
93
154
  readonly configuration: AgentSessionConfigurationControl;
155
+ readonly operations: AgentOperationControl;
156
+ readonly managedContent: AgentManagedContentInventory;
157
+ readonly integrations: AgentIntegrationObservation;
158
+ readonly collaboration: AgentCollaborationControl;
159
+ readonly generatedResources: AgentGeneratedResourceAccess;
94
160
  readonly close: (input: AgentProviderCloseSessionInput) => MaybePromise<void>;
95
161
  }
96
162
  export type AgentSessionResumption = Readonly<{
@@ -1,4 +1,4 @@
1
- import { type AgentRequest, type AgentRequestResolution, type AgentSessionBinding, type AgentSessionBranchSource, type AgentSessionConfiguration, type AgentSessionId, type AgentTurnId, type AgentTurnInputContent } from "@agen-ai/agent-protocol";
1
+ import { type AgentCollaborationSpawnInput, type AgentConfigurationSelectionInput, type AgentGeneratedResourceId, type AgentOperationInvocation, type AgentRequest, type AgentRequestResolution, type AgentSessionBinding, type AgentSessionBranchSource, type AgentSessionConfiguration, type AgentSessionId, type AgentTurnId, type AgentTurnInputContent } from "@agen-ai/agent-protocol";
2
2
  import type { AgentProviderDriver, AgentProviderInstanceDefinition } from "../providerDriver.js";
3
3
  import type { AgentProviderRunTurnInput } from "../sessions.js";
4
4
  export interface AgentProviderConformanceScenario {
@@ -6,7 +6,10 @@ export interface AgentProviderConformanceScenario {
6
6
  readonly definition: AgentProviderInstanceDefinition;
7
7
  readonly workingDirectory: string;
8
8
  readonly configuration: AgentSessionConfiguration;
9
- readonly updatedConfiguration?: AgentSessionConfiguration;
9
+ readonly configurationSelection?: AgentConfigurationSelectionInput;
10
+ readonly operationInvocation?: AgentOperationInvocation;
11
+ readonly collaborationSpawn?: AgentCollaborationSpawnInput;
12
+ readonly generatedResourceId?: AgentGeneratedResourceId;
10
13
  readonly createSessionId: AgentSessionId;
11
14
  readonly resumeSessionId: AgentSessionId;
12
15
  readonly branchSessionId?: AgentSessionId;
@@ -275,12 +275,24 @@ async function runAgentProviderConformance(scenario) {
275
275
  checks.push("interruption");
276
276
  if (instance.capabilities.configuration.kind === "selectable") {
277
277
  requireCheck(
278
- created.configuration.kind === "selectable" && scenario.updatedConfiguration !== void 0,
278
+ created.configuration.kind === "selectable" && scenario.configurationSelection !== void 0,
279
279
  "configuration",
280
- "Selectable configuration requires a handler and updated fixture."
280
+ "Selectable configuration requires a handler and selection fixture."
281
281
  );
282
- const result = await created.configuration.applyConfiguration({
283
- configuration: scenario.updatedConfiguration
282
+ const catalog = await created.configuration.listConfiguration();
283
+ requireCheck(
284
+ catalog.fields.some(
285
+ (field) => field.key === scenario.configurationSelection?.key
286
+ ),
287
+ "configuration",
288
+ "Configuration catalog did not offer the selected field."
289
+ );
290
+ let executionStarted = 0;
291
+ const result = await created.configuration.applyConfigurationSelection({
292
+ selection: scenario.configurationSelection,
293
+ onProviderExecutionStarted: () => {
294
+ executionStarted += 1;
295
+ }
284
296
  });
285
297
  requireOperationStatus(
286
298
  result,
@@ -288,6 +300,11 @@ async function runAgentProviderConformance(scenario) {
288
300
  "configuration",
289
301
  "Selectable configuration did not complete atomically."
290
302
  );
303
+ requireCheck(
304
+ executionStarted === 1,
305
+ "configuration",
306
+ "Configuration selection did not report exactly one execution start."
307
+ );
291
308
  } else {
292
309
  requireCheck(
293
310
  created.configuration.kind === "managed",
@@ -296,6 +313,146 @@ async function runAgentProviderConformance(scenario) {
296
313
  );
297
314
  }
298
315
  checks.push("configuration");
316
+ if (instance.capabilities.operations.kind === "supported") {
317
+ requireCheck(
318
+ created.operations.kind === "supported" && scenario.operationInvocation !== void 0,
319
+ "operations",
320
+ "Supported operations require matching ports and an invocation fixture."
321
+ );
322
+ const catalog = await created.operations.listOperations();
323
+ requireCheck(
324
+ catalog.operations.some(
325
+ (operation) => operation.operationId === scenario.operationInvocation?.operationId
326
+ ),
327
+ "operations",
328
+ "Operation catalog did not offer the invocation fixture."
329
+ );
330
+ let executionStarted = 0;
331
+ const result = await created.operations.invokeOperation({
332
+ invocation: scenario.operationInvocation,
333
+ onProviderExecutionStarted: () => {
334
+ executionStarted += 1;
335
+ }
336
+ });
337
+ requireCheck(
338
+ result.status === "completed" && executionStarted === 1,
339
+ "operations",
340
+ "Operation invocation did not complete with one execution-start receipt."
341
+ );
342
+ } else {
343
+ requireCheck(
344
+ created.operations.kind === "unsupported",
345
+ "operations",
346
+ "Unsupported operations exposed callable ports."
347
+ );
348
+ }
349
+ checks.push("operations");
350
+ if (instance.capabilities.managedContent.kind === "supported") {
351
+ requireCheck(
352
+ created.managedContent.kind === "supported",
353
+ "managed_content",
354
+ "Supported managed content has no inventory port."
355
+ );
356
+ await created.managedContent.listManagedContent();
357
+ } else {
358
+ requireCheck(
359
+ created.managedContent.kind === "unsupported",
360
+ "managed_content",
361
+ "Unsupported managed content exposed an inventory port."
362
+ );
363
+ }
364
+ checks.push("managed_content");
365
+ if (instance.capabilities.integrations.kind === "supported") {
366
+ requireCheck(
367
+ created.integrations.kind === "supported",
368
+ "integrations",
369
+ "Supported integrations have no observation port."
370
+ );
371
+ await created.integrations.observeIntegrations();
372
+ } else {
373
+ requireCheck(
374
+ created.integrations.kind === "unsupported",
375
+ "integrations",
376
+ "Unsupported integrations exposed an observation port."
377
+ );
378
+ }
379
+ checks.push("integrations");
380
+ if (instance.capabilities.collaboration.kind === "supported") {
381
+ requireCheck(
382
+ created.collaboration.kind === "supported" && scenario.collaborationSpawn !== void 0,
383
+ "collaboration",
384
+ "Supported collaboration requires matching ports and a spawn fixture."
385
+ );
386
+ let executionStarted = 0;
387
+ const spawned = await created.collaboration.spawnCollaboration({
388
+ spawn: scenario.collaborationSpawn,
389
+ onProviderExecutionStarted: () => {
390
+ executionStarted += 1;
391
+ }
392
+ });
393
+ const stopped = await created.collaboration.controlCollaboration({
394
+ control: {
395
+ action: "stop",
396
+ collaborationId: spawned.collaborationId,
397
+ reason: "user_requested"
398
+ },
399
+ onProviderExecutionStarted: () => {
400
+ executionStarted += 1;
401
+ }
402
+ });
403
+ const closed = await created.collaboration.controlCollaboration({
404
+ control: {
405
+ action: "close",
406
+ collaborationId: stopped.collaborationId
407
+ },
408
+ onProviderExecutionStarted: () => {
409
+ executionStarted += 1;
410
+ }
411
+ });
412
+ const replayedClose = await created.collaboration.controlCollaboration({
413
+ control: {
414
+ action: "close",
415
+ collaborationId: stopped.collaborationId
416
+ },
417
+ onProviderExecutionStarted: () => {
418
+ executionStarted += 1;
419
+ }
420
+ });
421
+ requireCheck(
422
+ closed.status === "canceled" && closed.outcome?.kind === "canceled" && closed.closedAt !== void 0 && replayedClose === closed && executionStarted === 3,
423
+ "collaboration",
424
+ "Collaboration lifecycle did not preserve control and execution receipts."
425
+ );
426
+ } else {
427
+ requireCheck(
428
+ created.collaboration.kind === "unsupported",
429
+ "collaboration",
430
+ "Unsupported collaboration exposed callable ports."
431
+ );
432
+ }
433
+ checks.push("collaboration");
434
+ if (instance.capabilities.generatedResources.kind === "supported") {
435
+ requireCheck(
436
+ created.generatedResources.kind === "supported" && scenario.generatedResourceId !== void 0,
437
+ "generated_resources",
438
+ "Supported generated resources require an access port and fixture."
439
+ );
440
+ const resource = await created.generatedResources.getGeneratedResource({
441
+ resourceId: scenario.generatedResourceId
442
+ });
443
+ requireCheck(
444
+ resource.descriptor.resourceId === scenario.generatedResourceId,
445
+ "generated_resources",
446
+ "Generated resource access returned another resource."
447
+ );
448
+ } else {
449
+ requireCheck(
450
+ created.generatedResources.kind === "unsupported",
451
+ "generated_resources",
452
+ "Unsupported generated resources exposed an access port."
453
+ );
454
+ }
455
+ checks.push("generated_resources");
299
456
  await created.close({ reason: "idle" });
300
457
  await created.close({ reason: "idle" });
301
458
  checks.push("idempotent_session_close");
@@ -3,6 +3,7 @@ import {
3
3
  parseAgentInstanceId,
4
4
  parseAgentIsoDateTime,
5
5
  parseAgentItemId,
6
+ parseAgentOperationId,
6
7
  parseAgentApprovalOptionId,
7
8
  parseAgentProviderConversationId,
8
9
  parseAgentProviderHistoryAnchor,
@@ -35,7 +36,7 @@ function defaultCapabilities(providerKey) {
35
36
  }
36
37
  };
37
38
  return parseAgentCapabilities({
38
- protocolVersion: 7,
39
+ protocolVersion: 8,
39
40
  providerKey,
40
41
  sessions: { create: true, resume: true, branch: { kind: "through_turn" } },
41
42
  turns: {
@@ -48,7 +49,18 @@ function defaultCapabilities(providerKey) {
48
49
  kind: "supported",
49
50
  modes: [{ persistence: "once", scopeKinds: ["exact_action"] }]
50
51
  },
51
- elicitation: { kind: "structured" }
52
+ elicitation: {
53
+ kind: "supported",
54
+ fieldKinds: [
55
+ "text",
56
+ "single_select",
57
+ "multi_select",
58
+ "boolean",
59
+ "confirmation"
60
+ ],
61
+ maxFields: 16,
62
+ sensitiveFields: true
63
+ }
52
64
  },
53
65
  context: {
54
66
  usage: { kind: "unsupported" },
@@ -63,19 +75,61 @@ function defaultCapabilities(providerKey) {
63
75
  },
64
76
  configuration: {
65
77
  kind: "selectable",
66
- fields: [
67
- { key: "mode", optionIds: ["agent"] },
68
- {
69
- key: "model",
70
- optionIds: ["fake-model", "fake-model-2"]
71
- }
72
- ]
78
+ fieldKinds: [
79
+ "boolean",
80
+ "single_select",
81
+ "bounded_integer",
82
+ "bounded_text"
83
+ ],
84
+ maxFields: 100
85
+ },
86
+ operations: {
87
+ kind: "supported",
88
+ operationKinds: [
89
+ "session_control",
90
+ "managed_content_invoke",
91
+ "configuration_select",
92
+ "integration_control",
93
+ "collaboration_control",
94
+ "resource_generate"
95
+ ],
96
+ fieldKinds: [
97
+ "text",
98
+ "boolean",
99
+ "single_select",
100
+ "multi_select",
101
+ "integer"
102
+ ],
103
+ executionModes: ["immediate", "request_continuation", "durable_job"],
104
+ maxOperations: 100,
105
+ maxFieldsPerOperation: 16
73
106
  },
74
- interactionExtensions: {
75
- slashCommands: false,
76
- mcp: false,
77
- subagents: false,
78
- imageGeneration: false
107
+ managedContent: {
108
+ kind: "supported",
109
+ contentKinds: ["skill", "rule", "prompt", "agent_definition"],
110
+ maxEntries: 100
111
+ },
112
+ integrations: {
113
+ kind: "supported",
114
+ integrationKinds: ["mcp"],
115
+ maxIntegrations: 32,
116
+ maxServersPerIntegration: 32,
117
+ maxToolsPerServer: 100,
118
+ maxResourcesPerServer: 100
119
+ },
120
+ collaboration: {
121
+ kind: "supported",
122
+ roles: ["delegate", "reviewer", "researcher", "specialist"],
123
+ controlActions: ["spawn", "steer", "stop", "close", "inspect"],
124
+ maxDepth: 8,
125
+ maxChildrenPerNode: 16,
126
+ maxActiveNodes: 64
127
+ },
128
+ generatedResources: {
129
+ kind: "supported",
130
+ resourceKinds: ["image", "document", "archive"],
131
+ maxResourcesPerTurn: 16,
132
+ maxBytesPerResource: 25 * 1024 * 1024
79
133
  },
80
134
  authentication: { kind: "unsupported" },
81
135
  versionReporting: true
@@ -93,7 +147,7 @@ function sessionBinding(state, sessionId) {
93
147
  };
94
148
  }
95
149
  function eventBase(sessionId, turnId, occurredAt) {
96
- return { protocolVersion: 7, sessionId, turnId, occurredAt };
150
+ return { protocolVersion: 8, sessionId, turnId, occurredAt };
97
151
  }
98
152
  function requestForTurn(turnId) {
99
153
  return {
@@ -131,6 +185,13 @@ function completedResult(outputs = []) {
131
185
  }
132
186
  function fakeSession(input) {
133
187
  const pendingRequests = /* @__PURE__ */ new Map();
188
+ const collaborationNodes = /* @__PURE__ */ new Map();
189
+ const nextCollaborationObservedAt = (previous) => {
190
+ const observed = input.now();
191
+ return Date.parse(observed) > Date.parse(previous) ? observed : parseAgentIsoDateTime(
192
+ new Date(Date.parse(previous) + 1).toISOString()
193
+ );
194
+ };
134
195
  let closed = false;
135
196
  const runTurn = async function* (turnInput) {
136
197
  throwIfAgentOperationAborted(turnInput.signal);
@@ -256,14 +317,156 @@ function fakeSession(input) {
256
317
  } : { kind: "unsupported" },
257
318
  configuration: input.capabilities.configuration.kind === "selectable" ? {
258
319
  kind: "selectable",
259
- applyConfiguration: async (configurationInput) => {
320
+ listConfiguration: async (listInput = {}) => {
321
+ throwIfAgentOperationAborted(listInput.signal);
322
+ return {
323
+ revision: 1,
324
+ fields: [{
325
+ key: "model",
326
+ revision: 1,
327
+ label: "Model",
328
+ scope: "session",
329
+ applicationTiming: "next_session",
330
+ mutable: true,
331
+ fieldKind: "single_select",
332
+ currentValue: "fake-model",
333
+ options: [
334
+ { optionId: "fake-model", label: "Fake model" },
335
+ { optionId: "fake-model-2", label: "Fake model 2" }
336
+ ]
337
+ }]
338
+ };
339
+ },
340
+ applyConfigurationSelection: async (configurationInput) => {
260
341
  throwIfAgentOperationAborted(configurationInput.signal);
342
+ configurationInput.onProviderExecutionStarted?.();
261
343
  input.state.configurationRevisions.push(
262
- configurationInput.configuration.revision
344
+ `${configurationInput.selection.expectedCatalogRevision}:${configurationInput.selection.key}`
263
345
  );
264
346
  return completedResult();
265
347
  }
266
348
  } : { kind: "managed" },
349
+ operations: input.capabilities.operations.kind === "supported" ? {
350
+ kind: "supported",
351
+ listOperations: async (listInput = {}) => {
352
+ throwIfAgentOperationAborted(listInput.signal);
353
+ return {
354
+ revision: 1,
355
+ operations: [{
356
+ operationId: parseAgentOperationId("fake.session.reset"),
357
+ revision: 1,
358
+ kind: "session_control",
359
+ title: "Reset fake session",
360
+ context: "session",
361
+ timing: "idle_session",
362
+ executionMode: "immediate",
363
+ fields: [],
364
+ confirmation: "required",
365
+ idempotency: "required",
366
+ resultKind: "none"
367
+ }]
368
+ };
369
+ },
370
+ invokeOperation: async (operationInput) => {
371
+ throwIfAgentOperationAborted(operationInput.signal);
372
+ operationInput.onProviderExecutionStarted?.();
373
+ return {
374
+ invocationId: operationInput.invocation.invocationId,
375
+ status: "completed"
376
+ };
377
+ }
378
+ } : { kind: "unsupported" },
379
+ managedContent: input.capabilities.managedContent.kind === "supported" ? {
380
+ kind: "supported",
381
+ listManagedContent: async (listInput = {}) => {
382
+ throwIfAgentOperationAborted(listInput.signal);
383
+ return { revision: 1, entries: [] };
384
+ }
385
+ } : { kind: "unsupported" },
386
+ integrations: input.capabilities.integrations.kind === "supported" ? {
387
+ kind: "supported",
388
+ observeIntegrations: async (listInput = {}) => {
389
+ throwIfAgentOperationAborted(listInput.signal);
390
+ return {
391
+ revision: 1,
392
+ observedAt: input.now(),
393
+ integrations: []
394
+ };
395
+ }
396
+ } : { kind: "unsupported" },
397
+ collaboration: input.capabilities.collaboration.kind === "supported" ? {
398
+ kind: "supported",
399
+ spawnCollaboration: async (collaborationInput) => {
400
+ throwIfAgentOperationAborted(collaborationInput.signal);
401
+ collaborationInput.onProviderExecutionStarted?.();
402
+ const parent = collaborationInput.spawn.parentCollaborationId === void 0 ? void 0 : collaborationNodes.get(
403
+ collaborationInput.spawn.parentCollaborationId
404
+ );
405
+ const now = nextCollaborationObservedAt(
406
+ collaborationInput.spawn.createdAt
407
+ );
408
+ const node = {
409
+ collaborationId: collaborationInput.spawn.collaborationId,
410
+ rootCollaborationId: parent?.rootCollaborationId ?? collaborationInput.spawn.collaborationId,
411
+ ...collaborationInput.spawn.parentCollaborationId === void 0 ? {} : {
412
+ parentCollaborationId: collaborationInput.spawn.parentCollaborationId
413
+ },
414
+ role: collaborationInput.spawn.role,
415
+ title: collaborationInput.spawn.title,
416
+ status: "running",
417
+ objective: collaborationInput.spawn.objective,
418
+ usage: { kind: "unavailable" },
419
+ createdAt: collaborationInput.spawn.createdAt,
420
+ updatedAt: now
421
+ };
422
+ collaborationNodes.set(node.collaborationId, node);
423
+ return node;
424
+ },
425
+ controlCollaboration: async (collaborationInput) => {
426
+ throwIfAgentOperationAborted(collaborationInput.signal);
427
+ collaborationInput.onProviderExecutionStarted?.();
428
+ const previous = collaborationNodes.get(
429
+ collaborationInput.control.collaborationId
430
+ );
431
+ if (previous === void 0) {
432
+ throw new TypeError("Fake collaboration does not exist.");
433
+ }
434
+ const now = nextCollaborationObservedAt(previous.updatedAt);
435
+ const node = {
436
+ ...previous,
437
+ updatedAt: now,
438
+ ...collaborationInput.control.action === "stop" ? {
439
+ status: "canceled",
440
+ terminalAt: previous.terminalAt ?? now,
441
+ outcome: {
442
+ kind: "canceled",
443
+ reason: collaborationInput.control.reason
444
+ }
445
+ } : collaborationInput.control.action === "close" ? { closedAt: previous.closedAt ?? now } : {}
446
+ };
447
+ collaborationNodes.set(node.collaborationId, node);
448
+ return node;
449
+ }
450
+ } : { kind: "unsupported" },
451
+ generatedResources: input.capabilities.generatedResources.kind === "supported" ? {
452
+ kind: "supported",
453
+ getGeneratedResource: async (resourceInput) => {
454
+ throwIfAgentOperationAborted(resourceInput.signal);
455
+ return {
456
+ descriptor: {
457
+ resourceId: resourceInput.resourceId,
458
+ kind: "image",
459
+ status: "pending",
460
+ displayName: "Fake generated resource",
461
+ producer: {
462
+ kind: "session",
463
+ sessionId: input.context.sessionId
464
+ },
465
+ createdAt: input.now()
466
+ }
467
+ };
468
+ }
469
+ } : { kind: "unsupported" },
267
470
  close
268
471
  };
269
472
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agen-ai/agent-runtime",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "private": false,
5
5
  "description": "Provider-neutral driver, instance, adapter, session, output, and conformance contracts for coding-agent runtimes.",
6
6
  "type": "module",
@@ -27,7 +27,7 @@
27
27
  "./package.json": "./package.json"
28
28
  },
29
29
  "dependencies": {
30
- "@agen-ai/agent-protocol": "^0.2.2"
30
+ "@agen-ai/agent-protocol": "^0.2.3"
31
31
  },
32
32
  "devDependencies": {
33
33
  "tsup": "^8.5.0"