diff --git a/README.md b/README.md index 9d8c875..84eb91d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # smart-decisions +[![npm](https://img.shields.io/npm/v/smart-decisions.svg)](https://www.npmjs.com/package/smart-decisions) +[![CI](https://github.com/expilu/smart-decisions/actions/workflows/ci.yml/badge.svg)](https://github.com/expilu/smart-decisions/actions/workflows/ci.yml) +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) +[![types](https://img.shields.io/npm/types/smart-decisions)](https://www.npmjs.com/package/smart-decisions) + A TypeScript library that answers a decision question with a **probability distribution over every option**, using any existing LLM. To make the decision, you can choose between **[System 1](#system-1-vs-system-2) (fast, instinctive, milliseconds)** or **[System 2](#system-1-vs-system-2) (slow, deliberate, several seconds)** intelligence. @@ -68,6 +73,40 @@ Notes: - `confidence` is derived from the distribution shape. See [under the hood](#how-it-works-under-the-hood) for the exact formula. +## Examples + +### Route a support ticket to the right department + +Classify incoming tickets. When the distribution is too flat to trust, the returned `confidence` tells you so you can escalate to a human: + +```typescript +import { choice } from 'smart-decisions'; + +const criteria = { + billing: 'Customer asks about invoices, payments, refunds or charges', + technical: 'Customer reports a bug, error or product malfunction', + sales: 'Customer asks about pricing, plans or upgrading', + account: 'Customer needs help with login or account access', +}; + +const answer = await choice({ + apiBaseUrl: 'http://localhost:8000/v1', + apiKey: 'a-super-secret-api-key', + model: '/models/Qwen3.5-4B-Q4_K_M.gguf', + mode: 'system1', + state: + 'Customer support ticket:\n"Hi, I was charged twice this month. Can you refund the extra payment?"', + instructions: 'Classify the ticket into the right department', + criteria, +})!; + +if (answer.confidence < 0.5) { + return forwardToHuman(answer); // too unsure to act autonomously +} + +routeTo(answer.choice); // 'billing' +``` + ## Requirements - An **OpenAI-compatible v1 API** that supports **`logprobs` / `top_logprobs`** in diff --git a/examples/ticket-routing.ts b/examples/ticket-routing.ts new file mode 100644 index 0000000..5ead6a6 --- /dev/null +++ b/examples/ticket-routing.ts @@ -0,0 +1,32 @@ +import { choice } from '../src/index.js'; + +const criteria = { + billing: 'Customer asks about invoices, payments, refunds or charges', + technical: 'Customer reports a bug, error or product malfunction', + sales: 'Customer asks about pricing, plans or upgrading', + account: 'Customer needs help with login or account access', +}; + +const ticket = 'Hi, I was charged twice this month. Can you refund the extra payment?'; + +async function main() { + const answer = await choice({ + apiBaseUrl: process.env.API_BASE_URL!, + apiKey: process.env.API_KEY!, + model: '/models/Qwen3.5-4B-Q4_K_M.gguf', + mode: 'system1', + state: `Customer support ticket:\n"${ticket}"`, + instructions: 'Classify the ticket into the right department', + criteria, + }); + + if (answer.confidence < 0.5) { + console.log('Too unsure to act autonomously, escalate to a human:', answer); + return; + } + + console.log(`Route to: ${answer.choice}`); + console.log(answer); +} + +void main(); diff --git a/package.json b/package.json index aeb667c..1c748a3 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "test": "vitest run", "test:coverage": "vitest run --coverage", "example": "node --env-file=.env --import tsx examples/basic.ts", + "example:routing": "node --env-file=.env --import tsx examples/ticket-routing.ts", "prepublishOnly": "rm -rf dist && npm run lint && npm run format:check && npm run typecheck && npm run build && npm test" }, "repository": {