@t2000/engine 1.11.4 → 1.13.0

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/dist/index.d.ts CHANGED
@@ -934,6 +934,29 @@ interface PendingActionStep {
934
934
  description: string;
935
935
  /** Optional modifiable fields for THIS step (rare in v1; sourced from `tool-modifiable-fields.ts`). */
936
936
  modifiableFields?: PendingActionModifiableField[];
937
+ /**
938
+ * [SPEC 13 Phase 1] Index of an earlier step whose output coin handle
939
+ * is consumed as THIS step's input coin. When set, the host's
940
+ * `composeTx({ steps })` call must thread `priorOutputs[N]` into this
941
+ * step's appender as `inputCoin` (chain mode), skipping the wallet
942
+ * pre-fetch path. The producer at index `N` MUST be a tool that
943
+ * returns a coin handle (`withdraw`, `borrow`, `swap_execute`,
944
+ * `volo_stake`, `volo_unstake`); the consumer at this index MUST be
945
+ * a tool that accepts an input coin (`save_deposit`, `repay_debt`,
946
+ * `send_transfer`, `swap_execute`, `volo_stake`, `volo_unstake`).
947
+ *
948
+ * Populated by `composeBundleFromToolResults` for whitelisted
949
+ * producer→consumer pairs (see `compose-bundle.ts` `VALID_PAIRS`).
950
+ * Hosts that don't yet honour this field fall back to wallet-mode
951
+ * coin fetching at execute time — which is exactly the pre-Phase-1
952
+ * behaviour and remains correct for the 7 Phase 0 whitelisted pairs
953
+ * because every producer in those pairs leaves its output in the
954
+ * user's wallet via a terminal `tx.transferObjects([coin], sender)`.
955
+ *
956
+ * Pre-condition (validated by `composeTx` at execute time):
957
+ * `inputCoinFromStep < currentStepIndex` (forward-only references).
958
+ */
959
+ inputCoinFromStep?: number;
937
960
  }
