import { runTeamDiscussion, type ModelRef, type ModelRole, type Runner, type ToolSpec } from "@sema-agent/core"; import type { Logger } from "../observability/logger.js"; /** * `discuss` scenario — run a configured multi-agent DISCUSSION (core `runTeamDiscussion`) on a task. * Packaged as ONE tool the lead calls once (same shape as the code-review council), so the run model is * unchanged. * * ── 词汇([ref] / [ref],clay 直裁 [ref])────────────────────────────────────────────────────── * 「team」= agent-teams(持久具名团队)专用词;一次性多 agent 讨论叫「discuss」。所以**面向调用方/ * 模型的名字**全部是 discussion:场景 `discuss`、工具 `run_discussion`、协调者提示词。 * 而**模板注册面**(`BUILTIN_TEAMS` / `registerTeams` / `getTeam`)保留 team 词汇(历史命名,注册表是本仓 * 自己的模块级单例,不再对应任何中心配置键——见下段)。 * * HYBRID layering: the TEMPLATE here carries only the GENERIC orchestration skeleton (member roles + generic * personas, rounds, synthesizer); the CONSUMER (OA) injects the business prompt/context at call time * (`businessContext`); this service composes them. * * Templates: BUILTIN_TEAMS are the defaults. ⚠️ 中心的 `teams` 配置域自 settings-schema 0.7 **已删除** * (DOMAIN_SCHEMAS 无此域、FileConfigStore 不读、/effective 不铸),[ref] 件3 又拆掉了本仓 `applyEffective → * registerTeams` 那条消费腿——本文件旧注里「registry pushes more at runtime via GET /api/config/effective → teams」 * 是 doc-rot。今天 `registerTeams` 只剩公共信任边界这一层意义(调用方=测试),注册表在生产上恒等于 BUILTIN_TEAMS; * 中心侧的多 agent 讨论配置面是 `collab` 域(0.7 继任者),投影成命名 workflow(capabilities/collab-workflows.ts)。 * * 🔴 **成员重派阶梯收窄(core 7.24.0 [ref];本仓 7.90.0 提货批的读数说明,零改动)** —— 一次讨论**花的子 run * 数掉一半**,上游实测:两成员一轮的讨论从 **6 个子 run 变 3 个**。原因:`runTurn` 此前对**每一个**没有 * 「completed 且有正文」落地的成员轮都重派一次(同目标、同提示词、同模型、同工具面),包括那些**结局上 * 不可能变**的终局;现在只对引擎能**肯定**认出是确定性的两种终局拒绝重派(`blocked` 因由 = 宿主 * `UserPromptSubmit` 的拒绝,照字面信;`failed` 且治理表判 TERMINAL 的码,读 `classifySubagentError`)。 * * 🔴 **这不是「丢了重试」,读数变低也不是故障**(写在这里是因为它唯一会被误读的地方就是账单与子代行数): * · 其余一切**照旧**保留第二次尝试 —— 那个分类器的 `logic`/`unknown` 桶是**else 臂**(它不认识的码全落 * 那里),把「永不重派」挂在 else 臂上会让**将来每一个新码**默默变成不可重派,所以那条判决留在表里。 * ⚠️ **本句在 7.90.0(core 7.24.2 / [ref])修了措辞**:上一版写的是「`stream_torn` 住在 `logic` 桶里 * (else 臂)…负控挑它最有判别力」—— core 本版给三个 in-band 终局输出码**各自开了行** * (`stream_torn → network`(transient)/ `refusal → logic` / `length_empty → logic`),所以 * `stream_torn` **已经不在 else 臂上了**(本车亲跑差分实测:`classifySubagentError({code:"stream_torn"})` * 从 7.24.1 的 `{errorKind:"logic", retryable:false}` 变 7.24.2 的 `{errorKind:"network", retryable:true}` * —— 注意 `errorKind` 与 `retryable` **两个字段都翻了**,提货单只点了后者)。 * **结局没变**(`stream_torn` 照旧重派 ⇒ 仍 6):重派闸 `canDifferOnRetry` 判的是「`blocked` 因由 + 治理表 * 判 TERMINAL」,从不读桶名 —— 变的是**理由**(从「掉进 else 臂」变成「表里那一行说它 transient」)。 * ⇒ 拿 `stream_torn` 当 **else 臂**负控从本版起**没有判别力了**(它是一条有行的码);要挑 else 臂代表, * 挑**未知码** / **无码的 `failed`** / **空正文的 `completed`** —— 那三形才真的落 else 臂。 * · `[unavailable: /]` 标记、讨论转录、预算记账的**形一个字节没变**。 * · **本仓没有任何按子 run 数计费 / 计量的座**(2026-09-19 车JG 亲扫:`billable` 是 `http/route-table.ts` 上 * 「这条路由算不算一次计费提交」的路由性质,与子 run 无关;`council_runs_total` 数的是**议会被调用了几次**, * 不是子代;成员轮不建 run-store 行,它们是 TaskRegistry 上的 `a*` 句柄)。⇒ 本版在本仓**零改动**, * 唯一会动的读数是 `GET /v1/runs/:id/subagents` 的**行数**与经 `stats` 透传的**用量/花费**(都变低), * 两者都是上游事实的透传、本仓不据行数做任何裁决。 * * 🔴 **判据按「前缀族」写,不按具体码字**(test 仓对 core 7.24.0 的实测②,本仓照此记账;将来真在本仓开 * 计量点时钉法同此):引擎读的是治理表对**码**的裁决,而裁决是按**前缀族**给的 —— 一个族里凭空合成的码 * (test 实测的 `usage.FAKE_prefix_only`)照样判 TERMINAL ⇒ **3**。所以正控/负控各挑**一个**代表就够, * 逐字抄那张码表只会在上游加一行的那天变成谎: * · **⇒ 3(不重派)**:`blocked` 因由,以及 7 个被治理表判 TERMINAL 的前缀族失败码(合成同前缀码同判); * · **⇒ 仍 6(照旧两次)**:两个 transient 码 `memory.admission_required` / `config.compliance_required`, * 以及 `stream_torn` / `refusal` / `length_empty` / 未知码 / 无码的 `failed` / 空正文的 `completed`。 * 🔴 **这六形自 core 7.24.2([ref])起不再同源**:前三形在分类器里**各有一行** * (`stream_torn → network` transient / `refusal`、`length_empty` → `logic`),后三形才是真的 **else 臂**。 * 结局(仍 6)对六形都没变,但**负控要挑真 else 臂**:未知码 / 无码的 `failed` / 空正文的 `completed`。 */ type TeamFn = typeof runTeamDiscussion; export interface TeamMemberTemplate { role: string; /** Direct catalog model for this member (core `TeamMember.model`, wins over `modelRole`). The config * center accepts `member.model`; honor it end-to-end — an unset/unknown name lets core resolve the * `modelRole`/`"team"` fallback (or throw a clear "Unknown model ref"), never silently drop it (F8). */ model?: ModelRef; /** Per-member cost tiering (core 1.28): resolves this role instead of the shared `team` role. */ modelRole?: ModelRole; /** GENERIC persona only — the business prompt is appended at call time, never baked in here. */ systemPrompt?: string; } export interface TeamTemplate { name: string; members: TeamMemberTemplate[]; rounds: number; /** `model` = direct catalog model for the synthesizer (core `runTeamDiscussion` supports it — a generic * capability an operator-authored template can use). Unset ⇒ `modelRole`/`"synthesize"` fallback. */ synthesizer?: { role: string; model?: ModelRef; modelRole?: ModelRole; systemPrompt?: string; }; } /** Built-in team templates (placeholder until the sema registry supplies them). */ export declare const BUILTIN_TEAMS: Record; export declare function registerTeams(extra: Record): void; export declare function getTeam(name: string): TeamTemplate | undefined; export declare function teamNames(): string[]; /** 现役工具名(模型可见 = 行为面)。 */ export declare const DISCUSSION_TOOL_NAME = "run_discussion"; /** * Build the discussion tool bound to a template + the consumer's per-call business injection. * [ref]:[ref] 过渡窗的 `run_team` 同款别名已随 `SCENARIO_ALIASES` 同批删(prompts 写死旧名的 * 部署=「工具不存在」,[ref]/7.44 发车帖点名的预告语义)。 */ export declare function createDiscussionTools(subRunner: Runner, template: TeamTemplate, opts: { objective: string; businessContext?: string; teamFn?: TeamFn; logger?: Logger; }): ToolSpec[]; /** Build the `run_discussion` tool bound to a template + the consumer's per-call business injection. */ export declare function createDiscussionTool(subRunner: Runner, template: TeamTemplate, opts: { objective: string; businessContext?: string; teamFn?: TeamFn; }): ToolSpec; /** The lead just runs the discussion tool once and returns its conclusion verbatim. */ export declare const discussionCoordinatorPrompt: import("@sema-agent/core").PromptProvider; export {}; //# sourceMappingURL=team.d.ts.map