Why: KTD4 requires the RDM audit partition to be reachable from the admin zone by RDM domain admins and base superadmins, without hardcoding RDM into the base AdminZone or merging roles in the frontend. Evidence: npx vitest run 101/101 green (incl. design-guard), tsc --noEmit clean, knip 42 <= 43; Dev composite CI is authoritative. Impact: AdminZone merges admin-only builtin sections with sections declared by compiled plugins (GET /api/admin-zone/sections, loaded in refreshPlugins); the entry menu shows when isAdmin OR declared sections exist; declared sections render via an id-keyed builtin component map (rdm.audit -> RdmAuditWorkspace) with a version-mismatch placeholder for unknown ids; unknown icons fall back to the generic grid icon. Token and color usage unchanged. Refs: WP3-I3/KTD4; task card feature-adminzone-plugin-sections.
408 lines
15 KiB
TypeScript
408 lines
15 KiB
TypeScript
// 从 Agent-System-Core ts/types.ts 同步(make contracts 生成;Core 为权威)。
|
||
// Agent-System-Core 契约的 TypeScript 镜像。
|
||
// 线格式契约以 Go 类型(camelCase JSON 标签)与 testdata/golden/*.json 黄金样本为准;
|
||
// 本文件手工镜像同一契约,前端按未知 type/字段静默忽略(前向兼容原则)。
|
||
|
||
export type ID = string;
|
||
|
||
// ---- 领域模型 ----
|
||
|
||
export interface Project {
|
||
id: ID; owner?: ID; name: string; createdAt: string; updatedAt: string;
|
||
settings?: Record<string, unknown>;
|
||
}
|
||
|
||
export interface Conversation {
|
||
id: ID; projectId: ID; owner?: ID; title: string; profileId?: ID;
|
||
pinned?: boolean; archived?: boolean;
|
||
allowCrossRead?: boolean; crossPrivate?: boolean;
|
||
permissionMode?: 'default' | 'plan' | 'auto_edit' | '';
|
||
sessionNote?: string;
|
||
createdAt: string; updatedAt: string;
|
||
}
|
||
|
||
export type Role = 'user' | 'assistant' | 'system';
|
||
|
||
export type PartType =
|
||
| 'text' | 'thinking' | 'tool_call' | 'tool_result' | 'artifact_ref'
|
||
| 'hitl' | 'plan' | 'error' | 'card' | 'check';
|
||
|
||
export interface Part {
|
||
type: PartType;
|
||
text?: string;
|
||
toolCall?: { id: string; name: string; arguments?: string; durationMs?: number };
|
||
toolResult?: { callId: string; status: 'ok' | 'error'; summary?: string; truncated?: boolean };
|
||
artifact?: { artifactId: ID; name: string; kind?: string };
|
||
hitl?: { cardId: ID; question: string; resolved: boolean; answer?: string };
|
||
plan?: PlanSnapshot;
|
||
card?: { kind: string; data: UINode[]; cardId?: ID }; // cardId 非空 = 收件箱卡片引用部件(submit_card)
|
||
error?: { code: string; message: string };
|
||
check?: { passed: boolean; reason?: string }; // 终轮自动检查,过程区一行
|
||
process?: boolean; // run 终态后折叠为摘要行
|
||
durationMs?: number; // thinking 部件的思考时长(毫秒);工具耗时在 toolCall.durationMs
|
||
}
|
||
|
||
export interface Message {
|
||
id: ID; conversationId: ID; runId?: ID; role: Role;
|
||
parts: Part[]; createdAt: string;
|
||
excluded?: boolean;
|
||
variantGroup?: string;
|
||
variantIndex?: number;
|
||
}
|
||
|
||
export type RunKind = 'conversation' | 'subagent' | 'tool';
|
||
export type RunStatus =
|
||
| 'pending' | 'running' | 'waiting_hitl' | 'completed'
|
||
| 'failed' | 'cancelled' | 'interrupted';
|
||
export type RunPhase = 'thinking' | 'acting' | 'responding' | 'finalizing' | 'done';
|
||
|
||
export interface Usage {
|
||
promptTokens: number; completionTokens: number; totalTokens: number;
|
||
durationMs: number; toolCalls: number;
|
||
model?: string;
|
||
// N3 计费拆分(additive;旧记录缺省为 0):
|
||
// Last* 是最近一次请求的用量,Cache* 是缓存命中累计。
|
||
lastPromptTokens?: number;
|
||
lastCompletionTokens?: number;
|
||
cacheReadTokens?: number;
|
||
cacheWriteTokens?: number;
|
||
}
|
||
|
||
export interface Run {
|
||
id: ID; parentRunId?: ID; conversationId: ID; projectId: ID; owner?: ID;
|
||
kind: RunKind; profileId?: ID; status: RunStatus; phase?: RunPhase;
|
||
agentName?: string; createdAt: string; endedAt?: string;
|
||
usage?: Usage; error?: { code: string; message: string };
|
||
}
|
||
|
||
export interface Artifact {
|
||
id: ID; projectId: ID; owner?: ID; name: string; kind: string; mime?: string;
|
||
size: number; sourceRun?: ID; createdAt: string; updatedAt: string;
|
||
}
|
||
|
||
export interface PlanSnapshot {
|
||
planId: ID; title: string;
|
||
steps: { id: string; text: string; status: 'pending' | 'in_progress' | 'done' | 'skipped'; agentRun?: ID }[];
|
||
}
|
||
|
||
export interface TodoList {
|
||
conversationId: ID;
|
||
items: { id: string; text: string; status: 'pending' | 'in_progress' | 'done' }[];
|
||
}
|
||
|
||
// ---- 流式事件 ----
|
||
|
||
export type StreamEventType =
|
||
| 'message.delta' | 'thinking.delta'
|
||
| 'tool.call.delta' | 'tool.call' | 'tool.output' | 'tool.result'
|
||
| 'run.phase' | 'run.check' | 'hitl.request' | 'hitl.resolved' | 'plan.update' | 'todo.update'
|
||
| 'agent.spawn' | 'agent.progress' | 'agent.result'
|
||
| 'artifact.created' | 'artifact.updated'
|
||
| 'run.completed' | 'run.failed' | 'error'
|
||
| 'card.created' | 'card.updated' | 'card.status' | 'card.resolved'
|
||
| 'surface.updated';
|
||
|
||
export interface StreamEvent<P = unknown> {
|
||
seq: number; runId?: ID; conversationId: ID; ts: string; v: number;
|
||
type: StreamEventType; payload?: P;
|
||
}
|
||
|
||
// payload 形状(按 type 判别;未知字段忽略)
|
||
export interface MessageDeltaPayload { index: number; text: string }
|
||
export interface ToolCallDeltaPayload { index: number; callId?: string; name?: string; delta: string }
|
||
export interface ToolOutputPayload { callId: string; stream: 'stdout' | 'stderr'; text: string }
|
||
export interface ToolResultPayload { callId: string; status: string; summary?: string; truncated?: boolean; durationMs?: number }
|
||
export interface AgentSpawnPayload { agentRun: ID; name: string; task: string }
|
||
export interface AgentProgressPayload { agentRun: ID; note?: string; phase?: RunPhase }
|
||
export interface AgentResultPayload { agentRun: ID; status: RunStatus; summary?: string }
|
||
export interface HITLResolvedPayload { cardId: ID; answer?: string; kind: 'choice' | 'free' | 'timeout' | 'cancelled' }
|
||
export interface RunCompletedPayload {
|
||
usage: Usage
|
||
context?: ContextObservation
|
||
}
|
||
|
||
interface ContextSection {
|
||
name: string
|
||
estTokens: number
|
||
}
|
||
|
||
export interface ContextObservation {
|
||
items: string[]
|
||
truncations?: string[]
|
||
estChars: number
|
||
sections?: ContextSection[]
|
||
prefixHash?: string
|
||
}
|
||
export interface RunCheckPayload { passed: boolean; reason?: string }
|
||
export interface RunFailedPayload { code: string; message: string }
|
||
|
||
// ---- 收件箱卡片 ----
|
||
|
||
export type CardKind =
|
||
| 'progress' | 'confirm' | 'compare' | 'review-list'
|
||
| 'result' | 'error' | 'status';
|
||
|
||
export type CardStatus =
|
||
| 'active' | 'action_required' | 'done'
|
||
| 'resolved' | 'failed' | 'dismissed';
|
||
|
||
export interface ActivityCard {
|
||
id: ID; projectId: ID; conversationId?: ID;
|
||
sourceRunId?: ID; anchorMessageId?: ID;
|
||
kind: CardKind; title: string; status: CardStatus; tone?: string;
|
||
body?: UINode[]; actions?: { id: string; label: string; style?: 'primary' | 'default' | 'danger'; command?: string }[];
|
||
pinned?: boolean; createdAt: string; updatedAt: string;
|
||
}
|
||
|
||
export interface CardPayload { card: ActivityCard }
|
||
export interface CardStatusPayload { cardId: ID; status: CardStatus; tone?: string; note?: string }
|
||
export interface CardResolvedPayload { cardId: ID; actionId?: string; answer?: string }
|
||
|
||
// ---- HITL ----
|
||
|
||
export type HITLKind = 'choice' | 'input' | 'confirm' | 'form';
|
||
|
||
export interface HITLChoice {
|
||
id: string; label: string; description: string; impact: string; recommended?: boolean;
|
||
}
|
||
|
||
export interface HITLCard {
|
||
id: ID; runId: ID; conversationId: ID; question: string; kind: HITLKind;
|
||
choices?: HITLChoice[]; allowFreeInput: boolean; freeInputHint?: string;
|
||
timeoutSec?: number | null; form?: UINode[]; createdAt: string; resolved: boolean;
|
||
anchorMessageId?: ID; blocked?: boolean; blockReason?: string;
|
||
detail?: string;
|
||
}
|
||
|
||
export interface HITLResponse {
|
||
cardId: ID; choiceId?: string; freeText?: string; formData?: unknown;
|
||
}
|
||
|
||
// ---- UI 词汇 ----
|
||
|
||
export type UINodeType =
|
||
| 'section' | 'list' | 'kv' | 'form' | 'markdown' | 'doc-ref' | 'actions' | 'chart-lite'
|
||
| 'avatar' | 'progress' | 'compare' | 'tree' | 'table' | 'steps' | 'tabs' | 'timeline';
|
||
|
||
export interface UINode {
|
||
type: UINodeType;
|
||
/** Surface 层节点级标注(Generative UI U2):整页唯一稳定 id 与事实来源标识,旧路径不填。 */
|
||
id?: string;
|
||
source?: string[];
|
||
title?: string;
|
||
items?: string[];
|
||
kv?: [string, string][];
|
||
fields?: UIField[];
|
||
markdown?: string;
|
||
docId?: ID;
|
||
actions?: { id: string; label: string; style?: 'primary' | 'default' | 'danger' }[];
|
||
chart?: { kind: 'bar' | 'line'; labels: string[]; series: number[] };
|
||
children?: UINode[];
|
||
|
||
avatar?: { name?: string; sub?: string; tone?: string; stack?: { name?: string; sub?: string; tone?: string }[] };
|
||
progress?: { label?: string; value: number; tone?: string };
|
||
compare?: {
|
||
left: { title?: string; tone?: string; nodes?: UINode[] };
|
||
right: { title?: string; tone?: string; nodes?: UINode[] };
|
||
};
|
||
tree?: {
|
||
nodes: {
|
||
id: string; label: string; tone?: string; badge?: string; count?: number;
|
||
selected?: boolean; children?: unknown[];
|
||
}[];
|
||
};
|
||
table?: {
|
||
columns: { key: string; label: string }[];
|
||
rows: { id?: string; cells: [string, string][]; actions?: UINode['actions'] }[];
|
||
};
|
||
steps?: { current: number; steps: { label: string; status?: 'pending' | 'active' | 'done' | 'failed'; tone?: string }[] };
|
||
tabs?: { active?: string; tabs: { id: string; label: string; nodes?: UINode[] }[] };
|
||
timeline?: { items: { time?: string; title: string; tone?: string; markdown?: string; ref?: string }[] };
|
||
}
|
||
|
||
export interface UIField {
|
||
key: string; label: string;
|
||
type: 'text' | 'textarea' | 'number' | 'boolean' | 'select';
|
||
options?: string[]; required?: boolean; placeholder?: string; help?: string; default?: string;
|
||
}
|
||
|
||
// ---- 提示词库(prompt-library)----
|
||
|
||
export interface PromptTrigger {
|
||
kind: 'intent' | 'command' | 'attachment' | 'manual';
|
||
keywords?: string[]; command?: string;
|
||
}
|
||
|
||
export interface PromptModule {
|
||
id: string; layer: 'base' | 'env' | 'task' | 'agent' | 'tool' | 'aux' | 'style';
|
||
version: number; title: string; description?: string; priority?: number;
|
||
triggers?: PromptTrigger[]; requiresAttachments?: boolean;
|
||
body: string; outputContract?: string;
|
||
source?: 'builtin' | 'plugin' | 'user'; owner?: string;
|
||
basedOnVersion?: number; drifted?: boolean; disabled?: boolean;
|
||
/** 子代理 profile。只对 agent.sub.* 有意义;空字段表示沿用内置。 */
|
||
tools?: string[]; model?: string; maxTurns?: number;
|
||
}
|
||
|
||
export interface PromptBlock { moduleId: string; version: number; layer: string; body: string; }
|
||
export interface PromptHitRecord { moduleId: string; layer: string; reason: string; injected: boolean; }
|
||
|
||
// ---- 画像 / 设置 ----
|
||
|
||
export interface AgentProfile {
|
||
id: string; owner?: string; name: string; description?: string; builtin?: boolean; source?: string;
|
||
systemPrompt: string;
|
||
/** 提示词库模块引用(有序;空 = 默认 base+env 全集)。 */
|
||
promptModules?: string[];
|
||
model: { chat?: string; lightweight?: string; embedding?: string; rerank?: string };
|
||
tools: { allow: string[]; deny?: string[]; confirm?: string[] };
|
||
context: {
|
||
maxHistoryMessages: number; summarizeBeyond?: boolean;
|
||
memoryBudgetPct?: number; knowledgeBudgetPct?: number; maxToolResultChars?: number;
|
||
};
|
||
hitl: { askOnAmbiguity: boolean; timeoutSec?: number | null };
|
||
budget: { maxTokens?: number | null; maxToolCalls?: number | null; maxTurns?: number | null };
|
||
}
|
||
|
||
export interface SettingDesc {
|
||
key: string; group: string; label: string; description?: string;
|
||
type: 'string' | 'number' | 'boolean' | 'enum' | 'secret';
|
||
default?: unknown; options?: string[];
|
||
effect: 'hot' | 'new-run' | 'restart';
|
||
secret?: boolean;
|
||
}
|
||
|
||
// ---- 插件 ----
|
||
|
||
export interface PluginManifest {
|
||
id: string; name: string; version: string; apiVersion: string;
|
||
requires?: { network?: string[] };
|
||
provides: {
|
||
tools?: string[]; workflows?: string[]; intents?: string[];
|
||
prompts?: string[]; panels?: string[]; cards?: string[]; settings?: string[];
|
||
commands?: string[]; workspaces?: string[];
|
||
skills?: string[]; mcpServers?: string[]; knowledge?: string[];
|
||
parsers?: string[]; agents?: string[]; channels?: string[]; pages?: string[];
|
||
};
|
||
scope?: { tenants?: string[]; projects?: string[] };
|
||
backend?: { mode?: 'inproc' | 'sidecar'; command?: string; args?: string[]; schemaVersion?: number };
|
||
}
|
||
|
||
// ---- 管理区声明分区(WP3-I3/KTD4)----
|
||
/** 编译插件经 Registry.AddAdminZone 声明的管理区展示分区;入口不做前端权限合并,
|
||
* 分区内数据能力由组件自身的命令面 fail-closed。 */
|
||
export interface AdminZoneSection {
|
||
id: string; title: string; icon?: string; desc?: string; order?: number;
|
||
}
|
||
|
||
export interface PluginPanel {
|
||
id: string; title: string; icon?: string; body: UINode[]; refreshTool?: string;
|
||
}
|
||
|
||
/** 模板占位符:{{input}}、{{slots.<key>}}、{{steps.<id>.output}}。 */
|
||
export interface WorkflowDef {
|
||
id: string; title: string; description?: string; intentId?: string;
|
||
/** 整条工作流的 critic 重试上限。 */
|
||
maxRetries?: number;
|
||
steps: WorkflowStep[];
|
||
}
|
||
|
||
export interface StepCritic {
|
||
criteria: string;
|
||
/** 本步重试上限;缺省 1 次。 */
|
||
maxRetries?: number;
|
||
}
|
||
|
||
export interface WorkflowStep {
|
||
id: string; title: string;
|
||
kind: 'prompt' | 'tool' | 'hitl' | 'artifact' | 'card' | 'script';
|
||
prompt?: string;
|
||
/** prompt 步骤的子代理 profile,缺省 general。 */
|
||
agent?: string;
|
||
tool?: string;
|
||
args?: unknown;
|
||
hitl?: { question: string; kind: HITLKind; choices?: HITLChoice[]; allowFreeInput: boolean; freeInputHint?: string };
|
||
artifact?: string;
|
||
card?: { kind: CardKind; title: string; tone?: string; body?: UINode[]; actions?: { id: string; label: string; style?: 'primary' | 'default' | 'danger'; command?: string }[] };
|
||
/** script 步骤在插件目录内的相对路径。 */
|
||
script?: string;
|
||
critic?: StepCritic;
|
||
}
|
||
|
||
export interface PluginWorkspace {
|
||
id: string; title: string; icon?: string; shortcut?: string;
|
||
badgeTool?: string; body: UINode[]; refreshTool?: string;
|
||
}
|
||
|
||
export interface PluginPageDecl {
|
||
id: string; title: string; module: string;
|
||
}
|
||
|
||
// ---- 摄取 / 检索 ----
|
||
|
||
export interface ParsedDocument {
|
||
meta: {
|
||
filename: string; mime?: string; parser: string; confidence?: number;
|
||
crossCheck?: { with: string; diffBlocks: number; verdict: 'agree' | 'differ' };
|
||
parsedAt: string;
|
||
};
|
||
blocks: {
|
||
type: 'heading' | 'para' | 'list' | 'table' | 'code' | 'image-ref';
|
||
level?: number; text?: string; items?: string[];
|
||
rows?: string[][]; ref?: string; confidence?: number;
|
||
}[];
|
||
warnings?: string[];
|
||
}
|
||
|
||
export interface RetrievalHit {
|
||
doc: { id: ID; owner?: ID; projectId?: ID; source: string; title: string; ref?: string; chunk: string; createdAt: string };
|
||
score: number; kind: 'fulltext' | 'vector' | 'plugin';
|
||
}
|
||
|
||
export interface UploadInfo {
|
||
artifactId: ID; filename: string; mime?: string; size: number;
|
||
parsed?: ParsedDocument;
|
||
}
|
||
|
||
// ---- Generative UI Surface(提案 U2/U4;与 Go surface.go 同步)----
|
||
|
||
export interface SurfaceCompat {
|
||
schemaVersion: number;
|
||
catalogVersion: string;
|
||
pluginVersion?: string;
|
||
}
|
||
|
||
export interface SurfaceIdentity {
|
||
surfaceId: ID;
|
||
owner: string;
|
||
projectId?: ID;
|
||
conversationId?: ID;
|
||
sourceRunId?: ID;
|
||
pluginId: string;
|
||
}
|
||
|
||
export interface SurfaceSpec {
|
||
title: string;
|
||
nodes: UINode[];
|
||
}
|
||
|
||
export interface SurfaceSnapshot {
|
||
identity: SurfaceIdentity;
|
||
compat: SurfaceCompat;
|
||
revision: number;
|
||
baseRevision?: number;
|
||
contextVersion?: string;
|
||
activationEpoch: number;
|
||
spec: SurfaceSpec;
|
||
semanticText?: string;
|
||
}
|
||
|
||
export interface SurfaceMeta {
|
||
surfaceId: ID;
|
||
title: string;
|
||
pluginId: string;
|
||
revision: number;
|
||
conversationId?: ID;
|
||
updatedAt: string;
|
||
}
|