938
961
  /**
939
962
  * Serializable description of a write tool that needs user approval.
@@ -1692,35 +1715,85 @@ declare function bundleShortestTtl(toolUseIds: string[], toolNamesById: Record<s
1692
1715
  declare const REGENERATABLE_READ_TOOLS: ReadonlySet<string>;
1693
1716
 
1694
1717
  /**
1695
- * [F14-fix-2 / 2026-05-03] Maximum number of writes per atomic bundle.
1696
- *
1697
- * The engine refuses to compose a `pending_action` with more than this
1698
- * many steps. Bundles with N > MAX_BUNDLE_OPS get all-step error
1699
- * tool_results synthesized in `engine.ts` so the LLM re-plans into two
1700
- * sequential ≤N-op bundles. Why 5:
1701
- *
1702
- * - Vercel runtime budget. At N>5 writes, Turn 2's emission + guard
1703
- * work + bundle compose has been observed in production to push
1704
- * /api/engine/chat past the 300s `maxDuration`. Reducing the cap
1705
- * keeps every flow well under the timeout.
1706
- * - Quote-freshness coupling. SwapQuoteTracker `windowMs = 60_000`.
1707
- * With N>5 (especially 2+ swap legs), Turn 2's planning + emission
1708
- * routinely bleeds past 60s; the stale-quote guard then blocks
1709
- * swap_execute on legs whose quote went stale during thinking.
1710
- * - LLM working memory. Sonnet+medium has been observed to drop
1711
- * legs when bundling >5 writes (the original B2 incident — LLM
1712
- * asked to emit 6 writes in one Turn 2 emitted only 3).
1713
- * - User cognitive load. A 6+ leg PermissionCard takes 30+ seconds
1714
- * to re-read; capping at 5 keeps the card scannable.
1715
- * - PTB instruction budget. Sui PTB max instructions ~1024; each leg
1716
- * consumes 5–20 instructions. 5 legs 100 instructions well
1717
- * under the cap with comfortable headroom for nested splits.
1718
- *
1719
- * Hosts that want to advertise the cap in system prompts should import
1720
- * this constant rather than hardcoding `5` — bumping the cap in one
1721
- * place keeps host prompts and engine behavior in lockstep.
1722
- */
1723
- declare const MAX_BUNDLE_OPS = 5;
1718
+ * [Phase 0 / SPEC 13 / 2026-05-03] Maximum number of writes per atomic bundle.
1719
+ *
1720
+ * **History.** This was 5 between F14-fix-2 (2026-05-03 morning) and
1721
+ * Phase 0 (2026-05-03 evening). The May 3 production review found that
1722
+ * the underlying problem was never the count bundles fail because
1723
+ * SDK appenders pre-fetch coins from the wallet and the chained asset
1724
+ * doesn't exist there yet (e.g. `swap_execute(USDC→USDsui) +
1725
+ * save_deposit(USDsui)` reverts at PREPARE because USDsui isn't in the
1726
+ * wallet at compose time). SPEC 13 builds the chained-coin handoff
1727
+ * primitive. Until that ships in `1.13.0`, Phase 0 strict-tightens
1728
+ * bundles to:
1729
+ *
1730
+ * - Cap = 2 ops (was 5).
1731
+ * - Every adjacent pair MUST be in `VALID_PAIRS` (was: any 2
1732
+ * bundleable tools).
1733
+ *
1734
+ * **Why 2.** Every multi-write production failure today reduces to
1735
+ * the same gap: a chained-asset bundle whose intermediate output
1736
+ * doesn't exist in the wallet yet. The `VALID_PAIRS` whitelist below
1737
+ * enumerates every (producer, consumer) couple where chaining either
1738
+ * works today (because the consumer takes a wallet coin that the
1739
+ * producer happens to leave there via `tx.transferObjects`) OR will
1740
+ * work after Phase 1. Anything outside the whitelist falls through
1741
+ * to sequential — same outcome the LLM was already producing as a
1742
+ * fallback, just without the wasted PREPARE round-trip.
1743
+ *
1744
+ * **Why not 3+.** 3-op chains require a graph validator (every adjacent
1745
+ * pair valid + DAG topology checks) — that's Phase 2. Cap stays at 2
1746
+ * until Phase 1 lands the validator.
1747
+ *
1748
+ * Hosts importing this constant for system-prompt construction get the
1749
+ * current cap automatically. Bumping the cap in Phase 1 + Phase 2 + …
1750
+ * is a one-line change here that propagates to prompts via the import.
1751
+ */
1752
+ declare const MAX_BUNDLE_OPS = 2;
1753
+ /**
1754
+ * [Phase 0 / SPEC 13] Whitelisted (producer, consumer) pairs for atomic
1755
+ * bundling. Every key has the shape `${producer}->${consumer}`. Bundles
1756
+ * whose adjacent steps aren't in this set get refused with
1757
+ * `_gate: 'pair_not_whitelisted'` so the LLM splits sequentially.
1758
+ *
1759
+ * **The 7 pairs and why they're safe in Phase 0.**
1760
+ *
1761
+ * | Pair | Why it works at compose time today |
1762
+ * |---|---|
1763
+ * | `swap_execute → send_transfer` | Swap's `tx.transferObjects([result.coin], sender)` lands the swap output in the wallet for the same PTB; send's `selectAndSplitCoin` finds it. |
1764
+ * | `swap_execute → save_deposit` | Same mechanism — swap output is back in wallet for save's coin fetch. (P0 caveat: this currently *fails* if the wallet has zero of `swap.to` BEFORE the swap step. Phase 1's `inputCoinFromStep` fixes that. For now we accept the pair but warn the LLM in the prompt rule that wallet must hold ≥0 of target asset.) |
1765
+ * | `swap_execute → repay_debt` | Same as save. Same caveat. |
1766
+ * | `withdraw → swap_execute` | Withdraw's output is transferred to user; swap's coin fetch finds it. Same wallet caveat in reverse. |
1767
+ * | `withdraw → send_transfer` | Same shape. |
1768
+ * | `borrow → send_transfer` | Borrow output lands in wallet; send finds it. |
1769
+ * | `borrow → repay_debt` (same asset) | Unusual but valid — borrow output repays elsewhere. |
1770
+ *
1771
+ * **NOT in the whitelist** (sequential only until Phase 1+):
1772
+ *
1773
+ * - `swap → swap` — chained-asset handoff between two swaps. Phase 3.
1774
+ * - `borrow → swap` — borrow output is `USDC|USDsui`, swap takes any
1775
+ * `from`. Could be added in Phase 1.
1776
+ * - `claim_rewards → *` — produces N reward coins, structurally
1777
+ * different. Phase 5+.
1778
+ * - Anything with `volo_stake` / `volo_unstake` chained — Phase 5+.
1779
+ */
1780
+ declare const VALID_PAIRS: ReadonlySet<string>;
1781
+ /**
1782
+ * Test whether a 2-op bundle's (producer, consumer) pair is in the
1783
+ * Phase 0 whitelist. Returns the pair key on match, `null` otherwise
1784
+ * so callers can include the rejection reason in the synthesized
1785
+ * tool_result.
1786
+ *
1787
+ * Caller is responsible for ensuring `producer` and `consumer` are the
1788
+ * actual tool names of the bundle's two steps (in execution order).
1789
+ */
1790
+ declare function checkValidPair(producer: string, consumer: string): {
1791
+ ok: true;
1792
+ pair: string;
1793
+ } | {
1794
+ ok: false;
1795
+ pair: string;
1796
+ };
1724
1797
 
1725
1798
  /**
1726
1799
  * SPEC 7 v0.3 Quote-Refresh ReviewCard — engine-side bundle regeneration.
@@ -3730,4 +3803,4 @@ declare function getTelemetrySink(): TelemetrySink;
3730
3803
  /** Restore the default noop sink. Used by test teardowns. */
3731
3804
  declare function resetTelemetrySink(): void;
3732
3805
 
3733
- export { type AddressPortfolio, AnthropicProvider, type AnthropicProviderConfig, type AudricHistoryRecord, type AudricPortfolioResult, type AwaitOrFetchOpts, type BalancePrices, type BalanceResult, BalanceTracker, type BuildToolOptions, CANVAS_TEMPLATES, type CanvasTemplate, type ChatParams, type CompactOptions, type ContentBlock, ContextBudget, type ContextBudgetConfig, type ConversationState, type ConversationStateStore, type CostSnapshot, CostTracker, type CostTrackerConfig, DEFAULT_GUARD_CONFIG, DEFAULT_LEASE_SEC, DEFAULT_PERMISSION_CONFIG, DEFAULT_POLL_BUDGET_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_SYSTEM_PROMPT, DEFAULT_TOOL_TTL_MS, type DefiCacheEntry, type DefiCacheStore, type DefiProtocol, type DefiSummary, EFFORT_THINKING_BUDGET_CAPS, EarlyToolDispatcher, type EngineConfig, type EngineEvent, type EvalSummaryParseResult, type EvaluationItem, type EvaluationStatus, type FetchLock, type GuardCheckResult, type GuardConfig, type GuardEvent, type GuardInjection, type GuardResult, type GuardRunnerState, type GuardTier, type GuardVerdict, type HarnessShape, type HealthFactorResult, InMemoryDefiCacheStore, InMemoryFetchLock, InMemoryNaviCacheStore, InMemoryWalletCacheStore, InvalidAddressError, type LLMProvider, MAX_BUNDLE_OPS, type McpCallResult, McpClientManager, McpResponseCache, type McpServerConfig, type McpServerConnection, type McpToolAdapterConfig, type McpToolDescriptor, MemorySessionStore, type Message, NAVI_ADDR_TTL_SEC, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_RATES_TTL_SEC, NAVI_SERVER_NAME, type NaviCacheEntry, type NaviCacheStore, type NaviRawCoin, type NaviRawHealthFactor, type NaviRawPool, type NaviRawPosition, type NaviRawPositionsResponse, type NaviRawProtocolStats, type NaviRawRewardsResponse, type NaviReadOptions, NaviTools, type NormalizedAddress, type OutputConfig, PERMISSION_PRESETS, type PendingAction, type PendingActionModifiableField, type PendingActionStep, type PendingReward, type PendingToolCall, type PermissionLevel, type PermissionOperation, type PermissionResponse, type PermissionRule, type PortfolioCoin, type PositionEntry, type PreflightResult, type ProtocolStats, type ProviderEvent, QueryEngine, READ_TOOLS, REGENERATABLE_READ_TOOLS, type RatesResult, type Recipe, type RecipePrerequisite, RecipeRegistry, type RecipeStep, type RecipeStepOnError, type RegenerateFailure, type RegenerateResult, type RegenerateSuccess, type RegenerateTimelineEvent, RetryTracker, type SSEEvent, SUINS_NAME_REGEX, SUI_ADDRESS_REGEX, SUI_ADDRESS_STRICT_REGEX, type SavingsResult, type ServerPositionData, type SessionData, type SessionStore, type StateType, type StopReason, type SuiCoinBalance, SuinsNotRegisteredError, SuinsRpcError, type SystemBlock, type SystemPrompt, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TOOL_TTL_MS, type TelemetrySink, type TelemetryTags, type ThinkingConfig, type ThinkingEffort, type TodoItem$1 as TodoItem, type Tool, type ToolChoice, type ToolContext, type ToolDefinition, type ToolFlags, type ToolJsonSchema, type ToolResult, TxMutex, type UpdateTodoInput, type TodoItem as UpdateTodoItem, type UserFinancialProfile, type UserPermissionConfig, WRITE_TOOLS, type WalletCacheEntry, type WalletCacheStore, type WalletCoin, _resetNaviCircuitBreaker, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, awaitOrFetch, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, bundleShortestTtl, claimRewardsTool, clampThinkingForEffort, classifyEffort, clearPortfolioCache, clearPortfolioCacheFor, clearPriceMapCache, compactMessages, createGuardRunnerState, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAddressDefiPortfolio, fetchAddressPortfolio, fetchAudricHistory, fetchAudricPortfolio, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getAudricApiBase, getDefaultTools, getDefiCacheStore, getFetchLock, getMcpManager, getModifiableFields, getNaviCacheStore, getTelemetrySink, getToolFlags, getWalletAddress, getWalletCacheStore, guardArtifactPreview, guardStaleData, harnessShapeForEffort, hasNaviMcp, healthCheckTool, isBundleableTool, loadRecipes, looksLikeSuiNs, microcompact, mppServicesTool, naviKey, normalizeAddressInput, parseEvalSummary, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, regenerateBundle, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resetDefiCacheStore, resetFetchLock, resetNaviCacheStore, resetTelemetrySink, resetWalletCacheStore, resolveAddressToSuinsViaRpc, resolvePermissionTier, resolveSuinsTool, resolveSuinsViaRpc, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, setDefiCacheStore, setFetchLock, setNaviCacheStore, setTelemetrySink, setWalletCacheStore, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, tokenPricesTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, updateTodoTool, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
3806
+ export { type AddressPortfolio, AnthropicProvider, type AnthropicProviderConfig, type AudricHistoryRecord, type AudricPortfolioResult, type AwaitOrFetchOpts, type BalancePrices, type BalanceResult, BalanceTracker, type BuildToolOptions, CANVAS_TEMPLATES, type CanvasTemplate, type ChatParams, type CompactOptions, type ContentBlock, ContextBudget, type ContextBudgetConfig, type ConversationState, type ConversationStateStore, type CostSnapshot, CostTracker, type CostTrackerConfig, DEFAULT_GUARD_CONFIG, DEFAULT_LEASE_SEC, DEFAULT_PERMISSION_CONFIG, DEFAULT_POLL_BUDGET_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_SYSTEM_PROMPT, DEFAULT_TOOL_TTL_MS, type DefiCacheEntry, type DefiCacheStore, type DefiProtocol, type DefiSummary, EFFORT_THINKING_BUDGET_CAPS, EarlyToolDispatcher, type EngineConfig, type EngineEvent, type EvalSummaryParseResult, type EvaluationItem, type EvaluationStatus, type FetchLock, type GuardCheckResult, type GuardConfig, type GuardEvent, type GuardInjection, type GuardResult, type GuardRunnerState, type GuardTier, type GuardVerdict, type HarnessShape, type HealthFactorResult, InMemoryDefiCacheStore, InMemoryFetchLock, InMemoryNaviCacheStore, InMemoryWalletCacheStore, InvalidAddressError, type LLMProvider, MAX_BUNDLE_OPS, type McpCallResult, McpClientManager, McpResponseCache, type McpServerConfig, type McpServerConnection, type McpToolAdapterConfig, type McpToolDescriptor, MemorySessionStore, type Message, NAVI_ADDR_TTL_SEC, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_RATES_TTL_SEC, NAVI_SERVER_NAME, type NaviCacheEntry, type NaviCacheStore, type NaviRawCoin, type NaviRawHealthFactor, type NaviRawPool, type NaviRawPosition, type NaviRawPositionsResponse, type NaviRawProtocolStats, type NaviRawRewardsResponse, type NaviReadOptions, NaviTools, type NormalizedAddress, type OutputConfig, PERMISSION_PRESETS, type PendingAction, type PendingActionModifiableField, type PendingActionStep, type PendingReward, type PendingToolCall, type PermissionLevel, type PermissionOperation, type PermissionResponse, type PermissionRule, type PortfolioCoin, type PositionEntry, type PreflightResult, type ProtocolStats, type ProviderEvent, QueryEngine, READ_TOOLS, REGENERATABLE_READ_TOOLS, type RatesResult, type Recipe, type RecipePrerequisite, RecipeRegistry, type RecipeStep, type RecipeStepOnError, type RegenerateFailure, type RegenerateResult, type RegenerateSuccess, type RegenerateTimelineEvent, RetryTracker, type SSEEvent, SUINS_NAME_REGEX, SUI_ADDRESS_REGEX, SUI_ADDRESS_STRICT_REGEX, type SavingsResult, type ServerPositionData, type SessionData, type SessionStore, type StateType, type StopReason, type SuiCoinBalance, SuinsNotRegisteredError, SuinsRpcError, type SystemBlock, type SystemPrompt, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TOOL_TTL_MS, type TelemetrySink, type TelemetryTags, type ThinkingConfig, type ThinkingEffort, type TodoItem$1 as TodoItem, type Tool, type ToolChoice, type ToolContext, type ToolDefinition, type ToolFlags, type ToolJsonSchema, type ToolResult, TxMutex, type UpdateTodoInput, type TodoItem as UpdateTodoItem, type UserFinancialProfile, type UserPermissionConfig, VALID_PAIRS, WRITE_TOOLS, type WalletCacheEntry, type WalletCacheStore, type WalletCoin, _resetNaviCircuitBreaker, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, awaitOrFetch, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, bundleShortestTtl, checkValidPair, claimRewardsTool, clampThinkingForEffort, classifyEffort, clearPortfolioCache, clearPortfolioCacheFor, clearPriceMapCache, compactMessages, createGuardRunnerState, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAddressDefiPortfolio, fetchAddressPortfolio, fetchAudricHistory, fetchAudricPortfolio, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getAudricApiBase, getDefaultTools, getDefiCacheStore, getFetchLock, getMcpManager, getModifiableFields, getNaviCacheStore, getTelemetrySink, getToolFlags, getWalletAddress, getWalletCacheStore, guardArtifactPreview, guardStaleData, harnessShapeForEffort, hasNaviMcp, healthCheckTool, isBundleableTool, loadRecipes, looksLikeSuiNs, microcompact, mppServicesTool, naviKey, normalizeAddressInput, parseEvalSummary, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, regenerateBundle, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resetDefiCacheStore, resetFetchLock, resetNaviCacheStore, resetTelemetrySink, resetWalletCacheStore, resolveAddressToSuinsViaRpc, resolvePermissionTier, resolveSuinsTool, resolveSuinsViaRpc, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, setDefiCacheStore, setFetchLock, setNaviCacheStore, setTelemetrySink, setWalletCacheStore, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, tokenPricesTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, updateTodoTool, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
package/dist/index.js CHANGED
@@ -6732,7 +6732,50 @@ var REGENERATABLE_READ_TOOLS = /* @__PURE__ */ new Set([
6732
6732
  ]);
6733
6733
 
6734
6734
  // src/compose-bundle.ts
6735
- var MAX_BUNDLE_OPS = 5;
6735
+ var MAX_BUNDLE_OPS = 2;
6736
+ var VALID_PAIRS = /* @__PURE__ */ new Set([
6737
+ "swap_execute->send_transfer",
6738
+ "swap_execute->save_deposit",
6739
+ "swap_execute->repay_debt",
6740
+ "withdraw->swap_execute",
6741
+ "withdraw->send_transfer",
6742
+ "borrow->send_transfer",
6743
+ "borrow->repay_debt"
6744
+ ]);
6745
+ function checkValidPair(producer, consumer) {
6746
+ const pair = `${producer}->${consumer}`;
6747
+ return VALID_PAIRS.has(pair) ? { ok: true, pair } : { ok: false, pair };
6748
+ }
6749
+ function inferProducerOutputAsset(toolName, input) {
6750
+ if (typeof input !== "object" || input === null) return null;
6751
+ const i = input;
6752
+ if (toolName === "swap_execute") {
6753
+ return typeof i.to === "string" ? i.to.toLowerCase() : null;
6754
+ }
6755
+ if (toolName === "withdraw" || toolName === "borrow") {
6756
+ return typeof i.asset === "string" ? i.asset.toLowerCase() : "usdc";
6757
+ }
6758
+ return null;
6759
+ }
6760
+ function inferConsumerInputAsset(toolName, input) {
6761
+ if (typeof input !== "object" || input === null) return null;
6762
+ const i = input;
6763
+ if (toolName === "send_transfer" || toolName === "save_deposit" || toolName === "repay_debt") {
6764
+ return typeof i.asset === "string" ? i.asset.toLowerCase() : "usdc";
6765
+ }
6766
+ if (toolName === "swap_execute") {
6767
+ return typeof i.from === "string" ? i.from.toLowerCase() : null;
6768
+ }
6769
+ return null;
6770
+ }
6771
+ function shouldChainCoin(producer, consumer) {
6772
+ const pair = `${producer.name}->${consumer.name}`;
6773
+ if (!VALID_PAIRS.has(pair)) return false;
6774
+ const out = inferProducerOutputAsset(producer.name, producer.input);
6775
+ const inA = inferConsumerInputAsset(consumer.name, consumer.input);
6776
+ if (!out || !inA) return false;
6777
+ return out === inA;
6778
+ }
6736
6779
  function composeBundleFromToolResults(input) {
6737
6780
  if (input.pendingWrites.length < 2) {
6738
6781
  throw new Error(
@@ -6760,6 +6803,13 @@ function composeBundleFromToolResults(input) {
6760
6803
  ...modifiableFields?.length ? { modifiableFields } : {}
6761
6804
  };
6762
6805
  });
6806
+ for (let i = 1; i < input.pendingWrites.length; i++) {
6807
+ const producer = input.pendingWrites[i - 1];
6808
+ const consumer = input.pendingWrites[i];
6809
+ if (shouldChainCoin(producer, consumer)) {
6810
+ steps[i].inputCoinFromStep = i - 1;
6811
+ }
6812
+ }
6763
6813
  const regenerateToolUseIds = input.readResults.filter((r) => REGENERATABLE_READ_TOOLS.has(r.toolName)).map((r) => r.toolUseId);
6764
6814
  const canRegenerate = regenerateToolUseIds.length > 0;
6765
6815
  let quoteAge;
@@ -6920,6 +6970,10 @@ var QueryEngine = class {
6920
6970
  async *submitMessage(prompt, options) {
6921
6971
  if (this.costTracker.isOverBudget()) {
6922
6972
  yield { type: "error", error: new Error("Session budget exceeded") };
6973
+ getTelemetrySink().counter("engine.turn_outcome", {
6974
+ entry: "submit",
6975
+ outcome: "error_budget"
6976
+ });
6923
6977
  return;
6924
6978
  }
6925
6979
  this.abortController = new AbortController();
@@ -7058,6 +7112,10 @@ var QueryEngine = class {
7058
7112
  }
7059
7113
  if (!response.approved) {
7060
7114
  yield { type: "turn_complete", stopReason: "end_turn" };
7115
+ getTelemetrySink().counter("engine.turn_outcome", {
7116
+ entry: "resume",
7117
+ outcome: "pending_action_decline"
7118
+ });
7061
7119
  this.turnReadCache.clear();
7062
7120
  return;
7063
7121
  }
@@ -7344,10 +7402,22 @@ var QueryEngine = class {
7344
7402
  let turns = 0;
7345
7403
  let hasRetriedWithCleanHistory = false;
7346
7404
  let turnStartMs = Date.now();
7405
+ const recordTurnOutcome = (outcome, extra = {}) => {
7406
+ const tags = {
7407
+ entry: freshPrompt !== null ? "submit" : "resume",
7408
+ outcome
7409
+ };
7410
+ if (extra.stopReason) tags.stopReason = extra.stopReason;
7411
+ const sink = getTelemetrySink();
7412
+ sink.counter("engine.turn_outcome", tags);
7413
+ sink.histogram("engine.turn_duration_ms", Date.now() - turnStartMs, tags);
7414
+ sink.gauge("engine.turn_turns_used", turns, tags);
7415
+ };
7347
7416
  const turnReadToolResults = [];
7348
7417
  while (turns < this.maxTurns) {
7349
7418
  if (signal.aborted) {
7350
7419
  yield { type: "error", error: new Error("Aborted") };
7420
+ recordTurnOutcome("error_aborted");
7351
7421
  return;
7352
7422
  }
7353
7423
  turns++;
@@ -7532,6 +7602,7 @@ ${recipeCtx}`;
7532
7602
  this.messages.push({ role: "assistant", content: acc.assistantBlocks });
