{"id":20791488,"url":"https://github.com/meistrari/cursive","last_synced_at":"2025-04-06T07:13:50.677Z","repository":{"id":176967127,"uuid":"655735234","full_name":"meistrari/cursive","owner":"meistrari","description":"✦ The intuitive LLM framework","archived":false,"fork":false,"pushed_at":"2025-02-03T16:47:56.000Z","size":730,"stargazers_count":108,"open_issues_count":0,"forks_count":7,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-30T06:06:51.446Z","etag":null,"topics":["anthropic","framework","llm","openai","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/meistrari.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-19T13:45:22.000Z","updated_at":"2024-11-20T00:39:20.000Z","dependencies_parsed_at":"2023-11-06T04:27:20.181Z","dependency_job_id":"2187a6c0-7235-4a97-b846-ce5b3a94f280","html_url":"https://github.com/meistrari/cursive","commit_stats":null,"previous_names":["meistrari/cursive"],"tags_count":41,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meistrari%2Fcursive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meistrari%2Fcursive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meistrari%2Fcursive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meistrari%2Fcursive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meistrari","download_url":"https://codeload.github.com/meistrari/cursive/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247445671,"owners_count":20939958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anthropic","framework","llm","openai","typescript"],"created_at":"2024-11-17T15:45:04.678Z","updated_at":"2025-04-06T07:13:50.659Z","avatar_url":"https://github.com/meistrari.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Logo](/docs/logo-dark.svg#gh-dark-mode-only)\n![Logo](/docs/logo-light.svg#gh-light-mode-only)\n\nCursive is a universal and intuitive framework for interacting with LLMs.\n\nIt works in any JavaScript runtime and has a heavy focus on extensibility and developer experience.\n\n## ■ Highlights\n\u003cimg width=14 height=0 src=\"\"/\u003e✦ **Compatible** - Cursive works in any runtime, including the browser, Node.js, Deno, Bun and Cloudflare Workers. Through [WindowAI](https://windowai.io), users can securely bring their own credentials, provider, and model to completions.\n\n\u003cimg width=14 height=0 src=\"\"/\u003e✦ **Extensible** - You can easily hook into any part of a completion life cycle. Be it to log, cache, or modify the results.\n\n\u003cimg width=14 height=0 src=\"\"/\u003e✦ **Functions** - Easily describe functions that the LLM can use along with its definition, with any model (currently supporting GPT-4, GPT-3.5, Claude 2, and Claude Instant)\n\n\u003cimg width=14 height=0 src=\"\"/\u003e✦ **Universal** - Cursive's goal is to bridge as many capabilities between different models as possible. Ultimately, this means that with a single interface, you can allow your users to choose any model.\n\n\u003cimg width=14 height=0 src=\"\"/\u003e✦ **Informative** - Cursive comes with built-in token usage and costs calculations, as accurate as possible.\n\n\u003cimg width=14 height=0 src=\"\"/\u003e✦ **Reliable** - Cursive comes with automatic retry and model expanding upon exceeding context length. Which you can always configure.\n\n## ■ Quickstart\n1. Install.\n\n    ```bash\n    npm i cursive\n    ```\n\n2. Start using.\n\n    ```ts\n    import { useCursive } from 'cursive'\n\n    const cursive = useCursive({\n        openAI: {\n            apiKey: 'sk-xxxx'\n        }\n    })\n\n    const { answer } = await cursive.ask({\n        prompt: 'What is the meaning of life?',\n    })\n    ```\n\n## ■ Usage\n### Conversation\nChaining a conversation is easy with `cursive`. You can pass any of the options you're used to with OpenAI's API.\n\n```ts\nconst resA = await cursive.ask({\n    prompt: 'Give me a good name for a gecko.',\n    model: 'gpt-4',\n    maxTokens: 16,\n})\n\nconsole.log(resA.answer) // Zephyr\n\nconst resB = await resA.conversation.ask({\n    prompt: 'How would you say it in Portuguese?'\n})\n\nconsole.log(resB.answer) // Zéfiro\n```\n### Streaming\nStreaming is also supported, and we also keep track of the tokens for you!\n```ts\nconst result = await cursive.ask({\n    prompt: 'Count to 10',\n    stream: true,\n    onToken(partial) {\n        console.log(partial.content)\n    }\n})\n\nconsole.log(result.usage.totalTokens) // 40\n```\n\n### Functions\nYou can use `Type` to define and describe functions, along side with their execution code.\nThis is powered by the [**`typebox`**](https://github.com/sinclairzx81/typebox) library.\n```ts\nimport { Type, createFunction, useCursive } from 'cursive'\n\nconst cursive = useCursive({\n    openAI: {\n        apiKey: 'sk-xxxx'\n    }\n})\n\nconst sum = createFunction({\n    name: 'sum',\n    description: 'Sums two numbers',\n    parameters: {\n        a: Type.Number({ description: 'Number A' }),\n        b: Type.Number({ description: 'Number B' }),\n    },\n    async execute({ a, b }) {\n        return a + b\n    },\n})\n\nconst { answer } = await cursive.ask({\n    prompt: 'What is the sum of 232 and 243?',\n    functions: [sum],\n})\n\nconsole.log(answer) // The sum of 232 and 243 is 475.\n```\n\nThe functions' result will automatically be fed into the conversation and another completion will be made. If you want to prevent this, you can add `pause` to your function definition.\n\n```ts\nconst createCharacter = createFunction({\n    name: 'createCharacter',\n    description: 'Creates a character',\n    parameters: {\n        name: Type.String({ description: 'The name of the character' }),\n        age: Type.Number({ description: 'The age of the character' }),\n        hairColor: Type.StringEnum(['black', 'brown', 'blonde', 'red', 'white'], { description: 'The hair color of the character' }),\n    },\n    pause: true,\n    async execute({ name, age, hairColor }) {\n        return { name, age, hairColor }\n    },\n})\n\nconst { functionResult } = await cursive.ask({\n    prompt: 'Create a character named John who is 23 years old.',\n    functions: [createCharacter],\n})\n\nconsole.log(functionResult) // { name: 'John', age: 23 }\n```\n\nIf you're on a `0.x.x` version, you can check here for the [old documentation](https://github.com/meistrari/cursive/tree/v0.12.2).\n\n### Hooks\nYou can hook into any part of the completion life cycle.\n```ts\ncursive.on('completion:after', (result) =\u003e {\n    console.log(result.cost.total)\n    console.log(result.usage.total_tokens)\n})\n\ncursive.on('completion:error', (error) =\u003e {\n    console.log(error)\n})\n\ncursive.ask({\n    prompt: 'Can androids dream of electric sheep?',\n})\n\n// 0.0002185\n// 113\n```\n\n### Embedding\nYou can create embeddings pretty easily with `cursive`.\n```ts\nconst embedding = await cursive.embed('This should be a document.')\n```\nThis will support different types of documents and integrations pretty soon.\n\n### Reliability\nCursive comes with automatic retry with backoff upon failing completions, and model expanding upon exceeding context length -- which means that it tries again with a model with a bigger context length when it fails by running out of it.\n\nYou can configure this behavior by passing the `retry` and `expand` options to `useCursive`.\n\n```ts\nconst cursive = useCursive({\n    maxRetries: 5, // 0 disables it completely\n    expand: {\n        enable: true,\n        defaultsTo: 'gpt-3.5-turbo-16k',\n        modelMapping: {\n            'gpt-3.5-turbo': 'gpt-3.5-turbo-16k',\n            'gpt-4': 'claude-2',\n        },\n    },\n    allowWindowAI: true,\n    countUsage: false, // When disabled doesn't load and execute token counting and price estimates\n})\n```\n\n## ■ Examples\n\n-  \u003cimg src=\"https://seeklogo.com/images/N/nuxt-logo-64E0472AA8-seeklogo.com.png\" width=16/\u003e **[Nuxt ⇢ Simple Application](https://github.com/meistrari/cursive/blob/main/examples/nuxt)**\n-  \u003cimg src=\"https://seeklogo.com/images/C/cloudflare-workers-logo-9BF89B51E2-seeklogo.com.png\" width=16/\u003e **[Cloudflare Workers ⇢ Simple Edge API](https://github.com/meistrari/cursive/blob/main/examples/cf-workers)**\n\n## ■ Roadmap\n\n### Vendor support\n- [x] Anthropic\n- [ ] Cohere (works on browser through WindowAI)\n- [ ] Azure OpenAI models\n- [ ] Huggingface (works on browser through WindowAI)\n- [ ] Replicate (works on browser through WindowAI)\n\n\n## ■ Credits\n\nThanks to [**@disjukr**](https://github.com/disjukr) for transferring the `cursive` npm package name to us!","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeistrari%2Fcursive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeistrari%2Fcursive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeistrari%2Fcursive/lists"}