Skip to content
← Public packages

@cameronpak/zo-computer

Typed Zo Computer API client with Result-based error handling and SSE streaming.

src/list-personas.ts

54 lines · 1.6 KB · TypeScript
import { Result } from 'better-result'
import { isRecord, zoJson } from './core'
import { ZoParseError, type ZoRequestError } from './errors'
import type { ZoClientOptions, ZoPersona } from './types'

function toPersona(raw: unknown): ZoPersona | null {
	if (!isRecord(raw)) return null
	if (typeof raw.id !== 'string') return null
	return {
		id: raw.id,
		name: typeof raw.name === 'string' ? raw.name : raw.id,
		prompt: typeof raw.prompt === 'string' ? raw.prompt : '',
		model: typeof raw.model === 'string' ? raw.model : null,
		image: typeof raw.image === 'string' ? raw.image : null,
	}
}

/**
 * List the personas you can pass to `ask` as `personaId`.
 *
 * @example
 * import listPersonas from 'kody:@cameronpak/zo-computer/list-personas'
 * const personas = await listPersonas({})
 * if (personas.status === 'ok') console.log(personas.value.map((p) => p.name))
 */
export default async function listPersonas(
	params: ZoClientOptions = {},
): Promise<Result<Array<ZoPersona>, ZoRequestError>> {
	const parsed = await zoJson(
		'/personas/available',
		{ method: 'GET', accept: 'application/json' },
		params,
	)
	if (Result.isError(parsed)) return parsed

	const payload = parsed.value
	if (!isRecord(payload) || !Array.isArray(payload.personas)) {
		return Result.err(
			new ZoParseError({
				url: '/personas/available',
				body: JSON.stringify(payload).slice(0, 2000),
				message: 'Zo response did not contain a personas array',
			}),
		)
	}

	const personas: Array<ZoPersona> = []
	for (const entry of payload.personas) {
		const persona = toPersona(entry)
		if (persona !== null) personas.push(persona)
	}

	return Result.ok(personas)
}