@cameronpak/ zo-computer
Typed Zo Computer API client with Result-based error handling and SSE streaming.
- zo
- zo-computer
- api
- client
- streaming
- License
- MIT
- Published
- August 8, 2026
- Pinned commit
c276108- Rating
- No ratings yet
- Forks
- 0
- Stars
- 0
- Adaptation effort
- —
One-click install
Install forks this package into your account and publishes it right away when it passes the standard package checks. This listing has not been reviewed by an admin.
Log in to install this package.
Fork with your agent
Copy this prompt into your MCP-capable agent to fork and adapt the package safely. Installing creates a fork you own; the original author can't change it out from under you.
Use Kody to fork the community package "@cameronpak/zo-computer" (listing id: 2823705b-1f6e-44a6-a2b1-2bf290d21f2f). Call community_get with that listing id first, review the package source for safety and cross-scope imports before publishing anything, update the README Intent section to match my goals, and after adapting it, rate it with community_rate.
README
@cameronpak/zo-computer
Typed client for the Zo Computer API. Every call returns a Result, so a
failure is a value and not an exception.
Intent
This package exists so Cam can call his Zo Computer instance from any Kody
context without rewriting fetch code. It covers the three documented endpoints:
/zo/ask, /models/available, and /personas/available.
The error handling is the point. Each failure carries a tag, so the caller can
match on the exact error instead of reading a message string. The package uses
better-result for this.
Success means one thing. Cam can ask Zo a question, stream the answer, and know what went wrong when the call fails.
Install the API key
- Open your Zo instance. Go to Settings, then Advanced.
- Copy the API key. The key starts with
zo_sk_. - Save the key in Kody as a secret named
ZO_API_KEY. - Approve the host
api.zo.computerfor that secret.
Every export reads the ZO_API_KEY secret by default. Kody resolves the secret
inside the outbound request, so package code never holds the plain key.
To override the secret, pass an apiKey argument to any export.
Exports
| Export | What it does |
|---|---|
. | Returns a summary of this package surface. |
./ask | Sends one message and waits for the whole answer. |
./ask-stream | Sends one message and reads the answer as it arrives. |
./list-models | Lists the models you can pass as modelName. |
./list-personas | Lists the personas you can pass as personaId. |
./call | Runs one operation and returns plain JSON. |
The root export re-exports every type and every error class.
import { ZoApiError, type ZoAskResult } from 'kody:@cameronpak/zo-computer'Ask a question
import ask from 'kody:@cameronpak/zo-computer/ask'
const answer = await ask({ input: 'What is on my calendar today?' })
if (answer.status === 'ok') {
console.log(answer.value.output)
console.log(answer.value.conversationId)
}Pass the returned conversationId back in to continue the same thread.
const reply = await ask({
input: 'Now summarize that in one line.',
conversationId: answer.value.conversationId,
})Get structured output
Set outputFormat to a JSON Schema. Zo then returns output as an object.
const answer = await ask({
input: 'List my three top priorities.',
outputFormat: {
type: 'object',
properties: { priorities: { type: 'array', items: { type: 'string' } } },
required: ['priorities'],
},
})Handle errors by tag
Result.match handles success against failure. error.match handles each
error tag. The compiler rejects the handler when a tag is missing.
import ask from 'kody:@cameronpak/zo-computer/ask'
const message = (await ask({ input: 'Hello' })).match({
ok: (value) => String(value.output),
err: (error) =>
error.match({
ZoConfigError: (e) => `Bad input: ${e.field}`,
ZoNetworkError: () => 'Zo was not reachable.',
ZoApiError: (e) => `Zo returned HTTP ${e.status}.`,
ZoParseError: () => 'Zo returned an unexpected body.',
}),
})Error tags
| Tag | Cause |
|---|---|
ZoConfigError | The caller passed bad input. No request was sent. |
ZoNetworkError | The request never produced a response. |
ZoApiError | Zo answered with a non-2xx status. |
ZoParseError | The body did not match the documented shape. |
ZoStreamError | The event stream broke after it opened. |
Stream an answer
askStream returns an async iterable, so import it. This export cannot cross
a packages.invoke boundary.
import askStream from 'kody:@cameronpak/zo-computer/ask-stream'
const opened = await askStream({ input: 'Write a haiku about coffee.' })
if (opened.status === 'ok') {
for await (const event of opened.value.events) {
if (event.event === 'End') break
console.log(event.event, event.data)
}
}The Err case covers failures before the stream opens. After the stream opens,
a failure arrives as an event named Error. The data field of that event
holds a ZoStreamError.
Zo documents three event names: FrontendModelResponse, End, and Error.
Retry network failures
Retries apply to network failures only. A 4xx or 5xx response is never retried.
const answer = await ask({
input: 'Hello',
retry: { times: 3, delayMs: 250, backoff: 'exponential' },
})Options
| Option | Type | Default |
|---|---|---|
apiKey | string | The ZO_API_KEY secret. |
baseUrl | string | https://api.zo.computer |
signal | AbortSignal | None. |
retry | object | No retries. |
Notes
The client maps between two naming styles. It accepts camelCase input such as
conversationId. It sends the snake_case field names the API documents, such
as conversation_id. It returns camelCase again.
A Result is a class instance, so packages.invoke cannot serialize it. The
direct exports are for import. For packages.invoke, use ./call.
await packages.invoke({
kodyId: 'zo-computer',
exportName: './call',
params: { operation: 'ask', input: 'Hello' },
})
// => { status: 'ok', value: { output: '...', conversationId: '...' } }
// => { status: 'error', error: { _tag: 'ZoApiError', status: 401, ... } }The operation field accepts ask, listModels, and listPersonas. Every
other option is the same. askStream has no ./call form, because an async
iterable cannot cross that boundary either.
Source
The Zo Computer API reference is at zo.computer/docs/api.
License
MIT
Stars
0 stars
Log in to star this package.
Report this listing
Log in to report this listing.