@kaleidorg/mind 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. package/dist/bitrefill/contract.d.ts +60 -0
  2. package/dist/bitrefill/contract.d.ts.map +1 -0
  3. package/dist/bitrefill/contract.js +119 -0
  4. package/dist/bitrefill/contract.js.map +1 -0
  5. package/dist/context/compress.d.ts +65 -0
  6. package/dist/context/compress.d.ts.map +1 -0
  7. package/dist/context/compress.js +181 -0
  8. package/dist/context/compress.js.map +1 -0
  9. package/dist/engine.d.ts +20 -0
  10. package/dist/engine.d.ts.map +1 -1
  11. package/dist/engine.js +23 -4
  12. package/dist/engine.js.map +1 -1
  13. package/dist/evidence.d.ts +62 -0
  14. package/dist/evidence.d.ts.map +1 -0
  15. package/dist/evidence.js +47 -0
  16. package/dist/evidence.js.map +1 -0
  17. package/dist/flashnet/contract.d.ts +56 -0
  18. package/dist/flashnet/contract.d.ts.map +1 -0
  19. package/dist/flashnet/contract.js +100 -0
  20. package/dist/flashnet/contract.js.map +1 -0
  21. package/dist/funnel.d.ts +11 -0
  22. package/dist/funnel.d.ts.map +1 -1
  23. package/dist/funnel.js +50 -7
  24. package/dist/funnel.js.map +1 -1
  25. package/dist/index.d.ts +10 -1
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +7 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/kaleidoswap/contract.js +1 -1
  30. package/dist/kaleidoswap/contract.js.map +1 -1
  31. package/dist/knowledge/bitcoin-copilot.d.ts.map +1 -1
  32. package/dist/knowledge/bitcoin-copilot.js +83 -0
  33. package/dist/knowledge/bitcoin-copilot.js.map +1 -1
  34. package/dist/providers/types.d.ts +17 -0
  35. package/dist/providers/types.d.ts.map +1 -1
  36. package/dist/qvac/provider.d.ts.map +1 -1
  37. package/dist/qvac/provider.js +23 -0
  38. package/dist/qvac/provider.js.map +1 -1
  39. package/dist/qvac/stream.d.ts +6 -0
  40. package/dist/qvac/stream.d.ts.map +1 -1
  41. package/dist/qvac/stream.js +12 -0
  42. package/dist/qvac/stream.js.map +1 -1
  43. package/dist/recipe/flashnet-swap.d.ts +35 -0
  44. package/dist/recipe/flashnet-swap.d.ts.map +1 -0
  45. package/dist/recipe/flashnet-swap.js +239 -0
  46. package/dist/recipe/flashnet-swap.js.map +1 -0
  47. package/dist/recipe/kaleidoswap-atomic.d.ts.map +1 -1
  48. package/dist/recipe/kaleidoswap-atomic.js +37 -16
  49. package/dist/recipe/kaleidoswap-atomic.js.map +1 -1
  50. package/dist/recipe/kaleidoswap-channel-order.d.ts.map +1 -1
  51. package/dist/recipe/kaleidoswap-channel-order.js +31 -10
  52. package/dist/recipe/kaleidoswap-channel-order.js.map +1 -1
  53. package/dist/recipe/kaleidoswap-price.d.ts.map +1 -1
  54. package/dist/recipe/kaleidoswap-price.js +7 -1
  55. package/dist/recipe/kaleidoswap-price.js.map +1 -1
  56. package/dist/recipe/runner.d.ts.map +1 -1
  57. package/dist/recipe/runner.js +5 -3
  58. package/dist/recipe/runner.js.map +1 -1
  59. package/dist/recipe/swap.d.ts.map +1 -1
  60. package/dist/recipe/swap.js +14 -1
  61. package/dist/recipe/swap.js.map +1 -1
  62. package/dist/wallet/confirm.d.ts.map +1 -1
  63. package/dist/wallet/confirm.js +1 -0
  64. package/dist/wallet/confirm.js.map +1 -1
  65. package/dist/wallet/contract.d.ts.map +1 -1
  66. package/dist/wallet/contract.js +20 -4
  67. package/dist/wallet/contract.js.map +1 -1
  68. package/package.json +4 -4
  69. package/skills/bitrefill/SKILL.md +152 -52
  70. package/skills/flashnet-swaps/SKILL.md +158 -0
  71. package/skills/kaleido-lsps/SKILL.md +25 -8
  72. package/skills/kaleido-trading/SKILL.md +36 -12
  73. package/skills/merchant-finder/SKILL.md +1 -1
  74. package/skills/rgb-lightning-node/SKILL.md +35 -8
  75. package/skills/spark-wallet/SKILL.md +235 -0
  76. package/skills/wallet-assistant/SKILL.md +2 -2
  77. package/src/bitrefill/contract.test.ts +89 -0
  78. package/src/bitrefill/contract.ts +190 -0
  79. package/src/context/compress.test.ts +120 -0
  80. package/src/context/compress.ts +230 -0
  81. package/src/engine.test.ts +34 -0
  82. package/src/engine.ts +35 -4
  83. package/src/evidence.test.ts +80 -0
  84. package/src/evidence.ts +114 -0
  85. package/src/flashnet/contract.test.ts +101 -0
  86. package/src/flashnet/contract.ts +164 -0
  87. package/src/funnel.ts +59 -8
  88. package/src/index.ts +51 -1
  89. package/src/kaleidoswap/contract.ts +1 -1
  90. package/src/knowledge/bitcoin-copilot.ts +94 -0
  91. package/src/providers/types.ts +18 -0
  92. package/src/qvac/provider.ts +25 -1
  93. package/src/qvac/stream.test.ts +11 -0
  94. package/src/qvac/stream.ts +16 -0
  95. package/src/recipe/flashnet-swap.test.ts +114 -0
  96. package/src/recipe/flashnet-swap.ts +266 -0
  97. package/src/recipe/kaleidoswap-atomic.test.ts +21 -0
  98. package/src/recipe/kaleidoswap-atomic.ts +34 -16
  99. package/src/recipe/kaleidoswap-channel-order.test.ts +38 -0
  100. package/src/recipe/kaleidoswap-channel-order.ts +27 -9
  101. package/src/recipe/kaleidoswap-price.ts +7 -1
  102. package/src/recipe/recipe.test.ts +5 -0
  103. package/src/recipe/runner.ts +5 -3
  104. package/src/recipe/swap.ts +16 -1
  105. package/src/wallet/confirm.test.ts +8 -0
  106. package/src/wallet/confirm.ts +1 -0
  107. package/src/wallet/contract.test.ts +10 -0
  108. package/src/wallet/contract.ts +26 -4