7533
7603
  getTelemetrySink().histogram("anthropic.latency_ms", Date.now() - turnStartMs);
7534
7604
  yield { type: "turn_complete", stopReason: acc.stopReason };
7605
+ recordTurnOutcome("turn_complete", { stopReason: acc.stopReason });
7535
7606
  return;
7536
7607
  }
7537
7608
  if (signal.aborted) {
@@ -7541,6 +7612,7 @@ ${recipeCtx}`;
7541
7612
  }
7542
7613
  this.addErrorResults(acc.pendingToolCalls, "Aborted");
7543
7614
  yield { type: "error", error: new Error("Aborted") };
7615
+ recordTurnOutcome("error_aborted");
7544
7616
  return;
7545
7617
  }
7546
7618
  const approved = [];
@@ -7793,6 +7865,10 @@ ${recipeCtx}`;
7793
7865
  if (anyGuardBlocked) {
7794
7866
  this.messages.push({ role: "assistant", content: acc.assistantBlocks });
7795
7867
  this.messages.push({ role: "user", content: toolResultBlocks });
7868
+ getTelemetrySink().counter("engine.turn_outcome", {
7869
+ entry: freshPrompt !== null ? "submit" : "resume",
7870
+ outcome: "guard_block_continue"
7871
+ });
7796
7872
  continue;
7797
7873
  }
7798
7874
  } else {
@@ -7800,7 +7876,7 @@ ${recipeCtx}`;
7800
7876
  }
7801
7877
  if (guardPassedWrites.length > MAX_BUNDLE_OPS) {
7802
7878
  const cappedError = {
7803
- error: `Compound flows are capped at ${MAX_BUNDLE_OPS} atomic ops per bundle. You attempted ${guardPassedWrites.length}. Split into two sequential bundles (\u2264${MAX_BUNDLE_OPS} ops each) across two confirmation rounds. Tell the user "I'll do this in two steps \u2014 first <ops 1-${MAX_BUNDLE_OPS}>, then after that confirms, <remaining ops>" and emit only the first ${MAX_BUNDLE_OPS} writes for the first bundle.`,
7879
+ error: `Atomic bundles are capped at ${MAX_BUNDLE_OPS} ops in Phase 0. You attempted ${guardPassedWrites.length}. Execute these as ${guardPassedWrites.length} sequential single-write transactions: tell the user "I'll do this in ${guardPassedWrites.length} steps", then emit only the FIRST write. After it lands and the user confirms each step, emit the next.`,
7804
7880
  _gate: "max_bundle_ops"
7805
7881
  };
7806
7882
  for (const write of guardPassedWrites) {
@@ -7820,6 +7896,10 @@ ${recipeCtx}`;
7820
7896
  }
