@rivus/agent 0.12.6 → 0.13.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/dist/index.js CHANGED
@@ -2,7 +2,7 @@ import { a as createAgentLoopSkillExecutionStart, c as createAgentLoopToolExecut
2
2
  import { a as createMemoryNamespace, c as InvalidRivusPlugin, d as requiresToolApproval, i as RIVUS_MEMORY_TOOL_VERSION, l as RIVUS_PLUGIN_API_VERSION, n as RIVUS_MEMORY_TOOL_ID, o as createRivusMemoryToolContract, r as RIVUS_MEMORY_TOOL_PLUGIN_ID, s as restrictMemoryScopesForAudience, t as MEMORY_SCOPES, u as RivusToolInputRejected } from "./agent-memory.js";
3
3
  import { a as BACKGROUND_SESSION_TOOL_VERSION, c as createBackgroundSessionStepSourceMessageId, d as isBackgroundSessionToolId, f as narrowBackgroundSessionDefinition, i as BACKGROUND_SESSION_TOOL_PLUGIN_ID, l as createBackgroundSessionToolContracts, n as BACKGROUND_SESSION_START_TOOL_ID, o as backgroundSessionToolIds, r as BACKGROUND_SESSION_TOOL_IDS, s as createBackgroundSessionKey, t as BACKGROUND_SESSION_SESSION_KEY_PREFIX, u as extendBackgroundSessionDefinition } from "./background-session-authority.js";
4
4
  import { n as resolveRivusAgentDefinition, t as createRivusPluginCatalog } from "./rivus-plugin-registry.js";
5
- import { $ as loadRivusDeployment, A as DEFAULT_BACKGROUND_SESSION_LIFETIME_MS, B as acceptsCardPresentationProgress, C as loadRivusDaemonConfig, D as loadRivusDeploymentManifest, E as RivusDeploymentManifestError, F as DEFAULT_BACKGROUND_SESSION_SUPERVISOR_INTERVAL_MS, G as createCardPresentationChain, H as beginCardPresentationHandoff, I as resolveBackgroundSessionSupervisorIntervalMs, J as markCardPresentationTerminal, K as failCardPresentationHandoff, L as DEFAULT_CARD_STREAM_LEASE_MS, M as DEFAULT_BACKGROUND_SESSION_MAX_CONSECUTIVE_FAILURES, N as DEFAULT_BACKGROUND_SESSION_RETRY_BACKOFF_MS, O as DEFAULT_BACKGROUND_SESSION_LEASE_MS, P as DEFAULT_BACKGROUND_SESSION_STEP_TIMEOUT_MS, Q as RivusPluginLoadError, R as createFeishuCardRollover, S as RivusDaemonConfigError, U as compensateCardPresentationHandoff, V as activeCardPresentation, W as completeCardPresentationHandoff, X as resolveFeishuEndpointCredentials, Y as FeishuEndpointCredentialError, _ as createStableId, a as InvalidRivusProjectSpace, b as createRivusEnvFromOpenClawConfig, c as RivusDeploymentReadinessError, d as createRivusAgentHost, et as validateRivusDeploymentManifest, f as AgentInstanceBusy, g as createAgentInstanceRegistry, h as AgentInstanceConflict, i as resolveRivusProjectSpace, j as DEFAULT_BACKGROUND_SESSION_MAX_CONCURRENT_SESSIONS, k as DEFAULT_BACKGROUND_SESSION_LEASE_RENEWAL_INTERVAL_MS, l as createRivusDeploymentDaemon, m as createAgentRuntimePool, n as createRivusDeploymentCliProcess, o as RivusDeploymentAutomationReadinessError, p as AgentRuntimeDisposed, q as isCardPresentationHandoffDue, r as createConfiguredRivusDeploymentDaemon, s as RivusDeploymentDaemonLifecycleError, t as runRivusDaemonCli, u as InvalidRivusEndpointBinding, v as createRivusDaemonShutdownController, w as loadNodeRivusPluginModule, x as formatRivusEnvFile, y as OpenClawEnvImportError, z as CardPresentationTransitionDenied } from "./rivus-daemon-cli.js";
5
+ import { $ as resolveFeishuEndpointCredentials, A as DEFAULT_BACKGROUND_SESSION_LEASE_RENEWAL_INTERVAL_MS, B as RUN_PRESENTATION_SCHEMA_VERSION, C as loadRivusDaemonConfig, D as loadRivusDeploymentManifest, E as RivusDeploymentManifestError, F as DEFAULT_BACKGROUND_SESSION_STEP_TIMEOUT_MS, G as beginCardPresentationHandoff, H as CardPresentationTransitionDenied, I as DEFAULT_BACKGROUND_SESSION_SUPERVISOR_INTERVAL_MS, J as createCardPresentationChain, K as compensateCardPresentationHandoff, L as resolveBackgroundSessionSupervisorIntervalMs, M as DEFAULT_BACKGROUND_SESSION_MAX_CONCURRENT_SESSIONS, N as DEFAULT_BACKGROUND_SESSION_MAX_CONSECUTIVE_FAILURES, O as DEFAULT_CONVERSATION_PROGRESS_DISPLAY, P as DEFAULT_BACKGROUND_SESSION_RETRY_BACKOFF_MS, Q as FeishuEndpointCredentialError, R as DEFAULT_CARD_STREAM_LEASE_MS, S as RivusDaemonConfigError, U as acceptsCardPresentationProgress, V as hasInspectableRunProgress, W as activeCardPresentation, X as isCardPresentationHandoffDue, Y as failCardPresentationHandoff, Z as markCardPresentationTerminal, _ as createStableId, a as InvalidRivusProjectSpace, b as createRivusEnvFromOpenClawConfig, c as RivusDeploymentReadinessError, d as createRivusAgentHost, f as AgentInstanceBusy, g as createAgentInstanceRegistry, h as AgentInstanceConflict, i as resolveRivusProjectSpace, j as DEFAULT_BACKGROUND_SESSION_LIFETIME_MS, k as DEFAULT_BACKGROUND_SESSION_LEASE_MS, l as createRivusDeploymentDaemon, m as createAgentRuntimePool, n as createRivusDeploymentCliProcess, nt as loadRivusDeployment, o as RivusDeploymentAutomationReadinessError, p as AgentRuntimeDisposed, q as completeCardPresentationHandoff, r as createConfiguredRivusDeploymentDaemon, rt as validateRivusDeploymentManifest, s as RivusDeploymentDaemonLifecycleError, t as runRivusDaemonCli, tt as RivusPluginLoadError, u as InvalidRivusEndpointBinding, v as createRivusDaemonShutdownController, w as loadNodeRivusPluginModule, x as formatRivusEnvFile, y as OpenClawEnvImportError, z as createFeishuCardRollover } from "./rivus-daemon-cli.js";
6
6
  import { a as InvalidInvocationAuthority, i as normalizeStableJson, n as InvalidToolInput, o as createInvocationAuthority, r as createToolInputDigest, s as resolveInvocationAuthority, t as InvalidStableJson } from "./tool-input-digest.js";
7
7
  import { a as readBackgroundSessionWaitInput, i as readBackgroundSessionString, n as readBackgroundSessionObject, r as readBackgroundSessionPhase, t as readBackgroundSessionInteger } from "./background-session-input.js";
8
8
  import { n as assertRivusPluginConforms, r as createFakeRivusPlugin, t as RivusPluginConformanceError } from "./rivus-plugin-testkit.js";
@@ -28,67 +28,421 @@ function createSerialExecutor() {
28
28
  } };
29
29
  }
30
30
  //#endregion
