@spendgraph/tools 0.6.0 → 0.7.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 (186) hide show
  1. package/README.md +3 -2
  2. package/dist/agents/index.d.ts +1 -0
  3. package/dist/agents/index.js +1 -0
  4. package/dist/{builtin/write-document/write-document.d.ts → agents/moa/index.d.ts} +7 -2
  5. package/dist/agents/moa/index.js +1 -0
  6. package/dist/{builtin/write-document/commission.d.ts → agents/moa/moa.d.ts} +15 -15
  7. package/dist/agents/moa/moa.js +13 -0
  8. package/dist/{builtin/write-document → agents/moa}/types.d.ts +9 -9
  9. package/dist/builtin/calculate/calculate.d.ts +2 -0
  10. package/dist/builtin/calculate/calculate.js +1 -1
  11. package/dist/builtin/calculate/index.d.ts +2 -1
  12. package/dist/builtin/calculate/index.js +1 -1
  13. package/dist/builtin/code-exec/code-exec.d.ts +14 -0
  14. package/dist/builtin/date/date.d.ts +1 -1
  15. package/dist/builtin/date/date.js +1 -1
  16. package/dist/builtin/date/index.d.ts +1 -0
  17. package/dist/builtin/date/index.js +1 -1
  18. package/dist/builtin/date/shift.d.ts +1 -1
  19. package/dist/builtin/date/shift.js +1 -1
  20. package/dist/builtin/date/words.d.ts +13 -0
  21. package/dist/builtin/date/words.js +1 -0
  22. package/dist/builtin/decline/decline.d.ts +49 -0
  23. package/dist/builtin/decline/decline.js +1 -0
  24. package/dist/builtin/decline/index.d.ts +1 -0
  25. package/dist/builtin/decline/index.js +1 -0
  26. package/dist/builtin/escalate/escalate.d.ts +19 -0
  27. package/dist/builtin/escalate/escalate.js +1 -1
  28. package/dist/builtin/escalate/index.d.ts +1 -1
  29. package/dist/builtin/escalate/index.js +1 -1
  30. package/dist/builtin/extract/extract.d.ts +25 -0
  31. package/dist/builtin/extract/extract.js +1 -0
  32. package/dist/builtin/extract/index.d.ts +3 -0
  33. package/dist/builtin/extract/index.js +1 -0
  34. package/dist/builtin/extract/kinds.d.ts +6 -0
  35. package/dist/builtin/extract/kinds.js +1 -0
  36. package/dist/builtin/extract/readers.d.ts +7 -0
  37. package/dist/builtin/extract/readers.js +9 -0
  38. package/dist/builtin/finish/finish.d.ts +4 -0
  39. package/dist/builtin/finish/finish.js +1 -1
  40. package/dist/builtin/http/allow.d.ts +2 -0
  41. package/dist/builtin/http/allow.js +1 -1
  42. package/dist/builtin/http/hops.d.ts +10 -0
  43. package/dist/builtin/http/hops.js +1 -0
  44. package/dist/builtin/http/http.d.ts +9 -1
  45. package/dist/builtin/http/http.js +1 -1
  46. package/dist/builtin/http/index.d.ts +2 -0
  47. package/dist/builtin/http/index.js +1 -1
  48. package/dist/builtin/http/retry-after.d.ts +14 -0
  49. package/dist/builtin/http/retry-after.js +1 -0
  50. package/dist/builtin/index.d.ts +10 -6
  51. package/dist/builtin/index.js +1 -1
  52. package/dist/builtin/json/index.d.ts +1 -0
  53. package/dist/builtin/json/index.js +1 -1
  54. package/dist/builtin/json/json.js +1 -1
  55. package/dist/builtin/json/parse.d.ts +15 -0
  56. package/dist/builtin/json/parse.js +1 -0
  57. package/dist/builtin/notes/index.d.ts +1 -0
  58. package/dist/builtin/notes/index.js +1 -0
  59. package/dist/builtin/notes/notes.d.ts +45 -0
  60. package/dist/builtin/notes/notes.js +2 -0
  61. package/dist/builtin/openalex/api.d.ts +22 -0
  62. package/dist/builtin/openalex/api.js +1 -0
  63. package/dist/builtin/openalex/index.d.ts +4 -0
  64. package/dist/builtin/openalex/index.js +1 -0
  65. package/dist/builtin/openalex/openalex.d.ts +23 -0
  66. package/dist/builtin/openalex/openalex.js +1 -0
  67. package/dist/builtin/openalex/render.d.ts +2 -0
  68. package/dist/builtin/openalex/render.js +4 -0
  69. package/dist/builtin/polite.d.ts +14 -0
  70. package/dist/builtin/polite.js +1 -0
  71. package/dist/builtin/publish/index.d.ts +1 -0
  72. package/dist/builtin/publish/index.js +1 -0
  73. package/dist/builtin/publish/publish.d.ts +46 -0
  74. package/dist/builtin/publish/publish.js +1 -0
  75. package/dist/builtin/web-search/web-search.d.ts +10 -35
  76. package/dist/builtin/web-search/web-search.js +1 -1
  77. package/dist/builtin/wikidata/api.d.ts +40 -0
  78. package/dist/builtin/wikidata/api.js +1 -0
  79. package/dist/builtin/wikidata/index.d.ts +5 -0
  80. package/dist/builtin/wikidata/index.js +1 -0
  81. package/dist/builtin/wikidata/render.d.ts +13 -0
  82. package/dist/builtin/wikidata/render.js +2 -0
  83. package/dist/builtin/wikidata/wikidata.d.ts +21 -0
  84. package/dist/builtin/wikidata/wikidata.js +1 -0
  85. package/dist/bus/bus.d.ts +23 -1
  86. package/dist/bus/bus.js +1 -1
  87. package/dist/bus/group.d.ts +14 -1
  88. package/dist/bus/group.js +1 -1
  89. package/dist/bus/index.d.ts +4 -1
  90. package/dist/bus/index.js +1 -1
  91. package/dist/bus/invoke.d.ts +1 -1
  92. package/dist/bus/invoke.js +3 -1
  93. package/dist/bus/namespace.d.ts +21 -0
  94. package/dist/bus/namespace.js +1 -0
  95. package/dist/bus/once.d.ts +32 -0
  96. package/dist/bus/once.js +1 -0
  97. package/dist/bus/only.d.ts +29 -0
  98. package/dist/bus/only.js +0 -0
  99. package/dist/bus/options.d.ts +31 -0
  100. package/dist/bus/select.d.ts +0 -16
  101. package/dist/bus/select.js +1 -1
  102. package/dist/bus/spent.d.ts +16 -0
  103. package/dist/bus/spent.js +1 -0
  104. package/dist/bus/trace.d.ts +14 -1
  105. package/dist/bus/trace.js +1 -1
  106. package/dist/index.d.ts +6 -4
  107. package/dist/index.js +1 -1
  108. package/dist/internals.d.ts +8 -1
  109. package/dist/internals.js +1 -1
  110. package/dist/memories/client.d.ts +91 -0
  111. package/dist/memories/client.js +0 -0
  112. package/dist/memories/context.d.ts +5 -0
  113. package/dist/memories/context.js +1 -0
  114. package/dist/{builtin → memories}/deep-recall/deep-recall.d.ts +3 -0
  115. package/dist/memories/deep-recall/deep-recall.js +1 -0
  116. package/dist/memories/explore/explore.d.ts +18 -0
  117. package/dist/memories/explore/explore.js +7 -0
  118. package/dist/memories/explore/subgraph.d.ts +12 -0
  119. package/dist/memories/explore/subgraph.js +3 -0
  120. package/dist/memories/index.d.ts +30 -0
  121. package/dist/memories/index.js +1 -0
  122. package/dist/memories/observe/observe.d.ts +7 -0
  123. package/dist/memories/observe/observe.js +1 -0
  124. package/dist/memories/recall/recall.d.ts +42 -0
  125. package/dist/memories/recall/recall.js +1 -0
  126. package/dist/memories/recall/render.d.ts +5 -0
  127. package/dist/memories/recall/render.js +3 -0
  128. package/dist/memories/remember/remember.d.ts +49 -0
  129. package/dist/memories/remember/remember.js +1 -0
  130. package/dist/search/index.d.ts +5 -0
  131. package/dist/search/index.js +1 -0
  132. package/dist/search/retry.d.ts +6 -0
  133. package/dist/search/retry.js +1 -0
  134. package/dist/search/search.d.ts +63 -0
  135. package/dist/search/search.js +1 -0
  136. package/dist/search/searxng/index.d.ts +2 -0
  137. package/dist/search/searxng/index.js +1 -0
  138. package/dist/search/searxng/searxng.d.ts +14 -0
  139. package/dist/search/searxng/searxng.js +5 -0
  140. package/dist/search/searxng/text.d.ts +2 -0
  141. package/dist/search/searxng/text.js +3 -0
  142. package/dist/search/sonar/index.d.ts +2 -0
  143. package/dist/search/sonar/index.js +1 -0
  144. package/dist/search/sonar/sonar.d.ts +13 -0
  145. package/dist/search/sonar/sonar.js +1 -0
  146. package/dist/search/tavily/index.d.ts +4 -0
  147. package/dist/search/tavily/index.js +1 -0
  148. package/dist/search/tavily/reply.d.ts +22 -0
  149. package/dist/search/tavily/reply.js +5 -0
  150. package/dist/search/tavily/tavily.d.ts +14 -0
  151. package/dist/search/tavily/tavily.js +1 -0
  152. package/dist/testing/index.d.ts +2 -0
  153. package/dist/testing/index.js +1 -0
  154. package/dist/testing/replay.d.ts +55 -0
  155. package/dist/testing/replay.js +1 -0
  156. package/dist/testing/store.d.ts +35 -0
  157. package/dist/testing/store.js +4 -0
  158. package/dist/tool/tool.d.ts +4 -1
  159. package/dist/tool/tool.js +1 -1
  160. package/dist/types/index.d.ts +1 -1
  161. package/dist/types/result.d.ts +38 -0
  162. package/dist/types/tool.d.ts +61 -0
  163. package/docs/bogus.mdx +85 -0
  164. package/docs/builtins.mdx +156 -0
  165. package/docs/bus.mdx +90 -0
  166. package/docs/declaring.mdx +85 -0
  167. package/docs/effects.mdx +49 -0
  168. package/docs/overview.mdx +76 -0
  169. package/docs/selecting.mdx +79 -0
  170. package/docs/stored.mdx +83 -0
  171. package/docs/turns.mdx +57 -0
  172. package/package.json +22 -9
  173. package/dist/builtin/deep-recall/deep-recall.js +0 -1
  174. package/dist/builtin/write-document/commission.js +0 -13
  175. package/dist/builtin/write-document/index.d.ts +0 -6
  176. package/dist/builtin/write-document/index.js +0 -1
  177. package/dist/builtin/write-document/write-document.js +0 -1
  178. /package/dist/{builtin/write-document → agents/moa}/design.d.ts +0 -0
  179. /package/dist/{builtin/write-document → agents/moa}/design.js +0 -0
  180. /package/dist/{builtin/write-document → agents/moa}/http.d.ts +0 -0
  181. /package/dist/{builtin/write-document → agents/moa}/http.js +0 -0
  182. /package/dist/{builtin/write-document → agents/moa}/types.js +0 -0
  183. /package/dist/{builtin → memories}/deep-recall/index.d.ts +0 -0
  184. /package/dist/{builtin → memories}/deep-recall/index.js +0 -0
  185. /package/dist/{builtin/web-search → search/sonar}/reply.d.ts +0 -0
  186. /package/dist/{builtin/web-search → search/sonar}/reply.js +0 -0
