@t2000/engine 0.2.1 → 0.3.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
@@ -38,12 +38,8 @@ type EngineEvent = {
38
38
  result: unknown;
39
39
  isError: boolean;
40
40
  } | {
41
- type: 'permission_request';
42
- toolName: string;
43
- toolUseId: string;
44
- input: unknown;
45
- description: string;
46
- resolve: (response: PermissionResponse) => void;
41
+ type: 'pending_action';
42
+ action: PendingAction;
47
43
  } | {
48
44
  type: 'turn_complete';
49
45
  stopReason: StopReason;
@@ -59,11 +55,19 @@ type EngineEvent = {
59
55
  };
60
56
  type StopReason = 'end_turn' | 'tool_use' | 'max_tokens' | 'max_turns' | 'error';
61
57
  /**
62
- * Response from the client when resolving a permission request.
58
+ * Serializable description of a write tool that needs user approval.
59
+ * Stored in the session so the client can act on it in a separate request.
60
+ */
61
+ interface PendingAction {
62
+ toolName: string;
63
+ toolUseId: string;
64
+ input: unknown;
65
+ description: string;
66
+ }
67
+ /**
68
+ * Response from the client when resolving a pending action.
63
69
  * - `approved: false` → tool is declined, LLM is told "user declined"
64
- * - `approved: true` without `executionResult` → engine executes the tool server-side
65
- * - `approved: true` with `executionResult` → engine skips server-side execution
66
- * and uses the client-provided result (for client-side tx signing flows)
70
+ * - `approved: true` with `executionResult` → engine uses the client-provided result
67
71
  */
68
72
  interface PermissionResponse {
69
73
  approved: boolean;
@@ -231,16 +235,34 @@ declare class QueryEngine {
231
235
  private abortController;
232
236
  constructor(config: EngineConfig);
233
237
  /**
234
- * Submit a user message and receive a stream of engine events.
235
- * Handles the full agent loop: LLM → permission check → tool execution → LLM → ...
238
+ * Submit a user message and stream engine events.
239
+ *
240
+ * Read-only tools execute inline. Write tools that need confirmation yield a
241
+ * `pending_action` event and the stream ends — no persistent connection needed.
242
+ * The caller should save messages + pendingAction to the session store, then
243
+ * call `resumeWithToolResult()` after the user approves/denies and executes.
236
244
  */
237
245
  submitMessage(prompt: string): AsyncGenerator<EngineEvent>;
246
+ /**
247
+ * Resume the conversation after a pending action is resolved.
248
+ * Called with the user's approval/denial and optional client-side execution result.
249
+ *
250
+ * This is a separate HTTP request — no persistent connection from submitMessage.
251
+ */
252
+ resumeWithToolResult(action: PendingAction, response: PermissionResponse): AsyncGenerator<EngineEvent>;
238
253
  interrupt(): void;
239
254
  getMessages(): readonly Message[];
240
255
  reset(): void;
241
256
  loadMessages(messages: Message[]): void;
242
257
  setServerPositions(data: EngineConfig['serverPositions']): void;
243
258
  getUsage(): CostSnapshot;
259
+ /**
260
+ * Run the LLM → tool → LLM loop. When a write tool needs confirmation,
261
+ * yields `pending_action` and returns immediately (stream ends cleanly).
262
+ *
263
+ * @param freshPrompt - The original user prompt (for corrupt-history retry). Null on resume.
264
+ */
265
+ private agentLoop;
244
266
  private addErrorResults;
245
267
  private handleProviderEvent;
246
268
  }
@@ -275,11 +297,6 @@ declare class TxMutex {
275
297
  }
276
298
  declare function runTools(pending: PendingToolCall[], tools: Tool[], context: ToolContext, txMutex: TxMutex): AsyncGenerator<EngineEvent>;
277
299
 
278
- /**
279
- * Wire-safe representation of EngineEvent for SSE transport.
280
- * `permission_request` replaces the `resolve` callback with a `permissionId`
281
- * that the client sends back via a separate HTTP endpoint.
282
- */
283
300
  type SSEEvent = {
284
301
  type: 'text_delta';
285
302
  text: string;
@@ -295,12 +312,8 @@ type SSEEvent = {
295
312
  result: unknown;
296
313
  isError: boolean;
297
314
  } | {
298
- type: 'permission_request';
299
- permissionId: string;
300
- toolName: string;
301
- toolUseId: string;
302
- input: unknown;
303
- description: string;
315
+ type: 'pending_action';
316
+ action: PendingAction;
304
317
  } | {
305
318
  type: 'turn_complete';
306
319
  stopReason: StopReason;
@@ -316,30 +329,7 @@ type SSEEvent = {
316
329
  };
317
330
  declare function serializeSSE(event: SSEEvent): string;
318
331
  declare function parseSSE(raw: string): SSEEvent | null;
319
- declare class PermissionBridge {
320
- private pending;
321
- private counter;
322
- /**
323
- * Register a permission_request resolve callback.
324
- * Returns the permissionId to send to the client.
325
- */
326
- register(resolve: (response: PermissionResponse) => void): string;
327
- /**
328
- * Resolve a pending permission request from the client.
329
- * Pass `executionResult` when the client executed the action itself
330
- * (e.g., signed a transaction) so the engine can skip server-side execution.
331
- */
332
- resolve(permissionId: string, approved: boolean, executionResult?: unknown): boolean;
333
- /** Number of pending (unresolved) permission requests. */
334
- get size(): number;
335
- /** Reject all pending permissions (e.g., on disconnect). */
336
- rejectAll(): void;
337
- }
338
- /**
339
- * Wraps a QueryEngine.submitMessage() generator, converting EngineEvents
340
- * to SSE text. Permission requests are routed through the bridge.
341
- */
342
- declare function engineToSSE(events: AsyncGenerator<EngineEvent>, bridge: PermissionBridge): AsyncGenerator<string>;
332
+ declare function engineToSSE(events: AsyncGenerator<EngineEvent>): AsyncGenerator<string>;
343
333
 
344
334
  interface SessionData {
345
335
  id: string;
@@ -347,6 +337,8 @@ interface SessionData {
347
337
  usage: CostSnapshot;
348
338
  createdAt: number;
349
339
  updatedAt: number;
340
+ /** Set when the engine is paused waiting for user approval of a write action. */
341
+ pendingAction?: PendingAction | null;
350
342
  metadata?: Record<string, unknown>;
351
343
  }
352
344
  interface SessionStore {
@@ -903,4 +895,4 @@ declare function fetchWalletCoins(address: string, rpcUrl?: string): Promise<Wal
903
895
 
904
896
  declare const DEFAULT_SYSTEM_PROMPT = "You are Audric, an AI assistant built on the Sui blockchain. You help users manage finances AND access 40+ paid API services via MPP (Machine Payment Protocol) micropayments.\n\n## Core Capabilities\n- Check balances, savings positions, health factors, and interest rates\n- Execute deposits, withdrawals, transfers, borrows, and repayments\n- Track transaction history and earnings\n- Look up swap quotes, bridge options, and token information via NAVI\n- **Access any MPP service** \u2014 weather, web search, news, crypto prices, stock quotes, translations, image generation, maps, flights, and more via the pay_api tool\n- Answer general knowledge questions conversationally\n\n## MPP Services (via pay_api tool)\nWhen users ask for real-world data (weather, search, prices, news, etc.), use the pay_api tool. Each call costs a few cents in USDC, paid automatically on-chain. Common services:\n- **Weather/forecast**: OpenWeather \u2014 current conditions, 5-day forecast\n- **Web search**: Brave Search, Serper (Google), Perplexity (AI-powered)\n- **News**: NewsAPI headlines and search\n- **Crypto**: CoinGecko prices, markets, trending\n- **Stocks**: Alpha Vantage quotes, daily data\n- **Maps**: Google Maps geocode, places, directions\n- **Translation**: DeepL, Google Translate\n- **FX rates**: Exchange rate conversion\n- **Scraping**: Firecrawl, Jina Reader\n- **Flights**: SerpAPI Google Flights\n- **Image gen**: Flux, Stable Diffusion, DALL-E\n- **Email**: Resend\n\nAlways tell users the cost before calling a paid service. If they agree, use pay_api.\n\n## Guidelines\n\n### Before Acting\n- Always check the user's balance before suggesting financial actions\n- Show real numbers from tool results \u2014 never fabricate rates, amounts, or balances\n- For transactions that move funds, explain what will happen and confirm intent\n\n### Tool Usage\n- Use any available tools to help the user \u2014 don't refuse requests you can handle\n- For real-world questions (weather, search, news, prices), use pay_api with the appropriate MPP endpoint\n- Use multiple read-only tools in parallel when you need several data points\n- Present amounts as currency ($1,234.56) and rates as percentages (4.86% APY)\n- If a tool errors, explain the issue clearly and suggest alternatives\n\n### Communication Style\n- Be concise and direct \u2014 lead with results, follow with context\n- Use short sentences. Avoid hedging language.\n- When presenting positions or balances, use a structured format\n- For non-financial questions, answer naturally and helpfully\n\n### Safety\n- Never encourage risky financial behavior\n- Warn when health factor drops below 1.5\n- Remind users of gas costs for on-chain transactions\n- All amounts are in USDC unless explicitly stated otherwise";
905
897
 
906
- export { AnthropicProvider, type AnthropicProviderConfig, type BalancePrices, type BalanceResult, type BuildToolOptions, type ChatParams, type CompactOptions, type ContentBlock, type CostSnapshot, CostTracker, type CostTrackerConfig, DEFAULT_SYSTEM_PROMPT, type EngineConfig, type EngineEvent, type HealthFactorResult, type LLMProvider, type McpCallResult, McpClientManager, McpResponseCache, type McpServerConfig, type McpServerConnection, type McpToolAdapterConfig, type McpToolDescriptor, MemorySessionStore, type Message, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, type NaviRawCoin, type NaviRawHealthFactor, type NaviRawPool, type NaviRawPosition, type NaviRawPositionsResponse, type NaviRawProtocolStats, type NaviRawRewardsResponse, type NaviReadOptions, NaviTools, type PendingReward, type PendingToolCall, PermissionBridge, type PermissionLevel, type PermissionResponse, type PositionEntry, type ProtocolStats, type ProviderEvent, QueryEngine, READ_TOOLS, type RatesResult, type SSEEvent, type SavingsResult, type ServerPositionData, type SessionData, type SessionStore, type StopReason, type SuiCoinBalance, type Tool, type ToolContext, type ToolDefinition, type ToolJsonSchema, type ToolResult, TxMutex, WRITE_TOOLS, type WalletCoin, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, balanceCheckTool, borrowTool, buildMcpTools, buildTool, claimRewardsTool, compactMessages, engineToSSE, estimateTokens, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getWalletAddress, hasNaviMcp, healthCheckTool, parseMcpJson, parseSSE, payApiTool, ratesInfoTool, registerEngineTools, repayDebtTool, requireAgent, runTools, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, withdrawTool };
898
+ export { AnthropicProvider, type AnthropicProviderConfig, type BalancePrices, type BalanceResult, type BuildToolOptions, type ChatParams, type CompactOptions, type ContentBlock, type CostSnapshot, CostTracker, type CostTrackerConfig, DEFAULT_SYSTEM_PROMPT, type EngineConfig, type EngineEvent, type HealthFactorResult, type LLMProvider, type McpCallResult, McpClientManager, McpResponseCache, type McpServerConfig, type McpServerConnection, type McpToolAdapterConfig, type McpToolDescriptor, MemorySessionStore, type Message, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, type NaviRawCoin, type NaviRawHealthFactor, type NaviRawPool, type NaviRawPosition, type NaviRawPositionsResponse, type NaviRawProtocolStats, type NaviRawRewardsResponse, type NaviReadOptions, NaviTools, type PendingAction, type PendingReward, type PendingToolCall, type PermissionLevel, type PermissionResponse, type PositionEntry, type ProtocolStats, type ProviderEvent, QueryEngine, READ_TOOLS, type RatesResult, type SSEEvent, type SavingsResult, type ServerPositionData, type SessionData, type SessionStore, type StopReason, type SuiCoinBalance, type Tool, type ToolContext, type ToolDefinition, type ToolJsonSchema, type ToolResult, TxMutex, WRITE_TOOLS, type WalletCoin, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, balanceCheckTool, borrowTool, buildMcpTools, buildTool, claimRewardsTool, compactMessages, engineToSSE, estimateTokens, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getWalletAddress, hasNaviMcp, healthCheckTool, parseMcpJson, parseSSE, payApiTool, ratesInfoTool, registerEngineTools, repayDebtTool, requireAgent, runTools, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, withdrawTool };
package/dist/index.js CHANGED
@@ -1259,8 +1259,12 @@ var QueryEngine = class {
1259
1259
  this.tools = config.tools ?? (config.agent ? getDefaultTools() : []);
1260
1260
  }
1261
1261
  /**
1262
- * Submit a user message and receive a stream of engine events.
1263
- * Handles the full agent loop: LLM → permission check → tool execution → LLM → ...
1262
+ * Submit a user message and stream engine events.
1263
+ *
1264
+ * Read-only tools execute inline. Write tools that need confirmation yield a
1265
+ * `pending_action` event and the stream ends — no persistent connection needed.
1266
+ * The caller should save messages + pendingAction to the session store, then
1267
+ * call `resumeWithToolResult()` after the user approves/denies and executes.
1264
1268
  */
1265
1269
  async *submitMessage(prompt) {
1266
1270
  if (this.costTracker.isOverBudget()) {
@@ -1273,6 +1277,71 @@ var QueryEngine = class {
1273
1277
  role: "user",
1274
1278
  content: [{ type: "text", text: prompt }]
1275
1279
  });
1280
+ yield* this.agentLoop(prompt, signal);
1281
+ }
1282
+ /**
1283
+ * Resume the conversation after a pending action is resolved.
1284
+ * Called with the user's approval/denial and optional client-side execution result.
1285
+ *
1286
+ * This is a separate HTTP request — no persistent connection from submitMessage.
1287
+ */
1288
+ async *resumeWithToolResult(action, response) {
1289
+ this.abortController = new AbortController();
1290
+ const signal = this.abortController.signal;
1291
+ const toolResultBlock = response.approved ? {
1292
+ type: "tool_result",
1293
+ toolUseId: action.toolUseId,
1294
+ content: JSON.stringify(response.executionResult ?? { success: true }),
1295
+ isError: false
1296
+ } : {
1297
+ type: "tool_result",
1298
+ toolUseId: action.toolUseId,
1299
+ content: JSON.stringify({ error: "User declined this action" }),
1300
+ isError: true
1301
+ };
1302
+ this.messages.push({ role: "user", content: [toolResultBlock] });
1303
+ yield {
1304
+ type: "tool_result",
1305
+ toolName: action.toolName,
1306
+ toolUseId: action.toolUseId,
1307
+ result: response.approved ? response.executionResult ?? { success: true } : { error: "User declined this action" },
1308
+ isError: !response.approved
1309
+ };
1310
+ if (!response.approved) {
1311
+ yield { type: "turn_complete", stopReason: "end_turn" };
1312
+ return;
1313
+ }
1314
+ yield* this.agentLoop(null, signal);
1315
+ }
1316
+ interrupt() {
1317
+ this.abortController?.abort();
1318
+ }
1319
+ getMessages() {
1320
+ return this.messages;
1321
+ }
1322
+ reset() {
1323
+ this.messages = [];
1324
+ this.costTracker.reset();
1325
+ }
1326
+ loadMessages(messages) {
1327
+ this.messages = sanitizeMessages(messages);
1328
+ }
1329
+ setServerPositions(data) {
1330
+ this.serverPositions = data;
1331
+ }
1332
+ getUsage() {
1333
+ return this.costTracker.getSnapshot();
1334
+ }
1335
+ // ---------------------------------------------------------------------------
1336
+ // Core agent loop — shared by submitMessage and resumeWithToolResult
1337
+ // ---------------------------------------------------------------------------
1338
+ /**
1339
+ * Run the LLM → tool → LLM loop. When a write tool needs confirmation,
1340
+ * yields `pending_action` and returns immediately (stream ends cleanly).
1341
+ *
1342
+ * @param freshPrompt - The original user prompt (for corrupt-history retry). Null on resume.
1343
+ */
1344
+ async *agentLoop(freshPrompt, signal) {
1276
1345
  const context = {
1277
1346
  agent: this.agent,
1278
1347
  mcpManager: this.mcpManager,
@@ -1282,6 +1351,7 @@ var QueryEngine = class {
1282
1351
  signal
1283
1352
  };
1284
1353
  let turns = 0;
1354
+ let hasRetriedWithCleanHistory = false;
1285
1355
  while (turns < this.maxTurns) {
1286
1356
  if (signal.aborted) {
1287
1357
  yield { type: "error", error: new Error("Aborted") };
@@ -1295,16 +1365,29 @@ var QueryEngine = class {
1295
1365
  assistantBlocks: [],
1296
1366
  pendingToolCalls: []
1297
1367
  };
1298
- const stream = this.provider.chat({
1299
- messages: this.messages,
1300
- systemPrompt: this.systemPrompt,
1301
- tools: toolDefs,
1302
- model: this.model,
1303
- maxTokens: this.maxTokens,
1304
- signal
1305
- });
1306
- for await (const event of stream) {
1307
- yield* this.handleProviderEvent(event, acc);
1368
+ try {
1369
+ const stream = this.provider.chat({
1370
+ messages: this.messages,
1371
+ systemPrompt: this.systemPrompt,
1372
+ tools: toolDefs,
1373
+ model: this.model,
1374
+ maxTokens: this.maxTokens,
1375
+ signal
1376
+ });
1377
+ for await (const event of stream) {
1378
+ yield* this.handleProviderEvent(event, acc);
1379
+ }
1380
+ } catch (err) {
1381
+ if (freshPrompt && !hasRetriedWithCleanHistory && isCorruptHistoryError(err)) {
1382
+ hasRetriedWithCleanHistory = true;
1383
+ console.warn("[engine] Corrupt session history detected, resetting to fresh conversation");
1384
+ this.messages = [
1385
+ { role: "user", content: [{ type: "text", text: freshPrompt }] }
1386
+ ];
1387
+ turns--;
1388
+ continue;
1389
+ }
1390
+ throw err;
1308
1391
  }
1309
1392
  if (acc.text) {
1310
1393
  acc.assistantBlocks.push({ type: "text", text: acc.text });
@@ -1329,71 +1412,16 @@ var QueryEngine = class {
1329
1412
  yield { type: "tool_start", toolName: call.name, toolUseId: call.id, input: call.input };
1330
1413
  continue;
1331
1414
  }
1332
- let resolvePermission;
1333
- const permissionPromise = new Promise((r) => {
1334
- resolvePermission = r;
1335
- });
1336
1415
  yield {
1337
- type: "permission_request",
1338
- toolName: call.name,
1339
- toolUseId: call.id,
1340
- input: call.input,
1341
- description: describeAction(tool, call),
1342
- resolve: resolvePermission
1343
- };
1344
- let response;
1345
- try {
1346
- response = await Promise.race([
1347
- permissionPromise,
1348
- new Promise((_, reject) => {
1349
- if (signal.aborted) reject(new Error("Aborted"));
1350
- signal.addEventListener("abort", () => reject(new Error("Aborted")), { once: true });
1351
- })
1352
- ]);
1353
- } catch {
1354
- this.addErrorResults(acc.pendingToolCalls, "Aborted");
1355
- yield { type: "error", error: new Error("Aborted") };
1356
- return;
1357
- }
1358
- if (!response.approved) {
1359
- toolResultBlocks.push({
1360
- type: "tool_result",
1361
- toolUseId: call.id,
1362
- content: JSON.stringify({ error: "User declined this action" }),
1363
- isError: true
1364
- });
1365
- yield {
1366
- type: "tool_result",
1367
- toolName: call.name,
1368
- toolUseId: call.id,
1369
- result: { error: "User declined this action" },
1370
- isError: true
1371
- };
1372
- } else if (response.executionResult !== void 0) {
1373
- const clientResult = response.executionResult;
1374
- toolResultBlocks.push({
1375
- type: "tool_result",
1376
- toolUseId: call.id,
1377
- content: JSON.stringify(clientResult),
1378
- isError: false
1379
- });
1380
- yield {
1381
- type: "tool_start",
1382
- toolName: call.name,
1383
- toolUseId: call.id,
1384
- input: call.input
1385
- };
1386
- yield {
1387
- type: "tool_result",
1416
+ type: "pending_action",
1417
+ action: {
1388
1418
  toolName: call.name,
1389
1419
  toolUseId: call.id,
1390
- result: clientResult,
1391
- isError: false
1392
- };
1393
- } else {
1394
- approved.push(call);
1395
- yield { type: "tool_start", toolName: call.name, toolUseId: call.id, input: call.input };
1396
- }
1420
+ input: call.input,
1421
+ description: describeAction(tool, call)
1422
+ }
1423
+ };
1424
+ return;
1397
1425
  }
1398
1426
  for await (const toolEvent of runTools(approved, this.tools, context, this.txMutex)) {
1399
1427
  yield toolEvent;
@@ -1414,25 +1442,6 @@ var QueryEngine = class {
1414
1442
  }
1415
1443
  yield { type: "turn_complete", stopReason: "max_turns" };
1416
1444
  }
1417
- interrupt() {
1418
- this.abortController?.abort();
1419
- }
1420
- getMessages() {
1421
- return this.messages;
1422
- }
1423
- reset() {
1424
- this.messages = [];
1425
- this.costTracker.reset();
1426
- }
1427
- loadMessages(messages) {
1428
- this.messages = sanitizeMessages(messages);
1429
- }
1430
- setServerPositions(data) {
1431
- this.serverPositions = data;
1432
- }
1433
- getUsage() {
1434
- return this.costTracker.getSnapshot();
1435
- }
1436
1445
  // ---------------------------------------------------------------------------
1437
1446
  // Internal
1438
1447
  // ---------------------------------------------------------------------------
@@ -1491,8 +1500,12 @@ var QueryEngine = class {
1491
1500
  }
1492
1501
  }
1493
1502
  };
1503
+ function isCorruptHistoryError(err) {
1504
+ const msg = err instanceof Error ? err.message : String(err);
1505
+ return msg.includes("tool_use") && msg.includes("tool_result") || msg.includes("roles must alternate") || msg.includes("400") && msg.includes("invalid_request_error");
1506
+ }
1494
1507
  function sanitizeMessages(messages) {
1495
- const result = [];
1508
+ const trimmed = [];
1496
1509
  for (let i = 0; i < messages.length; i++) {
1497
1510
  const msg = messages[i];
1498
1511
  const toolUseIds = msg.content.filter((b) => b.type === "tool_use").map((b) => b.id);
@@ -1506,7 +1519,19 @@ function sanitizeMessages(messages) {
1506
1519
  break;
1507
1520
  }
1508
1521
  }
1522
+ trimmed.push(msg);
1523
+ }
1524
+ const result = [];
1525
+ let lastRole = null;
1526
+ for (const msg of trimmed) {
1527
+ if (msg.role === lastRole) {
1528
+ result.pop();
1529
+ }
1509
1530
  result.push(msg);
1531
+ lastRole = msg.role;
1532
+ }
1533
+ while (result.length > 0 && result[result.length - 1].role === "user") {
1534
+ result.pop();
1510
1535
  }
1511
1536
  return result;
1512
1537
  }
@@ -1549,68 +1574,12 @@ function parseSSE(raw) {
1549
1574
  return null;
1550
1575
  }
1551
1576
  }
1552
- var PermissionBridge = class {
1553
- pending = /* @__PURE__ */ new Map();
1554
- counter = 0;
1555
- /**
1556
- * Register a permission_request resolve callback.
1557
- * Returns the permissionId to send to the client.
1558
- */
1559
- register(resolve) {
1560
- const id = `perm_${++this.counter}_${Date.now()}`;
1561
- this.pending.set(id, resolve);
1562
- return id;
1563
- }
1564
- /**
1565
- * Resolve a pending permission request from the client.
1566
- * Pass `executionResult` when the client executed the action itself
1567
- * (e.g., signed a transaction) so the engine can skip server-side execution.
1568
- */
1569
- resolve(permissionId, approved, executionResult) {
1570
- const resolver = this.pending.get(permissionId);
1571
- if (!resolver) return false;
1572
- resolver({ approved, executionResult });
1573
- this.pending.delete(permissionId);
1574
- return true;
1575
- }
1576
- /** Number of pending (unresolved) permission requests. */
1577
- get size() {
1578
- return this.pending.size;
1579
- }
1580
- /** Reject all pending permissions (e.g., on disconnect). */
1581
- rejectAll() {
1582
- for (const resolver of this.pending.values()) {
1583
- resolver({ approved: false });
1584
- }
1585
- this.pending.clear();
1586
- }
1587
- };
1588
- async function* engineToSSE(events, bridge) {
1577
+ async function* engineToSSE(events) {
1589
1578
  for await (const event of events) {
1590
- switch (event.type) {
1591
- case "permission_request": {
1592
- const permissionId = bridge.register(event.resolve);
1593
- yield serializeSSE({
1594
- type: "permission_request",
1595
- permissionId,
1596
- toolName: event.toolName,
1597
- toolUseId: event.toolUseId,
1598
- input: event.input,
1599
- description: event.description
1600
- });
1601
- break;
1602
- }
1603
- case "error": {
1604
- yield serializeSSE({
1605
- type: "error",
1606
- message: event.error.message
1607
- });
1608
- break;
1609
- }
1610
- default: {
1611
- yield serializeSSE(event);
1612
- break;
1613
- }
1579
+ if (event.type === "error") {
1580
+ yield serializeSSE({ type: "error", message: event.error.message });
1581
+ } else {
1582
+ yield serializeSSE(event);
1614
1583
  }
1615
1584
  }
1616
1585
  }
@@ -2213,6 +2182,6 @@ function mapStopReason(reason) {
2213
2182
  }
2214
2183
  }
2215
2184
 
2216
- export { AnthropicProvider, CostTracker, DEFAULT_SYSTEM_PROMPT, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, PermissionBridge, QueryEngine, READ_TOOLS, TxMutex, WRITE_TOOLS, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, balanceCheckTool, borrowTool, buildMcpTools, buildTool, claimRewardsTool, compactMessages, engineToSSE, estimateTokens, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getWalletAddress, hasNaviMcp, healthCheckTool, parseMcpJson, parseSSE, payApiTool, ratesInfoTool, registerEngineTools, repayDebtTool, requireAgent, runTools, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, withdrawTool };
2185
+ export { AnthropicProvider, CostTracker, DEFAULT_SYSTEM_PROMPT, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, QueryEngine, READ_TOOLS, TxMutex, WRITE_TOOLS, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, balanceCheckTool, borrowTool, buildMcpTools, buildTool, claimRewardsTool, compactMessages, engineToSSE, estimateTokens, extractMcpText, fetchAvailableRewards, fetchBalance, fetchHealthFactor, fetchPositions, fetchProtocolStats, fetchRates, fetchSavings, fetchWalletCoins, findTool, getDefaultTools, getMcpManager, getWalletAddress, hasNaviMcp, healthCheckTool, parseMcpJson, parseSSE, payApiTool, ratesInfoTool, registerEngineTools, repayDebtTool, requireAgent, runTools, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, withdrawTool };
2217
2186
  //# sourceMappingURL=index.js.map
2218
2187
  //# sourceMappingURL=index.js.map