31
+ //#region src/application/presentation/presented-value.ts
32
+ const DEFAULT_MAX_COLLECTION_ITEMS = 20;
33
+ const DEFAULT_MAX_DEPTH = 5;
34
+ const DEFAULT_MAX_NODES = 100;
35
+ const DEFAULT_MAX_STRING_CHARACTERS = 800;
36
+ const SENSITIVE_KEY = /authorization|cookie|credential|password|passwd|private[-_]?key|secret|session[-_]?token|(?:^|[-_])token(?:$|[-_])|api[-_]?key|access[-_]?(?:key|token)|refresh[-_]?token|client[-_]?secret/i;
37
+ const WORKING_DIRECTORY_KEY = /^(?:cwd|workdir|workingDirectory|workspace|workspaceRoot)$/i;
38
+ const INLINE_SECRET = /\b(Bearer\s+)[^\s,;]+|\b(?:gh[opusr]_|sk-|xox[baprs]-)[A-Za-z0-9_-]{8,}/gi;
39
+ const NAMED_SECRET_ARGUMENT = /((?:--?|\b)(?:authorization|password|passwd|secret|token|api[-_]?key|access[-_]?token)(?:\s+|=))([^\s,;]+)/gi;
40
+ const SECRET_ENVIRONMENT_ASSIGNMENT = /\b([A-Z0-9_]*(?:PASSWORD|SECRET|TOKEN|API_KEY|ACCESS_KEY)=)([^\s,;]+)/g;
41
+ function createPresentedValue(value, options = {}) {
42
+ return present(value, {
43
+ ancestors: /* @__PURE__ */ new Set(),
44
+ depth: 0,
45
+ maxCollectionItems: options.maxCollectionItems ?? DEFAULT_MAX_COLLECTION_ITEMS,
46
+ maxDepth: options.maxDepth ?? DEFAULT_MAX_DEPTH,
47
+ nodeBudget: { remaining: options.maxNodes ?? DEFAULT_MAX_NODES },
48
+ maxStringCharacters: options.maxStringCharacters ?? DEFAULT_MAX_STRING_CHARACTERS
49
+ });
50
+ }
51
+ function present(value, context, key) {
52
+ if (key && SENSITIVE_KEY.test(key)) return {
53
+ kind: "redacted",
54
+ reason: "sensitive-key"
55
+ };
56
+ if (context.nodeBudget.remaining <= 0) return {
57
+ kind: "unsupported",
58
+ valueType: "node-budget"
59
+ };
60
+ context.nodeBudget.remaining -= 1;
61
+ if (value === null) return { kind: "null" };
62
+ if (typeof value === "boolean") return {
63
+ kind: "boolean",
64
+ value
65
+ };
66
+ if (typeof value === "number") return Number.isFinite(value) ? {
67
+ kind: "number",
68
+ value
69
+ } : {
70
+ kind: "unsupported",
71
+ valueType: "number"
72
+ };
73
+ if (typeof value === "string") return presentText(value, context.maxStringCharacters, key);
74
+ if (typeof value !== "object") return {
75
+ kind: "unsupported",
76
+ valueType: typeof value
77
+ };
78
+ if (context.depth >= context.maxDepth) return {
79
+ kind: "unsupported",
80
+ valueType: "max-depth"
81
+ };
82
+ if (context.ancestors.has(value)) return {
83
+ kind: "unsupported",
84
+ valueType: "circular"
85
+ };
86
+ context.ancestors.add(value);
87
+ const nested = {
88
+ ...context,
89
+ depth: context.depth + 1
90
+ };
91
+ try {
92
+ if (Array.isArray(value)) {
93
+ const visibleLength = Math.min(value.length, context.maxCollectionItems);
94
+ const items = Array.from({ length: visibleLength }, (_, index) => Object.hasOwn(value, index) ? present(value[index], nested) : {
95
+ kind: "unsupported",
96
+ valueType: "array-hole"
97
+ });
98
+ return {
99
+ items,
100
+ kind: "list",
101
+ omittedItems: Math.max(0, value.length - items.length)
102
+ };
103
+ }
104
+ if (value instanceof Error) return {
105
+ entries: [{
106
+ key: "name",
107
+ value: present(value.name, nested, "name")
108
+ }, {
109
+ key: "message",
110
+ value: present(value.message, nested, "message")
111
+ }],
112
+ kind: "record",
113
+ omittedEntries: 0
114
+ };
115
+ const prototype = Object.getPrototypeOf(value);
116
+ if (prototype !== Object.prototype && prototype !== null) return {
117
+ kind: "unsupported",
118
+ valueType: prototype?.constructor?.name ?? "object"
119
+ };
120
+ const allEntries = Object.entries(value);
121
+ const entries = allEntries.slice(0, context.maxCollectionItems).map(([entryKey, entryValue]) => ({
122
+ key: safeKey(entryKey),
123
+ value: present(entryValue, nested, entryKey)
124
+ }));
125
+ return {
126
+ entries,
127
+ kind: "record",
128
+ omittedEntries: Math.max(0, allEntries.length - entries.length)
129
+ };
130
+ } finally {
131
+ context.ancestors.delete(value);
132
+ }
133
+ }
134
+ function presentText(value, maxCharacters, key) {
135
+ if (INLINE_SECRET.test(value)) {
136
+ INLINE_SECRET.lastIndex = 0;
137
+ value = value.replace(INLINE_SECRET, (_match, bearerPrefix) => bearerPrefix ? `${bearerPrefix}<redacted>` : "<redacted>");
138
+ }
139
+ INLINE_SECRET.lastIndex = 0;
140
+ value = value.replace(NAMED_SECRET_ARGUMENT, "$1<redacted>").replace(SECRET_ENVIRONMENT_ASSIGNMENT, "$1<redacted>");
141
+ value = normalizeMachinePaths(value, key);
142
+ const preview = value.slice(0, maxCharacters);
143
+ return {
144
+ kind: "text",
145
+ omittedCharacters: Math.max(0, value.length - preview.length),
146
+ value: preview
147
+ };
148
+ }
149
+ function normalizeMachinePaths(value, key) {
150
+ if (key && WORKING_DIRECTORY_KEY.test(key)) return "<workspace>";
151
+ return value.replace(/\/(?:Users|home)\/[^/\s]+/g, "<home>").replace(/\/(?:private\/)?tmp\/[^\s'";]*/g, (path) => `<tmp>/${path.split("/").at(-1) || "item"}`);
152
+ }
153
+ function safeKey(value) {
154
+ return value.replace(/[^\p{L}\p{N}._:/-]+/gu, " ").trim().slice(0, 80) || "unknown";
155
+ }
156
+ //#endregion
157
+ //#region src/application/presentation/run-presentation-projector.ts
158
+ function createRunPresentationProjector() {
159
+ const runs = /* @__PURE__ */ new Map();
160
+ const stateFor = (runId) => {
161
+ const existing = runs.get(runId);
162
+ if (existing) return existing;
163
+ const created = {
164
+ answer: "",
165
+ answerStartedAt: void 0,
166
+ assistantSequence: 0,
167
+ currentSkillId: void 0,
168
+ order: [],
169
+ phase: "running",
170
+ revision: 0,
171
+ steps: /* @__PURE__ */ new Map()
172
+ };
173
+ runs.set(runId, created);
174
+ return created;
175
+ };
176
+ const snapshot = (runId) => {
177
+ const state = runs.get(runId);
178
+ if (!state) return void 0;
179
+ const visibleKeys = state.order.slice(-8);
180
+ return {
181
+ answer: {
182
+ format: "markdown",
183
+ text: state.answer
184
+ },
185
+ omittedStepCount: Math.max(0, state.order.length - visibleKeys.length),
186
+ phase: state.phase,
187
+ revision: state.revision,
188
+ runId,
189
+ schemaVersion: 2,
190
+ steps: visibleKeys.map((key) => state.steps.get(key)).filter((step) => step !== void 0),
191
+ totalStepCount: state.order.length,
192
+ totalToolCallCount: [...state.steps.values()].filter((step) => step.kind === "tool").length
193
+ };
194
+ };
195
+ const mutate = (runId, mutation) => {
196
+ const state = stateFor(runId);
197
+ mutation(state);
198
+ state.revision += 1;
199
+ return snapshot(runId);
200
+ };
201
+ const upsert = (state, step) => {
202
+ if (!state.steps.has(step.id)) state.order.push(step.id);
203
+ state.steps.set(step.id, step);
204
+ };
205
+ const commitAssistantNarration = (state, endedAt) => {
206
+ const text = state.answer.trim();
207
+ if (!text) return;
208
+ const id = `assistant:${state.assistantSequence + 1}`;
209
+ state.assistantSequence += 1;
210
+ const startedAt = state.answerStartedAt ?? endedAt.toISOString();
211
+ upsert(state, {
212
+ durationMs: elapsed(startedAt, endedAt),
213
+ endedAt: endedAt.toISOString(),
214
+ id,
215
+ kind: "assistant",
216
+ label: "过程说明",
217
+ startedAt,
218
+ status: "completed",
219
+ text
220
+ });
221
+ state.answer = "";
222
+ state.answerStartedAt = void 0;
223
+ };
224
+ return {
225
+ apply: (event, canonicalText) => {
226
+ switch (event.type) {
227
+ case "agent_run_accepted":
228
+ runs.set(event.runId, {
229
+ answer: "",
230
+ answerStartedAt: void 0,
231
+ assistantSequence: 0,
232
+ currentSkillId: void 0,
233
+ order: [],
234
+ phase: "running",
235
+ revision: 1,
236
+ steps: /* @__PURE__ */ new Map()
237
+ });
238
+ return snapshot(event.runId);
239
+ case "agent_turn_started": return mutate(event.runId, (state) => {
240
+ state.answer = "";
241
+ state.answerStartedAt = void 0;
242
+ state.currentSkillId = void 0;
243
+ });
244
+ case "agent_model_execution_started": return mutate(event.runId, (state) => {
245
+ state.answer = "";
246
+ state.answerStartedAt = void 0;
247
+ state.currentSkillId = void 0;
248
+ upsert(state, {
249
+ id: `model:${event.modelCallId}`,
250
+ kind: "model",
251
+ label: "分析问题",
252
+ model: safeIdentifier(event.model),
253
+ provider: safeIdentifier(event.provider),
254
+ startedAt: event.occurredAt.toISOString(),
255
+ status: "running"
256
+ });
257
+ });
258
+ case "agent_model_execution_ended": return mutate(event.runId, (state) => {
259
+ const id = `model:${event.modelCallId}`;
260
+ upsert(state, {
261
+ ...completedTiming(state, id, event.occurredAt),
262
+ id,
263
+ kind: "model",
264
+ label: "分析问题",
265
+ model: safeIdentifier(event.responseModel ?? event.model),
266
+ provider: safeIdentifier(event.provider),
267
+ status: event.errorMessage ? "failed" : "completed"
268
+ });
269
+ });
270
+ case "agent_skill_execution_started": return mutate(event.runId, (state) => {
271
+ commitAssistantNarration(state, event.occurredAt);
272
+ state.currentSkillId = safeIdentifier(event.skillId);
273
+ upsert(state, {
274
+ id: `skill:${event.skillCallId}`,
275
+ kind: "skill",
276
+ label: "读取技能",
277
+ skillId: safeIdentifier(event.skillId),
278
+ startedAt: event.occurredAt.toISOString(),
279
+ status: "running"
280
+ });
281
+ });
282
+ case "agent_skill_execution_ended": return mutate(event.runId, (state) => {
283
+ const id = `skill:${event.skillCallId}`;
284
+ upsert(state, {
285
+ ...completedTiming(state, id, event.occurredAt),
286
+ id,
287
+ kind: "skill",
288
+ label: "读取技能",
289
+ skillId: safeIdentifier(event.skillId),
290
+ status: event.isError ? "failed" : "completed"
291
+ });
292
+ });
293
+ case "agent_tool_execution_started": return mutate(event.runId, (state) => {
294
+ commitAssistantNarration(state, event.occurredAt);
295
+ upsert(state, runningToolStep(state, event));
296
+ });
297
+ case "agent_tool_execution_updated": return mutate(event.runId, (state) => {
298
+ upsert(state, runningToolStep(state, event));
299
+ });
300
+ case "agent_tool_execution_ended": return mutate(event.runId, (state) => {
301
+ const id = `tool:${event.toolCallId}`;
302
+ const existing = state.steps.get(id);
303
+ const startedAt = existing?.startedAt ?? event.occurredAt.toISOString();
304
+ const input = existing?.kind === "tool" ? existing.input : createPresentedValue(void 0);
305
+ upsert(state, {
306
+ durationMs: elapsed(startedAt, event.occurredAt),
307
+ endedAt: event.occurredAt.toISOString(),
308
+ ...event.isError ? { error: createPresentedValue(event.result) } : { output: createPresentedValue(event.result) },
309
+ id,
310
+ input,
311
+ kind: "tool",
312
+ label: "执行工具",
313
+ ...existing?.kind === "tool" && existing.skillId ? { skillId: existing.skillId } : {},
314
+ startedAt,
315
+ status: event.isError ? "failed" : "completed",
316
+ toolName: safeIdentifier(event.toolName)
317
+ });
318
+ });
319
+ case "assistant_text_delta": return mutate(event.runId, (state) => {
320
+ state.answerStartedAt ??= event.occurredAt.toISOString();
321
+ state.answer += event.delta;
322
+ });
323
+ case "assistant_thinking_delta":
324
+ case "agent_turn_completed": return snapshot(event.runId);
325
+ case "agent_run_completed": {
326
+ const result = finish(event.runId, "completed", "回答已完成", event.occurredAt, canonicalText, event.finalText, stateFor, mutate, upsert);
327
+ runs.delete(event.runId);
328
+ return result;
329
+ }
330
+ case "agent_run_failed": {
331
+ const result = finish(event.runId, "failed", "运行未完成", event.occurredAt, void 0, canonicalText, stateFor, mutate, upsert);
332
+ runs.delete(event.runId);
333
+ return result;
334
+ }
335
+ case "agent_run_cancelled": {
336
+ const result = finish(event.runId, "cancelled", "运行已取消", event.occurredAt, void 0, canonicalText, stateFor, mutate, upsert);
337
+ runs.delete(event.runId);
338
+ return result;
339
+ }
340
+ }
341
+ },
342
+ snapshot
343
+ };
344
+ }
345
+ function runningToolStep(state, event) {
346
+ const id = `tool:${event.toolCallId}`;
347
+ const existing = state.steps.get(id);
348
+ const skillId = existing?.kind === "tool" ? existing.skillId : state.currentSkillId;
349
+ const output = event.type === "agent_tool_execution_updated" ? createPresentedValue(event.partialResult) : existing?.kind === "tool" ? existing.output : void 0;
350
+ return {
351
+ id,
352
+ input: createPresentedValue(event.input),
353
+ kind: "tool",
354
+ label: "执行工具",
355
+ ...output === void 0 ? {} : { output },
356
+ ...skillId ? { skillId } : {},
357
+ startedAt: existing?.startedAt ?? event.occurredAt.toISOString(),
358
+ status: "running",
359
+ toolName: safeIdentifier(event.toolName)
360
+ };
361
+ }
362
+ function finish(runId, phase, label, occurredAt, preferredText, fallbackText, stateFor, mutate, upsert) {
363
+ stateFor(runId);
364
+ const startedAt = occurredAt.toISOString();
365
+ return mutate(runId, (state) => {
366
+ state.phase = phase;
367
+ state.answer = preferredText?.trim() || state.answer.trim() || fallbackText?.trim() || state.answer;
368
+ for (const step of state.steps.values()) if (step.status === "running") state.steps.set(step.id, finishRunningStep(step, occurredAt, phase === "completed" ? "completed" : "failed"));
369
+ upsert(state, {
370
+ endedAt: occurredAt.toISOString(),
371
+ id: `response:${phase}`,
372
+ kind: "response",
373
+ label,
374
+ startedAt,
375
+ status: phase === "completed" ? "completed" : "failed"
376
+ });
377
+ });
378
+ }
379
+ function finishRunningStep(step, occurredAt, status) {
380
+ return {
381
+ ...step,
382
+ durationMs: elapsed(step.startedAt, occurredAt),
383
+ endedAt: occurredAt.toISOString(),
384
+ status
385
+ };
386
+ }
387
+ function completedTiming(state, id, occurredAt) {
388
+ const startedAt = state.steps.get(id)?.startedAt ?? occurredAt.toISOString();
389
+ return {
390
+ durationMs: elapsed(startedAt, occurredAt),
391
+ endedAt: occurredAt.toISOString(),
392
+ startedAt
393
+ };
394
+ }
395
+ function elapsed(startedAt, endedAt) {
396
+ return Math.max(0, endedAt.getTime() - Date.parse(startedAt));
397
+ }
398
+ function safeIdentifier(value) {
399
+ return value.replace(/[^\p{L}\p{N}._:/-]+/gu, " ").trim().slice(0, 80) || "unknown";
400
+ }
401
+ //#endregion
31
402
  //#region src/application/feishu/feishu-stream-projector.ts
32
403
  function createFeishuStreamProjector() {
33
- const currentTextByRun = /* @__PURE__ */ new Map();
34
- const lastTextByRun = /* @__PURE__ */ new Map();
35
- const update = (runId, text) => [{
36
- runId,
37
- text,
38
- type: "update_text"
39
- }];
40
- const clear = (runId) => {
41
- currentTextByRun.delete(runId);
42
- lastTextByRun.delete(runId);
43
- };
404
+ const presentations = createRunPresentationProjector();
44
405
  const applyEvent = (event, canonicalText) => {
406
+ const presentation = presentations.apply(event, canonicalText);
45
407
  switch (event.type) {
46
408
  case "agent_run_accepted":
47
- currentTextByRun.set(event.runId, "");
48
- lastTextByRun.set(event.runId, "");
49
- return [];
50
409
  case "agent_turn_started":
51
- currentTextByRun.set(event.runId, "");
52
- lastTextByRun.set(event.runId, "");
53
- return [];
410
+ case "assistant_thinking_delta":
411
+ case "agent_turn_completed": return [];
54
412
  case "agent_model_execution_started":
55
- currentTextByRun.set(event.runId, "");
56
- return update(event.runId, "正在分析…");
57
- case "agent_skill_execution_started": return update(event.runId, `正在读取技能 \`${presentProgressIdentifier(event.skillId)}\`…`);
58
- case "agent_tool_execution_started": return update(event.runId, `正在执行工具 \`${presentProgressIdentifier(event.toolName)}\`…`);
59
- case "agent_tool_execution_ended": return update(event.runId, event.isError ? "工具执行失败,正在调整方案…" : "已取得工具结果,正在继续分析…");
60
- case "assistant_text_delta": {
61
- const text = `${currentTextByRun.get(event.runId) ?? ""}${event.delta}`;
62
- currentTextByRun.set(event.runId, text);
63
- if (text.trim()) lastTextByRun.set(event.runId, text);
64
- return update(event.runId, text);
65
- }
66
- case "agent_run_completed": {
67
- const currentText = currentTextByRun.get(event.runId)?.trim();
68
- const lastText = lastTextByRun.get(event.runId)?.trim();
69
- const text = currentText || lastText || canonicalText || event.finalText;
70
- clear(event.runId);
71
- return [{
72
- runId: event.runId,
73
- text,
74
- type: "finish"
75
- }];
76
- }
77
- case "agent_run_failed":
78
- clear(event.runId);
79
- return [{
80
- errorMessage: event.errorMessage,
81
- runId: event.runId,
82
- type: "fail"
83
- }];
84
- case "agent_run_cancelled":
85
- clear(event.runId);
86
- return [{
87
- ...event.reason ? { reason: event.reason } : {},
88
- runId: event.runId,
89
- type: "cancel"
90
- }];
91
- default: return [];
413
+ case "agent_model_execution_ended":
414
+ case "agent_skill_execution_started":
415
+ case "agent_skill_execution_ended":
416
+ case "agent_tool_execution_started":
417
+ case "agent_tool_execution_updated":
418
+ case "agent_tool_execution_ended": return presentation ? [{
419
+ presentation,
420
+ runId: event.runId,
421
+ type: "update_progress"
422
+ }] : [];
423
+ case "assistant_text_delta": return [{
424
+ runId: event.runId,
425
+ text: presentation?.answer.text ?? event.delta,
426
+ type: "update_text"
427
+ }];
428
+ case "agent_run_completed": return [{
429
+ ...hasMeaningfulProgress(presentation) ? { presentation } : {},
430
+ runId: event.runId,
431
+ text: presentation?.answer.text.trim() || canonicalText?.trim() || event.finalText,
432
+ type: "finish"
433
+ }];
434
+ case "agent_run_failed": return [{
435
+ errorMessage: event.errorMessage,
436
+ ...hasMeaningfulProgress(presentation) ? { presentation } : {},
437
+ runId: event.runId,
438
+ type: "fail"
439
+ }];
440
+ case "agent_run_cancelled": return [{
441
+ ...hasMeaningfulProgress(presentation) ? { presentation } : {},
442
+ ...event.reason ? { reason: event.reason } : {},
443
+ runId: event.runId,
444
+ type: "cancel"
445
+ }];
92
446
  }
93
447
  };
94
448
  return {
@@ -102,8 +456,8 @@ function createFeishuStreamProjector() {
102
456
  } : event, state.finalText) : applyEvent(event, state.finalText)
103
457
  };
104
458
  }
105
- function presentProgressIdentifier(value) {
106
- return value.replace(/[^\p{L}\p{N}._:/-]+/gu, " ").trim().slice(0, 80) || "unknown";
459
+ function hasMeaningfulProgress(presentation) {
460
+ return presentation !== void 0 && hasInspectableRunProgress(presentation);
107
461
  }
108
462
  //#endregion
109
463
  //#region src/application/feishu/feishu-card-delivery-ledger.ts
@@ -146,7 +500,7 @@ function createFeishuCardDeliveryReconciler(options) {
146
500
  return { reconcile: () => Effect.gen(function* () {
147
501
  const projector = createFeishuStreamProjector();
148
502
  const terminalByRun = /* @__PURE__ */ new Map();
149
- for (const event of options.events) for (const action of projector.apply(event)) if (action.type !== "update_text" && action.type !== "handoff") terminalByRun.set(action.runId, action);
503
+ for (const event of options.events) for (const action of projector.apply(event)) if (action.type === "cancel" || action.type === "fail" || action.type === "finish") terminalByRun.set(action.runId, action);
150
504
  let repaired = 0;
151
505
  let skipped = 0;
152
506
  for (const [runId, action] of terminalByRun) {
@@ -884,7 +1238,10 @@ function evolveAgentRun(state, event) {
884
1238
  ...state,
885
1239
  thinkingText: `${state.thinkingText ?? ""}${event.delta}`
886
1240
  };
887
- case "agent_model_execution_started":
1241
+ case "agent_model_execution_started": return {
1242
+ ...state,
1243
+ finalText: ""
1244
+ };
888
1245
  case "agent_model_execution_ended": return state;
889
1246
  case "agent_skill_execution_started": return {
890
1247
  ...state,
@@ -2519,9 +2876,16 @@ function createFeishuAgentDaemon(options) {
2519
2876
  messageId: inbound.messageId,
2520
2877
  runId: result.runId
2521
2878
  };
2522
- }).pipe(Effect.catchAll((error) => Effect.sync(() => {
2523
- if (dedupeMessageId !== void 0) seenMessageIds.delete(dedupeMessageId);
2524
- }).pipe(Effect.flatMap(() => Effect.fail(error)))));
2879
+ }).pipe(Effect.catchAll((error) => {
2880
+ if (error instanceof AgentRunCancelled) return Effect.succeed({
2881
+ cancelled: true,
2882
+ messageId: dedupeMessageId ?? payload.event.message.message_id,
2883
+ runId: error.runId
2884
+ });
2885
+ return Effect.sync(() => {
2886
+ if (dedupeMessageId !== void 0) seenMessageIds.delete(dedupeMessageId);
2887
+ }).pipe(Effect.flatMap(() => Effect.fail(error)));
2888
+ }));
2525
2889
  }
2526
2890
  };
2527
2891
  }
@@ -3328,43 +3692,225 @@ function createFeishuCardRolloverSupervisor(options) {
3328
3692
  };
3329
3693
  }
