diff --git a/README.md b/README.md index c1ec92b..43ca758 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,16 @@ -# Intent +

+ Intent +

+ +

Intent

+ +

+ npm version + npm downloads + License: MIT + Node.js + TypeScript +

`intent` is an LLM-based reranker library that offers ranking, filtering, and choice all with explicit, inspectable reasoning. @@ -28,7 +40,33 @@ const docs = [ ]; const ranked = await intent.rank("exponential backoff retries", docs); -// => [doc1, doc2] (doc3 is filtered out via relevancy threshold) +// => [ +// "To reduce flaky tests, add exponential backoff with jitter to HTTP retries.", +// "Many network requests can fail intermittently due to transient issues." +// ] +``` + +### With explanations + +Pass `{ explain: true }` to see why each item was ranked: + +```ts +const results = await intent.rank("exponential backoff retries", docs, { explain: true }); + +for (const { item, explanation } of results) { + console.log(`- "${item.slice(0, 50)}..."`); + console.log(` ${explanation}`); +} +``` + +``` +- "To reduce flaky tests, add exponential backoff wit..." + This entry explains adding exponential backoff with jitter to HTTP + retries, directly addressing the requested technique. + +- "Many network requests can fail intermittently due ..." + The summary mentions transient failures in network requests, which can + motivate using backoff retries but does not describe the method. ``` Intent will use a default Groq client when `GROQ_API_KEY` is set. @@ -71,11 +109,11 @@ const docs: Doc[] = [ const results = await intent.rank("Find expense reports and anything about spend approvals", docs); ``` -### Include explanations +### With explanations ```ts const results = await intent.rank("expense reports", docs, { explain: true }); -// => [{ item: Doc, explanation: string }, ...] +// => [{ item: Doc, explanation: "Covers Q2 travel and meal expenses..." }, ...] ``` ## 2) Tool filtering with `filter()` @@ -106,14 +144,23 @@ const tools: Tool[] = [ const task = "Find the customer's last invoice total and email it to them."; const relevantTools = await intent.filter(task, tools); -// [sendEmail, runSQL] +// => [sendEmail, runSQL] ``` -### Filter with explanations +### With explanations ```ts -const relevantTools = await intent.filter(task, tools, { explain: true }); -// => [{ item: Tool, explanation: string }, ...] +const results = await intent.filter(task, tools, { explain: true }); + +for (const { item, explanation } of results) { + console.log(`- ${item.name}: ${explanation}`); +} +``` + +``` +- sendEmail: Sending an email is necessary to deliver the invoice total to the customer. +- runSQL: Running a SQL query against the analytics DB can retrieve the last invoice + total needed for the task. ``` ## 3) Model routing with `choice()` @@ -155,7 +202,15 @@ const models: Model[] = [ const task = "Implement a feature to add retries with exponential backoff and tests."; const { item: selected, explanation } = await intent.choice(task, models, { explain: true }); -// selected.id => gpt-5.2 + +console.log(`Selected: ${selected.id}`); +console.log(`Why: ${explanation}`); +``` + +``` +Selected: gpt-5.2 +Why: Feature implementation and testing fall under code generation and + refactoring, which gpt-5.2 excels at. ``` ## Configuration @@ -243,8 +298,18 @@ Hard timeout per LLM call. - Increase it when you have larger batches, longer summaries, or slower models. - Decrease it when you prefer quick fallbacks over waiting. -If we timeout, we never throw an error; instead, we return the original -results. +### Error handling + +Intent is designed to fail gracefully. On **any** LLM error (timeout, invalid API +key, rate limit, malformed response), we return items in their original order +rather than throwing. This ensures your application keeps working even when the +LLM is unavailable. + +- `rank()` → returns all candidates in original order +- `filter()` → returns all candidates (nothing filtered out) +- `choice()` → returns the first candidate + +When `{ explain: true }` is set, failed calls return empty explanation strings. #### `INTENT_BATCH_SIZE` diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..5f911fb Binary files /dev/null and b/logo.png differ diff --git a/package-lock.json b/package-lock.json index beb9d56..c780844 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@with-logic/intent", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@with-logic/intent", - "version": "0.1.0", + "version": "0.1.1", "license": "MIT", "dependencies": { "dotenv": "^16.4.5", diff --git a/package.json b/package.json index 86d3956..3d195fc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@with-logic/intent", - "version": "0.1.0", + "version": "0.1.1", "private": false, "description": "Intent: a small, well-typed LLM-based reranker.", "keywords": [ @@ -23,6 +23,9 @@ "publishConfig": { "access": "public" }, + "engines": { + "node": ">=18" + }, "type": "module", "sideEffects": false, "main": "dist/index.cjs",