@agen-ai/agent-runtime 0.2.3 → 0.2.4

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 CHANGED
@@ -101,8 +101,13 @@ receipt rule: stale or malformed input fails before provider delegation, while a
101
101
  the candidate reports execution start is wrapped as `AgentProviderDelegatedOperationError` and
102
102
  makes the session unusable. The start boundary commits only after the host observer returns
103
103
  successfully; an observer failure remains a pre-delegation error and leaves the session reusable.
104
- Operation, collaboration, and generated-resource observations also
105
- enforce correlation, immutable identity, declared bounds, and forward-only lifecycle transitions.
104
+ Operation invocation also carries a caller-owned `observationTurnId` and an optional `onOutput`
105
+ sink. An adapter must await that sink for every operation observation. The validated runtime
106
+ admits only operation-scoped progress, context, compaction, operation, resource, warning, error,
107
+ and diagnostic events; it enforces the exact session/observation-turn correlation, immutable
108
+ identity, declared bounds, forward-only lifecycle transitions, and per-output backpressure before
109
+ the operation result may settle. Collaboration and generated-resource observations retain the
110
+ same correlation and lifecycle validation at their respective ports.
106
111
 
107
112
  ## Minimal driver
108
113
 
@@ -163,7 +168,7 @@ turn/request ordering, request resolution, steering, interruption, configuration
163
168
  close, and idempotent disposal. Unsupported operations must remain explicit discriminants and
164
169
  must not expose handlers.
165
170
 
166
- The package is at `0.2.3` while the public SPI is being proven with external adapters. Pre-1.0
171
+ The package is at `0.2.4` while the public SPI is being proven with external adapters. Pre-1.0
167
172
  releases may include breaking changes during this beta period, and those changes are called out in
168
173
  the release notes.
169
174
 
@@ -507,6 +507,45 @@ function observeTurnOutput(input) {
507
507
  contextUsageState: input.contextUsageState
508
508
  });
509
509
  }
