{"_id":"@alethi/pantheon-chat","name":"@alethi/pantheon-chat","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@alethi/pantheon-chat","version":"0.1.0","type":"module","description":"Framework-agnostic Pantheon client and React chat component.","license":"MIT","sideEffects":false,"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js"},"./react":{"types":"./dist/react/index.d.ts","import":"./dist/react/index.js","default":"./dist/react/index.js"}},"typesVersions":{"*":{"react":["./dist/react/index.d.ts"]}},"scripts":{"build":"tsc -p tsconfig.json","clean":"rm -rf dist","prepare":"npm run build","pretest":"npm run build","test":"node --test tests/*.test.mjs"},"engines":{"node":">=18"},"repository":{"type":"git","url":"git+https://github.com/alethibusiness/pantheon.git","directory":"sdk/typescript"},"homepage":"https://pantheon-todo.alethiconsulting.com/docs/","publishConfig":{"access":"public"},"keywords":["pantheon","chat","agents","sse","alethi","react"],"peerDependencies":{"react":">=18","react-dom":">=18"},"peerDependenciesMeta":{"react":{"optional":true},"react-dom":{"optional":true}},"devDependencies":{"@types/react":"18.3.18","@types/react-dom":"18.3.5","happy-dom":"20.14.0","react":"18.3.1","react-dom":"18.3.1","typescript":"5.8.3"},"_id":"@alethi/pantheon-chat@0.1.0","gitHead":"ee1d659dca787b8756e71a85baf9a420a968a643","bugs":{"url":"https://github.com/alethibusiness/pantheon/issues"},"_nodeVersion":"22.22.0","_npmVersion":"10.9.4","dist":{"integrity":"sha512-icTfJAc7JFGczfwP1JTS/BCXMEjJCvcQS40dPIjCZRHVUnckXkihoheG/Q3vLEpv61QZEjoB6RNYmSZgJYUOoA==","shasum":"6b260115e3f421d1737aa2238bf9141cd7abbf22","tarball":"https://registry.npmjs.org/@alethi/pantheon-chat/-/pantheon-chat-0.1.0.tgz","fileCount":43,"unpackedSize":164119,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDRu5DunYzaPW4or5Nloneft9uU+Ba4JPB2v70Ad+OnowIgJcI0kiDabq0ddF2U0x+lwrpfwXkVzl3sAyYN4Or62c0="}]},"_npmUser":{"name":"alethi","email":"alethibusiness@gmail.com"},"directories":{},"maintainers":[{"name":"alethi","email":"alethibusiness@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/pantheon-chat_0.1.0_1788667663893_0.7505950092014553"},"_hasShrinkwrap":false}},"time":{"created":"2026-09-06T04:07:43.776Z","0.1.0":"2026-09-06T04:07:44.058Z","modified":"2026-09-06T04:07:44.277Z"},"maintainers":[{"name":"alethi","email":"alethibusiness@gmail.com"}],"description":"Framework-agnostic Pantheon client and React chat component.","homepage":"https://pantheon-todo.alethiconsulting.com/docs/","keywords":["pantheon","chat","agents","sse","alethi","react"],"repository":{"type":"git","url":"git+https://github.com/alethibusiness/pantheon.git","directory":"sdk/typescript"},"bugs":{"url":"https://github.com/alethibusiness/pantheon/issues"},"license":"MIT","readme":"# @alethi/pantheon-chat\n\nTypeScript client and React chat for the Pantheon `/v1` API. Works in browsers and Node 18+. The core client has no runtime dependencies.\n\nDocs: [https://pantheon-todo.alethiconsulting.com/docs/](https://pantheon-todo.alethiconsulting.com/docs/)\n\n## Install\n\n```bash\nnpm install @alethi/pantheon-chat\n```\n\nReact apps that import `@alethi/pantheon-chat/react` also install `react` and `react-dom` (18 or newer). Apps that import only `@alethi/pantheon-chat` do not need React.\n\nEvery request uses `{baseUrl}/v1/...` and sends `Authorization: Bearer {apiKey}`. Set `baseUrl` to your Pantheon origin (no trailing slash required), for example `https://pantheon-todo.alethiconsulting.com/pantheon-api`.\n\n## Vanilla client\n\n```js\nimport { PantheonClient } from \"@alethi/pantheon-chat\";\n\nconst baseUrl = process.env.PANTHEON_BASE_URL;\nconst apiKey = process.env.PANTHEON_API_KEY;\nconst client = new PantheonClient({ baseUrl, apiKey });\nconst session = await client.createSession({ agentSlug: \"todo-assistant\" });\nconst run = await client.startRun(session.id, \"Hello\");\nfor await (const event of client.streamEvents(session.id)) {\n  if (event.type === \"message.delta\") process.stdout.write(event.delta.text || \"\");\n  if (event.type === \"run.completed\") break;\n}\n```\n\n## React\n\n```tsx\nimport { PantheonChat } from \"@alethi/pantheon-chat/react\";\n\n<PantheonChat\n  baseUrl=\"https://pantheon.example\"\n  apiKey={apiKey}\n  agentSlug=\"todo-assistant\"\n  tools={{\n    echo_tool: async (input) => ({ echoed: input.message }),\n    todo_ops: { requireApproval: true, execute: async (input) => ({ applied: true, operations: input.operations }) },\n  }}\n/>\n```\n\nServe the examples from this folder after `npm run build`:\n\n```bash\npython3 -m http.server 4173\n# http://127.0.0.1:4173/examples/vanilla.html\n# http://127.0.0.1:4173/examples/react/index.html\n```\n\nPaste any Pantheon base URL and API key into the input boxes.\n\n## Props\n\n| Prop | Type | Notes |\n| --- | --- | --- |\n| `baseUrl` | string | Origin of the Pantheon API, no trailing slash required |\n| `apiKey` | string | Sent as `Authorization: Bearer` |\n| `agentSlug` | string | Session is created with this slug |\n| `deploymentId` | string | Alternative to `agentSlug` |\n| `tools` | `{ [name]: handler \\| { execute, requireApproval } }` | Client-executed application tools |\n| `theme` | `\"light\" \\| \"dark\" \\| \"auto\"` | CSS variables, default `auto` |\n| `title` | string | Session title |\n\nMark a tool with `requireApproval: true` to show an in-page Approve / Decline card before `resumeWithToolResult`.\n\n## Client methods\n\n- `createTool({ name, displayName, description, inputSchema, outputSchema })`\n- `createAgent({ name, slug, model, systemPrompt, toolRequirements, requiresSandbox })`\n- `createDeployment({ agentId, agentVersion, toolDefinitionIds, model })`\n- `deleteAgent(agentId)`\n- `createSession({ agentSlug, deploymentId, title })`\n- `startRun(sessionId, text)`\n- `streamEvents(sessionId, { lastEventId })` async iterator. Reconnects with `Last-Event-ID`, ignores keep-alive comments, and on `stream.resync` re-reads the persisted stream. The React chat keeps the last durable SSE id across turns.\n- `resumeWithToolResult({ sessionId, runId, inReplyToEventId, toolCallId, content, error })` sends a stable per-tool-call `Idempotency-Key` and retries network failures with that same key.\n- `cancelRun(sessionId, runId)` waits for HTTP 202. The chat Stop button does the same and shows an error if cancel fails.\n- `archiveSession(sessionId)`\n\n## Events\n\nDurable events have an SSE `id` and `seq`/`sequence`. Ephemeral events have no id and are never replayed: `message.started`, `message.delta`, `reasoning.delta`, `intermediate.delta`, `stream.resync`.\n\nContent is either a list of `{ type: \"text\", text }` blocks or a JSON object. Tool pause: `tool.started` then `agent.custom_tool_use` then `session.status_idle` with `stop_reason.type = requires_action`. Release four emits the same `tool_call_id` on `tool.started`, `agent.custom_tool_use`, `tool.completed`, and `tool.failed`. The SDK correlates those events strictly by `tool_call_id`, so two concurrent calls to the same tool stay as two pills. `findToolLegacyByNameAndOrder` is a labelled helper for older servers that mismatched those ids; the chat does not use it. Terminal stream events are applied only when they belong to the active `run_id`.\n\n## Chat UI\n\n- Message deltas append inline with whitespace preserved.\n- Reasoning deltas append inline; `reasoning.message` replaces them. Collapsed by default.\n- One tool pill per `tool_call_id` (release four, identical ids across the tool events above), status `running` then `done` or `failed`.\n- Sends typed during a run or a pending approval are queued, with a visible queued notice.\n- Stop waits for cancel HTTP 202. If cancel fails, the error is shown, the run stays `running` or `awaiting_approval`, and Stop can be retried. A successful stop clears queued messages.\n\n## Troubleshooting\n\n**SESSION_BUSY (409).** Another run is active on the session. The error includes `active_run_id`. Call `cancelRun`, or wait and resume the waiting tool. The chat surfaces this as \"Session busy\".\n\n**4xx.** Wrong API key (401/403), unknown session or agent (404), or a malformed body (400). The alert shows the server message.\n\n**5xx.** Pantheon or a dependency failed (sandbox, resume store). Retry. The chat labels this \"Server error\".\n\n**Network loss.** `startRun` failures show \"Network loss\". An open `streamEvents` iterator reconnects with `Last-Event-ID` and keeps keep-alives as comments. If the server emits `stream.resync`, the client re-reads persisted events and continues.\n\n## Tests\n\n```bash\nnpm test\n```\n\nUses `node:test` and the mock server in `tests/mock-pantheon.mjs` (same response shapes as `examples/builder-smoke/mock-pantheon.mjs`).\n","readmeFilename":"README.md","_rev":"1-071aa89e0ec5bc9609b35a53835921a3"}