| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- // Bot 工作组(docs/design/13-bot-teams.md):机器人、Bot Key、工作组与工作组事件
- import type { FileDto, PermissionMode } from './api'
- import type { InteractionRequest, InteractionResolution, ProviderId } from './events'
- /** 组长(lead)负责拆分和分派任务;组员(worker)执行具体工作 */
- export type BotKind = 'lead' | 'worker'
- export interface BotDto {
- id: string
- name: string
- /** 一个 emoji 或一两个字 */
- avatar: string
- kind: BotKind
- /** 岗位描述:擅长什么、不负责什么 */
- description: string
- profileId: string
- enabled: boolean
- createdAt: string
- updatedAt: string
- }
- export type BotInput = Pick<BotDto, 'name' | 'avatar' | 'kind' | 'description' | 'profileId' | 'enabled'>
- /** Bot API 中可见的机器人信息(不含 Profile 配置) */
- export interface BotSummary {
- id: string
- name: string
- avatar: string
- kind: BotKind
- description: string
- provider: ProviderId | null
- model: string | null
- }
- /** 能力卡片:组长据此了解组员会什么(由服务端根据机器人配置生成,docs/design/13-bot-teams.md §5.1) */
- export interface BotCard extends BotSummary {
- /** Profile 中的技能(name + SKILL.md 中的 description) */
- skills: { name: string; description: string }[]
- /** 第三方 MCP 服务(内置工具不列出) */
- mcpServers: { name: string; title: string; description: string }[]
- /** 可访问的资料库名称 */
- knowledge: string[]
- permissionMode: PermissionMode | null
- }
- export interface BotKeyDto {
- id: string
- name: string
- prefix: string
- enabled: boolean
- allowedBotIds: string[]
- createdAt: string
- lastUsedAt: string | null
- }
- export type TeamStatus = 'active' | 'paused' | 'closed'
- export type TeamBotStatus = 'idle' | 'queued' | 'working' | 'waiting_input'
- /** 工作组里的人类成员:由调用方提供的显示身份,AgentServer 不做认证 */
- export interface TeamHuman {
- id: string
- name: string
- }
- export interface TeamBotDto extends BotSummary {
- role: BotKind
- status: TeamBotStatus
- /** 这个机器人在本工作组中的引擎会话(还没有工作过时为 null) */
- sessionId: string | null
- joinedAt: string
- }
- /** 每个任务的限额(docs/design/13-bot-teams.md §7);超出后任务暂停,由成员选择继续或取消 */
- export interface TeamLimits {
- /** 每个任务的子任务数 */
- maxTasksPerJob: number
- /** 每个任务中组长的执行轮数 */
- maxLeadRunsPerJob: number
- /** 每个任务的成本上限(美元),null 表示不限 */
- maxCostUsdPerJob: number | null
- /** 每个任务的时长上限(分钟) */
- maxMinutesPerJob: number
- /** 工作组同时执行的 Run 数 */
- maxConcurrentRuns: number
- /** 机器人会话的上下文超过这个 token 数时,下一轮开始新的会话(组长在两项任务之间);null 表示不限 */
- sessionMaxContextTokens: number | null
- /** 机器人闲置超过这个小时数后,下一轮开始新的会话;null 表示不限 */
- sessionIdleHours: number | null
- }
- /** 任务级的限额(超出时任务暂停) */
- export type TeamLimitKey = Exclude<keyof TeamLimits, 'maxConcurrentRuns' | 'sessionMaxContextTokens' | 'sessionIdleHours'>
- /** 调试设置:只有来源为 admin 的工作组(Bot Playground)可以设置 */
- export interface TeamDebug {
- /** 逐步执行:每次唤醒机器人之前先停下,由管理员点"继续" */
- stepMode: boolean
- /** 替身组员:分派给它们的子任务不执行,由管理员手动填写结果 */
- stubBotIds: string[]
- }
- /** 逐步执行模式下等待"继续"的一步 */
- export interface TeamStepDto {
- id: string
- botId: string
- /** 例如"子任务 #2:清洗数据"或"处理 2 条新消息" */
- reason: string
- createdAt: string
- }
- export interface TeamDto {
- id: string
- title: string
- human: TeamHuman
- status: TeamStatus
- /** Bot Key id 或 'admin' */
- source: string
- bots: TeamBotDto[]
- limits: TeamLimits
- debug: TeamDebug
- /** 进行中(含因限额暂停)的任务 */
- activeJobId: string | null
- lastSeq: number
- createdAt: string
- updatedAt: string
- }
- export interface TeamInteractionDto {
- botId: string
- sessionId: string
- request: InteractionRequest
- }
- export interface TeamDetailDto extends TeamDto {
- pendingInteractions: TeamInteractionDto[]
- pendingSteps: TeamStepDto[]
- }
- export interface CreateTeamBody {
- title?: string
- human: TeamHuman
- leadBotId?: string
- workerBotIds?: string[]
- /** 只能调低默认限额 */
- limits?: Partial<TeamLimits>
- /** 仅 admin */
- debug?: Partial<TeamDebug>
- }
- export interface PatchTeamBody {
- title?: string
- limits?: Partial<TeamLimits>
- /** 仅 admin */
- debug?: Partial<TeamDebug>
- }
- // ---- 任务与子任务(docs/design/13-bot-teams.md §5.2)----
- /** blocked:超出限额,等待成员选择继续或取消 */
- export type JobStatus = 'running' | 'blocked' | 'completed' | 'failed' | 'cancelled'
- export interface JobDto {
- id: string
- teamId: string
- /** 工作组内的序号,从 1 开始 */
- no: number
- title: string
- plan: string
- status: JobStatus
- /** 完成时的总结或失败、取消的原因 */
- summary: string | null
- files: TeamFileRef[]
- /** 因哪项限额暂停 */
- blockedBy: TeamLimitKey | null
- /** 已放宽的限额(成员选择"继续"后加倍) */
- limits: Record<TeamLimitKey, number | null>
- leadRuns: number
- taskCount: number
- costUsd: number
- createdAt: string
- endedAt: string | null
- }
- /** waiting:等待依赖的子任务完成;stub:分派给替身,等待管理员填写结果 */
- export type TaskStatus = 'waiting' | 'queued' | 'running' | 'stub' | 'completed' | 'failed' | 'cancelled'
- export interface TaskDto {
- id: string
- jobId: string
- teamId: string
- /** 工作组内的序号,从 1 开始 */
- no: number
- botId: string
- title: string
- instructions: string
- /** 依赖的子任务序号 */
- dependsOn: number[]
- status: TaskStatus
- /** 结果或失败原因 */
- result: string | null
- files: TeamFileRef[]
- runId: string | null
- sessionId: string | null
- costUsd: number
- createdAt: string
- startedAt: string | null
- endedAt: string | null
- }
- export interface TeamJobsDto {
- jobs: JobDto[]
- tasks: TaskDto[]
- }
- /** 替身组员的子任务结果(仅 admin) */
- export interface StubTaskBody {
- outcome: 'completed' | 'failed'
- result: string
- fileIds?: string[]
- }
- export interface TeamUsageRow {
- runs: number
- inputTokens: number
- outputTokens: number
- costUsd: number
- }
- export interface TeamUsageDto {
- total: TeamUsageRow
- bots: (TeamUsageRow & { botId: string })[]
- jobs: (TeamUsageRow & { jobId: string })[]
- tasks: (TeamUsageRow & { taskId: string })[]
- }
- export interface SendTeamMessageBody {
- text: string
- /** 被 @ 的机器人 id;不 @ 时:有组长交给组长,只有一个组员时交给它,否则返回 400 */
- mentions?: string[]
- /** 已上传到本工作组的文件 */
- fileIds?: string[]
- }
- export type TeamSender =
- | { kind: 'human'; id: string; name: string }
- | { kind: 'bot'; botId: string; name: string; avatar: string }
- | { kind: 'system' }
- export interface TeamFileRef {
- fileId: string
- path: string
- mime: string
- size: number
- }
- /** 消息上附带的卡片:任务、子任务、限额、替身、逐步执行(状态以 jobs / tasks / steps 的最新值为准) */
- export type TeamCard =
- | { kind: 'job'; jobId: string; event: 'started' | 'completed' | 'failed' | 'cancelled' }
- | { kind: 'task'; taskId: string; no: number; event: 'assigned' | 'completed' | 'failed' | 'cancelled'; stub?: boolean }
- | { kind: 'limit'; jobId: string; limit: TeamLimitKey }
- | { kind: 'stub'; taskId: string; no: number }
- | { kind: 'step'; stepId: string }
- export interface TeamMessage {
- id: string
- sender: TeamSender
- text: string
- mentions: string[]
- files: TeamFileRef[]
- /** 这条消息唤醒的机器人 */
- targets: string[]
- /** 机器人消息:产生它的 Run 与会话,用于查看完整执行过程 */
- runId?: string
- sessionId?: string
- /** 系统消息的级别 */
- level?: 'info' | 'warning' | 'error'
- card?: TeamCard
- }
- export interface TeamEventPayloads {
- 'message.created': TeamMessage
- 'bot.status': { botId: string; status: TeamBotStatus; sessionId: string | null; runId: string | null }
- 'interaction.required': TeamInteractionDto
- 'interaction.resolved': { botId: string; sessionId: string; interactionId: string; resolution: InteractionResolution; answers?: Record<string, string | string[]>; reason?: string }
- 'file.changed': { file: FileDto; kind: 'created' | 'modified' }
- 'team.updated': TeamDto
- 'job.updated': JobDto
- 'task.updated': TaskDto
- 'step.updated': { steps: TeamStepDto[] }
- }
- export type TeamEventType = keyof TeamEventPayloads
- export interface TeamEventOf<T extends TeamEventType> {
- seq: number
- type: T
- teamId: string
- ts: string
- payload: TeamEventPayloads[T]
- }
- export type TeamEvent = { [T in TeamEventType]: TeamEventOf<T> }[TeamEventType]
- /** 不落库、只保留在内存缓冲中的事件(状态类,断线续传后以接口返回的最新状态为准) */
- export const TRANSIENT_TEAM_EVENT_TYPES: ReadonlySet<TeamEventType> = new Set(['bot.status', 'file.changed', 'team.updated', 'step.updated'])
- // ---- 回归用例(仅后台,§12.2) ----
- /** 回归用例:成员组成 + 第一条命令。重放时按它新建一个后台工作组并发出命令,结果由人工比对 */
- export interface TeamCaseDto {
- id: string
- name: string
- leadBotId: string | null
- workerBotIds: string[]
- /** 重放时设为替身的组员 */
- stubBotIds: string[]
- limits: Partial<TeamLimits> | null
- humanName: string
- text: string
- mentions: string[]
- files: { name: string; size: number }[]
- createdAt: string
- updatedAt: string
- runCount: number
- lastRun: TeamCaseRunDto | null
- }
- /** 一次重放:对应一个工作组 */
- export interface TeamCaseRunDto {
- teamId: string
- createdAt: string
- /** running:还有机器人在工作或在等审批 / 替身结果;done:都空闲了 */
- state: 'running' | 'done'
- /** 最后一项任务(组长开了任务时) */
- job: Pick<JobDto, 'id' | 'no' | 'title' | 'status' | 'summary' | 'files' | 'leadRuns' | 'taskCount' | 'endedAt'> | null
- /** 没有任务时:机器人的最后一条回复 */
- reply: string | null
- runs: number
- costUsd: number
- }
- export interface CreateTeamCaseBody {
- name: string
- /** 从这个工作组保存:取它的成员组成、替身设置、限额和成员发出的第一条消息 */
- teamId: string
- }
|