@spendgraph/tools 0.7.0 → 0.8.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 (71) hide show
  1. package/dist/builtin/index.d.ts +1 -0
  2. package/dist/builtin/index.js +1 -1
  3. package/dist/builtin/openalex/api.d.ts +8 -4
  4. package/dist/builtin/openalex/api.js +1 -1
  5. package/dist/builtin/openalex/index.d.ts +0 -1
  6. package/dist/builtin/openalex/index.js +1 -1
  7. package/dist/builtin/openalex/openalex.d.ts +30 -17
  8. package/dist/builtin/openalex/openalex.js +1 -1
  9. package/dist/builtin/paper-search/index.d.ts +1 -0
  10. package/dist/builtin/paper-search/index.js +1 -0
  11. package/dist/builtin/paper-search/paper-search.d.ts +38 -0
  12. package/dist/builtin/paper-search/paper-search.js +3 -0
  13. package/dist/builtin/polite.d.ts +1 -0
  14. package/dist/builtin/polite.js +1 -1
  15. package/dist/builtin/publish/publish.d.ts +1 -1
  16. package/dist/builtin/wikidata/wikidata.d.ts +3 -1
  17. package/dist/builtin/wikidata/wikidata.js +1 -1
  18. package/dist/bus/output.d.ts +0 -17
  19. package/dist/bus/output.js +2 -2
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +1 -1
  22. package/dist/papers/consensus/consensus.d.ts +12 -0
  23. package/dist/papers/consensus/consensus.js +1 -0
  24. package/dist/papers/consensus/index.d.ts +4 -0
  25. package/dist/papers/consensus/index.js +1 -0
  26. package/dist/papers/consensus/reply.d.ts +24 -0
  27. package/dist/papers/consensus/reply.js +1 -0
  28. package/dist/papers/every.d.ts +6 -0
  29. package/dist/papers/every.js +1 -0
  30. package/dist/papers/index.d.ts +11 -0
  31. package/dist/papers/index.js +1 -0
  32. package/dist/papers/openalex/index.d.ts +2 -0
  33. package/dist/papers/openalex/index.js +1 -0
  34. package/dist/papers/openalex/openalex.d.ts +8 -0
  35. package/dist/papers/openalex/openalex.js +1 -0
  36. package/dist/papers/papers.d.ts +54 -0
  37. package/dist/papers/papers.js +1 -0
  38. package/dist/{builtin/openalex → papers}/render.d.ts +1 -1
  39. package/dist/papers/render.js +4 -0
  40. package/dist/papers/semantic-scholar/index.d.ts +4 -0
  41. package/dist/papers/semantic-scholar/index.js +1 -0
  42. package/dist/papers/semantic-scholar/reply.d.ts +29 -0
  43. package/dist/papers/semantic-scholar/reply.js +1 -0
  44. package/dist/papers/semantic-scholar/semantic-scholar.d.ts +8 -0
  45. package/dist/papers/semantic-scholar/semantic-scholar.js +1 -0
  46. package/dist/search/every.d.ts +6 -0
  47. package/dist/search/every.js +4 -0
  48. package/dist/search/index.d.ts +4 -2
  49. package/dist/search/index.js +1 -1
  50. package/dist/search/search.d.ts +6 -0
  51. package/dist/search/searxng/searxng.js +3 -3
  52. package/dist/search/sonar/sonar.js +1 -1
  53. package/dist/search/tavily/tavily.js +1 -1
  54. package/dist/tool/tool.d.ts +4 -0
  55. package/dist/tool/tool.js +1 -1
  56. package/dist/types/tool.d.ts +13 -0
  57. package/docs/builtins.mdx +65 -4
  58. package/package.json +10 -4
  59. package/dist/agents/index.d.ts +0 -1
  60. package/dist/agents/index.js +0 -1
  61. package/dist/agents/moa/design.d.ts +0 -49
  62. package/dist/agents/moa/design.js +0 -5
  63. package/dist/agents/moa/http.d.ts +0 -34
  64. package/dist/agents/moa/http.js +0 -1
  65. package/dist/agents/moa/index.d.ts +0 -74
  66. package/dist/agents/moa/index.js +0 -1
  67. package/dist/agents/moa/moa.d.ts +0 -56
  68. package/dist/agents/moa/moa.js +0 -13
  69. package/dist/agents/moa/types.d.ts +0 -33
  70. package/dist/agents/moa/types.js +0 -0
  71. package/dist/builtin/openalex/render.js +0 -4
@@ -10,6 +10,7 @@ export { checkUrl, type HttpOptions, httpRequest, retryAfterMs } from "./http/in
10
10
  export { type JsonQueryOptions, jsonFrom, jsonQuery } from "./json/index.js";
11
11
  export { type NotesOptions, type NotesStore, notes, notesStore } from "./notes/index.js";
12
12
  export { type OpenAlexApi, type OpenAlexOptions, openalex } from "./openalex/index.js";
13
+ export { type PaperSearchOptions, paperSearch } from "./paper-search/index.js";
13
14
  export { type Publisher, type PublishOptions, publish } from "./publish/index.js";
14
15
  export { think } from "./think/index.js";
15
16
  export { type SearchDepth, type WebSearchOptions, webSearch } from "./web-search/index.js";
@@ -1 +1 @@
1
- import{calculate as o,evaluate as t}from"./calculate/index.js";import{currentTime as a}from"./clock/index.js";import{codeExec as x}from"./code-exec/index.js";import{dateMath as s,dates as i}from"./date/index.js";import{decline as n,declinedFor as l,isDeclined as d}from"./decline/index.js";import{escalate as u,escalationOf as k,isEscalated as w}from"./escalate/index.js";import{extract as b}from"./extract/index.js";import{answerOf as y,finish as E,isFinished as M}from"./finish/index.js";import{checkUrl as S,httpRequest as q,retryAfterMs as v}from"./http/index.js";import{jsonFrom as D,jsonQuery as Q}from"./json/index.js";import{notes as T,notesStore as U}from"./notes/index.js";import{openalex as z}from"./openalex/index.js";import{publish as C}from"./publish/index.js";import{think as H}from"./think/index.js";import{webSearch as J}from"./web-search/index.js";import{wikidata as L}from"./wikidata/index.js";export{y as answerOf,o as calculate,S as checkUrl,x as codeExec,a as currentTime,s as dateMath,i as dates,n as decline,l as declinedFor,u as escalate,k as escalationOf,t as evaluate,b as extract,E as finish,q as httpRequest,d as isDeclined,w as isEscalated,M as isFinished,D as jsonFrom,Q as jsonQuery,T as notes,U as notesStore,z as openalex,C as publish,v as retryAfterMs,H as think,J as webSearch,L as wikidata};
1
+ import{calculate as o,evaluate as t}from"./calculate/index.js";import{currentTime as a}from"./clock/index.js";import{codeExec as x}from"./code-exec/index.js";import{dateMath as s,dates as c}from"./date/index.js";import{decline as n,declinedFor as l,isDeclined as d}from"./decline/index.js";import{escalate as u,escalationOf as k,isEscalated as w}from"./escalate/index.js";import{extract as S}from"./extract/index.js";import{answerOf as j,finish as y,isFinished as E}from"./finish/index.js";import{checkUrl as O,httpRequest as q,retryAfterMs as v}from"./http/index.js";import{jsonFrom as D,jsonQuery as Q}from"./json/index.js";import{notes as T,notesStore as U}from"./notes/index.js";import{openalex as z}from"./openalex/index.js";import{paperSearch as C}from"./paper-search/index.js";import{publish as H}from"./publish/index.js";import{think as J}from"./think/index.js";import{webSearch as L}from"./web-search/index.js";import{wikidata as P}from"./wikidata/index.js";export{j as answerOf,o as calculate,O as checkUrl,x as codeExec,a as currentTime,s as dateMath,c as dates,n as decline,l as declinedFor,u as escalate,k as escalationOf,t as evaluate,S as extract,y as finish,q as httpRequest,d as isDeclined,w as isEscalated,E as isFinished,D as jsonFrom,Q as jsonQuery,T as notes,U as notesStore,z as openalex,C as paperSearch,H as publish,v as retryAfterMs,J as think,L as webSearch,P as wikidata};
@@ -1,3 +1,4 @@
1
+ import { type PaperFilters } from "../../papers/papers.js";
1
2
  import { type PoliteOptions } from "../polite.js";