@@ -95,10 +95,12 @@ export async function extractSlots(
95
95
  const system = [
96
96
  `Call ${EXTRACT_TOOL} with the fields from the user's message.`,
97
97
  recipe.description ? `This extraction is for: ${recipe.description}.` : '',
98
- 'Only emit values that match the field descriptions.',
98
+ 'Only emit values that match the field descriptions. Use the examples and phrasings listed in each field\'s description (including context like "on the other" when "my side" appears).',
99
99
  'Canonical assets: BTC, USDT, XAUT (pass as strings like "BTC" or "USDT").',
100
100
  'amount_side: "to" when the named amount is what you receive/buy (e.g. "buy 1 USDT" → to_asset=USDT, amount=1, from_asset=BTC); "from" for sell/swap (amount on from_asset).',
101
101
  'The host binding handles per-asset precision scaling (BTC in sats → maker units; USDT/XAUT whole units). Pass the user\'s number as-is for the correct side.',
102
+ 'If a value is ambiguous from the message, prefer the mapping from the field descriptions rather than guessing.',
103
+ 'For status-related follow-ups the history (or recall result) will contain explicit "order_id=... access_token=..." or "atomic_id=..." strings from prior summaries — when relevant extract them exactly.',
102
104
  'Do not call any other tool and do not add commentary.',
103
105
  ].filter(Boolean).join(' ');
104
106
 
@@ -175,10 +177,10 @@ export async function runRecipe(recipe: Recipe, text: string, opts: RunRecipeOpt
175
177
  if (recipe.confident && !recipe.confident(ctx.slots)) {
176
178
  const missing = recipe.slots
177
179
  .filter((s) => s.required && (ctx.slots[s.name] == null || ctx.slots[s.name] === ''))
178
- .map((s) => `${s.name} (${s.description})`);
180
+ .map((s) => s.name);
179
181
  const ask =
180
182
  missing.length > 0
181
- ? `I need a bit more info — please specify: ${missing.join('; ')}.`
183
+ ? `I need a bit more info — please specify the ${missing.join(' and ')} (rephrase with the numbers, or use recall if this is a follow-up status check).`
182
184
  : "I don't have enough info to do that — could you rephrase with the specifics?";
183
185
  return { recipe: recipe.name, slots: ctx.slots, results: ctx.results, text: ask, status: 'needs-info', inferences };
184
186
  }
@@ -12,7 +12,7 @@
12
12
 
13
13
  import type { Recipe } from './types.js';
14
14
 
15
- const ASSET = /\b(btc|bitcoin|sats?|usdt|tether|xaut|gold)\b/i;
15
+ const ASSET = /\b(btc|bitcoin|sats?|usdt|tether|xaut|gold|usdb)\b/i;
16
16
 
17
17
  /** Strict: returns a canonical code only for a KNOWN crypto asset, else undefined
18
18
  * (so "kaleido", "the", etc. are not mistaken for an asset). */
@@ -22,6 +22,7 @@ function knownAsset(a?: string): string | undefined {
22
22
  if (/^(btc|bitcoin|sat|sats|satoshi|satoshis)$/.test(x)) return 'BTC';
23
23
  if (/^(usdt|tether)$/.test(x)) return 'USDT';
24
24
  if (/^(xaut|gold)$/.test(x)) return 'XAUT';
25
+ if (/^usdb$/.test(x)) return 'USDB';
25
26
  return undefined;
26
27
  }
27
28
 
@@ -106,6 +107,20 @@ export function extractPriceQuery(text: string): Record<string, unknown> | null
106
107
  // Reject swap intent — those go to the atomic recipe, not the price recipe.
107
108
  if (/\b(swap|exchange|convert|trade|buy|sell|get|purchase|acquire)\b/i.test(t)) return null;
108
109
 
110
+ // Natural quantity quote: "how many sats is 10 USDT worth?" The amount is
111
+ // on the priced asset (TO leg); the requested denomination is the FROM leg.
112
+ const quantityWorth = t.match(
113
+ /\bhow\s+(?:many|much)\s+([a-z]+)\s+(?:is|are)\s+(\d[\d.,]*)\s+([a-z]+)\s+worth\b/i,
114
+ );
115
+ if (quantityWorth) {
116
+ const denom = knownAsset(quantityWorth[1]);
117
+ const amount = parseAmount(quantityWorth[2]);
118
+ const asset = knownAsset(quantityWorth[3]);
119
+ if (denom && asset && amount != null) {
120
+ return { amount, from_asset: denom, to_asset: asset, amount_side: 'to' };
121
+ }
122
+ }
123
+
109
124
  // ORDER MATTERS: "how much B for A" (first) must be checked BEFORE
110
125
  // "how much X (in Y)?" — otherwise the latter would gobble the first asset
111
126
  // and miss the "for/per" tail. Optional "the" article is tolerated
@@ -40,6 +40,14 @@ describe('confirmReadback', () => {
40
40
  expect(line).toBe('Pay Lightning invoice lnbc1p…abcd over RLN. Confirm?');
41
41
  });
42
42
 
43
+ it('spark_pay_invoice: same readback shape, over Spark', () => {
44
+ const line = confirmReadback({
45
+ name: 'spark_pay_invoice',
46
+ arguments: { invoice: 'lnbc1ptestinvoice0123456789abcd' },
47
+ });
48
+ expect(line).toBe('Pay Lightning invoice lnbc1p…abcd over Spark. Confirm?');
49
+ });
50
+
43
51
  it('execute_swap: from → to with amount', () => {
44
52
  expect(confirmReadback({ name: 'execute_swap', arguments: { from_asset: 'BTC', to_asset: 'USDT', amount: 0.01 } }))
45
53
  .toBe('Swap 0.01 BTC for USDT. Confirm?');
@@ -64,6 +64,7 @@ export function confirmReadback(call: { name: string; arguments: Record<string,
64
64
  case 'liquid_send':
65
65
  return ask(`Send ${asset(a.amount, a.asset)} to ${to()}${over(name, a)}`);
66
66
  case 'rln_pay_invoice':
67
+ case 'spark_pay_invoice':
67
68
  return ask(`Pay Lightning invoice ${shortRef(String(a.invoice ?? ''))}${over(name, a)}`);
68
69
  case 'execute_swap':
69
70
  return ask(`Swap ${fmtNum(Number(a.amount))} ${String(a.from_asset)} for ${String(a.to_asset)}`);
@@ -39,12 +39,22 @@ describe('WALLET_TOOLS contract', () => {
39
39
  expect(isSpendTool('rln_send_asset')).toBe(true);
40
40
  expect(isSpendTool('execute_swap')).toBe(true);
41
41
  expect(isSpendTool('spark_send')).toBe(true);
42
+ expect(isSpendTool('spark_pay_invoice')).toBe(true);
42
43
  // reads are not
43
44
  expect(isSpendTool('get_balances')).toBe(false);
44
45
  expect(isSpendTool('get_price')).toBe(false);
45
46
  expect([...SPEND_TOOLS].length).toBeGreaterThanOrEqual(5);
46
47
  });
47
48
 
49
+ it('spark_pay_invoice is its own tool — BOLT11-shaped, amount optional', () => {
50
+ const def = getWalletTool('spark_pay_invoice');
51
+ expect(def?.layer).toBe('spark');
52
+ expect(def?.spend).toBe(true);
53
+ expect((def!.parameters as any).required).toEqual(['invoice']);
54
+ expect((def!.parameters as any).properties.invoice.type).toBe('string');
55
+ expect((def!.parameters as any).properties.amount_sats.type).toBe('number');
56
+ });
57
+
48
58
  it('required args declared on the actionable tools', () => {
49
59
  expect((getWalletTool('send_payment')!.parameters as any).required).toContain('to');
50
60
  expect((getWalletTool('fiat_to_sats')!.parameters as any).required).toEqual(['amount', 'currency']);
@@ -56,10 +56,32 @@ const asset = { type: 'string', description: "Asset ticker, e.g. 'USDT', 'XAUT',
56
56
  /** The full contract. Keep descriptions terse — small models read every word. */
57
57
  export const WALLET_TOOLS: WalletToolDef[] = [
58
58
  // ── Spark ──────────────────────────────────────────────────────────────
59
- t('spark', 'spark_get_balance', 'Get the Spark wallet BTC balance.'),
60
- t('spark', 'spark_get_address', 'Get a Spark deposit address to receive BTC.'),
61
- t('spark', 'spark_create_invoice', 'Create a Spark Lightning invoice to receive BTC.', { amount_sats: sats }),
62
- t('spark', 'spark_send', 'Send BTC from Spark to an address or invoice.', { amount_sats: sats, to: { type: 'string', description: 'Address or invoice' } }, ['amount_sats', 'to'], true),
59
+ t('spark', 'spark_get_balance', 'Get the Spark wallet balances — BTC sats AND every Spark-native token (e.g. USDB). Returns `{ total: <sats>, tokens: [{ address, balance, symbol?, decimals?, available_to_send? }], connected, layer, network }`. Use for ANY "balance / how much / what do I have on Spark" question — call it fresh every time, balances change. The `tokens` array surfaces ALL Spark-native tokens the wallet holds, so you do NOT need to call flashnet_get_balance separately for that (flashnet_get_balance is the AMM-client view of the same wallet and returns the same numbers). For RGB asset balances (USDT, XAUT) use the RLN tools — RGB assets are NOT on Spark.'),
60
+ // The user-facing "Spark address" an off-chain Spark identity (sparkrt1…/
61
+ // spark1…). For OFF-CHAIN peer transfers WITHIN Spark. NOT a Bitcoin
62
+ // on-chain address. Use spark_get_onchain_address for the on-chain deposit
63
+ // path; use spark_create_invoice for a Lightning invoice.
64
+ t('spark', 'spark_get_address', 'Get the user\'s Spark address (sparkrt1…/spark1…) — an OFF-CHAIN Spark identity for receiving Spark-to-Spark transfers. NOT a Bitcoin on-chain address (does not start with bc1/tb1/bcrt1) and NOT a Lightning invoice. For "an on-chain address to deposit BTC into Spark" use spark_get_onchain_address. For a Lightning invoice use spark_create_invoice.'),
65
+ // Real on-chain Bitcoin address used to deposit BTC FROM mainnet INTO the
66
+ // Spark wallet. The SDK calls this a "static deposit address" — bc1…/tb1…/
67
+ // bcrt1…. The opposite of spark_get_address.
68
+ t('spark', 'spark_get_onchain_address', 'Get a real Bitcoin ON-CHAIN address (bc1…/tb1…/bcrt1…) for depositing BTC from the Bitcoin L1 into the Spark wallet. Use ANY time the user asks for "an on-chain address", "deposit address", "Bitcoin address to fund Spark", "where do I send my on-chain BTC". This is NOT the Spark identity (spark_get_address) and NOT a Lightning invoice (spark_create_invoice).'),
69
+ t('spark', 'spark_create_invoice', 'Create a Spark Lightning invoice (BOLT11) to receive BTC over Lightning. Returns an invoice string the user can share. Use when the user asks for "an invoice", "a lightning invoice", "pay me", or names an amount they want received. NOT an address.', { amount_sats: sats }),
70
+ // Explicit Lightning-invoice payer. BOLT11 invoices encode the amount, so
71
+ // `amount_sats` is optional and only used for amount-less ("any-amount")
72
+ // invoices. Prefer this over `spark_send` when the destination is a BOLT11
73
+ // invoice — it removes ambiguity for small models and gives the cross-skill
74
+ // bitrefill flow a single, unambiguous target.
75
+ t('spark', 'spark_pay_invoice',
76
+ 'Pay a Lightning (BOLT11) invoice from the Spark wallet. The invoice already encodes the amount; pass amount_sats ONLY for amount-less invoices. Use this for any BOLT11 destination (Bitrefill, contact, raw invoice).',
77
+ { invoice: { type: 'string', description: 'BOLT11 Lightning invoice (lnbc…/lntb…/lnbcrt…).' }, amount_sats: { type: 'number', description: 'Required ONLY when the invoice has no amount; omit otherwise.' } },
78
+ ['invoice'],
79
+ /* spend */ true),
80
+ t('spark', 'spark_send',
81
+ 'Send BTC from Spark to an on-chain address (bc1…/tb1…). For BOLT11 invoices, prefer spark_pay_invoice.',
82
+ { amount_sats: sats, to: { type: 'string', description: 'On-chain Bitcoin address.' } },
83
+ ['amount_sats', 'to'],
84
+ /* spend */ true),
63
85
 
64
86
  // ── RLN / RGB ──────────────────────────────────────────────────────────
65
87
  t('rln', 'rln_get_balances', 'Get RLN node balances (BTC + RGB assets).'),