paseo-plugin-zcode-provider 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE.md +29 -0
- package/README.md +112 -2
- package/client/account.tsx +827 -0
- package/client/diagnostics.tsx +379 -0
- package/client/runtime.tsx +296 -0
- package/client/settings.tsx +84 -0
- package/client/value.tsx +20 -0
- package/icon.svg +1 -0
- package/index.client.tsx +22 -0
- package/index.server.ts +39 -0
- package/package.json +77 -4
- package/paseo-plugin.json +6 -0
- package/server/account.ts +781 -0
- package/server/attachments.ts +150 -0
- package/server/build-info.ts +2 -0
- package/server/conversation.ts +319 -0
- package/server/diagnostics.ts +252 -0
- package/server/discovery/discover.ts +225 -0
- package/server/discovery/manifest.ts +36 -0
- package/server/discovery/types.ts +30 -0
- package/server/errors.ts +36 -0
- package/server/host/bridge.ts +490 -0
- package/server/host/schemas.ts +119 -0
- package/server/logger.ts +19 -0
- package/server/mapping.ts +270 -0
- package/server/models.ts +68 -0
- package/server/persistence.ts +146 -0
- package/server/presentation.ts +470 -0
- package/server/provider-status.ts +81 -0
- package/server/provider.ts +838 -0
- package/server/runtime/managed.ts +501 -0
- package/server/runtime/pins.ts +72 -0
- package/server/runtime-setup.ts +77 -0
- package/server/session-types.ts +49 -0
- package/server/session.ts +866 -0
- package/server/status.ts +89 -0
- package/server/timeline.ts +18 -0
- package/server/usage.ts +362 -0
- package/server/vendor/zcode/LICENSE +202 -0
- package/server/vendor/zcode/NOTICE.md +70 -0
- package/server/vendor/zcode/THIRD-PARTY-NOTICES.md +37 -0
- package/server/vendor/zcode/packages/model-option-map/src/compiler.ts +92 -0
- package/server/vendor/zcode/packages/model-option-map/src/evaluator.ts +214 -0
- package/server/vendor/zcode/packages/model-option-map/src/index.ts +5 -0
- package/server/vendor/zcode/packages/model-option-map/src/merge-patch.ts +97 -0
- package/server/vendor/zcode/packages/model-option-map/src/option-maps.ts +42 -0
- package/server/vendor/zcode/packages/model-option-map/src/parser.ts +240 -0
- package/server/vendor/zcode/packages/model-option-map/src/tokenizer.ts +141 -0
- package/server/vendor/zcode/packages/model-option-map/src/types.ts +36 -0
- package/server/vendor/zcode/packages/rpc/src/buffer.ts +88 -0
- package/server/vendor/zcode/packages/rpc/src/channelClient.ts +275 -0
- package/server/vendor/zcode/packages/rpc/src/channelServer.ts +283 -0
- package/server/vendor/zcode/packages/rpc/src/channels.shared.ts +66 -0
- package/server/vendor/zcode/packages/rpc/src/channels.ts +4 -0
- package/server/vendor/zcode/packages/rpc/src/delayedChannel.ts +17 -0
- package/server/vendor/zcode/packages/rpc/src/foundation.ts +260 -0
- package/server/vendor/zcode/packages/rpc/src/protocol.ts +397 -0
- package/server/vendor/zcode/packages/rpc/src/proxy-channel.ts +213 -0
- package/server/vendor/zcode/packages/rpc/src/serialization.ts +291 -0
- package/server/vendor/zcode/packages/shared/src/account-provider-state.ts +13 -0
- package/server/vendor/zcode/packages/shared/src/background-bash-output.ts +24 -0
- package/server/vendor/zcode/packages/shared/src/background-task-controls.ts +404 -0
- package/server/vendor/zcode/packages/shared/src/bash-output-display.ts +11 -0
- package/server/vendor/zcode/packages/shared/src/bots.ts +558 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/backend.ts +80 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/command-metadata.ts +170 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/commands.ts +588 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/result.ts +130 -0
- package/server/vendor/zcode/packages/shared/src/browser-use/snapshot.ts +77 -0
- package/server/vendor/zcode/packages/shared/src/command-types.ts +96 -0
- package/server/vendor/zcode/packages/shared/src/config-schema.ts +8 -0
- package/server/vendor/zcode/packages/shared/src/cuaAccessibilitySettings.ts +41 -0
- package/server/vendor/zcode/packages/shared/src/database-startup.ts +178 -0
- package/server/vendor/zcode/packages/shared/src/env.ts +63 -0
- package/server/vendor/zcode/packages/shared/src/execution-output-preview.ts +14 -0
- package/server/vendor/zcode/packages/shared/src/localTtft.ts +192 -0
- package/server/vendor/zcode/packages/shared/src/model-config.ts +123 -0
- package/server/vendor/zcode/packages/shared/src/model-execution.ts +23 -0
- package/server/vendor/zcode/packages/shared/src/model-provider-family.ts +171 -0
- package/server/vendor/zcode/packages/shared/src/model-provider-types.ts +81 -0
- package/server/vendor/zcode/packages/shared/src/model-selection.ts +60 -0
- package/server/vendor/zcode/packages/shared/src/oauth.ts +203 -0
- package/server/vendor/zcode/packages/shared/src/official-mcp-auth.ts +272 -0
- package/server/vendor/zcode/packages/shared/src/official-mcp-tool-error.ts +68 -0
- package/server/vendor/zcode/packages/shared/src/process-diagnostic.ts +42 -0
- package/server/vendor/zcode/packages/shared/src/protocol.ts +369 -0
- package/server/vendor/zcode/packages/shared/src/provider-family-connection-selection.ts +32 -0
- package/server/vendor/zcode/packages/shared/src/remoteAssetInstallMode.ts +11 -0
- package/server/vendor/zcode/packages/shared/src/remoteResourcePackages.ts +91 -0
- package/server/vendor/zcode/packages/shared/src/runtimeEnv.ts +315 -0
- package/server/vendor/zcode/packages/shared/src/settings-source.ts +10 -0
- package/server/vendor/zcode/packages/shared/src/usage-quota.ts +74 -0
- package/server/vendor/zcode/packages/shared/src/usage-stats.ts +462 -0
- package/server/vendor/zcode/packages/shared/src/validationAppSettings.ts +562 -0
- package/server/vendor/zcode/packages/shared/src/workspacePurpose.ts +2 -0
- package/server/vendor/zcode/packages/shared/src/wslUserValidation.ts +33 -0
- package/server/vendor/zcode/packages/shared/src/zcode-agent-policy.ts +25 -0
- package/server/vendor/zcode/packages/shared/src/zcode-media-policy.ts +10 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol/index.ts +3720 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-legacy-types.ts +529 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/apply.ts +218 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/attachment-ref.ts +14 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/command.ts +482 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/core.ts +100 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/create-workflow-display.ts +156 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/cuaPermission.ts +41 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/delta.ts +147 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/input-intent.ts +69 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/rows.ts +432 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/session-config.ts +43 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index-workflow-activity.ts +195 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/sessions-index.ts +85 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/shared-context-import.ts +38 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/shared-context-ref.ts +10 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/snapshot.ts +509 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/submission.ts +5 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/toolDisplay.ts +264 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/transport.ts +1152 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-assembler.ts +574 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-binary.ts +65 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-codec.ts +240 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire-fault.ts +39 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/wire.ts +159 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-artifacts.ts +291 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-observation-display.ts +281 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-row-meta.ts +163 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-run-settings-command.ts +62 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs-delta.ts +517 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workflow-runs.ts +512 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workspace-config.ts +81 -0
- package/server/vendor/zcode/packages/shared/src/zcode-protocol-v4/workspace-hook-review.ts +210 -0
- package/server/vendor/zcode/packages/shared/src/zcode-task-mode-schema.ts +6 -0
- package/server/vendor/zcode/packages/shared/src/zcode-task-types-core.ts +1187 -0
- package/server/vendor/zcode/packages/shared/src/zcodeEndpoint.ts +296 -0
- package/server/vendor/zcode/provenance.json +405 -0
- package/shared/account.ts +201 -0
- package/shared/diagnostics.ts +52 -0
- package/shared/runtime-setup.ts +73 -0
- package/vendor/acp-registry/LICENSE +176 -0
- package/vendor/paseo/LICENSE +211 -0
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
// ConversationRow:行类型自包含。
|
|
2
|
+
// 三条结构性规则:row 自包含(渲染任一行不需看别的行);
|
|
3
|
+
// 结构变化换整行(row.upserted),文本增长用 append(row.delta);turn 是 row 上的标签不是容器。
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { executionOutputPreviewSchema } from "../execution-output-preview.js";
|
|
6
|
+
import { timestampSchema } from "./core.js";
|
|
7
|
+
import { backgroundResultOriginMetaSchema, workflowLaunchMetaSchema } from "./workflow-row-meta.js";
|
|
8
|
+
|
|
9
|
+
// RowBase。rowId:session 内单调、永不复用、事件日志的确定性纯函数。
|
|
10
|
+
const rowBaseFields = {
|
|
11
|
+
rowId: z.number(),
|
|
12
|
+
turnId: z.string(),
|
|
13
|
+
// canonical identity:新 CLI 每行必传;optional 只用于兼容旧版帧。
|
|
14
|
+
// entityId 定位持久实体,productTurnId 是产品轮次,不得由 UI 重猜。
|
|
15
|
+
entityId: z.string().min(1).optional(),
|
|
16
|
+
productTurnId: z.string().min(1).optional(),
|
|
17
|
+
visibility: z.literal("visible").optional(),
|
|
18
|
+
createdAt: timestampSchema,
|
|
19
|
+
createdAtSeq: z.number(),
|
|
20
|
+
// 缺省全 false;只下发为 true 的键。canRewind 不在载荷内(rewind = editUserQuery 的 UI 入口)。
|
|
21
|
+
actions: z
|
|
22
|
+
.object({
|
|
23
|
+
canFork: z.literal(true).optional(),
|
|
24
|
+
canEdit: z.literal(true).optional(),
|
|
25
|
+
canRetry: z.literal(true).optional(),
|
|
26
|
+
canRewindFiles: z.literal(true).optional(),
|
|
27
|
+
editDisposition: z.enum(["rewind", "fork"]).optional(),
|
|
28
|
+
})
|
|
29
|
+
.optional(),
|
|
30
|
+
} as const;
|
|
31
|
+
|
|
32
|
+
export const rowActionsSchema = rowBaseFields.actions;
|
|
33
|
+
export type RowActions = NonNullable<z.infer<typeof rowActionsSchema>>;
|
|
34
|
+
|
|
35
|
+
// workflow 轮的行级元数据拆到了 workflow-row-meta.ts(max-lines);名字在此原样再导出。
|
|
36
|
+
export {
|
|
37
|
+
backgroundResultOriginMetaSchema,
|
|
38
|
+
workflowLaunchMetaSchema,
|
|
39
|
+
workflowNotificationMetaSchema,
|
|
40
|
+
workflowSettingsAmendMetaSchema,
|
|
41
|
+
type BackgroundResultOriginMeta,
|
|
42
|
+
type WorkflowLaunchMeta,
|
|
43
|
+
type WorkflowNotificationMeta,
|
|
44
|
+
type WorkflowSettingsAmendMeta,
|
|
45
|
+
} from "./workflow-row-meta.js";
|
|
46
|
+
|
|
47
|
+
export const turnWorkSegmentSchema = z.object({
|
|
48
|
+
segmentId: z.string().min(1),
|
|
49
|
+
triggerEntityId: z.string().min(1).optional(),
|
|
50
|
+
startedAt: timestampSchema,
|
|
51
|
+
endedAt: timestampSchema.optional(),
|
|
52
|
+
activeMs: z.number().nonnegative().optional(),
|
|
53
|
+
});
|
|
54
|
+
export type TurnWorkSegment = z.infer<typeof turnWorkSegmentSchema>;
|
|
55
|
+
|
|
56
|
+
// turnHeader:product turn 边界 + 权威工时 + 每轮文件摘要。
|
|
57
|
+
// guide 产生的内部折叠边界由 workSegments 表达;行归属仍由 CLI 决定,客户端零归属逻辑。
|
|
58
|
+
export const turnHeaderRowSchema = z.object({
|
|
59
|
+
...rowBaseFields,
|
|
60
|
+
kind: z.literal("turnHeader"),
|
|
61
|
+
// workflowLaunch:中枢直接启动的 controlOnly 轮。
|
|
62
|
+
// 记录在案的偏斜:闭集枚举加值 → 旧桌面 + 新 CLI 时该行 parse 失败被丢(与下方
|
|
63
|
+
// backgroundSource: "workflow" 加值同一档),CLI 与桌面同批发布下接受。
|
|
64
|
+
origin: z.enum([
|
|
65
|
+
"userInput",
|
|
66
|
+
"backgroundResult",
|
|
67
|
+
"goalContinuation",
|
|
68
|
+
"editRerun",
|
|
69
|
+
"workflowLaunch",
|
|
70
|
+
]),
|
|
71
|
+
// 执行语义由 CLI 投影裁决;UI 不得根据输入文本或 duration 反推。
|
|
72
|
+
// optional 仅用于兼容旧 snapshot,新的 turnHeader 一律显式写入。
|
|
73
|
+
executionKind: z.enum(["agent", "controlOnly"]).optional(),
|
|
74
|
+
// 当前 query 的命令归因与历史轮次数;optional 兼容旧 transcript/snapshot。
|
|
75
|
+
sourceCommandId: z.string().optional(),
|
|
76
|
+
historyRoundCount: z.number().int().nonnegative().optional(),
|
|
77
|
+
state: z.enum(["running", "completedSuccess", "completedInterrupted", "failed"]),
|
|
78
|
+
startedAt: timestampSchema,
|
|
79
|
+
endedAt: timestampSchema.optional(),
|
|
80
|
+
// 权威工时:排除权限等待/用户输入等待/verifier 等待。
|
|
81
|
+
activeMs: z.number().optional(),
|
|
82
|
+
// guide 不切 product turn,但每条 accepted guide 都开启独立视觉工作段。
|
|
83
|
+
// 普通 turn 缺省以保持旧 snapshot 兼容;一旦出现 guide,CLI 负责完整投影首段与后续段。
|
|
84
|
+
workSegments: z.array(turnWorkSegmentSchema).optional(),
|
|
85
|
+
originMeta: backgroundResultOriginMetaSchema.optional(),
|
|
86
|
+
// origin === "workflowLaunch" 的轮上在场(活投影来源);与 originMeta 并列,不复用其形状。
|
|
87
|
+
workflowLaunch: workflowLaunchMetaSchema.optional(),
|
|
88
|
+
fileChanges: z
|
|
89
|
+
.object({
|
|
90
|
+
additions: z.number(),
|
|
91
|
+
deletions: z.number(),
|
|
92
|
+
files: z.number(),
|
|
93
|
+
state: z.enum(["active", "reverted"]).optional(),
|
|
94
|
+
})
|
|
95
|
+
.optional(),
|
|
96
|
+
});
|
|
97
|
+
export type TurnHeaderRow = z.infer<typeof turnHeaderRowSchema>;
|
|
98
|
+
|
|
99
|
+
// userInput。originMeta 消灭文本嗅探。
|
|
100
|
+
export const userInputRowSchema = z.object({
|
|
101
|
+
...rowBaseFields,
|
|
102
|
+
kind: z.literal("userInput"),
|
|
103
|
+
text: z.string(),
|
|
104
|
+
// text 从此下标起是引擎附加文本(dwf ask 尾注 /
|
|
105
|
+
// nudge),GUI 把它折进默认收起的披露;0 = 整条都是;缺席 = 无(老转录、非工作流会话)。
|
|
106
|
+
epilogueStart: z.number().int().nonnegative().optional(),
|
|
107
|
+
// workflowLaunch:中枢直接启动轮的用户可见行。
|
|
108
|
+
// 消息文本仍进 text(旧客户端 / TUI 的降级呈现就是那句规范英文);新客户端用下方
|
|
109
|
+
// workflowLaunch 元数据画轮尾 run 卡而非气泡。闭集加值的偏斜同 turnHeader.origin 注释。
|
|
110
|
+
origin: z.enum([
|
|
111
|
+
"realUser",
|
|
112
|
+
"backgroundResult",
|
|
113
|
+
"goalContinuation",
|
|
114
|
+
"mailbox",
|
|
115
|
+
"synthetic",
|
|
116
|
+
"workflowLaunch",
|
|
117
|
+
]),
|
|
118
|
+
originMeta: z
|
|
119
|
+
.object({
|
|
120
|
+
// 与 backgroundResultOriginMetaSchema 同一组取值(含 workflow run 的 "workflow")。
|
|
121
|
+
backgroundSource: z.enum(["bash", "subagent", "workflow"]).optional(),
|
|
122
|
+
workId: z.string().optional(),
|
|
123
|
+
senderSessionId: z.string().optional(),
|
|
124
|
+
senderLabel: z.string().optional(),
|
|
125
|
+
})
|
|
126
|
+
.optional(),
|
|
127
|
+
// origin === "workflowLaunch" 的行上在场;与 originMeta 并列,与 turnHeader 上同一份。
|
|
128
|
+
workflowLaunch: workflowLaunchMetaSchema.optional(),
|
|
129
|
+
// 经 turn-steer 注入(guideModeTurnSteer)。
|
|
130
|
+
guided: z.literal(true).optional(),
|
|
131
|
+
// realUser/guided 必带;系统来源缺省。overlay 收口锚点。
|
|
132
|
+
sourceCommandId: z.string().optional(),
|
|
133
|
+
// edit/retry 会生成新的 sourceCommandId;该字段固定指向 canonical input 根,
|
|
134
|
+
// 用于一次性恢复预算等跨重跑 lineage 判定。旧 transcript 可缺省。
|
|
135
|
+
rootSourceCommandId: z.string().optional(),
|
|
136
|
+
// 提交端身份由 CLI admission 写入;旧 transcript 可缺省。
|
|
137
|
+
clientId: z.string().optional(),
|
|
138
|
+
attachments: z
|
|
139
|
+
.array(
|
|
140
|
+
z.object({
|
|
141
|
+
ref: z.string(),
|
|
142
|
+
fileName: z.string(),
|
|
143
|
+
mime: z.string(),
|
|
144
|
+
bytes: z.number(),
|
|
145
|
+
previewRef: z.string().optional(),
|
|
146
|
+
}),
|
|
147
|
+
)
|
|
148
|
+
.optional(),
|
|
149
|
+
});
|
|
150
|
+
export type UserInputRow = z.infer<typeof userInputRowSchema>;
|
|
151
|
+
|
|
152
|
+
// assistantText / reasoning。
|
|
153
|
+
// 不变量:追加只能进 state="streaming" 的行;普通新 response 必然新 rowId。唯一例外是
|
|
154
|
+
// ProductProjection 已由 length/zero-tool 事实确认的 output-token Continue,会重新打开同 turn
|
|
155
|
+
// 且视觉紧邻的 assistantText row;客户端仍只观察标准 row.upserted + row.delta。
|
|
156
|
+
export const assistantTextRowSchema = z.object({
|
|
157
|
+
...rowBaseFields,
|
|
158
|
+
kind: z.literal("assistantText"),
|
|
159
|
+
// 同一模型 response 的正文与工具共享此 ID;optional 兼容旧 snapshot。
|
|
160
|
+
assistantResponseId: z.string().min(1).optional(),
|
|
161
|
+
text: z.string(),
|
|
162
|
+
state: z.enum(["streaming", "complete", "interrupted", "failed"]),
|
|
163
|
+
model: z.string().optional(),
|
|
164
|
+
feedback: z.enum(["like", "dislike"]).optional(),
|
|
165
|
+
});
|
|
166
|
+
export type AssistantTextRow = z.infer<typeof assistantTextRowSchema>;
|
|
167
|
+
|
|
168
|
+
export const reasoningRowSchema = z.object({
|
|
169
|
+
...rowBaseFields,
|
|
170
|
+
kind: z.literal("reasoning"),
|
|
171
|
+
// 同一模型 response 的思考、正文与工具共享此 ID;optional 兼容旧 snapshot。
|
|
172
|
+
assistantResponseId: z.string().min(1).optional(),
|
|
173
|
+
text: z.string(),
|
|
174
|
+
state: z.enum(["streaming", "complete", "interrupted"]),
|
|
175
|
+
durationMs: z.number().optional(),
|
|
176
|
+
});
|
|
177
|
+
export type ReasoningRow = z.infer<typeof reasoningRowSchema>;
|
|
178
|
+
|
|
179
|
+
// toolCall 展示层 schema 已拆至 ./toolDisplay.ts(rows.ts 受 max-lines 约束)。
|
|
180
|
+
import { toolCallDisplaySchema, toolOutputSchema, toolProgressSchema } from "./toolDisplay.js";
|
|
181
|
+
|
|
182
|
+
export const cuaAppIdentitySchema = z
|
|
183
|
+
.object({
|
|
184
|
+
pid: z.number().int().positive(),
|
|
185
|
+
name: z.string().trim().min(1).max(256),
|
|
186
|
+
bundleId: z.string().trim().min(1).max(512).optional(),
|
|
187
|
+
})
|
|
188
|
+
.strict();
|
|
189
|
+
export type CuaAppIdentity = z.infer<typeof cuaAppIdentitySchema>;
|
|
190
|
+
|
|
191
|
+
export const toolCallRowSchema = z.object({
|
|
192
|
+
...rowBaseFields,
|
|
193
|
+
kind: z.literal("toolCall"),
|
|
194
|
+
// 同一模型 response 的正文与工具共享此 ID;optional 兼容旧 snapshot。
|
|
195
|
+
assistantResponseId: z.string().min(1).optional(),
|
|
196
|
+
toolCallId: z.string(),
|
|
197
|
+
toolName: z.string(),
|
|
198
|
+
status: z.enum(["inputStreaming", "pendingApproval", "running", "success", "error", "cancelled"]),
|
|
199
|
+
inputText: z.string(),
|
|
200
|
+
input: z.unknown().optional(),
|
|
201
|
+
cuaApp: cuaAppIdentitySchema.optional(),
|
|
202
|
+
output: toolOutputSchema.optional(),
|
|
203
|
+
// display 解析失败只丢这张卡的载荷,不拒整条 row(理由见 toolDisplay.ts 的 toolOutputSchema
|
|
204
|
+
// 注释:装饰载荷不得决定 row/帧/订阅的生死)。
|
|
205
|
+
display: toolCallDisplaySchema.optional().catch(undefined),
|
|
206
|
+
// status=error 时必带。
|
|
207
|
+
error: z.object({ code: z.string(), message: z.string() }).optional(),
|
|
208
|
+
// 仅 replayable 档运行中出现,终态清除。
|
|
209
|
+
progress: toolProgressSchema.optional(),
|
|
210
|
+
// continuous/replayable 共用的有界 Bash 内容,终态或后台移交时清除。
|
|
211
|
+
outputPreview: executionOutputPreviewSchema.optional(),
|
|
212
|
+
// status=pendingApproval 时指向 pendingInteractions 项。
|
|
213
|
+
approvalInteractionId: z.string().optional(),
|
|
214
|
+
backgrounded: z.literal(true).optional(),
|
|
215
|
+
workId: z.string().optional(),
|
|
216
|
+
startedAt: timestampSchema.optional(),
|
|
217
|
+
endedAt: timestampSchema.optional(),
|
|
218
|
+
});
|
|
219
|
+
export type ToolCallRow = z.infer<typeof toolCallRowSchema>;
|
|
220
|
+
|
|
221
|
+
// 分享结果物是会话正式投影的一部分;ref 在本地投影中是受 Host 授权的读取引用,
|
|
222
|
+
// 公开分享投影必须将其替换为 zcode-artifact://share/:id,禁止透传本地路径。
|
|
223
|
+
export const conversationArtifactTypeSchema = z.enum([
|
|
224
|
+
"pdf",
|
|
225
|
+
"pptx",
|
|
226
|
+
"docx",
|
|
227
|
+
"xlsx",
|
|
228
|
+
"image",
|
|
229
|
+
"html",
|
|
230
|
+
"md",
|
|
231
|
+
"text",
|
|
232
|
+
]);
|
|
233
|
+
export type ConversationArtifactType = z.infer<typeof conversationArtifactTypeSchema>;
|
|
234
|
+
|
|
235
|
+
export const artifactRowSchema = z.object({
|
|
236
|
+
...rowBaseFields,
|
|
237
|
+
kind: z.literal("artifact"),
|
|
238
|
+
artifactVersionId: z.string().trim().min(1),
|
|
239
|
+
logicalArtifactKey: z.string().trim().min(1),
|
|
240
|
+
displayName: z.string().trim().min(1),
|
|
241
|
+
artifactType: conversationArtifactTypeSchema,
|
|
242
|
+
mimeType: z.string().trim().min(1),
|
|
243
|
+
sizeBytes: z.number().int().nonnegative(),
|
|
244
|
+
sha256: z.string().regex(/^[0-9a-f]{64}$/u),
|
|
245
|
+
ref: z.string().trim().min(1),
|
|
246
|
+
state: z.literal("current"),
|
|
247
|
+
});
|
|
248
|
+
export type ArtifactRow = z.infer<typeof artifactRowSchema>;
|
|
249
|
+
|
|
250
|
+
// subagent。前提:subagent 镜像事件必须进事件日志。
|
|
251
|
+
export const subagentRowSchema = z.object({
|
|
252
|
+
...rowBaseFields,
|
|
253
|
+
kind: z.literal("subagent"),
|
|
254
|
+
// 触发该子智能体的 Agent/Task 工具调用;并发 spawn 顺序不可作为关联依据。
|
|
255
|
+
parentToolCallId: z.string().optional(),
|
|
256
|
+
subagentType: z.string(),
|
|
257
|
+
status: z.enum(["running", "success", "failed", "cancelled"]),
|
|
258
|
+
summaryText: z.string(),
|
|
259
|
+
// 存在 → UI 可下钻订阅 conversation/<childSessionId>(不内嵌 child rows)。
|
|
260
|
+
childSessionId: z.string().optional(),
|
|
261
|
+
backgrounded: z.literal(true).optional(),
|
|
262
|
+
workId: z.string().optional(),
|
|
263
|
+
startedAt: timestampSchema.optional(),
|
|
264
|
+
endedAt: timestampSchema.optional(),
|
|
265
|
+
});
|
|
266
|
+
export type SubagentRow = z.infer<typeof subagentRowSchema>;
|
|
267
|
+
|
|
268
|
+
// Hook runtime descriptor 只用于 CLI event/projection 输入兼容。对话 wire row 使用下方
|
|
269
|
+
// client-safe summary,不携带命令、绝对路径、stdin/stdout/stderr/tool input 或环境变量。
|
|
270
|
+
export const hookExecutionDescriptorSchema = z
|
|
271
|
+
.object({
|
|
272
|
+
clientVisible: z.literal(true),
|
|
273
|
+
sourceKind: z.enum(["user", "plugin", "project", "internal"]),
|
|
274
|
+
sourcePath: z.string().optional(),
|
|
275
|
+
pluginId: z.string().optional(),
|
|
276
|
+
pluginName: z.string().optional(),
|
|
277
|
+
statusMessage: z.string().optional(),
|
|
278
|
+
executionType: z.enum(["process", "command"]),
|
|
279
|
+
executionMode: z.enum(["foreground", "background"]),
|
|
280
|
+
commandDisplay: z.string(),
|
|
281
|
+
timeoutMs: z.number().int().positive(),
|
|
282
|
+
})
|
|
283
|
+
.strict();
|
|
284
|
+
export type HookExecutionDescriptor = z.infer<typeof hookExecutionDescriptorSchema>;
|
|
285
|
+
|
|
286
|
+
export const hookExecutionProjectionSchema = z
|
|
287
|
+
.object({
|
|
288
|
+
hookRunId: z.string().min(1),
|
|
289
|
+
hookIndex: z.number().int().nonnegative(),
|
|
290
|
+
// 同一 runId 已观察到 HookRunStarted 才为 true;admission-only blocked 为 false。
|
|
291
|
+
didExecute: z.boolean(),
|
|
292
|
+
state: z.enum(["running", "completed", "failed"]),
|
|
293
|
+
outcome: z.enum(["success", "blocked", "failed", "cancelled", "timed_out"]).optional(),
|
|
294
|
+
blockReason: z.string().trim().min(1).optional(),
|
|
295
|
+
startedAt: timestampSchema,
|
|
296
|
+
endedAt: timestampSchema.optional(),
|
|
297
|
+
durationMs: z.number().nonnegative().optional(),
|
|
298
|
+
displayName: z.string().trim().min(1),
|
|
299
|
+
sourceKind: z.enum(["user", "plugin", "project"]),
|
|
300
|
+
pluginName: z.string().optional(),
|
|
301
|
+
toolName: z.string().optional(),
|
|
302
|
+
})
|
|
303
|
+
.strict();
|
|
304
|
+
export type HookExecutionProjection = z.infer<typeof hookExecutionProjectionSchema>;
|
|
305
|
+
|
|
306
|
+
export const hookInvocationRowSchema = z.object({
|
|
307
|
+
...rowBaseFields,
|
|
308
|
+
kind: z.literal("hookInvocation"),
|
|
309
|
+
hookInvocationId: z.string().min(1),
|
|
310
|
+
hookEventName: z.enum([
|
|
311
|
+
"SessionStart",
|
|
312
|
+
"UserPromptSubmit",
|
|
313
|
+
"PreToolUse",
|
|
314
|
+
"PermissionRequest",
|
|
315
|
+
"PostToolUse",
|
|
316
|
+
"PostToolUseFailure",
|
|
317
|
+
"Stop",
|
|
318
|
+
]),
|
|
319
|
+
hookCount: z.number().int().positive(),
|
|
320
|
+
state: z.enum(["running", "completed", "failed"]),
|
|
321
|
+
startedAt: timestampSchema,
|
|
322
|
+
endedAt: timestampSchema.optional(),
|
|
323
|
+
durationMs: z.number().nonnegative().optional(),
|
|
324
|
+
lane: z.enum(["assistantWork", "toolBefore", "toolAfter"]),
|
|
325
|
+
anchorToolCallId: z.string().optional(),
|
|
326
|
+
executions: z.array(hookExecutionProjectionSchema),
|
|
327
|
+
});
|
|
328
|
+
export type HookInvocationRow = z.infer<typeof hookInvocationRowSchema>;
|
|
329
|
+
|
|
330
|
+
// timelineMarker。
|
|
331
|
+
// compact.status=cancelled 表示 auto compact 被 stop;失败终态为 failed。
|
|
332
|
+
export const timelineMarkerPayloadSchema = z.union([
|
|
333
|
+
z.object({
|
|
334
|
+
type: z.literal("compact"),
|
|
335
|
+
origin: z.enum(["manual", "auto"]),
|
|
336
|
+
status: z.enum(["running", "success", "failed", "noop", "cancelled"]),
|
|
337
|
+
tokensBefore: z.number().optional(),
|
|
338
|
+
tokensAfter: z.number().optional(),
|
|
339
|
+
summaryRef: z.string().optional(),
|
|
340
|
+
}),
|
|
341
|
+
// 出现在 child 会话首部(forkTimelineIsBoundary)。
|
|
342
|
+
z.object({
|
|
343
|
+
type: z.literal("forkNotice"),
|
|
344
|
+
parentSessionId: z.string(),
|
|
345
|
+
parentRowId: z.number(),
|
|
346
|
+
}),
|
|
347
|
+
// 出现在 parent(可选展示)。
|
|
348
|
+
z.object({
|
|
349
|
+
type: z.literal("forkCreated"),
|
|
350
|
+
childSessionId: z.string(),
|
|
351
|
+
atRowId: z.number(),
|
|
352
|
+
}),
|
|
353
|
+
z.object({
|
|
354
|
+
type: z.literal("modelChange"),
|
|
355
|
+
fromProvider: z.string(),
|
|
356
|
+
fromModel: z.string(),
|
|
357
|
+
toProvider: z.string(),
|
|
358
|
+
toModel: z.string(),
|
|
359
|
+
toThought: z.string(),
|
|
360
|
+
}),
|
|
361
|
+
z.object({
|
|
362
|
+
type: z.literal("modelChange"),
|
|
363
|
+
// 显式 ∅→X 模型边界没有来源;never 保证两个来源字段不能只出现一个,
|
|
364
|
+
// 避免 renderer 接收到半个 provider/model 元组。
|
|
365
|
+
fromProvider: z.never().optional(),
|
|
366
|
+
fromModel: z.never().optional(),
|
|
367
|
+
toProvider: z.string(),
|
|
368
|
+
toModel: z.string(),
|
|
369
|
+
toThought: z.string(),
|
|
370
|
+
}),
|
|
371
|
+
z.object({
|
|
372
|
+
type: z.literal("goalSet"),
|
|
373
|
+
objective: z.string(),
|
|
374
|
+
previousObjective: z.string().optional(),
|
|
375
|
+
}),
|
|
376
|
+
z.object({
|
|
377
|
+
type: z.literal("goalVerify"),
|
|
378
|
+
iteration: z.number(),
|
|
379
|
+
outcome: z.enum(["running", "pass", "notSatisfied", "failed"]),
|
|
380
|
+
detail: z.string().optional(),
|
|
381
|
+
}),
|
|
382
|
+
z.object({
|
|
383
|
+
type: z.literal("retryNotice"),
|
|
384
|
+
attempt: z.number(),
|
|
385
|
+
reasonCode: z.string(),
|
|
386
|
+
}),
|
|
387
|
+
// workspace 域动作在时间线上的回执。
|
|
388
|
+
z.object({
|
|
389
|
+
type: z.literal("checkpointRestored"),
|
|
390
|
+
checkpointId: z.string(),
|
|
391
|
+
}),
|
|
392
|
+
]);
|
|
393
|
+
export type TimelineMarkerPayload = z.infer<typeof timelineMarkerPayloadSchema>;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* marker 泳道:
|
|
397
|
+
* 落位语义由 CLI 投影裁决,UI 只按 lane 装配、不得按 marker type 自行推断。
|
|
398
|
+
* - assistantWork:assistant 工作活动(compact),进「已工作」折叠组;
|
|
399
|
+
* - turnTailBoundary:轮尾边界(goalVerify/forkNotice),留轮结尾不折叠;
|
|
400
|
+
* - lightBoundary:轮顶轻边界(modelChange),渲染在 user 输入之前。
|
|
401
|
+
* optional = 老 snapshot 兼容(缺省时 UI 按 marker type 回落映射)。
|
|
402
|
+
*/
|
|
403
|
+
export const timelineMarkerLaneSchema = z.enum([
|
|
404
|
+
"assistantWork",
|
|
405
|
+
"turnTailBoundary",
|
|
406
|
+
"lightBoundary",
|
|
407
|
+
]);
|
|
408
|
+
export type TimelineMarkerLane = z.infer<typeof timelineMarkerLaneSchema>;
|
|
409
|
+
|
|
410
|
+
export const timelineMarkerRowSchema = z.object({
|
|
411
|
+
...rowBaseFields,
|
|
412
|
+
kind: z.literal("timelineMarker"),
|
|
413
|
+
// 用户触发的 marker 必带。
|
|
414
|
+
sourceCommandId: z.string().optional(),
|
|
415
|
+
lane: timelineMarkerLaneSchema.optional(),
|
|
416
|
+
marker: timelineMarkerPayloadSchema,
|
|
417
|
+
});
|
|
418
|
+
export type TimelineMarkerRow = z.infer<typeof timelineMarkerRowSchema>;
|
|
419
|
+
|
|
420
|
+
export const conversationRowSchema = z.discriminatedUnion("kind", [
|
|
421
|
+
turnHeaderRowSchema,
|
|
422
|
+
userInputRowSchema,
|
|
423
|
+
assistantTextRowSchema,
|
|
424
|
+
reasoningRowSchema,
|
|
425
|
+
toolCallRowSchema,
|
|
426
|
+
artifactRowSchema,
|
|
427
|
+
subagentRowSchema,
|
|
428
|
+
hookInvocationRowSchema,
|
|
429
|
+
timelineMarkerRowSchema,
|
|
430
|
+
]);
|
|
431
|
+
export type ConversationRow = z.infer<typeof conversationRowSchema>;
|
|
432
|
+
export type ConversationRowKind = ConversationRow["kind"];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { modelSelectionSchema } from "../model-selection.js";
|
|
3
|
+
|
|
4
|
+
// ── config──
|
|
5
|
+
export const sessionConfigStateSchema = z.object({
|
|
6
|
+
/** Session 接受并持久化的稀疏选择意图;provider/model/thought 仅为 UI effective 投影。 */
|
|
7
|
+
modelSelection: modelSelectionSchema.optional(),
|
|
8
|
+
provider: z.string(),
|
|
9
|
+
model: z.string(),
|
|
10
|
+
thought: z.string(),
|
|
11
|
+
// 思考档位是当前模型的能力,不是 workspace/UI 偏好。
|
|
12
|
+
// default 仅用于兼容旧快照;新 agent 必须从 runtime 投影实际集合。
|
|
13
|
+
thoughtLevels: z.array(z.string()).default([]),
|
|
14
|
+
followupMode: z.enum(["queue", "guide"]),
|
|
15
|
+
// additive(冻结面演进,同 meta 的裁决口径):agent 协作模式(core CollaborationMode)。
|
|
16
|
+
// 必须带 default 才不破坏旧快照/旧发送端的解析;投影经 SessionModeChanged 事件更新。
|
|
17
|
+
mode: z.string().default("build"),
|
|
18
|
+
planEnabled: z.boolean().optional(),
|
|
19
|
+
/** 明确审批结果;草稿按 interactionId 消费一次,普通 mode 更新不重置它。 */
|
|
20
|
+
permissionGrant: z.object({ interactionId: z.string().min(1) }).optional(),
|
|
21
|
+
/** 最近工具转换的关联,供草稿定向同步;不新增可见历史事件。 */
|
|
22
|
+
planTransition: z
|
|
23
|
+
.object({
|
|
24
|
+
toolCallId: z.string(),
|
|
25
|
+
planEnabled: z.boolean(),
|
|
26
|
+
})
|
|
27
|
+
.optional(),
|
|
28
|
+
});
|
|
29
|
+
export type SessionConfigState = z.infer<typeof sessionConfigStateSchema>;
|
|
30
|
+
|
|
31
|
+
export const sessionModelTransitionSchema = z.object({
|
|
32
|
+
eventId: z.string().min(1),
|
|
33
|
+
origin: z.literal("registryFallback"),
|
|
34
|
+
from: z.object({
|
|
35
|
+
provider: z.string(),
|
|
36
|
+
model: z.string(),
|
|
37
|
+
}),
|
|
38
|
+
to: z.object({
|
|
39
|
+
provider: z.string(),
|
|
40
|
+
model: z.string(),
|
|
41
|
+
}),
|
|
42
|
+
});
|
|
43
|
+
export type SessionModelTransition = z.infer<typeof sessionModelTransitionSchema>;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// sessions-index 的工作流运行摘要
|
|
3
|
+
// ============================================================
|
|
4
|
+
// 侧栏要在会话标题下画一条「Workflow 图标 + 迷你轨道灯 + 当前 phase 名」,却不能为此订阅整个
|
|
5
|
+
// workflowRuns(那是 conversation 权威投影,按 run 进度高频变化)。这里把同一 snapshot 的
|
|
6
|
+
// `workflowRuns` + `backgroundWorks` 派生成一份**有界、只装侧栏真正读的字段**的摘要:
|
|
7
|
+
// 纯函数、无时钟——「已结束的行何时折叠」由渲染端的已确认集合决定,不在这里记时间。
|
|
8
|
+
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { timestampSchema } from "./core.js";
|
|
11
|
+
import type { BackgroundWorkSummary } from "./snapshot.js";
|
|
12
|
+
import {
|
|
13
|
+
WORKFLOW_RUNS_LIMITS,
|
|
14
|
+
workflowRunSchema,
|
|
15
|
+
type WorkflowRunNode,
|
|
16
|
+
type WorkflowRunState,
|
|
17
|
+
type WorkflowRunsState,
|
|
18
|
+
} from "./workflow-runs.js";
|
|
19
|
+
|
|
20
|
+
/** 每会话最多下发的 run 数:在跑的按启动序在前,其后是最近结束的。 */
|
|
21
|
+
export const SESSION_WORKFLOW_ACTIVITY_MAX_RUNS = 4;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 站点灯的四态,与卡片时间线同一词汇(`STATUS_DOT`)。控制流给出骨架:在跑时当前 phase
|
|
25
|
+
* running、已进入 done、其余 pending;completed 已进入 done;errored 当前 failed;stopped 当前 pending。
|
|
26
|
+
*
|
|
27
|
+
* 成员节点再补一条:run 在跑时,
|
|
28
|
+
* **出生在这一站**且此刻真在跑的节点把它点亮。并行阶段因此能同时烧——控制流只记得最后一个标记,
|
|
29
|
+
* 而 A 的子代理在 B 的标记之后仍在干活。节点只会说「还在跑」,绝不把 done / failed / pending
|
|
30
|
+
* 改成别的:失败词留给控制流。
|
|
31
|
+
*/
|
|
32
|
+
export const sessionWorkflowPhaseStatusSchema = z.enum(["pending", "running", "done", "failed"]);
|
|
33
|
+
export type SessionWorkflowPhaseStatus = z.infer<typeof sessionWorkflowPhaseStatusSchema>;
|
|
34
|
+
|
|
35
|
+
export const sessionWorkflowPhaseSummarySchema = z.object({
|
|
36
|
+
name: z.string().min(1).max(WORKFLOW_RUNS_LIMITS.maxPhaseNameLength),
|
|
37
|
+
status: sessionWorkflowPhaseStatusSchema,
|
|
38
|
+
/**
|
|
39
|
+
* 进入本站时仍在跑的其他站的**下标**(下标落在本 `phases` 数组上),来自
|
|
40
|
+
* `run.phaseAlongside`。侧栏据此把并行的两站之间画成双线段。只有声明表那条路有这个事实——
|
|
41
|
+
* 退化路(已进入的 phase)是按进入序拼出来的,没有并行可言,所以那时整个键缺席。
|
|
42
|
+
*/
|
|
43
|
+
alongside: z.array(z.number().int().nonnegative()).max(WORKFLOW_RUNS_LIMITS.maxPhases).optional(),
|
|
44
|
+
});
|
|
45
|
+
export type SessionWorkflowPhaseSummary = z.infer<typeof sessionWorkflowPhaseSummarySchema>;
|
|
46
|
+
|
|
47
|
+
export const sessionWorkflowRunSummarySchema = z.object({
|
|
48
|
+
runId: z.string().min(1),
|
|
49
|
+
/** 发起行的工具调用 id:点击运行行打开 run pane 的键;直接启动的 run 也有(`launch-` 前缀)。 */
|
|
50
|
+
toolCallId: z.string().min(1).optional(),
|
|
51
|
+
/** 工作流后台工作的标题(= run 的展示名);投影里没有对应后台工作时缺席。 */
|
|
52
|
+
name: z.string().min(1).optional(),
|
|
53
|
+
status: workflowRunSchema.shape.status,
|
|
54
|
+
stopReason: workflowRunSchema.shape.stopReason,
|
|
55
|
+
/** 后台工作的开始时刻,tooltip 的 elapsed 用;没有后台工作时缺席。 */
|
|
56
|
+
startedAt: timestampSchema.optional(),
|
|
57
|
+
/**
|
|
58
|
+
* 站点表,声明序:`run.phaseNames`(run-launched 带来的声明表)在场用它,否则退化为已进入的
|
|
59
|
+
* phase + 当前 phase(进入序)。两者都没有时为空数组,UI 画一个隐含站点「Workflow」。
|
|
60
|
+
*/
|
|
61
|
+
phases: z.array(sessionWorkflowPhaseSummarySchema).max(WORKFLOW_RUNS_LIMITS.maxPhases),
|
|
62
|
+
currentPhase: z.string().min(1).max(WORKFLOW_RUNS_LIMITS.maxPhaseNameLength).optional(),
|
|
63
|
+
/** status === "running" 的子代理数(tooltip 的「{n} agents working」)。 */
|
|
64
|
+
agentsWorking: z.number().int().nonnegative(),
|
|
65
|
+
});
|
|
66
|
+
export type SessionWorkflowRunSummary = z.infer<typeof sessionWorkflowRunSummarySchema>;
|
|
67
|
+
|
|
68
|
+
export const sessionWorkflowActivitySchema = z.object({
|
|
69
|
+
runs: z.array(sessionWorkflowRunSummarySchema).max(SESSION_WORKFLOW_ACTIVITY_MAX_RUNS),
|
|
70
|
+
});
|
|
71
|
+
export type SessionWorkflowActivity = z.infer<typeof sessionWorkflowActivitySchema>;
|
|
72
|
+
|
|
73
|
+
export function isSessionWorkflowRunLive(status: SessionWorkflowRunSummary["status"]): boolean {
|
|
74
|
+
return status === "pending" || status === "running";
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 「这个节点此刻真在跑」:与 packages/ui 的 `statusOfRunNode` 的 running 臂逐条相同,也与
|
|
79
|
+
* reducer 推 actor 三态用的那一组相同(workflow-runs-reducer.ts),所以站点灯与
|
|
80
|
+
* 「{n} agents working」永远对同一件事说「在跑」。
|
|
81
|
+
*
|
|
82
|
+
* `dispatched` / `waiting` 不算:前者是「会话就绪、首个请求尚未准入」的短暂相位,后者在等槽位
|
|
83
|
+
* 或在退避——真正发出去了由 `node-executing` 说。
|
|
84
|
+
*/
|
|
85
|
+
function isRunNodeRunning(node: WorkflowRunNode): boolean {
|
|
86
|
+
return node.phase === "executing" || node.phase === "repairing" || node.phase === "nudged";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* 站名 ↔ 实例出生戳的关联规则。与 packages/ui 的 `phaseNameMatches`(workflow-graph/phase-name.ts)
|
|
91
|
+
* 逐条相同:精确匹配,站名**恰好顶到上界**时才按前缀兜底——前缀只在截断真的发生过时才开,
|
|
92
|
+
* 否则「计划」会误认「计划修复」。那个 helper 在 ui 层,shared 不能反向依赖,所以这里内联同一条规则。
|
|
93
|
+
*/
|
|
94
|
+
function phaseNameMatches(stationName: string, stamp: string): boolean {
|
|
95
|
+
return (
|
|
96
|
+
stationName === stamp ||
|
|
97
|
+
(stationName.length >= WORKFLOW_RUNS_LIMITS.maxPhaseNameLength && stamp.startsWith(stationName))
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function derivePhases(run: WorkflowRunState): SessionWorkflowPhaseSummary[] {
|
|
102
|
+
const entered = new Set((run.phases ?? []).map((phase) => phase.name));
|
|
103
|
+
const current = run.currentPhase;
|
|
104
|
+
let names: string[];
|
|
105
|
+
// 「同时在跑」的下标说的是**声明表**里的位置,所以只有走声明表这条路时它才有意义;退化路
|
|
106
|
+
// (已进入的 phase + 当前 phase)是另一个下标空间,那时整张表不带。
|
|
107
|
+
let alongside: readonly (readonly number[])[] | undefined;
|
|
108
|
+
if (run.phaseNames !== undefined && run.phaseNames.length > 0) {
|
|
109
|
+
names = run.phaseNames;
|
|
110
|
+
alongside = run.phaseAlongside;
|
|
111
|
+
} else {
|
|
112
|
+
names = (run.phases ?? []).map((phase) => phase.name);
|
|
113
|
+
if (current !== undefined && !entered.has(current)) names = [...names, current];
|
|
114
|
+
}
|
|
115
|
+
const live = isSessionWorkflowRunLive(run.status);
|
|
116
|
+
// 在跑的节点的出生戳。run 不在跑时整张表为空:终态 run 里没有人还在干活,哪怕某条 settled
|
|
117
|
+
// 事件没来得及落下(与 actor 三态里「终态压过一切」同一姿态)。
|
|
118
|
+
const burning = live
|
|
119
|
+
? run.nodes.filter(isRunNodeRunning).flatMap((node) => node.phaseName ?? [])
|
|
120
|
+
: [];
|
|
121
|
+
const emitted = Math.min(names.length, WORKFLOW_RUNS_LIMITS.maxPhases);
|
|
122
|
+
return names.slice(0, WORKFLOW_RUNS_LIMITS.maxPhases).map((name, index) => {
|
|
123
|
+
const isCurrent = name === current;
|
|
124
|
+
const wasEntered = entered.has(name) || isCurrent;
|
|
125
|
+
// 出生在这一站的节点还在跑 → 这一站还在烧,哪怕控制流早已走到下一个标记。
|
|
126
|
+
const burningHere = burning.some((stamp) => phaseNameMatches(name, stamp));
|
|
127
|
+
let status: SessionWorkflowPhaseStatus;
|
|
128
|
+
if (live) {
|
|
129
|
+
status = isCurrent || burningHere ? "running" : wasEntered ? "done" : "pending";
|
|
130
|
+
} else if (run.status === "completed") {
|
|
131
|
+
status = wasEntered ? "done" : "pending";
|
|
132
|
+
} else if (run.status === "errored") {
|
|
133
|
+
status = isCurrent ? "failed" : wasEntered ? "done" : "pending";
|
|
134
|
+
} else {
|
|
135
|
+
// stopped:控制流停在当前 phase,它没有完成也没有失败——留空心灯。
|
|
136
|
+
status = isCurrent ? "pending" : wasEntered ? "done" : "pending";
|
|
137
|
+
}
|
|
138
|
+
// 裁表之后下标空间跟着变窄:指向被裁掉的站的引用一起丢掉,剩下空的就不建键。
|
|
139
|
+
const beside = (alongside?.[index] ?? []).filter(
|
|
140
|
+
(other) => Number.isInteger(other) && other >= 0 && other < emitted && other !== index,
|
|
141
|
+
);
|
|
142
|
+
return { name, status, ...(beside.length === 0 ? {} : { alongside: beside }) };
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function summarizeRun(
|
|
147
|
+
run: WorkflowRunState,
|
|
148
|
+
work: BackgroundWorkSummary | undefined,
|
|
149
|
+
): SessionWorkflowRunSummary {
|
|
150
|
+
const name = work?.title.trim();
|
|
151
|
+
return {
|
|
152
|
+
runId: run.runId,
|
|
153
|
+
...(run.toolCallId === undefined ? {} : { toolCallId: run.toolCallId }),
|
|
154
|
+
...(name === undefined || name.length === 0 ? {} : { name }),
|
|
155
|
+
status: run.status,
|
|
156
|
+
...(run.stopReason === undefined ? {} : { stopReason: run.stopReason }),
|
|
157
|
+
...(work === undefined ? {} : { startedAt: work.startedAt }),
|
|
158
|
+
phases: derivePhases(run),
|
|
159
|
+
...(run.currentPhase === undefined ? {} : { currentPhase: run.currentPhase }),
|
|
160
|
+
agentsWorking: run.actors.filter((actor) => actor.status === "running").length,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 从同一 snapshot 的 `workflowRuns` + `backgroundWorks` 派生会话的工作流运行摘要。
|
|
166
|
+
* 在跑的 run(pending / running)按 `runs[]` 序(= 启动序)在前;其后是已结束的,按后台工作的
|
|
167
|
+
* `endedAt` 倒序、无 endedAt 时按 `runs[]` 倒序(越晚建的越新)。总数裁到 4。
|
|
168
|
+
* 会话一个 run 都没有 → `undefined`(键整个缺席,旧 CLI 因此什么都不变)。
|
|
169
|
+
*/
|
|
170
|
+
export function deriveSessionWorkflowActivity(input: {
|
|
171
|
+
workflowRuns: WorkflowRunsState | undefined;
|
|
172
|
+
backgroundWorks: readonly BackgroundWorkSummary[];
|
|
173
|
+
}): SessionWorkflowActivity | undefined {
|
|
174
|
+
const runs = input.workflowRuns?.runs;
|
|
175
|
+
if (runs === undefined || runs.length === 0) return undefined;
|
|
176
|
+
const workByRunId = new Map<string, BackgroundWorkSummary>();
|
|
177
|
+
for (const work of input.backgroundWorks) {
|
|
178
|
+
if (work.kind === "workflow") workByRunId.set(work.workId, work);
|
|
179
|
+
}
|
|
180
|
+
const live: SessionWorkflowRunSummary[] = [];
|
|
181
|
+
const settled: { summary: SessionWorkflowRunSummary; endedAt: number; index: number }[] = [];
|
|
182
|
+
runs.forEach((run, index) => {
|
|
183
|
+
const work = workByRunId.get(run.runId);
|
|
184
|
+
const summary = summarizeRun(run, work);
|
|
185
|
+
if (isSessionWorkflowRunLive(run.status)) live.push(summary);
|
|
186
|
+
else settled.push({ summary, endedAt: work?.endedAt ?? 0, index });
|
|
187
|
+
});
|
|
188
|
+
settled.sort((a, b) => b.endedAt - a.endedAt || b.index - a.index);
|
|
189
|
+
return {
|
|
190
|
+
runs: [...live, ...settled.map((entry) => entry.summary)].slice(
|
|
191
|
+
0,
|
|
192
|
+
SESSION_WORKFLOW_ACTIVITY_MAX_RUNS,
|
|
193
|
+
),
|
|
194
|
+
};
|
|
195
|
+
}
|