{"version":3,"file":"pi-messages-D61G2tgs.mjs","names":[],"sources":["../node_modules/.pnpm/@earendil-works+pi-ai@0.84.1_ws@8.21.3_zod@4.4.3/node_modules/@earendil-works/pi-ai/dist/api/pi-messages.js"],"sourcesContent":["/**\n * pi-messages API implementation.\n *\n * Streams pi's own message protocol directly to a backend: the request is a\n * single POST of `{ model, context, options }` to `<baseUrl>/messages`, the\n * response is an SSE stream of serialized assistant-message events plus a\n * terminal `done`/`error` event. This is the wire protocol spoken by the\n * Radius gateway, but any backend implementing it can be used, e.g. via a\n * models.json custom provider with `\"api\": \"pi-messages\"`.\n */\nimport { appendAssistantMessageDiagnostic, createAssistantMessageDiagnostic } from \"../utils/diagnostics.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { headersToRecord, providerHeadersToRecord } from \"../utils/headers.js\";\nimport { parseStreamingJson } from \"../utils/json-parse.js\";\nimport { getProviderEnvValue } from \"../utils/provider-env.js\";\nexport class PiMessagesResponseError extends Error {\n    code;\n    diagnosticDetails;\n    constructor(message, code, diagnosticDetails) {\n        super(message);\n        this.name = \"PiMessagesResponseError\";\n        this.code = code;\n        this.diagnosticDetails = diagnosticDetails;\n    }\n}\nfunction parsePiMessagesErrorBody(body) {\n    try {\n        const parsed = JSON.parse(body);\n        const error = parsed?.error;\n        return parsed && typeof error === \"object\" && error !== null && !Array.isArray(error) ? parsed : undefined;\n    }\n    catch {\n        return undefined;\n    }\n}\nfunction truncateDiagnosticString(value) {\n    const maxLength = 8192;\n    return value.length > maxLength ? `${value.slice(0, maxLength)}…` : value;\n}\nfunction formatPiMessagesResponseError(response, body, errorBody) {\n    const message = typeof errorBody?.error?.message === \"string\" ? errorBody.error.message : undefined;\n    const code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : undefined;\n    const suffix = message ?? body;\n    const codeSuffix = code ? ` (${code})` : \"\";\n    return `${response.status} ${response.statusText}: ${suffix}${codeSuffix}`;\n}\nfunction createPiMessagesResponseError(model, url, response, body) {\n    const errorBody = parsePiMessagesErrorBody(body);\n    const code = typeof errorBody?.error?.code === \"string\" ? errorBody.error.code : undefined;\n    return new PiMessagesResponseError(formatPiMessagesResponseError(response, body, errorBody), code, {\n        version: 1,\n        provider: model.provider,\n        model: model.id,\n        url: url.toString(),\n        status: response.status,\n        statusText: response.statusText,\n        error: errorBody?.error,\n        body: errorBody ? undefined : truncateDiagnosticString(body),\n        timestampMs: Date.now(),\n    });\n}\nfunction createEmptyUsage() {\n    return {\n        input: 0,\n        output: 0,\n        cacheRead: 0,\n        cacheWrite: 0,\n        totalTokens: 0,\n        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n    };\n}\nfunction appendRewriteDiagnostic(message, rewrite) {\n    if (!rewrite) {\n        return;\n    }\n    appendAssistantMessageDiagnostic(message, {\n        type: \"pi_messages_rewrite\",\n        timestamp: Date.now(),\n        details: { ...rewrite },\n    });\n}\nfunction createEventConverter(model) {\n    const partial = {\n        role: \"assistant\",\n        content: [],\n        api: model.api,\n        provider: model.provider,\n        model: model.id,\n        usage: createEmptyUsage(),\n        stopReason: \"pending\",\n        timestamp: Date.now(),\n    };\n    const toolJson = new Map();\n    return (event) => {\n        switch (event.type) {\n            case \"done\":\n                Object.assign(partial, {\n                    stopReason: event.reason,\n                    usage: event.usage,\n                    responseId: event.responseId,\n                });\n                appendRewriteDiagnostic(partial, event.rewrite);\n                return { type: \"done\", reason: event.reason, message: partial };\n            case \"error\":\n                Object.assign(partial, {\n                    stopReason: event.reason,\n                    usage: event.usage,\n                    errorMessage: event.errorMessage,\n                    responseId: event.responseId,\n                });\n                appendRewriteDiagnostic(partial, event.rewrite);\n                return { type: \"error\", reason: event.reason, error: partial };\n            case \"start\":\n                break;\n            case \"text_start\":\n                partial.content[event.contentIndex] = { type: \"text\", text: \"\" };\n                break;\n            case \"text_delta\":\n                partial.content[event.contentIndex].text += event.delta;\n                break;\n            case \"text_end\":\n                Object.assign(partial.content[event.contentIndex], {\n                    text: event.content,\n                    textSignature: event.contentSignature,\n                });\n                break;\n            case \"thinking_start\":\n                partial.content[event.contentIndex] = { type: \"thinking\", thinking: \"\" };\n                break;\n            case \"thinking_delta\":\n                partial.content[event.contentIndex].thinking += event.delta;\n                break;\n            case \"thinking_end\":\n                Object.assign(partial.content[event.contentIndex], {\n                    thinking: event.content,\n                    thinkingSignature: event.contentSignature,\n                    redacted: event.redacted,\n                });\n                break;\n            case \"toolcall_start\":\n                partial.content[event.contentIndex] = {\n                    type: \"toolCall\",\n                    id: event.id,\n                    name: event.toolName,\n                    arguments: {},\n                };\n                toolJson.set(event.contentIndex, \"\");\n                break;\n            case \"toolcall_delta\": {\n                const json = `${toolJson.get(event.contentIndex) ?? \"\"}${event.delta}`;\n                toolJson.set(event.contentIndex, json);\n                partial.content[event.contentIndex].arguments =\n                    parseStreamingJson(json);\n                break;\n            }\n            case \"toolcall_end\":\n                Object.assign(partial.content[event.contentIndex], event.toolCall);\n                toolJson.delete(event.contentIndex);\n                return {\n                    type: \"toolcall_end\",\n                    contentIndex: event.contentIndex,\n                    toolCall: partial.content[event.contentIndex],\n                    partial,\n                };\n        }\n        return { ...event, partial };\n    };\n}\nasync function* readPiMessagesEvents(stream) {\n    const decoder = new TextDecoder();\n    const reader = stream.getReader();\n    let buffer = \"\";\n    try {\n        while (true) {\n            const { done, value } = await reader.read();\n            buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });\n            buffer = buffer.replace(/\\r\\n/g, \"\\n\");\n            let split = buffer.indexOf(\"\\n\\n\");\n            while (split !== -1) {\n                const event = parsePiMessagesEvent(buffer.slice(0, split));\n                if (event) {\n                    yield event;\n                }\n                buffer = buffer.slice(split + 2);\n                split = buffer.indexOf(\"\\n\\n\");\n            }\n            if (done) {\n                break;\n            }\n        }\n        if (buffer.trim()) {\n            const event = parsePiMessagesEvent(buffer);\n            if (event) {\n                yield event;\n            }\n        }\n    }\n    finally {\n        reader.releaseLock();\n    }\n}\nfunction parsePiMessagesEvent(raw) {\n    const data = raw\n        .split(\"\\n\")\n        .find((line) => line.startsWith(\"data:\"))\n        ?.slice(5)\n        .trim();\n    return data && data !== \"[DONE]\" ? JSON.parse(data) : undefined;\n}\nfunction createErrorEvent(model, error, aborted) {\n    const reason = aborted ? \"aborted\" : \"error\";\n    const assistantMessage = {\n        role: \"assistant\",\n        content: [],\n        api: model.api,\n        provider: model.provider,\n        model: model.id,\n        usage: createEmptyUsage(),\n        stopReason: reason,\n        errorMessage: error instanceof Error ? error.message : String(error),\n        timestamp: Date.now(),\n    };\n    if (!aborted && error instanceof PiMessagesResponseError) {\n        appendAssistantMessageDiagnostic(assistantMessage, createAssistantMessageDiagnostic(\"pi_messages_response_failure\", error, error.diagnosticDetails));\n    }\n    return { type: \"error\", reason, error: assistantMessage };\n}\nfunction resolveCacheRetention(cacheRetention, env) {\n    if (cacheRetention) {\n        return cacheRetention;\n    }\n    // Backend defaults apply when unset; only the legacy env opt-in is mapped.\n    return getProviderEnvValue(\"PI_CACHE_RETENTION\", env) === \"long\" ? \"long\" : undefined;\n}\nexport const stream = (model, context, options) => {\n    const eventStream = new AssistantMessageEventStream();\n    const convertEvent = createEventConverter(model);\n    void (async () => {\n        try {\n            const apiKey = options?.apiKey;\n            if (!apiKey) {\n                throw new Error(`No API key provided for provider \"${model.provider}\"`);\n            }\n            const url = new URL(`${model.baseUrl.replace(/\\/+$/u, \"\")}/messages`);\n            if (options?.debug) {\n                url.searchParams.set(\"debug\", \"1\");\n            }\n            let payload = {\n                model: model.id,\n                context,\n                options: {\n                    temperature: options?.temperature,\n                    maxTokens: options?.maxTokens,\n                    reasoning: options?.reasoning,\n                    cacheRetention: resolveCacheRetention(options?.cacheRetention, options?.env),\n                    sessionId: options?.sessionId,\n                    toolChoice: options?.toolChoice,\n                },\n            };\n            const nextPayload = await options?.onPayload?.(payload, model);\n            if (nextPayload !== undefined) {\n                payload = nextPayload;\n            }\n            const response = await (options?.fetch ?? globalThis.fetch)(url, {\n                method: \"POST\",\n                headers: {\n                    authorization: `Bearer ${apiKey}`,\n                    accept: \"text/event-stream\",\n                    \"content-type\": \"application/json\",\n                    ...providerHeadersToRecord(options?.headers),\n                },\n                body: JSON.stringify(payload),\n                signal: options?.signal,\n            });\n            await options?.onResponse?.({ status: response.status, headers: headersToRecord(response.headers) }, model);\n            if (!response.ok) {\n                const body = await response.text();\n                throw createPiMessagesResponseError(model, url, response, body);\n            }\n            if (!response.body) {\n                throw new Error(`${model.provider} response has no body`);\n            }\n            for await (const piEvent of readPiMessagesEvents(response.body)) {\n                const event = convertEvent(piEvent);\n                eventStream.push(event);\n                if (event.type === \"done\" || event.type === \"error\") {\n                    return;\n                }\n            }\n            throw new Error(`${model.provider} stream ended without a terminal event`);\n        }\n        catch (error) {\n            eventStream.push(createErrorEvent(model, error, options?.signal?.aborted ?? false));\n        }\n    })();\n    return eventStream;\n};\nexport const streamSimple = (model, context, options) => {\n    const extra = options;\n    return stream(model, context, {\n        ...options,\n        reasoning: options?.reasoning,\n        toolChoice: extra?.toolChoice,\n        debug: extra?.debug,\n    });\n};\n//# sourceMappingURL=pi-messages.js.map"],"x_google_ignoreList":[0],"mappings":"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"}