3330
3694
  //#endregion
3695
+ //#region src/infrastructure/feishu/feishu-run-presentation-renderer.ts
3696
+ function renderFeishuRunProgress(presentation) {
3697
+ const visible = presentation.steps.filter(isVisibleStep);
3698
+ const running = [...visible].reverse().find((step) => step.status === "running");
3699
+ const title = visible.length === 0 ? "执行过程 · 展开查看" : presentation.phase === "running" && running ? `执行过程 · ${runningLabel(running)}` : `执行过程 · ${visible.length} 段 · ${presentation.totalToolCallCount} 次工具调用`;
3700
+ return {
3701
+ markdown: [...presentation.omittedStepCount > 0 ? [`> 另有 ${presentation.omittedStepCount} 个较早步骤未展示`] : [], ...renderProgressSteps(visible)].join("\n\n") || "正在准备执行…",
3702
+ title
3703
+ };
3704
+ }
3705
+ function renderFeishuRunTimeline(presentation, options) {
3706
+ const visible = presentation.steps.filter(isVisibleStep);
3707
+ const elements = [];
3708
+ for (let index = 0; index < visible.length;) {
3709
+ const step = visible[index];
3710
+ if (step.kind !== "tool") {
3711
+ elements.push(...renderTimelineStep(step, options.expanded));
3712
+ index += 1;
3713
+ continue;
3714
+ }
3715
+ const tools = [];
3716
+ while (index < visible.length && visible[index]?.kind === "tool") {
3717
+ tools.push(visible[index]);
3718
+ index += 1;
3719
+ }
3720
+ elements.push(renderToolSequence(tools, options.expanded));
3721
+ }
3722
+ return {
3723
+ elements,
3724
+ inspectable: visible.some((step) => step.kind === "skill" || step.kind === "tool")
3725
+ };
3726
+ }
3727
+ function renderFeishuVisibleAnswer(presentation, currentText) {
3728
+ const committed = presentation?.steps.filter((step) => step.kind === "assistant").map((step) => step.text.trim()).filter(Boolean) ?? [];
3729
+ const current = currentText.trim();
3730
+ return [...committed, ...current ? [current] : []].join("\n\n");
3731
+ }
3732
+ function renderProgressSteps(steps) {
3733
+ const rendered = [];
3734
+ for (let index = 0; index < steps.length;) {
3735
+ const step = steps[index];
3736
+ if (step.kind !== "tool") {
3737
+ rendered.push(renderStep(step));
3738
+ index += 1;
3739
+ continue;
3740
+ }
3741
+ const tools = [];
3742
+ while (index < steps.length && steps[index]?.kind === "tool") {
3743
+ tools.push(steps[index]);
3744
+ index += 1;
3745
+ }
3746
+ rendered.push(tools.map(renderToolSummary).join("\n"));
3747
+ }
3748
+ return rendered;
3749
+ }
3750
+ function renderToolSequence(tools, expanded) {
3751
+ if (tools.length === 1) return {
3752
+ content: renderToolSummary(tools[0]),
3753
+ tag: "markdown"
3754
+ };
3755
+ return collapsiblePanel({
3756
+ content: tools.map(renderToolSummary).join("\n"),
3757
+ expanded: expanded || tools.some((tool) => tool.status === "running"),
3758
+ title: toolSequenceTitle(tools)
3759
+ });
3760
+ }
3761
+ function toolSequenceTitle(tools) {
3762
+ if ([...tools].reverse().find((tool) => tool.status === "running")) return `执行过程 · ${tools.length} 个工具 · 进行中`;
3763
+ if (tools.some((tool) => tool.status === "failed")) return `执行过程 · ${tools.length} 个工具 · 有失败`;
3764
+ const totalDuration = tools.reduce((total, tool) => total + (tool.durationMs ?? 0), 0);
3765
+ return totalDuration > 0 ? `执行过程 · ${tools.length} 个工具 · 已完成 · ${formatDuration$1(totalDuration)}` : `执行过程 · ${tools.length} 个工具 · 已完成`;
3766
+ }
3767
+ function renderToolSummary(step) {
3768
+ const skill = step.skillId ? ` · ${escapeInline(step.skillId)}` : "";
3769
+ const duration = step.durationMs === void 0 ? "" : ` · ${formatDuration$1(step.durationMs)}`;
3770
+ return `- ${statusIcon(step.status)} **${escapeInline(toolAction(step.toolName))}**${skill}${duration}`;
3771
+ }
3772
+ function renderTimelineStep(step, expandCompleted) {
3773
+ switch (step.kind) {
3774
+ case "assistant": return [{
3775
+ content: step.text,
3776
+ margin: "0px",
3777
+ tag: "markdown",
3778
+ text_align: "left",
3779
+ text_size: "normal"
3780
+ }];
3781
+ case "skill": return [collapsiblePanel({
3782
+ content: skillDetails(step),
3783
+ expanded: step.status === "running" || expandCompleted,
3784
+ title: `${step.skillId} · ${step.status === "running" ? "读取中" : step.status === "failed" ? "读取失败" : "已读取"}`
3785
+ })];
3786
+ case "tool": return [{
3787
+ content: renderToolSummary(step),
3788
+ tag: "markdown"
3789
+ }];
3790
+ case "model":
3791
+ case "response": return [];
3792
+ }
3793
+ }
3794
+ function collapsiblePanel(options) {
3795
+ return {
3796
+ background_color: options.expanded ? "blue-50" : "grey-50",
3797
+ elements: [{
3798
+ content: options.content,
3799
+ tag: "markdown",
3800
+ text_align: "left",
3801
+ text_size: "normal"
3802
+ }],
3803
+ expanded: options.expanded,
3804
+ header: {
3805
+ expanded_title: {
3806
+ content: options.title,
3807
+ tag: "plain_text",
3808
+ text_align: "left"
3809
+ },
3810
+ icon: {
3811
+ color: "grey",
3812
+ tag: "standard_icon",
3813
+ token: "down-small-ccm_outlined"
3814
+ },
3815
+ icon_expanded_angle: -180,
3816
+ icon_position: "right",
3817
+ padding: "8px 12px 8px 12px",
3818
+ title: {
3819
+ content: options.title,
3820
+ tag: "plain_text",
3821
+ text_align: "left"
3822
+ },
3823
+ width: "fill"
3824
+ },
3825
+ margin: "8px 0px 0px 0px",
3826
+ padding: "12px 12px 12px 12px",
3827
+ tag: "collapsible_panel"
3828
+ };
3829
+ }
3830
+ function skillDetails(step) {
3831
+ const duration = step.durationMs === void 0 ? "" : ` · ${formatDuration$1(step.durationMs)}`;
3832
+ return [`**${statusLabel(step.status)}**${duration}`, `这一步:读取并应用技能 \`${escapeInline(step.skillId)}\` 的任务说明。`].join("\n\n");
3833
+ }
3834
+ function statusLabel(status) {
3835
+ switch (status) {
3836
+ case "completed": return "已完成";
3837
+ case "failed": return "未完成";
3838
+ case "running": return "进行中";
3839
+ }
3840
+ }
3841
+ function toolAction(toolName) {
3842
+ const normalized = toolName.toLowerCase();
3843
+ const executable = normalized.split(/[\\/]/u).at(-1) ?? normalized;
3844
+ if (executable === "bash" || executable === "exec" || executable === "exec_command") return "执行命令";
3845
+ if (normalized.includes("read") && normalized.includes("file")) return "读取文件";
3846
+ if (normalized.includes("write") && normalized.includes("file")) return "写入文件";
3847
+ if (normalized.includes("search") || normalized === "rg") return "搜索内容";
3848
+ if (normalized.includes("fetch") || normalized.includes("http")) return "访问服务";
3849
+ return `调用 ${toolName.replace(/^.*[\\/]/u, "")}`;
3850
+ }
3851
+ function renderStep(step) {
3852
+ const duration = step.durationMs === void 0 ? "" : ` · ${formatDuration$1(step.durationMs)}`;
3853
+ switch (step.kind) {
3854
+ case "assistant": return step.text;
3855
+ case "model": return `- ${statusIcon(step.status)} ${step.label}${duration}`;
3856
+ case "skill": return `- ${statusIcon(step.status)} ${step.label} \`${escapeInline(step.skillId)}\`${duration}`;
3857
+ case "response": return `- ${statusIcon(step.status)} ${step.label}${duration}`;
3858
+ case "tool": return renderToolSummary(step);
3859
+ }
3860
+ }
3861
+ function isVisibleStep(step) {
3862
+ return step.kind === "assistant" || step.kind === "skill" || step.kind === "tool";
3863
+ }
3864
+ function runningLabel(step) {
3865
+ switch (step.kind) {
3866
+ case "assistant": return "正在说明进展";
3867
+ case "model": return "正在分析";
3868
+ case "skill": return "正在读取技能";
3869
+ case "tool": return `正在调用 ${step.toolName}`;
3870
+ case "response": return "正在整理回答";
3871
+ }
3872
+ }
3873
+ function statusIcon(status) {
3874
+ switch (status) {
3875
+ case "completed": return "✅";
3876
+ case "failed": return "⚠️";
3877
+ case "running": return "⏳";
3878
+ }
3879
+ }
3880
+ function formatDuration$1(milliseconds) {
3881
+ if (milliseconds < 1e3) return `${milliseconds} 毫秒`;
3882
+ if (milliseconds < 6e4) {
3883
+ const seconds = milliseconds / 1e3;
3884
+ return `${Number(seconds.toFixed(seconds < 10 ? 1 : 0))} 秒`;
3885
+ }
3886
+ return `${Math.floor(milliseconds / 6e4)} 分 ${Math.floor(milliseconds % 6e4 / 1e3)} 秒`;
3887
+ }
3888
+ function escapeInline(value) {
3889
+ return value.replace(/`/g, "ˋ");
3890
+ }
3891
+ //#endregion
3331
3892
  //#region src/infrastructure/feishu/feishu-agent-run-card.ts
3332
3893
  const FEISHU_AGENT_CARD_ELEMENT_ID = "rivus_agent_answer";
3894
+ const FEISHU_AGENT_CARD_PROGRESS_ELEMENT_ID = "rivus_agent_progress";
3333
3895
  function createFeishuAgentRunCard(input) {
3334
3896
  const presentation = resolveRunPresentation(input);
3335
3897
  return {
3336
- body: { elements: [
3337
- {
3338
- content: presentation.content,
3339
- element_id: input.status === "running" ? input.elementId ?? "rivus_agent_answer" : FEISHU_AGENT_CARD_ELEMENT_ID,
3340
- tag: "markdown"
3341
- },
3342
- {
3343
- content: `_${presentation.note}_`,
3344
- tag: "markdown"
3345
- },
3346
- ...input.status === "running" && input.cancelButton !== false ? [{
3347
- behaviors: [{
3348
- type: "callback",
3349
- value: {
3350
- rivus_action: "cancel_run",
3351
- run_id: input.runId,
3352
- session_key: input.sessionKey
3353
- }
3354
- }],
3355
- tag: "button",
3356
- text: {
3357
- content: "停止生成",
3358
- tag: "plain_text"
3359
- },
3360
- type: "danger"
3361
- }] : []
3362
- ] },
3898
+ body: {
3899
+ direction: "vertical",
3900
+ elements: [
3901
+ ...createRunElements("progressDisplay" in input ? input.progressDisplay : void 0, "presentation" in input ? input.presentation : void 0, presentation.content, input),
3902
+ { tag: "hr" },
3903
+ createRunFooter(input, presentation.note)
3904
+ ],
3905
+ padding: "18px 18px 16px 18px",
3906
+ vertical_spacing: "small"
3907
+ },
3363
3908
  config: {
3364
3909
  streaming_mode: input.status === "running",
3365
3910
  update_multi: true
3366
3911
  },
3367
3912
  header: {
3913
+ padding: "12px 18px 12px 18px",
3368
3914
  template: presentation.template,
3369
3915
  title: {
3370
3916
  content: `${input.agentName} · ${presentation.title}`,
@@ -3374,19 +3920,68 @@ function createFeishuAgentRunCard(input) {
3374
3920
  schema: "2.0"
3375
3921
  };
3376
3922
  }
3923
+ function createRunFooter(input, note) {
3924
+ const footerText = footerTextElement(note);
3925
+ if (input.status !== "running") return footerRow([footerText, footerTextElement("_Rivus_")]);
3926
+ if (input.cancelButton === false) return footerText;
3927
+ return footerRow([footerText, {
3928
+ behaviors: [{
3929
+ type: "callback",
3930
+ value: {
3931
+ rivus_action: "cancel_run",
3932
+ run_id: input.runId,
3933
+ session_key: input.sessionKey
3934
+ }
3935
+ }],
3936
+ tag: "button",
3937
+ text: {
3938
+ content: "停止",
3939
+ tag: "plain_text"
3940
+ },
3941
+ type: "danger"
3942
+ }]);
3943
+ }
3944
+ function footerRow(elements) {
3945
+ return {
3946
+ columns: [{
3947
+ elements: [elements[0]],
3948
+ tag: "column",
3949
+ vertical_align: "center",
3950
+ weight: 1,
3951
+ width: "weighted"
3952
+ }, ...elements.length > 1 ? [{
3953
+ elements: [elements[1]],
3954
+ horizontal_align: "right",
3955
+ tag: "column",
3956
+ vertical_align: "center",
3957
+ width: "auto"
3958
+ }] : []],
3959
+ flex_mode: "none",
3960
+ horizontal_align: "left",
3961
+ horizontal_spacing: "small",
3962
+ margin: "12px 0px 0px 0px",
3963
+ tag: "column_set"
3964
+ };
3965
+ }
3966
+ function footerTextElement(content) {
3967
+ return {
3968
+ tag: "div",
3969
+ text: {
3970
+ content,
3971
+ tag: "lark_md",
3972
+ text_align: "left",
3973
+ text_color: "grey",
3974
+ text_size: "notation"
3975
+ }
3976
+ };
3977
+ }
3377
3978
  function resolveRunPresentation(input) {
3378
3979
  switch (input.status) {
3379
3980
  case "running": return {
3380
- content: input.text || "正在思考…",
3381
- note: input.cancelButton === false ? `回答将实时更新;如需停止,请发送 \`/cancel ${input.runId}\`` : input.generation ? "接续上一条消息,回答将实时更新" : "回答将实时更新",
3382
- template: "blue",
3383
- title: input.generation ? "正在处理(续)" : "正在处理"
3384
- };
3385
- case "handoff": return {
3386
- content: "这是同一任务的续卡。任务仍在后台处理,进度将继续显示在下一条消息。",
3387
- note: "本卡片已停止更新;请查看下一条消息,不会创建第二个任务",
3981
+ content: input.text || "正在生成回答…",
3982
+ note: input.cancelButton === false ? `${progressNote(input.progressDisplay, input.presentation)}如需停止,请发送 \`/cancel ${input.runId}\`` : progressNote(input.progressDisplay, input.presentation),
3388
3983
  template: "blue",
3389
- title: "同一任务已续卡"
3984
+ title: "正在处理"
3390
3985
  };
3391
3986
  case "completed": return {
3392
3987
  content: input.text || "已完成。",
@@ -3403,6 +3998,29 @@ function resolveRunPresentation(input) {
3403
3998
  case "cancelled": return resolveCancellationPresentation(input.reason, input.text);
3404
3999
  }
3405
4000
  }
4001
+ function createRunElements(display, presentation, currentText, input) {
4002
+ const mode = display ?? "collapsed";
4003
+ const inspectable = presentation !== void 0 && hasInspectableRunProgress(presentation);
4004
+ const elementId = input.status === "running" ? input.elementId ?? "rivus_agent_answer" : void 0;
4005
+ if (mode === "hidden" || !inspectable) return [answerElement(renderFeishuVisibleAnswer(presentation, currentText) || currentText, elementId)];
4006
+ const timeline = renderFeishuRunTimeline(presentation, { expanded: mode === "expanded" });
4007
+ const current = currentText.trim();
4008
+ return [...timeline.elements, ...current || timeline.elements.length === 0 ? [answerElement(current || "正在生成回答…", elementId)] : elementId ? [answerElement("", elementId)] : []];
4009
+ }
4010
+ function answerElement(content, elementId) {
4011
+ return {
4012
+ content,
4013
+ ...elementId ? { element_id: elementId } : {},
4014
+ tag: "markdown"
4015
+ };
4016
+ }
4017
+ function progressNote(display, presentation) {
4018
+ return (display ?? "collapsed") === "hidden" || !presentation || !hasInspectableRunProgress(presentation) || !hasExpandableToolSequence(presentation) ? "内容实时更新;" : "内容实时更新;连续工具可展开;";
4019
+ }
4020
+ function hasExpandableToolSequence(presentation) {
4021
+ const visible = presentation.steps.filter((step) => step.kind === "assistant" || step.kind === "skill" || step.kind === "tool");
4022
+ return visible.some((step, index) => step.kind === "tool" && visible[index + 1]?.kind === "tool");
4023
+ }
3406
4024
  function resolveCancellationPresentation(reason, text) {
3407
4025
  const timeoutMs = readRunTimeoutMs(reason);
3408
4026
  if (timeoutMs !== void 0) return {
@@ -3513,59 +4131,83 @@ function createFeishuCardKitOpenApiClient(options) {
3513
4131
  const agentName = options.agentName ?? "Rivus Agent";
3514
4132
  const streamingClosedCards = /* @__PURE__ */ new Set();
3515
4133
  const call = (request) => options.client.request(request).pipe(Effect.asVoid);
3516
- const updateTerminal = (request, status) => updateWholeCard(baseUrl, agentName, request, status, call).pipe(Effect.tap(() => Effect.sync(() => streamingClosedCards.delete(request.cardId))));
4134
+ const updateTerminal = (request, status) => updateWholeCard(baseUrl, agentName, request, status, call, options.progressDisplay).pipe(Effect.tap(() => Effect.sync(() => streamingClosedCards.delete(request.cardId))));
4135
+ const publishStreamingUpdate = (cardId, update) => {
4136
+ if (streamingClosedCards.has(cardId)) return Effect.void;
4137
+ return update.pipe(Effect.catchAll((error) => {
4138
+ if (!isStreamingClosed(error)) return Effect.fail(error);
4139
+ return Effect.sync(() => {
4140
+ streamingClosedCards.add(cardId);
4141
+ options.onStreamingClosed?.(cardId);
4142
+ });
4143
+ }));
4144
+ };
3517
4145
  return {
3518
4146
  cancel: (request) => updateTerminal(request, "cancelled"),
3519
4147
  fail: (request) => updateTerminal(request, "failed"),
3520
4148
  finish: (request) => updateTerminal(request, "completed"),
3521
- handoff: (request) => Effect.sync(() => streamingClosedCards.add(request.cardId)).pipe(Effect.flatMap(() => updateWholeCard(baseUrl, agentName, request, "handoff", call))),
3522
- updateText: (request) => {
3523
- if (streamingClosedCards.has(request.cardId)) return Effect.void;
3524
- return call({
3525
- body: {
3526
- content: request.content,
3527
- sequence: request.sequence
3528
- },
3529
- method: "PUT",
3530
- url: `${baseUrl}/open-apis/cardkit/v1/cards/${encodeURIComponent(request.cardId)}/elements/${encodeURIComponent(request.elementId)}/content`
3531
- }).pipe(Effect.catchAll((error) => {
3532
- if (!isStreamingClosed(error)) return Effect.fail(error);
3533
- return Effect.sync(() => {
3534
- streamingClosedCards.add(request.cardId);
3535
- options.onStreamingClosed?.(request.cardId);
3536
- });
3537
- }));
3538
- }
4149
+ updatePresentation: (request) => publishStreamingUpdate(request.cardId, updateRunningCard(baseUrl, agentName, request, call, options.progressDisplay, options.cancelButton)),
4150
+ updateText: (request) => publishStreamingUpdate(request.cardId, call({
4151
+ body: {
4152
+ content: request.content,
4153
+ sequence: request.sequence
4154
+ },
4155
+ method: "PUT",
4156
+ url: `${baseUrl}/open-apis/cardkit/v1/cards/${encodeURIComponent(request.cardId)}/elements/${encodeURIComponent(request.elementId)}/content`
4157
+ }))
3539
4158
  };
3540
4159
  }
4160
+ function updateRunningCard(baseUrl, agentName, request, call, progressDisplay, cancelButton) {
4161
+ const card = createFeishuAgentRunCard({
4162
+ agentName,
4163
+ ...cancelButton === void 0 ? {} : { cancelButton },
4164
+ ...request.presentation === void 0 ? {} : { presentation: request.presentation },
4165
+ ...progressDisplay === void 0 ? {} : { progressDisplay },
4166
+ runId: request.runId,
4167
+ sessionKey: request.sessionKey,
4168
+ status: "running",
4169
+ ...request.text === void 0 ? {} : { text: request.text }
4170
+ });
4171
+ return replaceCard(baseUrl, request.cardId, request.sequence, card, call);
4172
+ }
3541
4173
  function isStreamingClosed(error) {
3542
4174
  return error instanceof FeishuOpenApiError && (error.code === 200850 || error.code === 300309);
3543
4175
  }
3544
- function updateWholeCard(baseUrl, agentName, request, status, call) {
4176
+ function updateWholeCard(baseUrl, agentName, request, status, call, progressDisplay) {
3545
4177
  const requestText = "text" in request ? request.text : void 0;
4178
+ const requestPresentation = "presentation" in request ? request.presentation : void 0;
3546
4179
  const card = status === "completed" ? createFeishuAgentRunCard({
3547
4180
  agentName,
4181
+ ...requestPresentation === void 0 ? {} : { presentation: requestPresentation },
4182
+ ...progressDisplay === void 0 ? {} : { progressDisplay },
3548
4183
  status,
3549
4184
  text: requestText ?? ""
3550
4185
  }) : status === "cancelled" ? createFeishuAgentRunCard({
3551
4186
  agentName,
4187
+ ...requestPresentation === void 0 ? {} : { presentation: requestPresentation },
4188
+ ...progressDisplay === void 0 ? {} : { progressDisplay },
3552
4189
  ..."reason" in request && request.reason ? { reason: request.reason } : {},
3553
4190
  status,
3554
4191
  ...requestText === void 0 ? {} : { text: requestText }
3555
4192
  }) : createFeishuAgentRunCard({
3556
4193
  agentName,
4194
+ ...requestPresentation === void 0 ? {} : { presentation: requestPresentation },
4195
+ ...progressDisplay === void 0 ? {} : { progressDisplay },
3557
4196
  status
3558
4197
  });
4198
+ return replaceCard(baseUrl, request.cardId, request.sequence, card, call);
4199
+ }
4200
+ function replaceCard(baseUrl, cardId, sequence, card, call) {
3559
4201
  return call({
3560
4202
  body: {
3561
4203
  card: {
3562
4204
  data: JSON.stringify(card),
3563
4205
  type: "card_json"
3564
4206
  },
3565
- sequence: request.sequence
4207
+ sequence
3566
4208
  },
3567
4209
  method: "PUT",
3568
- url: `${baseUrl}/open-apis/cardkit/v1/cards/${encodeURIComponent(request.cardId)}`
4210
+ url: `${baseUrl}/open-apis/cardkit/v1/cards/${encodeURIComponent(cardId)}`
3569
4211
  });
3570
4212
  }
3571
4213
  //#endregion
@@ -3574,6 +4216,7 @@ function createFeishuCardKitPublisher(options) {
3574
4216
  const ledger = options.ledger ?? createFeishuCardDeliveryLedger();
3575
4217
  return { publish: (action) => Effect.gen(function* () {
3576
4218
  const target = yield* options.resolveTarget(action.runId);
4219
+ if (action.type === "update_progress" && !target.progressElementId) return;
3577
4220
  const sequence = yield* ledger.reserveSequence(action.runId);
3578
4221
  switch (action.type) {
3579
4222
  case "update_text": return yield* options.client.updateText({
@@ -3582,14 +4225,24 @@ function createFeishuCardKitPublisher(options) {
3582
4225
  elementId: target.elementId,
3583
4226
  sequence
3584
4227
  });
3585
- case "handoff": return yield* options.client.handoff({
4228
+ case "update_progress": return yield* options.client.updateText({
4229
+ cardId: target.cardId,
4230
+ content: renderFeishuRunProgress(action.presentation).markdown,
4231
+ elementId: target.progressElementId,
4232
+ sequence
4233
+ });
4234
+ case "update_presentation": return yield* options.client.updatePresentation({
3586
4235
  cardId: target.cardId,
4236
+ ...action.presentation === void 0 ? {} : { presentation: action.presentation },
4237
+ runId: action.runId,
3587
4238
  sequence,
4239
+ sessionKey: action.sessionKey,
3588
4240
  ...action.text === void 0 ? {} : { text: action.text }
3589
4241
  });
3590
4242
  case "finish":
3591
4243
  yield* options.client.finish({
3592
4244
  cardId: target.cardId,
4245
+ ...action.presentation === void 0 ? {} : { presentation: action.presentation },
3593
4246
  sequence,
3594
4247
  text: action.text
3595
4248
  });
@@ -3598,12 +4251,14 @@ function createFeishuCardKitPublisher(options) {
3598
4251
  yield* options.client.fail({
3599
4252
  cardId: target.cardId,
3600
4253
  errorMessage: action.errorMessage,
4254
+ ...action.presentation === void 0 ? {} : { presentation: action.presentation },
3601
4255
  sequence
3602
4256
  });
3603
4257
  return yield* ledger.markTerminal(action.runId);
3604
4258
  case "cancel":
3605
4259
  yield* options.client.cancel({
3606
4260
  cardId: target.cardId,
4261
+ ...action.presentation === void 0 ? {} : { presentation: action.presentation },
3607
4262
  ...action.reason ? { reason: action.reason } : {},
3608
4263
  sequence,
3609
4264
  ...action.text === void 0 ? {} : { text: action.text }
@@ -3616,7 +4271,9 @@ function createFeishuCardKitPublisher(options) {
3616
4271
  //#region src/infrastructure/feishu/feishu-coalescing-publisher.ts
3617
4272
  function createCoalescingFeishuPublisher(options) {
3618
4273
  const pendingTextByRun = /* @__PURE__ */ new Map();
3619
- const flushOne = (runId, text) => Effect.gen(function* () {
4274
+ const pendingProgressByRun = /* @__PURE__ */ new Map();
4275
+ const pendingPresentationByRun = /* @__PURE__ */ new Map();
4276
+ const flushText = (runId, text) => Effect.gen(function* () {
3620
4277
  pendingTextByRun.delete(runId);
3621
4278
  yield* options.publisher.publish({
3622
4279
  runId,
@@ -3624,28 +4281,58 @@ function createCoalescingFeishuPublisher(options) {
3624
4281
  type: "update_text"
3625
4282
  });
3626
4283
  });
4284
+ const flushProgress = (runId, presentation) => Effect.gen(function* () {
4285
+ pendingProgressByRun.delete(runId);
4286
+ yield* options.publisher.publish({
4287
+ presentation,
4288
+ runId,
4289
+ type: "update_progress"
4290
+ });
4291
+ });
3627
4292
  const flushRun = (runId) => {
3628
4293
  const text = pendingTextByRun.get(runId);
3629
- return text === void 0 ? Effect.void : flushOne(runId, text);
4294
+ const progress = pendingProgressByRun.get(runId);
4295
+ const presentation = pendingPresentationByRun.get(runId);
4296
+ return Effect.gen(function* () {
4297
+ if (presentation !== void 0) {
4298
+ pendingPresentationByRun.delete(runId);
4299
+ yield* options.publisher.publish(presentation);
4300
+ pendingProgressByRun.delete(runId);
4301
+ pendingTextByRun.delete(runId);
4302
+ return;
4303
+ }
4304
+ if (progress !== void 0) yield* flushProgress(runId, progress);
4305
+ if (text !== void 0) yield* flushText(runId, text);
4306
+ });
3630
4307
  };
3631
4308
  return {
3632
4309
  flush: (runId) => runId === void 0 ? Effect.gen(function* () {
3633
- for (const [pendingRunId, text] of Array.from(pendingTextByRun)) yield* flushOne(pendingRunId, text);
4310
+ const runIds = /* @__PURE__ */ new Set([
4311
+ ...pendingPresentationByRun.keys(),
4312
+ ...pendingProgressByRun.keys(),
4313
+ ...pendingTextByRun.keys()
4314
+ ]);
4315
+ for (const pendingRunId of runIds) yield* flushRun(pendingRunId);
3634
4316
  }) : flushRun(runId),
3635
4317
  publish: (action) => {
3636
4318
  switch (action.type) {
3637
4319
  case "update_text": return Effect.sync(() => {
3638
4320
  pendingTextByRun.set(action.runId, action.text);
3639
4321
  });
3640
- case "handoff": return options.publisher.publish(action);
3641
- case "finish": return Effect.gen(function* () {
3642
- pendingTextByRun.set(action.runId, action.text);
3643
- yield* flushRun(action.runId);
3644
- yield* options.publisher.publish(action);
4322
+ case "update_progress": return Effect.sync(() => {
4323
+ pendingProgressByRun.set(action.runId, action.presentation);
3645
4324
  });
4325
+ case "update_presentation": return Effect.sync(() => {
4326
+ pendingPresentationByRun.set(action.runId, action);
4327
+ });
4328
+ case "finish":
3646
4329
  case "fail":
3647
4330
  case "cancel": return Effect.gen(function* () {
3648
- yield* flushRun(action.runId);
4331
+ yield* Effect.sync(() => {
4332
+ pendingProgressByRun.delete(action.runId);
4333
+ pendingTextByRun.delete(action.runId);
4334
+ pendingPresentationByRun.delete(action.runId);
4335
+ });
3649
4336
  yield* options.publisher.publish(action);
3650
4337
  });
3651
4338
  }
@@ -3670,8 +4357,10 @@ function createConfiguredFeishuCardKitPublisher(options) {
3670
4357
  client: createFeishuCardKitOpenApiClient({
3671
4358
  ...options.agentName === void 0 ? {} : { agentName: options.agentName },
3672
4359
  baseUrl: options.config.feishu.baseUrl,
4360
+ ...options.cancelButton === void 0 ? {} : { cancelButton: options.cancelButton },
3673
4361
  client: options.client,
3674
- ...options.onStreamingClosed === void 0 ? {} : { onStreamingClosed: options.onStreamingClosed }
4362
+ ...options.onStreamingClosed === void 0 ? {} : { onStreamingClosed: options.onStreamingClosed },
4363
+ ...options.progressDisplay === void 0 ? {} : { progressDisplay: options.progressDisplay }
3675
4364
  }),
3676
4365
  ...options.ledger ? { ledger: options.ledger } : {},
3677
4366
  resolveTarget: options.resolveTarget
@@ -3698,6 +4387,7 @@ function createConfiguredFeishuCardKitTargetCreator(options) {
3698
4387
  client: options.client,
3699
4388
  elementId: options.elementId ?? DEFAULT_ELEMENT_ID,
3700
4389
  ...options.initialContent === void 0 ? {} : { initialContent: options.initialContent },
4390
+ ...options.progressDisplay === void 0 ? {} : { progressDisplay: options.progressDisplay },
3701
4391
  ...options.title === void 0 ? {} : { title: options.title }
3702
4392
  });
3703
4393
  }
@@ -3712,6 +4402,8 @@ function createFeishuCardKitOpenApiTargetCreator(options) {
3712
4402
  agentName: title,
3713
4403
  elementId: options.elementId,
3714
4404
  ...createOptions?.generation === void 0 ? {} : { generation: createOptions.generation },
4405
+ ...createOptions?.initialPresentation === void 0 ? {} : { presentation: createOptions.initialPresentation },
4406
+ ...options.progressDisplay === void 0 ? {} : { progressDisplay: options.progressDisplay },
3715
4407
  runId: run.runId,
3716
4408
  sessionKey: run.sessionKey,
3717
4409
  status: "running",
@@ -3754,14 +4446,20 @@ const MIN_SUPERVISOR_INTERVAL_MS = 200;
3754
4446
  const MAX_SUPERVISOR_INTERVAL_MS = 5e3;
3755
4447
  function createConfiguredFeishuCardRolloverRuntime(options) {
3756
4448
  const leaseMs = options.config.feishu.cardStreamLeaseMs;
4449
+ const progressDisplay = options.progressDisplay ?? "collapsed";
3757
4450
  let rollover;
3758
4451
  const publisher = createConfiguredFeishuCardKitPublisher({
3759
4452
  ...options.agentName === void 0 ? {} : { agentName: options.agentName },
4453
+ ...options.cancelButton === void 0 ? {} : { cancelButton: options.cancelButton },
3760
4454
  client: options.client,
3761
4455
  config: options.config,
3762
4456
  ...options.ledger ? { ledger: options.ledger } : {},
3763
4457
  onStreamingClosed: (cardId) => rollover?.observeStreamClosed(cardId),
3764
- resolveTarget: (runId) => options.cardTargets.resolveTarget(runId),
4458
+ progressDisplay,
4459
+ resolveTarget: (runId) => options.cardTargets.resolveTarget(runId).pipe(Effect.map((target) => progressDisplay === "hidden" ? target : {
4460
+ ...target,
4461
+ progressElementId: FEISHU_AGENT_CARD_PROGRESS_ELEMENT_ID
4462
+ })),
3765
4463
  sleep: options.sleep
3766
4464
  });
3767
4465
  const creator = createConfiguredFeishuCardKitTargetCreator({
@@ -3770,13 +4468,14 @@ function createConfiguredFeishuCardRolloverRuntime(options) {
3770
4468
  config: options.config,
3771
4469
  ...options.elementId === void 0 ? {} : { elementId: options.elementId },
3772
4470
  ...options.initialContent === void 0 ? {} : { initialContent: options.initialContent },
4471
+ progressDisplay,
3773
4472
  ...options.title === void 0 ? {} : { title: options.title }
3774
4473
  });
3775
4474
  const cardRollover = createFeishuCardRollover({
3776
4475
  clock: options.clock,
3777
- createSuccessor: ({ generation, run, text }) => creator.createTarget(run, {
4476
+ createSuccessor: ({ generation, run }) => creator.createTarget(run, {
3778
4477
  generation,
3779
- ...text === void 0 ? {} : { initialContent: text }
4478
+ initialContent: ""
3780
4479
  }),
3781
4480
  leaseMs,
3782
4481
  ...options.observe ? { observe: options.observe } : {},
@@ -3907,7 +4606,6 @@ function createConfiguredRivusDaemonBootstrap(options) {
3907
4606
  });
3908
4607
  const cardRollover = createConfiguredFeishuCardRolloverRuntime({
3909
4608
  cardTargets: options.cardTargets,
3910
- cancelButton: false,
3911
4609
  client: openApiClient,
3912
4610
  clock: options.clock,
3913
4611
  config: options.config,
@@ -5055,6 +5753,114 @@ function createPiSessionRegistry(options) {
5055
5753
  };
5056
5754
  }
5057
5755
  //#endregion
5756
+ //#region src/domain/automation-presentation.ts
5757
+ const AUTOMATION_PRESENTATION_SCHEMA_VERSION = 1;
5758
+ var InvalidAutomationPresentation = class extends Error {
5759
+ name = "InvalidAutomationPresentation";
5760
+ };
5761
+ function createAutomationPresentation(input) {
5762
+ const title = requiredText(input.title, "title", 120);
5763
+ const meta = (input.meta ?? []).map((value, index) => requiredText(value, `meta[${index}]`, 80));
5764
+ if (meta.length > 6) throw new InvalidAutomationPresentation("Automation presentation meta exceeds 6 items");
5765
+ if (input.sections.length > 12) throw new InvalidAutomationPresentation("Automation presentation exceeds 12 sections");
5766
+ const sections = input.sections.map((section, sectionIndex) => {
5767
+ const id = requiredIdentifier(section.id, `sections[${sectionIndex}].id`);
5768
+ const sectionTitle = requiredText(section.title, `sections[${sectionIndex}].title`, 80);
5769
+ if (section.items.length > 40) throw new InvalidAutomationPresentation(`Automation presentation section '${id}' exceeds 40 items`);
5770
+ return Object.freeze({
5771
+ id,
5772
+ items: Object.freeze(section.items.map((item, itemIndex) => Object.freeze({
5773
+ headline: requiredText(item.headline, `sections[${sectionIndex}].items[${itemIndex}].headline`, 240),
5774
+ ...item.note ? { note: requiredText(item.note, `sections[${sectionIndex}].items[${itemIndex}].note`, 400) } : {},
5775
+ sources: Object.freeze((item.sources ?? []).map((source, sourceIndex) => Object.freeze({
5776
+ label: requiredText(source.label, `sections[${sectionIndex}].items[${itemIndex}].sources[${sourceIndex}].label`, 60),
5777
+ url: safeHttpUrl(source.url, `sections[${sectionIndex}].items[${itemIndex}].sources[${sourceIndex}].url`)
5778
+ })))
5779
+ }))),
5780
+ title: sectionTitle
5781
+ });
5782
+ });
5783
+ return Object.freeze({
5784
+ ...input.footnote ? { footnote: requiredText(input.footnote, "footnote", 240) } : {},
5785
+ ...input.kind === void 0 ? {} : { kind: input.kind },
5786
+ meta: Object.freeze(meta),
5787
+ schemaVersion: 1,
5788
+ sections: Object.freeze(sections),
5789
+ ...input.summary ? { summary: requiredText(input.summary, "summary", 800) } : {},
5790
+ title
5791
+ });
5792
+ }
5793
+ function readAutomationPresentation(value) {
5794
+ const record = objectValue(value, "Automation presentation");
5795
+ if (record.schemaVersion !== 1) throw new InvalidAutomationPresentation(`Automation presentation schemaVersion must be 1`);
5796
+ const meta = arrayValue(record.meta, "Automation presentation meta").map((item, index) => stringValue(item, `Automation presentation meta[${index}]`));
5797
+ const sections = arrayValue(record.sections, "Automation presentation sections").map((sectionValue, sectionIndex) => {
5798
+ const section = objectValue(sectionValue, `Automation presentation sections[${sectionIndex}]`);
5799
+ return {
5800
+ id: stringValue(section.id, `Automation presentation sections[${sectionIndex}].id`),
5801
+ items: arrayValue(section.items, `Automation presentation sections[${sectionIndex}].items`).map((itemValue, itemIndex) => {
5802
+ const item = objectValue(itemValue, `Automation presentation sections[${sectionIndex}].items[${itemIndex}]`);
5803
+ return {
5804
+ headline: stringValue(item.headline, `Automation presentation sections[${sectionIndex}].items[${itemIndex}].headline`),
5805
+ ...item.note === void 0 ? {} : { note: stringValue(item.note, `Automation presentation sections[${sectionIndex}].items[${itemIndex}].note`) },
5806
+ sources: arrayValue(item.sources, `Automation presentation sections[${sectionIndex}].items[${itemIndex}].sources`).map((sourceValue, sourceIndex) => {
5807
+ const source = objectValue(sourceValue, `Automation presentation sections[${sectionIndex}].items[${itemIndex}].sources[${sourceIndex}]`);
5808
+ return {
5809
+ label: stringValue(source.label, "Automation presentation source label"),
5810
+ url: stringValue(source.url, "Automation presentation source URL")
5811
+ };
5812
+ })
5813
+ };
5814
+ }),
5815
+ title: stringValue(section.title, `Automation presentation sections[${sectionIndex}].title`)
5816
+ };
5817
+ });
5818
+ return createAutomationPresentation({
5819
+ ...record.footnote === void 0 ? {} : { footnote: stringValue(record.footnote, "Automation presentation footnote") },
5820
+ meta,
5821
+ ...record.kind === void 0 ? {} : { kind: automationPresentationKind(record.kind) },
5822
+ sections,
5823
+ ...record.summary === void 0 ? {} : { summary: stringValue(record.summary, "Automation presentation summary") },
5824
+ title: stringValue(record.title, "Automation presentation title")
5825
+ });
5826
+ }
5827
+ function automationPresentationKind(value) {
5828
+ if (value === "daily-ai" || value === "generic" || value === "industry" || value === "news" || value === "subscriptions") return value;
5829
+ throw new InvalidAutomationPresentation("Automation presentation kind is invalid");
5830
+ }
5831
+ function requiredText(value, path, maxLength) {
5832
+ const normalized = value.trim();
5833
+ if (!normalized) throw new InvalidAutomationPresentation(`Automation presentation ${path} is empty`);
5834
+ if (normalized.length > maxLength) throw new InvalidAutomationPresentation(`Automation presentation ${path} exceeds ${maxLength} characters`);
5835
+ return normalized;
5836
+ }
5837
+ function requiredIdentifier(value, path) {
5838
+ const normalized = requiredText(value, path, 80);
5839
+ if (!/^[a-z0-9][a-z0-9._-]*$/i.test(normalized)) throw new InvalidAutomationPresentation(`Automation presentation ${path} is not a stable identifier`);
5840
+ return normalized;
5841
+ }
5842
+ function safeHttpUrl(value, path) {
5843
+ try {
5844
+ const parsed = new URL(value);
5845
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") throw new Error("unsupported protocol");
5846
+ return parsed.toString();
5847
+ } catch {
5848
+ throw new InvalidAutomationPresentation(`Automation presentation ${path} must be an HTTP(S) URL`);
5849
+ }
5850
+ }
5851
+ function objectValue(value, path) {
5852
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new InvalidAutomationPresentation(`${path} must be an object`);
5853
+ return value;
5854
+ }
5855
+ function arrayValue(value, path) {
5856
+ if (!Array.isArray(value)) throw new InvalidAutomationPresentation(`${path} must be an array`);
5857
+ return value;
5858
+ }
5859
+ function stringValue(value, path) {
5860
+ if (typeof value !== "string") throw new InvalidAutomationPresentation(`${path} must be a string`);
5861
+ return value;
5862
+ }
5863
+ //#endregion
5058
5864
  //#region src/application/feishu/feishu-card-presentation-store.ts
5059
5865
  var FeishuCardPresentationNotFound = class {
5060
5866
  runId;
@@ -8669,6 +9475,7 @@ async function executeDue(options, schedule, at, claim) {
8669
9475
  record = await options.repository.put({
8670
9476
  ...record,
8671
9477
  body: result.body,
9478
+ ...result.presentation === void 0 ? {} : { presentation: result.presentation },
8672
9479
  revision: record.revision + 1,
8673
9480
  runId: result.runId,
8674
9481
  status: "generated"
@@ -8686,7 +9493,8 @@ async function executeDue(options, schedule, at, claim) {
8686
9493
  if (!record.body) throw new Error(`Automation ${options.automationId} generated an empty delivery body`);
8687
9494
  const delivered = await options.deliver({
8688
9495
  body: record.body,
8689
- idempotencyKey: record.tickId
9496
+ idempotencyKey: record.tickId,
9497
+ ...record.presentation === void 0 ? {} : { presentation: record.presentation }
8690
9498
  });
8691
9499
  return options.repository.put({
8692
9500
  ...record,
@@ -8783,6 +9591,7 @@ function readRecord(value) {
8783
9591
  ...typeof value.error === "string" ? { error: value.error } : {},
8784
9592
  mandateId: value.mandateId,
8785
9593
  occurrence: value.occurrence,
9594
+ ...value.presentation === void 0 ? {} : { presentation: readAutomationPresentation(value.presentation) },
8786
9595
  ...typeof value.providerMessageId === "string" ? { providerMessageId: value.providerMessageId } : {},
8787
9596
  revision: value.revision,
8788
9597
  ...typeof value.runId === "string" ? { runId: value.runId } : {},
@@ -9180,7 +9989,7 @@ function createConfiguredFeishuAutomationCardSender(options) {
9180
9989
  const baseUrl = options.config.feishu.baseUrl.replace(/\/$/, "");
9181
9990
  return { send: (input) => sendFeishuInteractiveCard(options.client, {
9182
9991
  body: {
9183
- content: JSON.stringify(createAutomationCard(input.markdown)),
9992
+ content: JSON.stringify(createAutomationCard(input.markdown, input.presentation)),
9184
9993
  msg_type: "interactive",
9185
9994
  receive_id: input.receiveId,
9186
9995
  uuid: deliveryUuid(input.idempotencyKey)
@@ -9189,21 +9998,98 @@ function createConfiguredFeishuAutomationCardSender(options) {
9189
9998
  url: `${baseUrl}/open-apis/im/v1/messages?receive_id_type=${encodeURIComponent(input.receiveIdType)}`
9190
9999
  }, "Feishu send failed") };
9191
10000
  }
9192
- function createAutomationCard(markdown) {
10001
+ function createAutomationCard(markdown, structured) {
10002
+ if (structured) return createStructuredAutomationCard(structured);
9193
10003
  const presentation = splitPresentation(markdown);
10004
+ return automationCard(presentation.title, [{
10005
+ content: presentation.content,
10006
+ tag: "markdown"
10007
+ }, {
10008
+ content: "_由 Rivus 自动生成_",
10009
+ tag: "markdown"
10010
+ }]);
10011
+ }
10012
+ function createStructuredAutomationCard(presentation) {
10013
+ const elements = [];
10014
+ if (presentation.meta.length > 0) elements.push({
10015
+ margin: "0px 0px 4px 0px",
10016
+ tag: "div",
10017
+ text: {
10018
+ content: presentation.meta.map(escapeMarkdown).join(" · "),
10019
+ tag: "lark_md",
10020
+ text_color: "grey",
10021
+ text_size: "notation"
10022
+ }
10023
+ });
10024
+ if (presentation.meta.length > 0 && (presentation.summary || presentation.sections.length > 0)) elements.push({ tag: "hr" });
10025
+ if (presentation.summary) {
10026
+ const summaryHeading = presentation.kind === "subscriptions" ? "先看这两条" : "今日概览";
10027
+ const summary = presentation.summary.trim();
10028
+ elements.push({
10029
+ content: summary === summaryHeading ? `**${summaryHeading}**` : `**${summaryHeading}**\n\n${escapeMarkdown(summary)}`,
10030
+ tag: "markdown",
10031
+ text_size: "normal"
10032
+ });
10033
+ }
10034
+ presentation.sections.forEach((section, index) => {
10035
+ if (presentation.summary || index > 0) elements.push({ tag: "hr" });
10036
+ elements.push({
10037
+ content: `**${escapeMarkdown(section.title)}**`,
10038
+ margin: "4px 0px 0px 0px",
10039
+ tag: "markdown",
10040
+ text_size: "heading"
10041
+ });
10042
+ for (const item of section.items) elements.push(renderDigestItem(item));
10043
+ });
10044
+ if (presentation.footnote) {
10045
+ elements.push({ tag: "hr" });
10046
+ elements.push({
10047
+ tag: "div",
10048
+ text: {
10049
+ content: escapeMarkdown(presentation.footnote),
10050
+ tag: "lark_md",
10051
+ text_color: "grey",
10052
+ text_size: "notation"
10053
+ }
10054
+ });
10055
+ }
10056
+ elements.push({
10057
+ margin: "12px 0px 0px 0px",
10058
+ tag: "div",
10059
+ text: {
10060
+ content: "Rivus",
10061
+ tag: "lark_md",
10062
+ text_align: "right",
10063
+ text_color: "grey",
10064
+ text_size: "notation"
10065
+ }
10066
+ });
10067
+ return automationCard(presentation.title, elements);
10068
+ }
10069
+ function renderDigestItem(item) {
10070
+ const sources = item.sources.map((source) => `[${escapeMarkdown(source.label)} ↗](${source.url})`).join(" ");
10071
+ const note = item.note ? `\n<font color='grey'>${escapeMarkdown(item.note)}</font>` : "";
9194
10072
  return {
9195
- body: { elements: [{
9196
- content: presentation.content,
9197
- tag: "markdown"
9198
- }, {
9199
- content: "_由 Rivus 自动生成_",
9200
- tag: "markdown"
9201
- }] },
10073
+ content: `• ${escapeMarkdown(item.headline)}${sources ? ` ${sources}` : ""}${note}`,
10074
+ margin: "4px 0px 0px 0px",
10075
+ tag: "markdown",
10076
+ text_size: "normal"
10077
+ };
10078
+ }
10079
+ function automationCard(title, elements) {
10080
+ return {
10081
+ body: {
10082
+ direction: "vertical",
10083
+ elements,
10084
+ padding: "18px 18px 16px 18px",
10085
+ vertical_spacing: "small"
10086
+ },
9202
10087
  config: { update_multi: true },
9203
10088
  header: {
10089
+ padding: "12px 18px 12px 18px",
9204
10090
  template: "blue",
9205
10091
  title: {
9206
- content: presentation.title,
10092
+ content: title,
9207
10093
  tag: "plain_text"
9208
10094
  }
9209
10095
  },
@@ -9226,6 +10112,9 @@ function splitPresentation(markdown) {
9226
10112
  function deliveryUuid(idempotencyKey) {
9227
10113
  return `rivus-${createHash("sha256").update(idempotencyKey).digest("hex").slice(0, 32)}`;
9228
10114
  }
10115
+ function escapeMarkdown(value) {
10116
+ return value.replace(/([\\`*_{}[\]|])/g, "\\$1");
10117
+ }
9229
10118
  //#endregion
9230
10119
  //#region src/application/interaction/human-interaction-repository.ts
9231
10120
  var HumanInteractionRepositoryError = class extends Error {
@@ -9579,4 +10468,4 @@ function validateDecisionInput(input) {
9579
10468
  if (input.recommendedOptionId && !optionIds.includes(input.recommendedOptionId)) throw new Error("recommended user decision option must be available");
9580
10469
  }
9581
10470
  //#endregion
9582
- export { AgentContextBudgetExceeded, AgentEventHandlerFailed, AgentEventLogStoreError, AgentEventSinkFailed, AgentHarnessBusy, AgentInstanceBusy, AgentInstanceConflict, AgentLoopFailed, AgentMemoryError, AgentRunCancelled, AgentRuntimeDisposed, AutomationMandateError, BACKGROUND_SESSION_DELIVERY_JSONL_VERSION, BACKGROUND_SESSION_JSONL_VERSION, BACKGROUND_SESSION_SESSION_KEY_PREFIX, BACKGROUND_SESSION_START_TOOL_ID, BACKGROUND_SESSION_TOOL_IDS, BACKGROUND_SESSION_TOOL_PLUGIN_ID, BACKGROUND_SESSION_TOOL_VERSION, BackgroundSessionCallerDenied, BackgroundSessionDeliveryConflict, BackgroundSessionRepositoryConflict, BackgroundSessionRepositoryCorrupted, BackgroundSessionTransitionDenied, CardPresentationTransitionDenied, CompactionError, DEFAULT_BACKGROUND_SESSION_LEASE_MS, DEFAULT_BACKGROUND_SESSION_LEASE_RENEWAL_INTERVAL_MS, DEFAULT_BACKGROUND_SESSION_LIFETIME_MS, DEFAULT_BACKGROUND_SESSION_MAX_CONCURRENT_SESSIONS, DEFAULT_BACKGROUND_SESSION_MAX_CONSECUTIVE_FAILURES, DEFAULT_BACKGROUND_SESSION_RETRY_BACKOFF_MS, DEFAULT_BACKGROUND_SESSION_STEP_TIMEOUT_MS, DEFAULT_BACKGROUND_SESSION_SUPERVISOR_INTERVAL_MS, DEFAULT_CARD_STREAM_LEASE_MS, DelegationDenied, DeliveryOutboxError, FeishuCardPresentationNotFound, FeishuCardTargetNotFound, FeishuCardTargetRegistryStoreError, FeishuCotProtocolError, FeishuEndpointCredentialError, FeishuOpenApiError, FeishuTenantAccessTokenError, HumanInteractionRepositoryError, HumanInteractionTransitionDenied, InvalidFeishuCardAction, InvalidFeishuMessageContent, InvalidFeishuSessionReference, InvalidFeishuTopicContext, InvalidInvocationAuthority, InvalidProjectSkillCatalog, InvalidRecoveryAction, InvalidRivusEndpointBinding, InvalidRivusPlugin, InvalidRivusProjectSpace, InvalidStableJson, InvalidToolInput, InvalidWorkspaceRoot, LangfuseTelemetryConfigError, MEMORY_SCOPES, OpenClawEnvImportError, PluginStateConflict, RIVUS_MEMORY_TOOL_ID, RIVUS_MEMORY_TOOL_PLUGIN_ID, RIVUS_MEMORY_TOOL_VERSION, RIVUS_PLUGIN_API_VERSION, RivusDaemonConfigError, RivusDeploymentAutomationReadinessError, RivusDeploymentDaemonLifecycleError, RivusDeploymentManifestError, RivusDeploymentReadinessError, RivusPluginConformanceError, RivusPluginLoadError, RivusToolInputRejected, SessionSchedulerCapacityExceeded, SessionSchedulerDisposed, ToolInvocationDenied, UnsupportedFeishuCardAction, UnsupportedFeishuMessage, WorkspaceInstructionsSourceError, acceptsCardPresentationProgress, activeCardPresentation, appendBackgroundSessionInput, assembleAgentContext, assertRivusPluginConforms, backgroundSessionToolIds, claimBackgroundSession, commitAutomationOutcome, completeBackgroundSessionStep, completeBackgroundSessionStop, composeFeishuTopicPrompt, createAgentCommandFromFeishuCardAction, createAgentCommandFromFeishuMessage, createAgentConversationMessages, createAgentDomainEventHandler, createAgentDomainEventSink, createAgentDomainEventSinkFromCallback, createAgentHarness, createAgentHarnessClient, createAgentHarnessPooledRuntime, createAgentInstanceRegistry, createAgentLoopFromCallback, createAgentLoopModelExecutionEnd, createAgentLoopModelExecutionStart, createAgentLoopPromptTransformer, createAgentLoopSkillExecutionEnd, createAgentLoopSkillExecutionStart, createAgentLoopTextDelta, createAgentLoopThinkingDelta, createAgentLoopToolExecutionEnd, createAgentLoopToolExecutionStart, createAgentLoopToolExecutionUpdate, createAgentLoopTurnStart, createAgentMemoryService, createAgentRunUpdateHandler, createAgentRuntime, createAgentRuntimePool, createAgentTranscriptMessages, createAgentTranscriptTurn, createAgentsMdInstructionsProvider, createAsyncIterableAgentLoop, createAutomationMandateStore, createBackgroundSession, createBackgroundSessionCard, createBackgroundSessionDeliveryStore, createBackgroundSessionHostTools, createBackgroundSessionKey, createBackgroundSessionRepository, createBackgroundSessionService, createBackgroundSessionStepSourceMessageId, createBackgroundSessionSupervisor, createBackgroundSessionToolContracts, createCoalescingFeishuPublisher, createCompactionService, createCompositeRivusDaemonTransport, createConfiguredFeishuAutomationCardSender, createConfiguredFeishuBackgroundSessionDelivery, createConfiguredFeishuCardKitPublisher, createConfiguredFeishuCardKitTargetCreator, createConfiguredFeishuCardRolloverRuntime, createConfiguredFeishuHumanInteractionPresenter, createConfiguredFeishuMessageReactionSender, createConfiguredFeishuOpenApiClient, createConfiguredFeishuTextReplySender, createConfiguredRivusDaemonBootstrap, createConfiguredRivusDeploymentDaemon, createDailyAutomationSchedule, createDefaultAgentHarness, createDefaultAgentHarnessClient, createDefaultAgentHarnessClientFromCallback, createDefaultAgentHarnessClientFromTextCallback, createDefaultAgentHarnessFromCallback, createDefaultAgentHarnessFromTextCallback, createDefaultAgentRuntime, createDefaultAgentRuntimeFromCallback, createDefaultAgentRuntimeFromTextCallback, createDelegationService, createDeliveryOutbox, createEventAgentLoop, createFakeRivusPlugin, createFeishuAgentDaemon, createFeishuAgentRunCard, createFeishuAgentRuntime, createFeishuCardActionCallbackResponse, createFeishuCardActionErrorResponse, createFeishuCardDeliveryLedger, createFeishuCardDeliveryReconciler, createFeishuCardKitOpenApiClient, createFeishuCardKitOpenApiTargetCreator, createFeishuCardKitPublisher, createFeishuCardPresentationStore, createFeishuCardRollover, createFeishuCardRolloverSupervisor, createFeishuCardTargetPreparation, createFeishuConversationId, createFeishuCotPublisher, createFeishuDeploymentEndpoint, createFeishuEventHandlers, createFeishuHumanInteractionCard, createFeishuHumanInteractionPresenter, createFeishuInboxRepository, createFeishuMessageQueue, createFeishuMessageWorker, createFeishuOpenApiClient, createFeishuPeriodicFlush, createFeishuPresentationPreparation, createFeishuSessionKey, createFeishuSessionStore, createFeishuStreamProjector, createFeishuTenantAccessTokenProvider, createFeishuTopicContextResolver, createFeishuWebSocketDaemon, createFeishuWorkerLoop, createFixedClock, createHumanInteractionEndpointRegistry, createHumanInteractionService, createHumanInteractionToolApprovalGateway, createInMemoryFeishuCardTargetRegistry, createInMemoryHumanInteractionRepository, createInvocationAuthority, createJsonFetchRequest, createJsonFileFeishuCardTargetRegistry, createJsonlAgentEventLog, createJsonlHumanInteractionRepository, createLangfuseAgentTelemetry, createLazyFeishuWebSocketEventDispatcher, createMemoryNamespace, createOpenTelemetryAgentEventSink, createOpenTelemetryAgentTelemetry, createPiAgentLoop, createPiSdkAgentLoop, createPiSessionRegistry, createPluginStateStore, createProjectMemoryPromptPreparer, createRateLimitedFeishuPublisher, createRecoveryAction, createRecoveryControl, createRivusAgentHost, createRivusDaemonProcess, createRivusDaemonShutdownController, createRivusDaemonStatusHttpServer, createRivusDaemonStatusReporter, createRivusDeploymentCliProcess, createRivusDeploymentDaemon, createRivusEnvFromOpenClawConfig, createRivusMemoryTool, createRivusMemoryToolContract, createRivusMemoryToolDescriptor, createRivusPluginCatalog, createRoutedHumanInteractionToolApprovalService, createScheduledAutomation, createSequenceRunIds, createSessionScheduler, createSubagentCoordinator, createSystemClock, createTelemetryContentRedactor, createTestClock, createTextAgentLoop, createTextAgentLoopFromCallback, createToolBroker, createToolInputDigest, createToolOperationLedger, createUuidRunIds, createWorkspaceRootHandle, describeFeishuMessageIntake, evolveAgentRun, extendBackgroundSessionDefinition, failBackgroundSessionStep, formatRivusEnvFile, initialAgentRunState, intersectToolIds, isAgentToolExecutionEvent, isAssistantTextDeltaEvent, isAssistantThinkingDeltaEvent, isBackgroundSessionDue, isBackgroundSessionLeaseExpired, isBackgroundSessionState, isBackgroundSessionTerminalPhase, isBackgroundSessionToolId, isCardPresentationHandoffDue, isTerminalAgentDomainEvent, isTerminalAgentRunPhase, loadNodeRivusPluginModule, loadRivusDaemonConfig, loadRivusDeployment, loadRivusDeploymentManifest, narrowBackgroundSessionDefinition, normalizeStableJson, openJsonAutomationTickRepository, openJsonFeishuSessionStore, openJsonlAgentMemoryService, openJsonlBackgroundSessionDeliveryStore, openJsonlBackgroundSessionRepository, openJsonlFeishuCardDeliveryLedger, openJsonlFeishuInboxRepository, openJsonlRecoveryControl, openJsonlToolOperationLedger, parkBackgroundSessionForReconciliation, progressDeliveryId, readFeishuMessageContent, releaseBackgroundSessionLease, renewBackgroundSessionLease, replayAgentHistory, replayAgentTranscript, requestBackgroundSessionStop, requeueInterruptedBackgroundSessionStep, requiresToolApproval, resolveBackgroundSessionReconciliation, resolveBackgroundSessionSupervisorIntervalMs, resolveFeishuDeliveryChatId, resolveFeishuEndpointCredentials, resolveLangfuseTelemetryConfig, resolveRivusAgentDefinition, resolveRivusProjectSpace, restoreAgentHistory, restoreConfiguredRivusDaemonBootstrap, restrictMemoryScopesForAudience, runRivusDaemonCli, sessionIdFromSessionKey, shouldAcceptFeishuEndpointMessage, suspendBackgroundSession, terminalDeliveryId, transitionHumanInteraction, validateProjectSkillCatalog, validateProjectSkillCommand, validateRivusDeploymentManifest };
10471
+ export { AUTOMATION_PRESENTATION_SCHEMA_VERSION, AgentContextBudgetExceeded, AgentEventHandlerFailed, AgentEventLogStoreError, AgentEventSinkFailed, AgentHarnessBusy, AgentInstanceBusy, AgentInstanceConflict, AgentLoopFailed, AgentMemoryError, AgentRunCancelled, AgentRuntimeDisposed, AutomationMandateError, BACKGROUND_SESSION_DELIVERY_JSONL_VERSION, BACKGROUND_SESSION_JSONL_VERSION, BACKGROUND_SESSION_SESSION_KEY_PREFIX, BACKGROUND_SESSION_START_TOOL_ID, BACKGROUND_SESSION_TOOL_IDS, BACKGROUND_SESSION_TOOL_PLUGIN_ID, BACKGROUND_SESSION_TOOL_VERSION, BackgroundSessionCallerDenied, BackgroundSessionDeliveryConflict, BackgroundSessionRepositoryConflict, BackgroundSessionRepositoryCorrupted, BackgroundSessionTransitionDenied, CardPresentationTransitionDenied, CompactionError, DEFAULT_BACKGROUND_SESSION_LEASE_MS, DEFAULT_BACKGROUND_SESSION_LEASE_RENEWAL_INTERVAL_MS, DEFAULT_BACKGROUND_SESSION_LIFETIME_MS, DEFAULT_BACKGROUND_SESSION_MAX_CONCURRENT_SESSIONS, DEFAULT_BACKGROUND_SESSION_MAX_CONSECUTIVE_FAILURES, DEFAULT_BACKGROUND_SESSION_RETRY_BACKOFF_MS, DEFAULT_BACKGROUND_SESSION_STEP_TIMEOUT_MS, DEFAULT_BACKGROUND_SESSION_SUPERVISOR_INTERVAL_MS, DEFAULT_CARD_STREAM_LEASE_MS, DEFAULT_CONVERSATION_PROGRESS_DISPLAY, DelegationDenied, DeliveryOutboxError, FEISHU_AGENT_CARD_ELEMENT_ID, FEISHU_AGENT_CARD_PROGRESS_ELEMENT_ID, FeishuCardPresentationNotFound, FeishuCardTargetNotFound, FeishuCardTargetRegistryStoreError, FeishuCotProtocolError, FeishuEndpointCredentialError, FeishuOpenApiError, FeishuTenantAccessTokenError, HumanInteractionRepositoryError, HumanInteractionTransitionDenied, InvalidAutomationPresentation, InvalidFeishuCardAction, InvalidFeishuMessageContent, InvalidFeishuSessionReference, InvalidFeishuTopicContext, InvalidInvocationAuthority, InvalidProjectSkillCatalog, InvalidRecoveryAction, InvalidRivusEndpointBinding, InvalidRivusPlugin, InvalidRivusProjectSpace, InvalidStableJson, InvalidToolInput, InvalidWorkspaceRoot, LangfuseTelemetryConfigError, MEMORY_SCOPES, OpenClawEnvImportError, PluginStateConflict, RIVUS_MEMORY_TOOL_ID, RIVUS_MEMORY_TOOL_PLUGIN_ID, RIVUS_MEMORY_TOOL_VERSION, RIVUS_PLUGIN_API_VERSION, RUN_PRESENTATION_SCHEMA_VERSION, RivusDaemonConfigError, RivusDeploymentAutomationReadinessError, RivusDeploymentDaemonLifecycleError, RivusDeploymentManifestError, RivusDeploymentReadinessError, RivusPluginConformanceError, RivusPluginLoadError, RivusToolInputRejected, SessionSchedulerCapacityExceeded, SessionSchedulerDisposed, ToolInvocationDenied, UnsupportedFeishuCardAction, UnsupportedFeishuMessage, WorkspaceInstructionsSourceError, acceptsCardPresentationProgress, activeCardPresentation, appendBackgroundSessionInput, assembleAgentContext, assertRivusPluginConforms, backgroundSessionToolIds, claimBackgroundSession, commitAutomationOutcome, completeBackgroundSessionStep, completeBackgroundSessionStop, composeFeishuTopicPrompt, createAgentCommandFromFeishuCardAction, createAgentCommandFromFeishuMessage, createAgentConversationMessages, createAgentDomainEventHandler, createAgentDomainEventSink, createAgentDomainEventSinkFromCallback, createAgentHarness, createAgentHarnessClient, createAgentHarnessPooledRuntime, createAgentInstanceRegistry, createAgentLoopFromCallback, createAgentLoopModelExecutionEnd, createAgentLoopModelExecutionStart, createAgentLoopPromptTransformer, createAgentLoopSkillExecutionEnd, createAgentLoopSkillExecutionStart, createAgentLoopTextDelta, createAgentLoopThinkingDelta, createAgentLoopToolExecutionEnd, createAgentLoopToolExecutionStart, createAgentLoopToolExecutionUpdate, createAgentLoopTurnStart, createAgentMemoryService, createAgentRunUpdateHandler, createAgentRuntime, createAgentRuntimePool, createAgentTranscriptMessages, createAgentTranscriptTurn, createAgentsMdInstructionsProvider, createAsyncIterableAgentLoop, createAutomationMandateStore, createAutomationPresentation, createBackgroundSession, createBackgroundSessionCard, createBackgroundSessionDeliveryStore, createBackgroundSessionHostTools, createBackgroundSessionKey, createBackgroundSessionRepository, createBackgroundSessionService, createBackgroundSessionStepSourceMessageId, createBackgroundSessionSupervisor, createBackgroundSessionToolContracts, createCoalescingFeishuPublisher, createCompactionService, createCompositeRivusDaemonTransport, createConfiguredFeishuAutomationCardSender, createConfiguredFeishuBackgroundSessionDelivery, createConfiguredFeishuCardKitPublisher, createConfiguredFeishuCardKitTargetCreator, createConfiguredFeishuCardRolloverRuntime, createConfiguredFeishuHumanInteractionPresenter, createConfiguredFeishuMessageReactionSender, createConfiguredFeishuOpenApiClient, createConfiguredFeishuTextReplySender, createConfiguredRivusDaemonBootstrap, createConfiguredRivusDeploymentDaemon, createDailyAutomationSchedule, createDefaultAgentHarness, createDefaultAgentHarnessClient, createDefaultAgentHarnessClientFromCallback, createDefaultAgentHarnessClientFromTextCallback, createDefaultAgentHarnessFromCallback, createDefaultAgentHarnessFromTextCallback, createDefaultAgentRuntime, createDefaultAgentRuntimeFromCallback, createDefaultAgentRuntimeFromTextCallback, createDelegationService, createDeliveryOutbox, createEventAgentLoop, createFakeRivusPlugin, createFeishuAgentDaemon, createFeishuAgentRunCard, createFeishuAgentRuntime, createFeishuCardActionCallbackResponse, createFeishuCardActionErrorResponse, createFeishuCardDeliveryLedger, createFeishuCardDeliveryReconciler, createFeishuCardKitOpenApiClient, createFeishuCardKitOpenApiTargetCreator, createFeishuCardKitPublisher, createFeishuCardPresentationStore, createFeishuCardRollover, createFeishuCardRolloverSupervisor, createFeishuCardTargetPreparation, createFeishuConversationId, createFeishuCotPublisher, createFeishuDeploymentEndpoint, createFeishuEventHandlers, createFeishuHumanInteractionCard, createFeishuHumanInteractionPresenter, createFeishuInboxRepository, createFeishuMessageQueue, createFeishuMessageWorker, createFeishuOpenApiClient, createFeishuPeriodicFlush, createFeishuPresentationPreparation, createFeishuSessionKey, createFeishuSessionStore, createFeishuStreamProjector, createFeishuTenantAccessTokenProvider, createFeishuTopicContextResolver, createFeishuWebSocketDaemon, createFeishuWorkerLoop, createFixedClock, createHumanInteractionEndpointRegistry, createHumanInteractionService, createHumanInteractionToolApprovalGateway, createInMemoryFeishuCardTargetRegistry, createInMemoryHumanInteractionRepository, createInvocationAuthority, createJsonFetchRequest, createJsonFileFeishuCardTargetRegistry, createJsonlAgentEventLog, createJsonlHumanInteractionRepository, createLangfuseAgentTelemetry, createLazyFeishuWebSocketEventDispatcher, createMemoryNamespace, createOpenTelemetryAgentEventSink, createOpenTelemetryAgentTelemetry, createPiAgentLoop, createPiSdkAgentLoop, createPiSessionRegistry, createPluginStateStore, createPresentedValue, createProjectMemoryPromptPreparer, createRateLimitedFeishuPublisher, createRecoveryAction, createRecoveryControl, createRivusAgentHost, createRivusDaemonProcess, createRivusDaemonShutdownController, createRivusDaemonStatusHttpServer, createRivusDaemonStatusReporter, createRivusDeploymentCliProcess, createRivusDeploymentDaemon, createRivusEnvFromOpenClawConfig, createRivusMemoryTool, createRivusMemoryToolContract, createRivusMemoryToolDescriptor, createRivusPluginCatalog, createRoutedHumanInteractionToolApprovalService, createRunPresentationProjector, createScheduledAutomation, createSequenceRunIds, createSessionScheduler, createSubagentCoordinator, createSystemClock, createTelemetryContentRedactor, createTestClock, createTextAgentLoop, createTextAgentLoopFromCallback, createToolBroker, createToolInputDigest, createToolOperationLedger, createUuidRunIds, createWorkspaceRootHandle, describeFeishuMessageIntake, evolveAgentRun, extendBackgroundSessionDefinition, failBackgroundSessionStep, formatRivusEnvFile, hasInspectableRunProgress, initialAgentRunState, intersectToolIds, isAgentToolExecutionEvent, isAssistantTextDeltaEvent, isAssistantThinkingDeltaEvent, isBackgroundSessionDue, isBackgroundSessionLeaseExpired, isBackgroundSessionState, isBackgroundSessionTerminalPhase, isBackgroundSessionToolId, isCardPresentationHandoffDue, isTerminalAgentDomainEvent, isTerminalAgentRunPhase, loadNodeRivusPluginModule, loadRivusDaemonConfig, loadRivusDeployment, loadRivusDeploymentManifest, narrowBackgroundSessionDefinition, normalizeStableJson, openJsonAutomationTickRepository, openJsonFeishuSessionStore, openJsonlAgentMemoryService, openJsonlBackgroundSessionDeliveryStore, openJsonlBackgroundSessionRepository, openJsonlFeishuCardDeliveryLedger, openJsonlFeishuInboxRepository, openJsonlRecoveryControl, openJsonlToolOperationLedger, parkBackgroundSessionForReconciliation, progressDeliveryId, readAutomationPresentation, readFeishuMessageContent, releaseBackgroundSessionLease, renewBackgroundSessionLease, replayAgentHistory, replayAgentTranscript, requestBackgroundSessionStop, requeueInterruptedBackgroundSessionStep, requiresToolApproval, resolveBackgroundSessionReconciliation, resolveBackgroundSessionSupervisorIntervalMs, resolveFeishuDeliveryChatId, resolveFeishuEndpointCredentials, resolveLangfuseTelemetryConfig, resolveRivusAgentDefinition, resolveRivusProjectSpace, restoreAgentHistory, restoreConfiguredRivusDaemonBootstrap, restrictMemoryScopesForAudience, runRivusDaemonCli, sessionIdFromSessionKey, shouldAcceptFeishuEndpointMessage, suspendBackgroundSession, terminalDeliveryId, transitionHumanInteraction, validateProjectSkillCatalog, validateProjectSkillCommand, validateRivusDeploymentManifest };