UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

113 lines (112 loc) • 3.02 kB
import { isCredentialHeaderName } from "../core/secret-env.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", ]); const NO_KEYS = Object.freeze([]); export function applyExtraBody(body, extraBody, reserved) { if (!extraBody) return { body, dropped: NO_KEYS }; const passthrough = {}; const dropped = []; for (const [k, v] of Object.entries(extraBody)) { if (reserved.has(k)) dropped.push(k); else passthrough[k] = v; } return { body: { ...passthrough, ...body }, dropped: dropped.length === 0 ? NO_KEYS : dropped }; } 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 headerBagOnce(bag) { return bag === undefined ? undefined : { ...bag }; } 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 (isCredentialHeaderName(name)) { 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; }