@myagentroam/agent 0.11.46 → 0.11.47

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.
@@ -10,6 +10,8 @@ export interface ExtensionOperationContext {
10
10
  /** Correlation with the actual enclosing tool call; not an authority token. */
11
11
  readonly toolCallId?: string;
12
12
  readonly parentToolCallId?: string;
13
+ /** Publish bounded public metadata for this tool invocation, without changing its result. */
14
+ readonly publishEventData?: (data: Readonly<Record<string, unknown>>) => Promise<void>;
13
15
  /** Wakes a foreground tool wait when its Execution receives a steering input. */
14
16
  readonly waitInterrupt?: import('../runtime/wait.js').ToolWaitInterrupt;
15
17
  /** Present only for the exact tool invocation explicitly approved by the Host. */
@@ -35,6 +35,7 @@ declare class OpenAiResponsesTurnSession implements ModelTurnSession {
35
35
  private run;
36
36
  close(): Promise<void>;
37
37
  resetContinuation(): void;
38
+ restartProviderTurn(): void;
38
39
  continuationInputCount(): number;
39
40
  commitContinuationInput(messageCount: number): void;
40
41
  captureCompletedResponseId(responseId: string | undefined): void;
@@ -14,7 +14,7 @@ import { acquireModelCredential, appendModelCredentialHeaders, modelCredentialSe
14
14
  import { reportModelAttempt } from './attempt-diagnostics.js';
15
15
  import { productUserAgent } from '../network/product-user-agent.js';
16
16
  import { ResponsesSessionCache, clearResponsesContinuation, invalidateResponsesWebSocket, terminateWebSocket } from './responses-session-cache.js';
17
- const WEBSOCKET_IDLE_TIMEOUT_MS = 300_000;
17
+ const WEBSOCKET_IDLE_TIMEOUT_MS = 180_000;
18
18
  const WEBSOCKET_SEND_FRAME_BYTES = 1024 * 1024;
19
19
  export const OPENAI_RESPONSES_EARLY_EOF_REASON = 'OPENAI_RESPONSES_EARLY_EOF';
20
20
  export const OPENAI_RESPONSES_WEBSOCKET_CONNECTION_LIMIT_REASON = 'OPENAI_RESPONSES_WEBSOCKET_CONNECTION_LIMIT';
@@ -61,6 +61,13 @@ export class OpenAiResponsesAdapter {
61
61
  const maxAttempts = modelRetryMaxAttempts(retryState);
62
62
  let resetOutputTiming = false;
63
63
  while (retryState.attempts < maxAttempts) {
64
+ signal.throwIfAborted();
65
+ if (retryState.attempts > 0) {
66
+ // Adapter retries and Runtime recovery share this counter, but not Provider Turn state.
67
+ turn.restartProviderTurn();
68
+ useContinuation = false;
69
+ requestBody = prepared.fullBody;
70
+ }
64
71
  if (resetOutputTiming)
65
72
  yield { type: 'output.reset' };
66
73
  resetOutputTiming = false;
@@ -152,8 +159,7 @@ export class OpenAiResponsesAdapter {
152
159
  invalidContinuationFallbackUsed = true;
153
160
  useContinuation = false;
154
161
  requestBody = prepared.fullBody;
155
- turn.resetContinuation();
156
- turn.invalidateWebSocket();
162
+ turn.restartProviderTurn();
157
163
  retryState.attempts = Math.max(0, retryState.attempts - 1);
158
164
  credentialReason = 'RECONNECT';
159
165
  await reportFailure(true, {
@@ -171,8 +177,7 @@ export class OpenAiResponsesAdapter {
171
177
  invalidContinuationFallbackUsed = true;
172
178
  useContinuation = false;
173
179
  requestBody = prepared.fullBody;
174
- turn.resetContinuation();
175
- turn.invalidateWebSocket();
180
+ turn.restartProviderTurn();
176
181
  credentialReason = 'RECONNECT';
177
182
  await reportFailure(true, {
178
183
  retryDelayMs: 0,
@@ -697,7 +702,7 @@ class OpenAiResponsesTurnSession {
697
702
  }
698
703
  finally {
699
704
  if (!finished)
700
- invalidateResponsesWebSocket(this.state, true);
705
+ this.restartProviderTurn();
701
706
  this.#completedResponseId = undefined;
702
707
  this.#active = undefined;
703
708
  this.#abort = undefined;
@@ -725,6 +730,11 @@ class OpenAiResponsesTurnSession {
725
730
  resetContinuation() {
726
731
  clearResponsesContinuation(this.state);
727
732
  }
733
+ restartProviderTurn() {
734
+ this.#turnState = undefined;
735
+ this.#completedResponseId = undefined;
736
+ invalidateResponsesWebSocket(this.state, true);
737
+ }
728
738
  continuationInputCount() {
729
739
  return this.state.lastMessageCount ?? 0;
730
740
  }
package/dist/model/sse.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { AgentError } from '../error.js';
2
2
  import { isRetryableModelHttpStatus } from './http.js';
3
- const DEFAULT_MODEL_STREAM_IDLE_TIMEOUT_MS = 300_000;
3
+ const DEFAULT_MODEL_STREAM_IDLE_TIMEOUT_MS = 180_000;
4
4
  const streamEventObservedAt = new WeakMap();
5
5
  export function observeModelStreamEvent(value, observedAt) {
6
6
  if (typeof value === 'object' && value !== null && observedAt !== undefined)
@@ -89,6 +89,12 @@ export type AgentEvent = AgentEventBase & ({
89
89
  input?: unknown;
90
90
  data?: import('./public-tool-metadata.js').PublicToolMetadata;
91
91
  truncated?: boolean;
92
+ } | {
93
+ type: 'tool.updated';
94
+ toolName: string;
95
+ callId: string;
96
+ parentCallId?: string;
97
+ data: Readonly<Record<string, unknown>>;
92
98
  } | {
93
99
  type: 'tool.output';
94
100
  toolName: 'exec' | 'exec_wait' | 'code_exec_wait';
@@ -1,5 +1,5 @@
1
1
  import { AgentError } from '../error.js';
2
- const MODEL_PROGRESS_TIMEOUT_MS = 300_000;
2
+ const MODEL_PROGRESS_TIMEOUT_MS = 180_000;
3
3
  /** Watch normalized generation progress, not transport traffic or consumer processing. */
4
4
  export async function* observeModelProgress(start, parent) {
5
5
  parent.throwIfAborted();
@@ -15,7 +15,7 @@ export async function* observeModelProgress(start, parent) {
15
15
  const startedAt = performance.now();
16
16
  let abort;
17
17
  const timer = setTimeout(() => {
18
- controller.abort(new AgentError('MAR_AGENT_MODEL_TIMEOUT', 'Model request produced no generation progress for 300 seconds.', { details: { reason: 'MODEL_PROGRESS_TIMEOUT' }, retryable: true }));
18
+ controller.abort(new AgentError('MAR_AGENT_MODEL_TIMEOUT', 'Model request produced no generation progress for 180 seconds.', { details: { reason: 'MODEL_PROGRESS_TIMEOUT' }, retryable: true }));
19
19
  }, Math.ceil(remainingMs));
20
20
  timer.unref();
21
21
  let next;
@@ -1,5 +1,5 @@
1
1
  import { createExecutionCodeModeContext } from './execution-code-mode.js';
2
- import { currentExecutionImages } from '../tools/output-projection.js';
2
+ import { currentExecutionImages, publicExtensionToolEventData } from '../tools/output-projection.js';
3
3
  import { requestSmartCompaction } from '../runtime/compaction/smart.js';
4
4
  import { renderPromptSections } from '../prompts/prompt-sections.js';
5
5
  import { withToolPermissions } from '../tools/permissions.js';
@@ -56,7 +56,8 @@ export function createExecutionToolScope(input) {
56
56
  waitInterrupt,
57
57
  emit,
58
58
  skills: skills,
59
- invokeTool: (call, context, caller) => {
59
+ invokeTool: async (call, context, caller) => {
60
+ let active = true;
60
61
  const invoke = () => coreExtensions.withTools(roundBindings, scheduleTool, () => withToolPermissions(permissionPolicy, () => operations.enter({
61
62
  sessionId,
62
63
  sessionEpoch: coreExtensions.epoch,
@@ -70,9 +71,35 @@ export function createExecutionToolScope(input) {
70
71
  ...(context.waitInterrupt === undefined
71
72
  ? {}
72
73
  : { waitInterrupt: context.waitInterrupt }),
74
+ ...(call.callId === undefined
75
+ ? {}
76
+ : {
77
+ publishEventData: async (value) => {
78
+ if (!active)
79
+ return;
80
+ context.signal.throwIfAborted();
81
+ const data = publicExtensionToolEventData(value);
82
+ if (data === undefined)
83
+ return;
84
+ await context.emit({
85
+ type: 'tool.updated',
86
+ toolName: call.name,
87
+ callId: call.callId,
88
+ ...(context.parentCallId === undefined
89
+ ? {}
90
+ : { parentCallId: context.parentCallId }),
91
+ data
92
+ });
93
+ }
94
+ }),
73
95
  signal: context.signal
74
96
  }, (operation) => coreExtensions.invoke(call, operation, roundBindings))));
75
- return sources.withFrame(context, invoke);
97
+ try {
98
+ return await sources.withFrame(context, invoke);
99
+ }
100
+ finally {
101
+ active = false;
102
+ }
76
103
  }
77
104
  };
78
105
  const recentImages = async () => {
@@ -4,7 +4,7 @@ import type { McpToolCallContext, ToolCall, ToolExecutionResult } from '../contr
4
4
  import type { ToolRuntimeContext } from '../runtime-context.js';
5
5
  import type { createSessionToolScheduler } from '../scheduler.js';
6
6
  type ToolEvent = Extract<AgentEvent, {
7
- type: 'tool.started' | 'tool.output' | 'tool.completed' | 'tool.failed';
7
+ type: 'tool.started' | 'tool.updated' | 'tool.output' | 'tool.completed' | 'tool.failed';
8
8
  }>;
9
9
  type Payload<T = ToolEvent> = T extends ToolEvent ? Omit<T, 'eventId' | 'sequence' | 'timestamp' | 'sessionId' | 'executionId' | 'turnId'> : never;
10
10
  /** Capture only the cell's immutable dispatch identity, never the model loop or its AbortSignal. */
@@ -32,7 +32,9 @@ export function createCodeToolDispatch(input) {
32
32
  const expected = input.expectations.get(call.name);
33
33
  const result = await executeRegisteredTool(call.name, call.arguments, callId, {
34
34
  ...input.context,
35
- emit: (event) => event.type === 'tool.output' ? input.emit(event) : input.context.emit(event),
35
+ emit: (event) => event.type === 'tool.output' || event.type === 'tool.updated'
36
+ ? input.emit(event)
37
+ : input.context.emit(event),
36
38
  parentCallId: input.parentCallId,
37
39
  signal,
38
40
  ...(expected ? { expectedMcpTool: expected } : {})
@@ -18,6 +18,12 @@ export interface ToolImageStore extends ResourceStore {
18
18
  } | undefined>;
19
19
  }
20
20
  export type ToolRuntimeEvent = {
21
+ type: 'tool.updated';
22
+ toolName: string;
23
+ callId: string;
24
+ parentCallId?: string;
25
+ data: Readonly<Record<string, unknown>>;
26
+ } | {
21
27
  type: 'tool.output';
22
28
  toolName: 'exec' | 'exec_wait' | 'code_exec_wait';
23
29
  callId: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.11.46",
3
+ "version": "0.11.47",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",