{"_id":"openai-harmony-js","name":"openai-harmony-js","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"openai-harmony-js","version":"1.0.0","description":"TypeScript/JavaScript utilities for the GPT‑OSS Harmony format: renderers, parsers, tokenizers, and streaming helpers","license":"MIT","type":"module","main":"dist/index.js","types":"dist/index.d.ts","sideEffects":false,"publishConfig":{"access":"public"},"engines":{"node":">=18"},"scripts":{"build":"tsc -p tsconfig.json","test":"vitest run --coverage","test:watch":"vitest","typecheck":"tsc -p tsconfig.json --noEmit","lint":"eslint . --ext .ts","lint:fix":"eslint . --ext .ts --fix","format":"prettier --write .","format:check":"prettier --check .","prepack":"npm run build && npm run test","prepublishOnly":"npm run typecheck && npm run lint","prepare":"husky"},"keywords":["harmony","openai","gpt-oss","parser","renderer","tokenizer","streaming","typescript","javascript","llm","ai","conversation","format","tool-calls"],"repository":{"type":"git","url":"git+https://github.com/fredrikalindh/openai-harmony-js.git"},"bugs":{"url":"https://github.com/fredrikalindh/openai-harmony-js/issues"},"homepage":"https://github.com/fredrikalindh/openai-harmony-js#readme","author":{"name":"Fredrika Lindh"},"devDependencies":{"@types/node":"^20.11.0","@vitest/coverage-v8":"^1.6.0","eslint":"^8.57.0","@typescript-eslint/eslint-plugin":"^6.21.0","@typescript-eslint/parser":"^6.21.0","eslint-config-prettier":"^9.1.0","eslint-plugin-import":"^2.29.1","eslint-plugin-unused-imports":"^3.1.0","husky":"^9.0.11","lint-staged":"^15.2.2","prettier":"^3.3.3","typescript":"^5.4.0","vitest":"^1.6.0"},"lint-staged":{"*.{ts,js,json,md,yml,yaml}":["prettier --write"],"*.ts":["eslint --fix"]},"_id":"openai-harmony-js@1.0.0","gitHead":"f92411768d5e37773aab65a1b340f86d1796cc4f","_nodeVersion":"22.18.0","_npmVersion":"10.9.3","dist":{"integrity":"sha512-fB/t8/sAEeTK9z153pm/R6dyX/V+XzDdlfHsTIdxYzR9BavMxajLmL5Ysj0r4L0JsO723HolnWIDp/5Hl2faoA==","shasum":"372235ec058336ddb5b0ef45845b3039c6f94ead","tarball":"https://registry.npmjs.org/openai-harmony-js/-/openai-harmony-js-1.0.0.tgz","fileCount":7,"unpackedSize":62378,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICUjcTQ0PIzcK2umax4W5sYkfWSM3ip89ZGhxXKgOyU/AiEA3GjQaXNMmngYowChRL7ipaBOq7J95KjCVOieiNphf6g="}]},"_npmUser":{"name":"fredrika","email":"fredrikalindh@gmail.com"},"directories":{},"maintainers":[{"name":"fredrika","email":"fredrikalindh@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/openai-harmony-js_1.0.0_1755163996582_0.5074747232022867"},"_hasShrinkwrap":false}},"time":{"created":"2025-08-14T09:33:16.463Z","1.0.0":"2025-08-14T09:33:16.772Z","modified":"2025-08-14T09:33:17.080Z"},"maintainers":[{"name":"fredrika","email":"fredrikalindh@gmail.com"}],"description":"TypeScript/JavaScript utilities for the GPT‑OSS Harmony format: renderers, parsers, tokenizers, and streaming helpers","homepage":"https://github.com/fredrikalindh/openai-harmony-js#readme","keywords":["harmony","openai","gpt-oss","parser","renderer","tokenizer","streaming","typescript","javascript","llm","ai","conversation","format","tool-calls"],"repository":{"type":"git","url":"git+https://github.com/fredrikalindh/openai-harmony-js.git"},"author":{"name":"Fredrika Lindh"},"bugs":{"url":"https://github.com/fredrikalindh/openai-harmony-js/issues"},"license":"MIT","readme":"# openai-harmony-js\n\nTypeScript/JavaScript utilities for the GPT‑OSS Harmony format: renderers, parsers, tokenizers, and streaming helpers.\n\n[OpenAI Harmony reference](https://github.com/openai/harmony)\n\n[![npm version](https://img.shields.io/npm/v/openai-harmony-js.svg)](https://www.npmts.com/package/openai-harmony-js)\n[![node](https://img.shields.io/node/v/openai-harmony-js.svg)](https://www.npmts.com/package/openai-harmony-js)\n[![license](https://img.shields.io/npm/l/openai-harmony-js.svg)](LICENSE)\n\n### Features\n\n- Render a structured conversation to Harmony completion tokens\n- Parse token arrays back into a typed conversation\n- Tokenize raw completion strings and parse conversations directly from strings\n- Detect Harmony-formatted strings\n- Extract \"analysis\" (reasoning), \"final\", and \"commentary\" text from GPT‑OSS streams\n- Incremental streaming parser for live updates\n- ESM-first, TypeScript types included, Node ≥ 18\n\n### Installation\n\n```bash\nnpm install openai-harmony-js\n# or\nyarn add openai-harmony-js\n# or\npnpm add openai-harmony-js\n# or\nbun add openai-harmony-js\n```\n\n### Quick start\n\n```ts\nimport {\n  Conversation,\n  Message,\n  renderConversation,\n  parseTokens,\n  type HarmonyConversation,\n} from \"openai-harmony-js\";\n\nconst convo: HarmonyConversation = Conversation.fromMessages([\n  Message.fromRoleAndContent(\"system\", \"You are a helpful assistant.\"),\n  Message.fromRoleAndContent(\"user\", \"Hello!\"),\n]);\n\n// Render to Harmony completion tokens\nconst tokens = renderConversation(convo);\n\n// Parse tokens back to a typed structure\nconst roundTripped = parseTokens(tokens);\n```\n\n### Parsing a Harmony completion string\n\nIf you receive a raw completion string containing Harmony markers like `<|start|>`, `<|channel|>`, `<|message|>`, and `<|end|>`, you can tokenize and parse directly:\n\n```ts\nimport { tokenizeCompletionString, parseConversationFromString } from \"openai-harmony-js\";\n\nconst raw = \"\" + \"<|start|>assistant\" + \"<|channel|>message<|message|>Hello there!\" + \"<|end|>\";\n\nconst tokens = tokenizeCompletionString(raw);\nconst conversation = parseConversationFromString(raw);\n```\n\n### Extracting reasoning/final text from streams\n\nGPT‑OSS models often stream Harmony strings that contain channels like `analysis`, `final`, and `commentary`. Use these helpers to extract text safely at any time:\n\n```ts\nimport { extractReasoningContent, extractFinalContent } from \"openai-harmony-js\";\n\nconst streamed = \"...<|channel|>analysis<|message|>thinking...<|end|>...\";\nconst analysis = extractReasoningContent(streamed); // \"thinking...\"\nconst final = extractFinalContent(streamed); // prefers `final`, falls back to `commentary`\n```\n\n### Incremental streaming parser\n\nUse `HarmonyStreamParser` to accumulate partial chunks and get incremental snapshots (current analysis/final/commentary, last channel, and completeness):\n\n```ts\nimport { HarmonyStreamParser } from \"openai-harmony-js\";\n\nconst stream = new HarmonyStreamParser();\n\n// In your streaming loop, call addContent with the latest chunk\nconst result1 = stream.addContent(\"<|start|>assistant<|channel|>analysis<|message|>plan\");\n// result1.currentAnalysis === \"plan\" (partial)\n\nconst result2 = stream.addContent(\" more<|end|>\");\n// result2.currentAnalysis === \"plan more\"\n// result2.isComplete indicates whether <|start|> and <|end|> counts match\n\n// Access the full buffer if needed\nconst full = stream.getBuffer();\n```\n\n### Custom delimiters\n\nBy default, delimiters are `<|start|>`, `<|message|>`, and `<|end|>`. You can override them:\n\n```ts\nimport { renderConversation, createParser, type HarmonyDelimiters } from \"openai-harmony-js\";\n\nconst custom: HarmonyDelimiters = {\n  start: \"<<S>>\",\n  message: \"<<M>>\",\n  end: \"<<E>>\",\n};\n\nconst tokens = renderConversation({ messages: [] }, { delimiters: custom });\n\nconst parser = createParser();\nfor (const t of tokens) parser.push(t, custom);\nconst parsed = parser.finish();\n```\n\n### Roles and channels\n\n- Roles: `system`, `developer`, `user`, `assistant`, `tool`\n- Content chunk channels (structured): `message`, `reasoning`, `tool`, `function`, `error`\n- String helper channels (raw Harmony strings): `analysis`, `final`, `commentary`\n\nThis library accepts structured `HarmonyMessage` content with channels suited for token rendering, and also provides string-level helpers that target the GPT‑OSS convention (`analysis`/`final`/`commentary`) for easy extraction while streaming.\n\n### Encoding facade\n\n```ts\nimport { loadHarmonyEncoding } from \"openai-harmony-js\";\n\nconst enc = loadHarmonyEncoding(\"HARMONY_GPT_OSS\");\nconst tokens = enc.renderConversationForCompletion({ messages: [] });\nconst parsed = enc.parseMessagesFromCompletionTokens(tokens);\n```\n\n### API reference (surface)\n\n- `renderConversation(conversation, options?) => string[]`\n- `createParser() => { push(token, delimiters?), finish() }`\n- `parseTokens(tokens, delimiters?) => HarmonyConversation`\n- `tokenizeCompletionString(input, delimiters?) => string[]`\n- `parseConversationFromString(input, delimiters?) => HarmonyConversation`\n- `isHarmonyFormat(input, delimiters?) => boolean`\n- `extractReasoningContent(input) => string`\n- `extractFinalContent(input) => string`\n- `HarmonyStreamParser` class for incremental parsing\n- `Message.fromRoleAndContent(role, content)`\n- `Conversation.fromMessages(messages)`\n- `loadHarmonyEncoding(name)`\n\nTypes (partial): `HarmonyConversation`, `HarmonyMessage`, `HarmonyContentChunk`, `HarmonyRole`, `HarmonyChannel`, `HarmonyDelimiters`, `StreamParseResult`.\n\n### Requirements\n\n- Node.js 18 or newer\n- ESM only (use `import` syntax)\n\n### License\n\nMIT — see `LICENSE`.\n\n### Acknowledgements\n\nThis project mirrors concepts from the Harmony format by OpenAI and aims for parity with the Python reference where practical.\n","readmeFilename":"README.md","_rev":"1-7ccfc61f9f27e29f6572a897f1160eb8"}