UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

123 lines (122 loc) • 5.78 kB
import { RETAIN_DEFAULT_TTL_MS, RETAIN_DEFAULT_MAX, SESSION_DEFAULT_TTL_DAYS } from "./defaults.js"; export const CONFIG_CATALOG_VERSION = "sema-config@1"; export function describeConfigCatalog() { const knobs = [ { key: "limits.maxTurns", recommended: null, unit: "turns", kind: "budget", summary: "Per-slice turn ceiling. Unset = unbounded (design/164 retired the engine-side net): a task that needs a turn bound states one. 0 = the explicit unbounded sentinel.", precedence: "spec.limits.maxTurns > unset", }, { key: "limits.maxWalltimeMs", recommended: null, unit: "ms", kind: "budget", summary: "Per-slice ACTIVE wall-clock window for the task (suspended time does not count; a resume opens a fresh window). Unset = unbounded, which is the recommendation — bound work by tokens, not by time.", precedence: "spec.limits.maxWalltimeMs > unset", }, { key: "limits.maxOutputTokens", recommended: null, unit: "tokens", kind: "budget", summary: "Per-REQUEST output cap (provider max_tokens). Unset = model default. Distinct from the cumulative budget maxTokens.", precedence: "spec.limits.maxOutputTokens > model.maxTokens > provider default", }, { key: "limits.maxCostUsd", recommended: null, unit: "usd", kind: "budget", summary: "Per-slice spend ceiling (hard-cancels the in-flight stream by default when crossed). Unset = unbounded.", precedence: "spec.limits.maxCostUsd > unset", }, { key: "limits.maxTokens", recommended: null, unit: "tokens", kind: "budget", summary: "Per-slice token budget — the PRIMARY axis. Unset = unbounded.", precedence: "spec.limits.maxTokens > unset", }, { key: "limits.approachNotice", recommended: null, kind: "behavior", summary: "Advisory limit-approach reminders (one at ~80% of the tightest armed axis, one at ~95%). Unset = ON whenever an axis is armed; false = off; { at } overrides the thresholds.", precedence: "spec.limits.approachNotice > on-when-any-axis-armed", }, { key: "budget.totalTokens", recommended: null, unit: "tokens", kind: "budget", summary: "Cross-slice token allocation for resource-suspend tasks. First slice only; later slices read the frozen ledger. Unset = per-slice windows only.", precedence: "spec.resourceSuspend.totalTokens (first slice) > unset", }, { key: "delegation.retainTtlMs", recommended: RETAIN_DEFAULT_TTL_MS, unit: "ms", kind: "retention", summary: "Retained child session TTL (settled-at based) within the parent run's retain ledger.", precedence: "TaskSpec.retainSubagentSessions.ttlMs > default", }, { key: "delegation.retainMax", recommended: RETAIN_DEFAULT_MAX, unit: "count", kind: "retention", summary: "Max retained children per parent run (oldest settled idle evicted beyond it).", precedence: "TaskSpec.retainSubagentSessions.max > default", }, { key: "session.idleTtlDays", recommended: SESSION_DEFAULT_TTL_DAYS, unit: "days", kind: "retention", summary: "Idle TTL before a cached session is evicted from the session store.", precedence: "TtlSessionStoreOptions.defaultTtlDays > default", }, ]; return { version: CONFIG_CATALOG_VERSION, knobs }; } export const MAX_OVERRIDE_DECLARATIONS = 32; const MAX_DECLARATION_CHARS = 200; const sanitizeDeclarationText = (s) => s.replace(/[\u0000-\u0008\u000b-\u001f\u007f]/g, "").slice(0, MAX_DECLARATION_CHARS); export function resolveEffectiveConfig(spec, ctx) { const l = spec.limits; const pick = (key, specVal, dflt) => specVal !== undefined ? { key, value: specVal, provenance: "spec" } : { key, value: dflt, provenance: "default" }; const maxOutputTokens = l?.maxOutputTokens !== undefined ? { key: "limits.maxOutputTokens", value: l.maxOutputTokens, provenance: "spec" } : ctx?.modelMaxTokens !== undefined ? { key: "limits.maxOutputTokens", value: ctx.modelMaxTokens, provenance: "derived" } : { key: "limits.maxOutputTokens", value: null, provenance: "default" }; const fields = [ pick("limits.maxTurns", l?.maxTurns, null), pick("limits.maxWalltimeMs", l?.maxWalltimeMs, null), maxOutputTokens, pick("limits.maxCostUsd", l?.maxCostUsd, null), pick("limits.maxTokens", l?.maxTokens, null), pick("budget.totalTokens", spec.resourceSuspend?.totalTokens, null), pick("budget.totalBudgetUsd", spec.resourceSuspend?.totalBudgetUsd, null), ]; for (const d of (spec.configOverrides ?? []).slice(0, MAX_OVERRIDE_DECLARATIONS)) { fields.push({ key: sanitizeDeclarationText(d.key), value: typeof d.value === "string" ? sanitizeDeclarationText(d.value) : d.value, provenance: "host-declared", }); } return fields; } export function declarationReasons(declarations) { const reasons = {}; for (const d of (declarations ?? []).slice(0, MAX_OVERRIDE_DECLARATIONS)) { reasons[sanitizeDeclarationText(d.key)] = sanitizeDeclarationText(d.reason); } return reasons; }