510
+ const SESSION_OPERATION_OBSERVATION_EVENT_TYPES = /* @__PURE__ */ new Set([
511
+ "item.started",
512
+ "item.updated",
513
+ "item.completed",
514
+ "progress.updated",
515
+ "context.usage.updated",
516
+ "operation.updated",
517
+ "resource.updated",
518
+ "runtime.warning",
519
+ "runtime.error",
520
+ "provider.diagnostic"
521
+ ]);
522
+ function observeSessionOperationOutput(input) {
523
+ if (input.output.kind === "event") {
524
+ const event = input.output.event;
525
+ if (!SESSION_OPERATION_OBSERVATION_EVENT_TYPES.has(event.type)) {
526
+ invalidTurnSequence(
527
+ input.providerKey,
528
+ "Provider emitted turn-owned output from a session operation."
529
+ );
530
+ }
531
+ if ((event.type === "item.started" || event.type === "item.updated" || event.type === "item.completed") && event.payload.itemKind !== "context_compaction") {
532
+ invalidTurnSequence(
533
+ input.providerKey,
534
+ "Provider emitted a non-compaction item from a session operation."
535
+ );
536
+ }
537
+ }
538
+ observeTurnOutput({
539
+ capabilities: input.capabilities,
540
+ providerKey: input.providerKey,
541
+ output: input.output,
542
+ state: input.state,
543
+ pendingRequests: /* @__PURE__ */ new Map(),
544
+ openedRequestIds: /* @__PURE__ */ new Set(),
545
+ contextUsageState: input.contextUsageState,
546
+ interactionState: input.interactionState
547
+ });
548
+ }
510
549
  function assertStableTurnBoundary(input) {
511
550
  const terminal = input.state.terminal && !input.state.waiting;
512
551
  const waiting = !input.state.terminal && input.state.waiting && input.pendingRequests.size === 1;
@@ -718,8 +757,18 @@ function validateAgentProviderSession(input) {
718
757
  input2.observer?.();
719
758
  executionStarted = true;
720
759
  };
760
+ const onOutput = async (candidate) => {
761
+ if (!executionStarted) {
762
+ throwAgentProviderContractError(
763
+ providerKey,
764
+ "invalid_operation_result",
765
+ "Provider emitted operation output before reporting execution start."
766
+ );
767
+ }
768
+ await input2.observeOutput?.(candidate);
769
+ };
721
770
  try {
722
- const candidate = await input2.invoke(onProviderExecutionStarted);
771
+ const candidate = await input2.invoke(onProviderExecutionStarted, onOutput);
723
772
  if (!executionStarted) {
724
773
  throwAgentProviderContractError(
725
774
  providerKey,
@@ -1129,8 +1178,12 @@ function validateAgentProviderSession(input) {
1129
1178
  requireUsable();
1130
1179
  throwIfAgentOperationAborted(operationInput.signal);
1131
1180
  let invocation;
1181
+ let observationTurnId;
1132
1182
  try {
1133
1183
  invocation = parseAgentOperationInvocation(operationInput.invocation);
1184
+ observationTurnId = parseAgentTurnId(
1185
+ operationInput.observationTurnId
1186
+ );
1134
1187
  } catch {
1135
1188
  return throwAgentProviderContractError(
1136
1189
  providerKey,
@@ -1189,6 +1242,16 @@ function validateAgentProviderSession(input) {
1189
1242
  const trackedInvocation = {
1190
1243
  invocation
1191
1244
  };
1245
+ const observationState = {
1246
+ fileChangeMode: capabilities.output.fileChanges,
1247
+ observedItems: /* @__PURE__ */ new Map(),
1248
+ proposedPlans: /* @__PURE__ */ new Map(),
1249
+ generatedResourceIds: /* @__PURE__ */ new Set(),
1250
+ started: true,
1251
+ terminal: false,
1252
+ waiting: false,
1253
+ finalDiffObserved: false
1254
+ };
1192
1255
  interactionState.operationInvocations.set(
1193
1256
  invocation.invocationId,
1194
1257
  trackedInvocation
@@ -1197,11 +1260,31 @@ function validateAgentProviderSession(input) {
1197
1260
  const result = await delegateProviderMutation({
1198
1261
  operation: "invoke_operation",
1199
1262
  observer: operationInput.onProviderExecutionStarted,
1200
- invoke: (onProviderExecutionStarted) => declaredOperations.invokeOperation({
1263
+ invoke: (onProviderExecutionStarted, onOutput) => declaredOperations.invokeOperation({
1201
1264
  invocation,
1265
+ observationTurnId,
1202
1266
  onProviderExecutionStarted,
1267
+ onOutput,
1203
1268
  ...operationInput.signal === void 0 ? {} : { signal: operationInput.signal }
1204
1269
  }),
1270
+ observeOutput: async (candidate) => {
1271
+ const output = validateAgentProviderOutputForContext(
1272
+ candidate,
1273
+ {
1274
+ ...outputContext(observationTurnId),
1275
+ operationInvocationId: invocation.invocationId
1276
+ }
1277
+ );
1278
+ observeSessionOperationOutput({
1279
+ capabilities,
1280
+ providerKey,
1281
+ output,
1282
+ state: observationState,
1283
+ contextUsageState,
1284
+ interactionState
1285
+ });
1286
+ await operationInput.onOutput?.(output);
1287
+ },
1205
1288
  validate: (candidate) => {
1206
1289
  const result2 = validateAgentOperationResultTransition({
1207
1290
  providerKey,
@@ -20,6 +20,7 @@ export interface AgentProviderBranchSessionInput extends AgentProviderSessionCon
20
20
  readonly onBindingCreated: AgentSessionBindingCreatedObserver;
21
21
  }
22
22
  export type AgentProviderExecutionStartedObserver = () => void;
23
+ export type AgentProviderOutputObserver = (output: AgentProviderOutput) => MaybePromise<void>;
23
24
  export interface AgentProviderRunTurnInput {
24
25
  readonly turnId: AgentTurnId;
25
26
  readonly interactionMode: AgentTurnInteractionMode;
@@ -49,8 +50,10 @@ export interface AgentProviderApplyConfigurationSelectionInput {
49
50
  }
50
51
  export interface AgentProviderInvokeOperationInput {
51
52
  readonly invocation: AgentOperationInvocation;
53
+ readonly observationTurnId: AgentTurnId;
52
54
  readonly signal?: AbortSignal;
53
55
  readonly onProviderExecutionStarted?: AgentProviderExecutionStartedObserver;
56
+ readonly onOutput?: AgentProviderOutputObserver;
54
57
  }
55
58
  export interface AgentProviderSpawnCollaborationInput {
56
59
  readonly spawn: AgentCollaborationSpawnInput;
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  matchesAgentSessionBinding,
3
- parseAgentRequestResolutionFor
3
+ parseAgentRequestResolutionFor,
4
+ parseAgentTurnId
4
5
  } from "@agen-ai/agent-protocol";
5
6
  import { isAgentOperationAbortError } from "../foundation.js";
6
7
  import {
@@ -330,6 +331,9 @@ async function runAgentProviderConformance(scenario) {
330
331
  let executionStarted = 0;
331
332
  const result = await created.operations.invokeOperation({
332
333
  invocation: scenario.operationInvocation,
334
+ observationTurnId: parseAgentTurnId(
335
+ scenario.operationInvocation.invocationId
336
+ ),
333
337
  onProviderExecutionStarted: () => {
334
338
  executionStarted += 1;
335
339
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agen-ai/agent-runtime",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
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.3"
30
+ "@agen-ai/agent-protocol": "^0.2.4"
31
31
  },
32
32
  "devDependencies": {
33
33
  "tsup": "^8.5.0"