@myagentroam/agent 0.9.95 → 0.9.96

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.
Files changed (2) hide show
  1. package/dist/sdk/agent.js +65 -17
  2. package/package.json +1 -1
package/dist/sdk/agent.js CHANGED
@@ -576,8 +576,7 @@ export async function createMarAgent(options) {
576
576
  estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeMessages, executionTools),
577
577
  contextWindowTokens: selectedModel.contextWindowTokens,
578
578
  latestUsage: lastServerUsage,
579
- usageMatchesHistory: lastServerUsage?.historyMessageCount === undefined ||
580
- lastServerUsage.historyMessageCount === compactHistory.length,
579
+ historyMessages: compactHistory,
581
580
  appendedMessages: nativeMessages.slice(projectedHistory.length)
582
581
  });
583
582
  messages.splice(0, messages.length, ...(useNative ? nativeMessages : fallbackMessages()));
@@ -627,8 +626,7 @@ export async function createMarAgent(options) {
627
626
  estimatedRequestTokens: estimatedRequestTokens(compactSystemPrompt, nativeCompactMessages, executionTools),
628
627
  contextWindowTokens: selectedModel.contextWindowTokens,
629
628
  latestUsage: lastServerUsage,
630
- usageMatchesHistory: lastServerUsage?.historyMessageCount === undefined ||
631
- lastServerUsage.historyMessageCount === compactHistory.length,
629
+ historyMessages: compactHistory,
632
630
  appendedMessages: nativeCompactMessages.slice(projectedHistory.length)
633
631
  });
