← Public packages
@cameronpak/zo-computer
Typed Zo Computer API client with Result-based error handling and SSE streaming.
src/ask.ts
75 lines · 2.2 KB · TypeScriptimport { Result } from 'better-result'
import { isRecord, zoJson } from './core'
import { ZoConfigError, ZoParseError, type ZoRequestError } from './errors'
import type { ZoAskInput, ZoAskResult, ZoClientOptions } from './types'
/**
* Send one message to Zo and wait for the whole answer.
*
* Set `outputFormat` to a JSON Schema when you want `output` as an object.
* Pass the returned `conversationId` back in to continue the thread.
*
* @example
* import ask from 'kody:@cameronpak/zo-computer/ask'
* const answer = await ask({ input: 'Summarize my week' })
* if (answer.status === 'ok') console.log(answer.value.output)
*/
export default async function ask(
params: ZoAskInput & ZoClientOptions,
): Promise<Result<ZoAskResult, ZoRequestError>> {
if (typeof params?.input !== 'string' || params.input.trim() === '') {
return Result.err(
new ZoConfigError({
field: 'input',
message: 'input must be a non-empty string',
}),
)
}
const body: Record<string, unknown> = { input: params.input, stream: false }
if (params.conversationId !== undefined) {
body.conversation_id = params.conversationId
}
if (params.modelName !== undefined) body.model_name = params.modelName
if (params.personaId !== undefined) body.persona_id = params.personaId
if (params.outputFormat !== undefined) {
body.output_format = params.outputFormat
}
const parsed = await zoJson(
'/zo/ask',
{ method: 'POST', accept: 'application/json', body },
params,
)
if (Result.isError(parsed)) return parsed
const payload = parsed.value
if (!isRecord(payload) || !('output' in payload)) {
return Result.err(
new ZoParseError({
url: '/zo/ask',
body: JSON.stringify(payload).slice(0, 2000),
message: 'Zo response did not contain an output field',
}),
)
}
const output = payload.output
if (typeof output !== 'string' && !isRecord(output)) {
return Result.err(
new ZoParseError({
url: '/zo/ask',
body: JSON.stringify(payload).slice(0, 2000),
message: 'Zo output was neither a string nor an object',
}),
)
}
return Result.ok({
output,
conversationId:
typeof payload.conversation_id === 'string'
? payload.conversation_id
: '',
})
}