package/dist/bus/group.js CHANGED
@@ -1 +1 @@
1
- import{toAnthropic as O,toMarkdown as I,toOpenAI as $}from"../wire/index.js";import{scorerFor as k}from"./score.js";import{toStep as A}from"./step.js";import{ceilingFor as M,termsIn as T}from"./terms.js";import{newTrace as x}from"./trace.js";const B=6,v=3;function D(t){return{name:t.name,description:t.description,args:[]}}function F(t){const s=new Map;for(const e of t)for(const o of e.bus.all()){const c=s.get(o.name);if(c)throw new Error(`Two buses offer a tool called "${o.name}": "${c.name}" and "${e.name}". A name has to say which one runs.`);s.set(o.name,e)}return s}function S(t){return t.flatMap(s=>{const e=s.bus.all().filter(o=>o.pinned).map(o=>o.name);return e.length>0?s.bus.declarations(e):[]})}function C(t){const s=[],e=new Set;let o=t;return{chosen:s,holds:c=>e.has(c),full:()=>s.length>=o,room:()=>t-s.length,narrowTo:c=>{o=Math.min(o,c)},take(c){e.has(c.name)||s.length>=o||(e.add(c.name),s.push(c))}}}function L(t,s,e){const o=t.flat(),c=k(o),f=o.map(l=>({declaration:l,n:c(l,s)})).sort((l,u)=>u.n-l.n);if(f.length===0||f[0].n===0)return!1;f.length>1&&f[0].n>=f[1].n*2&&e.narrowTo(e.chosen.length+v);for(const{declaration:l}of f){if(e.full())break;e.take(l)}return!0}function N(t,s){for(let e=0;!s.full();e++){let o=!1;for(const c of t){const f=c[e];if(f!==void 0&&(o=!0,s.take(f),s.full()))break}if(!o)break}}function z(t,s={}){const e=new Set;for(const n of t){if(e.has(n.name))throw new Error(`Two buses are called "${n.name}".`);e.add(n.name)}const o=F(t),c=S(t),f=new Map(t.map(n=>[n,D(n)])),m=k([...f.values()]),l=M(s.limit,B),u=n=>o.get(n),b=()=>t.flatMap(n=>n.bus.all()),p=()=>t.flatMap(n=>n.bus.declarations()),y=n=>t.map(a=>({member:a,n:m(f.get(a),n)})).sort((a,r)=>r.n-a.n),g={all:b,missing:n=>n.filter(a=>!o.has(a)),get:n=>u(n)?.bus.get(n),effectOf:n=>u(n)?.bus.effectOf(n),destructive:()=>t.flatMap(n=>n.bus.destructive()),unannotated:()=>t.flatMap(n=>n.bus.unannotated()),declarations:n=>n?t.flatMap(a=>{const r=n.filter(i=>o.get(i)===a);return r.length>0?a.bus.declarations(r):[]}):p(),anthropic:n=>O(n??p()),openai:n=>$(n??p()),markdown:(n,a)=>I(n??p(),a),select:(n="",a)=>{const r=C(M(a,l));for(const h of c)r.take(h);const i=r.room();if(i<=0)return r.chosen;const d=y(T(n)),w=d.map(({member:h})=>h.bus.select(n,i).filter(E=>!r.holds(E.name)));if(d.length>1&&d[0].n>0&&d[0].n>=d[1].n*2&&w[0].length>0){r.narrowTo(r.chosen.length+v);for(const h of w[0])r.take(h);return r.chosen}return L(w,T(n),r)||N(w,r),r.chosen},invoke:async(n,a)=>{const r=u(n);return r?r.bus.invoke(n,a):{name:n,args:a,status:"failed",output:"",error:`No tool called "${n}". Offered: ${[...o.keys()].join(", ")}`,latencyMs:0}},usage:()=>Object.assign({},...t.map(n=>n.bus.usage())),step:(n,a)=>A(n,a),trace:(n="",a)=>x(g.select(n,a),(r,i)=>g.invoke(r,i))};return g}export{z as busgroup};
1
+ import{toAnthropic as T,toMarkdown as b,toOpenAI as E}from"../wire/index.js";import{naming as N}from"./namespace.js";import{scorerFor as I}from"./score.js";import{toStep as S}from"./step.js";import{ceilingFor as $,termsIn as A}from"./terms.js";import{newTrace as j}from"./trace.js";const C=6,x=3;function L(r){return{name:r.name,description:r.description,args:[]}}function G(r,f){const a=new Map;for(const o of r)for(const c of o.bus.all()){const l=f.offered(o,c.name),w=a.get(l);if(w)throw new Error(`Two buses offer a tool called "${l}": "${w.name}" and "${o.name}". A name has to say which one runs \u2014 set \`namespace\` to name them after their bus.`);a.set(l,o)}return a}function U(r,f){return r.flatMap(a=>{const o=a.bus.all().filter(c=>c.pinned).map(c=>c.name);return o.length>0?v(a,f,a.bus.declarations(o)):[]})}const v=(r,f,a)=>a.map(o=>({...o,name:f.offered(r,o.name)}));function _(r){const f=[],a=new Set;let o=r;return{chosen:f,holds:c=>a.has(c),full:()=>f.length>=o,room:()=>r-f.length,narrowTo:c=>{o=Math.min(o,c)},take(c){a.has(c.name)||f.length>=o||(a.add(c.name),f.push(c))}}}function K(r,f,a){const o=r.flat(),c=I(o),l=o.map(d=>({declaration:d,n:c(d,f)})).sort((d,O)=>O.n-d.n);if(l.length===0||l[0].n===0)return!1;l.length>1&&l[0].n>=l[1].n*2&&a.narrowTo(a.chosen.length+x);for(const{declaration:d}of l){if(a.full())break;a.take(d)}return!0}function P(r,f){for(let a=0;!f.full();a++){let o=!1;for(const c of r){const l=c[a];if(l!==void 0&&(o=!0,f.take(l),f.full()))break}if(!o)break}}function W(r,f={}){const a=new Set;for(const n of r){if(a.has(n.name))throw new Error(`Two buses are called "${n.name}".`);a.add(n.name)}const o=N(r,f.namespace),c=G(r,o),l=U(r,o),w=new Map(r.map(n=>[n,L(n)])),d=I([...w.values()]),O=$(f.limit,C),m=n=>c.get(n),g=(n,t)=>o.owned(n,t),y=()=>r.flatMap(n=>n.bus.all().map(t=>({...t,name:o.offered(n,t.name)}))),k=()=>r.flatMap(n=>v(n,o,n.bus.declarations())),B=(n,t)=>Object.fromEntries(Object.entries(t).map(([e,u])=>[o.offered(n,e),u])),D=n=>r.map(t=>({member:t,n:d(w.get(t),n)})).sort((t,e)=>e.n-t.n),h={all:y,missing:n=>n.filter(t=>!c.has(t)),get:n=>{const t=m(n),e=t?.bus.get(g(t,n));return e&&t?{...e,name:n}:e},effectOf:n=>{const t=m(n);return t?.bus.effectOf(g(t,n))},trustOf:n=>{const t=m(n);return t?.bus.trustOf(g(t,n))},destructive:()=>r.flatMap(n=>n.bus.destructive().map(t=>o.offered(n,t))),unannotated:()=>r.flatMap(n=>n.bus.unannotated().map(t=>o.offered(n,t))),declarations:n=>n?r.flatMap(t=>{const e=n.filter(s=>c.get(s)===t);if(e.length===0)return[];const u=e.map(s=>g(t,s));return v(t,o,t.bus.declarations(u))}):k(),anthropic:n=>T(n??k()),openai:n=>E(n??k()),markdown:(n,t)=>b(n??k(),t),select:(n="",t)=>{const e=_($(t,O));for(const p of l)e.take(p);const u=e.room();if(u<=0)return e.chosen;const s=D(A(n)),i=s.map(({member:p})=>v(p,o,p.bus.select(n,u)).filter(F=>!e.holds(F.name)));if(s.length>1&&s[0].n>0&&s[0].n>=s[1].n*2&&i[0].length>0){e.narrowTo(e.chosen.length+x);for(const p of i[0])e.take(p);return e.chosen}return K(i,A(n),e)||P(i,e),e.chosen},invoke:async(n,t)=>{const e=m(n);return e?{...await e.bus.invoke(g(e,n),t),name:n}:{name:n,args:t,status:"failed",output:"",error:`No tool called "${n}". Offered: ${[...c.keys()].join(", ")}`,latencyMs:0}},usage:()=>Object.assign({},...r.map(n=>B(n,n.bus.usage()))),step:(n,t)=>S(n,t),trace:(n="",t)=>j(h.select(n,t),(e,u)=>h.invoke(e,u)),only:n=>{const t=n.filter(s=>c.has(s)),e=()=>h.declarations(t),u={...h,all:()=>y().filter(s=>t.includes(s.name)),missing:s=>s.filter(i=>!t.includes(i)),declarations:s=>s?e().filter(i=>s.includes(i.name)):e(),anthropic:s=>T(s??e()),openai:s=>E(s??e()),markdown:(s,i)=>b(s??e(),i),select:(s="",i)=>h.select(s,i).filter(M=>t.includes(M.name)),trace:(s="",i)=>j(u.select(s,i),(M,p)=>h.invoke(M,p))};return u}};return h}export{W as busgroup};
@@ -1,4 +1,7 @@
1
1
  export { type ToolBus, toolbus } from "./bus.js";
