Add a finalizing phase and a check part #18
@@ -43,6 +43,7 @@ const (
|
||||
EvToolOutput StreamEventType = "tool.output" // 执行中的 stdout/stderr 增量
|
||||
EvToolResult StreamEventType = "tool.result"
|
||||
EvRunPhase StreamEventType = "run.phase"
|
||||
EvRunCheck StreamEventType = "run.check" // 终轮自动检查,过程区一行
|
||||
EvHITLRequest StreamEventType = "hitl.request"
|
||||
EvHITLResolved StreamEventType = "hitl.resolved"
|
||||
EvPlanUpdate StreamEventType = "plan.update"
|
||||
@@ -112,6 +113,12 @@ type RunPhasePayload struct {
|
||||
Phase RunPhase `json:"phase"`
|
||||
}
|
||||
|
||||
// RunCheckPayload 与 CheckPart 同形,让运行中和重新加载后的检查行一致。
|
||||
type RunCheckPayload struct {
|
||||
Passed bool `json:"passed"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
type HITLResolvedPayload struct {
|
||||
CardID ID `json:"cardId"`
|
||||
Answer string `json:"answer,omitempty"`
|
||||
|
||||
@@ -17,26 +17,26 @@ type ID = string
|
||||
// Owner 是租户标识(多租户主线,设计 D5/D16):空串 = 单租户默认(嵌入式档/
|
||||
// 未启用认证时的隐式 owner)。API 层强制 owner 过滤,跨租户访问一律 NotFound。
|
||||
type Project struct {
|
||||
ID ID `json:"id"`
|
||||
Owner ID `json:"owner,omitempty"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
ID ID `json:"id"`
|
||||
Owner ID `json:"owner,omitempty"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Settings map[string]any `json:"settings,omitempty"` // 项目层设置覆盖(4.9 覆盖链)
|
||||
}
|
||||
|
||||
type Conversation struct {
|
||||
ID ID `json:"id"`
|
||||
ProjectID ID `json:"projectId"`
|
||||
Owner ID `json:"owner,omitempty"` // 冗余自项目,查询过滤用
|
||||
Title string `json:"title"`
|
||||
ProfileID ID `json:"profileId,omitempty"` // 空为默认画像
|
||||
Pinned bool `json:"pinned,omitempty"` // 侧栏置顶(方案 A P6/P8:本端组织偏好,服务端权威)
|
||||
Archived bool `json:"archived,omitempty"` // 归档:列表默认隐藏,数据保留
|
||||
AllowCrossRead bool `json:"allowCrossRead,omitempty"` // 跨会话出站:本会话读取同项目其他会话记录(需项目开关 crossSession.read)
|
||||
CrossPrivate bool `json:"crossPrivate,omitempty"` // 跨会话入站:私有会话,不被他读、不出现在他方列表
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
ID ID `json:"id"`
|
||||
ProjectID ID `json:"projectId"`
|
||||
Owner ID `json:"owner,omitempty"` // 冗余自项目,查询过滤用
|
||||
Title string `json:"title"`
|
||||
ProfileID ID `json:"profileId,omitempty"` // 空为默认画像
|
||||
Pinned bool `json:"pinned,omitempty"` // 侧栏置顶(方案 A P6/P8:本端组织偏好,服务端权威)
|
||||
Archived bool `json:"archived,omitempty"` // 归档:列表默认隐藏,数据保留
|
||||
AllowCrossRead bool `json:"allowCrossRead,omitempty"` // 跨会话出站:本会话读取同项目其他会话记录(需项目开关 crossSession.read)
|
||||
CrossPrivate bool `json:"crossPrivate,omitempty"` // 跨会话入站:私有会话,不被他读、不出现在他方列表
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// ---- 消息与部件 ----
|
||||
@@ -61,16 +61,17 @@ const (
|
||||
PartHITL PartType = "hitl"
|
||||
PartPlan PartType = "plan"
|
||||
PartError PartType = "error"
|
||||
PartCard PartType = "card" // 插件自定义卡片(Data 为 UI schema)
|
||||
PartCard PartType = "card" // 插件自定义卡片(Data 为 UI schema)
|
||||
PartCheck PartType = "check" // 终轮自动检查,过程区一行,不是给用户的回复
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
ID ID `json:"id"`
|
||||
ConversationID ID `json:"conversationId"`
|
||||
RunID ID `json:"runId,omitempty"`
|
||||
Role Role `json:"role"`
|
||||
Parts []Part `json:"parts"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
ID ID `json:"id"`
|
||||
ConversationID ID `json:"conversationId"`
|
||||
RunID ID `json:"runId,omitempty"`
|
||||
Role Role `json:"role"`
|
||||
Parts []Part `json:"parts"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
// Part 是判别联合:Type 决定哪些字段有意义;未用字段为零值。
|
||||
@@ -84,8 +85,9 @@ type Part struct {
|
||||
Artifact *ArtifactRef `json:"artifact,omitempty"`
|
||||
Hitl *HITLSummary `json:"hitl,omitempty"`
|
||||
Plan *PlanSnapshot `json:"plan,omitempty"`
|
||||
Card *CardPart `json:"card,omitempty"`
|
||||
Card *CardPart `json:"card,omitempty"`
|
||||
Err *ErrorPart `json:"error,omitempty"`
|
||||
Check *CheckPart `json:"check,omitempty"`
|
||||
|
||||
// 过程标记:true 的部件在 run 终态后由前端折叠为摘要行(4.2)。
|
||||
Process bool `json:"process,omitempty"`
|
||||
@@ -96,17 +98,17 @@ type Part struct {
|
||||
}
|
||||
|
||||
type ToolCallPart struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Arguments string `json:"arguments,omitempty"` // 原始 JSON
|
||||
Duration float64 `json:"durationMs,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Arguments string `json:"arguments,omitempty"` // 原始 JSON
|
||||
Duration float64 `json:"durationMs,omitempty"`
|
||||
}
|
||||
|
||||
type ToolResultPart struct {
|
||||
CallID string `json:"callId"`
|
||||
Status string `json:"status"` // ok | error
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Truncated bool `json:"truncated,omitempty"` // 超长截断并转工件引用(4.10)
|
||||
CallID string `json:"callId"`
|
||||
Status string `json:"status"` // ok | error
|
||||
Summary string `json:"summary,omitempty"`
|
||||
Truncated bool `json:"truncated,omitempty"` // 超长截断并转工件引用(4.10)
|
||||
}
|
||||
|
||||
type ArtifactRef struct {
|
||||
@@ -127,6 +129,12 @@ type ErrorPart struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// CheckPart 是终轮自动检查的结果。过程区显示一行,不进入给用户的回复。
|
||||
type CheckPart struct {
|
||||
Passed bool `json:"passed"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// CardPart.Data 是 UI schema 节点(4.6 有限词汇)。
|
||||
// CardID 非空 = 收件箱 ActivityCard 的引用部件(如 submit_card 产卡:卡片为产物
|
||||
// 权威载体,消息只存引用+锚点渲染);空 = 插件内嵌卡片部件(自包含 Data)。
|
||||
@@ -149,39 +157,40 @@ const (
|
||||
type RunStatus string
|
||||
|
||||
const (
|
||||
RunPending RunStatus = "pending"
|
||||
RunRunning RunStatus = "running"
|
||||
RunWaitingHITL RunStatus = "waiting_hitl"
|
||||
RunCompleted RunStatus = "completed"
|
||||
RunFailed RunStatus = "failed"
|
||||
RunCancelled RunStatus = "cancelled"
|
||||
RunInterrupted RunStatus = "interrupted"
|
||||
RunPending RunStatus = "pending"
|
||||
RunRunning RunStatus = "running"
|
||||
RunWaitingHITL RunStatus = "waiting_hitl"
|
||||
RunCompleted RunStatus = "completed"
|
||||
RunFailed RunStatus = "failed"
|
||||
RunCancelled RunStatus = "cancelled"
|
||||
RunInterrupted RunStatus = "interrupted"
|
||||
)
|
||||
|
||||
type RunPhase string
|
||||
|
||||
const (
|
||||
PhaseThinking RunPhase = "thinking"
|
||||
PhaseActing RunPhase = "acting"
|
||||
PhaseThinking RunPhase = "thinking"
|
||||
PhaseActing RunPhase = "acting"
|
||||
PhaseResponding RunPhase = "responding"
|
||||
PhaseDone RunPhase = "done"
|
||||
PhaseFinalizing RunPhase = "finalizing" // 工作循环已结束,正在整理给用户的最终回复
|
||||
PhaseDone RunPhase = "done"
|
||||
)
|
||||
|
||||
type Run struct {
|
||||
ID ID `json:"id"`
|
||||
ParentRunID ID `json:"parentRunId,omitempty"`
|
||||
ConversationID ID `json:"conversationId"`
|
||||
ProjectID ID `json:"projectId"`
|
||||
Owner ID `json:"owner,omitempty"` // 冗余自会话
|
||||
Kind RunKind `json:"kind"`
|
||||
ProfileID ID `json:"profileId,omitempty"`
|
||||
Status RunStatus `json:"status"`
|
||||
Phase RunPhase `json:"phase,omitempty"`
|
||||
AgentName string `json:"agentName,omitempty"` // subagent 显示名
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
EndedAt *time.Time `json:"endedAt,omitempty"`
|
||||
Usage *Usage `json:"usage,omitempty"`
|
||||
Error *ErrorPart `json:"error,omitempty"`
|
||||
ID ID `json:"id"`
|
||||
ParentRunID ID `json:"parentRunId,omitempty"`
|
||||
ConversationID ID `json:"conversationId"`
|
||||
ProjectID ID `json:"projectId"`
|
||||
Owner ID `json:"owner,omitempty"` // 冗余自会话
|
||||
Kind RunKind `json:"kind"`
|
||||
ProfileID ID `json:"profileId,omitempty"`
|
||||
Status RunStatus `json:"status"`
|
||||
Phase RunPhase `json:"phase,omitempty"`
|
||||
AgentName string `json:"agentName,omitempty"` // subagent 显示名
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
EndedAt *time.Time `json:"endedAt,omitempty"`
|
||||
Usage *Usage `json:"usage,omitempty"`
|
||||
Error *ErrorPart `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type Usage struct {
|
||||
@@ -210,20 +219,20 @@ type Artifact struct {
|
||||
// ---- 计划与待办(右栏 Plan / Todos)----
|
||||
|
||||
type PlanSnapshot struct {
|
||||
PlanID ID `json:"planId"`
|
||||
Title string `json:"title"`
|
||||
Steps []PlanStep `json:"steps"`
|
||||
PlanID ID `json:"planId"`
|
||||
Title string `json:"title"`
|
||||
Steps []PlanStep `json:"steps"`
|
||||
}
|
||||
|
||||
type PlanStep struct {
|
||||
ID string `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Status string `json:"status"` // pending | in_progress | done | skipped
|
||||
AgentRun ID `json:"agentRun,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Status string `json:"status"` // pending | in_progress | done | skipped
|
||||
AgentRun ID `json:"agentRun,omitempty"`
|
||||
}
|
||||
|
||||
type TodoList struct {
|
||||
ConversationID ID `json:"conversationId"`
|
||||
ConversationID ID `json:"conversationId"`
|
||||
Items []TodoItem `json:"items"`
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -22,7 +22,7 @@ export type Role = 'user' | 'assistant' | 'system';
|
||||
|
||||
export type PartType =
|
||||
| 'text' | 'thinking' | 'tool_call' | 'tool_result' | 'artifact_ref'
|
||||
| 'hitl' | 'plan' | 'error' | 'card';
|
||||
| 'hitl' | 'plan' | 'error' | 'card' | 'check';
|
||||
|
||||
export interface Part {
|
||||
type: PartType;
|
||||
@@ -34,6 +34,7 @@ export interface Part {
|
||||
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
|
||||
}
|
||||
@@ -47,7 +48,7 @@ export type RunKind = 'conversation' | 'subagent' | 'tool';
|
||||
export type RunStatus =
|
||||
| 'pending' | 'running' | 'waiting_hitl' | 'completed'
|
||||
| 'failed' | 'cancelled' | 'interrupted';
|
||||
export type RunPhase = 'thinking' | 'acting' | 'responding' | 'done';
|
||||
export type RunPhase = 'thinking' | 'acting' | 'responding' | 'finalizing' | 'done';
|
||||
|
||||
export interface Usage {
|
||||
promptTokens: number; completionTokens: number; totalTokens: number;
|
||||
@@ -81,7 +82,7 @@ export interface TodoList {
|
||||
export type StreamEventType =
|
||||
| 'message.delta' | 'thinking.delta'
|
||||
| 'tool.call.delta' | 'tool.call' | 'tool.output' | 'tool.result'
|
||||
| 'run.phase' | 'hitl.request' | 'hitl.resolved' | 'plan.update' | 'todo.update'
|
||||
| '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'
|
||||
@@ -111,6 +112,7 @@ export interface ContextObservation {
|
||||
truncations?: string[]
|
||||
estChars: number
|
||||
}
|
||||
export interface RunCheckPayload { passed: boolean; reason?: string }
|
||||
export interface RunFailedPayload { code: string; message: string }
|
||||
|
||||
// ---- 收件箱卡片 ----
|
||||
|
||||
Reference in New Issue
Block a user