634
632
  const fallbackMessages = () => buildCompactionMessages(buildCompactionInput(compactHistory, {
@@ -740,6 +738,7 @@ export async function createMarAgent(options) {
740
738
  let stop;
741
739
  let sawTool = false;
742
740
  let latestUsage;
741
+ let roundServerUsage;
743
742
  const pendingTools = [];
744
743
  let incompleteToolCall = false;
745
744
  await ensureContextBudget();
@@ -885,14 +884,13 @@ export async function createMarAgent(options) {
885
884
  Number.isSafeInteger(reportedContext) &&
886
885
  reportedContext >= 0) {
887
886
  lastServerContextTokens = reportedContext;
888
- lastServerUsage = {
887
+ roundServerUsage = {
889
888
  contextInputTokens: reportedContext,
890
889
  outputTokens: typeof event.usage.outputTokens === 'number' &&
891
890
  Number.isSafeInteger(event.usage.outputTokens) &&
892
891
  event.usage.outputTokens >= 0
893
892
  ? event.usage.outputTokens
894
- : undefined,
895
- historyMessageCount: messages.length
893
+ : undefined
896
894
  };
897
895
  }
898
896
  await emit({ type: 'usage.updated', ...publicModelUsage(event.usage) });
@@ -973,6 +971,11 @@ export async function createMarAgent(options) {
973
971
  throw error;
974
972
  }
975
973
  recoveringFromContextOverflow = false;
974
+ if (roundServerUsage !== undefined)
975
+ lastServerUsage = {
976
+ ...roundServerUsage,
977
+ historyMessages: [...messages]
978
+ };
976
979
  if (pendingTools.length === 0 && mailbox.length > 0) {
977
980
  await appendMailboxMessages();
978
981
  finalAnswer = '';
@@ -1705,22 +1708,50 @@ function currentExecutionImages(modelInputImages, toolImages) {
1705
1708
  }
1706
1709
  function latestModelUsage(records, selectedModelId) {
1707
1710
  let usage;
1711
+ const toolCallIds = new Set();
1708
1712
  // readContext starts at compact.completed, whose execution header is before the boundary.
1709
1713
  let activeModelId = selectedModelId;
1710
1714
  for (const record of records) {
1711
1715
  const payload = record.payload;
1712
1716
  if (compactSummaryFromCheckpoint(record) !== undefined) {
1713
1717
  usage = undefined;
1718
+ toolCallIds.clear();
1714
1719
  activeModelId = modelIdFromPayload(payload);
1715
1720
  continue;
1716
1721
  }
1717
1722
  if (record.type === 'execution.header') {
1718
1723
  activeModelId = modelIdFromPayload(payload);
1719
1724
  usage = undefined;
1725
+ toolCallIds.clear();
1720
1726
  continue;
1721
1727
  }
1722
- if (usage !== undefined && invalidatesUsageCalibration(record.type, payload.type))
1723
- usage = undefined;
1728
+ if (record.type === 'model.context' && payload.role === 'tool_call') {
1729
+ if (typeof payload.callId === 'string' && payload.callId.length > 0)
1730
+ toolCallIds.add(payload.callId);
1731
+ else
1732
+ usage = undefined;
1733
+ }
1734
+ if (usage !== undefined) {
1735
+ if (record.type === 'model.context') {
1736
+ const role = payload.role;
1737
+ if (role === 'tool') {
1738
+ if (typeof payload.callId !== 'string' || !toolCallIds.has(payload.callId))
1739
+ usage = undefined;
1740
+ else
1741
+ usage = {
1742
+ ...usage,
1743
+ appendedMessages: [
1744
+ ...(usage.appendedMessages ?? []),
1745
+ payload
1746
+ ]
1747
+ };
1748
+ }
1749
+ else if (role !== 'tool_call' && role !== 'assistant' && role !== 'provider')
1750
+ usage = undefined;
1751
+ }
1752
+ else if (invalidatesUsageCalibration(record.type, payload.type))
1753
+ usage = undefined;
1754
+ }
1724
1755
  if (payload.type === 'usage.updated' && activeModelId === selectedModelId) {
1725
1756
  const value = payload.contextInputTokens ?? payload.inputTokens;
1726
1757
  if (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0)
@@ -1739,20 +1770,37 @@ function latestModelUsage(records, selectedModelId) {
1739
1770
  function shouldUseNativeCompaction(input) {
1740
1771
  if (input.estimatedRequestTokens <= input.contextWindowTokens)
1741
1772
  return true;
1742
- if (input.latestUsage === undefined ||
1743
- input.latestUsage.outputTokens === undefined ||
1744
- !input.usageMatchesHistory)
1773
+ if (input.latestUsage === undefined || input.latestUsage.outputTokens === undefined)
1774
+ return false;
1775
+ const historyDelta = appendOnlyUsageDelta(input.latestUsage, input.historyMessages);
1776
+ if (historyDelta === undefined)
1745
1777
  return false;
1746
- const appendedTokens = countModelTokens(stableJson(input.appendedMessages));
1778
+ const appendedTokens = countModelTokens(stableJson([...historyDelta, ...input.appendedMessages]));
1747
1779
  return (input.latestUsage.contextInputTokens + input.latestUsage.outputTokens + appendedTokens <=
1748
1780
  input.contextWindowTokens);
1749
1781
  }
1782
+ function appendOnlyUsageDelta(usage, historyMessages) {
1783
+ if (usage.historyMessages === undefined)
1784
+ return usage.appendedMessages ?? [];
1785
+ if (historyMessages.length < usage.historyMessages.length)
1786
+ return undefined;
1787
+ for (let index = 0; index < usage.historyMessages.length; index++)
1788
+ if (!isDeepStrictEqual(usage.historyMessages[index], historyMessages[index]))
1789
+ return undefined;
1790
+ const appended = historyMessages.slice(usage.historyMessages.length);
1791
+ const toolCallIds = new Set(usage.historyMessages
1792
+ .filter((message) => message.role === 'tool_call')
1793
+ .map((message) => message.callId));
1794
+ return appended.every((message) => message.role === 'tool' && toolCallIds.has(message.callId))
1795
+ ? appended
1796
+ : undefined;
1797
+ }
1750
1798
  function invalidatesUsageCalibration(recordType, payloadType) {
1751
- if (recordType === 'turn.user' || recordType === 'context.environment')
1799
+ if (recordType === 'turn.user' ||
1800
+ recordType === 'context.environment' ||
1801
+ recordType === 'context.gc.completed')
1752
1802
  return true;
1753
- return (payloadType === 'message.completed' ||
1754
- payloadType === 'tool.completed' ||
1755
- payloadType === 'tool.failed');
1803
+ return payloadType === 'message.completed';
1756
1804
  }
1757
1805
  const PROVIDER_CONTEXT_OVERFLOW_CODES = new Set([
1758
1806
  'mar_agent_context_limit',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myagentroam/agent",
3
- "version": "0.9.95",
3
+ "version": "0.9.96",
4
4
  "description": "Embeddable MAR coding agent SDK and CLI.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",