2
- export { type BusMember, busgroup } from "./group.js";
2
+ export { type BusGroupOptions, type BusMember, busgroup } from "./group.js";
3
+ export type { Namespacing } from "./namespace.js";
4
+ export type { Offering } from "./only.js";
3
5
  export type { ToolBusOptions } from "./options.js";
6
+ export { priced, spentOn } from "./spent.js";
4
7
  export { newTrace, type ToolTrace } from "./trace.js";
package/dist/bus/index.js CHANGED
@@ -1 +1 @@
1
- import{toolbus as e}from"./bus.js";import{busgroup as t}from"./group.js";import{newTrace as m}from"./trace.js";export{t as busgroup,m as newTrace,e as toolbus};
1
+ import{toolbus as e}from"./bus.js";import{busgroup as t}from"./group.js";import{priced as m,spentOn as x}from"./spent.js";import{newTrace as s}from"./trace.js";export{t as busgroup,s as newTrace,m as priced,x as spentOn,e as toolbus};
@@ -6,4 +6,4 @@ import type { Tool, ToolResult } from "../types/index.js";
6
6
  * step worth recording, not an exception that ends the run — the same argument
7
7
  * `status` and `error` exist on a rollout for.
8
8
  */
9
- export declare function invokeTool(byName: Map<string, Tool<never>>, calls: Map<string, number>, now: () => number, name: string, args: Record<string, unknown>): Promise<ToolResult>;
9
+ export declare function invokeTool(byName: Map<string, Tool<never>>, calls: Map<string, number>, now: () => number, name: string, args: Record<string, unknown>, maxOutputChars?: number): Promise<ToolResult>;
@@ -1 +1,3 @@
1
- import{FieldValidationError as d,validateFields as f}from"@spendgraph/sdk";import{readyArgs as p}from"./args.js";import{reasonFor as y,render as g}from"./output.js";async function F(n,i,r,t,s){const a=r(),e=n.get(t),o={name:t,args:s,latencyMs:0};if(!e)return{...o,status:"failed",output:"",error:`No tool called "${t}". Offered: ${[...n.keys()].join(", ")}`};const l=f(s,e.args);if(l.length>0)return{...o,status:"failed",output:"",error:new d(l).message,latencyMs:r()-a};i.set(t,(i.get(t)??0)+1);const c=p(e.args,s);try{const u=await e.run(c);return{...o,status:"completed",output:g(u),latencyMs:r()-a}}catch(u){return{...o,status:"failed",output:"",error:y(u),latencyMs:r()-a}}}export{F as invokeTool};
1
+ import{FieldValidationError as d,validateFields as y}from"@spendgraph/sdk";import{readyArgs as g}from"./args.js";import{reasonFor as h,render as p}from"./output.js";function M(r,e){if(e===void 0||r.length<=e)return{output:r};const t=Math.max(0,e);return{output:`${r.slice(0,t)}
2
+
3
+ [cut: showing the first ${t} of ${r.length} characters]`,truncated:{kept:t,of:r.length}}}function $(r){const e=r?.results;if(!Array.isArray(e))return{};const t=e.filter(s=>!!s&&typeof s.url=="string"&&s.url!=="");return t.length?{sources:t}:{}}function k(r,e){if(!r.costOf)return{};try{const t=r.costOf(e);return typeof t=="number"&&Number.isFinite(t)&&t>=0?{costMicros:t}:{}}catch{return{}}}async function A(r,e,t,s,u,f){const i=t(),n=r.get(s),c={name:s,args:u,latencyMs:0,...n?.trust?{trust:n.trust}:{}};if(!n)return{...c,status:"failed",output:"",error:`No tool called "${s}". Offered: ${[...r.keys()].join(", ")}`};const a=y(u,n.args);if(a.length>0)return{...c,status:"failed",output:"",error:new d(a).message,latencyMs:t()-i};e.set(s,(e.get(s)??0)+1);const l=g(n.args,u);try{const o=await n.run(l);return{...c,status:"completed",...M(p(o),f),latencyMs:t()-i,...k(n,o),...$(o)}}catch(o){return{...c,status:"failed",output:"",error:h(o),latencyMs:t()-i}}}export{A as invokeTool};
@@ -0,0 +1,21 @@
1
+ import type { BusMember } from "./group.js";
2
+ /** How a grouped tool is named to the model. */
3
+ export type Namespacing = boolean | ((member: string, tool: string) => string);
4
+ export interface Naming {
5
+ /** What the model is offered, given a tool's own name on its bus. */
6
+ offered(member: BusMember, tool: string): string;
7
+ /** Back to the name the owning bus knows, given a name the model used. */
8
+ owned(member: BusMember, offered: string): string;
9
+ }
10
+ /**
11
+ * Names every tool after the bus that runs it, or leaves them all alone.
12
+ *
13
+ * Off by default, because a name that says nothing about who runs it is a name
14
+ * worth fixing at the source. It is not always yours to fix: a group standing
15
+ * in front of several servers you do not own will meet two of them offering
16
+ * `search`, and refusing to start is not better than disambiguating.
17
+ *
18
+ * Built eagerly from what each bus holds, so the reverse lookup is complete
19
+ * before the first call rather than filled in as names happen to be asked for.
20
+ */
21
+ export declare function naming(members: BusMember[], how: Namespacing | undefined): Naming;
@@ -0,0 +1 @@
1
+ const d="__",p=(o,t)=>`${o}__${t}`;function u(o,t){if(!t)return{offered:(n,e)=>e,owned:(n,e)=>e};const r=typeof t=="function"?t:p,m=new Map,s=new Map;for(const n of o){const e=new Map,f=new Map;for(const a of n.bus.all()){const c=r(n.name,a.name);e.set(a.name,c),f.set(c,a.name)}m.set(n.name,e),s.set(n.name,f)}return{offered:(n,e)=>m.get(n.name)?.get(e)??e,owned:(n,e)=>s.get(n.name)?.get(e)??e}}export{u as naming};
@@ -0,0 +1,32 @@
1
+ import type { Tool, ToolResult } from "../types/index.js";
2
+ /**
3
+ * The same call again: the tool, and the arguments in a stable order.
4
+ *
5
+ * Sorted, because a model writing `{invoice, amount}` on one turn and
6
+ * `{amount, invoice}` on the next means the same call, and a key that said
7
+ * otherwise would let the second one through — which is the whole failure.
8
+ */
9
+ export declare const callKey: (name: string, args: Record<string, unknown>) => string;
10
+ /**
11
+ * Remembers what each destructive call already did, so a repeat does not do it twice.
12
+ *
13
+ * The agent runtime retries — after a timeout, a crash, a redelivery — and that
14
+ * is correct; the tool layer is where a repeat has to stop being a second
15
+ * refund. `effect` has always said which calls need this and nothing has ever
16
+ * read it: `destructive` is precisely the label for a call that is not safe to
17
+ * repeat, and `idempotent` is the label for one that is.
18
+ *
19
+ * Only completed calls are remembered. A failed one is exactly what a retry is
20
+ * for, and refusing to try again because the first attempt fell over would turn
21
+ * every transient error into a permanent one.
22
+ *
23
+ * A tool that declared no effect is not covered. Unset means nobody has said,
24
+ * which is not the same as safe — the package cannot invent the label, and
25
+ * quietly deduplicating an unlabelled call would be a guess about somebody
26
+ * else's API.
27
+ */
28
+ export declare function onceEach(): {
29
+ /** The earlier result for this exact destructive call, when there is one. */
30
+ earlier(tool: Tool<never> | undefined, name: string, args: Record<string, unknown>): ToolResult | undefined;
31
+ keep(tool: Tool<never> | undefined, result: ToolResult): void;
32
+ };
@@ -0,0 +1 @@
1
+ const r=t=>{if(t===null||typeof t!="object")return JSON.stringify(t)??"";if(Array.isArray(t))return`[${t.map(r).join(",")}]`;const n=t;return`{${Object.keys(n).sort().map(e=>`${JSON.stringify(e)}:${r(n[e])}`).join(",")}}`},c=(t,n)=>`${t}::${r(n)}`;function o(){const t=new Map;return{earlier(n,e,i){if(n?.effect==="destructive")return t.get(c(e,i))},keep(n,e){n?.effect!=="destructive"||e.status!=="completed"||t.set(c(e.name,e.args),e)}}}export{c as callKey,o as onceEach};
@@ -0,0 +1,29 @@
1
+ import type { Effect, Tool, ToolDeclaration, ToolResult } from "../types/index.js";
2
+ import type { AnthropicTool, OpenAITool } from "../wire/index.js";
3
+ import type { ToolTrace } from "./trace.js";
4
+ /**
5
+ * A bus narrowed to some of its tools.
6
+ *
7
+ * The declaring half is the half that changes: a model is shown these, and
8
+ * everything reaches the same `invoke` underneath. Written out rather than
9
+ * derived from `toolbus`, because a type that referred back to its own return
10
+ * would be circular — and because what a view promises is worth saying once.
11
+ */
12
+ export interface Offering {
13
+ /** The tools in this view, in declaration order. */
14
+ all(): Tool<never>[];
15
+ get(name: string): Tool<never> | undefined;
16
+ /** Names this view does not offer, whether or not the bus behind it has them. */
17
+ missing(names: string[]): string[];
18
+ effectOf(name: string): Effect | undefined;
19
+ declarations(names?: string[]): ToolDeclaration[];
20
+ anthropic(decls?: ToolDeclaration[]): AnthropicTool[];
21
+ openai(decls?: ToolDeclaration[]): OpenAITool[];
22
+ markdown(decls?: ToolDeclaration[], heading?: string): string;
23
+ select(query?: string, limit?: number): ToolDeclaration[];
24
+ /** Runs one, through the bus this view came from. */
25
+ invoke(name: string, args: Record<string, unknown>): Promise<ToolResult>;
26
+ /** How often each has been called on the bus behind this view. */
27
+ usage(): Record<string, number>;
28
+ trace(query?: string, limit?: number): ToolTrace;
29
+ }
File without changes
@@ -19,4 +19,35 @@ export interface ToolBusOptions {
19
19
  * often, which is why it is worth saying at construction.
20
20
  */
21
21
  warnOnOverlap?: boolean;
22
+ /**
23
+ * Longest output a tool may return, in characters. No cap by default.
24
+ *
25
+ * One tool handing back a whole document fills a window on its own, and the
26
+ * failure is silent: no error, a clean call, a clean reply, and an answer
27
+ * that is wrong in the same tone as a right one. Nothing downstream can tell
28
+ * a tool that found three matches from one that found three hundred and was
29
+ * cut after three.
30
+ *
31
+ * Cut output says so, twice: a line the model reads at the end of the text,
32
+ * and `truncated` on the result for code that needs to count it. A model told
33
+ * it is looking at part of something asks again; one that is not, answers.
34
+ *
35
+ * No default, because a cap is a statement about your context window and your
36
+ * tools, and a number chosen here would be wrong for both. The builtins that
37
+ * fetch carry their own `maxChars` for the same reason.
38
+ */
39
+ maxOutputChars?: number;
40
+ /**
41
+ * Run each destructive call once, however many times it is asked for.
42
+ *
43
+ * A repeat of a call that already completed gets the first result back
44
+ * without the tool running again, marked `repeated` so an operator can count
45
+ * it. `readonly` and `idempotent` calls run every time, which is what those
46
+ * labels mean; a tool that declared no effect is not covered.
47
+ *
48
+ * Off by default. Deduplication is scoped to one bus, so what counts as "the
49
+ * same call again" is a decision about how long a bus lives — one per run, one
50
+ * per session, one per process — and the package cannot make it for you.
51
+ */
52
+ onceEach?: boolean;
22
53
  }