7821
7897
  this.messages.push({ role: "assistant", content: acc.assistantBlocks });
7822
7898
  this.messages.push({ role: "user", content: toolResultBlocks });
7899
+ getTelemetrySink().counter("engine.turn_outcome", {
7900
+ entry: freshPrompt !== null ? "submit" : "resume",
7901
+ outcome: "max_bundle_ops_continue"
7902
+ });
7823
7903
  continue;
7824
7904
  }
7825
7905
  if (guardPassedWrites.length > 0) {
@@ -7827,6 +7907,41 @@ ${recipeCtx}`;
7827
7907
  const turnIndex = this.messages.filter((m) => m.role === "assistant").length;
7828
7908
  this.turnPaused = true;
7829
7909
  if (allBundleable) {
7910
+ if (guardPassedWrites.length === 2) {
7911
+ const producer = guardPassedWrites[0].call.name;
7912
+ const consumer = guardPassedWrites[1].call.name;
7913
+ const check = checkValidPair(producer, consumer);
7914
+ if (!check.ok) {
7915
+ const pairError = {
7916
+ error: `Bundle pair '${check.pair}' is not in the Phase 0 chaining whitelist. Whitelisted pairs: ${[...VALID_PAIRS].join(", ")}. Run these two writes sequentially: tell the user "I'll do this in two steps", emit only the first write, then the second after it lands and confirms.`,
7917
+ _gate: "pair_not_whitelisted"
7918
+ };
7919
+ for (const write of guardPassedWrites) {
7920
+ yield {
7921
+ type: "tool_result",
7922
+ toolName: write.call.name,
7923
+ toolUseId: write.call.id,
7924
+ result: pairError,
7925
+ isError: true
7926
+ };
7927
+ toolResultBlocks.push({
7928
+ type: "tool_result",
7929
+ toolUseId: write.call.id,
7930
+ content: JSON.stringify(pairError),
7931
+ isError: true
7932
+ });
7933
+ }
7934
+ this.turnPaused = false;
7935
+ this.messages.push({ role: "assistant", content: acc.assistantBlocks });
7936
+ this.messages.push({ role: "user", content: toolResultBlocks });
7937
+ getTelemetrySink().counter("engine.turn_outcome", {
7938
+ entry: freshPrompt !== null ? "submit" : "resume",
7939
+ outcome: "pair_not_whitelisted_continue",
7940
+ pair: check.pair
7941
+ });
7942
+ continue;
7943
+ }
7944
+ }
7830
7945
  const completedResults = toolResultBlocks.map((b) => ({
7831
7946
  toolUseId: b.toolUseId,
7832
7947
  content: b.content,
@@ -7842,6 +7957,7 @@ ${recipeCtx}`;
7842
7957
  turnIndex
7843
7958
  });
