@kaleidorg/mind 0.4.0 → 0.5.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.
Files changed (79) hide show
  1. package/dist/funnel.d.ts +19 -0
  2. package/dist/funnel.d.ts.map +1 -1
  3. package/dist/funnel.js +48 -10
  4. package/dist/funnel.js.map +1 -1
  5. package/dist/index.d.ts +5 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +10 -3
  8. package/dist/index.js.map +1 -1
  9. package/dist/kaleidoswap/contract.d.ts +3 -3
  10. package/dist/kaleidoswap/contract.d.ts.map +1 -1
  11. package/dist/kaleidoswap/contract.js +16 -4
  12. package/dist/kaleidoswap/contract.js.map +1 -1
  13. package/dist/knowledge/bitcoin-copilot.d.ts.map +1 -1
  14. package/dist/knowledge/bitcoin-copilot.js +102 -0
  15. package/dist/knowledge/bitcoin-copilot.js.map +1 -1
  16. package/dist/knowledge/btc-map.d.ts +14 -17
  17. package/dist/knowledge/btc-map.d.ts.map +1 -1
  18. package/dist/knowledge/btc-map.js +66 -266
  19. package/dist/knowledge/btc-map.js.map +1 -1
  20. package/dist/lsps1/contract.d.ts.map +1 -1
  21. package/dist/lsps1/contract.js +28 -10
  22. package/dist/lsps1/contract.js.map +1 -1
  23. package/dist/recipe/buy-asset-channel.d.ts +26 -0
  24. package/dist/recipe/buy-asset-channel.d.ts.map +1 -0
  25. package/dist/recipe/buy-asset-channel.js +112 -0
  26. package/dist/recipe/buy-asset-channel.js.map +1 -0
  27. package/dist/recipe/kaleidoswap-atomic.d.ts +26 -18
  28. package/dist/recipe/kaleidoswap-atomic.d.ts.map +1 -1
  29. package/dist/recipe/kaleidoswap-atomic.js +101 -63
  30. package/dist/recipe/kaleidoswap-atomic.js.map +1 -1
  31. package/dist/recipe/kaleidoswap-channel-order.d.ts +35 -0
  32. package/dist/recipe/kaleidoswap-channel-order.d.ts.map +1 -0
  33. package/dist/recipe/kaleidoswap-channel-order.js +493 -0
  34. package/dist/recipe/kaleidoswap-channel-order.js.map +1 -0
  35. package/dist/recipe/kaleidoswap-price.d.ts +21 -0
  36. package/dist/recipe/kaleidoswap-price.d.ts.map +1 -0
  37. package/dist/recipe/kaleidoswap-price.js +57 -0
  38. package/dist/recipe/kaleidoswap-price.js.map +1 -0
  39. package/dist/recipe/runner.d.ts +7 -1
  40. package/dist/recipe/runner.d.ts.map +1 -1
  41. package/dist/recipe/runner.js +115 -29
  42. package/dist/recipe/runner.js.map +1 -1
  43. package/dist/recipe/swap.d.ts +26 -1
  44. package/dist/recipe/swap.d.ts.map +1 -1
  45. package/dist/recipe/swap.js +108 -13
  46. package/dist/recipe/swap.js.map +1 -1
  47. package/dist/recipe/types.d.ts +25 -1
  48. package/dist/recipe/types.d.ts.map +1 -1
  49. package/dist/skills/registry.d.ts +33 -1
  50. package/dist/skills/registry.d.ts.map +1 -1
  51. package/dist/skills/registry.js +45 -1
  52. package/dist/skills/registry.js.map +1 -1
  53. package/package.json +1 -1
  54. package/skills/README.md +3 -0
  55. package/skills/kaleido-lsps/SKILL.md +101 -43
  56. package/skills/kaleido-trading/SKILL.md +81 -31
  57. package/skills/merchant-finder/SKILL.md +96 -66
  58. package/skills/rgb-lightning-node/SKILL.md +108 -0
  59. package/skills/wallet-assistant/SKILL.md +32 -21
  60. package/src/funnel.ts +66 -11
  61. package/src/index.ts +14 -2
  62. package/src/kaleidoswap/contract.test.ts +7 -2
  63. package/src/kaleidoswap/contract.ts +27 -5
  64. package/src/knowledge/bitcoin-copilot.ts +111 -0
  65. package/src/knowledge/btc-map.test.ts +53 -96
  66. package/src/knowledge/btc-map.ts +72 -287
  67. package/src/lsps1/contract.ts +32 -14
  68. package/src/recipe/buy-asset-channel.test.ts +148 -0
  69. package/src/recipe/buy-asset-channel.ts +118 -0
  70. package/src/recipe/kaleidoswap-atomic.test.ts +134 -61
  71. package/src/recipe/kaleidoswap-atomic.ts +112 -66
  72. package/src/recipe/kaleidoswap-channel-order.test.ts +333 -0
  73. package/src/recipe/kaleidoswap-channel-order.ts +548 -0
  74. package/src/recipe/kaleidoswap-price.ts +68 -0
  75. package/src/recipe/recipe.test.ts +61 -5
  76. package/src/recipe/runner.ts +128 -31
  77. package/src/recipe/swap.ts +109 -13
  78. package/src/recipe/types.ts +25 -1
  79. package/src/skills/registry.ts +52 -1
