{"_id":"@actae/sdk","name":"@actae/sdk","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@actae/sdk","version":"0.1.0","description":"TypeScript SDK for Actae — a real-time event store for agent workflows. Feature-parity port of the Python SDK (actae-client).","type":"module","license":"MIT","repository":{"type":"git","url":"git+https://github.com/BViganotti/new_actae.git","directory":"sdks/typescript"},"homepage":"https://actae.dev/docs/sdks/typescript/","bugs":{"url":"https://github.com/BViganotti/new_actae/issues"},"engines":{"node":">=20"},"main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./adapters/langgraph":{"types":"./dist/adapters/langgraph.d.ts","default":"./dist/adapters/langgraph.js"},"./adapters/langchain":{"types":"./dist/adapters/langchain.d.ts","default":"./dist/adapters/langchain.js"},"./adapters/claude":{"types":"./dist/adapters/claude.d.ts","default":"./dist/adapters/claude.js"},"./adapters/openai":{"types":"./dist/adapters/openai.d.ts","default":"./dist/adapters/openai.js"},"./adapters/codex":{"types":"./dist/adapters/codex.d.ts","default":"./dist/adapters/codex.js"},"./adapters/copilot":{"types":"./dist/adapters/copilot.d.ts","default":"./dist/adapters/copilot.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","test:live":"vitest run --config vitest.live.config.ts","smoke":"node smoke/smoke.mjs"},"keywords":["actae","agents","event-store","websocket","fork","resume","state"],"dependencies":{"ws":"^8.18.0"},"devDependencies":{"@anthropic-ai/claude-agent-sdk":"^0.3.226","@github/copilot-sdk":"^1.0.9","@langchain/core":"^1.2.5","@langchain/langgraph":"^1.4.9","@openai/agents":"^0.14.3","@types/node":"^22.10.0","@types/ws":"^8.5.13","@vitest/coverage-v8":"^3.2.7","typescript":"^5.7.2","vitest":"^3.0.0"},"_id":"@actae/sdk@0.1.0","gitHead":"1e47fdc0a1b1f5f06be6812ff9c5e19bb571e349","_nodeVersion":"24.5.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-pzEhXAwAopyWPcwlKFxx5OffHXUeTbhtZEZ0SO/NDFMBQ9F/WjzDzDGSXKcTDkbuuL5QHCEor6BvVw6lLuEhOA==","shasum":"849d8b6f04f9355f9ebf6fd80eb5a9d5b51361bd","tarball":"https://registry.npmjs.org/@actae/sdk/-/sdk-0.1.0.tgz","fileCount":79,"unpackedSize":654928,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQD9HjF/cmTQGJ8BkeRtAOaXf6gQ48nWYBr+ggm+dU3A2gIhAII9xdKojTYcHdwyLw8SJLOP5zq2z3ycEtTcFsE9JOP9"}]},"_npmUser":{"name":"bviganotti","email":"hello@actae.dev"},"directories":{},"maintainers":[{"name":"bviganotti","email":"hello@actae.dev"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.1.0_1787642905861_0.010749477192669277"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-25T07:28:25.723Z","0.1.0":"2026-08-25T07:28:26.001Z","modified":"2026-08-25T07:28:26.195Z"},"maintainers":[{"name":"bviganotti","email":"hello@actae.dev"}],"description":"TypeScript SDK for Actae — a real-time event store for agent workflows. Feature-parity port of the Python SDK (actae-client).","homepage":"https://actae.dev/docs/sdks/typescript/","keywords":["actae","agents","event-store","websocket","fork","resume","state"],"repository":{"type":"git","url":"git+https://github.com/BViganotti/new_actae.git","directory":"sdks/typescript"},"bugs":{"url":"https://github.com/BViganotti/new_actae/issues"},"license":"MIT","readme":"# Actae TypeScript SDK\n\n> Distributed agent coordination and Group Fork are documented in [`../../docs/EXECUTION_GROUPS.md`](../../docs/EXECUTION_GROUPS.md). `client.executionGroup(id)` exposes durable messaging, fenced leases, `waitFor`/`waitAny`/`waitAll`, acknowledgements, promotion, and receipts.\n\nTypeScript client for **Actae** — a real-time event store for agent\nworkflows. Feature-parity port of the [Python SDK](../python/README.md) and\nthe [Go SDK](../go/README.md). Node 20+ ESM-only.\n\n```\n@actae/sdk · Node ≥ 20 · runtime dependency: ws\n```\n\n> **Gotchas at a glance** (full details below): the server never echoes your\n> own WebSocket publishes back to you (use `echoSelf`), payload numbers that\n> exceed `Number.MAX_SAFE_INTEGER` arrive as `bigint` (use `asInt64`/\n> `asBigInt`), and the JSON serializer emits bigint as raw number tokens (so\n> values received from `parseJson` round-trip without precision loss).\n\n## Installation\n\n```bash\nnpm install @actae/sdk\n```\n\n## 60-second start\n\n```ts\nimport { ActaeClient } from '@actae/sdk';\n\nconst client = new ActaeClient({\n  apiKey: 'sk-dev-0000000000000000000000',\n  endpoint: 'http://localhost:8002',\n});\n\n// Record an event, then replay it back\nconst ev = await client.record('my-channel', 'agent.step', { input: 'hello' }, { actor: 'agent' });\nconst events = await client.replay('my-channel', { limit: 100 });\n```\n\nThat's the whole loop: **channels** are named event streams, **events** are\nimmutable JSON blobs with a monotonic cursor, and **replay** reads them back.\nEverything else is a convenience or specialization on top of that.\n(`newClientFromEnv()` reads `ACTAE_URL`, `ACTAE_WS_URL`, `ACTAE_API_KEY`.)\n\n## API surface\n\nThe SDK mirrors the Python SDK's `ActaeClient` 1:1. Every HTTP method is\navailable directly and through namespaced facades (`client.events.record(...)`\n=== `client.record(...)`).\n\n| Area | Client methods | Facade |\n|------|---------------|--------|\n| Events | `record`, `replay`, `query`, `getCursor`, `latestCursor`, `transition` | `client.events` |\n| State | `saveState`, `latestState`, `listStates`, `getState`, `deleteState` | `client.state` |\n| Channels/forks | `listChannels`, `fork`, `getForkReceipt`, `resolveStep`, `getChannelMetadata`, `listBranches`, `getExecutionTree`, `updateMetadata`, `deleteChannel`, `setOutcome`, `promoteChannel`, `diffStates`, `decisionTrail`, `compareChannels` | `client.channels` |\n| Experiments | `createExperiment`, `listExperiments`, `addExperimentMember`, `rankExperiment` | — |\n| Tool executions | `claimExecution`, `completeExecution`, `failExecution`, `heartbeatExecution`, `cancelExecution`, `getExecution`, `listExecutions`, `deleteExecution` | `client.executions` |\n| Consumer groups | `createGroup`, `listGroups`, `deleteGroup`, `joinGroup`, `claimWork`, `ackWork`, `heartbeat`, `groupOffsets` | `client.groups` |\n| Wake-ups | `scheduleWakeup`, `listWakeups`, `getWakeup`, `cancelWakeup` | `client.wakeups` |\n| Health/metrics | `healthCheck`, `readinessCheck`, `getMetricsText`, `getMetricsJson` | `client.health` |\n| Auth (JWT) | `signup`, `login`, `logout`, `getMe` | `client.auth` |\n| WebSocket | `connect`, `disconnect`, `subscribe`, `subscribeAndWait`, `unsubscribe`, `publish`, `stream`, callbacks | `client.ws` |\n\n## Errors\n\nAll SDK errors extend `ActaeError`. HTTP/WS failures map to typed classes:\n\n| Situation | Error |\n|-----------|-------|\n| 401 / bad WS auth | `AuthError` |\n| 402 (control-plane lock) | `LockError` |\n| transport (refused/timeout/drop) | `ConnectionError` |\n| 429 | `RateLimitError` (`retryAfterSeconds`) |\n| 404 | `NotFoundError` / `ExecutionNotFoundError` |\n| 409 fork boundary | `SnapshotBoundaryError` |\n| 409 version guard | `VersionConflictError` |\n| 409 idempotency / channel | `IdempotencyConflictError` / `ChannelConflictError` |\n| 409 execution claim | `ExecutionNotOwnedError` / `IdempotencyKeyMismatchError` |\n| 409 consumer group | `ConsumerError` |\n| session lifecycle | `SessionError` / `SessionCompletedError` / `NoRestorableCheckpointError` |\n| wake-up already fired | `WakeupAlreadyFiredError` |\n| generic 5xx | `ServerError` |\n\nUse `instanceof` to branch:\n\n```ts\ntry {\n  await client.record(...);\n} catch (err) {\n  if (err instanceof AuthError) { /* wrong key */ }\n  if (err instanceof ConnectionError) { /* retry */ }\n}\n```\n\n## WebSocket realtime\n\n```ts\nawait client.connect();\nclient.onMessage((topic, event) => console.log(topic, event));\nawait client.subscribe('my-channel', 0);          // cursor 0 = replay from start\nconst ev = await client.publish('my-channel', { note: 'hi' }); // returns persisted event\nawait client.unsubscribe('my-channel');\nclient.disconnect();\n```\n\n- `onMessage` callbacks accumulate; `onError`, `onSubscribed`,\n  `onDisconnected`, `onReconnect` are single-slot.\n- The server **does not echo broadcasts back to the publishing connection** —\n  delivery tests use two clients. For a single-client demo set\n  `echoSelf: true` (ClientOptions).\n- `publish(topic, payload, { operationId })` returns the persisted `Event`\n  from the server ack (no HTTP round-trip). A stable `operationId` makes\n  retries idempotent.\n- `client.stream(topic, cursor?)` returns an async iterator of live events\n  (Python `stream()` parity); it ends when the connection drops.\n- Auto-reconnect (backoff 0.5s → 30s, cap 10 failures) resubscribes all\n  topics; `disconnect()` disables it permanently.\n\n## AgentSession — step / fork / resume\n\n```ts\nimport { ActaeClient, AgentSession } from '@actae/sdk';\n\nconst session = new AgentSession(client, 'my-run', {\n  stateFn: () => ({ messages: state.messages }),  // snapshots every step\n  snapshotInterval: 1,\n});\nawait session.start();\nawait session.step('agent.step', { input: { n: 1 }, output: { ok: true } });\n\n// Fork at step 1 → the fork continues at step 2 with steps 1..1's state,\n// without re-running step 1.\nconst fork = await session.fork(1, 'my-run-fix', { reason: 'refine step 2' });\nawait fork.start();\nawait fork.step('agent.step', { input: { refined: true }, output: { ok: true } });\n```\n\n- `boundaryMode`: `'exact'` (default — raises `NoRestorableCheckpointError`\n  when no snapshot exists at the boundary), `'approximate'` (falls back to\n  latest state, reports drift via `resolvedBoundaryCursor`),\n  `'lineage_only'` (no state copy).\n- `AgentSession.resume(client, channelId, { forkAtStep, name })` does crash\n  recovery (in-place) or fork-from-existing; raising\n  `SessionCompletedError` on completed non-fork resume.\n- Boundary provenance is exposed on the session (`forkReceipt`,\n  `boundaryRestorable`, `requestedBoundaryCursor`, `resolvedBoundaryCursor`,\n  `sourceStateSha256`, `reproducibility`).\n\n## StateManager\n\nFramework-agnostic versioned state:\n\n```ts\nimport { StateManager } from '@actae/sdk';\nconst mgr = new StateManager(client, 'my-agent');\nawait mgr.save({ messages: [] });\nconst state = await mgr.resume({ messages: [] });\nawait mgr.fork('my-agent-fix', { reason: 'refine' });\n```\n\n## Adapters\n\nEach adapter lives behind a subpath export and imports its framework lazily —\nthe core SDK has **no** dependency on LangGraph/LangChain/Claude/OpenAI.\n\n```ts\nimport { ActaeCheckpointSaver } from '@actae/sdk/adapters/langgraph';\nimport { ActaeContextSaver, ChainResumer } from '@actae/sdk/adapters/langchain';\nimport { ActaeClaudeSessionStore } from '@actae/sdk/adapters/claude';\nimport { installActaeTracing } from '@actae/sdk/adapters/openai';\nimport { CodexOTLPReceiver } from '@actae/sdk/adapters/codex';\nimport { CopilotManager } from '@actae/sdk/adapters/copilot';\n```\n\n- **LangGraph.js** — `ActaeCheckpointSaver` implements the checkpoint-saver\n  protocol (put/putWrites/getTuple/list/deleteThread/get + `forkThread`)\n  backed by Actae state snapshots; verified against a real `StateGraph`.\n- **LangChain.js** — `ActaeContextSaver` (callback handler saving full\n  context every N callbacks) + `ChainResumer` (restart with context);\n  verified against a real `CallbackManager`.\n- **Claude Agent SDK** — `ActaeClaudeSessionStore` implements the real\n  `SessionStore` protocol (camelCase methods, uuid-idempotent appends,\n  `foldSessionSummary` summaries, null-for-absent loads, cascade deletes);\n  verified against `InMemorySessionStore` + compile-time conformance.\n- **OpenAI Agents** — `ActaeTracingProcessor` implements the real\n  `@openai/agents` `TracingProcessor`; `installActaeTracing` registers it;\n  `forkTrace(traceId, newChannel, {reason})` copies one run's snapshot into a\n  new channel (fork-for-comparison — the Agents SDK is stateless);\n  verified against the real SDK (`withTrace` + real `Span` objects).\n- **Codex CLI** — `CodexOTLPReceiver` hosts an OTLP log endpoint mirroring\n  Codex `codex.*` events into per-conversation channels with accumulating\n  token/tool snapshots.\n- **GitHub Copilot** — `CopilotRecorder` + `CopilotManager` record every\n  Copilot session event (dedup, backfill, fork at an event, snapshots) —\n  Go `actae/copilot` parity for `@github/copilot-sdk`.\n\n**Known gap**: no CrewAI adapter — CrewAI has no TypeScript port.\n\n## int64 / bigint fidelity\n\nThe server (sonic-rs) wraps integers that cannot be represented exactly as\nJSON numbers in a marker object. The SDK:\n\n- parses out-of-safe-range integers as `bigint` (never silently rounds);\n- unwraps sonic-rs markers recursively;\n- exposes `asInt64`, `asBigInt`, `asFloat`, `asString`, `asMap`, `asList`\n  accessors mirroring the Go SDK's `As*` helpers;\n- serializes outbound `bigint` as raw JSON number tokens (no precision loss,\n  no `JSON.stringify` TypeError).\n\n```ts\nimport { asInt64, asBigInt } from '@actae/sdk';\nasInt64(event.payload.count);        // number when safe\nasBigInt(event.payload.big_count);   // bigint\n```\n\n## Development\n\n```bash\nnpm install\nnpm run typecheck     # tsc --noEmit\nnpm test              # vitest run (336 unit tests; no server needed)\nnpm run test:coverage # vitest --coverage (~88% lines; src 89%)\nnpm run build         # compile to dist/\nnpm run smoke         # live end-to-end vs a running dev Actae\n```\n\nLive suite (needs `cd actae && cargo run -- --dev`):\n\n```bash\nACTAE_LIVE=1 npm run test:live\n```\n\nExamples (`npm run build` first):\n\n```bash\nnode examples/quickstart.ts\nnode examples/session.ts\n```\n\nAll four framework adapters (LangGraph, LangChain, Claude, OpenAI) are\nverified against their **real** SDKs (devDependencies), plus Codex (real HTTP\nOTLP export) and Copilot (recorder/manager against a fake session). CI\n(`.github/workflows/ci.yml`, `typescript-sdk` job) runs test + typecheck +\nbuild + `npm pack` on every push.\nExecution-group members also provide `subscribeWebSocket()`,\n`unsubscribeWebSocket()`, and `streamWebSocket()` for cursor-replay plus live\nWebSocket delivery of group messages.\n","readmeFilename":"README.md","_rev":"1-5cd6961721d9fd215d0a294c67833377"}