@beeos-ai/beeos-types
v1.0.0
Published
Domain-namespaced TypeScript wire types for BeeOS protocols (ACP today; platform / a2a coming). Independent of upstream @agentclientprotocol/sdk.
Maintainers
Readme
@beeos-ai/beeos-types
Domain-namespaced TypeScript wire types for BeeOS protocols.
Today this package ships one domain — acp — which covers the full agent client protocol
spoken between beeos-claw agents and the web / mobile SDKs. The layout is designed so
future domains (platform, a2a, …) can be added without churn in existing consumers.
This package is the single source of truth for the JSON-over-WebSocket protocol that flows
between BeeOS agents and their front-end clients. It is independent of the upstream
@agentclientprotocol/sdk — BeeOS operates a proxy layer that adapts ACP for multi-tenant
cloud deployment.
Install
npm install @beeos-ai/beeos-typesUsage
All protocol types live under a domain namespace. The package root intentionally does not re-export types flat: this forces the domain to appear at the call site, which is what makes the package extensible without collisions.
Pick whichever style suits the file:
Option A — subpath import (preferred for heavy type files)
import type {
ServerSessionUpdate,
ClientSessionUpdate,
AgentMessageChunkUpdate,
ToolCallStartUpdate,
StreamCompleteOk,
StreamCompleteErr,
} from "@beeos-ai/beeos-types/acp";
function handle(update: ClientSessionUpdate) {
switch (update.sessionUpdate) {
case "agent_message_chunk":
// update.content is narrowed to TextBlock | ImageBlock | ResourceLinkBlock
break;
case "stream_complete":
if (update.stopReason === "error") {
// update.error is narrowed to string (required)
}
break;
}
}Option B — namespace import (preferred when mixing multiple future domains)
import { acp } from "@beeos-ai/beeos-types";
const update: acp.ClientSessionUpdate = /* ... */;Produce messages (factories, type-safe, no as any)
import {
makeAgentMessageChunk,
makeToolCallStart,
makeStreamCompleteError,
} from "@beeos-ai/beeos-types/acp/factories";
const chunk = makeAgentMessageChunk("Hello", { _turnId: "run-abc" });
const err = makeStreamCompleteError("Provider timed out");Normalize snake_case payloads (legacy interop)
import { normalizeSessionUpdate } from "@beeos-ai/beeos-types/acp/normalize";
// Converts upstream snake_case keys (tool_call_id, raw_input) to camelCase
// and trims unknown fields before feeding to chat-store.
const camel = normalizeSessionUpdate(rawWireMessage);Design principles
- Domain-namespaced — every protocol lives under its own directory / namespace. The root barrel only re-exports namespaces, never flat types. This is Interface Segregation at the package level: adding a new domain can never rename or shadow an existing symbol.
- Protocol is a contract, not an implementation — types live in a versioned package so
beeos-claw,web, andmobiledepend on the same source. - Discriminated unions — every
sessionUpdatevariant and JSON-RPCmethodis a separate interface keyed by a string literal;switchstatements are provably exhaustive. - LSP subset —
ServerSessionUpdate ⊂ ClientSessionUpdate. The transport signature uses the narrower type, the reducer signature uses the wider one. - Zero runtime deps —
@a2ui/reactand other UI frameworks are decoupled via genericCanvasUpdateEnvelope<TMessage = unknown>; consumers instantiate with their message type. - Branded IDs —
JsonRpcId,SessionId,ToolCallId,MessageIdare nominal string types preventing accidental cross-use.
Package layout
src/
├── index.ts # root barrel: `export * as acp` only
└── acp/ # ACP protocol domain
├── index.ts # acp barrel
├── meta.ts # ACP_PROTOCOL_VERSION, ResponseMeta
├── ids.ts # branded IDs
├── enums.ts # ToolKind / ToolStatus / StopReason / MessageRole
├── run-outcome.ts # RunOutcomeShape for prompt termination
├── normalize.ts # runtime snake_case ↔ camelCase helper
├── content/ # ContentBlock variants (Text/Image/Audio/File/Resource/ResourceLink)
├── session-update/ # 16 sessionUpdate variants + ServerSessionUpdate / ClientSessionUpdate
├── json-rpc/ # envelope + 29 method-specific params/results + registry
└── factories/ # type-safe builders (replaces all `as unknown as ACPUpdatePayload`)Subpath exports in package.json:
| Subpath | Contents |
| ------------------------------------ | ------------------------------------------- |
| @beeos-ai/beeos-types | root barrel — acp namespace only |
| @beeos-ai/beeos-types/acp | all ACP types (flat) |
| @beeos-ai/beeos-types/acp/factories| message factories |
| @beeos-ai/beeos-types/acp/normalize| snake_case ↔ camelCase normalizer |
Versioning
1.x— API stable. Breaking changes to a domain surface only ship at majors.- Adding a new domain (e.g.
platform,a2a) is a minor bump: existing consumers are unaffected because the root barrel only exposes namespaces.
Compatible with:
beeos-claw>= 0.2.41@beeos/sdk(web/mobile) via facade re-exports
Migration from 0.x
1.0.0 is a breaking change on the import path only; the runtime wire protocol and all
type shapes are identical to 0.1.0-beta.4. Pick the style that fits each file and do a
whole-repo find/replace:
| 0.x | 1.0 |
| ------------------------------------------------------ | ------------------------------------------------------------ |
| from "@beeos-ai/beeos-types" | from "@beeos-ai/beeos-types/acp" |
| from "@beeos-ai/beeos-types/factories" | from "@beeos-ai/beeos-types/acp/factories" |
| from "@beeos-ai/beeos-types/normalize" | from "@beeos-ai/beeos-types/acp/normalize" |
If you prefer namespaced access, the alternative is:
import { acp } from "@beeos-ai/beeos-types";
type X = acp.ClientSessionUpdate;License
MIT
