import type { MonitorOperator, ProcessJobOperator, ProviderAuthOperator } from "@mono-agent/agent-contracts"; import type { TuiAdapterConfig, TuiAdapterOptions, TuiAdapterStartResult } from "@mono-agent/operator-adapter"; import { discoverLocalProviders } from "@mono-agent/runtime-adapter"; import type { DiscoveredLocalModel, LocalProviderDefinition } from "@mono-agent/runtime-adapter"; import { deliverWebNotification } from "@mono-agent/web"; import type { ChannelDriver, ChannelStartInput, RunningChannel } from "../channels.js"; import type { CronOperatorRegistry } from "../cron-operator-service.js"; export interface TuiChannelOverrides { readonly adapterFactory?: (options: TuiAdapterOptions) => Promise; /** Test seam: replaces the real local-provider model discovery call. */ readonly discoverModels?: (providers: readonly LocalProviderDefinition[] | undefined) => Promise; /** * Test seam: replaces the zero-config local-provider probe. This one MUST be * injectable — the real implementation reaches localhost:11434 and * localhost:1234, so a developer with Ollama running would otherwise get * different test results from one who does not. */ readonly discoverProviders?: typeof discoverLocalProviders; /** Test/embedding seam for the owner-private local web ingress. */ readonly deliverNotification?: typeof deliverWebNotification; } /** * Producer-side payload budgets for `/v1/info`. * * `/v1/info` shares ONE 1 MiB body cap ({@link MAX_INFO_BODY_BYTES}) across * every field it carries, and `sendBoundedInfo` in the operator adapter is what * enforces it: it measures the exact string it is about to send, sheds whole * optional fields largest-first, logs the shed at error level, and falls back to * a fixed liveness body. That fence is TOTAL — no body leaves this process over * the cap whatever these numbers say — so the fence, and only the fence, is what * decides that something genuinely cannot ship. * * What a budget HERE is for is bounding the AGGREGATE growth of a contributor * whose size nobody authored, so one such contributor cannot flood the body and * cost an unrelated field its place at the fence: * * discovered model refs 384 KiB advisory: whatever a local endpoint said * provider summary 128 KiB advisory tail behind the declared vendors * skills 256 KiB `MAX_SKILL_REGISTRY_BYTES`, skill-registry.ts * * Configured routes get NO budget here, and that is the correction to a defect * this file carried through three review rounds. A budget is not an opinion * about which content deserves to ship, and a fixed per-contributor slice * becomes exactly that the moment one VALID item is bigger than the slice. * Round 3 bounded the model projection at 128 KiB and dropped a valid * configured fallback; round 4 kept the rule and raised the constant to * 512 KiB, and a then-valid 270,000-byte OpenRouter fallback was still dropped — * from a body that would have been 540,778 bytes against a 1,048,576-byte cap. * No constant was the right one; the shape was wrong. Dropping an authored * route served neither purpose a budget has (the body fit, and nothing was * being starved), and it cost real function: the TUI never calls `/v1/models` * and rebuilds its picker from `info.models` alone, so a withheld route is an * unselectable primary or fallback in the operator's own console. * * Nor is a single reference bounded. Two rounds put a byte ceiling in the * reference parser so that no ONE item could be pathological, and both numbers * refused a model that really exists — 96 bytes a Hugging Face GGUF repo Ollama * serves, 160 bytes an `ollama::` reference whose two halves Ollama * itself validates at 80 bytes each. A grammar layer does not get to decide what * a provider calls a model, so the ceiling is gone and a single reference can be * any size again. That changes nothing here, because the rule was never about * item size: nothing bounds how MANY routes an operator may declare or how many * rows a local `/v1/models` may report either, so a per-contributor slice would * still be an opinion about authored content, and configured routes still get * none. What it does mean is that the fence below is load-bearing for a case it * briefly was not — one authored route larger than the whole cap — which * `tui-info-wire.test.ts` drives over a real socket. * * So every configured route is admitted, and a result that cannot fit is the * fence's call, made loudly. Advisory discovery then spends its own aggregate * budget on top — but never room the body no longer has * ({@link INFO_NON_MODEL_RESERVE_BYTES}) — so discovery can never be the reason * the fence fires. * * The discovery budget is exported because it is the whole contract between * authored routes and advisory content, and a test that keeps its own copy of a * constant cannot notice that constant changing. */ export declare const MAX_DISCOVERED_INFO_MODEL_BYTES: number; /** * Start only a driver created by this module with app-owner capabilities. The * private symbol plus exact object identity prevents a plugin or arbitrary * driver named `tui` from opting into the owner path. */ export declare function startAppOwnedTuiChannel(driver: ChannelDriver, input: ChannelStartInput, processJobs: ProcessJobOperator | undefined, monitors: MonitorOperator | undefined, providerAuth: ProviderAuthOperator | undefined): Promise | undefined; /** * The TUI stream endpoint deviates from the channels-off convention: with no * `tui` section it is enabled on loopback with an ephemeral port. An explicit * `"tui": {"enabled": false}` opts out. */ export declare function createTuiChannelDriver(overrides?: TuiChannelOverrides, cronOperator?: CronOperatorRegistry): ChannelDriver; //# sourceMappingURL=tui.d.ts.map