@t2000/engine 0.55.0 → 0.56.2
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 +86 -1
- package/dist/index.js +200 -17
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1978,7 +1978,11 @@ declare function parseMcpJson<T = unknown>(content: Array<{
|
|
|
1978
1978
|
interface NaviReadOptions {
|
|
1979
1979
|
/** MCP server name override (default: 'navi'). */
|
|
1980
1980
|
serverName?: string;
|
|
1981
|
+
/** Skip the cache for this call (default: false). Useful for post-write refreshes. */
|
|
1982
|
+
skipCache?: boolean;
|
|
1981
1983
|
}
|
|
1984
|
+
/** Test seam — reset NAVI CB state between tests. */
|
|
1985
|
+
declare function _resetNaviCircuitBreaker(): void;
|
|
1982
1986
|
declare function fetchRates(manager: McpClientManager, opts?: NaviReadOptions): Promise<RatesResult>;
|
|
1983
1987
|
declare function fetchHealthFactor(manager: McpClientManager, address: string, opts?: NaviReadOptions): Promise<HealthFactorResult>;
|
|
1984
1988
|
declare function fetchBalance(manager: McpClientManager, address: string, opts?: NaviReadOptions): Promise<BalanceResult>;
|
|
@@ -2795,4 +2799,85 @@ declare function fetchAudricHistory(address: string, opts: {
|
|
|
2795
2799
|
|
|
2796
2800
|
declare const DEFAULT_SYSTEM_PROMPT = "You are Audric \u2014 a financial agent on Sui. Audric is exactly five products: Audric Passport (the trust layer \u2014 Google sign-in, non-custodial wallet, tap-to-confirm consent, sponsored gas \u2014 wraps every other product), Audric Intelligence (you \u2014 the 5-system brain: Agent Harness with 34 tools, Reasoning Engine with 14 guards and 6 skill recipes, Silent Profile, Chain Memory, AdviceLog), Audric Finance (manage money on Sui \u2014 Save via NAVI lending at 3-8% APY USDC, Credit via NAVI borrowing with health factor, Swap via Cetus aggregator across 20+ DEXs at 0.1% fee, Charts for yield/health/portfolio viz), Audric Pay (move money \u2014 send USDC, receive via payment links / invoices / QR; free, global, instant on Sui), and Audric Store (creator marketplace, ships Phase 5 \u2014 say \"coming soon\" if asked). Save, swap, borrow, repay, withdraw, charts \u2192 Audric Finance. Send, receive, payment-link, invoice, QR \u2192 Audric Pay. Your silent context (profile, memory, chain facts, advice log) shapes your replies but never surfaces as a notification \u2014 you act only when the user asks, and every write waits on their tap-to-confirm via Passport. You can also call 41 paid APIs (music, image, research, translation, weather, fulfilment) via MPP micropayments using the pay_api tool \u2014 this is an internal capability, not a promoted product, so only mention it when the user asks for something that needs it.\n\n## Response rules\n- 1-2 sentences max. No bullet lists unless asked. No preambles.\n- Never say \"Would you like me to...\", \"Sure!\", \"Great question!\", \"Absolutely!\" \u2014 just do it or say you can't.\n- Present amounts as $1,234.56 and rates as X.XX% APY.\n- Show top 3 results unless asked for more. Summarize totals in one line.\n\n## Caption rules (after tool calls)\n- **When a canvas was rendered (`render_canvas` was called, or any tool that auto-renders a card like balance_check / portfolio_analysis / savings_info / health_check / transaction_history): the canvas IS the answer.** Your chat message must NOT restate wallet, savings, debt, holdings, or net-worth numbers \u2014 they are already on screen. Add at most ONE sentence of context, advice, or next step (e.g. \"Your USDC is idle \u2014 consider depositing for ~4.5% APY\"), or say nothing.\n- **When NO canvas was rendered:** lead with the result and quote the actual numbers from the tool. One sentence.\n- **NEVER describe a position as \"no\", \"none\", \"minimal\", \"zero\", or \"inactive\" if the tool result contains a positive value for that field.** The tool result is the source of truth \u2014 never your interior summary. If the canvas shows $100 in savings, you cannot say \"no active savings\" in the caption.\n- **NEVER claim \"no DeFi positions\" when the tool result says the DeFi slice is UNAVAILABLE.** When `balance_check` displayText contains \"DeFi positions: UNAVAILABLE\" or \"DeFi data source unreachable\", the slice is unknown \u2014 say \"DeFi data is currently unavailable\" or omit the mention. Only claim \"no DeFi positions\" when the displayText explicitly omits any DeFi line (i.e. the fetch succeeded with $0 across every covered protocol).\n\n## Execution rule\nOnly offer to execute actions you have tools for. If you retrieved a quote, data, or information but have no tool to act on it, give the user the result and tell them where to execute manually \u2014 in one sentence. Never say \"Would you like me to proceed?\" unless you have a tool that can actually proceed.\n\n## Before acting\n- ALWAYS call a read tool first before any write tool \u2014 balance_check before save/send/borrow, savings_info before withdraw.\n- Show real numbers from tools \u2014 never fabricate rates, amounts, or balances.\n- When user says \"all\" or an imprecise amount, call the read tool first to get the exact number.\n\n## Tool usage\n- Use tools proactively \u2014 don't refuse requests you can handle.\n- For real-world questions (weather, search, news, prices), use pay_api. Tell the user the cost first.\n- For NAVI lending APYs, use rates_info; for VOLO liquid staking stats, use volo_stats; for spot token prices, use token_prices.\n- For protocol-level due diligence (TVL, fees, audits, safety) on Sui DeFi protocols, use protocol_deep_dive with the slug.\n- Run multiple read-only tools in parallel when you need several data points.\n- If a tool errors, say what went wrong and what to try instead. One sentence.\n\n## Savings = USDC or USDsui (critical)\n- save_deposit and borrow accept ONLY USDC or USDsui. No other token can be deposited or borrowed.\n- USDC is the canonical default. USDsui is permitted because it has a productive NAVI pool (often a higher APY than USDC). All other holdings (GOLD, SUI, USDT, USDe, ETH, NAVX, WAL) are NOT saveable.\n- When asked \"how much can I save?\":\n - Report saveableUsdc from balance_check (the user's USDC wallet balance \u2014 canonical saveable).\n - If the user also holds USDsui in their wallet, report that separately as \"USDsui (saveable): X.XX\". Do NOT roll the two together \u2014 the LLM must keep the per-asset distinction so the user can pick.\n- When the user says \"save 10 USDC\" \u2192 call save_deposit with asset=\"USDC\". When they say \"save 10 USDsui\" \u2192 call with asset=\"USDsui\". Never silently substitute.\n- When the user says \"save 10\" (no asset) \u2192 call balance_check first and ask which stable they want, OR pick whichever they hold more of with a one-line explanation.\n- \"Best stable to save right now?\" \u2192 call rates_info to compare USDC vs USDsui APY on NAVI; let the user pick.\n- NEVER say a non-saveable token (GOLD, SUI, USDT, etc.) is \"in savings\" or \"earning APY in savings\". Wallet holdings \u2260 savings positions, even for stables we don't accept.\n- If user wants to save a non-saveable token, tell them to swap to USDC or USDsui first. Do NOT auto-chain swap + deposit.\n- Repay symmetry: a USDsui debt MUST be repaid with USDsui (and USDC debt with USDC). When calling repay_debt, pass asset=\"USDsui\" if the borrow is USDsui. If the user asks \"repay my debt\" and savings_info shows borrows in BOTH stables, list both and ask which to repay first. If the user holds the wrong stable, tell them to swap manually \u2014 do NOT auto-chain swap + repay.\n\n## Multi-step flows\n- \"How much X for Y?\": swap_quote first, then swap_execute if user confirms.\n- \"Swap then save\": swap_execute \u2192 balance_check \u2192 save_deposit. Confirm each step.\n- \"Buy $X of token\": token_prices \u2192 calculate amount \u2192 swap_execute.\n- \"Best yield on SUI\": compare rates_info (NAVI lending) + volo_stats (vSUI liquid staking).\n- withdraw supports legacy positions: USDC, USDe, USDsui, SUI. Pass asset param to withdraw a specific token.\n- \"Deposit SUI to earn yield\": volo_stake for SUI liquid staking. save_deposit only accepts USDC or USDsui.\n- \"Is protocol X safe?\" / \"Tell me about NAVI\": protocol_deep_dive with the slug.\n- \"Full account report\" / \"account summary\" / \"give me everything\" / \"complete overview\": triggers the `account_report` recipe \u2014 when the recipe block appears, follow EVERY step including all six tool calls. Each step renders a distinct rich card; skipping a step means a missing card.\n\n## Safety\n- Never encourage risky financial behavior.\n- Warn when health factor < 1.5.\n- All amounts in USDC unless stated otherwise.";
|
|
2797
2801
|
|
|
2798
|
-
|
|
2802
|
+
/** Cache entry shape. `cachedAt` is the wall-clock ms at write time. */
|
|
2803
|
+
interface NaviCacheEntry {
|
|
2804
|
+
data: unknown;
|
|
2805
|
+
/** Wall-clock ms when the entry was written. Used by callers for freshness math. */
|
|
2806
|
+
cachedAt: number;
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2809
|
+
* Pluggable cache backend for NAVI MCP reads.
|
|
2810
|
+
*
|
|
2811
|
+
* All methods are async to accommodate Redis-backed implementations.
|
|
2812
|
+
* `get` must return `null` (not throw) on backend failure.
|
|
2813
|
+
* `set` must swallow errors.
|
|
2814
|
+
*/
|
|
2815
|
+
interface NaviCacheStore {
|
|
2816
|
+
get(key: string): Promise<NaviCacheEntry | null>;
|
|
2817
|
+
set(key: string, entry: NaviCacheEntry, ttlSec: number): Promise<void>;
|
|
2818
|
+
delete(key: string): Promise<void>;
|
|
2819
|
+
clear(): Promise<void>;
|
|
2820
|
+
}
|
|
2821
|
+
declare class InMemoryNaviCacheStore implements NaviCacheStore {
|
|
2822
|
+
private readonly store;
|
|
2823
|
+
get(key: string): Promise<NaviCacheEntry | null>;
|
|
2824
|
+
set(key: string, entry: NaviCacheEntry, ttlSec: number): Promise<void>;
|
|
2825
|
+
delete(key: string): Promise<void>;
|
|
2826
|
+
clear(): Promise<void>;
|
|
2827
|
+
}
|
|
2828
|
+
/** Swap the active NAVI cache store. Called once at engine init by Audric. */
|
|
2829
|
+
declare function setNaviCacheStore(store: NaviCacheStore): void;
|
|
2830
|
+
/** Returns the currently active store. Used by navi-reads.ts. */
|
|
2831
|
+
declare function getNaviCacheStore(): NaviCacheStore;
|
|
2832
|
+
/** Restore the default in-memory store. Used by test teardowns. */
|
|
2833
|
+
declare function resetNaviCacheStore(): void;
|
|
2834
|
+
/** 30s TTL for address-scoped reads (savings, health). */
|
|
2835
|
+
declare const NAVI_ADDR_TTL_SEC = 30;
|
|
2836
|
+
/** 300s (5 min) TTL for the global rates table. */
|
|
2837
|
+
declare const NAVI_RATES_TTL_SEC = 300;
|
|
2838
|
+
declare const naviKey: {
|
|
2839
|
+
readonly rates: () => string;
|
|
2840
|
+
readonly savings: (address: string) => string;
|
|
2841
|
+
readonly health: (address: string) => string;
|
|
2842
|
+
};
|
|
2843
|
+
|
|
2844
|
+
/** A flat tag bag. Values are strings for universal serialization. */
|
|
2845
|
+
type TelemetryTags = Record<string, string | number>;
|
|
2846
|
+
/**
|
|
2847
|
+
* Pluggable telemetry backend.
|
|
2848
|
+
*
|
|
2849
|
+
* All methods are fire-and-forget — implementations MUST NOT throw.
|
|
2850
|
+
* Swallow errors internally and optionally log a warning; the hot path
|
|
2851
|
+
* should never fail because an observability call failed.
|
|
2852
|
+
*/
|
|
2853
|
+
interface TelemetrySink {
|
|
2854
|
+
/**
|
|
2855
|
+
* Increment a named counter by 1 (or `value` if supplied).
|
|
2856
|
+
* Used for discrete countable events: requests, errors, cache hits.
|
|
2857
|
+
*/
|
|
2858
|
+
counter(name: string, tags?: TelemetryTags, value?: number): void;
|
|
2859
|
+
/**
|
|
2860
|
+
* Record the current value of a gauge.
|
|
2861
|
+
* Used for point-in-time measurements: circuit-breaker open (0|1),
|
|
2862
|
+
* queue depths, active connections.
|
|
2863
|
+
*/
|
|
2864
|
+
gauge(name: string, value: number, tags?: TelemetryTags): void;
|
|
2865
|
+
/**
|
|
2866
|
+
* Record a distribution sample (latency, sizes).
|
|
2867
|
+
* Implementations may bucket, percentile, or just counter/average.
|
|
2868
|
+
*/
|
|
2869
|
+
histogram(name: string, value: number, tags?: TelemetryTags): void;
|
|
2870
|
+
}
|
|
2871
|
+
/**
|
|
2872
|
+
* Swap the active telemetry sink. Call once at engine init from a runtime
|
|
2873
|
+
* that wants to emit real metrics (e.g. Audric injecting `VercelTelemetrySink`).
|
|
2874
|
+
* Idempotent — calling again replaces the previous sink. Tests can inject
|
|
2875
|
+
* a spy sink and use `resetTelemetrySink()` to restore the noop default.
|
|
2876
|
+
*/
|
|
2877
|
+
declare function setTelemetrySink(sink: TelemetrySink): void;
|
|
2878
|
+
/** Returns the currently active sink. Used by hot-path instrumentation. */
|
|
2879
|
+
declare function getTelemetrySink(): TelemetrySink;
|
|
2880
|
+
/** Restore the default noop sink. Used by test teardowns. */
|
|
2881
|
+
declare function resetTelemetrySink(): void;
|
|
2882
|
+
|
|
2883
|
+
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, type DefiCacheEntry, type DefiCacheStore, type DefiProtocol, type DefiSummary, EarlyToolDispatcher, type EngineConfig, type EngineEvent, type FetchLock, type GuardCheckResult, type GuardConfig, type GuardEvent, type GuardInjection, type GuardResult, type GuardRunnerState, type GuardTier, type GuardVerdict, type HealthFactorResult, InMemoryDefiCacheStore, InMemoryFetchLock, InMemoryNaviCacheStore, InMemoryWalletCacheStore, type LLMProvider, 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 OutputConfig, PERMISSION_PRESETS, type PendingAction, type PendingActionModifiableField, 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, type RatesResult, type Recipe, type RecipePrerequisite, RecipeRegistry, type RecipeStep, type RecipeStepOnError, RetryTracker, type SSEEvent, type SavingsResult, type ServerPositionData, type SessionData, type SessionStore, type StateType, type StopReason, type SuiCoinBalance, type SystemBlock, type SystemPrompt, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, type TelemetrySink, type TelemetryTags, type ThinkingConfig, type ThinkingEffort, type Tool, type ToolChoice, type ToolContext, type ToolDefinition, type ToolFlags, type ToolJsonSchema, type ToolResult, TxMutex, 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, claimRewardsTool, 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, hasNaviMcp, healthCheckTool, loadRecipes, microcompact, mppServicesTool, naviKey, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resetDefiCacheStore, resetFetchLock, resetNaviCacheStore, resetTelemetrySink, resetWalletCacheStore, resolvePermissionTier, 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, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
|
package/dist/index.js
CHANGED
|
@@ -655,6 +655,26 @@ async function awaitOrFetch(key, fetcher, opts = {}) {
|
|
|
655
655
|
return fetcher();
|
|
656
656
|
}
|
|
657
657
|
|
|
658
|
+
// src/telemetry.ts
|
|
659
|
+
var NoopTelemetrySink = class {
|
|
660
|
+
counter(_name, _tags, _value) {
|
|
661
|
+
}
|
|
662
|
+
gauge(_name, _value, _tags) {
|
|
663
|
+
}
|
|
664
|
+
histogram(_name, _value, _tags) {
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
var activeSink = new NoopTelemetrySink();
|
|
668
|
+
function setTelemetrySink(sink) {
|
|
669
|
+
activeSink = sink;
|
|
670
|
+
}
|
|
671
|
+
function getTelemetrySink() {
|
|
672
|
+
return activeSink;
|
|
673
|
+
}
|
|
674
|
+
function resetTelemetrySink() {
|
|
675
|
+
activeSink = new NoopTelemetrySink();
|
|
676
|
+
}
|
|
677
|
+
|
|
658
678
|
// src/blockvision-prices.ts
|
|
659
679
|
var BLOCKVISION_BASE = "https://api.blockvision.org/v2/sui";
|
|
660
680
|
var PORTFOLIO_TIMEOUT_MS = 4e3;
|
|
@@ -683,6 +703,7 @@ function cbRecord429(now) {
|
|
|
683
703
|
cb429Timestamps = cb429Timestamps.filter((t) => now - t < CB_WINDOW_MS);
|
|
684
704
|
if (cb429Timestamps.length >= CB_THRESHOLD && !cbIsOpen(now)) {
|
|
685
705
|
cbOpenUntil = now + CB_COOLDOWN_MS;
|
|
706
|
+
getTelemetrySink().gauge("bv.cb_open", 1);
|
|
686
707
|
console.warn(
|
|
687
708
|
`[blockvision] circuit breaker OPEN \u2014 ${CB_THRESHOLD} 429s in ${CB_WINDOW_MS}ms, retries disabled for ${CB_COOLDOWN_MS / 1e3}s`
|
|
688
709
|
);
|
|
@@ -728,18 +749,26 @@ async function fetchBlockVisionWithRetry(url, init, opts = {}) {
|
|
|
728
749
|
} catch (err) {
|
|
729
750
|
lastError = err;
|
|
730
751
|
if (err?.name === "AbortError") throw err;
|
|
752
|
+
getTelemetrySink().counter("bv.requests", { status: "network_err", attempt: String(attempt) });
|
|
731
753
|
continue;
|
|
732
754
|
}
|
|
733
|
-
if (lastResponse.ok)
|
|
755
|
+
if (lastResponse.ok) {
|
|
756
|
+
getTelemetrySink().counter("bv.requests", { status: "2xx", attempt: String(attempt) });
|
|
757
|
+
return lastResponse;
|
|
758
|
+
}
|
|
734
759
|
if (lastResponse.status !== 429 && lastResponse.status < 500) {
|
|
760
|
+
getTelemetrySink().counter("bv.requests", { status: String(lastResponse.status), attempt: String(attempt) });
|
|
735
761
|
return lastResponse;
|
|
736
762
|
}
|
|
737
763
|
if (lastResponse.status === 429) {
|
|
764
|
+
getTelemetrySink().counter("bv.requests", { status: "429", attempt: String(attempt) });
|
|
738
765
|
const now = (opts.now ?? Date.now)();
|
|
739
766
|
cbRecord429(now);
|
|
740
767
|
if (cbIsOpen(now)) {
|
|
741
768
|
return lastResponse;
|
|
742
769
|
}
|
|
770
|
+
} else {
|
|
771
|
+
getTelemetrySink().counter("bv.requests", { status: "5xx", attempt: String(attempt) });
|
|
743
772
|
}
|
|
744
773
|
}
|
|
745
774
|
if (lastResponse) return lastResponse;
|
|
@@ -785,8 +814,12 @@ async function fetchAddressPortfolio(address, apiKey, fallbackRpcUrl) {
|
|
|
785
814
|
if (cachedEntry) {
|
|
786
815
|
const ageMs = Date.now() - cachedEntry.pricedAt;
|
|
787
816
|
if (ageMs < walletFreshTtlMs(cachedEntry.data.source)) {
|
|
817
|
+
getTelemetrySink().counter("bv.cache_hit", { kind: "wallet", freshness: "fresh" });
|
|
788
818
|
return cachedEntry.data;
|
|
789
819
|
}
|
|
820
|
+
getTelemetrySink().counter("bv.cache_hit", { kind: "wallet", freshness: "stale-served" });
|
|
821
|
+
} else {
|
|
822
|
+
getTelemetrySink().counter("bv.cache_hit", { kind: "wallet", freshness: "miss" });
|
|
790
823
|
}
|
|
791
824
|
const existing = portfolioInflight.get(address);
|
|
792
825
|
if (existing) return existing;
|
|
@@ -1106,8 +1139,12 @@ async function fetchAddressDefiPortfolio(address, apiKey, priceHints = {}) {
|
|
|
1106
1139
|
const ageMs = Date.now() - cachedEntry.pricedAt;
|
|
1107
1140
|
const freshTtlMs = freshTtlForSource(cachedEntry.data.source);
|
|
1108
1141
|
if (ageMs < freshTtlMs) {
|
|
1142
|
+
getTelemetrySink().counter("bv.cache_hit", { kind: "defi", freshness: "fresh" });
|
|
1109
1143
|
return cachedEntry.data;
|
|
1110
1144
|
}
|
|
1145
|
+
getTelemetrySink().counter("bv.cache_hit", { kind: "defi", freshness: "stale-served" });
|
|
1146
|
+
} else {
|
|
1147
|
+
getTelemetrySink().counter("bv.cache_hit", { kind: "defi", freshness: "miss" });
|
|
1111
1148
|
}
|
|
1112
1149
|
let inflight = defiInflight.get(address);
|
|
1113
1150
|
if (inflight) return inflight;
|
|
@@ -1911,10 +1948,80 @@ var balanceCheckTool = buildTool({
|
|
|
1911
1948
|
}
|
|
1912
1949
|
});
|
|
1913
1950
|
|
|
1951
|
+
// src/navi-cache.ts
|
|
1952
|
+
var InMemoryNaviCacheStore = class {
|
|
1953
|
+
store = /* @__PURE__ */ new Map();
|
|
1954
|
+
async get(key) {
|
|
1955
|
+
const slot = this.store.get(key);
|
|
1956
|
+
if (!slot) return null;
|
|
1957
|
+
if (Date.now() >= slot.expiresAt) {
|
|
1958
|
+
this.store.delete(key);
|
|
1959
|
+
return null;
|
|
1960
|
+
}
|
|
1961
|
+
return slot.entry;
|
|
1962
|
+
}
|
|
1963
|
+
async set(key, entry, ttlSec) {
|
|
1964
|
+
this.store.set(key, {
|
|
1965
|
+
entry,
|
|
1966
|
+
expiresAt: Date.now() + ttlSec * 1e3
|
|
1967
|
+
});
|
|
1968
|
+
}
|
|
1969
|
+
async delete(key) {
|
|
1970
|
+
this.store.delete(key);
|
|
1971
|
+
}
|
|
1972
|
+
async clear() {
|
|
1973
|
+
this.store.clear();
|
|
1974
|
+
}
|
|
1975
|
+
};
|
|
1976
|
+
var activeStore3 = new InMemoryNaviCacheStore();
|
|
1977
|
+
function setNaviCacheStore(store) {
|
|
1978
|
+
activeStore3 = store;
|
|
1979
|
+
}
|
|
1980
|
+
function getNaviCacheStore() {
|
|
1981
|
+
return activeStore3;
|
|
1982
|
+
}
|
|
1983
|
+
function resetNaviCacheStore() {
|
|
1984
|
+
activeStore3 = new InMemoryNaviCacheStore();
|
|
1985
|
+
}
|
|
1986
|
+
var NAVI_ADDR_TTL_SEC = 30;
|
|
1987
|
+
var NAVI_RATES_TTL_SEC = 300;
|
|
1988
|
+
var naviKey = {
|
|
1989
|
+
rates: () => "navi:rates",
|
|
1990
|
+
savings: (address) => `navi:savings:${address.toLowerCase()}`,
|
|
1991
|
+
health: (address) => `navi:health:${address.toLowerCase()}`
|
|
1992
|
+
};
|
|
1993
|
+
|
|
1914
1994
|
// src/navi-reads.ts
|
|
1915
1995
|
function sn(opts) {
|
|
1916
1996
|
return opts?.serverName ?? NAVI_SERVER_NAME;
|
|
1917
1997
|
}
|
|
1998
|
+
var NAVI_CB_WINDOW_MS = 5e3;
|
|
1999
|
+
var NAVI_CB_THRESHOLD = 10;
|
|
2000
|
+
var NAVI_CB_COOLDOWN_MS = 3e4;
|
|
2001
|
+
var naviCb429Timestamps = [];
|
|
2002
|
+
var naviCbOpenUntil = 0;
|
|
2003
|
+
function naviCbIsOpen(now) {
|
|
2004
|
+
return now < naviCbOpenUntil;
|
|
2005
|
+
}
|
|
2006
|
+
function naviCbRecordError(now) {
|
|
2007
|
+
naviCb429Timestamps.push(now);
|
|
2008
|
+
naviCb429Timestamps = naviCb429Timestamps.filter((t) => now - t < NAVI_CB_WINDOW_MS);
|
|
2009
|
+
if (naviCb429Timestamps.length >= NAVI_CB_THRESHOLD && !naviCbIsOpen(now)) {
|
|
2010
|
+
naviCbOpenUntil = now + NAVI_CB_COOLDOWN_MS;
|
|
2011
|
+
getTelemetrySink().gauge("navi.cb_open", 1);
|
|
2012
|
+
console.warn(
|
|
2013
|
+
`[navi-reads] circuit breaker OPEN \u2014 ${NAVI_CB_THRESHOLD} errors in ${NAVI_CB_WINDOW_MS}ms, retries disabled for ${NAVI_CB_COOLDOWN_MS / 1e3}s`
|
|
2014
|
+
);
|
|
2015
|
+
naviCb429Timestamps = [];
|
|
2016
|
+
}
|
|
2017
|
+
}
|
|
2018
|
+
function _resetNaviCircuitBreaker() {
|
|
2019
|
+
naviCb429Timestamps = [];
|
|
2020
|
+
naviCbOpenUntil = 0;
|
|
2021
|
+
}
|
|
2022
|
+
var NAVI_RETRY_MAX_ATTEMPTS = 3;
|
|
2023
|
+
var NAVI_RETRY_BASE_DELAY_MS = 200;
|
|
2024
|
+
var NAVI_RETRY_BACKOFF_FACTOR = 3;
|
|
1918
2025
|
async function callNavi2(manager, tool, args = {}, opts) {
|
|
1919
2026
|
const result = await manager.callTool(sn(opts), tool, args);
|
|
1920
2027
|
if (result.isError) {
|
|
@@ -1923,31 +2030,92 @@ async function callNavi2(manager, tool, args = {}, opts) {
|
|
|
1923
2030
|
}
|
|
1924
2031
|
return parseMcpJson(result.content);
|
|
1925
2032
|
}
|
|
2033
|
+
async function callNaviWithRetry(manager, tool, args = {}, opts) {
|
|
2034
|
+
const sink = getTelemetrySink();
|
|
2035
|
+
const now = () => Date.now();
|
|
2036
|
+
if (naviCbIsOpen(now())) {
|
|
2037
|
+
sink.counter("navi.requests", { tool, status: "cb_open" });
|
|
2038
|
+
throw new Error(`[navi-reads] circuit breaker open \u2014 skipping ${tool}`);
|
|
2039
|
+
}
|
|
2040
|
+
let lastError;
|
|
2041
|
+
for (let attempt = 0; attempt < NAVI_RETRY_MAX_ATTEMPTS; attempt++) {
|
|
2042
|
+
if (attempt > 0) {
|
|
2043
|
+
const delay = NAVI_RETRY_BASE_DELAY_MS * Math.pow(NAVI_RETRY_BACKOFF_FACTOR, attempt - 1);
|
|
2044
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
2045
|
+
}
|
|
2046
|
+
try {
|
|
2047
|
+
const result = await callNavi2(manager, tool, args, opts);
|
|
2048
|
+
sink.counter("navi.requests", { tool, status: "2xx", attempt: String(attempt) });
|
|
2049
|
+
return result;
|
|
2050
|
+
} catch (err) {
|
|
2051
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
2052
|
+
sink.counter("navi.requests", { tool, status: "5xx", attempt: String(attempt) });
|
|
2053
|
+
naviCbRecordError(now());
|
|
2054
|
+
if (naviCbIsOpen(now())) {
|
|
2055
|
+
throw lastError;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
throw lastError ?? new Error(`NAVI MCP: ${tool} failed after ${NAVI_RETRY_MAX_ATTEMPTS} attempts`);
|
|
2060
|
+
}
|
|
2061
|
+
async function cacheGet(key) {
|
|
2062
|
+
try {
|
|
2063
|
+
const entry = await getNaviCacheStore().get(key);
|
|
2064
|
+
if (entry !== null) {
|
|
2065
|
+
getTelemetrySink().counter("navi.cache_hit", { key_prefix: key.split(":").slice(0, 2).join(":"), freshness: "fresh" });
|
|
2066
|
+
return entry.data;
|
|
2067
|
+
}
|
|
2068
|
+
getTelemetrySink().counter("navi.cache_hit", { key_prefix: key.split(":").slice(0, 2).join(":"), freshness: "miss" });
|
|
2069
|
+
return null;
|
|
2070
|
+
} catch {
|
|
2071
|
+
return null;
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
async function cacheSet(key, data, ttlSec) {
|
|
2075
|
+
try {
|
|
2076
|
+
await getNaviCacheStore().set(key, { data, cachedAt: Date.now() }, ttlSec);
|
|
2077
|
+
} catch {
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
1926
2080
|
async function fetchRates(manager, opts) {
|
|
1927
|
-
const
|
|
1928
|
-
|
|
2081
|
+
const key = naviKey.rates();
|
|
2082
|
+
if (!opts?.skipCache) {
|
|
2083
|
+
const cached = await cacheGet(key);
|
|
2084
|
+
if (cached) return cached;
|
|
2085
|
+
}
|
|
2086
|
+
const pools = await callNaviWithRetry(manager, NaviTools.GET_POOLS, {}, opts);
|
|
2087
|
+
const result = transformRates(pools);
|
|
2088
|
+
await cacheSet(key, result, NAVI_RATES_TTL_SEC);
|
|
2089
|
+
return result;
|
|
1929
2090
|
}
|
|
1930
2091
|
async function fetchHealthFactor(manager, address, opts) {
|
|
2092
|
+
const key = naviKey.health(address);
|
|
2093
|
+
if (!opts?.skipCache) {
|
|
2094
|
+
const cached = await cacheGet(key);
|
|
2095
|
+
if (cached) return cached;
|
|
2096
|
+
}
|
|
1931
2097
|
const [hfRaw, posRaw] = await Promise.all([
|
|
1932
|
-
|
|
1933
|
-
|
|
2098
|
+
callNaviWithRetry(manager, NaviTools.GET_HEALTH_FACTOR, { address }, opts),
|
|
2099
|
+
callNaviWithRetry(manager, NaviTools.GET_POSITIONS, {
|
|
1934
2100
|
address,
|
|
1935
2101
|
protocols: "navi",
|
|
1936
2102
|
format: "json"
|
|
1937
2103
|
}, opts)
|
|
1938
2104
|
]);
|
|
1939
|
-
|
|
2105
|
+
const result = transformHealthFactor(hfRaw, posRaw);
|
|
2106
|
+
await cacheSet(key, result, NAVI_ADDR_TTL_SEC);
|
|
2107
|
+
return result;
|
|
1940
2108
|
}
|
|
1941
2109
|
async function fetchBalance(manager, address, opts) {
|
|
1942
2110
|
const [coins, positions, rewards, pools] = await Promise.all([
|
|
1943
|
-
|
|
1944
|
-
|
|
2111
|
+
callNaviWithRetry(manager, NaviTools.GET_COINS, { address }, opts),
|
|
2112
|
+
callNaviWithRetry(manager, NaviTools.GET_POSITIONS, {
|
|
1945
2113
|
address,
|
|
1946
2114
|
protocols: "navi",
|
|
1947
2115
|
format: "json"
|
|
1948
2116
|
}, opts),
|
|
1949
|
-
|
|
1950
|
-
|
|
2117
|
+
callNaviWithRetry(manager, NaviTools.GET_AVAILABLE_REWARDS, { address }, opts),
|
|
2118
|
+
callNaviWithRetry(manager, NaviTools.GET_POOLS, {}, opts)
|
|
1951
2119
|
]);
|
|
1952
2120
|
const rates = transformRates(pools);
|
|
1953
2121
|
const prices = {};
|
|
@@ -1957,18 +2125,25 @@ async function fetchBalance(manager, address, opts) {
|
|
|
1957
2125
|
return transformBalance(coins, positions, rewards, prices);
|
|
1958
2126
|
}
|
|
1959
2127
|
async function fetchSavings(manager, address, opts) {
|
|
2128
|
+
const key = naviKey.savings(address);
|
|
2129
|
+
if (!opts?.skipCache) {
|
|
2130
|
+
const cached = await cacheGet(key);
|
|
2131
|
+
if (cached) return cached;
|
|
2132
|
+
}
|
|
1960
2133
|
const [positions, pools] = await Promise.all([
|
|
1961
|
-
|
|
2134
|
+
callNaviWithRetry(manager, NaviTools.GET_POSITIONS, {
|
|
1962
2135
|
address,
|
|
1963
2136
|
protocols: "navi",
|
|
1964
2137
|
format: "json"
|
|
1965
2138
|
}, opts),
|
|
1966
|
-
|
|
2139
|
+
callNaviWithRetry(manager, NaviTools.GET_POOLS, {}, opts)
|
|
1967
2140
|
]);
|
|
1968
|
-
|
|
2141
|
+
const result = transformSavings(positions, pools);
|
|
2142
|
+
await cacheSet(key, result, NAVI_ADDR_TTL_SEC);
|
|
2143
|
+
return result;
|
|
1969
2144
|
}
|
|
1970
2145
|
async function fetchPositions(manager, address, opts) {
|
|
1971
|
-
const raw = await
|
|
2146
|
+
const raw = await callNaviWithRetry(
|
|
1972
2147
|
manager,
|
|
1973
2148
|
NaviTools.GET_POSITIONS,
|
|
1974
2149
|
{ address, protocols: opts?.protocols ?? "navi", format: "json" },
|
|
@@ -1977,7 +2152,7 @@ async function fetchPositions(manager, address, opts) {
|
|
|
1977
2152
|
return transformPositions(raw);
|
|
1978
2153
|
}
|
|
1979
2154
|
async function fetchAvailableRewards(manager, address, opts) {
|
|
1980
|
-
const raw = await
|
|
2155
|
+
const raw = await callNaviWithRetry(
|
|
1981
2156
|
manager,
|
|
1982
2157
|
NaviTools.GET_AVAILABLE_REWARDS,
|
|
1983
2158
|
{ address },
|
|
@@ -1986,7 +2161,7 @@ async function fetchAvailableRewards(manager, address, opts) {
|
|
|
1986
2161
|
return transformRewards(raw);
|
|
1987
2162
|
}
|
|
1988
2163
|
async function fetchProtocolStats(manager, opts) {
|
|
1989
|
-
const raw = await
|
|
2164
|
+
const raw = await callNaviWithRetry(manager, NaviTools.GET_PROTOCOL_STATS, {}, opts);
|
|
1990
2165
|
return {
|
|
1991
2166
|
tvl: raw?.tvl ?? 0,
|
|
1992
2167
|
totalBorrowUsd: raw?.totalBorrowUsd ?? 0,
|
|
@@ -6384,12 +6559,14 @@ var QueryEngine = class {
|
|
|
6384
6559
|
};
|
|
6385
6560
|
let turns = 0;
|
|
6386
6561
|
let hasRetriedWithCleanHistory = false;
|
|
6562
|
+
let turnStartMs = Date.now();
|
|
6387
6563
|
while (turns < this.maxTurns) {
|
|
6388
6564
|
if (signal.aborted) {
|
|
6389
6565
|
yield { type: "error", error: new Error("Aborted") };
|
|
6390
6566
|
return;
|
|
6391
6567
|
}
|
|
6392
6568
|
turns++;
|
|
6569
|
+
turnStartMs = Date.now();
|
|
6393
6570
|
const toolDefs = toolsToDefinitions(this.tools);
|
|
6394
6571
|
const acc = {
|
|
6395
6572
|
text: "",
|
|
@@ -6553,6 +6730,7 @@ ${recipeCtx}`;
|
|
|
6553
6730
|
const hasRemainingCalls = acc.pendingToolCalls.length > 0;
|
|
6554
6731
|
if (!hasEarlyResults && !hasRemainingCalls) {
|
|
6555
6732
|
this.messages.push({ role: "assistant", content: acc.assistantBlocks });
|
|
6733
|
+
getTelemetrySink().histogram("anthropic.latency_ms", Date.now() - turnStartMs);
|
|
6556
6734
|
yield { type: "turn_complete", stopReason: acc.stopReason };
|
|
6557
6735
|
return;
|
|
6558
6736
|
}
|
|
@@ -6900,6 +7078,11 @@ ${recipeCtx}`;
|
|
|
6900
7078
|
event.cacheWriteTokens
|
|
6901
7079
|
);
|
|
6902
7080
|
this.contextBudget.update(event.inputTokens);
|
|
7081
|
+
const sink = getTelemetrySink();
|
|
7082
|
+
if (event.inputTokens) sink.counter("anthropic.tokens", { kind: "input" }, event.inputTokens);
|
|
7083
|
+
if (event.outputTokens) sink.counter("anthropic.tokens", { kind: "output" }, event.outputTokens);
|
|
7084
|
+
if (event.cacheReadTokens) sink.counter("anthropic.tokens", { kind: "cache_read" }, event.cacheReadTokens);
|
|
7085
|
+
if (event.cacheWriteTokens) sink.counter("anthropic.tokens", { kind: "cache_write" }, event.cacheWriteTokens);
|
|
6903
7086
|
yield {
|
|
6904
7087
|
type: "usage",
|
|
6905
7088
|
inputTokens: event.inputTokens,
|
|
@@ -8086,6 +8269,6 @@ function sanitizeAnthropicMessages(messages) {
|
|
|
8086
8269
|
return merged;
|
|
8087
8270
|
}
|
|
8088
8271
|
|
|
8089
|
-
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, EarlyToolDispatcher, InMemoryDefiCacheStore, InMemoryFetchLock, InMemoryWalletCacheStore, McpClientManager, McpResponseCache, MemorySessionStore, NAVI_MCP_CONFIG, NAVI_MCP_URL, NAVI_SERVER_NAME, NaviTools, PERMISSION_PRESETS, QueryEngine, READ_TOOLS, RecipeRegistry, RetryTracker, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TxMutex, WRITE_TOOLS, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, awaitOrFetch, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, claimRewardsTool, 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, getToolFlags, getWalletAddress, getWalletCacheStore, guardArtifactPreview, guardStaleData, hasNaviMcp, healthCheckTool, loadRecipes, microcompact, mppServicesTool, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resetDefiCacheStore, resetFetchLock, resetWalletCacheStore, resolvePermissionTier, resolveUsdValue, runGuards, runTools, saveContactTool, saveDepositTool, savingsInfoTool, sendTransferTool, serializeSSE, setDefiCacheStore, setFetchLock, setWalletCacheStore, spendingAnalyticsTool, swapExecuteTool, swapQuoteTool, tokenPricesTool, toolNameToOperation, toolsToDefinitions, transactionHistoryTool, transformBalance, transformHealthFactor, transformPositions, transformRates, transformRewards, transformSavings, updateGuardStateAfterToolResult, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
|
|
8272
|
+
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, EarlyToolDispatcher, InMemoryDefiCacheStore, InMemoryFetchLock, InMemoryNaviCacheStore, InMemoryWalletCacheStore, 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, RecipeRegistry, RetryTracker, TOOL_FLAGS, TOOL_MODIFIABLE_FIELDS, TxMutex, WRITE_TOOLS, _resetNaviCircuitBreaker, activitySummaryTool, adaptAllMcpTools, adaptAllServerTools, adaptMcpTool, applyToolFlags, awaitOrFetch, balanceCheckTool, borrowTool, budgetToolResult, buildCachedSystemPrompt, buildMcpTools, buildProactivenessInstructions, buildProfileContext, buildSelfEvaluationInstruction, buildStateContext, buildTool, claimRewardsTool, 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, hasNaviMcp, healthCheckTool, loadRecipes, microcompact, mppServicesTool, naviKey, parseMcpJson, parseRecipe, parseSSE, payApiTool, portfolioAnalysisTool, protocolDeepDiveTool, ratesInfoTool, registerEngineTools, renderCanvasTool, repayDebtTool, requireAgent, resetDefiCacheStore, resetFetchLock, resetNaviCacheStore, resetTelemetrySink, resetWalletCacheStore, resolvePermissionTier, 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, validateHistory, voloStakeTool, voloStatsTool, voloUnstakeTool, webSearchTool, withdrawTool, yieldSummaryTool };
|
|
8090
8273
|
//# sourceMappingURL=index.js.map
|
|
8091
8274
|
//# sourceMappingURL=index.js.map
|