@myagentroam/agent 0.11.2 → 0.11.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.
@@ -74,8 +74,10 @@ function validEvent(event) {
74
74
  return (typeof event.itemId === 'string' &&
75
75
  typeof event.text === 'string' &&
76
76
  (event.phase === undefined || ['commentary', 'final_answer'].includes(event.phase)));
77
- case 'reasoning.summary':
78
- return typeof event.itemId === 'string' && typeof event.text === 'string';
77
+ case 'reasoning.completed':
78
+ return (typeof event.itemId === 'string' &&
79
+ typeof event.text === 'string' &&
80
+ ['summary', 'visible_thinking', 'unspecified'].includes(String(event.representation)));
79
81
  case 'client_tool.call':
80
82
  return (typeof event.callId === 'string' &&
81
83
  typeof event.name === 'string' &&
@@ -144,6 +144,7 @@ export class AnthropicMessagesAdapter {
144
144
  // Block completion precedes the stop reason, which determines commentary vs final answer.
145
145
  const pendingTextBlocks = new Set();
146
146
  let responseId = `anthropic-${randomUUID()}`;
147
+ const completedThinking = new Set();
147
148
  let terminal;
148
149
  let latestInputUsage;
149
150
  let thinkingBytes = 0;
@@ -305,6 +306,9 @@ export class AnthropicMessagesAdapter {
305
306
  if (block?.type === 'text')
306
307
  pendingTextBlocks.add(index);
307
308
  else if (block?.type === 'thinking' || block?.type === 'redacted_thinking') {
309
+ if (completedThinking.has(index))
310
+ continue;
311
+ completedThinking.add(index);
308
312
  if (block.type === 'redacted_thinking' || block.signature) {
309
313
  const item = anthropicThinkingBlock(block.type === 'thinking'
310
314
  ? { type: 'thinking', thinking: block.text, signature: block.signature }
@@ -315,8 +319,13 @@ export class AnthropicMessagesAdapter {
315
319
  assertAnthropicThinkingBudget(thinkingBytes);
316
320
  yield observeModelStreamEvent({ type: 'response.item', provider: 'ANTHROPIC_MESSAGES', item }, modelStreamEventObservedAt(raw));
317
321
  }
318
- if (block.type === 'thinking' && block.text)
319
- yield observeModelStreamEvent({ type: 'reasoning.summary', itemId: block.id, text: block.text }, modelStreamEventObservedAt(raw));
322
+ if (block.type === 'thinking' && block.text.trim())
323
+ yield observeModelStreamEvent({
324
+ type: 'reasoning.completed',
325
+ itemId: block.id,
326
+ representation: 'visible_thinking',
327
+ text: block.text
328
+ }, modelStreamEventObservedAt(raw));
320
329
  }
321
330
  else if (block?.type === 'server_tool_use') {
322
331
  yield observeModelStreamEvent({ type: 'output.paused' }, modelStreamEventObservedAt(raw));
@@ -161,8 +161,9 @@ export type ModelEvent = {
161
161
  phase?: 'commentary' | 'final_answer';
162
162
  text: string;
163
163
  } | {
164
- type: 'reasoning.summary';
164
+ type: 'reasoning.completed';
165
165
  itemId: string;
166
+ representation: 'summary' | 'visible_thinking' | 'unspecified';
166
167
  text: string;
167
168
  } | {
168
169
  type: 'client_tool.call';
@@ -305,6 +305,7 @@ export class OpenAiResponsesAdapter {
305
305
  const textPhases = new Map();
306
306
  const pendingCompletedText = new Map();
307
307
  const emittedCompletedText = new Set();
308
+ const emittedReasoning = new Set();
308
309
  const emittedFunctionCalls = new Set();
309
310
  const hostedWebCalls = new Map();
310
311
  try {
@@ -412,12 +413,22 @@ export class OpenAiResponsesAdapter {
412
413
  else
413
414
  pendingCompletedText.set(itemId, completedText);
414
415
  }
415
- else if (type === 'response.reasoning_summary_text.done')
416
+ else if (type === 'response.reasoning_summary_text.done') {
417
+ const itemId = JSON.stringify([
418
+ text(event.item_id) ?? `reasoning-${event.output_index ?? 0}`,
419
+ event.summary_index ?? 0
420
+ ]);
421
+ const summary = text(event.text) ?? '';
422
+ if (!summary.trim() || emittedReasoning.has(itemId))
423
+ continue;
424
+ emittedReasoning.add(itemId);
416
425
  yield observeModelStreamEvent({
417
- type: 'reasoning.summary',
418
- itemId: text(event.item_id) ?? 'reasoning',
419
- text: text(event.text) ?? ''
426
+ type: 'reasoning.completed',
427
+ itemId,
428
+ representation: 'summary',
429
+ text: summary
420
430
  }, modelStreamEventObservedAt(raw));
431
+ }
421
432
  else if (type === 'response.output_item.done' &&
422
433
  text(record(event.item).type) === 'tool_search_call') {
423
434
  const item = record(event.item);
@@ -687,7 +698,7 @@ class OpenAiResponsesTurnSession {
687
698
  else if (event.type === 'text.delta' ||
688
699
  event.type === 'output.delta' ||
689
700
  event.type === 'text.completed' ||
690
- event.type === 'reasoning.summary' ||
701
+ event.type === 'reasoning.completed' ||
691
702
  event.type === 'client_tool.call' ||
692
703
  event.type === 'hosted_tool' ||
693
704
  event.type === 'citation' ||
@@ -1435,7 +1446,7 @@ function isSemanticEvent(event) {
1435
1446
  return false;
1436
1447
  if (event.type === 'text.delta')
1437
1448
  return event.delta.length > 0;
1438
- if (event.type === 'text.completed' || event.type === 'reasoning.summary')
1449
+ if (event.type === 'text.completed' || event.type === 'reasoning.completed')
1439
1450
  return event.text.length > 0;
1440
1451
  return true;
1441
1452
  }
@@ -47,7 +47,7 @@ export class CompactionOperation {
47
47
  if (event.type === 'text.delta')
48
48
  this.#textDeltaCharacters += event.delta.length;
49
49
  if ((event.type === 'text.delta' && event.delta.length > 0) ||
50
- ((event.type === 'text.completed' || event.type === 'reasoning.summary') &&
50
+ ((event.type === 'text.completed' || event.type === 'reasoning.completed') &&
51
51
  event.text.length > 0)) {
52
52
  this.#lastOutputAfterMs = Math.max(0, Date.now() - this.#startedAt);
53
53
  this.#firstOutputAfterMs ??= this.#lastOutputAfterMs;
@@ -22,6 +22,10 @@ export type MarAgentEvent = MarAgentEventBase & ({
22
22
  type: 'execution.started';
23
23
  mode: ExecutionMode;
24
24
  permissionMode?: import('../tools/permissions.js').PermissionMode;
25
+ } | {
26
+ type: 'message.started';
27
+ itemId: string;
28
+ phase: 'commentary' | 'final_answer';
25
29
  } | {
26
30
  type: 'message.delta';
27
31
  itemId: string;
@@ -53,7 +57,9 @@ export type MarAgentEvent = MarAgentEventBase & ({
53
57
  itemId: string;
54
58
  text: string;
55
59
  } | {
56
- type: 'reasoning.summary';
60
+ type: 'reasoning.completed';
61
+ itemId: string;
62
+ representation: 'summary' | 'visible_thinking' | 'unspecified';
57
63
  text: string;
58
64
  } | {
59
65
  /** Legacy persisted event; the Catalog exposes standard tool events instead. */
@@ -1,3 +1,4 @@
1
+ import { randomUUID } from 'node:crypto';
1
2
  import { MarAgentError } from '../error.js';
2
3
  import { isProviderContextOverflow, recoverModelStream } from '../model/recovery.js';
3
4
  import { modelStreamEventObservedAt } from '../model/sse.js';
@@ -35,6 +36,10 @@ export class ExecutionLoop {
35
36
  const pendingTools = [];
36
37
  let incompleteToolCall = false;
37
38
  const round = await input.prepareRound(pendingOutputContinuation);
39
+ const reasoningScope = randomUUID();
40
+ const publishedReasoning = new Set();
41
+ const startedMessages = new Set();
42
+ const leadingMessageWhitespace = new Map();
38
43
  let sawModelSemanticEvent = false;
39
44
  let requestStartedAt;
40
45
  let firstModelResponseAt;
@@ -146,6 +151,20 @@ export class ExecutionLoop {
146
151
  delta = prefix.push(delta);
147
152
  }
148
153
  if (mode !== 'compact' && delta) {
154
+ if (!startedMessages.has(event.itemId)) {
155
+ delta = (leadingMessageWhitespace.get(event.itemId) ?? '') + delta;
156
+ if (!delta.trim()) {
157
+ leadingMessageWhitespace.set(event.itemId, delta);
158
+ continue;
159
+ }
160
+ leadingMessageWhitespace.delete(event.itemId);
161
+ startedMessages.add(event.itemId);
162
+ await input.publish({
163
+ type: 'message.started',
164
+ itemId: event.itemId,
165
+ phase: event.phase
166
+ });
167
+ }
149
168
  await input.publish({
150
169
  type: 'message.delta',
151
170
  itemId: event.itemId,
@@ -155,6 +174,7 @@ export class ExecutionLoop {
155
174
  }
156
175
  }
157
176
  else if (event.type === 'text.completed') {
177
+ leadingMessageWhitespace.delete(event.itemId);
158
178
  const phase = event.phase ?? 'final_answer';
159
179
  if (phase === 'final_answer')
160
180
  this.finalAnswer = event.text;
@@ -218,9 +238,16 @@ export class ExecutionLoop {
218
238
  }
219
239
  await input.publish({ type: 'usage.updated', ...publicModelUsage(event.usage) });
220
240
  }
221
- else if (event.type === 'reasoning.summary') {
222
- if (mode !== 'compact')
223
- await input.publish({ type: 'reasoning.summary', text: event.text });
241
+ else if (event.type === 'reasoning.completed') {
242
+ if (mode !== 'compact' && event.text.trim() && !publishedReasoning.has(event.itemId)) {
243
+ await input.publish({
244
+ type: 'reasoning.completed',
245
+ itemId: `${reasoningScope}:${event.itemId}`,
246
+ representation: event.representation,
247
+ text: event.text
248
+ });
249
+ publishedReasoning.add(event.itemId);
250
+ }
224
251
  }
225
252
  else if (event.type === 'hosted_tool') {
226
253
  if (mode !== 'compact')
@@ -404,7 +431,7 @@ export class ExecutionLoop {
404
431
  function isModelResponseEvent(event) {
405
432
  if (event.type === 'text.delta')
406
433
  return event.delta.length > 0;
407
- if (event.type === 'text.completed' || event.type === 'reasoning.summary')
434
+ if (event.type === 'text.completed' || event.type === 'reasoning.completed')
408
435
  return event.text.length > 0;
409
436
  return (event.type === 'response.item' ||
410
437
  event.type === 'output.delta' ||
@@ -72,7 +72,7 @@ function isGenerationProgress(event, hostedStates) {
72
72
  case 'text.delta':
73
73
  return event.delta.length > 0;
74
74
  case 'text.completed':
75
- case 'reasoning.summary':
75
+ case 'reasoning.completed':
76
76
  return event.text.length > 0;
77
77
  case 'hosted_tool': {
78
78
  const previous = hostedStates.get(event.itemId);
@@ -58,8 +58,10 @@ export async function openMarAgentSessionCatalog(input) {
58
58
  }
59
59
  }));
60
60
  }
61
- if (isMarAgentEvent(record.payload))
62
- return [{ kind: 'event', sequence: record.sequence, event: record.payload }];
61
+ if (isMarAgentEvent(record.payload)) {
62
+ const event = record.payload;
63
+ return [{ kind: 'event', sequence: record.sequence, event }];
64
+ }
63
65
  return [];
64
66
  });
65
67
  return {
@@ -147,6 +149,7 @@ export function imageMetadata(value) {
147
149
  function isMarAgentEvent(value) {
148
150
  return (isRecord(value) &&
149
151
  typeof value.type === 'string' &&
152
+ value.type !== 'reasoning.summary' &&
150
153
  typeof value.eventId === 'string' &&
151
154
  typeof value.sequence === 'number' &&
152
155
  typeof value.timestamp === 'string' &&
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.11.2",
3
+ "version": "0.11.4",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",