@kaleidorg/mind 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities.d.ts +4 -0
- package/dist/capabilities.d.ts.map +1 -1
- package/dist/capabilities.js +7 -0
- package/dist/capabilities.js.map +1 -1
- package/dist/engine.d.ts +9 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -0
- package/dist/engine.js.map +1 -1
- package/dist/funnel.d.ts +6 -0
- package/dist/funnel.d.ts.map +1 -1
- package/dist/funnel.js +26 -6
- package/dist/funnel.js.map +1 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/kaleidoswap/contract.d.ts +72 -0
- package/dist/kaleidoswap/contract.d.ts.map +1 -0
- package/dist/kaleidoswap/contract.js +125 -0
- package/dist/kaleidoswap/contract.js.map +1 -0
- package/dist/knowledge/btc-map.d.ts +87 -0
- package/dist/knowledge/btc-map.d.ts.map +1 -0
- package/dist/knowledge/btc-map.js +365 -0
- package/dist/knowledge/btc-map.js.map +1 -0
- package/dist/lsps1/contract.d.ts +55 -0
- package/dist/lsps1/contract.d.ts.map +1 -0
- package/dist/lsps1/contract.js +91 -0
- package/dist/lsps1/contract.js.map +1 -0
- package/dist/memory/store.d.ts +7 -1
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +43 -3
- package/dist/memory/store.js.map +1 -1
- package/dist/memory/types.d.ts +12 -0
- package/dist/memory/types.d.ts.map +1 -1
- package/dist/qvac/assistant.d.ts +73 -0
- package/dist/qvac/assistant.d.ts.map +1 -0
- package/dist/qvac/assistant.js +97 -0
- package/dist/qvac/assistant.js.map +1 -0
- package/dist/qvac/config.d.ts +64 -0
- package/dist/qvac/config.d.ts.map +1 -0
- package/dist/qvac/config.js +71 -0
- package/dist/qvac/config.js.map +1 -0
- package/dist/qvac/delegate.d.ts +48 -0
- package/dist/qvac/delegate.d.ts.map +1 -0
- package/dist/qvac/delegate.js +51 -0
- package/dist/qvac/delegate.js.map +1 -0
- package/dist/qvac/index.d.ts +19 -0
- package/dist/qvac/index.d.ts.map +1 -0
- package/dist/qvac/index.js +19 -0
- package/dist/qvac/index.js.map +1 -0
- package/dist/qvac/parse.d.ts +44 -0
- package/dist/qvac/parse.d.ts.map +1 -0
- package/dist/qvac/parse.js +28 -0
- package/dist/qvac/parse.js.map +1 -0
- package/dist/qvac/provider.d.ts +49 -0
- package/dist/qvac/provider.d.ts.map +1 -0
- package/dist/qvac/provider.js +68 -0
- package/dist/qvac/provider.js.map +1 -0
- package/dist/qvac/stream.d.ts +37 -0
- package/dist/qvac/stream.d.ts.map +1 -0
- package/dist/qvac/stream.js +29 -0
- package/dist/qvac/stream.js.map +1 -0
- package/dist/qvac/text.d.ts +19 -0
- package/dist/qvac/text.d.ts.map +1 -0
- package/dist/qvac/text.js +56 -0
- package/dist/qvac/text.js.map +1 -0
- package/dist/qvac/voice.d.ts +69 -0
- package/dist/qvac/voice.d.ts.map +1 -0
- package/dist/qvac/voice.js +51 -0
- package/dist/qvac/voice.js.map +1 -0
- package/dist/recipe/kaleidoswap-atomic.d.ts +27 -0
- package/dist/recipe/kaleidoswap-atomic.d.ts.map +1 -0
- package/dist/recipe/kaleidoswap-atomic.js +111 -0
- package/dist/recipe/kaleidoswap-atomic.js.map +1 -0
- package/dist/recipe/runner.d.ts.map +1 -1
- package/dist/recipe/runner.js +13 -1
- package/dist/recipe/runner.js.map +1 -1
- package/dist/skills/registry.d.ts.map +1 -1
- package/dist/skills/registry.js +20 -2
- package/dist/skills/registry.js.map +1 -1
- package/dist/wallet/confirm.d.ts +12 -0
- package/dist/wallet/confirm.d.ts.map +1 -0
- package/dist/wallet/confirm.js +67 -0
- package/dist/wallet/confirm.js.map +1 -0
- package/package.json +16 -1
- package/skills/README.md +6 -1
- package/skills/kaleido-lsps/SKILL.md +56 -0
- package/skills/kaleido-trading/SKILL.md +85 -18
- package/skills/merchant-finder/SKILL.md +87 -0
- package/skills/paid-data/SKILL.md +12 -0
- package/skills/wallet-assistant/SKILL.md +38 -0
- package/src/capabilities.ts +12 -0
- package/src/context/context.test.ts +6 -2
- package/src/engine.ts +6 -0
- package/src/funnel.ts +32 -7
- package/src/index.ts +43 -0
- package/src/kaleidoswap/contract.test.ts +147 -0
- package/src/kaleidoswap/contract.ts +212 -0
- package/src/knowledge/btc-map.test.ts +188 -0
- package/src/knowledge/btc-map.ts +446 -0
- package/src/lsps1/contract.test.ts +81 -0
- package/src/lsps1/contract.ts +132 -0
- package/src/memory/memory.test.ts +55 -0
- package/src/memory/store.ts +49 -4
- package/src/memory/types.ts +13 -0
- package/src/qvac/assistant.test.ts +132 -0
- package/src/qvac/assistant.ts +146 -0
- package/src/qvac/config.test.ts +44 -0
- package/src/qvac/config.ts +76 -0
- package/src/qvac/delegate.test.ts +68 -0
- package/src/qvac/delegate.ts +71 -0
- package/src/qvac/index.ts +72 -0
- package/src/qvac/parse.test.ts +52 -0
- package/src/qvac/parse.ts +57 -0
- package/src/qvac/provider.test.ts +107 -0
- package/src/qvac/provider.ts +124 -0
- package/src/qvac/stream.test.ts +79 -0
- package/src/qvac/stream.ts +56 -0
- package/src/qvac/text.test.ts +70 -0
- package/src/qvac/text.ts +60 -0
- package/src/qvac/voice.test.ts +151 -0
- package/src/qvac/voice.ts +122 -0
- package/src/recipe/kaleidoswap-atomic.test.ts +138 -0
- package/src/recipe/kaleidoswap-atomic.ts +117 -0
- package/src/recipe/runner.ts +13 -1
- package/src/skills/registry.ts +21 -2
- package/src/skills/skills.test.ts +42 -0
- package/src/wallet/confirm.test.ts +57 -0
- package/src/wallet/confirm.ts +74 -0
- package/skills/kaleido-wallet/SKILL.md +0 -28
|
@@ -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;
|
|
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"}
|
package/dist/skills/registry.js
CHANGED
|
@@ -68,6 +68,22 @@ const STOPWORDS = new Set([
|
|
|
68
68
|
'have', 'has', 'are', 'was', 'can', 'will', 'please', 'today', 'now', 'get',
|
|
69
69
|
'show', 'tell', 'how', 'much', 'many', 'about', 'into', 'over',
|
|
70
70
|
]);
|
|
71
|
+
/** Escape a string for safe inclusion in a regex. */
|
|
72
|
+
function reEscape(s) {
|
|
73
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Match a trigger phrase in the query with WORD BOUNDARIES — so the
|
|
77
|
+
* `usd` trigger on a wallet skill doesn't fire on `usdt`/`usdc`, and
|
|
78
|
+
* `cafe` doesn't fire on `cafeteria`. Multi-word triggers ("near me")
|
|
79
|
+
* still work because spaces are already word boundaries.
|
|
80
|
+
*/
|
|
81
|
+
function triggerMatches(query, trigger) {
|
|
82
|
+
const t = trigger.toLowerCase().trim();
|
|
83
|
+
if (!t)
|
|
84
|
+
return false;
|
|
85
|
+
return new RegExp(`\\b${reEscape(t)}\\b`).test(query);
|
|
86
|
+
}
|
|
71
87
|
/** Default selector: score by meaningful keyword overlap; triggers weigh most. */
|
|
72
88
|
export const keywordSelector = {
|
|
73
89
|
select(query, skills) {
|
|
@@ -82,9 +98,11 @@ export const keywordSelector = {
|
|
|
82
98
|
for (const w of hayWords)
|
|
83
99
|
if (words.has(w))
|
|
84
100
|
score += 1;
|
|
85
|
-
// Strong boost for an explicit trigger appearing in the query
|
|
101
|
+
// Strong boost for an explicit trigger appearing in the query — at a
|
|
102
|
+
// word boundary, so short triggers (`usd`, `eur`, `cafe`) don't leak
|
|
103
|
+
// into longer words (`usdt`, `europe`, `cafeteria`).
|
|
86
104
|
for (const t of skill.triggers ?? [])
|
|
87
|
-
if (q
|
|
105
|
+
if (triggerMatches(q, t))
|
|
88
106
|
score += 3;
|
|
89
107
|
if (score > bestScore) {
|
|
90
108
|
bestScore = score;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,yEAAyE;AACzE,MAAM,CAAC,MAAM,mBAAmB,GAAG,sBAAsB,CAAC;AAE1D;;;;;;;;;;;GAWG;AACH,oEAAoE;AACpE,SAAS,OAAO,CAAC,CAAS;IACxB,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACnB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACrF,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,QAAgB,EAAE,UAA6B;IACxE,MAAM,EAAE,GAAG,QAAQ,CAAC,KAAK,CAAC,0CAA0C,CAAC,CAAC;IACtE,MAAM,IAAI,GAA2B,EAAE,CAAC;IACxC,IAAI,IAAI,GAAG,QAAQ,CAAC;IACpB,IAAI,EAAE,EAAE,CAAC;QACP,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,MAAM,IAAI,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7C,0EAA0E;YAC1E,0EAA0E;YAC1E,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;YAC9D,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,CAAU,EAAE,EAAE,CAC1B,CAAC;QACC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QACnD,CAAC,CAAC,SAAS,CAAC;IAEhB,IAAI,CAAC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAE1E,8DAA8D;IAC9D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC;IACpE,MAAM,QAAQ,GAA2B,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC;QAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;YAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAE9E,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,EAAE;QACnC,YAAY,EAAE,IAAI,CAAC,IAAI,EAAE;QACzB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;QACvB,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;QAC7B,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;QAC7D,UAAU,EAAE,UAAU,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;KACrE,CAAC;AACJ,CAAC;AAED,0DAA0D;AAC1D,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IACxB,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAC1E,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK;IAC3E,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM;CAC/D,CAAC,CAAC;AAEH,kFAAkF;AAClF,MAAM,CAAC,MAAM,eAAe,GAAkB;IAC5C,MAAM,CAAC,KAAK,EAAE,MAAM;QAClB,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,IAAI,GAAG,CACnB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAChE,CAAC;QACF,IAAI,IAAI,GAAiB,IAAI,CAAC;QAC9B,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,GAAG,KAAK,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC;YAC1F,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACxF,IAAI,KAAK,GAAG,CAAC,CAAC;YACd,KAAK,MAAM,CAAC,IAAI,QAAQ;gBAAE,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;oBAAE,KAAK,IAAI,CAAC,CAAC;YACvD
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/skills/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confirm-sheet readback — a deterministic, voice-first summary of a spend that
|
|
3
|
+
* the host speaks before executing it ("Send 4,800 sats to bob over Spark.
|
|
4
|
+
* Confirm?"). Built from the resolved tool call, not the model: zero inference,
|
|
5
|
+
* identical on every surface, and impossible for the model to phrase around.
|
|
6
|
+
*/
|
|
7
|
+
/** A spoken confirmation ending in "Confirm?", or null for non-spend tools. */
|
|
8
|
+
export declare function confirmReadback(call: {
|
|
9
|
+
name: string;
|
|
10
|
+
arguments: Record<string, unknown>;
|
|
11
|
+
}): string | null;
|
|
12
|
+
//# sourceMappingURL=confirm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.d.ts","sourceRoot":"","sources":["../../src/wallet/confirm.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyCH,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CA0BzG"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Confirm-sheet readback — a deterministic, voice-first summary of a spend that
|
|
3
|
+
* the host speaks before executing it ("Send 4,800 sats to bob over Spark.
|
|
4
|
+
* Confirm?"). Built from the resolved tool call, not the model: zero inference,
|
|
5
|
+
* identical on every surface, and impossible for the model to phrase around.
|
|
6
|
+
*/
|
|
7
|
+
import { getWalletTool } from './contract.js';
|
|
8
|
+
const LAYER_LABEL = {
|
|
9
|
+
spark: 'Spark',
|
|
10
|
+
rln: 'RLN',
|
|
11
|
+
arkade: 'Arkade',
|
|
12
|
+
liquid: 'Liquid',
|
|
13
|
+
};
|
|
14
|
+
/** Group an integer with thousands separators, locale-independently (test-stable). */
|
|
15
|
+
function fmtNum(n) {
|
|
16
|
+
if (!Number.isFinite(n))
|
|
17
|
+
return String(n);
|
|
18
|
+
const neg = n < 0;
|
|
19
|
+
const [int, frac] = Math.abs(n).toString().split('.');
|
|
20
|
+
const grouped = int.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
|
21
|
+
return (neg ? '-' : '') + (frac ? `${grouped}.${frac}` : grouped);
|
|
22
|
+
}
|
|
23
|
+
/** Looks like an address/invoice/lnurl (vs a human contact name). */
|
|
24
|
+
function isRef(s) {
|
|
25
|
+
return /^(ln(bc|tb|bcrt)|bc1|tb1|lq1|lnurl)/i.test(s) || (s.length > 20 && !/\s/.test(s));
|
|
26
|
+
}
|
|
27
|
+
/** Shorten an address/invoice for speech; leave contact names intact. */
|
|
28
|
+
function shortRef(s) {
|
|
29
|
+
const v = s.trim();
|
|
30
|
+
return isRef(v) ? `${v.slice(0, 6)}…${v.slice(-4)}` : v;
|
|
31
|
+
}
|
|
32
|
+
/** " over Spark" suffix for the call's layer (explicit arg wins, else the tool's). */
|
|
33
|
+
function over(name, args) {
|
|
34
|
+
const layer = typeof args.layer === 'string' ? args.layer : getWalletTool(name)?.layer;
|
|
35
|
+
const label = layer ? LAYER_LABEL[layer] : undefined;
|
|
36
|
+
return label ? ` over ${label}` : '';
|
|
37
|
+
}
|
|
38
|
+
const sats = (v) => `${fmtNum(Number(v))} sats`;
|
|
39
|
+
const asset = (amount, ticker) => `${fmtNum(Number(amount))} ${String(ticker)}`;
|
|
40
|
+
/** A spoken confirmation ending in "Confirm?", or null for non-spend tools. */
|
|
41
|
+
export function confirmReadback(call) {
|
|
42
|
+
const { name, arguments: a } = call;
|
|
43
|
+
const to = (k = 'to') => shortRef(String(a[k] ?? ''));
|
|
44
|
+
const ask = (s) => `${s}. Confirm?`;
|
|
45
|
+
switch (name) {
|
|
46
|
+
case 'send_payment': {
|
|
47
|
+
const amt = a.amount_sats != null ? sats(a.amount_sats)
|
|
48
|
+
: a.asset != null && a.amount != null ? asset(a.amount, a.asset)
|
|
49
|
+
: undefined;
|
|
50
|
+
return ask(amt ? `Send ${amt} to ${to()}${over(name, a)}` : `Send a payment to ${to()}${over(name, a)}`);
|
|
51
|
+
}
|
|
52
|
+
case 'spark_send':
|
|
53
|
+
case 'arkade_send':
|
|
54
|
+
return ask(`Send ${sats(a.amount_sats)} to ${to()}${over(name, a)}`);
|
|
55
|
+
case 'rln_send_asset':
|
|
56
|
+
case 'liquid_send':
|
|
57
|
+
return ask(`Send ${asset(a.amount, a.asset)} to ${to()}${over(name, a)}`);
|
|
58
|
+
case 'rln_pay_invoice':
|
|
59
|
+
return ask(`Pay Lightning invoice ${shortRef(String(a.invoice ?? ''))}${over(name, a)}`);
|
|
60
|
+
case 'execute_swap':
|
|
61
|
+
return ask(`Swap ${fmtNum(Number(a.amount))} ${String(a.from_asset)} for ${String(a.to_asset)}`);
|
|
62
|
+
default:
|
|
63
|
+
// Unknown but spend-flagged tool → a generic, still-honest readback.
|
|
64
|
+
return getWalletTool(name)?.spend ? ask(`Confirm ${name.replace(/_/g, ' ')}`) : null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=confirm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"confirm.js","sourceRoot":"","sources":["../../src/wallet/confirm.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kaleidorg/mind",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Local-first reasoning + function-calling engine for KaleidoSwap. QVAC-powered.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -34,6 +34,11 @@
|
|
|
34
34
|
"types": "./dist/logger.d.ts",
|
|
35
35
|
"import": "./dist/logger.js",
|
|
36
36
|
"default": "./dist/logger.js"
|
|
37
|
+
},
|
|
38
|
+
"./qvac": {
|
|
39
|
+
"types": "./dist/qvac/index.d.ts",
|
|
40
|
+
"import": "./dist/qvac/index.js",
|
|
41
|
+
"default": "./dist/qvac/index.js"
|
|
37
42
|
}
|
|
38
43
|
},
|
|
39
44
|
"files": [
|
|
@@ -51,7 +56,17 @@
|
|
|
51
56
|
"lint": "eslint src",
|
|
52
57
|
"bundle-skills": "node scripts/bundle-skills.mjs"
|
|
53
58
|
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"@qvac/sdk": ">=0.12.2"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"@qvac/sdk": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
54
67
|
"devDependencies": {
|
|
68
|
+
"@qvac/sdk": "^0.13.1",
|
|
69
|
+
"@types/node": "^20.0.0",
|
|
55
70
|
"vitest": "^1.6.0"
|
|
56
71
|
}
|
|
57
72
|
}
|
package/skills/README.md
CHANGED
|
@@ -70,5 +70,10 @@ Then per query: `const skill = registry.select(query)` →
|
|
|
70
70
|
`https://api.bitrefill.com/mcp` (needs `BITREFILL_API_KEY` — anonymous = 401).
|
|
71
71
|
Source: https://github.com/bitrefill/agents (MIT). Update with
|
|
72
72
|
`npx skills add bitrefill/agents` or re-vendor the folder.
|
|
73
|
-
- **
|
|
73
|
+
- **wallet-assistant/** — everyday wallet tasks (balance, receive, send, pay,
|
|
74
|
+
price, fiat→sats, resolve a contact). Resolves to host-bound `wallet/contract.ts`
|
|
75
|
+
tools (in-process WDK on mobile, MCP on desktop).
|
|
76
|
+
- **merchant-finder/** — find Bitcoin-accepting merchants via BTC Map. Live
|
|
77
|
+
data when the host injects a fetch + location; bundled offline list otherwise.
|
|
78
|
+
- **paid-data/** — fetch L402-paywalled resources via `fetch_paid_resource`.
|
|
74
79
|
- **kaleido-trading/** — prices, quotes, atomic swaps, LSP channels.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: kaleido-lsps
|
|
3
|
+
description: "Buy inbound Lightning channel capacity from a Lightning Service Provider (LSPS1). Quote, estimate fees, and create a channel order. Triggers when the user wants inbound liquidity, can't receive a payment, needs a channel, or asks about LSP fees."
|
|
4
|
+
tools: lsp_get_info, lsp_get_network_info, lsp_estimate_fees, lsp_create_order, lsp_get_order
|
|
5
|
+
triggers: inbound, liquidity, channel order, lsp, lsps1, receive limit, can't receive, open channel
|
|
6
|
+
metadata:
|
|
7
|
+
author: kaleidoswap
|
|
8
|
+
version: "0.1.0"
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Lightning channel orders (LSPS1)
|
|
12
|
+
|
|
13
|
+
Buy inbound Lightning channel capacity from a Lightning Service Provider when
|
|
14
|
+
the user can't receive a payment (no inbound liquidity) or wants a bigger
|
|
15
|
+
receive limit. The host binds these to whichever LSP it talks to — the
|
|
16
|
+
KaleidoSwap maker by default, but the contract is LSP-agnostic (`lsp_*`).
|
|
17
|
+
|
|
18
|
+
## Critical rules
|
|
19
|
+
|
|
20
|
+
You have **no knowledge of LSP fees, channel sizes, or order status**. Every
|
|
21
|
+
number, capacity, fee, or order id in your reply MUST come from a tool result
|
|
22
|
+
returned in the CURRENT turn. Never quote a fee from memory. Never claim an
|
|
23
|
+
order completed without calling `lsp_get_order`. Never reuse a number from a
|
|
24
|
+
previous turn.
|
|
25
|
+
|
|
26
|
+
**Calling the tool IS the answer.** Don't write "the LSP info is fetched with
|
|
27
|
+
`lsp_get_info`" — call it.
|
|
28
|
+
|
|
29
|
+
If a tool needs a required argument the user didn't give (e.g. an `order_id`
|
|
30
|
+
when polling), ASK. Don't loop the same failing call.
|
|
31
|
+
|
|
32
|
+
## Flow
|
|
33
|
+
|
|
34
|
+
1. **Check the LSP first.** Call `lsp_get_info` once per session to learn the
|
|
35
|
+
min/max channel size and the fee structure. Use those numbers to validate
|
|
36
|
+
the user's request (e.g. "200k sats" against `min_channel_sat`).
|
|
37
|
+
2. **Estimate before ordering.** Call `lsp_estimate_fees` with the desired
|
|
38
|
+
`lsp_balance_sat`. Surface the total cost explicitly — never hide it.
|
|
39
|
+
3. **Show + confirm.** State: inbound capacity requested, total fee, expiry
|
|
40
|
+
(if applicable), and the LSP node URI from `lsp_get_network_info` (so the
|
|
41
|
+
user knows the counterparty). The next step is spend-gated.
|
|
42
|
+
4. **Create the order.** Call `lsp_create_order` with the same parameters.
|
|
43
|
+
The host pauses for explicit confirmation. Returns an `order_id` and a
|
|
44
|
+
Lightning invoice the user must pay to lock the order.
|
|
45
|
+
5. **Track it.** Poll `lsp_get_order` until the channel opens (status
|
|
46
|
+
`completed`) or fails. Report the outcome plainly.
|
|
47
|
+
|
|
48
|
+
## Rules
|
|
49
|
+
|
|
50
|
+
- **Re-estimate when parameters change.** Don't reuse an estimate across
|
|
51
|
+
different channel sizes or expiries.
|
|
52
|
+
- **Never invent capacity / fees / pubkeys.** Tool results are the truth.
|
|
53
|
+
- **Lightning over on-chain for ordering.** LSPS1 orders are paid by
|
|
54
|
+
Lightning invoice; if Lightning isn't available, say so and stop.
|
|
55
|
+
- **A channel order is not the same as a payment.** Make this explicit when
|
|
56
|
+
the user confuses them.
|
|
@@ -1,31 +1,98 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: kaleido-trading
|
|
3
|
-
description: "Trade
|
|
4
|
-
tools: get_price,
|
|
5
|
-
triggers:
|
|
3
|
+
description: "Trade on KaleidoSwap — quote and execute swaps between BTC and RGB assets (USDT, XAUT). Get assets and pairs, pull an executable quote, place a market order, or track an atomic swap end-to-end. Triggers when the user wants a price, a quote, to swap or trade assets, or to rebalance between BTC and stablecoins."
|
|
4
|
+
tools: get_price, fiat_to_sats, kaleidoswap_get_assets, kaleidoswap_get_pairs, kaleidoswap_get_quote, kaleidoswap_get_nodeinfo, kaleidoswap_place_order, kaleidoswap_get_order_status, kaleidoswap_get_order_history
|
|
5
|
+
triggers: quote, swap, trade, rebalance, slippage, pair, pairs, usdt, xaut, kaleidoswap, rfq
|
|
6
6
|
metadata:
|
|
7
7
|
author: kaleidoswap
|
|
8
|
-
version: "0.
|
|
9
|
-
surface: "kaleido-mcp (KaleidoSwap maker + market data)"
|
|
8
|
+
version: "0.3.0"
|
|
10
9
|
---
|
|
11
10
|
|
|
12
11
|
# KaleidoSwap trading
|
|
13
12
|
|
|
14
|
-
Quote
|
|
15
|
-
|
|
13
|
+
Quote and execute swaps on the KaleidoSwap maker. The model picks tools by
|
|
14
|
+
name; the host binds them through whichever transport it runs over (WDK on
|
|
15
|
+
mobile, HTTP/MCP/CLI on desktop).
|
|
16
|
+
|
|
17
|
+
## Critical rules — these override everything else
|
|
18
|
+
|
|
19
|
+
You have **no knowledge** of any price, quote, fee, pair, or order. Every
|
|
20
|
+
number, pair, or quote id in your reply MUST come from a tool result returned
|
|
21
|
+
in the CURRENT turn:
|
|
22
|
+
|
|
23
|
+
- "What's the BTC price?" → call `get_price` and state the number it returns.
|
|
24
|
+
- "What pairs are listed?" → call `kaleidoswap_get_pairs` and list them.
|
|
25
|
+
- "Quote 100k sats to USDT" → call `kaleidoswap_get_quote(BTC, USDT, 100000)`,
|
|
26
|
+
then state the receive amount + fees from the result.
|
|
27
|
+
|
|
28
|
+
**Calling the tool IS the answer.** Never write "the pairs are listed using
|
|
29
|
+
kaleidoswap_get_pairs" or "the function returns the quote" — just call it.
|
|
30
|
+
|
|
31
|
+
**Never reuse a number across turns.** If the user asks a new question, the
|
|
32
|
+
previous turn's quote, price, or fee is irrelevant — fetch fresh.
|
|
33
|
+
|
|
34
|
+
**Never invent a quote.** Without a `quote_id` and `receive_amount` returned
|
|
35
|
+
this turn, you do not have a quote. Say so and re-quote.
|
|
36
|
+
|
|
37
|
+
## Asset codes (canonical)
|
|
38
|
+
|
|
39
|
+
Only these codes are accepted:
|
|
40
|
+
|
|
41
|
+
- `BTC` (Bitcoin, amounts always in satoshis)
|
|
42
|
+
- `USDT` (Tether) — **not** `USD`, **not** `tether`
|
|
43
|
+
- `XAUT` (Tether Gold) — **not** `XAU`, **not** `gold`
|
|
44
|
+
|
|
45
|
+
When the user types `USD` they almost always mean `USDT` — confirm before
|
|
46
|
+
quoting. Same for `gold` → `XAUT`. Don't silently substitute.
|
|
47
|
+
|
|
48
|
+
## Tools
|
|
49
|
+
|
|
50
|
+
### `kaleidoswap_get_pairs` — no args
|
|
51
|
+
Use when the user asks "what can I trade", "list pairs", "what's available",
|
|
52
|
+
or before quoting an unfamiliar pair.
|
|
53
|
+
|
|
54
|
+
### `kaleidoswap_get_quote` — REQUIRES `amount`
|
|
55
|
+
Required args: `from_asset` AND `to_asset` AND `amount`. The maker rejects
|
|
56
|
+
calls missing any of these.
|
|
57
|
+
|
|
58
|
+
**If the user didn't give an amount, ASK for it. Do not call the tool with
|
|
59
|
+
from/to alone.**
|
|
60
|
+
|
|
61
|
+
Examples:
|
|
62
|
+
- "Quote 100k sats to USDT" → `{from_asset: "BTC", to_asset: "USDT", amount: 100000}`
|
|
63
|
+
- "What's the USDT/BTC rate?" → ask: "How many USDT do you want to swap?"
|
|
64
|
+
(no amount → no quote possible).
|
|
65
|
+
- "Buy 50 USDT of BTC" → `{from_asset: "USDT", to_asset: "BTC", amount: 50}`
|
|
66
|
+
(USDT is what's being spent).
|
|
67
|
+
|
|
68
|
+
### `kaleidoswap_place_order(quote_id)` 🔒 spend
|
|
69
|
+
Only after `kaleidoswap_get_quote` returned a `quote_id` THIS turn, and only
|
|
70
|
+
when the user has explicitly approved the amount + direction.
|
|
71
|
+
|
|
72
|
+
### `kaleidoswap_get_order_status(order_id)`
|
|
73
|
+
Poll after placing an order. Report status plainly — pending, settling,
|
|
74
|
+
completed, failed.
|
|
16
75
|
|
|
17
76
|
## Flow
|
|
18
77
|
|
|
19
|
-
1. **
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
78
|
+
1. **Pick a pair** — skip when obvious (`BTC/USDT`, `BTC/XAUT`).
|
|
79
|
+
2. **Quote** — `kaleidoswap_get_quote`. REQUIRES amount.
|
|
80
|
+
3. **Show + confirm** — surface pair, direction, amount in, expected out,
|
|
81
|
+
fees, slippage. **Never hide cost** — a small model must not abbreviate
|
|
82
|
+
fees out of the message.
|
|
83
|
+
4. **Place** — spend-gated by the engine. The host pauses for the user.
|
|
84
|
+
5. **Track** — poll `kaleidoswap_get_order_status` until it terminates.
|
|
85
|
+
|
|
86
|
+
## Don'ts
|
|
27
87
|
|
|
28
|
-
|
|
88
|
+
- Don't invent prices, quotes, quote_ids, or order_ids.
|
|
89
|
+
- Don't reuse a number from a previous turn.
|
|
90
|
+
- Don't describe how a tool works — call it.
|
|
91
|
+
- Don't call `kaleidoswap_get_quote` with from/to only — ask for the amount.
|
|
92
|
+
- Don't accept `XAU` as `XAUT` or `USD` as `USDT` silently — confirm.
|
|
93
|
+
- Don't retry the same failing tool call in a loop. If a call fails, read the
|
|
94
|
+
error and either ask the user, fix the args, or stop.
|
|
29
95
|
|
|
30
|
-
|
|
31
|
-
|
|
96
|
+
For the atomic-swap flow (trust-minimised cross-asset swap that the maker
|
|
97
|
+
can't settle from balance), use the `kaleido-trading` atomic recipe — the
|
|
98
|
+
agentic chain is not safe to plan on a 0.6B model.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: merchant-finder
|
|
3
|
+
description: "Find Bitcoin-accepting merchants near the user using live BTC Map data and the device's real location. Triggers when the user asks where to spend Bitcoin, for a shop, store, restaurant, cafe, bar, or ATM that accepts Bitcoin, or for merchants nearby."
|
|
4
|
+
tools: find_merchant_locations, get_merchant_info
|
|
5
|
+
triggers: merchant, merchants, shop, shops, store, stores, restaurant, restaurants, cafe, cafes, bar, bars, atm, atms, accept, accepts, accepting, nearby, near me, around, place, places, spend, find, pizza, food, coffee, bitcoin map, btcmap
|
|
6
|
+
metadata:
|
|
7
|
+
author: kaleidoswap
|
|
8
|
+
version: "0.2.0"
|
|
9
|
+
homepage: "https://btcmap.org"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Merchant finder
|
|
13
|
+
|
|
14
|
+
Discover places that accept Bitcoin payments — cafés, restaurants, bars, shops,
|
|
15
|
+
and ATMs. Live BTC Map data when the host injects a fetcher + location;
|
|
16
|
+
otherwise a small offline list keeps the skill answerable.
|
|
17
|
+
|
|
18
|
+
## Critical rule — never answer from memory
|
|
19
|
+
|
|
20
|
+
You have **no knowledge of any merchant**. Every place, name, address and
|
|
21
|
+
distance in your reply MUST come from a `find_merchant_locations` result
|
|
22
|
+
returned in the CURRENT turn. **Call `find_merchant_locations` for every
|
|
23
|
+
place question**, even if a similar question was answered earlier — do NOT
|
|
24
|
+
reuse or adapt a previous answer. Never invent a merchant.
|
|
25
|
+
|
|
26
|
+
## How to call the tools
|
|
27
|
+
|
|
28
|
+
1. **Start with `find_merchant_locations`.** Pass ONLY the fields the user
|
|
29
|
+
actually named — do not invent constraints:
|
|
30
|
+
|
|
31
|
+
- `query` — a specific thing the user named (e.g. `"tapas"`, `"coffee"`,
|
|
32
|
+
`"pizza"`). Omit when they only said "near me" or only named a place.
|
|
33
|
+
|
|
34
|
+
- `category` — must be EXACTLY one of: `restaurant`, `cafe`, `bar`, `shop`,
|
|
35
|
+
`grocery`, `lodging`, `atm`. **Anything else is invalid — leave it empty.**
|
|
36
|
+
The words "merchant", "merchants", "place", "places", "store", "stores"
|
|
37
|
+
are NOT categories — they're the generic noun for what you're searching
|
|
38
|
+
for, so they belong in `query` at best, never in `category`.
|
|
39
|
+
|
|
40
|
+
- `near_address` — a city, neighbourhood, or address (e.g. `"Milan"`,
|
|
41
|
+
`"Bitcoin Beach, El Salvador"`). Use this any time the user names a
|
|
42
|
+
location instead of "near me".
|
|
43
|
+
|
|
44
|
+
- `radius_km` — **omit unless the user names a specific number.** The
|
|
45
|
+
default (5 km) is a sensible search radius for a city. Don't pick a
|
|
46
|
+
small radius (1, 2, 3) yourself — city-wide searches need 5+.
|
|
47
|
+
|
|
48
|
+
- `limit` — 1–20, default 10. Omit unless the user names a count.
|
|
49
|
+
|
|
50
|
+
Examples (positive):
|
|
51
|
+
- "where can I spend btc near me" → `find_merchant_locations({})`
|
|
52
|
+
- "find merchants in Milan" → `find_merchant_locations({ near_address: "Milan" })`
|
|
53
|
+
↑ no `category` — "merchants" is NOT a category.
|
|
54
|
+
- "cafes in Lisbon" → `find_merchant_locations({ category: "cafe", near_address: "Lisbon" })`
|
|
55
|
+
- "pizza places in Switzerland that take bitcoin" →
|
|
56
|
+
`find_merchant_locations({ query: "pizza", near_address: "Switzerland" })`
|
|
57
|
+
↑ "places" is NOT a category — pizza goes in `query`.
|
|
58
|
+
- "lightning bars in NYC, within 2 km" →
|
|
59
|
+
`find_merchant_locations({ category: "bar", near_address: "New York", radius_km: 2 })`
|
|
60
|
+
↑ user explicitly said "2 km" → set radius_km.
|
|
61
|
+
|
|
62
|
+
Examples (anti — do NOT do these):
|
|
63
|
+
- ❌ `category: "merchant"` (not a category)
|
|
64
|
+
- ❌ `category: "place"` (not a category)
|
|
65
|
+
- ❌ `radius_km: 2` when the user didn't say "2 km" — you're picking a
|
|
66
|
+
too-small radius and the result will be empty.
|
|
67
|
+
|
|
68
|
+
2. **Present the results.** Each row carries:
|
|
69
|
+
- `name`, `category`, `address`
|
|
70
|
+
- `distance_m` when present — show in metres or km
|
|
71
|
+
- `accepts_bitcoin` / `accepts_lightning` — relevant because Lightning is
|
|
72
|
+
fastest for small payments
|
|
73
|
+
- `phone`, `website`, `opening_hours` when present — surface if asked
|
|
74
|
+
|
|
75
|
+
3. **Use `get_merchant_info` only when** the user asks for more detail on one
|
|
76
|
+
specific result. Pass `merchant_id` (preferred) or `merchant_name`.
|
|
77
|
+
|
|
78
|
+
## Reply style
|
|
79
|
+
|
|
80
|
+
- Be concise. One line per merchant works:
|
|
81
|
+
`Name — category, address (X m away, accepts: lightning, onchain)`.
|
|
82
|
+
- If the result `source` is `offline`, say so plainly — it means the live
|
|
83
|
+
BTC Map fetch wasn't available, so the list is limited.
|
|
84
|
+
- If `find_merchant_locations` returns zero merchants, say so — don't invent
|
|
85
|
+
places. Suggest widening `radius_km` or trying `near_address`.
|
|
86
|
+
- When the user says "near me" and `precise_location` is false, mention which
|
|
87
|
+
fallback location was used so they know it's not their actual GPS.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: paid-data
|
|
3
|
+
description: Fetch premium or paywalled data that requires a small Lightning (L402) payment — paid feeds, gated APIs, unlockable resources. Triggers when the user wants premium, paid, or unlockable data behind an L402 paywall.
|
|
4
|
+
tools: fetch_paid_resource
|
|
5
|
+
triggers: premium, paid, l402, feed, subscription, unlock, paywall
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Paid data
|
|
9
|
+
|
|
10
|
+
Fetch L402-paywalled resources, paying small Lightning invoices automatically
|
|
11
|
+
with `fetch_paid_resource`. Small amounts pay without prompting (capped);
|
|
12
|
+
anything larger is declined. Tell the user what was paid and what was returned.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: wallet-assistant
|
|
3
|
+
description: Everyday wallet tasks on this phone — check the BTC/asset balance, create an invoice to receive, send a payment, look up a contact, get the BTC price, or convert a fiat amount to sats. Triggers when the user asks about their balance, wants to receive or send money, pay an invoice, or pay a contact.
|
|
4
|
+
tools: get_balances, get_price, fiat_to_sats, resolve_contact, send_payment, rln_pay_invoice, rln_create_ln_invoice, spark_create_invoice
|
|
5
|
+
triggers: balance, pay, send, receive, address, invoice, transactions, contact, funds, money, price, sats, eur, gbp
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Wallet assistant
|
|
9
|
+
|
|
10
|
+
You operate the user's on-device multi-L2 Bitcoin wallet. ALWAYS use a tool to
|
|
11
|
+
get real data — NEVER invent a balance, address, amount, price, or result.
|
|
12
|
+
|
|
13
|
+
## Critical rules
|
|
14
|
+
|
|
15
|
+
You have no knowledge of balances, prices, addresses, or invoices. Every value
|
|
16
|
+
in your reply MUST come from a tool result returned in the CURRENT turn — do
|
|
17
|
+
not reuse a number from a previous turn.
|
|
18
|
+
|
|
19
|
+
When a tool returns multiple fields, **report all the load-bearing ones**:
|
|
20
|
+
- `get_balances` may return `{confirmed, pending, total}` — when `pending`
|
|
21
|
+
is non-zero, report BOTH. `confirmed` is spendable; `pending` is settling
|
|
22
|
+
and is NOT spendable yet. The user needs to know the difference.
|
|
23
|
+
- `fiat_to_sats` returns `{sats}` plus a `note` when the currency was an
|
|
24
|
+
approximation — surface the note.
|
|
25
|
+
|
|
26
|
+
## Rules
|
|
27
|
+
|
|
28
|
+
- Balance / "how much do I have" → call `get_balances`, then state the number.
|
|
29
|
+
- Receive / "an invoice for N sats" → call `rln_create_ln_invoice` (or
|
|
30
|
+
`spark_create_invoice`) with the amount.
|
|
31
|
+
- Price → `get_price`. "How many sats is 3 EUR" → `fiat_to_sats`.
|
|
32
|
+
- Pay a Lightning invoice → `rln_pay_invoice`.
|
|
33
|
+
- Send to a person/amount → first `resolve_contact` (and `fiat_to_sats` if the
|
|
34
|
+
amount is in fiat), then `send_payment` with the amount in sats and the
|
|
35
|
+
recipient. State the amount and destination; the app asks the user to confirm
|
|
36
|
+
before it sends.
|
|
37
|
+
|
|
38
|
+
Keep replies short, but never drop a balance component or a fee.
|
package/src/capabilities.ts
CHANGED
|
@@ -25,6 +25,10 @@ export interface MindCapabilities {
|
|
|
25
25
|
memory: boolean;
|
|
26
26
|
/** Semantic recall for memory (needs embeddings). */
|
|
27
27
|
semanticMemory: boolean;
|
|
28
|
+
/** Embedding-only dedup of near-duplicate memories (zero inference — mobile-safe). */
|
|
29
|
+
dedupeMemory: boolean;
|
|
30
|
+
/** LLM merge of near-duplicate memories (an extra inference — capable/delegated only). */
|
|
31
|
+
mergeMemory: boolean;
|
|
28
32
|
/** Retrieval-augmented generation (needs embeddings + enough RAM/context). */
|
|
29
33
|
rag: boolean;
|
|
30
34
|
/** Token budget for injected system context. */
|
|
@@ -48,6 +52,12 @@ export function capabilityProfile(input: CapabilityInput): MindCapabilities {
|
|
|
48
52
|
const memory = budget >= 256;
|
|
49
53
|
const semanticMemory = memory && hasEmb;
|
|
50
54
|
|
|
55
|
+
// Consolidation: embedding-only dedup is cheap (no inference) — on wherever
|
|
56
|
+
// semantic memory is. The LLM merge costs an extra inference, so reserve it
|
|
57
|
+
// for delegated or roomy on-device setups; never run it on a tiny phone model.
|
|
58
|
+
const dedupeMemory = semanticMemory;
|
|
59
|
+
const mergeMemory = dedupeMemory && (input.delegated || (ramGb >= 4 && ctx >= 4096));
|
|
60
|
+
|
|
51
61
|
// RAG is the expensive one: needs embeddings, a non-tiny context window, and
|
|
52
62
|
// (on-device) enough RAM to hold an embedding model + index.
|
|
53
63
|
const rag = hasEmb && ctx >= 4096 && (input.delegated || ramGb >= 3);
|
|
@@ -59,6 +69,8 @@ export function capabilityProfile(input: CapabilityInput): MindCapabilities {
|
|
|
59
69
|
return {
|
|
60
70
|
memory,
|
|
61
71
|
semanticMemory,
|
|
72
|
+
dedupeMemory,
|
|
73
|
+
mergeMemory,
|
|
62
74
|
rag,
|
|
63
75
|
contextBudgetTokens: budget,
|
|
64
76
|
topKMemory,
|
|
@@ -60,18 +60,22 @@ describe('ContextBuilder', () => {
|
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
describe('capabilityProfile', () => {
|
|
63
|
-
it('low-end phone: memory yes, RAG no', () => {
|
|
63
|
+
it('low-end phone: memory yes, RAG no, dedup yes but no LLM merge', () => {
|
|
64
64
|
const c = capabilityProfile({ ramBytes: 2 * 1024 ** 3, modelCtxTokens: 2048, hasEmbeddings: true });
|
|
65
65
|
expect(c.memory).toBe(true);
|
|
66
66
|
expect(c.rag).toBe(false); // ctx too small + low RAM
|
|
67
67
|
expect(c.topKRag).toBe(0);
|
|
68
|
+
expect(c.dedupeMemory).toBe(true); // embedding-only dedup is mobile-safe
|
|
69
|
+
expect(c.mergeMemory).toBe(false); // never run merge inference on a tiny phone
|
|
68
70
|
});
|
|
69
71
|
|
|
70
|
-
it('desktop / delegated: RAG on', () => {
|
|
72
|
+
it('desktop / delegated: RAG on, memory merge on', () => {
|
|
71
73
|
const c = capabilityProfile({ modelCtxTokens: 8192, hasEmbeddings: true, delegated: true });
|
|
72
74
|
expect(c.rag).toBe(true);
|
|
73
75
|
expect(c.topKRag).toBeGreaterThan(0);
|
|
74
76
|
expect(c.semanticMemory).toBe(true);
|
|
77
|
+
expect(c.dedupeMemory).toBe(true);
|
|
78
|
+
expect(c.mergeMemory).toBe(true);
|
|
75
79
|
});
|
|
76
80
|
|
|
77
81
|
it('no embeddings → no RAG, no semantic memory', () => {
|
package/src/engine.ts
CHANGED
|
@@ -35,6 +35,11 @@ export interface AgenticOptions {
|
|
|
35
35
|
onStart?: (requestId: string, turn: number) => void;
|
|
36
36
|
/** Fired when the model requests a tool, before it executes. */
|
|
37
37
|
onToolCall?: (call: { name: string; arguments: Record<string, unknown> }, turn: number) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Fired after a tool returns (success OR error — errors arrive as `{error}`).
|
|
40
|
+
* Useful for surfacing the raw response back to the user in a debug UI.
|
|
41
|
+
*/
|
|
42
|
+
onToolResult?: (event: { name: string; arguments: Record<string, unknown>; result: unknown }, turn: number) => void;
|
|
38
43
|
/** Human-in-the-loop gate for tools flagged requiresConfirmation. */
|
|
39
44
|
onConfirm?: (call: { name: string; arguments: Record<string, unknown> }) => Promise<ConfirmDecision>;
|
|
40
45
|
/**
|
|
@@ -127,6 +132,7 @@ export class Engine {
|
|
|
127
132
|
}
|
|
128
133
|
|
|
129
134
|
executed.push({ name: call.name, arguments: call.arguments, result });
|
|
135
|
+
opts.onToolResult?.({ name: call.name, arguments: call.arguments, result }, turn);
|
|
130
136
|
history.push({
|
|
131
137
|
role: 'tool',
|
|
132
138
|
content: typeof result === 'string' ? result : JSON.stringify(result),
|