2
3
  export interface Paper {
3
4
  title: string;
@@ -9,12 +10,15 @@ export interface Paper {
9
10
  pdf: string | null;
10
11
  abstract: string;
11
12
  }
13
+ export interface Works {
14
+ papers: Paper[];
15
+ costMicroUsd?: number;
16
+ }
12
17
  export interface OpenAlexApi {
13
- search(query: string, limit: number): Promise<Paper[]>;
18
+ search(query: string, limit: number, filters?: PaperFilters): Promise<Works>;
14
19
  }
15
- export interface ApiOptions extends Omit<PoliteOptions, "userAgent"> {
16
- /** Your address, sent as `mailto`; OpenAlex answers named callers from a faster pool. */
17
- mailto?: string;
20
+ export interface ApiOptions extends Omit<PoliteOptions, "userAgent" | "headers"> {
21
+ apiKey?: string;
18
22
  }
19
23
  /** OpenAlex stores an abstract as word → positions; this puts the words back in order. */
20
24
  export declare function abstractOf(index: Record<string, number[]> | null | undefined): string;
@@ -1 +1 @@
1
- import{politeGet as n}from"../polite.js";const i="https://api.openalex.org/works",c="spendgraph-tools (https://spendgraph.locusgraph.com)",l=["id","doi","title","publication_year","cited_by_count","authorships","primary_location","open_access","abstract_inverted_index"].join(",");function p(t){if(!t)return"";const e=[];for(const[o,s]of Object.entries(t))for(const r of s)e[r]=o;return e.filter(o=>o!==void 0).join(" ")}function u(t){return{title:t.title?.trim()||"(untitled)",year:t.publication_year??null,authors:(t.authorships??[]).flatMap(e=>e.author?.display_name?[e.author.display_name]:[]),venue:t.primary_location?.source?.display_name??null,citations:t.cited_by_count??0,doi:t.doi?.replace(/^https?:\/\/doi\.org\//,"")??null,pdf:t.open_access?.oa_url??t.primary_location?.pdf_url??null,abstract:p(t.abstract_inverted_index)}}function h(t={}){const e=n({...t,userAgent:c});return{async search(o,s){const r=new URL(i);r.searchParams.set("search",o),r.searchParams.set("per-page",String(s)),r.searchParams.set("select",l),t.mailto&&r.searchParams.set("mailto",t.mailto);const a=await e(r);if(!a.ok)throw new Error(`OpenAlex answered ${a.status}.`);return((await a.json()).results??[]).map(u)}}}export{p as abstractOf,h as openAlexApi};
1
+ import{microUsd as u}from"../../papers/papers.js";import{politeGet as p}from"../polite.js";const d="https://api.openalex.org/works",f="spendgraph-tools (https://spendgraph.locusgraph.com)",_=/[?*]/g;function h(e){return e.replace(_," ").replace(/\s+/g," ").trim()}const m=["id","doi","title","publication_year","cited_by_count","authorships","primary_location","open_access","abstract_inverted_index"].join(",");function y(e){if(!e)return"";const t=[];for(const[n,s]of Object.entries(e))for(const o of s)t[o]=n;return t.filter(n=>n!==void 0).join(" ")}function b(e){return{title:e.title?.trim()||"(untitled)",year:e.publication_year??null,authors:(e.authorships??[]).flatMap(t=>t.author?.display_name?[t.author.display_name]:[]),venue:e.primary_location?.source?.display_name||null,citations:e.cited_by_count??0,doi:e.doi?.replace(/^https?:\/\/doi\.org\//,"")||null,pdf:e.open_access?.oa_url||e.primary_location?.pdf_url||null,abstract:y(e.abstract_inverted_index)}}function g(e){if(!e)return null;const{yearMin:t,yearMax:n,openAccess:s,minCitations:o}=e,r=[t===void 0?null:`publication_year:>${t-1}`,n===void 0?null:`publication_year:<${n+1}`,o===void 0?null:`cited_by_count:>${o-1}`,s?"is_oa:true":null].filter(a=>a!==null);return r.length>0?r.join(","):null}function j(e={}){const t=p({...e,userAgent:f,...e.apiKey?{headers:{authorization:`Bearer ${e.apiKey}`}}:{}});return{async search(n,s,o){const r=new URL(d);r.searchParams.set("search",h(n)),r.searchParams.set("per-page",String(s)),r.searchParams.set("select",m);const a=g(o);a&&r.searchParams.set("filter",a);const i=await t(r);if(!i.ok)throw new Error(`OpenAlex answered ${i.status}.`);const c=await i.json(),l=u(c.meta?.cost_usd);return{papers:(c.results??[]).map(b),...l===void 0?{}:{costMicroUsd:l}}}}}export{y as abstractOf,j as openAlexApi};
@@ -1,4 +1,3 @@
1
1
  export type { ApiOptions, OpenAlexApi, Paper } from "./api.js";
2
2
  export { abstractOf, openAlexApi } from "./api.js";
3
3
  export { type OpenAlexOptions, openalex } from "./openalex.js";
4
- export { rendered } from "./render.js";
@@ -1 +1 @@
1
- import{abstractOf as o,openAlexApi as p}from"./api.js";import{openalex as x}from"./openalex.js";import{rendered as a}from"./render.js";export{o as abstractOf,p as openAlexApi,x as openalex,a as rendered};
1
+ import{abstractOf as p,openAlexApi as r}from"./api.js";import{openalex as x}from"./openalex.js";export{p as abstractOf,r as openAlexApi,x as openalex};
@@ -1,23 +1,36 @@
1
- import { type ApiOptions, type OpenAlexApi } from "./api.js";
2
- export interface OpenAlexOptions extends ApiOptions {
3
- /** Papers returned. Default 5. */
4
- maxResults?: number;
5
- /** Abstract kept per paper. Default 400 characters. */
1
+ import { type OpenAlexPapersOptions } from "../../papers/openalex/index.js";
2
+ export interface OpenAlexOptions extends OpenAlexPapersOptions {
6
3
  maxAbstractChars?: number;
7
- /** Injected for tests, in place of the call to OpenAlex. */
8
- api?: OpenAlexApi;
9
4
  }
10
- /**
11
- * Papers on a topic from OpenAlex, as text — title, authors, venue, how often
12
- * cited, a DOI, a PDF when one is open, and the start of the abstract.
13
- *
14
- * Free and unauthenticated. For what the literature says; not for anything
15
- * recent, commercial, or outside a published paper.
16
- */
17
5
  export declare function openalex(opts?: OpenAlexOptions): import("../../index.js").Tool<import("../../index.js").ArgsOf<readonly [{
18
- readonly name: "question";
6
+ readonly name: "query";
19
7
  readonly type: "string";
20
8
  readonly required: true;
21
- readonly maxLength: 300;
22
- readonly description: "The topic, as a phrase a paper title or abstract would contain.";
9
+ readonly maxLength: 1000;
10
+ readonly description: string;
11
+ }, {
12
+ readonly name: "year_min";
13
+ readonly type: "number";
14
+ readonly required: false;
15
+ readonly min: 1500;
16
+ readonly max: 2200;
17
+ readonly description: "Earliest year of publication. Leave unset for any.";
18
+ }, {
19
+ readonly name: "year_max";
20
+ readonly type: "number";
21
+ readonly required: false;
22
+ readonly min: 1500;
23
+ readonly max: 2200;
24
+ readonly description: "Latest year of publication. Leave unset for any.";
25
+ }, {
26
+ readonly name: "min_citations";
27
+ readonly type: "number";
28
+ readonly required: false;
29
+ readonly min: 0;
30
+ readonly description: "Only papers cited at least this often. Raises confidence and hides recent work.";
31
+ }, {
32
+ readonly name: "open_access";
33
+ readonly type: "boolean";
34
+ readonly required: false;
35
+ readonly description: "Only papers whose full text can be read without a subscription.";
23
36
  }]>>;
@@ -1 +1 @@
1
- import{tool as i}from"../../tool/index.js";import{openAlexApi as c}from"./api.js";import{rendered as h}from"./render.js";const p=5,m=400;function l(t={}){const a=t.api??c(t),n=t.maxResults??p,o=t.maxAbstractChars??m;return i({name:"paper_search",effect:"readonly",trust:"external",description:"Finds published papers on a topic and returns them as text: title, authors, venue, citation count, DOI, an open PDF when there is one, and the start of the abstract. Use it for what research has found or measured, and cite the DOI. Not for prices, products, news or anything from the last few months.",args:[{name:"question",type:"string",required:!0,maxLength:300,description:"The topic, as a phrase a paper title or abstract would contain."}],run:async({question:s})=>{const e=s.trim();if(!e)throw new Error("Name the topic to search for.");const r=await a.search(e,n);if(r.length===0)throw new Error(`OpenAlex has no papers matching "${e}".`);return h(e,r,o)}})}export{l as openalex};
1
+ import{openAlexPapers as e}from"../../papers/openalex/index.js";import{paperSearch as t}from"../paper-search/index.js";const s=5,o=400;function n(r={}){const a=r.maxResults??s;return t({papers:e({...r,maxResults:a}),maxResults:a,maxAbstractChars:r.maxAbstractChars??o})}export{n as openalex};
@@ -0,0 +1 @@
1
+ export { type PaperSearchOptions, paperSearch } from "./paper-search.js";
@@ -0,0 +1 @@
1
+ import{paperSearch as p}from"./paper-search.js";export{p as paperSearch};
@@ -0,0 +1,38 @@
1
+ import { type PaperSearcher } from "../../papers/papers.js";
2
+ export interface PaperSearchOptions {
3
+ papers: PaperSearcher;
4
+ maxResults?: number;
5
+ maxAbstractChars?: number;
6
+ }
7
+ export declare function paperSearch(opts: PaperSearchOptions): import("../../index.js").Tool<import("../../index.js").ArgsOf<readonly [{
8
+ readonly name: "query";
9
+ readonly type: "string";
10
+ readonly required: true;
11
+ readonly maxLength: 1000;
12
+ readonly description: string;
13
+ }, {
14
+ readonly name: "year_min";
15
+ readonly type: "number";
16
+ readonly required: false;
17
+ readonly min: 1500;
18
+ readonly max: 2200;
19
+ readonly description: "Earliest year of publication. Leave unset for any.";
20
+ }, {
21
+ readonly name: "year_max";
22
+ readonly type: "number";
23
+ readonly required: false;
24
+ readonly min: 1500;
25
+ readonly max: 2200;
26
+ readonly description: "Latest year of publication. Leave unset for any.";
27
+ }, {
28
+ readonly name: "min_citations";
29
+ readonly type: "number";
30
+ readonly required: false;
31
+ readonly min: 0;
32
+ readonly description: "Only papers cited at least this often. Raises confidence and hides recent work.";
33
+ }, {
34
+ readonly name: "open_access";
35
+ readonly type: "boolean";
36
+ readonly required: false;
37
+ readonly description: "Only papers whose full text can be read without a subscription.";
38
+ }]>>;
@@ -0,0 +1,3 @@
1
+ import{DEFAULT_ABSTRACT_CHARS as m,DEFAULT_MAX_PAPERS as f}from"../../papers/papers.js";import{rendered as w}from"../../papers/render.js";import{tool as y}from"../../tool/index.js";const i="Finds published papers on a topic and returns them as text: title, authors, venue, citation count, DOI, an open PDF when there is one, how the study was run where that is known, and the start of the abstract. Use it for what research has found or measured, and cite the DOI. Not for prices, products, news or anything from the last few months.";function b(e){const t=e.pdf??e.url??(e.doi?`https://doi.org/${e.doi}`:null);return t?{url:t,title:e.title,...e.year===null?{}:{date:String(e.year)}}:null}function x(e){return e?`${i} Papers come from ${e}.`:i}function _(e){if(typeof e?.papers!="function")throw new Error("paperSearch needs a paper searcher to run on: consensus({ apiKey }), semanticScholar() or openAlexPapers().");const{papers:t}=e,c=e.maxResults??f,u=e.maxAbstractChars??m;return y({name:"paper_search",description:x(t.source),effect:"readonly",trust:"external",wants:{name:"query",description:"the same ask as a short search phrase \u2014 the words a paper title or abstract would carry, not a sentence. A whole question finds far less."},costOf:s=>s.costMicroUsd,args:[{name:"query",type:"string",required:!0,maxLength:1e3,description:"The topic, as a phrase a paper title or abstract would contain. A whole question works and is ranked, but the shorter the phrase the better it matches."},{name:"year_min",type:"number",required:!1,min:1500,max:2200,description:"Earliest year of publication. Leave unset for any."},{name:"year_max",type:"number",required:!1,min:1500,max:2200,description:"Latest year of publication. Leave unset for any."},{name:"min_citations",type:"number",required:!1,min:0,description:"Only papers cited at least this often. Raises confidence and hides recent work."},{name:"open_access",type:"boolean",required:!1,description:"Only papers whose full text can be read without a subscription."}],run:async({query:s,year_min:p,year_max:d,min_citations:h,open_access:l})=>{const n=s.trim();if(!n)throw new Error("Name the topic to search for.");const r=await t({query:n,limit:c,yearMin:p,yearMax:d,minCitations:h,openAccess:l}),o=(r.failed??[]).map(a=>`${a.source} did not answer: ${a.reason}`);if(r.papers.length===0)throw new Error([`No papers matching "${n}" in ${r.source}.`,...o].join(" "));return{answer:[w(n,r.papers,u),...o].join(`
2
+
3
+ `),results:r.papers.map(b).filter(a=>a!==null),...r.costMicroUsd===void 0?{}:{costMicroUsd:r.costMicroUsd}}}})}export{_ as paperSearch};
@@ -1,6 +1,7 @@
1
1
  export interface PoliteOptions {
2
2
  /** Named on every request, as the open APIs ask, so a shared IP is still identifiable. */
3
3
  userAgent: string;
4
+ headers?: Record<string, string>;
4
5
  timeoutMs?: number;
5
6
  /** Injected for tests. */
6
7
  fetch?: typeof fetch;
@@ -1 +1 @@
1
- const a=429,_=2,c=1e3,R=5e3,u=1e4,o=t=>new Promise(e=>setTimeout(e,t));function E(t){const e=Number(t.headers.get("retry-after")),n=Number.isFinite(e)&&e>0?e*1e3:1e3;return Math.min(n,5e3)}function A(t){const e=t.fetch??globalThis.fetch.bind(globalThis),n=t.wait??o,T=t.timeoutMs??1e4;return async i=>{for(let r=0;;r++){const s=await e(i,{signal:AbortSignal.timeout(T),headers:{"user-agent":t.userAgent,"api-user-agent":t.userAgent}});if(s.status!==429||r>=2)return s;await n(E(s))}}}export{A as politeGet};
1
+ const E=429,_=2,c=1e3,R=5e3,u=1e4,a=t=>new Promise(e=>setTimeout(e,t));function o(t){const e=Number(t.headers.get("retry-after")),n=Number.isFinite(e)&&e>0?e*1e3:1e3;return Math.min(n,5e3)}function A(t){const e=t.fetch??globalThis.fetch.bind(globalThis),n=t.wait??a,T=t.timeoutMs??1e4;return async i=>{for(let r=0;;r++){const s=await e(i,{signal:AbortSignal.timeout(T),headers:{"user-agent":t.userAgent,"api-user-agent":t.userAgent,...t.headers}});if(s.status!==429||r>=2)return s;await n(o(s))}}}export{A as politeGet};
@@ -31,7 +31,7 @@ export declare function publish(opts: PublishOptions): import("../../index.js").
31
31
  readonly name: "to";
32
32
  readonly type: "enum";
33
33
  readonly required: true;
34
- readonly options: readonly ("md" | "pdf" | "html" | "txt")[];
34
+ readonly options: readonly ("pdf" | "html" | "md" | "txt")[];
35
35
  }, {
36
36
  readonly name: "from";
37
37
  readonly type: "enum";
@@ -1,10 +1,12 @@
1
1
  import { type ApiOptions, type WikidataApi } from "./api.js";
2
+ import { type Fact } from "./render.js";
2
3
  export interface WikidataOptions extends ApiOptions {
3
4
  /** Facts kept per thing. Default 30; a country has hundreds. */
4
5
  maxFacts?: number;
5
6
  /** Injected for tests, in place of the three calls to Wikidata. */
6
7
  api?: WikidataApi;
7
8
  }
9
+ export declare function matching(facts: readonly Fact[], about: string): Fact[];
8
10
  /**
9
11
  * Facts about a thing from Wikidata, as text — its label, what it is, and
10
12
  * the statements made about it, with every id resolved to a name.
@@ -17,5 +19,5 @@ export declare function wikidata(opts?: WikidataOptions): import("../../index.js
17
19
  readonly type: "string";
18
20
  readonly required: true;
19
21
  readonly maxLength: 200;
20
- readonly description: "The thing's name, optionally followed by ': ' and what about it.";
22
+ readonly description: string;
21
23
  }]>>;
@@ -1 +1 @@
1
- import{tool as w}from"../../tool/index.js";import{wikidataApi as b}from"./api.js";import{factsOf as g,referenced as k,rendered as y,statementsOf as x}from"./render.js";const E=30;function L(t){const a=t.indexOf(":");if(a<1)return{name:t.trim(),about:null};const o=t.slice(a+1).trim();return{name:t.slice(0,a).trim(),about:o||null}}function A(t,a){const o=a.toLowerCase().split(/\s+/).filter(Boolean);return t.filter(i=>{const r=i.property.toLowerCase();return o.some(n=>r.includes(n))})}function $(t={}){const a=t.api??b(t),o=t.maxFacts??E;return w({name:"wikidata",effect:"readonly",trust:"external",description:"Looks a thing up on Wikidata and returns what is recorded about it as plain text: what it is, when it began, where it is, who runs it, and so on. Name the thing \u2014 a company, person, place, product or event \u2014 and add ': ' and a topic to narrow it, as in 'Cloudflare: founded' or 'Paris: population'. Not for prices, versions or news.",args:[{name:"question",type:"string",required:!0,maxLength:200,description:"The thing's name, optionally followed by ': ' and what about it."}],run:async({question:i})=>{const{name:r,about:n}=L(i);if(!r)throw new Error("Name the thing to look up.");const s=await a.search(r);if(!s)throw new Error(`Wikidata has nothing named "${r}".`);const e=await a.entity(s.id);if(!e)throw new Error(`Wikidata has no record for ${s.id}.`);const c=x(e).slice(0,o),f=c.flatMap(([p,m])=>[p,...m.flatMap(h=>k(h.mainsnak))]),u=await a.labels(f),d=g(c,u),l=n?A(d,n):d;if(n&&l.length===0)throw new Error(`Wikidata records nothing about "${n}" for ${e.label}.`);return y(e,l)}})}export{$ as wikidata};
1
+ import{tool as y}from"../../tool/index.js";import{wikidataApi as b}from"./api.js";import{factsOf as g,referenced as k,rendered as p,statementsOf as x}from"./render.js";const v=30;function A(e){const t=e.indexOf(":");if(t<1)return{name:e.trim(),about:null};const o=e.slice(t+1).trim();return{name:e.slice(0,t).trim(),about:o||null}}const L={founded:["inception","start time"],founder:["founded by"],created:["inception"],started:["inception"],began:["inception"],born:["date of birth"],died:["date of death"],headquarters:["headquarters location"],ceo:["chief executive officer"],boss:["chief executive officer"],owner:["owned by"],parent:["parent organization"]};function N(e,t){const s=t.toLowerCase().split(/\s+/).filter(Boolean).flatMap(n=>[n,...L[n]??[]]);return e.filter(n=>{const a=n.property.toLowerCase();return s.some(r=>a.includes(r))})}function F(e={}){const t=e.api??b(e),o=e.maxFacts??v;return y({name:"wikidata",effect:"readonly",trust:"external",description:"One curated fact about one named thing, with the source it came from. It settles who, when, where and what-is: who makes or runs something, when it began or a person was born, what a place's capital or population is, what a compound's formula is. Name the thing \u2014 a company, person, place, product, substance or work \u2014 and add ': ' and the one property wanted, as in 'Cloudflare: inception' or 'Ozempic: manufacturer'. Not for what a study found, which is a paper and not a property; not for a price or anything contested, which has no single recorded value; and not for anything recent, because a volunteer updates it when they get round to it.",wants:{name:"entity",description:"the thing's name on its own \u2014 'Novo Nordisk', never a sentence or a question \u2014 optionally followed by ': ' and the one property wanted, as in 'Novo Nordisk: inception'."},args:[{name:"question",type:"string",required:!0,maxLength:200,description:"The thing's name on its own, optionally followed by ': ' and the property wanted. A question finds nothing \u2014 Wikidata is searched by name."}],run:async({question:s})=>{const{name:n,about:a}=A(s);if(!n)throw new Error("Name the thing to look up.");const r=await t.search(n);if(!r)throw new Error(`Wikidata has nothing named "${n}".`);const i=await t.entity(r.id);if(!i)throw new Error(`Wikidata has no record for ${r.id}.`);const c=x(i),f=c.flatMap(([l,w])=>[l,...w.flatMap(m=>k(m.mainsnak))]),u=await t.labels(f),d=g(c,u);if(!a)return p(i,d.slice(0,o));const h=N(d,a);if(h.length===0)throw new Error(`Wikidata records nothing about "${a}" for ${i.label}.`);return p(i,h.slice(0,o))}})}export{N as matching,F as wikidata};
@@ -1,20 +1,3 @@
1
- /**
2
- * What a handler returned, as the string a result carries.
3
- *
4
- * A string is itself; anything else is JSON. `graph`'s `stringify` describes
5
- * this as "the same convention as a tool result" — it was not, and this is the
6
- * side that had drifted.
7
- *
8
- * `JSON.stringify` returns `undefined` for a function or an undefined value, so
9
- * a completed result carried `output: undefined` where its own type says
10
- * `string`, and the model was handed nothing while being told it was handed
11
- * something. And it *throws* on a circular object, a `BigInt`, or anything whose
12
- * `toJSON` throws — a circular object being any value with a parent backlink.
13
- *
14
- * What comes back when a value cannot be written is a note saying so, never
15
- * `""`: an empty output reads as a tool that produced nothing, and this is a
16
- * tool that produced something unwritable.
17
- */
18
1
  export declare function render(value: unknown): string;
19
2
  /**
20
3
  * Why a handler failed, from whatever it threw.
@@ -1,2 +1,2 @@
1
- function r(n){if(n==null)return"";if(typeof n=="string")return n;try{const t=JSON.stringify(n);return t===void 0?`[not recordable: ${typeof n}]`:t}catch(t){return`[not recordable: ${(t instanceof Error?t.message:String(t)).split(`
2
- `)[0]}]`}}function o(n){if(n instanceof Error&&n.message.trim())return n.message;if(typeof n=="string"&&n.trim())return n;const t=r(n);return t&&t!=="{}"?`Tool failed: ${t}`:"Tool failed."}export{o as reasonFor,r as render};
1
+ function t(n){const r=n;return typeof r?.answer=="string"&&r.answer.trim()!==""&&Array.isArray(r.results)}function e(n){if(n==null)return"";if(typeof n=="string")return n;if(t(n))return n.answer;try{const r=JSON.stringify(n);return r===void 0?`[not recordable: ${typeof n}]`:r}catch(r){return`[not recordable: ${(r instanceof Error?r.message:String(r)).split(`
2
+ `)[0]}]`}}function o(n){if(n instanceof Error&&n.message.trim())return n.message;if(typeof n=="string"&&n.trim())return n;const r=e(n);return r&&r!=="{}"?`Tool failed: ${r}`:"Tool failed."}export{o as reasonFor,e as render};
package/dist/index.d.ts CHANGED
@@ -7,11 +7,11 @@
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, 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";
10
+ 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 PaperSearchOptions, type Publisher, type PublishOptions, paperSearch, 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
11
  export type { BusGroupOptions, BusMember, Namespacing, Offering, ToolBus, ToolBusOptions, ToolTrace, } from "./bus/index.js";
13
12
  export { busgroup, priced, spentOn, toolbus } from "./bus/index.js";
14
13
  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";
14
+ export type { Source } from "./search/search.js";
15
15
  export type { BoundSpec, ToolSpec } from "./tool/index.js";
16
16
  export { bindTool, ToolDriftError, ToolNotStoredError, tool } from "./tool/index.js";
17
17
  export type { ArgSpec, ArgsOf, ArgValue, Effect, Tool, ToolDeclaration, ToolResult, Trust, } from "./types/index.js";
package/dist/index.js CHANGED
@@ -1 +1 @@
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};
1
+ import{answerOf as o,calculate as t,codeExec as s,currentTime as a,dateMath as i,dates as l,decline as c,declinedFor as n,escalate as d,escalationOf as p,extract as m,finish as f,httpRequest as x,isDeclined as h,isEscalated as u,isFinished as b,jsonFrom as E,jsonQuery as S,notes as T,notesStore as w,openalex as y,paperSearch as F,publish as M,retryAfterMs as O,think as j,webSearch as k,wikidata as D}from"./builtin/index.js";import{busgroup as g,priced as q,spentOn as v,toolbus as A}from"./bus/index.js";import{contextId as N,deepRecall as Q,exploreMemory as z,memories as B,observer as C,recall as G,remember as H}from"./memories/index.js";import{bindTool as K,ToolDriftError as L,ToolNotStoredError as P,tool as U}from"./tool/index.js";export{L as ToolDriftError,P as ToolNotStoredError,o as answerOf,K as bindTool,g as busgroup,t as calculate,s as codeExec,N as contextId,a as currentTime,i as dateMath,l as dates,c as decline,n as declinedFor,Q as deepRecall,d as escalate,p as escalationOf,z as exploreMemory,m as extract,f as finish,x as httpRequest,h as isDeclined,u as isEscalated,b as isFinished,E as jsonFrom,S as jsonQuery,B as memories,T as notes,w as notesStore,C as observer,y as openalex,F as paperSearch,q as priced,M as publish,G as recall,H as remember,O as retryAfterMs,v as spentOn,j as think,U as tool,A as toolbus,k as webSearch,D as wikidata};
@@ -0,0 +1,12 @@
1
+ import { type PaperSearcher, type PaperSearcherOptions } from "../papers.js";
2
+ export interface ConsensusOptions extends PaperSearcherOptions {
3
+ apiKey: string;
4
+ studyTypes?: string[];
5
+ humanOnly?: boolean;
6
+ controlledOnly?: boolean;
7
+ excludePreprints?: boolean;
8
+ minSampleSize?: number;
9
+ domain?: string;
10
+ journalName?: string;
11
+ }
12
+ export declare function consensus(opts: ConsensusOptions): PaperSearcher;
@@ -0,0 +1 @@
1
+ import{retrying as l}from"../../search/retry.js";import{DEFAULT_MAX_PAPERS as m,paperLimit as d}from"../papers.js";import{readReply as y}from"./reply.js";const f="https://api.consensus.app/v1/search",_="consensus",S=6e4,h=500;function g(e){return{...e.studyTypes?.length?{study_types:e.studyTypes.join(",")}:{},...e.humanOnly?{human:"true"}:{},...e.controlledOnly?{controlled:"true"}:{},...e.excludePreprints?{exclude_preprints:"true"}:{},...e.minSampleSize?{sample_size_min:String(e.minSampleSize)}:{},...e.domain?{domain:e.domain}:{},...e.journalName?{journal_name:e.journalName}:{}}}function p(e){return{...e.yearMin===void 0?{}:{year_min:String(e.yearMin)},...e.yearMax===void 0?{}:{year_max:String(e.yearMax)},...e.minCitations===void 0?{}:{citation_min:String(e.minCitations)},...e.openAccess?{open_access:"true"}:{}}}function w(e){if(!e.apiKey?.trim())throw new Error("consensus needs an apiKey; it will not read one from the process.");const s=e.fetch??globalThis.fetch.bind(globalThis),o=e.maxResults??m,c=l(e);return Object.assign(async i=>{const t=d(i,o),a=new URL(f);for(const[r,u]of Object.entries({query:i.query,page_size:String(t),...p(i),...g(e)}))a.searchParams.set(r,u);const n=await c(()=>s(a,{signal:AbortSignal.timeout(e.timeoutMs??S),headers:{"x-api-key":e.apiKey,accept:"application/json"}}));if(!n.ok){const r=(await n.text()).slice(0,h);throw new Error(`Consensus returned ${n.status}: ${r}`)}return y(await n.json(),t,e.costMicroUsd)},{source:_})}export{w as consensus};
@@ -0,0 +1,4 @@
1
+ export type { ConsensusOptions } from "./consensus.js";
2
+ export { consensus } from "./consensus.js";
3
+ export type { ConsensusReply } from "./reply.js";
4
+ export { readReply } from "./reply.js";
@@ -0,0 +1 @@
1
+ import{consensus as r}from"./consensus.js";import{readReply as s}from"./reply.js";export{r as consensus,s as readReply};
@@ -0,0 +1,24 @@
1
+ import type { PapersFound } from "../papers.js";
2
+ interface RawResult {
3
+ title?: string | null;
4
+ authors?: string[] | null;
5
+ publish_year?: number | null;
6
+ doi?: string | null;
7
+ journal_name?: string | null;
8
+ citation_count?: number | null;
9
+ study_type?: string | null;
10
+ sample_size?: number | null;
11
+ takeaway?: string | null;
12
+ abstract?: string | null;
13
+ url?: string | null;
14
+ pdf_url?: string | null;
15
+ }
16
+ export interface ConsensusReply {
17
+ results?: RawResult[];
18
+ page?: number;
19
+ page_size?: number;
20
+ is_end?: boolean;
21
+ next_page?: number | null;
22
+ }
23
+ export declare function readReply(raw: ConsensusReply, maxResults: number, costMicroUsd?: number): PapersFound;
24
+ export {};
@@ -0,0 +1 @@
1
+ const s="consensus";function i(t){return{title:t.title?.trim()||"(untitled)",year:t.publish_year??null,authors:t.authors??[],venue:t.journal_name||null,citations:t.citation_count??0,doi:t.doi?.replace(/^https?:\/\/doi\.org\//,"")||null,pdf:t.pdf_url||null,url:t.url||null,studyType:t.study_type||null,sampleSize:t.sample_size??null,takeaway:t.takeaway||null,abstract:t.abstract??""}}function o(t,u,e){const l=t.results??[],n=l.slice(0,u);return{papers:n.map(i),source:s,total:null,truncated:l.length>n.length||t.is_end===!1,...e===void 0?{}:{costMicroUsd:e}}}export{o as readReply};
@@ -0,0 +1,6 @@
1
+ import { type PaperSearcher } from "./papers.js";
2
+ export interface EveryPaperOptions {
3
+ maxResults?: number;
4
+ }
5
+ export declare function listed(names: string[]): string;
6
+ export declare function everyPaper(searchers: PaperSearcher[], opts?: EveryPaperOptions): PaperSearcher;
@@ -0,0 +1 @@
1
+ import{DEFAULT_MAX_PAPERS as h,paperLimit as m}from"./papers.js";function g(e){const t=[];for(let n=0;;n++){let o=!1;for(const a of e){const u=a[n];u!==void 0&&(o=!0,t.push(u))}if(!o)return t}}function w(e){return e.doi?`doi:${e.doi.toLowerCase()}`:`title:${e.title.toLowerCase().replace(/[^a-z0-9]+/g," ").trim()}`}function v(e,t){return{title:e.title,year:e.year??t.year,authors:e.authors.length>0?e.authors:t.authors,venue:e.venue??t.venue,citations:Math.max(e.citations,t.citations),doi:e.doi??t.doi,pdf:e.pdf??t.pdf,url:e.url??t.url,studyType:e.studyType??t.studyType,sampleSize:e.sampleSize??t.sampleSize,takeaway:e.takeaway??t.takeaway,abstract:e.abstract||t.abstract}}function M(e){const t=new Map;for(const n of e){const o=w(n),a=t.get(o);t.set(o,a?v(a,n):n)}return[...t.values()]}const $=e=>e instanceof Error?e.message:String(e);function b(e){return e.map((t,n)=>t.source??`source ${n+1}`)}function f(e){return e.length<2?e[0]??"":`${e.slice(0,-1).join(", ")} and ${e.at(-1)}`}function x(e){const t=e.flatMap(n=>n.costMicroUsd===void 0?[]:[n.costMicroUsd]);return t.length>0?t.reduce((n,o)=>n+o,0):void 0}function E(e){const t=e.flatMap(n=>n.total===null?[]:[n.total]);return t.length>0?t.reduce((n,o)=>n+o,0):null}function L(e,t={}){if(e.length===0)throw new Error("everyPaper needs at least one paper searcher to run.");const n=b(e),o=t.maxResults??h;return Object.assign(async a=>{const u=m(a,o),p=await Promise.allSettled(e.map(r=>r({...a,limit:u}))),s=[],i=[];if(p.forEach((r,y)=>{r.status==="fulfilled"?s.push(r.value):i.push({source:n[y],reason:$(r.reason)})}),s.length===0)throw new Error(`No paper searcher answered. ${i.map(r=>`${r.source}: ${r.reason}`).join(" ")}`);const c=M(g(s.map(r=>r.papers))),l=c.slice(0,u),d=x(s);return{papers:l,source:f(s.map(r=>r.source)),total:E(s),truncated:c.length>l.length||s.some(r=>r.truncated),...d===void 0?{}:{costMicroUsd:d},...i.length>0?{failed:i}:{}}},{source:f(n)})}export{L as everyPaper,f as listed};
@@ -0,0 +1,11 @@
1
+ export type { ConsensusOptions, ConsensusReply } from "./consensus/index.js";
2
+ export { consensus } from "./consensus/index.js";
3
+ export type { EveryPaperOptions } from "./every.js";
4
+ export { everyPaper } from "./every.js";
5
+ export type { OpenAlexPapersOptions } from "./openalex/index.js";
6
+ export { openAlexPapers } from "./openalex/index.js";
7
+ export type { Paper, PaperAsk, PaperFailure, PaperFilters, PaperSearcher, PaperSearcherOptions, PapersFound, } from "./papers.js";
8
+ export { DEFAULT_ABSTRACT_CHARS, DEFAULT_MAX_PAPERS } from "./papers.js";
9
+ export { rendered } from "./render.js";
10
+ export type { SemanticScholarOptions, SemanticScholarReply } from "./semantic-scholar/index.js";
11
+ export { semanticScholar } from "./semantic-scholar/index.js";
@@ -0,0 +1 @@
1
+ import{consensus as o}from"./consensus/index.js";import{everyPaper as A}from"./every.js";import{openAlexPapers as t}from"./openalex/index.js";import{DEFAULT_ABSTRACT_CHARS as f,DEFAULT_MAX_PAPERS as n}from"./papers.js";import{rendered as a}from"./render.js";import{semanticScholar as S}from"./semantic-scholar/index.js";export{f as DEFAULT_ABSTRACT_CHARS,n as DEFAULT_MAX_PAPERS,o as consensus,A as everyPaper,t as openAlexPapers,a as rendered,S as semanticScholar};
@@ -0,0 +1,2 @@
1
+ export type { OpenAlexPapersOptions } from "./openalex.js";
2
+ export { openAlexPapers } from "./openalex.js";
@@ -0,0 +1 @@
1
+ import{openAlexPapers as p}from"./openalex.js";export{p as openAlexPapers};
@@ -0,0 +1,8 @@
1
+ import { type ApiOptions, type OpenAlexApi } from "../../builtin/openalex/api.js";
2
+ import { type PaperSearcher } from "../papers.js";
3
+ export interface OpenAlexPapersOptions extends ApiOptions {
4
+ maxResults?: number;
5
+ costMicroUsd?: number;
6
+ api?: OpenAlexApi;
7
+ }
8
+ export declare function openAlexPapers(opts?: OpenAlexPapersOptions): PaperSearcher;
@@ -0,0 +1 @@
1
+ import{openAlexApi as u}from"../../builtin/openalex/api.js";import{DEFAULT_MAX_PAPERS as c,paperLimit as l}from"../papers.js";const s="openalex";function p(e){return{...e,url:null,studyType:null,sampleSize:null,takeaway:null}}function d(e={}){const o=e.api??u(e),a=e.maxResults??c;return Object.assign(async n=>{const r=await o.search(n.query,l(n,a),n),t=r.costMicroUsd??e.costMicroUsd;return{papers:r.papers.map(p),source:s,total:null,truncated:!1,...t===void 0?{}:{costMicroUsd:t}}},{source:s})}export{d as openAlexPapers};
@@ -0,0 +1,54 @@
1
+ export interface Paper {
2
+ title: string;
3
+ year: number | null;
4
+ authors: string[];
5
+ venue: string | null;
6
+ citations: number;
7
+ doi: string | null;
8
+ pdf: string | null;
9
+ url: string | null;
10
+ studyType: string | null;
11
+ sampleSize: number | null;
12
+ takeaway: string | null;
13
+ abstract: string;
14
+ }
15
+ export interface PaperFilters {
16
+ yearMin?: number;
17
+ yearMax?: number;
18
+ openAccess?: boolean;
19
+ minCitations?: number;
20
+ }
21
+ export interface PaperAsk extends PaperFilters {
22
+ query: string;
23
+ limit?: number;
24
+ }
25
+ export interface PaperFailure {
26
+ source: string;
27
+ reason: string;
28
+ }
29
+ export interface PapersFound {
30
+ papers: Paper[];
31
+ source: string;
32
+ total: number | null;
33
+ truncated: boolean;
34
+ costMicroUsd?: number;
35
+ failed?: PaperFailure[];
36
+ }
37
+ export type PaperSearcher = ((ask: PaperAsk) => Promise<PapersFound>) & {
38
+ source?: string;
39
+ };
40
+ export interface PaperSearcherOptions {
41
+ maxResults?: number;
42
+ costMicroUsd?: number;
43
+ timeoutMs?: number;
44
+ attempts?: number;
45
+ fetch?: typeof fetch;
46
+ sleep?: (ms: number) => Promise<void>;
47
+ random?: () => number;
48
+ }
49
+ export declare const DEFAULT_MAX_PAPERS = 10;
50
+ export declare const DEFAULT_ABSTRACT_CHARS = 400;
51
+ export declare function paperLimit(ask: PaperAsk, ceiling: number): number;
52
+ export declare function yearRange({ yearMin, yearMax }: PaperFilters): string | null;
53
+ export declare const MICRO_USD = 1000000;
54
+ export declare const microUsd: (usd: number | undefined) => number | undefined;
@@ -0,0 +1 @@
1
+ const r=10,o=400;function i(t,n){return Math.max(1,Math.min(t.limit??n,n))}function u({yearMin:t,yearMax:n}){return t===void 0&&n===void 0?null:`${t??""}-${n??""}`}const e=1e6,p=t=>typeof t=="number"&&Number.isFinite(t)?Math.round(t*e):void 0;export{o as DEFAULT_ABSTRACT_CHARS,r as DEFAULT_MAX_PAPERS,e as MICRO_USD,p as microUsd,i as paperLimit,u as yearRange};
@@ -1,2 +1,2 @@
1
- import type { Paper } from "./api.js";
1
+ import type { Paper } from "./papers.js";
2
2
  export declare function rendered(query: string, papers: readonly Paper[], maxChars: number): string;
@@ -0,0 +1,4 @@
1
+ const m=3;function c(n){const t=n.authors.slice(0,3).map(e=>e.split(" ").at(-1)??e),o=n.authors.length-t.length;return t.length===0?"unknown authors":o>0?`${t.join(", ")} +${o}`:t.join(", ")}function d(n){const t=n.year===null?"":` (${n.year})`,o=n.venue?` \xB7 ${n.venue}`:"";return`${n.title}${t} \u2014 ${c(n)}${o} \xB7 ${n.citations} citations`}function $(n){const o=[n.studyType,n.sampleSize===null?null:`n=${n.sampleSize}`].filter(e=>!!e);return o.length>0?o.join(" \xB7 "):null}function f(n){const o=[n.doi?`doi:${n.doi}`:null,n.pdf?`pdf: ${n.pdf}`:null].filter(e=>e!==null);return o.length>0?o.join(" \xB7 "):n.url}function h(n){const t=n.takeaway?.trim();return t?`Found: ${t}`:null}function a(n,t){const o=n.abstract.trim();return o?o.length>t?`${o.slice(0,t).trimEnd()}\u2026`:o:null}function g(n,t,o){const e=`${t.length} paper${t.length===1?"":"s"} on "${n}", most relevant first`,i=t.map((u,s)=>[`${s+1}. ${d(u)}`,$(u),f(u),h(u),a(u,o)].filter(l=>l!==null).map((l,r)=>r===0?l:` ${l}`).join(`
2
+ `));return[e,...i].join(`
3
+
4
+ `)}export{g as rendered};
@@ -0,0 +1,4 @@
1
+ export type { SemanticScholarReply } from "./reply.js";
2
+ export { readReply } from "./reply.js";
3
+ export type { SemanticScholarOptions } from "./semantic-scholar.js";
4
+ export { semanticScholar } from "./semantic-scholar.js";
@@ -0,0 +1 @@
1
+ import{readReply as o}from"./reply.js";import{semanticScholar as m}from"./semantic-scholar.js";export{o as readReply,m as semanticScholar};
@@ -0,0 +1,29 @@
1
+ import type { PapersFound } from "../papers.js";
2
+ interface RawPaper {
3
+ title?: string | null;
4
+ abstract?: string | null;
5
+ year?: number | null;
6
+ venue?: string | null;
7
+ citationCount?: number | null;
8
+ authors?: {
9
+ name?: string | null;
10
+ }[] | null;
11
+ externalIds?: {
12
+ DOI?: string | null;
13
+ } | null;
14
+ openAccessPdf?: {
15
+ url?: string | null;
16
+ } | null;
17
+ url?: string | null;
18
+ tldr?: {
19
+ text?: string | null;
20
+ } | null;
21
+ }
22
+ export interface SemanticScholarReply {
23
+ total?: number;
24
+ offset?: number;
25
+ next?: number;
26
+ data?: RawPaper[];
27
+ }
28
+ export declare function readReply(raw: SemanticScholarReply, maxResults: number, costMicroUsd?: number): PapersFound;
29
+ export {};
@@ -0,0 +1 @@
1
+ const s="semantic-scholar";function o(t){return{title:t.title?.trim()||"(untitled)",year:t.year??null,authors:(t.authors??[]).flatMap(l=>l.name?[l.name]:[]),venue:t.venue?.trim()||null,citations:t.citationCount??0,doi:t.externalIds?.DOI||null,pdf:t.openAccessPdf?.url||null,url:t.url||null,studyType:null,sampleSize:null,takeaway:t.tldr?.text||null,abstract:t.abstract??""}}function c(t,l,u){const a=t.data??[],n=a.slice(0,l),e=t.total??null;return{papers:n.map(o),source:s,total:e,truncated:a.length>n.length||e!==null&&e>n.length,...u===void 0?{}:{costMicroUsd:u}}}export{c as readReply};
@@ -0,0 +1,8 @@
1
+ import { type PaperSearcher, type PaperSearcherOptions } from "../papers.js";
2
+ export interface SemanticScholarOptions extends PaperSearcherOptions {
3
+ apiKey?: string;
4
+ fieldsOfStudy?: string[];
5
+ publicationTypes?: string[];
6
+ venues?: string[];
7
+ }
8
+ export declare function semanticScholar(opts?: SemanticScholarOptions): PaperSearcher;
@@ -0,0 +1 @@
1
+ import{retrying as u}from"../../search/retry.js";import{DEFAULT_MAX_PAPERS as f,paperLimit as d,yearRange as m}from"../papers.js";import{readReply as h}from"./reply.js";const y="https://api.semanticscholar.org/graph/v1/paper/search",p="semantic-scholar",S=6e4,g=500,A=["title","abstract","year","venue","citationCount","authors","externalIds","openAccessPdf","url","tldr"].join(",");function T(e){return{...e.fieldsOfStudy?.length?{fieldsOfStudy:e.fieldsOfStudy.join(",")}:{},...e.publicationTypes?.length?{publicationTypes:e.publicationTypes.join(",")}:{},...e.venues?.length?{venue:e.venues.join(",")}:{}}}function R(e){const t=m(e);return{...t===null?{}:{year:t},...e.minCitations===void 0?{}:{minCitationCount:String(e.minCitations)},...e.openAccess?{openAccessPdf:""}:{}}}function j(e={}){const t=e.fetch??globalThis.fetch.bind(globalThis),s=e.maxResults??f,c=u(e);return Object.assign(async i=>{const a=d(i,s),o=new URL(y);for(const[r,l]of Object.entries({query:i.query,limit:String(a),fields:A,...R(i),...T(e)}))o.searchParams.set(r,l);const n=await c(()=>t(o,{signal:AbortSignal.timeout(e.timeoutMs??S),headers:{accept:"application/json",...e.apiKey?{"x-api-key":e.apiKey}:{}}}));if(!n.ok){const r=(await n.text()).slice(0,g);throw new Error(`Semantic Scholar returned ${n.status}: ${r}`)}return h(await n.json(),a,e.costMicroUsd)},{source:p})}export{j as semanticScholar};
@@ -0,0 +1,6 @@
1
+ import { type Searcher } from "./search.js";
2
+ export interface EverySearchOptions {
3
+ maxChars?: number;
4
+ maxResults?: number;
5
+ }
6
+ export declare function everySearch(searchers: Searcher[], opts?: EverySearchOptions): Searcher;
@@ -0,0 +1,4 @@
1
+ import{DEFAULT_MAX_CHARS as T,DEFAULT_MAX_RESULTS as k}from"./search.js";const g={inputTokens:0,outputTokens:0,citationTokens:0,reasoningTokens:0,searchQueries:0};function w(e){return e.reduce((n,t)=>({inputTokens:n.inputTokens+t.inputTokens,outputTokens:n.outputTokens+t.outputTokens,citationTokens:n.citationTokens+t.citationTokens,reasoningTokens:n.reasoningTokens+t.reasoningTokens,searchQueries:n.searchQueries+t.searchQueries}),g)}function S(e){const n=[];for(let t=0;;t++){let r=!1;for(const u of e){const a=u[t];a!==void 0&&(r=!0,n.push(a))}if(!r)return n}}const d=e=>e.url.replace(/\/+$/,"").toLowerCase();function E(e){const n=new Set;return e.filter(t=>!n.has(d(t))&&n.add(d(t)))}const $=e=>e instanceof Error?e.message:String(e);function v(e){return e.map((n,t)=>n.source??`searcher ${t+1}`)}function x(e){if(e.every(n=>n.domains?.length))return[...new Set(e.flatMap(n=>[...n.domains??[]]))]}const j=e=>`# via ${e.model}
2
+ ${e.answer}`;function A(e,n={}){if(e.length===0)throw new Error("everySearch needs at least one searcher to run.");const t=v(e),r=n.maxChars??T,u=n.maxResults??k,a=x(e);return Object.assign(async m=>{const p=await Promise.allSettled(e.map(s=>s(m))),o=[],i=[];if(p.forEach((s,h)=>{s.status==="fulfilled"?o.push(s.value):i.push({source:t[h],reason:$(s.reason)})}),o.length===0)throw new Error(`No searcher answered. ${i.map(s=>`${s.source}: ${s.reason}`).join(" ")}`);const c=o.map(j).join(`
3
+
4
+ `),l=E(S(o.map(s=>s.results))),f=l.slice(0,u);return{answer:c.slice(0,r),results:f,model:o.map(s=>s.model).join(", "),truncated:c.length>r||l.length>f.length||o.some(s=>s.truncated),usage:w(o.map(s=>s.usage)),...i.length>0?{failed:i}:{}}},{source:t.join(", "),...a?{domains:a}:{}})}export{A as everySearch};
@@ -1,5 +1,7 @@
1
- export type { Recency, SearchAsk, SearchDepth, Searched, Searcher, SearcherOptions, SearchUsage, Source, } from "./search.js";
1
+ export type { EverySearchOptions } from "./every.js";
2
+ export { everySearch } from "./every.js";
3
+ export type { Recency, SearchAsk, SearchDepth, Searched, Searcher, SearcherOptions, SearchFailure, SearchUsage, Source, } from "./search.js";
2
4
  export { DEPTHS, NO_TOKENS } from "./search.js";
3
5
  export { type SearxngOptions, searxng, textOf } from "./searxng/index.js";
4
- export { type TavilyOptions, tavily } from "./tavily/index.js";
5
6
  export { readReply, type SonarOptions, sonar } from "./sonar/index.js";
7
+ export { type TavilyOptions, tavily } from "./tavily/index.js";
@@ -1 +1 @@
1
- import{DEPTHS as e,NO_TOKENS as t}from"./search.js";import{searxng as f,textOf as p}from"./searxng/index.js";import{tavily as m}from"./tavily/index.js";import{readReply as l,sonar as n}from"./sonar/index.js";export{e as DEPTHS,t as NO_TOKENS,l as readReply,f as searxng,n as sonar,m as tavily,p as textOf};
1
+ import{everySearch as o}from"./every.js";import{DEPTHS as x,NO_TOKENS as f}from"./search.js";import{searxng as a,textOf as m}from"./searxng/index.js";import{readReply as O,sonar as S}from"./sonar/index.js";import{tavily as n}from"./tavily/index.js";export{x as DEPTHS,f as NO_TOKENS,o as everySearch,O as readReply,a as searxng,S as sonar,n as tavily,m as textOf};