@@ -1,19 +1,3 @@
1
1
  import type { Tool, ToolDeclaration } from "../types/index.js";
2
2
  import type { Scorer } from "./score.js";
3
- /**
4
- * The working set for one request: pinned, then what the query matches, then
5
- * what actually gets used.
6
- *
7
- * Relevance before usage, which is the opposite of what this did first. At a
8
- * shortlist of twelve the order was harmless; at six, three previously-used
9
- * tools take half the slots and push out the tool the query needs.
10
- *
11
- * Usage still earns its place as the tiebreaker among equal matches, and as the
12
- * fallback when nothing matches — the case where an agent would otherwise be
13
- * handed nothing.
14
- *
15
- * How many come back depends on how clearly the query matched. A single strong
16
- * match needs no company; a flat spread means the ranking does not know, and a
17
- * wider net is worth the distraction.
18
- */
19
3
  export declare function selectTools(tools: Tool<never>[], calls: Map<string, number>, declare: (t: Tool<never>) => ToolDeclaration, scoreOf: Scorer, query: string, ceiling: number): ToolDeclaration[];
@@ -1 +1 @@
1
- import{termsIn as u}from"./terms.js";function v(m,e,h,a,p,f){const d=u(p),n=[],r=t=>{!n.includes(t)&&n.length<f&&n.push(t)};for(const t of m)t.pinned&&r(t);const i=m.filter(t=>!t.pinned),o=i.map(t=>({t,n:a(t,d)})).filter(t=>t.n>0).sort((t,s)=>s.n-t.n||(e.get(s.t.name)??0)-(e.get(t.t.name)??0)),c=f-n.length,k=o.length>1&&o[0].n>=o[1].n*2,g=n.length+(k?Math.min(3,c):c);for(const{t}of o){if(n.length>=g)break;r(t)}const b=[...i].sort((t,s)=>(e.get(s.name)??0)-(e.get(t.name)??0));for(const t of b){if(n.length>=g||(e.get(t.name)??0)===0)break;r(t)}if(o.length===0)for(const t of i){if(n.length>=f)break;r(t)}return n.map(h)}export{v as selectTools};
1
+ import{termsIn as l}from"./terms.js";function w(t,o,g){if(!t.some(f=>f.needs?.length))return t;const r=[];for(const f of t){if(r.includes(f))continue;const s=(f.needs??[]).map(i=>o.get(i)).filter(i=>i!==void 0&&!r.includes(i));r.length+1+s.length>g||r.push(f,...s)}return r}function M(t,o,g,r,f,s){const i=new Map(t.map(n=>[n.name,n])),p=l(f),e=[],m=n=>{!e.includes(n)&&e.length<s&&e.push(n)};for(const n of t)n.pinned&&m(n);const d=t.filter(n=>!n.pinned),c=d.map(n=>({t:n,n:r(n,p)})).filter(n=>n.n>0).sort((n,a)=>a.n-n.n||(o.get(a.t.name)??0)-(o.get(n.t.name)??0)),u=s-e.length,k=c.length>1&&c[0].n>=c[1].n*2,h=e.length+(k?Math.min(3,u):u);for(const{t:n}of c){if(e.length>=h)break;m(n)}const b=[...d].sort((n,a)=>(o.get(a.name)??0)-(o.get(n.name)??0));for(const n of b){if(e.length>=h||(o.get(n.name)??0)===0)break;m(n)}if(c.length===0)for(const n of d){if(e.length>=s)break;m(n)}return w(e,i,s).map(g)}export{M as selectTools};
@@ -0,0 +1,16 @@
1
+ import type { ToolResult } from "../types/index.js";
2
+ /**
3
+ * What the tools themselves cost, in micro-USD.
4
+ *
5
+ * A run's token counts are the outer model's. A tool that spends on its own —
6
+ * a deep recall, a judge, a sub-agent — is not in them, so a loop that called
7
+ * three of those reports a bill that is missing most of itself. Only results
8
+ * from tools that declared a `costOf` count; the rest are not free, they are
9
+ * unmeasured, and those are different claims.
10
+ */
11
+ export declare function spentOn(results: readonly ToolResult[]): number;
12
+ /** The calls that reported a price, so an unmeasured one is visible as an absence. */
13
+ export declare function priced(results: readonly ToolResult[]): {
14
+ name: string;
15
+ costMicros: number;
16
+ }[];
@@ -0,0 +1 @@
1
+ function c(o){let t=0;for(const r of o)t+=r.costMicros??0;return t}function e(o){return o.filter(t=>t.costMicros!==void 0).map(t=>({name:t.name,costMicros:t.costMicros}))}export{e as priced,c as spentOn};
@@ -18,7 +18,12 @@ export interface ToolTrace {
18
18
  * never said — and for one that was never offered.
19
19
  */
20
20
  effectOf(name: string): Effect | undefined;
21
- /** Runs a tool and records the step. Never throws, exactly as `invoke`. */
21
+ /**
22
+ * Runs a tool this turn offered and records the step. Never throws.
23
+ *
24
+ * A name that was not offered comes back as a failed result naming what was,
25
+ * without reaching the bus — see `newTrace`.
26
+ */
22
27
  invoke(name: string, args: Record<string, unknown>): Promise<ToolResult>;
23
28
  /** The steps so far, in call order. */
24
29
  steps(): RolloutStep[];
@@ -38,5 +43,13 @@ export interface ToolTrace {
38
43
  *
39
44
  * Selection happens once, here, and the same list is what gets reported. A trace
40
45
  * cannot disagree with itself about what the model saw.
46
+ *
47
+ * It also cannot run what it did not offer. A shortlist narrows the declarations
48
+ * and used to hand `invoke` the whole bus, so a name the model produced out of
49
+ * nowhere still ran if anything on the bus happened to be called that — and the
50
+ * rollout came back with a step that had no matching entry in `offeredTools`,
51
+ * which reads as impossible. The refusal is a failed result rather than a throw,
52
+ * carrying the names that were offered, because that is an observation the model
53
+ * can correct from on its next turn; an exception is one the run dies of.
41
54
  */
42
55
  export declare function newTrace(offered: ToolDeclaration[], invoke: (name: string, args: Record<string, unknown>) => Promise<ToolResult>): ToolTrace;
package/dist/bus/trace.js CHANGED
@@ -1 +1 @@
1
- import{toAnthropic as s,toMarkdown as a,toOpenAI as c}from"../wire/index.js";import{toStep as i}from"./step.js";function h(n,r){const o=[];return{offered:n,anthropic:()=>s(n),openai:()=>c(n),markdown:t=>a(n,t),effectOf:t=>n.find(e=>e.name===t)?.effect,invoke:async(t,e)=>{const p=await r(t,e);return o.push(i(p,o.length)),p},steps:()=>[...o],record:()=>({offeredTools:n.map(t=>t.name),steps:[...o]})}}export{h as newTrace};
1
+ import{toAnthropic as p,toMarkdown as c,toOpenAI as i}from"../wire/index.js";import{toStep as u}from"./step.js";function m(t,r,o){return{name:t,args:r,status:"failed",output:"",error:`No tool called "${t}" was offered this turn. Offered: ${o.map(n=>n.name).join(", ")}`,latencyMs:0}}function h(t,r){const o=[];return{offered:t,anthropic:()=>p(t),openai:()=>i(t),markdown:n=>c(t,n),effectOf:n=>t.find(e=>e.name===n)?.effect,invoke:async(n,e)=>{const s=t.some(a=>a.name===n)?await r(n,e):m(n,e,t);return o.push(u(s,o.length)),s},steps:()=>[...o],record:()=>({offeredTools:t.map(n=>n.name),steps:[...o]})}}export{h as newTrace};
package/dist/index.d.ts CHANGED
@@ -7,10 +7,12 @@
7
7
  * converters themselves, for a caller adapting a declaration by hand.
8
8
  */
9
9
  export type { RolloutStep } from "@spendgraph/sdk";
10
- export { type ArtifactFormat, answerOf, type ClockOptions, type CodeExecOptions, CommissionAbortedError, type CommissionClient, CommissionTimeoutError, calculate, codeExec, currentTime, DEFAULT_DESIGN, type DeepRecallOptions, type DesignGuide, dateMath, deepRecall, type EscalateOptions, type EscalationRequest, escalate, type Finished, finish, type HttpOptions, httpRequest, isFinished, type JsonQueryOptions, jsonQuery, mergeDesign, type RecalledFact, type Recaller, type RecallResult, renderDesign, type Sandbox, type SandboxRequest, type SandboxResult, type SearchDepth, think, type WebSearchOptions, type WriteDocumentOptions, webSearch, writeDocument, } from "./builtin/index.js";
11
- export type { BusMember, ToolBus, ToolBusOptions, ToolTrace } from "./bus/index.js";
12
- export { busgroup, toolbus } from "./bus/index.js";
10
+ export { type ArtifactFormat, DEFAULT_DESIGN, type DesignGuide, MoaAbortedError, type MoaClient, MoaTimeoutError, mergeDesign, renderDesign, type WriteDocumentOptions, writeDocument, } from "./agents/index.js";
11
+ export { answerOf, type ClockOptions, type CodeExecOptions, calculate, codeExec, currentTime, type Declined, dateMath, dates, decline, declinedFor, type EscalateOptions, type EscalationRequest, type ExtractOptions, escalate, escalationOf, extract, type Finished, finish, type HttpOptions, httpRequest, isDeclined, isEscalated, isFinished, type JsonQueryOptions, jsonFrom, jsonQuery, type NotesOptions, type NotesStore, notes, notesStore, type OpenAlexApi, type OpenAlexOptions, openalex, type Publisher, type PublishOptions, publish, retryAfterMs, type Sandbox, type SandboxRequest, type SandboxResult, type SearchDepth, think, type Unanswerable, type WebSearchOptions, type WikidataApi, type WikidataOptions, webSearch, wikidata, } from "./builtin/index.js";
12
+ export type { BusGroupOptions, BusMember, Namespacing, Offering, ToolBus, ToolBusOptions, ToolTrace, } from "./bus/index.js";
13
+ export { busgroup, priced, spentOn, toolbus } from "./bus/index.js";
14
+ export { contextId, type DeepRecallOptions, deepRecall, type ExploreOptions, exploreMemory, type MemoriesOptions, type MemoryClient, type MemoryContext, type MemoryGraph, type MemoryKind, type MemorySet, type MemorySource, type Moment, type MomentSource, memories, type Observer, type ObserverOptions, observer, type RecalledFact, type Recaller, type RecallFormat, type RecallOptions, type RecallResult, type RememberOptions, recall, remember, } from "./memories/index.js";
13
15
  export type { BoundSpec, ToolSpec } from "./tool/index.js";
14
16
  export { bindTool, ToolDriftError, ToolNotStoredError, tool } from "./tool/index.js";
15
- export type { ArgSpec, ArgsOf, ArgValue, Effect, Tool, ToolDeclaration, ToolResult, } from "./types/index.js";
17
+ export type { ArgSpec, ArgsOf, ArgValue, Effect, Tool, ToolDeclaration, ToolResult, Trust, } from "./types/index.js";
16
18
  export type { AnthropicTool, JsonSchema, JsonSchemaProperty, OpenAITool, } from "./wire/index.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{answerOf as r,CommissionAbortedError as t,CommissionTimeoutError as i,calculate as s,codeExec as n,currentTime as m,DEFAULT_DESIGN as l,dateMath as a,deepRecall as c,escalate as u,finish as d,httpRequest as E,isFinished as f,jsonQuery as h,mergeDesign as p,renderDesign as D,think as T,webSearch as b,writeDocument as g}from"./builtin/index.js";import{busgroup as w,toolbus as S}from"./bus/index.js";import{bindTool as C,ToolDriftError as F,ToolNotStoredError as N,tool as R}from"./tool/index.js";export{t as CommissionAbortedError,i as CommissionTimeoutError,l as DEFAULT_DESIGN,F as ToolDriftError,N as ToolNotStoredError,r as answerOf,C as bindTool,w as busgroup,s as calculate,n as codeExec,m as currentTime,a as dateMath,c as deepRecall,u as escalate,d as finish,E as httpRequest,f as isFinished,h as jsonQuery,p as mergeDesign,D as renderDesign,T as think,R as tool,S as toolbus,b as webSearch,g as writeDocument};
1
+ import{DEFAULT_DESIGN as o,MoaAbortedError as t,MoaTimeoutError as i,mergeDesign as s,renderDesign as n,writeDocument as a}from"./agents/index.js";import{answerOf as c,calculate as d,codeExec as m,currentTime as p,dateMath as f,dates as u,decline as x,declinedFor as b,escalate as E,escalationOf as h,extract as D,finish as T,httpRequest as M,isDeclined as g,isEscalated as w,isFinished as F,jsonFrom as S,jsonQuery as y,notes as A,notesStore as O,openalex as j,publish as k,retryAfterMs as I,think as N,webSearch as R,wikidata as q}from"./builtin/index.js";import{busgroup as G,priced as L,spentOn as Q,toolbus as U}from"./bus/index.js";import{contextId as z,deepRecall as B,exploreMemory as C,memories as H,observer as J,recall as K,remember as P}from"./memories/index.js";import{bindTool as W,ToolDriftError as X,ToolNotStoredError as Y,tool as Z}from"./tool/index.js";export{o as DEFAULT_DESIGN,t as MoaAbortedError,i as MoaTimeoutError,X as ToolDriftError,Y as ToolNotStoredError,c as answerOf,W as bindTool,G as busgroup,d as calculate,m as codeExec,z as contextId,p as currentTime,f as dateMath,u as dates,x as decline,b as declinedFor,B as deepRecall,E as escalate,h as escalationOf,C as exploreMemory,D as extract,T as finish,M as httpRequest,g as isDeclined,w as isEscalated,F as isFinished,S as jsonFrom,y as jsonQuery,H as memories,s as mergeDesign,A as notes,O as notesStore,J as observer,j as openalex,L as priced,k as publish,K as recall,P as remember,n as renderDesign,I as retryAfterMs,Q as spentOn,N as think,Z as tool,U as toolbus,R as webSearch,q as wikidata,a as writeDocument};
@@ -4,7 +4,14 @@
4
4
  * Not in the main entry: a bus already wires all of it, and a caller reaching
5
5
  * here is building their own. Kept exported so that stays possible.
6
6
  */
7
- export { evaluate } from "./builtin/calculate/index.js";
7
+ /**
8
+ * The arithmetic behind `calculate`, and the way it renders a result.
9
+ *
10
+ * Both, because either alone is half a comparison. A rail checking a model's
11
+ * sum has to render its own the way the tool did or it flags a correct answer:
12
+ * `evaluate("0.1 + 0.2")` is `0.30000000000000004` and the tool said `0.3`.
13
+ */
14
+ export { evaluate, exact } from "./builtin/calculate/index.js";
8
15
  export { between, parseDate, shift, type Unit } from "./builtin/date/index.js";
9
16
  export { checkUrl } from "./builtin/http/index.js";
10
17
  export { readPath } from "./builtin/json/index.js";
package/dist/internals.js CHANGED
@@ -1 +1 @@
1
- import{evaluate as e}from"./builtin/calculate/index.js";import{between as p,parseDate as f,shift as m}from"./builtin/date/index.js";import{checkUrl as a}from"./builtin/http/index.js";import{readPath as c}from"./builtin/json/index.js";import{invokeTool as s}from"./bus/invoke.js";import{warnOnOverlap as v}from"./bus/overlap.js";import{scorerFor as T}from"./bus/score.js";import{selectTools as k}from"./bus/select.js";import{toStep as b}from"./bus/step.js";import{newTrace as u}from"./bus/trace.js";export{p as between,a as checkUrl,e as evaluate,s as invokeTool,u as newTrace,f as parseDate,c as readPath,T as scorerFor,k as selectTools,m as shift,b as toStep,v as warnOnOverlap};
1
+ import{evaluate as o,exact as t}from"./builtin/calculate/index.js";import{between as f,parseDate as x,shift as a}from"./builtin/date/index.js";import{checkUrl as c}from"./builtin/http/index.js";import{readPath as n}from"./builtin/json/index.js";import{invokeTool as h}from"./bus/invoke.js";import{warnOnOverlap as w}from"./bus/overlap.js";import{scorerFor as i}from"./bus/score.js";import{selectTools as O}from"./bus/select.js";import{toStep as d}from"./bus/step.js";import{newTrace as D}from"./bus/trace.js";export{f as between,c as checkUrl,o as evaluate,t as exact,h as invokeTool,D as newTrace,x as parseDate,n as readPath,i as scorerFor,O as selectTools,a as shift,d as toStep,w as warnOnOverlap};
@@ -0,0 +1,91 @@
1
+ import type { RootContextId } from "./context.js";
2
+ import type { Recaller } from "./deep-recall/deep-recall.js";
3
+ export type MemorySource = "policy" | "verified" | "tool" | "document" | "user" | "assistant" | "derived" | "system";
4
+ export type MomentSource = "policy" | "verified" | "tool" | "turn";
5
+ export type MemoryKind = "fact" | "decision" | "constraint" | "feedback" | "observation";
6
+ export interface MemoryContext {
7
+ context_id: string;
8
+ context_type: string;
9
+ context_name: string;
10
+ reference_count: number;
11
+ }
12
+ export interface RecalledItem {
13
+ locus_id: string;
14
+ context_ids: string[];
15
+ text: string;
16
+ score: number;
17
+ source?: string;
18
+ kind?: string;
19
+ created?: number;
20
+ }
21
+ export interface MemoryClient extends Recaller {
22
+ retrieveMemories(query: {
23
+ query: string;
24
+ graphId?: string;
25
+ limit?: number;
26
+ contextIds?: string[];
27
+ boostContextIds?: string[];
28
+ sources?: string[];
29
+ format?: string;
30
+ }): Promise<{
31
+ items_found: number;
32
+ items?: RecalledItem[];
33
+ }>;
34
+ storeEventsBatch(items: {
35
+ event_kind: string;
36
+ context_id?: string;
37
+ source?: MemorySource;
38
+ extends?: string[];
39
+ related_to?: string[];
40
+ reinforces?: string[];
41
+ contradicts?: string[];
42
+ payload: Record<string, unknown>;
43
+ }[], graphId?: string): Promise<{
44
+ stored: number;
45
+ filtered: number;
46
+ failed: number;
47
+ results: {
48
+ status: "recorded" | "filtered" | "error";
49
+ event_id?: string;
50
+ relevance?: "high" | "medium" | "low";
51
+ error?: string;
52
+ }[];
53
+ }>;
54
+ searchContexts(query: string, graphId?: string, options?: {
55
+ context_type?: string;
56
+ page_size?: number;
57
+ include?: string;
58
+ format?: string;
59
+ }): Promise<{
60
+ contexts: MemoryContext[];
61
+ total: number;
62
+ relationships_text?: string;
63
+ }>;
64
+ listContextTypes(graphId?: string): Promise<{
65
+ context_types: {
66
+ context_type: string;
67
+ count: number;
68
+ }[];
69
+ total: number;
70
+ }>;
71
+ getContextGraph(options: {
72
+ graphId?: string;
73
+ contextType: string;
74
+ contextName: string;
75
+ depth?: number;
76
+ }): Promise<unknown>;
77
+ observe(request: {
78
+ graphId?: string;
79
+ source: MomentSource;
80
+ payload: string | Record<string, unknown>;
81
+ stream?: string;
82
+ observedAt?: number;
83
+ }): Promise<{
84
+ observed: boolean;
85
+ }>;
86
+ }
87
+ export interface MemoryGraph {
88
+ client: MemoryClient;
89
+ graphId?: string;
90
+ rootContextId?: RootContextId;
91
+ }
File without changes
@@ -0,0 +1,5 @@
1
+ export declare function contextId(raw: string, defaultType?: string): string;
2
+ export declare const contextIds: (raw: string[] | undefined, defaultType?: string) => string[] | undefined;
3
+ export type RootContextId = string | (() => string | undefined);
4
+ export declare function rootOf(rootContextId: RootContextId | undefined): string | undefined;
5
+ export declare const fixedRoot: (rootContextId: RootContextId | undefined) => string | undefined;
@@ -0,0 +1 @@
1
+ const r="topic",f=120,c=e=>e.toLowerCase().replace(/[^a-z0-9]+/g,"_").replace(/^_+|_+$/g,"");function o(e,n=r){const t=e.indexOf(":"),i=c(t<0?n:e.slice(0,t)),s=c(t<0?e:e.slice(t+1));if(!s)throw new Error(`"${e}" names no context; write it as type:name, like person:alice.`);return`${i}:${s}`.slice(0,120)}const p=(e,n)=>e?.length?e.map(t=>o(t,n)):void 0;function u(e){if(e===void 0)return;const n=typeof e=="function"?e():e;if(!n)throw new Error("No root context id is set for this run, so memory stays closed.");return o(n)}const d=e=>typeof e=="string"?o(e):void 0;export{o as contextId,p as contextIds,d as fixedRoot,u as rootOf};
@@ -1,3 +1,4 @@
1
+ import { type RootContextId } from "../context.js";
1
2
  /** One piece of evidence, with where it came from. */
2
3
  export interface RecalledFact {
3
4
  text: string;
@@ -41,6 +42,8 @@ export interface DeepRecallOptions {
41
42
  client: Recaller;
42
43
  /** Graph the walk runs over. Unset, the client's own default is used. */
43
44
  graphId?: string;
45
+ /** Context the walk starts from, fixed or read from run state on each call. */
46
+ rootContextId?: RootContextId;
44
47
  /** Longest evidence list handed back. Default 20. */
45
48
  maxFacts?: number;
46
49
  }
@@ -0,0 +1 @@
1
+ import{tool as c}from"../../tool/index.js";import{rootOf as d}from"../context.js";const l=20;function h(t){const o=t.maxFacts??l;return c({name:"deep_recall",description:"Searches your own knowledge base and returns an answer with the evidence it rests on. A walker follows linked contexts, so it answers questions spread across several notes \u2014 what do we know about X, what was decided and why. Ask one focused thing. Prefer it over a web search whenever the answer could already be in your records.",effect:"readonly",needs:["recall"],args:[{name:"question",type:"string",required:!0,maxLength:1e3,description:"One focused question, not a conversation and not several at once."},{name:"context_ids",type:"list",required:!1,description:"Contexts to start the walk from, as type:name \u2014 take them from the contexts of an earlier result. A hint, not a filter; the walk may go elsewhere."}],costOf:a=>a.costMicroUsd,run:async({question:a,context_ids:r})=>{const n=d(t.rootContextId),s=n?[...new Set([n,...r??[]])]:r,e=await t.client.deepRecall({question:a,...t.graphId?{graphId:t.graphId}:{},...s?.length?{contextIds:s}:{}});return{summary:e.summary,facts:e.facts.slice(0,o),truncated:e.facts.length>o,contextsWalked:e.contexts_walked,coverage:e.coverage,fallback:e.fallback,costMicroUsd:Math.round(e.usage.cost_usd*1e6)}}})}export{h as deepRecall};
@@ -0,0 +1,18 @@
1
+ import type { MemoryGraph } from "../client.js";
2
+ export interface ExploreOptions extends MemoryGraph {
3
+ limit?: number;
4
+ depth?: number;
5
+ }
6
+ export declare function exploreMemory(opts: ExploreOptions): import("../../index.js").Tool<import("../../index.js").ArgsOf<readonly [{
7
+ readonly name: "query";
8
+ readonly type: "string";
9
+ readonly required: false;
10
+ readonly maxLength: 200;
11
+ readonly description: "Part of a context name, like pric or alice. Leave out to list what is there.";
12
+ }, {
13
+ readonly name: "type";
14
+ readonly type: "string";
15
+ readonly required: false;
16
+ readonly maxLength: 60;
17
+ readonly description: "Only contexts of this type, like person or decision.";
18
+ }]>>;
@@ -0,0 +1,7 @@
1
+ import{tool as f}from"../../tool/index.js";import{fixedRoot as g,rootOf as y}from"../context.js";import{drawSubgraph as w,readSubgraph as _}from"./subgraph.js";const d=20,$=3,L=t=>`${t} note${t===1?"":"s"}`,l=t=>t.length===0?"Memory is empty: no contexts yet.":`Context types: ${t.map(e=>`${e.context_type} (${e.count})`).join(", ")}.`,m=t=>t.map(e=>`- ${e.context_id} (${L(e.reference_count)})`).join(`
2
+ `),I=t=>{const e=new Map;for(const o of t)e.set(o.context_type,(e.get(o.context_type)??0)+1);return[...e].map(([o,r])=>({context_type:o,count:r}))},C=(t,e,o)=>t.filter(r=>!o||r.context_type===o).filter(r=>!e||r.context_id.toLowerCase().includes(e.toLowerCase())),p=t=>`No contexts match "${t}". Try a shorter stem, or no query to list the types.`;function M(t){const e=t.rootContextId!==void 0,o=g(t.rootContextId)??"your root",r=e?`Shows what is filed under ${o} and how it links up, without reading the notes themselves. With no query it lists the contexts in that subtree and their links. With a query it narrows to the contexts whose name contains it.`:"Shows what is filed in your own memory and how it links up, without reading the notes themselves. With no query it lists the context types in use, which is how to learn the filing scheme before you remember something. With a query it finds matching contexts and draws their relationships.",x=async(n,i,s)=>{const c=n.indexOf(":"),a=_(await t.client.getContextGraph({contextType:n.slice(0,c),contextName:n.slice(c+1),depth:t.depth??$,...t.graphId?{graphId:t.graphId}:{}})),h=C(a.nodes,i,s).slice(0,t.limit??d);return h.length===0?i?p(i):`Nothing is filed under ${n} yet.`:`${l(I(h))}
3
+
4
+ ${w(h,a.edges)}`},u=async(n,i)=>{if(!n?.trim()){const a=await t.client.listContextTypes(t.graphId);return l(a.context_types)}const s=await t.client.searchContexts(n,t.graphId,{page_size:t.limit??d,include:"relationships",format:"mindmap",...i?{context_type:i}:{}});if(s.contexts.length===0)return p(n);const c=s.relationships_text?.trim();return c?`${m(s.contexts)}
5
+
6
+ Links:
7
+ ${c}`:m(s.contexts)};return f({name:"explore_memory",effect:"readonly",description:r,args:[{name:"query",type:"string",required:!1,maxLength:200,description:"Part of a context name, like pric or alice. Leave out to list what is there."},{name:"type",type:"string",required:!1,maxLength:60,description:"Only contexts of this type, like person or decision."}],run:({query:n,type:i})=>{const s=y(t.rootContextId);return s?x(s,n?.trim(),i):u(n?.trim(),i)}})}export{M as exploreMemory};
@@ -0,0 +1,12 @@
1
+ import type { MemoryContext } from "../client.js";
2
+ export interface SubgraphEdge {
3
+ from: string;
4
+ to: string;
5
+ link_type: string;
6
+ }
7
+ export interface Subgraph {
8
+ nodes: MemoryContext[];
9
+ edges: SubgraphEdge[];
10
+ }
11
+ export declare function readSubgraph(raw: unknown): Subgraph;
12
+ export declare const drawSubgraph: (nodes: MemoryContext[], edges: SubgraphEdge[]) => string;
@@ -0,0 +1,3 @@
1
+ const c=t=>typeof t=="object"&&t!==null,o=t=>typeof t=="string"?t:"",s=t=>{if(!c(t)||typeof t.context_id!="string")return null;const n=t.context_id.indexOf(":");return{context_id:t.context_id,context_type:o(t.context_type)||t.context_id.slice(0,n),context_name:o(t.context_name)||t.context_id.slice(n+1),reference_count:typeof t.reference_count=="number"?t.reference_count:0}},d=t=>{if(!c(t))return null;const n=o(t.from)||o(t.from_context_id),e=o(t.to)||o(t.to_context_id);return n&&e?{from:n,to:e,link_type:o(t.link_type)||"related_to"}:null};function p(t){const n=c(t)&&c(t.graph)?t.graph:t;if(!c(n))return{nodes:[],edges:[]};const e=Array.isArray(n.nodes)?n.nodes.map(s):[],i=Array.isArray(n.edges)?n.edges.map(d):[];return{nodes:e.filter(r=>r!==null),edges:i.filter(r=>r!==null)}}const _={extends:"extended_by",reinforces:"reinforced_by",contradicts:"contradicted_by",related_to:"related_to"},f=(t,n)=>[...n.filter(e=>e.from===t).map(e=>`${e.link_type} \u2192 ${e.to}`),...n.filter(e=>e.to===t).map(e=>`${_[e.link_type]??e.link_type} \u2190 ${e.from}`)],l=t=>t.map((n,e)=>` ${e===t.length-1?"\u2514\u2500":"\u251C\u2500"} ${n}`),x=(t,n)=>t.map(e=>[e.context_id,...l(f(e.context_id,n))].join(`
2
+ `)).join(`
3
+ `);export{x as drawSubgraph,p as readSubgraph};
@@ -0,0 +1,30 @@
1
+ import type { Tool } from "../types/index.js";
2
+ import type { MemoryClient, MemorySource } from "./client.js";
3
+ import type { RootContextId } from "./context.js";
4
+ import { type Observer } from "./observe/observe.js";
5
+ import { type RecallFormat } from "./recall/recall.js";
6
+ export type { MemoryClient, MemoryContext, MemoryGraph, MemoryKind, MemorySource, MomentSource, } from "./client.js";
7
+ export { contextId, type RootContextId } from "./context.js";
8
+ export { type DeepRecallOptions, deepRecall, type RecalledFact, type Recaller, type RecallResult, } from "./deep-recall/index.js";
9
+ export { type ExploreOptions, exploreMemory } from "./explore/explore.js";
10
+ export { type Moment, type Observer, type ObserverOptions, observer, } from "./observe/observe.js";
11
+ export { type RecallFormat, type RecallOptions, recall } from "./recall/recall.js";
12
+ export { type RememberOptions, remember } from "./remember/remember.js";
13
+ export interface MemoriesOptions {
14
+ client: MemoryClient;
15
+ graphId?: string;
16
+ rootContextId?: RootContextId;
17
+ source?: MemorySource;
18
+ defaultContextType?: string;
19
+ recallFormat?: RecallFormat;
20
+ recallLimit?: number;
21
+ /** Let `recall` say which notes a later one superseded. See `RecallOptions`. */
22
+ supersede?: boolean;
23
+ stream?: string;
24
+ maxFacts?: number;
25
+ }
26
+ export interface MemorySet {
27
+ tools: Tool<never>[];
28
+ observe: Observer;
29
+ }
30
+ export declare function memories(opts: MemoriesOptions): MemorySet;
@@ -0,0 +1 @@
1
+ import{deepRecall as a}from"./deep-recall/index.js";import{exploreMemory as l}from"./explore/explore.js";import{observer as c}from"./observe/observe.js";import{recall as n}from"./recall/recall.js";import{remember as x}from"./remember/remember.js";import{contextId as C}from"./context.js";import{deepRecall as g}from"./deep-recall/index.js";import{exploreMemory as v}from"./explore/explore.js";import{observer as T}from"./observe/observe.js";import{recall as R}from"./recall/recall.js";import{remember as j}from"./remember/remember.js";function s(e){const r={client:e.client,...e.graphId?{graphId:e.graphId}:{},...e.rootContextId!==void 0?{rootContextId:e.rootContextId}:{}},o=e.defaultContextType,t=[n({...r,format:e.recallFormat,limit:e.recallLimit,...e.supersede?{supersede:!0}:{},defaultContextType:o}),a({...r,maxFacts:e.maxFacts}),x({...r,source:e.source,defaultContextType:o}),l(r)],m=c({...r,stream:e.stream});return{tools:t,observe:m}}export{C as contextId,g as deepRecall,v as exploreMemory,s as memories,T as observer,R as recall,j as remember};
@@ -0,0 +1,7 @@
1
+ import type { MemoryGraph, MomentSource } from "../client.js";
2
+ export type Moment = string | Record<string, unknown>;
3
+ export type Observer = (moment: Moment, source?: MomentSource) => Promise<boolean>;
4
+ export interface ObserverOptions extends MemoryGraph {
5
+ stream?: string;
6
+ }
7
+ export declare function observer(opts: ObserverOptions): Observer;
@@ -0,0 +1 @@
1
+ const t="turn";function c(r){return async(e,a=t)=>{const{observed:n}=await r.client.observe({source:a,payload:e,...r.graphId?{graphId:r.graphId}:{},...r.stream?{stream:r.stream}:{}});return n}}export{c as observer};
@@ -0,0 +1,42 @@
1
+ import type { MemoryGraph } from "../client.js";
2
+ import { type RecallFormat } from "./render.js";
3
+ export type { RecallFormat } from "./render.js";
4
+ export interface RecallOptions extends MemoryGraph {
5
+ format?: RecallFormat;
6
+ limit?: number;
7
+ sources?: string[];
8
+ defaultContextType?: string;
9
+ /**
10
+ * Say which notes a later one superseded, rather than returning both flat.
11
+ *
12
+ * `remember` takes a `contradicts` link, and without this nothing downstream
13
+ * ever reads it: a recall hands back the old plan and the new plan as two
14
+ * rows in score order, and the model answers with whichever scored higher.
15
+ * The graph knew which one won; the answer did not.
16
+ *
17
+ * Off by default because it costs a second read — the subtree under
18
+ * `rootContextId` — on every recall, and because it needs that root to have
19
+ * a subtree to read. Without a root there is nothing to fetch and the column
20
+ * is left off rather than filled with blanks.
21
+ */
22
+ supersede?: boolean;
23
+ }
24
+ export declare function recall(opts: RecallOptions): import("../../index.js").Tool<import("../../index.js").ArgsOf<readonly [{
25
+ readonly name: "question";
26
+ readonly type: "string";
27
+ readonly required: true;
28
+ readonly maxLength: 1000;
29
+ readonly description: "What you want to know, in a sentence.";
30
+ }, {
31
+ readonly name: "context_ids";
32
+ readonly type: "list";
33
+ readonly required: false;
34
+ readonly description: string;
35
+ }, {
36
+ readonly name: "limit";
37
+ readonly type: "number";
38
+ readonly required: false;
39
+ readonly min: 1;
40
+ readonly max: 50;
41
+ readonly description: `Most notes to return. Default ${number}.`;
42
+ }]>>;