UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

115 lines (114 loc) • 3.13 kB
import { RESPONSES_APIS } from "./reasoning.js"; export const OPENAI_RESERVED = new Set([ "model", "messages", "stream", "stream_options", "tools", "temperature", "max_tokens", "stop", "reasoning_effort", "thinking", "reasoning", "enable_thinking", "chat_template_kwargs", ]); export const ANTHROPIC_RESERVED = new Set([ "model", "messages", "system", "stream", "tools", "temperature", "max_tokens", "thinking", "output_config", "context_management", ]); export const RESPONSES_RESERVED = new Set([ "model", "input", "stream", "instructions", "tools", "temperature", "max_output_tokens", "reasoning", "store", "previous_response_id", "conversation", ]); export function reservedFor(api) { if (RESPONSES_APIS.has(api)) return RESPONSES_RESERVED; return api === "anthropic-messages" ? ANTHROPIC_RESERVED : OPENAI_RESERVED; } export function applyExtraBody(body, extraBody, reserved) { if (!extraBody) return body; const passthrough = {}; for (const [k, v] of Object.entries(extraBody)) { if (!reserved.has(k)) passthrough[k] = v; } return { ...passthrough, ...body }; } export const AUTH_CARRIER_NAMES = new Set(["authorization", "x-api-key"]); export function lockHeader(headers, lowerName, value) { for (const k of Object.keys(headers)) { if (k !== lowerName && k.toLowerCase() === lowerName) delete headers[k]; } headers[lowerName] = value; } export function takeHeaderCasefold(headers, lowerName) { for (const k of Object.keys(headers)) { if (k.toLowerCase() === lowerName) { const v = headers[k]; delete headers[k]; return v; } } return undefined; } export function mergeHeaders(...bags) { const out = {}; const spellingByFold = new Map(); for (const bag of bags) { if (!bag) continue; for (const [name, value] of Object.entries(bag)) { const fold = name.toLowerCase(); if (AUTH_CARRIER_NAMES.has(fold)) { out[name] = value; continue; } const prior = spellingByFold.get(fold); if (prior !== undefined && prior !== name) delete out[prior]; spellingByFold.set(fold, name); out[name] = value; } } return out; } export const OUTPUT_CAP_KEYS = { openai: ["max_tokens", "max_completion_tokens"], anthropic: ["max_tokens"], responses: ["max_output_tokens"], }; export function effectiveOutputCap(body, keys) { let smallest; for (const key of keys) { const raw = body[key]; if (typeof raw !== "number" || !Number.isFinite(raw) || raw <= 0) continue; if (smallest === undefined || raw < smallest) smallest = raw; } return smallest; } export function reservedCollisions(extraBody, reserved) { return extraBody ? Object.keys(extraBody).filter((k) => reserved.has(k)) : []; }