import { type WorkflowAgentHandle } from "@sema-agent/core"; /** The result of resolving a steer target. core does NOT enforce label uniqueness within a run (a script may * spawn two steerable agents with the same explicit `label`), so a (runId,label) can address MORE THAN ONE live * agent — steering then has no well-defined target and must be refused, not sent to an arbitrary one. */ export interface SteerResolution { /** The live handle iff EXACTLY ONE matches; undefined when none (not here) or when ambiguous (>1). */ handle?: WorkflowAgentHandle; /** Live handles matching (0 = none on this replica, 1 = unique target, >1 = ambiguous → the route 409s). */ count: number; } /** A process-local registry of the steerable workflow-agent handles live on THIS replica. Mirrors the * `steerableRuns` / `preemptableRuns` pattern (a live in-memory handle is replica-local — a cross-replica steer * is a structured 409, never a silent drop). Stores a LIST per (runId,label): core does not enforce label * uniqueness, so a duplicate-label collision must NOT silently last-writer-wins (that would steer the WRONG * agent + strand the sibling) — {@link resolve} reports the count so the route can 409-on-ambiguous instead. */ export declare class WorkflowAgentRegistry { private readonly handles; /** Register a handle when its `agentStream` starts on this replica. Returns an unregister thunk to call when * the agent settles (keeps the map from leaking). APPENDS (does not overwrite) so a duplicate-label sibling is * also tracked → {@link resolve} sees count>1 and the route refuses rather than steering an arbitrary one. */ register(handle: WorkflowAgentHandle): () => void; /** Resolve `runId`+`label` to its UNIQUE live handle on this replica. count=0 → not here (terminal / * cross-replica); count=1 → `handle` set; count>1 → ambiguous (`handle` undefined → the route 409s rather * than steering an arbitrary one of the colliding same-label agents). */ resolve(runId: string, label: string): SteerResolution; /** Total live handles (test/observability). */ get size(): number; } /** Max steer-in length fed to a worker (chars). A steer is a short redirection, not a payload; core's * `untrustedEgressForHuman` bounds + truncates beyond this. * * ⚠️ 纠正(2026-07-26,core 1.414 + 亲测):这里原本写的是「truncates with an **honest marker**」,现在只有 * 一半成立 —— 实测(`test/svc5-steer-live.test.ts` 里已钉): * · **「被截断过」仍有信号**:超界时正文段尾出现 `…`(未超界时不出现)⇒ 消费方能判断"这不是全文"; * · **「截了多少」不再披露**:`[+N chars]` 在**所有**档位都没有了(实测 +1 / +10 / +100 / +5000 / +50000 * 全部无披露,输出长度恒 4103)。所以一个超出 5 万字符的输入与只超 1 个字符的输入,**外观完全相同**。 * ⚠️ core [ref]⑤ 的措辞是「**刚过界**的输入现在是裸 `…` 结尾」,而实测是**全档位**都没有披露 —— 范围比 * 它描述的宽。已带实测数据上黑板问 core 这是否是有意的(可能只是描述省略,也可能是它没注意到)。 * 在得到答复前**不改行为**:core 的截断器是它那侧的安全件,server 不该自己在外面补一层"+N chars"去顶 * ——那会变成两处各说一套。 */ export declare const STEER_IN_MAX_CHARS = 4000; /** * **入参**上限(与 {@link STEER_IN_MAX_CHARS} 是两件事:那个限的是**输出**,这个限的是**请求带进来的**)。 * * ── 为什么需要它 ─────────────────────────────────────────────────────────────────────────────── * 脱敏门是**同步**函数,烧的是**事件循环** ⇒ 一次大 steer 卡住的是**整个副本**,不只是那个请求。 * 此前这里没有上限:`body.content` 只校验类型与非空,而 JSON 请求体上限是 8 MiB。 * * ── 数是怎么定的(实测,不是拍的)──────────────────────────────────────────────────────────────── * core 1.421.0 起该函数对输入是**线性**的(此前对「最长不间断词字符段」二次,已修)。 * 本机实测最坏形状(纯词字符段):64 KiB ≈ 17ms ⇒ **256 KiB ≈ 68ms**、8 MiB ≈ 2.2s。 * ⇒ 取 **256 KiB**:最坏一拍 ~70ms(可接受的事件循环占用),而它是输出上限的 **64 倍** —— * 任何正当的粘贴都装得下,而超出部分**本来就会被丢弃**(只保留 4000 字符 + 一个"丢了多少"的披露)。 * * ── 为什么是**拒**而不是**服务端先截** ────────────────────────────────────────────────────────── * 先截会让 core 的 `[+N chars]` 披露**低报**(N 会变成相对截断后输入的), * 而"诚实标记不得低报"是本仓另一条钉守着的性质。**为一个已经不紧迫的成本去改一条正确性性质,不划算。** * ⇒ 拒 + 在错误里说清上限,调用方自己决定发什么。 */ export declare const STEER_IN_MAX_REQUEST_CHARS: number; /** * The steer-in REDACTION gate (SVC-5 信任门). Treat the human/leader steer content as UNTRUSTED before it * reaches the worker: redact host-internal leaks (URLs / tokens / named secrets / absolute paths), size-bound, * and FENCE it so it can't pose as authority / forge a ``. `label` tags the fenced block for * the worker's reader. This is the service's half of the depth — `handle.steer` fences again inside its trusted * marker framing. */ export declare function redactSteerIn(content: string, label: string): string; //# sourceMappingURL=workflow-agent-steer.d.ts.map