7844
7959
  yield { type: "pending_action", action: bundleAction };
7960
+ recordTurnOutcome("pending_action_bundle");
7845
7961
  return;
7846
7962
  }
7847
7963
  const pendingWrite = guardPassedWrites[0];
@@ -7889,6 +8005,7 @@ ${recipeCtx}`;
7889
8005
  attemptId
7890
8006
  }
7891
8007
  };
8008
+ recordTurnOutcome("pending_action_single");
7892
8009
  return;
7893
8010
  }
7894
8011
  this.messages.push({ role: "assistant", content: acc.assistantBlocks });
@@ -7900,10 +8017,12 @@ ${recipeCtx}`;
7900
8017
  }
7901
8018
  if (this.costTracker.isOverBudget()) {
7902
8019
  yield { type: "error", error: new Error("Session budget exceeded") };
8020
+ recordTurnOutcome("error_budget");
7903
8021
  return;
7904
8022
  }
7905
8023
  }
7906
8024
  yield { type: "turn_complete", stopReason: "max_turns" };
8025
+ recordTurnOutcome("max_turns");
7907
8026
  }
7908
8027
  // ---------------------------------------------------------------------------
7909
8028
  // Internal
@@ -9374,6 +9493,6 @@ function sanitizeAnthropicMessages(messages) {
9374
9493
  return merged;
9375
9494
  }
