{"id":50578527,"url":"https://github.com/slegarraga/json-from-llm","last_synced_at":"2026-06-05T00:02:55.207Z","repository":{"id":362546984,"uuid":"1259497801","full_name":"slegarraga/json-from-llm","owner":"slegarraga","description":"Extract valid JSON from an LLM response, even when wrapped in reasoning/thinking tags, markdown fences or prose. Zero dependencies.","archived":false,"fork":false,"pushed_at":"2026-06-04T18:51:19.000Z","size":47,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-04T21:19:33.490Z","etag":null,"topics":["ai-agents","anthropic","deepseek","gemini","json","json-parser","llm","llm-output","openai","openai-compatible","parser","reasoning","structured-output","tool-calling","typescript","zero-dependencies"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/json-from-llm","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/slegarraga.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":"MAINTAINERS.md","copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-04T15:09:15.000Z","updated_at":"2026-06-04T18:51:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/slegarraga/json-from-llm","commit_stats":null,"previous_names":["slegarraga/json-from-llm"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/slegarraga/json-from-llm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slegarraga%2Fjson-from-llm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slegarraga%2Fjson-from-llm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slegarraga%2Fjson-from-llm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slegarraga%2Fjson-from-llm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/slegarraga","download_url":"https://codeload.github.com/slegarraga/json-from-llm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/slegarraga%2Fjson-from-llm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33924837,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-04T02:00:06.755Z","response_time":64,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ai-agents","anthropic","deepseek","gemini","json","json-parser","llm","llm-output","openai","openai-compatible","parser","reasoning","structured-output","tool-calling","typescript","zero-dependencies"],"created_at":"2026-06-05T00:02:54.328Z","updated_at":"2026-06-05T00:02:55.202Z","avatar_url":"https://github.com/slegarraga.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# json-from-llm\n\n[![npm version](https://img.shields.io/npm/v/json-from-llm.svg)](https://www.npmjs.com/package/json-from-llm)\n[![npm downloads](https://img.shields.io/npm/dm/json-from-llm.svg)](https://www.npmjs.com/package/json-from-llm)\n[![CI](https://github.com/slegarraga/json-from-llm/actions/workflows/ci.yml/badge.svg)](https://github.com/slegarraga/json-from-llm/actions/workflows/ci.yml)\n[![license](https://img.shields.io/npm/l/json-from-llm.svg)](./LICENSE)\n[![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen.svg)](./package.json)\n\n\u003e Extract valid JSON from an LLM response — even when it's wrapped in reasoning/thinking tags, markdown fences or prose. **Zero dependencies.**\n\nYou asked for JSON. The model gave you:\n\n````text\n\u003cthink\u003e\nLet me reason about this. The score should reflect... maybe {draft: 6}?\n\u003c/think\u003e\nSure! Here's the result:\n```json\n{\"score\": 8, \"reason\": \"clear\"}\n```\nHope that helps!\n````\n\n`JSON.parse` throws on all of that. `json-from-llm` returns `{ score: 8, reason: \"clear\" }`.\n\n```ts\nimport { extractJson } from 'json-from-llm';\n\nconst data = extractJson\u003c{ score: number }\u003e(modelOutput);\n```\n\n## Why\n\n- **Reasoning-model aware.** Strips `\u003cthink\u003e` / `\u003cthinking\u003e` blocks first, so brace-laden reasoning (a real cause of `No object generated` failures with DeepSeek R1, Gemini 2.5 thinking, prompted Claude) never gets mistaken for the payload.\n- **Handles the real wrappers.** Markdown fences (`json` and bare ```), conversational prose before/after, and the JSON sitting bare in the text.\n- **String-aware, never corrupts.** The scanner and the trailing-comma repair both respect string contents — a `}` or `,` inside `\"a string value\"` is left alone.\n- **Conservative repair.** Removes trailing commas (the most common malformation); it will never rewrite your data.\n- **Two entry points.** `extractJson` throws on failure; `tryExtractJson` returns `{ found }`.\n- **Zero dependencies**, ESM + CJS, fully typed.\n\n## Install\n\n```sh\nnpm install json-from-llm\n```\n\n## API\n\n### `extractJson\u003cT\u003e(text, options?) =\u003e T`\n\nReturns the extracted JSON value, or throws `JsonExtractionError` if none can be recovered.\n\n### `tryExtractJson\u003cT\u003e(text, options?) =\u003e { found: true, value: T } | { found: false }`\n\nThe non-throwing variant.\n\n### Options\n\n```ts\ninterface ExtractOptions {\n  repair?: boolean; // remove trailing commas (default true)\n  expect?: 'object' | 'array' | 'any'; // restrict the top-level type (default 'any')\n}\n```\n\n`expect` is handy when prose contains a stray array but you want the object:\n\n```ts\nextractJson('[1,2] then the answer {\"a\":1}', { expect: 'object' }); // { a: 1 }\n```\n\n### Algorithm\n\n1. Strip `\u003cthink\u003e` / `\u003cthinking\u003e` / `\u003creasoning\u003e` blocks.\n2. Prefer the contents of fenced `json (or bare `) code blocks.\n3. Otherwise scan for the first balanced `{…}` / `[…]` that parses, string-aware.\n4. If parsing fails, apply conservative repair (trailing commas) and retry.\n\nThe low-level pieces (`stripReasoning`, `fencedBlocks`, `balancedSpans`, `removeTrailingCommas`) are exported too.\n\n## Related\n\n- [`tool-schema`](https://www.npmjs.com/package/tool-schema) — turn a JSON Schema into a provider tool/function schema (define the shape you then extract).\n- [`llm-sse`](https://www.npmjs.com/package/llm-sse) · [`llm-messages`](https://www.npmjs.com/package/llm-messages) · [`llm-errors`](https://www.npmjs.com/package/llm-errors) — the provider-portability suite.\n\n## License\n\nMIT © Sebastian Legarraga\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslegarraga%2Fjson-from-llm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fslegarraga%2Fjson-from-llm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fslegarraga%2Fjson-from-llm/lists"}