/** Discriminator prefix shared by all OpenRouter server-tool item types. */
export const SERVER_TOOL_PREFIX = "openrouter:";
/** Envelope keys that describe the item shape rather than the tool's result. */
const SERVER_TOOL_ENVELOPE_KEYS = new Set(["type", "id", "status"]);
/**
 * Project a raw `openrouter:*` state.json item onto {@link ServerToolCall}:
 * strip the envelope keys into the output payload and recover `web_search`'s
 * query from `action.query` as input. Pure and total — unknown future tools
 * fall through to the generic envelope-stripping path.
 */
export function normalizeServerToolItem(item) {
    const callId = typeof item.id === "string" ? item.id : undefined;
    const output = {};
    for (const [k, v] of Object.entries(item)) {
        if (!SERVER_TOOL_ENVELOPE_KEYS.has(k))
            output[k] = v;
    }
    // web_search carries the model's query under `action.query`. Surface it as
    // recoverable input so the UI can show "web_search - '<query>'"; other
    // tools expose nothing comparable, so input stays undefined for them.
    let input;
    const action = item.action;
    if (action !== null && typeof action === "object") {
        const query = action.query;
        if (typeof query === "string")
            input = { query };
    }
    return {
        toolType: item.type,
        ...(callId !== undefined && { callId }),
        ...(input !== undefined && { input }),
        output,
    };
}
/** `"openrouter:web_search"` → `"web_search"` — the display/tool name the UI shows. */
export function serverToolName(toolType) {
    return toolType.startsWith(SERVER_TOOL_PREFIX) ? toolType.slice(SERVER_TOOL_PREFIX.length) : toolType;
}
/**
 * JSON-stringify a server tool's recoverable input for storage as the
 * `tool_use` ParsedMessage `content`. The model's input args usually aren't
 * preserved by OR's server-side tools — we don't know what URL was passed to
 * web_fetch, for example. Fall back to an empty object rather than
 * fabricating.
 */
export function serverToolInputContent(input) {
    if (input === null || input === undefined)
        return "{}";
    try {
        const json = JSON.stringify(input);
        return json ?? "{}";
    }
    catch {
        return "{}";
    }
}
/**
 * Stringify the result payload for the `tool_result` ParsedMessage `content`.
 * Empty payloads render as an empty string (matching the state.json parser's
 * historical behavior) so the bubble doesn't show a pointless `{}`.
 */
export function serverToolOutputContent(output) {
    if (output === null || output === undefined)
        return "";
    if (typeof output === "string")
        return output;
    if (typeof output === "object" && !Array.isArray(output) && Object.keys(output).length === 0)
        return "";
    try {
        const json = JSON.stringify(output);
        return json ?? String(output);
    }
    catch {
        return String(output);
    }
}
/**
 * Synthesize the `tool_use` + `tool_result` ParsedMessage pair for one server
 * tool call, stamped with `toolSource: "openrouter_server"` so the UI can
 * distinguish server-executed tools from local ones. The optional `timestamp`
 * (ISO) decorates both rows — transcript records carry one, state.json items
 * don't.
 */
export function serverToolToMessages(call, timestamp) {
    const toolName = serverToolName(call.toolType);
    return [
        {
            role: "assistant",
            type: "tool_use",
            toolName,
            toolSource: "openrouter_server",
            content: serverToolInputContent(call.input),
            ...(call.callId && { toolUseId: call.callId }),
            ...(timestamp && { timestamp }),
        },
        {
            role: "user",
            type: "tool_result",
            toolName,
            toolSource: "openrouter_server",
            content: serverToolOutputContent(call.output),
            ...(call.callId && { toolUseId: call.callId }),
            ...(timestamp && { timestamp }),
        },
    ];
}