9376
9495
 
9377
- export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_LEASE_SEC, DEFAULT_PERMISSION_CONFIG, DEFAULT_POLL_BUDGET_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_SYSTEM_PROMPT, DEFAULT_TOOL_TTL_MS, EFFORT_THINKING_BUDGET_CAPS, EarlyToolDispatcher, InMemoryDefiCacheStore, InMemoryFetchLock, InMemoryNaviCacheStore, InMemoryWalletCacheStore, InvalidAddressError, MAX_BUNDLE_OPS, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_ADDR_TTL_SEC, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_RATES_TTL_SEC, NAVI_SERVER_NAME, NaviTools, PERMISSION_PRESETS, QueryEngine, READ_TOOLS, REGENERATABLE_READ_TOOLS, RecipeRegistry, RetryTracker, SUINS_NAME_REGEX, SUI_ADDRESS_REGEX, SUI_ADDRESS_STRICT_REGEX, SuinsNotRegisteredError, SuinsRpcError, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TOOL_TTL_MS, TxMutex, WRITE_TOOLS, _resetNaviCircuitBreaker, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, awaitOrFetch, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, bundleShortestTtl, claimRewardsTool, clampThinkingForEffort, classifyEffort, clearPortfolioCache, clearPortfolioCacheFor, clearPriceMapCache, compactMessages, createGuardRunnerState, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAddressDefiPortfolio, fetchAddressPortfolio, fetchAudricHistory, fetchAudricPortfolio, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getAudricApiBase, getDefaultTools, getDefiCacheStore, getFetchLock, getMcpManager, getModifiableFields, getNaviCacheStore, getTelemetrySink, getToolFlags, getWalletAddress, getWalletCacheStore, guardArtifactPreview, guardStaleData, harnessShapeForEffort, hasNaviMcp, healthCheckTool, isBundleableTool, loadRecipes, looksLikeSuiNs, microcompact, mppServicesTool, naviKey, normalizeAddressInput, parseEvalSummary, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, regenerateBundle, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resetDefiCacheStore, resetFetchLock, resetNaviCacheStore, resetTelemetrySink, resetWalletCacheStore, resolveAddressToSuinsViaRpc, resolvePermissionTier, resolveSuinsTool, resolveSuinsViaRpc, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, setDefiCacheStore, setFetchLock, setNaviCacheStore, setTelemetrySink, setWalletCacheStore, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, tokenPricesTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, updateTodoTool, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
9496
+ export { AnthropicProvider, BalanceTracker, CANVAS_TEMPLATES, ContextBudget, CostTracker, DEFAULT_GUARD_CONFIG, DEFAULT_LEASE_SEC, DEFAULT_PERMISSION_CONFIG, DEFAULT_POLL_BUDGET_MS, DEFAULT_POLL_INTERVAL_MS, DEFAULT_SYSTEM_PROMPT, DEFAULT_TOOL_TTL_MS, EFFORT_THINKING_BUDGET_CAPS, EarlyToolDispatcher, InMemoryDefiCacheStore, InMemoryFetchLock, InMemoryNaviCacheStore, InMemoryWalletCacheStore, InvalidAddressError, MAX_BUNDLE_OPS, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_ADDR_TTL_SEC, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_RATES_TTL_SEC, NAVI_SERVER_NAME, NaviTools, PERMISSION_PRESETS, QueryEngine, READ_TOOLS, REGENERATABLE_READ_TOOLS, RecipeRegistry, RetryTracker, SUINS_NAME_REGEX, SUI_ADDRESS_REGEX, SUI_ADDRESS_STRICT_REGEX, SuinsNotRegisteredError, SuinsRpcError, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TOOL_TTL_MS, TxMutex, VALID_PAIRS, WRITE_TOOLS, _resetNaviCircuitBreaker, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, awaitOrFetch, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, bundleShortestTtl, checkValidPair, claimRewardsTool, clampThinkingForEffort, classifyEffort, clearPortfolioCache, clearPortfolioCacheFor, clearPriceMapCache, compactMessages, createGuardRunnerState, engineToSSE, estimateTokens, explainTxTool, extractConversationText, extractMcpText, fetchAddressDefiPortfolio, fetchAddressPortfolio, fetchAudricHistory, fetchAudricPortfolio, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchTokenPrices, fetchWalletCoins, findTool, getAudricApiBase, getDefaultTools, getDefiCacheStore, getFetchLock, getMcpManager, getModifiableFields, getNaviCacheStore, getTelemetrySink, getToolFlags, getWalletAddress, getWalletCacheStore, guardArtifactPreview, guardStaleData, harnessShapeForEffort, hasNaviMcp, healthCheckTool, isBundleableTool, loadRecipes, looksLikeSuiNs, microcompact, mppServicesTool, naviKey, normalizeAddressInput, parseEvalSummary, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, regenerateBundle, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resetDefiCacheStore, resetFetchLock, resetNaviCacheStore, resetTelemetrySink, resetWalletCacheStore, resolveAddressToSuinsViaRpc, resolvePermissionTier, resolveSuinsTool, resolveSuinsViaRpc, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, setDefiCacheStore, setFetchLock, setNaviCacheStore, setTelemetrySink, setWalletCacheStore, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, tokenPricesTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, updateTodoTool, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
9378
9497
  //# sourceMappingURL=index.js.map
9379
9498
  //# sourceMappingURL=index.js.map