@@ -8,24 +8,81 @@ const EXTRACT_TOOL = 'extract_request';
8
8
  /** Extract the recipe's slots — deterministic regex first, else ONE LLM call. */
9
9
  export async function extractSlots(provider, recipe, text) {
10
10
  const det = recipe.extract?.(text);
11
- if (det && Object.values(det).some((v) => v !== undefined && v !== null && v !== '')) {
11
+ const detValid = det && Object.values(det).some((v) => v !== undefined && v !== null && v !== '');
12
+ if (detValid && !recipe.forceModelExtract) {
12
13
  return { slots: det, inferences: 0 };
13
14
  }
15
+ // Build a richer extraction prompt + tool schema so small models have a
16
+ // better chance of producing correct structured output for recipes (especially
17
+ // when forceModelExtract is on for natural language intents like "buy 1 usdt").
14
18
  const properties = {};
15
19
  for (const s of recipe.slots)
16
20
  properties[s.name] = { type: s.type ?? 'string', description: s.description };
21
+ const recipeHint = recipe.description ? ` for the "${recipe.name}" recipe (${recipe.description})` : '';
17
22
  const extractTool = {
18
23
  name: EXTRACT_TOOL,
19
- description: `Extract the fields from the user's request.`,
24
+ description: `Extract the fields from the user's request${recipeHint}.`,
20
25
  parameters: { type: 'object', properties, required: recipe.slots.filter((s) => s.required).map((s) => s.name) },
21
26
  };
27
+ const system = [
28
+ `Call ${EXTRACT_TOOL} with the fields from the user's message.`,
29
+ recipe.description ? `This extraction is for: ${recipe.description}.` : '',
30
+ 'Only emit values that match the field descriptions.',
31
+ 'Canonical assets: BTC, USDT, XAUT (pass as strings like "BTC" or "USDT").',
32
+ '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).',
33
+ '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.',
34
+ 'Do not call any other tool and do not add commentary.',
35
+ ].filter(Boolean).join(' ');
22
36
  const out = await provider.runTurn({
23
- system: `Call ${EXTRACT_TOOL} with the fields from the user's message. Do not call any other tool and do not add commentary.`,
37
+ system,
24
38
  messages: [{ role: 'user', content: text }],
25
39
  tools: [extractTool],
26
40
  });
27
41
  const call = out.toolCalls?.find((c) => c.name === EXTRACT_TOOL) ?? out.toolCalls?.[0];
28
- return { slots: call?.arguments ?? {}, inferences: 1 };
42
+ let llmSlots = call?.arguments ?? {};
43
+ // Safety net when forceModelExtract is active.
44
+ // - The LLM is authoritative for the slots it filled — its output wins.
45
+ // - Det is used only to backfill required fields the LLM left empty.
46
+ // - The amount_side-specific check below applies ONLY to recipes that
47
+ // actually declare an `amount_side` slot (swap-shaped recipes) — for
48
+ // others (channel-order, etc.) it would clobber correct LLM extraction
49
+ // because amount_side is always undefined.
50
+ if (recipe.forceModelExtract && detValid) {
51
+ const required = recipe.slots.filter((s) => s.required);
52
+ const llmHasAllRequired = required.every((s) => {
53
+ const v = llmSlots[s.name];
54
+ return v != null && v !== '';
55
+ });
56
+ const recipeHasAmountSide = recipe.slots.some((s) => s.name === 'amount_side');
57
+ if (recipeHasAmountSide) {
58
+ const llmSide = String(llmSlots.amount_side || '').toLowerCase();
59
+ const validSide = llmSide === 'from' || llmSide === 'to';
60
+ if (!llmHasAllRequired || !validSide) {
61
+ llmSlots = { ...det, ...llmSlots };
62
+ }
63
+ else {
64
+ llmSlots.amount_side = llmSide;
65
+ }
66
+ if (!validSide && det.amount_side) {
67
+ llmSlots.amount_side = det.amount_side;
68
+ }
69
+ }
70
+ else {
71
+ // Generic path: backfill ANY slot the LLM didn't populate from det's
72
+ // value, when det has one. LLM wins on every field it actually filled,
73
+ // but det shouldn't be silently erased — small models often omit
74
+ // non-required slots (e.g. asset_ticker on a USDT channel) that the
75
+ // deterministic regex caught reliably.
76
+ for (const s of recipe.slots) {
77
+ const llmVal = llmSlots[s.name];
78
+ const detVal = det[s.name];
79
+ if ((llmVal == null || llmVal === '') && detVal != null && detVal !== '') {
80
+ llmSlots[s.name] = detVal;
81
+ }
82
+ }
83
+ }
84
+ }
85
+ return { slots: llmSlots, inferences: 1 };
29
86
  }
30
87
  /** Run a recipe end to end. Never throws — failures come back as status:'error'. */
31
88
  export async function runRecipe(recipe, text, opts) {
@@ -37,40 +94,69 @@ export async function runRecipe(recipe, text, opts) {
37
94
  ctx.slots = ex.slots;
38
95
  inferences = ex.inferences;
39
96
  }
40
- // Deterministic steps. Intermediate spend tools fire the same confirmation
41
- // gate as the final step recipes with multi-spend chains (e.g. atomic
42
- // swaps) MUST have every money-moving call gated, never just the last one.
43
- // Missing onConfirm fails closed, matching the Engine.
97
+ // Confidence re-check AFTER extraction (whether deterministic, LLM, or
98
+ // pre-supplied). When the recipe defines `confident()` and the extracted
99
+ // slots fail it, refuse to run the steps with bad data — surface a
100
+ // friendly "please specify <missing required slots>" message so the user
101
+ // can re-ask with the info instead of getting a maker 4xx mid-chain.
102
+ if (recipe.confident && !recipe.confident(ctx.slots)) {
103
+ const missing = recipe.slots
104
+ .filter((s) => s.required && (ctx.slots[s.name] == null || ctx.slots[s.name] === ''))
105
+ .map((s) => `${s.name} (${s.description})`);
106
+ const ask = missing.length > 0
107
+ ? `I need a bit more info — please specify: ${missing.join('; ')}.`
108
+ : "I don't have enough info to do that — could you rephrase with the specifics?";
109
+ return { recipe: recipe.name, slots: ctx.slots, results: ctx.results, text: ask, status: 'needs-info', inferences };
110
+ }
111
+ // Confirmation model:
112
+ // - Recipe with `confirm(ctx)`: fire ONE gate before the first spend step,
113
+ // showing the recipe-level summary; once approved, later spend steps run
114
+ // ungated (the whole chain is one approved decision).
115
+ // - Recipe without `confirm`: gate EACH spend tool individually (default;
116
+ // payments/receive/asset-send rely on this).
117
+ // Missing onConfirm FAILS CLOSED in both cases, matching the Engine.
118
+ const cancelled = () => ({
119
+ recipe: recipe.name, slots: ctx.slots, results: ctx.results,
120
+ text: 'Cancelled — nothing was sent.', status: 'cancelled', inferences,
121
+ });
122
+ let recipeApproved = false;
123
+ /** Gate a single (spend) step. Returns false if the user declined. */
124
+ const passesGate = async (toolName, args) => {
125
+ const def = await opts.tools.getDef(toolName);
126
+ if (!def?.requiresConfirmation)
127
+ return true;
128
+ // Recipe-level single confirm: ask once, then remember the approval.
129
+ if (recipe.confirm) {
130
+ if (recipeApproved)
131
+ return true;
132
+ const summary = recipe.confirm(ctx) ?? undefined;
133
+ const decision = opts.onConfirm
134
+ ? await opts.onConfirm({ name: toolName, arguments: args, summary })
135
+ : { approved: false, reason: 'no confirmation handler available' };
136
+ if (decision.approved)
137
+ recipeApproved = true;
138
+ return decision.approved;
139
+ }
140
+ // Per-tool confirm (legacy default).
141
+ const decision = opts.onConfirm
142
+ ? await opts.onConfirm({ name: toolName, arguments: args })
143
+ : { approved: false, reason: 'no confirmation handler available' };
144
+ return decision.approved;
145
+ };
44
146
  for (const step of recipe.steps) {
45
147
  if (step.skipIf?.(ctx))
46
148
  continue;
47
149
  const args = step.args(ctx);
48
- const def = await opts.tools.getDef(step.tool);
49
- if (def?.requiresConfirmation) {
50
- const decision = opts.onConfirm
51
- ? await opts.onConfirm({ name: step.tool, arguments: args })
52
- : { approved: false, reason: 'no confirmation handler available' };
53
- if (!decision.approved) {
54
- return { recipe: recipe.name, slots: ctx.slots, results: ctx.results, text: 'Cancelled — nothing was sent.', status: 'cancelled', inferences };
55
- }
56
- }
150
+ if (!(await passesGate(step.tool, args)))
151
+ return cancelled();
57
152
  const result = await opts.tools.execute(step.tool, args);
58
153
  ctx.results[step.as ?? step.tool] = result;
59
154
  opts.onStep?.(step.tool, args, result);
60
155
  }
61
- // Final action — confirmation-gated if the tool requires it. Like the
62
- // Engine, a missing onConfirm FAILS CLOSED: the spend is declined, never
63
- // silently executed.
156
+ // Final action.
64
157
  const finalArgs = recipe.final.args(ctx);
65
- const def = await opts.tools.getDef(recipe.final.tool);
66
- if (def?.requiresConfirmation) {
67
- const decision = opts.onConfirm
68
- ? await opts.onConfirm({ name: recipe.final.tool, arguments: finalArgs })
69
- : { approved: false, reason: 'no confirmation handler available' };
70
- if (!decision.approved) {
71
- return { recipe: recipe.name, slots: ctx.slots, results: ctx.results, text: 'Cancelled — nothing was sent.', status: 'cancelled', inferences };
72
- }
73
- }
158
+ if (!(await passesGate(recipe.final.tool, finalArgs)))
159
+ return cancelled();
74
160
  const finalResult = await opts.tools.execute(recipe.final.tool, finalArgs);
75
161
  ctx.results[recipe.final.as ?? recipe.final.tool] = finalResult;
76
162
  opts.onStep?.(recipe.final.tool, finalArgs, finalResult);
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/recipe/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/recipe/runner.ts"],"names":[],"mappings":"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"}
@@ -10,7 +10,32 @@
10
10
  * confirmation gate fires before it runs.
11
11
  */
12
12
  import type { Recipe } from './types.js';
13
- /** "buy 0.001 btc with usdt" / "swap 10 usdt for btc" / "sell 100 usdt for sats". */
13
+ /**
14
+ * Parse a swap/buy/sell request into { from_asset, to_asset, amount, amount_side }.
15
+ *
16
+ * `amount_side` says which leg the amount belongs to (the maker takes the amount
17
+ * on exactly one leg):
18
+ * - "buy N X" → receive N of X → amount on the TO leg, from defaults to BTC
19
+ * - "sell N X" → spend N of X → amount on the FROM leg, to defaults to BTC
20
+ * - "swap N X to Y" → spend N of X → amount on the FROM leg
21
+ *
22
+ * "buy one usdt" → from BTC, to USDT, amount 1 on `to`
23
+ * "buy 0.001 btc with usdt" → from USDT, to BTC, amount 0.001 on `to`
24
+ * "sell 100 usdt" → from USDT, to BTC, amount 100 on `from`
25
+ * "swap 10 usdt for btc" → from USDT, to BTC, amount 10 on `from`
26
+ */
14
27
  export declare function extractSwap(text: string): Record<string, unknown> | null;
28
+ /**
29
+ * Parse a PRICE / rate / "how much" question — read-only intent.
30
+ *
31
+ * Distinct from extractSwap: never returns slots for swap/buy/sell phrasings.
32
+ * Always `amount: 1` on the asked-about asset (TO leg). Used by
33
+ * `kaleidoswapPriceRecipe` to fire a quote without moving funds.
34
+ *
35
+ * "what is the price of usdt in sats" → {from: BTC, to: USDT, amount: 1, side: 'to'}
36
+ * "btc price" → {from: USDT, to: BTC, amount: 1, side: 'to'}
37
+ * "how much sats for 1 usdt" → {from: BTC, to: USDT, amount: 1, side: 'to'}
38
+ */
39
+ export declare function extractPriceQuery(text: string): Record<string, unknown> | null;
15
40
  export declare const swapRecipe: Recipe;
16
41
  //# sourceMappingURL=swap.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"swap.d.ts","sourceRoot":"","sources":["../../src/recipe/swap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAczC,qFAAqF;AACrF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAYxE;AAED,eAAO,MAAM,UAAU,EAAE,MAgCxB,CAAC"}
1
+ {"version":3,"file":"swap.d.ts","sourceRoot":"","sources":["../../src/recipe/swap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA8BzC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAkCxE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAgC9E;AAED,eAAO,MAAM,UAAU,EAAE,MAgCxB,CAAC"}
@@ -10,33 +10,128 @@
10
10
  * confirmation gate fires before it runs.
11
11
  */
12
12
  const ASSET = /\b(btc|bitcoin|sats?|usdt|tether|xaut|gold)\b/i;
13
- function normAsset(a) {
13
+ /** Strict: returns a canonical code only for a KNOWN crypto asset, else undefined
14
+ * (so "kaleido", "the", etc. are not mistaken for an asset). */
15
+ function knownAsset(a) {
14
16
  if (!a)
15
17
  return undefined;
16
18
  const x = a.toLowerCase();
17
- if (/btc|bitcoin|sat/.test(x))
19
+ if (/^(btc|bitcoin|sat|sats|satoshi|satoshis)$/.test(x))
18
20
  return 'BTC';
19
- if (/usdt|tether/.test(x))
21
+ if (/^(usdt|tether)$/.test(x))
20
22
  return 'USDT';
21
- if (/xaut|gold/.test(x))
23
+ if (/^(xaut|gold)$/.test(x))
22
24
  return 'XAUT';
23
- return a.toUpperCase();
25
+ return undefined;
24
26
  }
25
- const num = (s) => (s ? Number(s.replace(/,/g, '')) : undefined);
26
- /** "buy 0.001 btc with usdt" / "swap 10 usdt for btc" / "sell 100 usdt for sats". */
27
+ // Small word-numbers cover the common spoken/typed cases ("buy one usdt").
28
+ const WORD_NUM = {
29
+ a: 1, an: 1, one: 1, two: 2, three: 3, four: 4, five: 5,
30
+ six: 6, seven: 7, eight: 8, nine: 9, ten: 10,
31
+ };
32
+ const AMT = '([\\d.,]+|a|an|one|two|three|four|five|six|seven|eight|nine|ten)';
33
+ function parseAmount(s) {
34
+ if (!s)
35
+ return undefined;
36
+ const t = s.trim().toLowerCase();
37
+ if (t in WORD_NUM)
38
+ return WORD_NUM[t];
39
+ const n = Number(t.replace(/,/g, ''));
40
+ return Number.isFinite(n) ? n : undefined;
41
+ }
42
+ /**
43
+ * Parse a swap/buy/sell request into { from_asset, to_asset, amount, amount_side }.
44
+ *
45
+ * `amount_side` says which leg the amount belongs to (the maker takes the amount
46
+ * on exactly one leg):
47
+ * - "buy N X" → receive N of X → amount on the TO leg, from defaults to BTC
48
+ * - "sell N X" → spend N of X → amount on the FROM leg, to defaults to BTC
49
+ * - "swap N X to Y" → spend N of X → amount on the FROM leg
50
+ *
51
+ * "buy one usdt" → from BTC, to USDT, amount 1 on `to`
52
+ * "buy 0.001 btc with usdt" → from USDT, to BTC, amount 0.001 on `to`
53
+ * "sell 100 usdt" → from USDT, to BTC, amount 100 on `from`
54
+ * "swap 10 usdt for btc" → from USDT, to BTC, amount 10 on `from`
55
+ */
27
56
  export function extractSwap(text) {
28
57
  const t = text.trim();
29
58
  let m;
30
- // buy <amt> <to> with/using <from> (amount is of the asset being bought)
31
- if ((m = t.match(/buy\s+([\d.,]+)\s*([a-z]+)\s+(?:with|using|for)\s+([a-z]+)/i))) {
32
- return { amount: num(m[1]), to_asset: normAsset(m[2]), from_asset: normAsset(m[3]) };
59
+ // buy/get/purchase <amt> <asset> [with/using/from <funding-asset>]
60
+ // amount is of the asset being BOUGHT → it sits on the TO leg.
61
+ if ((m = t.match(new RegExp(`\\b(?:buy|get|purchase|acquire)\\s+${AMT}\\s*([a-z]+)(?:\\s+(?:with|using|from|for)\\s+([a-z]+))?`, 'i')))) {
62
+ const to = knownAsset(m[2]);
63
+ if (to) {
64
+ const from = knownAsset(m[3]) ?? (to === 'BTC' ? 'USDT' : 'BTC');
65
+ return { amount: parseAmount(m[1]), from_asset: from, to_asset: to, amount_side: 'to' };
66
+ }
67
+ }
68
+ // sell <amt> <asset> [for/to/into <target>]
69
+ // amount is of the asset being SOLD → it sits on the FROM leg.
70
+ if ((m = t.match(new RegExp(`\\bsell\\s+${AMT}\\s*([a-z]+)(?:\\s+(?:for|to|into)\\s+([a-z]+))?`, 'i')))) {
71
+ const from = knownAsset(m[2]);
72
+ if (from) {
73
+ const to = knownAsset(m[3]) ?? (from === 'BTC' ? 'USDT' : 'BTC');
74
+ return { amount: parseAmount(m[1]), from_asset: from, to_asset: to, amount_side: 'from' };
75
+ }
33
76
  }
34
- // swap/sell/convert/exchange/trade <amt> <from> for/to/into <to>
35
- if ((m = t.match(/(?:swap|sell|convert|exchange|trade)\s+([\d.,]+)\s*([a-z]+)\s+(?:for|to|into)\s+([a-z]+)/i))) {
36
- return { amount: num(m[1]), from_asset: normAsset(m[2]), to_asset: normAsset(m[3]) };
77
+ // swap/convert/exchange/trade <amt> <from> for/to/into <to>
78
+ if ((m = t.match(new RegExp(`\\b(?:swap|convert|exchange|trade)\\s+${AMT}\\s*([a-z]+)\\s+(?:for|to|into)\\s+([a-z]+)`, 'i')))) {
79
+ const from = knownAsset(m[2]);
80
+ const to = knownAsset(m[3]);
81
+ if (from && to)
82
+ return { amount: parseAmount(m[1]), from_asset: from, to_asset: to, amount_side: 'from' };
37
83
  }
84
+ // Price/rate questions are NOT swaps — they belong to extractPriceQuery +
85
+ // kaleidoswapPriceRecipe (read-only). Don't gobble them here.
38
86
  return null;
39
87
  }
88
+ /**
89
+ * Parse a PRICE / rate / "how much" question — read-only intent.
90
+ *
91
+ * Distinct from extractSwap: never returns slots for swap/buy/sell phrasings.
92
+ * Always `amount: 1` on the asked-about asset (TO leg). Used by
93
+ * `kaleidoswapPriceRecipe` to fire a quote without moving funds.
94
+ *
95
+ * "what is the price of usdt in sats" → {from: BTC, to: USDT, amount: 1, side: 'to'}
96
+ * "btc price" → {from: USDT, to: BTC, amount: 1, side: 'to'}
97
+ * "how much sats for 1 usdt" → {from: BTC, to: USDT, amount: 1, side: 'to'}
98
+ */
99
+ export function extractPriceQuery(text) {
100
+ const t = text.trim();
101
+ // Reject swap intent — those go to the atomic recipe, not the price recipe.
102
+ if (/\b(swap|exchange|convert|trade|buy|sell|get|purchase|acquire)\b/i.test(t))
103
+ return null;
104
+ // ORDER MATTERS: "how much B for A" (first) must be checked BEFORE
105
+ // "how much X (in Y)?" — otherwise the latter would gobble the first asset
106
+ // and miss the "for/per" tail. Optional "the" article is tolerated
107
+ // ("price of THE usdt") — natural English the maker doesn't care about.
108
+ const priceLike = t.match(/\bhow\s+(?:many|much)\s+(?:the\s+)?([a-z]+)\s+(?:for|per|in)\s+(?:1\s+|one\s+|the\s+)?([a-z]+)\b/i) ||
109
+ t.match(/\b(?:price|cost|worth)\s+of\s+(?:the\s+)?([a-z]+)(?:\s+in\s+(?:the\s+)?([a-z]+))?/i) ||
110
+ t.match(/\b(?:the\s+)?([a-z]+)\s+(?:price|cost)\b/i) ||
111
+ t.match(/\brate\s+of\s+(?:the\s+)?([a-z]+)(?:\s+(?:in|to|vs)\s+(?:the\s+)?([a-z]+))?/i) ||
112
+ t.match(/\b(?:the\s+)?([a-z]+)\s+(?:to|vs|in|\/)\s+([a-z]+)\s+rate\b/i) ||
113
+ t.match(/\bhow\s+much\s+(?:does\s+)?(?:1\s+|one\s+|the\s+)?([a-z]+)\s+cost\b/i) ||
114
+ t.match(/\bhow\s+much\s+(?:is\s+)?(?:1\s+|one\s+|the\s+)?([a-z]+)(?:\s+in\s+(?:the\s+)?([a-z]+))?\b/i);
115
+ if (!priceLike)
116
+ return null;
117
+ const a = knownAsset(priceLike[1]);
118
+ const b = knownAsset(priceLike[2]);
119
+ let asset;
120
+ let denom;
121
+ if (/how\s+(?:many|much)\s+\w+\s+(?:for|per|in)/i.test(t) && b) {
122
+ // "how much B for A" — asset is A (the named priced one), denom is B (unit).
123
+ asset = b;
124
+ denom = a;
125
+ }
126
+ else {
127
+ asset = a;
128
+ denom = b;
129
+ }
130
+ if (!asset)
131
+ return null;
132
+ const from = denom ?? (asset === 'BTC' ? 'USDT' : 'BTC');
133
+ return { amount: 1, from_asset: from, to_asset: asset, amount_side: 'to' };
134
+ }
40
135
  export const swapRecipe = {
41
136
  name: 'swap',
42
137
  description: 'Swap between BTC and an RGB asset — quote, then execute (with confirmation).',
@@ -1 +1 @@
1
- {"version":3,"file":"swap.js","sourceRoot":"","sources":["../../src/recipe/swap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"swap.js","sourceRoot":"","sources":["../../src/recipe/swap.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,14 @@ export interface Recipe {
43
43
  slots: RecipeSlot[];
44
44
  /** Optional deterministic extractor tried BEFORE the LLM (Tier-0 fast-path). */
45
45
  extract?: (text: string) => Record<string, unknown> | null;
46
+ /**
47
+ * When true (and `extract` is provided), the runner will *ignore* a successful
48
+ * deterministic extraction and always perform the 1-inference LLM slot
49
+ * extraction. This lets the model do the natural-language understanding of
50
+ * the user's request (e.g. "buy 1 usdt") while the Recipe still owns the
51
+ * reliable multi-step execution plan and single-confirmation safety.
52
+ */
53
+ forceModelExtract?: boolean;
46
54
  /**
47
55
  * Whether the recipe is confident enough to RUN deterministically given the
48
56
  * extracted slots (vs falling back to the agentic loop). e.g. payments needs a
@@ -55,8 +63,24 @@ export interface Recipe {
55
63
  final: RecipeStep;
56
64
  /** Render the outcome for the user. */
57
65
  summary?: (ctx: RecipeContext, finalResult: unknown) => string;
66
+ /**
67
+ * Single recipe-level confirmation. When set, the runner fires exactly ONE
68
+ * confirmation gate immediately before the first spend step, passing the
69
+ * returned string as the confirm summary; once approved, the remaining spend
70
+ * steps run WITHOUT re-prompting (the whole chain is one approved decision).
71
+ *
72
+ * Use for multi-spend chains where the user makes a single choice up front
73
+ * from data gathered by earlier (read-only) steps — e.g. an atomic swap:
74
+ * quote first, then confirm "swap X → Y, fee Z" once, then init/whitelist/
75
+ * execute run as a unit.
76
+ *
77
+ * Return `null` to skip confirmation entirely (rare). When `confirm` is
78
+ * absent, the runner falls back to gating EACH spend tool individually
79
+ * (the default — used by payments/receive/asset-send).
80
+ */
81
+ confirm?: (ctx: RecipeContext) => string | null;
58
82
  }
59
- export type RecipeStatus = 'done' | 'cancelled' | 'error';
83
+ export type RecipeStatus = 'done' | 'cancelled' | 'error' | 'needs-info';
60
84
  export interface RecipeResult {
61
85
  recipe: string;
62
86
  slots: Record<string, unknown>;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/recipe/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,6DAA6D;IAC7D,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3D;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IACxD,sEAAsE;IACtE,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,8EAA8E;IAC9E,KAAK,EAAE,UAAU,CAAC;IAClB,uCAAuC;IACvC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,KAAK,MAAM,CAAC;CAChE;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/recipe/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,IAAI,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtD,gEAAgE;IAChE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uEAAuE;IACvE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;CAC1C;AAED,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,6DAA6D;IAC7D,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,gFAAgF;IAChF,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC3D;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC;IACxD,sEAAsE;IACtE,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,8EAA8E;IAC9E,KAAK,EAAE,UAAU,CAAC;IAClB,uCAAuC;IACvC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,EAAE,WAAW,EAAE,OAAO,KAAK,MAAM,CAAC;IAC/D;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,MAAM,GAAG,IAAI,CAAC;CACjD;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,GAAG,YAAY,CAAC;AAEzE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -6,11 +6,43 @@
6
6
  * call); a host can inject a model-driven or embedding selector instead.
7
7
  */
8
8
  import type { Skill, SkillReference, SkillSelector } from './types.js';
9
+ import type { EmbeddingProvider } from '../rag/types.js';
9
10
  /** Tool name the reference source exposes for progressive disclosure. */
10
11
  export declare const READ_REFERENCE_TOOL = "read_skill_reference";
11
12
  export declare function parseSkill(markdown: string, references?: SkillReference[]): Skill;
12
- /** Default selector: score by meaningful keyword overlap; triggers weigh most. */
13
+ /** Default selector: score by meaningful keyword overlap; triggers weigh most.
14
+ * Light extra sensitivity for common location / discovery phrasing so merchant-finder
15
+ * and similar skills surface on natural queries even without exact trigger words.
16
+ */
13
17
  export declare const keywordSelector: SkillSelector;
18
+ /**
19
+ * Optional embedding-powered selector factory.
20
+ *
21
+ * When an EmbeddingProvider (the same shape used by Retriever/RAG) is supplied,
22
+ * hosts can use the returned selector for more semantic skill routing. This
23
+ * helps vague/natural location and discovery queries ("coffee near the station",
24
+ * "somewhere to grab a bite that takes lightning") reach merchant-finder or
25
+ * similar skills even without exact keyword overlap.
26
+ *
27
+ * The current implementation keeps a synchronous SkillSelector contract (to match
28
+ * the existing interface used by Funnel and SkillRegistry). It therefore:
29
+ * - Uses an enhanced keywordSelector as the fast path (see above).
30
+ * - If embeddings are provided it is ready for hosts to wrap or evolve into a
31
+ * fully semantic version (prototype embeddings of skill descriptions +
32
+ * cosine vs. query, mixed with keyword score).
33
+ *
34
+ * Example host usage (CLI / provider with embeddings already loaded):
35
+ * import { createEmbeddingSkillSelector, SkillRegistry } from '@kaleidorg/mind';
36
+ * const selector = createEmbeddingSkillSelector(embeddingsProvider);
37
+ * const reg = new SkillRegistry(loadedSkills, selector);
38
+ *
39
+ * For a production semantic version a host can implement an async select
40
+ * wrapper around its own Funnel turn or pre-compute skill prototypes.
41
+ */
42
+ export declare function createEmbeddingSkillSelector(embeddings?: EmbeddingProvider, _opts?: {
43
+ minCosine?: number;
44
+ keywordFallback?: boolean;
45
+ }): SkillSelector;
14
46
  export declare class SkillRegistry {
15
47
  private readonly skills;
16
48
  private readonly selector;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEvE,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAuB1D,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,KAAK,CAkCjF;AA0BD,kFAAkF;AAClF,eAAO,MAAM,eAAe,EAAE,aAyB7B,CAAC;AAEF,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAE7B,MAAM,GAAE,KAAK,EAAO,EAAE,QAAQ,GAAE,aAA+B;IAK3E,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAKvB,uEAAuE;IACvE,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI;IAIlE,yEAAyE;IACzE,UAAU,IAAI,KAAK,CAAC,cAAc,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAMvD,yEAAyE;IACzE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAUnE,IAAI,IAAI,KAAK,EAAE;IAIf,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIpC,8DAA8D;IAC9D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAInC;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;CAwBxF"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAGzD,yEAAyE;AACzE,eAAO,MAAM,mBAAmB,yBAAyB,CAAC;AAuB1D,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,KAAK,CAkCjF;AA0BD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,aAkC7B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,CAAC,EAAE,iBAAiB,EAC9B,KAAK,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,OAAO,CAAA;CAAO,GAC5D,aAAa,CAQf;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;gBAE7B,MAAM,GAAE,KAAK,EAAO,EAAE,QAAQ,GAAE,aAA+B;IAK3E,GAAG,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAKvB,uEAAuE;IACvE,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,cAAc,EAAE,GAAG,IAAI;IAIlE,yEAAyE;IACzE,UAAU,IAAI,KAAK,CAAC,cAAc,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAMvD,yEAAyE;IACzE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAUnE,IAAI,IAAI,KAAK,EAAE;IAIf,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIpC,8DAA8D;IAC9D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAInC;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;KAAE;CAwBxF"}
@@ -84,7 +84,10 @@ function triggerMatches(query, trigger) {
84
84
  return false;
85
85
  return new RegExp(`\\b${reEscape(t)}\\b`).test(query);
86
86
  }
87
- /** Default selector: score by meaningful keyword overlap; triggers weigh most. */
87
+ /** Default selector: score by meaningful keyword overlap; triggers weigh most.
88
+ * Light extra sensitivity for common location / discovery phrasing so merchant-finder
89
+ * and similar skills surface on natural queries even without exact trigger words.
90
+ */
88
91
  export const keywordSelector = {
89
92
  select(query, skills) {
90
93
  const q = query.toLowerCase();
@@ -104,6 +107,14 @@ export const keywordSelector = {
104
107
  for (const t of skill.triggers ?? [])
105
108
  if (triggerMatches(q, t))
106
109
  score += 3;
110
+ // Light discovery / location phrase boost (helps merchant-finder and
111
+ // similar skills on natural language like "coffee near the station" or
112
+ // "buy pizza with sats in turin").
113
+ if (/\b(near|nearby|around|close|spend|find|shop|cafe|coffee|food|eat|lunch|dinner|atm|buy|pizz|restaurant)\b/i.test(q)) {
114
+ const skillText = (skill.description + ' ' + (skill.triggers || []).join(' ')).toLowerCase();
115
+ if (/(merchant|btcmap|map|location|nearby|spend.*bitcoin|find.*place|food|restaurant|cafe|eat|pizza)/.test(skillText))
116
+ score += 1.5;
117
+ }
107
118
  if (score > bestScore) {
108
119
  bestScore = score;
109
120
  best = skill;
@@ -113,6 +124,39 @@ export const keywordSelector = {
113
124
  return bestScore >= 2 ? best : null;
114
125
  },
115
126
  };
127
+ /**
128
+ * Optional embedding-powered selector factory.
129
+ *
130
+ * When an EmbeddingProvider (the same shape used by Retriever/RAG) is supplied,
131
+ * hosts can use the returned selector for more semantic skill routing. This
132
+ * helps vague/natural location and discovery queries ("coffee near the station",
133
+ * "somewhere to grab a bite that takes lightning") reach merchant-finder or
134
+ * similar skills even without exact keyword overlap.
135
+ *
136
+ * The current implementation keeps a synchronous SkillSelector contract (to match
137
+ * the existing interface used by Funnel and SkillRegistry). It therefore:
138
+ * - Uses an enhanced keywordSelector as the fast path (see above).
139
+ * - If embeddings are provided it is ready for hosts to wrap or evolve into a
140
+ * fully semantic version (prototype embeddings of skill descriptions +
141
+ * cosine vs. query, mixed with keyword score).
142
+ *
143
+ * Example host usage (CLI / provider with embeddings already loaded):
144
+ * import { createEmbeddingSkillSelector, SkillRegistry } from '@kaleidorg/mind';
145
+ * const selector = createEmbeddingSkillSelector(embeddingsProvider);
146
+ * const reg = new SkillRegistry(loadedSkills, selector);
147
+ *
148
+ * For a production semantic version a host can implement an async select
149
+ * wrapper around its own Funnel turn or pre-compute skill prototypes.
150
+ */
151
+ export function createEmbeddingSkillSelector(embeddings, _opts = {}) {
152
+ // Today we return the (already lightly enhanced) keyword selector.
153
+ // The embeddings parameter and factory exist so hosts have a single
154
+ // obvious extension point and the public API signals the intent.
155
+ // A future revision can make SkillSelector support async or add a
156
+ // separate async entry point if the Funnel routing is made async.
157
+ void embeddings; // intentionally unused in the current sync impl
158
+ return keywordSelector;
159
+ }
116
160
  export class SkillRegistry {
117
161
  skills = [];
118
162
  selector;