stageflow 0.42.0 → 0.44.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.
Files changed (275) hide show
  1. package/README.md +12 -3
  2. package/dist/agent/activity.d.ts +18 -0
  3. package/dist/agent/claudeAdapter.js +7 -0
  4. package/dist/agent/claudeTools.d.ts +27 -18
  5. package/dist/agent/claudeTools.js +54 -15
  6. package/dist/agent/compactionEvents.d.ts +34 -0
  7. package/dist/agent/compactionEvents.js +37 -0
  8. package/dist/agent/openRouterRouting.d.ts +7 -0
  9. package/dist/agent/openRouterRouting.js +23 -0
  10. package/dist/agent/piAdapter.d.ts +6 -0
  11. package/dist/agent/piAdapter.js +128 -27
  12. package/dist/agent/piSettings.d.ts +7 -0
  13. package/dist/agent/piSettings.js +9 -0
  14. package/dist/agent/sandboxPiTools.d.ts +3 -1
  15. package/dist/agent/sandboxPiTools.js +8 -2
  16. package/dist/agent/stageTurnDriver.d.ts +11 -2
  17. package/dist/agent/stageTurnDriver.js +45 -4
  18. package/dist/agent/toolOutputBudget.d.ts +15 -1
  19. package/dist/agent/toolOutputBudget.js +18 -0
  20. package/dist/agent/toolOutputBudgetExtension.d.ts +2 -0
  21. package/dist/agent/toolOutputBudgetExtension.js +40 -3
  22. package/dist/agents/authorChat.d.ts +1 -0
  23. package/dist/agents/authorChat.js +7 -0
  24. package/dist/agents/authorSessionStore.d.ts +3 -0
  25. package/dist/agents/authorSessionStore.js +17 -2
  26. package/dist/agents/hostContext.d.ts +1 -1
  27. package/dist/agents/runtime/piRuntime.d.ts +5 -1
  28. package/dist/agents/runtime/piRuntime.js +46 -12
  29. package/dist/agents/service.js +3 -2
  30. package/dist/agents/sessions.js +3 -1
  31. package/dist/compaction/directives.d.ts +18 -0
  32. package/dist/compaction/directives.js +119 -0
  33. package/dist/compaction/extension.d.ts +20 -0
  34. package/dist/compaction/extension.js +78 -0
  35. package/dist/compaction/mask.d.ts +18 -0
  36. package/dist/compaction/mask.js +155 -0
  37. package/dist/compaction/pin.d.ts +21 -0
  38. package/dist/compaction/pin.js +270 -0
  39. package/dist/compaction/scrub.d.ts +7 -0
  40. package/dist/compaction/scrub.js +26 -0
  41. package/dist/compaction/sessionWiring.d.ts +22 -0
  42. package/dist/compaction/sessionWiring.js +26 -0
  43. package/dist/compaction/summarize.d.ts +79 -0
  44. package/dist/compaction/summarize.js +171 -0
  45. package/dist/compaction/toolPolicy.d.ts +3 -0
  46. package/dist/compaction/toolPolicy.js +33 -0
  47. package/dist/compaction/types.d.ts +45 -0
  48. package/dist/compaction/types.js +7 -0
  49. package/dist/compaction/workingState.d.ts +56 -0
  50. package/dist/compaction/workingState.js +198 -0
  51. package/dist/config/createPipeline.js +2 -0
  52. package/dist/config/createTrigger.js +7 -1
  53. package/dist/config/ensureCatalogScanRoot.d.ts +2 -0
  54. package/dist/config/ensureCatalogScanRoot.js +6 -0
  55. package/dist/config/evalCatalog.js +30 -2
  56. package/dist/config/githubTriggerAction.d.ts +8 -0
  57. package/dist/config/githubTriggerAction.js +29 -0
  58. package/dist/config/hostConfig.js +2 -0
  59. package/dist/config/loadEval.js +21 -3
  60. package/dist/config/pipelineNeeds.d.ts +2 -0
  61. package/dist/config/pipelineNeeds.js +16 -3
  62. package/dist/config/pipelineRoute.js +5 -4
  63. package/dist/config/validateCatalog.d.ts +1 -1
  64. package/dist/config/validateCatalog.js +12 -0
  65. package/dist/config/validateEval.js +43 -2
  66. package/dist/config/writeEval.js +2 -2
  67. package/dist/envelope/assertEmittedArtifacts.d.ts +12 -0
  68. package/dist/envelope/assertEmittedArtifacts.js +43 -0
  69. package/dist/envelope/preEmitChecks.d.ts +3 -0
  70. package/dist/evals/constants.d.ts +3 -1
  71. package/dist/evals/constants.js +3 -1
  72. package/dist/evals/engine/FakeEngine.d.ts +1 -1
  73. package/dist/evals/engine/FakeEngine.js +2 -1
  74. package/dist/evals/engine/promptfoo/PromptfooEngine.d.ts +1 -1
  75. package/dist/evals/engine/promptfoo/PromptfooEngine.js +2 -1
  76. package/dist/evals/engine/promptfoo/generate.d.ts +1 -1
  77. package/dist/evals/engine/promptfoo/generate.js +11 -8
  78. package/dist/evals/engine/promptfoo/rubricPrompt.d.ts +1 -1
  79. package/dist/evals/engine/promptfoo/rubricPrompt.js +5 -3
  80. package/dist/evals/manager.d.ts +13 -0
  81. package/dist/evals/manager.js +10 -2
  82. package/dist/evals/plan.d.ts +8 -1
  83. package/dist/evals/plan.js +28 -9
  84. package/dist/evals/planInternalAgent.d.ts +19 -0
  85. package/dist/evals/planInternalAgent.js +205 -0
  86. package/dist/evals/read/api.d.ts +12 -0
  87. package/dist/evals/read/api.js +5 -0
  88. package/dist/evals/read/list.js +10 -1
  89. package/dist/evals/read/runs.d.ts +5 -0
  90. package/dist/evals/read/runs.js +7 -1
  91. package/dist/evals/runner/caseRunner.d.ts +2 -1
  92. package/dist/evals/runner/caseRunner.js +16 -5
  93. package/dist/evals/runner/internalAgentCaseRunner.d.ts +6 -0
  94. package/dist/evals/runner/internalAgentCaseRunner.js +250 -0
  95. package/dist/evals/snapshot.d.ts +10 -2
  96. package/dist/evals/snapshot.js +8 -3
  97. package/dist/evals/types.d.ts +12 -2
  98. package/dist/evals/types.js +4 -1
  99. package/dist/guide/cardContract.d.ts +133 -0
  100. package/dist/guide/cardContract.js +156 -0
  101. package/dist/guide/chat.d.ts +45 -0
  102. package/dist/guide/chat.js +378 -0
  103. package/dist/guide/knowledge/index.d.ts +14 -0
  104. package/dist/guide/knowledge/index.js +109 -0
  105. package/dist/guide/knowledge/topics/agents.d.ts +2 -0
  106. package/dist/guide/knowledge/topics/agents.js +58 -0
  107. package/dist/guide/knowledge/topics/bestPractices.d.ts +2 -0
  108. package/dist/guide/knowledge/topics/bestPractices.js +67 -0
  109. package/dist/guide/knowledge/topics/connections.d.ts +2 -0
  110. package/dist/guide/knowledge/topics/connections.js +66 -0
  111. package/dist/guide/knowledge/topics/consoleMap.d.ts +2 -0
  112. package/dist/guide/knowledge/topics/consoleMap.js +55 -0
  113. package/dist/guide/knowledge/topics/evals.d.ts +2 -0
  114. package/dist/guide/knowledge/topics/evals.js +72 -0
  115. package/dist/guide/knowledge/topics/limitations.d.ts +2 -0
  116. package/dist/guide/knowledge/topics/limitations.js +84 -0
  117. package/dist/guide/knowledge/topics/mcpSkillsBrowser.d.ts +2 -0
  118. package/dist/guide/knowledge/topics/mcpSkillsBrowser.js +57 -0
  119. package/dist/guide/knowledge/topics/memories.d.ts +2 -0
  120. package/dist/guide/knowledge/topics/memories.js +63 -0
  121. package/dist/guide/knowledge/topics/modelsAndProviders.d.ts +2 -0
  122. package/dist/guide/knowledge/topics/modelsAndProviders.js +56 -0
  123. package/dist/guide/knowledge/topics/overview.d.ts +2 -0
  124. package/dist/guide/knowledge/topics/overview.js +56 -0
  125. package/dist/guide/knowledge/topics/pipelines.d.ts +2 -0
  126. package/dist/guide/knowledge/topics/pipelines.js +93 -0
  127. package/dist/guide/knowledge/topics/stages.d.ts +2 -0
  128. package/dist/guide/knowledge/topics/stages.js +54 -0
  129. package/dist/guide/knowledge/topics/tasks.d.ts +2 -0
  130. package/dist/guide/knowledge/topics/tasks.js +52 -0
  131. package/dist/guide/knowledge/topics/triggers.d.ts +2 -0
  132. package/dist/guide/knowledge/topics/triggers.js +68 -0
  133. package/dist/guide/knowledge/topics/troubleshooting.d.ts +2 -0
  134. package/dist/guide/knowledge/topics/troubleshooting.js +85 -0
  135. package/dist/guide/knowledgeTools.d.ts +2 -0
  136. package/dist/guide/knowledgeTools.js +56 -0
  137. package/dist/guide/showUi.d.ts +6 -0
  138. package/dist/guide/showUi.js +546 -0
  139. package/dist/guide/threadStore.d.ts +48 -0
  140. package/dist/guide/threadStore.js +189 -0
  141. package/dist/guide/writeRoot.d.ts +11 -0
  142. package/dist/guide/writeRoot.js +70 -0
  143. package/dist/hosted/translate.js +2 -0
  144. package/dist/mcp/agentTools.js +12 -0
  145. package/dist/mcp/catalogTools.js +18 -20
  146. package/dist/mcp/catalogWriteTools.d.ts +8 -0
  147. package/dist/mcp/catalogWriteTools.js +225 -0
  148. package/dist/mcp/connectionTools.d.ts +3 -0
  149. package/dist/mcp/connectionTools.js +85 -0
  150. package/dist/mcp/controlTools.js +34 -1
  151. package/dist/mcp/deps.d.ts +9 -0
  152. package/dist/mcp/evalTools.js +684 -21
  153. package/dist/mcp/memoryHostTools.d.ts +3 -0
  154. package/dist/mcp/memoryHostTools.js +72 -0
  155. package/dist/mcp/pipelineAuthorTools.js +14 -1
  156. package/dist/mcp/server.js +5 -0
  157. package/dist/mcp/tools.js +6 -0
  158. package/dist/mcp/triggerTools.js +77 -31
  159. package/dist/operatorAgent/evalGate.d.ts +22 -0
  160. package/dist/operatorAgent/evalGate.js +77 -0
  161. package/dist/operatorAgent/fakeHost.js +10 -2
  162. package/dist/operatorAgent/host.js +18 -2
  163. package/dist/operatorAgent/index.d.ts +1 -0
  164. package/dist/operatorAgent/index.js +1 -0
  165. package/dist/operatorAgent/internalAgents.d.ts +11 -0
  166. package/dist/operatorAgent/internalAgents.js +13 -0
  167. package/dist/operatorAgent/piModel.d.ts +5 -1
  168. package/dist/operatorAgent/piModel.js +15 -10
  169. package/dist/operatorAgent/profiles/agentAuthor.js +66 -22
  170. package/dist/operatorAgent/profiles/agentAuthorPlaybook.d.ts +1 -1
  171. package/dist/operatorAgent/profiles/agentAuthorPlaybook.js +1 -1
  172. package/dist/operatorAgent/profiles/guideConfirm.d.ts +21 -0
  173. package/dist/operatorAgent/profiles/guideConfirm.js +100 -0
  174. package/dist/operatorAgent/profiles/guideTools.d.ts +7 -0
  175. package/dist/operatorAgent/profiles/guideTools.js +123 -0
  176. package/dist/operatorAgent/profiles/stageflowGuide.d.ts +7 -0
  177. package/dist/operatorAgent/profiles/stageflowGuide.js +132 -0
  178. package/dist/operatorAgent/profiles/workshopAuthor.js +23 -0
  179. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.d.ts +1 -1
  180. package/dist/operatorAgent/profiles/workshopAuthorPlaybook.js +9 -1
  181. package/dist/operatorAgent/profiles/workshopAuthorTools.d.ts +2 -0
  182. package/dist/operatorAgent/profiles/workshopAuthorTools.js +197 -9
  183. package/dist/operatorAgent/types.d.ts +23 -0
  184. package/dist/package-meta.d.ts +1 -1
  185. package/dist/package-meta.js +1 -1
  186. package/dist/runstore/retention.d.ts +2 -1
  187. package/dist/runstore/retention.js +3 -7
  188. package/dist/runstore/runStatusClock.d.ts +17 -0
  189. package/dist/runstore/runStatusClock.js +19 -0
  190. package/dist/runstore/sqlite/SqliteRunStore.d.ts +1 -0
  191. package/dist/runstore/sqlite/SqliteRunStore.js +45 -45
  192. package/dist/runstore/workspaceLayout.js +6 -1
  193. package/dist/runtime/artifactDiskInspect.d.ts +14 -0
  194. package/dist/runtime/artifactDiskInspect.js +52 -0
  195. package/dist/runtime/artifactPath.d.ts +24 -0
  196. package/dist/runtime/artifactPath.js +84 -0
  197. package/dist/runtime/completionCheckRunner.js +15 -43
  198. package/dist/runtime/githubPollSource.d.ts +22 -4
  199. package/dist/runtime/githubPollSource.js +93 -8
  200. package/dist/runtime/priorArtifactGrants.d.ts +8 -0
  201. package/dist/runtime/priorArtifactGrants.js +105 -0
  202. package/dist/runtime/runActionEligibility.d.ts +46 -0
  203. package/dist/runtime/runActionEligibility.js +123 -0
  204. package/dist/runtime/runManager.d.ts +4 -1
  205. package/dist/runtime/runManager.js +52 -10
  206. package/dist/runtime/runRetryCoordinator.d.ts +2 -14
  207. package/dist/runtime/runRetryCoordinator.js +3 -67
  208. package/dist/runtime/sandboxContainer.d.ts +7 -0
  209. package/dist/runtime/sandboxContainer.js +48 -6
  210. package/dist/runtime/sandboxDesk.d.ts +2 -1
  211. package/dist/runtime/sandboxDesk.js +11 -12
  212. package/dist/runtime/stageEnvironment.js +1 -0
  213. package/dist/runtime/stageRoots.d.ts +12 -0
  214. package/dist/runtime/stageSandbox.d.ts +2 -1
  215. package/dist/runtime/stageSandbox.js +18 -2
  216. package/dist/runtime/stageWorker.js +20 -0
  217. package/dist/server/agentAuthorRoutes.js +12 -3
  218. package/dist/server/bootstrap.d.ts +5 -0
  219. package/dist/server/bootstrap.js +14 -1
  220. package/dist/server/evalRoutes.js +38 -9
  221. package/dist/server/guideRoutes.d.ts +5 -0
  222. package/dist/server/guideRoutes.js +166 -0
  223. package/dist/server/http.d.ts +10 -0
  224. package/dist/server/http.js +35 -1
  225. package/dist/server/internalAgentRoutes.d.ts +6 -0
  226. package/dist/server/internalAgentRoutes.js +12 -0
  227. package/dist/server/mcpHost.js +2 -0
  228. package/dist/toolkit/meta.d.ts +1 -1
  229. package/dist/toolkit/meta.js +39 -1
  230. package/dist/toolkit/profiles.d.ts +5 -0
  231. package/dist/toolkit/profiles.js +12 -0
  232. package/dist/tools/askOperator.js +2 -1
  233. package/dist/tools/emitStageEnvelope.d.ts +17 -16
  234. package/dist/tools/emitStageEnvelope.js +46 -32
  235. package/dist/tools/stageToolNames.d.ts +4 -0
  236. package/dist/tools/stageToolNames.js +4 -0
  237. package/dist/tools/workingState.d.ts +40 -0
  238. package/dist/tools/workingState.js +108 -0
  239. package/dist/tools/writeStageArtifact.d.ts +0 -9
  240. package/dist/tools/writeStageArtifact.js +2 -1
  241. package/dist/ui/assets/{MarkdownText-BTrOqu5J.js → MarkdownText-S5C_vemc.js} +2 -2
  242. package/dist/ui/assets/adapters-C0l4ruiR.js +17 -0
  243. package/dist/ui/assets/chat-CjnsmvqR.js +2 -0
  244. package/dist/ui/assets/chat-DFDd4UjS.css +2 -0
  245. package/dist/ui/assets/{main-CHlmTNJe.css → main-Del1GeLf.css} +1 -1
  246. package/dist/ui/assets/main-_yXVqcW9.js +277 -0
  247. package/dist/ui/chat.html +3 -4
  248. package/dist/ui/index.html +3 -4
  249. package/dist/workshop/chatTurn.js +1 -1
  250. package/dist/workshop/workshopPin.d.ts +3 -3
  251. package/dist/workshop/workshopPin.js +16 -15
  252. package/examples/compaction-stress/README.md +30 -0
  253. package/examples/compaction-stress/check-run.mjs +53 -0
  254. package/examples/compaction-stress/collect-evidence.yaml +60 -0
  255. package/examples/compaction-stress/compaction-stress.pipeline.yaml +141 -0
  256. package/examples/compaction-stress/compaction-stress.task.yaml +15 -0
  257. package/examples/compaction-stress/generate-evidence.mjs +110 -0
  258. package/examples/compaction-stress/root-cause.yaml +26 -0
  259. package/examples/compaction-stress/stageflow.yaml +9 -0
  260. package/examples/compaction-stress/write-postmortem.yaml +40 -0
  261. package/examples/evals/README.md +18 -0
  262. package/examples/evals/guide-behavior.dataset.jsonl +15 -0
  263. package/examples/evals/guide-behavior.eval.yaml +35 -0
  264. package/examples/evals/guide-depth.dataset.jsonl +35 -0
  265. package/examples/evals/guide-depth.eval.yaml +169 -0
  266. package/examples/memory/evals/guide-behavior.dataset.jsonl +15 -0
  267. package/examples/memory/evals/guide-behavior.eval.yaml +35 -0
  268. package/examples/memory/evals/guide-depth.dataset.jsonl +35 -0
  269. package/examples/memory/evals/guide-depth.eval.yaml +169 -0
  270. package/package.json +1 -1
  271. package/dist/ui/assets/AssistantRuntimeProvider-qIX1xNoH.js +0 -9
  272. package/dist/ui/assets/ReadonlyStore-BfXqHykm.js +0 -6
  273. package/dist/ui/assets/chat-Df_wCpak.js +0 -5
  274. package/dist/ui/assets/chat-P7KQznHm.css +0 -2
  275. package/dist/ui/assets/main-CvVfxmMd.js +0 -271
@@ -0,0 +1,546 @@
1
+ import path from "node:path";
2
+ import { Type } from "typebox";
3
+ import { z } from "zod";
4
+ import { isAgentError } from "../agents/errors.js";
5
+ import { defaultAgentProjectRoot } from "../agents/projectRoot.js";
6
+ import { loadDraftPackage, loadTaskArtifact, validateDraftPackage } from "../config/draftPackage.js";
7
+ import { listTasksMultiProject } from "../config/multiProjectCatalog.js";
8
+ import { loadCatalogTriggers } from "../config/triggerCatalog.js";
9
+ import { MemoryError } from "../memory/host.js";
10
+ import { buildEvalDetail, buildResultsPage, EvalApiError, locateEval, runByIdOr404 } from "../evals/read/api.js";
11
+ import { buildRunDetail } from "../evals/read/runs.js";
12
+ import { buildChoicesUi, buildLinksUi, buildPlanUi, GuideCardError, GUIDE_LINK_KINDS, GUIDE_RESOURCE_KINDS, GUIDE_UI_MAX_CHOICES, GUIDE_UI_MAX_FAILURES, GUIDE_UI_MAX_LINKS, GUIDE_UI_MAX_MESSAGES, GUIDE_UI_MAX_PLAN_STEPS, GUIDE_UI_MAX_TEXT, } from "./cardContract.js";
13
+ export const GUIDE_UI_TOOL_NAMES = ["show_ui"];
14
+ export { GUIDE_LINK_KINDS, GUIDE_RESOURCE_KINDS, } from "./cardContract.js";
15
+ const MAX_TEXT = GUIDE_UI_MAX_TEXT;
16
+ const MAX_PLAN_STEPS = GUIDE_UI_MAX_PLAN_STEPS;
17
+ const MAX_CHOICES = GUIDE_UI_MAX_CHOICES;
18
+ const MAX_LINKS = GUIDE_UI_MAX_LINKS;
19
+ const MAX_FAILURES = GUIDE_UI_MAX_FAILURES;
20
+ const MAX_MESSAGES = GUIDE_UI_MAX_MESSAGES;
21
+ const text = z.string().trim().min(1).max(MAX_TEXT);
22
+ const ref = z.string().trim().min(1).max(MAX_TEXT);
23
+ const pipelineArgs = z.object({
24
+ component: z.literal("pipeline"),
25
+ path: ref,
26
+ task_path: ref.optional(),
27
+ title: text.optional(),
28
+ });
29
+ const resourceArgs = z.object({
30
+ component: z.literal("resource"),
31
+ kind: z.string(),
32
+ id: ref,
33
+ project_root: ref.optional(),
34
+ title: text.optional(),
35
+ });
36
+ const planArgs = z.object({
37
+ component: z.literal("plan"),
38
+ title: text,
39
+ steps: z
40
+ .array(z.object({ title: text, detail: text.optional(), status: z.enum(["todo", "current", "done"]) }))
41
+ .min(1)
42
+ .max(MAX_PLAN_STEPS),
43
+ });
44
+ const choicesArgs = z.object({
45
+ component: z.literal("choices"),
46
+ question: text,
47
+ options: z
48
+ .array(z.object({ id: ref, label: text, description: text.optional() }))
49
+ .min(1)
50
+ .max(MAX_CHOICES),
51
+ allow_other: z.boolean().optional(),
52
+ });
53
+ const evalReportArgs = z.object({
54
+ component: z.literal("eval_report"),
55
+ eval_run_id: ref,
56
+ });
57
+ const linkArg = z.object({
58
+ kind: z.enum(GUIDE_LINK_KINDS),
59
+ id: ref,
60
+ path: ref.optional(),
61
+ project_root: ref.optional(),
62
+ label: text.optional(),
63
+ });
64
+ const linksArgs = z.object({
65
+ component: z.literal("links"),
66
+ title: text.optional(),
67
+ links: z.array(linkArg).min(1).max(MAX_LINKS),
68
+ });
69
+ class GuideUiError extends Error {
70
+ code;
71
+ constructor(code) {
72
+ super(code);
73
+ this.code = code;
74
+ }
75
+ }
76
+ function fail(code) {
77
+ return { ok: false, content: { ok: false, error: code }, error: code };
78
+ }
79
+ function parseArgs(schema, args) {
80
+ const parsed = schema.safeParse(args);
81
+ if (!parsed.success)
82
+ throw new GuideUiError("guide.ui_invalid_args");
83
+ return parsed.data;
84
+ }
85
+ function isRecord(value) {
86
+ return value !== null && typeof value === "object" && !Array.isArray(value);
87
+ }
88
+ function str(value) {
89
+ return typeof value === "string" && value.trim() ? value.trim() : undefined;
90
+ }
91
+ function clip(value) {
92
+ return value.length > MAX_TEXT ? `${value.slice(0, MAX_TEXT - 1)}…` : value;
93
+ }
94
+ function stringList(value) {
95
+ return Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
96
+ }
97
+ function stemOf(uses) {
98
+ return path.posix.basename(uses).replace(/(\.stage)?\.ya?ml$/i, "");
99
+ }
100
+ function channelNames(value) {
101
+ if (!Array.isArray(value))
102
+ return [];
103
+ const names = [];
104
+ for (const entry of value) {
105
+ if (!isRecord(entry))
106
+ continue;
107
+ const name = str(entry.alias) ?? str(entry.connection);
108
+ if (name)
109
+ names.push(name);
110
+ }
111
+ return names;
112
+ }
113
+ function hasEntries(value) {
114
+ if (Array.isArray(value))
115
+ return value.length > 0;
116
+ return isRecord(value) && Object.keys(value).length > 0;
117
+ }
118
+ function pipelineStages(draft) {
119
+ const files = new Map((draft.stages ?? []).map((stage) => [stage.path.trim().replace(/\\/g, "/"), stage.body]));
120
+ const stages = draft.pipeline.stages.map((entry) => {
121
+ const uses = str(entry.uses)?.replace(/\\/g, "/");
122
+ const body = uses ? (files.get(uses) ?? {}) : entry;
123
+ const id = str(entry.id) ?? str(body.id) ?? (uses ? stemOf(uses) : "");
124
+ const prompt = str(body.system_prompt)?.split("\n")[0]?.trim();
125
+ const model = str(body.model);
126
+ const channels = body.channels !== undefined ? body.channels : draft.pipeline.channels;
127
+ return {
128
+ id,
129
+ ...(prompt ? { summary: clip(prompt) } : {}),
130
+ ...(model ? { model } : {}),
131
+ needs: [],
132
+ gates: stringList(body.gate_kinds),
133
+ channels: channelNames(channels),
134
+ hasVerify: hasEntries(body.verify) || hasEntries(body.pre_emit_checks) || hasEntries(body.completion),
135
+ route: Array.isArray(entry.route) ? entry.route : [],
136
+ };
137
+ });
138
+ const byId = new Map(stages.map((stage) => [stage.id, stage]));
139
+ for (const stage of stages) {
140
+ for (const edge of stage.route) {
141
+ if (!isRecord(edge) || edge.type === "loop")
142
+ continue;
143
+ const target = byId.get(str(edge.to) ?? "");
144
+ if (target && !target.needs.includes(stage.id))
145
+ target.needs.push(stage.id);
146
+ }
147
+ }
148
+ return stages.map(({ route: _route, ...stage }) => stage);
149
+ }
150
+ async function pipelineUi(deps, args) {
151
+ const input = parseArgs(pipelineArgs, args);
152
+ const projectRoot = deps.projectRoot ?? deps.cwd;
153
+ const loaded = await loadDraftPackage(projectRoot, input.path, input.task_path ? { taskPath: input.task_path } : {});
154
+ if (!loaded.ok)
155
+ throw new GuideUiError(loaded.status === 404 ? "guide.ui_not_found" : "guide.ui_read_failed");
156
+ const validation = await validateDraftPackage(loaded.draft, { cwd: deps.cwd, projectRoot });
157
+ const { draft } = loaded;
158
+ const model = str(draft.pipeline.model);
159
+ const taskId = str(draft.task?.body.id);
160
+ const taskGoal = str(draft.task?.body.goal);
161
+ return {
162
+ component: "pipeline",
163
+ title: input.title ?? draft.pipeline.id,
164
+ pipeline: {
165
+ id: draft.pipeline.id,
166
+ path: loaded.pipelinePath,
167
+ ...(model ? { model } : {}),
168
+ stages: pipelineStages(draft),
169
+ memories: stringList(draft.pipeline.memories),
170
+ ...(taskId && taskGoal ? { task: { id: taskId, goal: clip(taskGoal) } } : {}),
171
+ },
172
+ validation: {
173
+ ok: validation.ok,
174
+ errors: validation.summary.errors,
175
+ warnings: validation.summary.warnings,
176
+ messages: validation.findings.slice(0, MAX_MESSAGES).map((finding) => clip(finding.message)),
177
+ },
178
+ link: { kind: "pipeline", id: draft.pipeline.id, path: loaded.pipelinePath, projectRoot },
179
+ };
180
+ }
181
+ function fields(entries) {
182
+ const out = [];
183
+ for (const [label, value] of entries) {
184
+ if (value === undefined || value === null)
185
+ continue;
186
+ const shown = Array.isArray(value) ? value.join(", ") : String(value);
187
+ if (shown.trim())
188
+ out.push({ label, value: clip(shown) });
189
+ }
190
+ return out;
191
+ }
192
+ async function agentResource(deps, id) {
193
+ if (!deps.agentService)
194
+ throw new GuideUiError("guide.ui_unavailable");
195
+ const { agent } = await deps.agentService.get(defaultAgentProjectRoot(deps.cwd), id);
196
+ return {
197
+ kind: "agent",
198
+ fields: fields([
199
+ ["Name", agent.name],
200
+ ["Description", agent.description],
201
+ ["Model", agent.model?.id ?? "default"],
202
+ ["Revision", agent.revision],
203
+ ["Tools", agent.tools.builtin],
204
+ ["MCP servers", agent.tools.mcpServers],
205
+ ["Skills", agent.tools.skills],
206
+ ["Schedule", agent.scheduleCron],
207
+ ["Channel", agent.channelConnection],
208
+ ["Sub-agents", agent.subAgents],
209
+ ]),
210
+ status: agent.enabled ? "enabled" : "disabled",
211
+ link: { kind: "agent", id: agent.id, label: agent.name },
212
+ };
213
+ }
214
+ async function triggerResource(deps, id, projectRoot) {
215
+ const items = await loadCatalogTriggers({ store: deps.store, bootCwd: deps.cwd });
216
+ const matches = items.filter((item) => item.id === id && (projectRoot === undefined || item.project_root === projectRoot));
217
+ if (matches.length === 0)
218
+ throw new GuideUiError("guide.ui_not_found");
219
+ if (matches.length > 1)
220
+ throw new GuideUiError("guide.ui_ambiguous");
221
+ const trigger = matches[0];
222
+ return {
223
+ kind: "trigger",
224
+ fields: fields([
225
+ ["Pipeline", trigger.pipeline],
226
+ ["Task", trigger.task],
227
+ ["Kind", trigger.kind],
228
+ ["Schedule", trigger.schedule ? [trigger.schedule.cron, trigger.schedule.timezone].filter(Boolean).join(" ") : undefined],
229
+ ["Event", trigger.event?.source],
230
+ ["Last fired", trigger.last_fired_at],
231
+ ["Last run", trigger.last_run_id],
232
+ ["Next run", trigger.next_run_at],
233
+ ]),
234
+ status: trigger.enabled ? "enabled" : "disabled",
235
+ link: { kind: "trigger", id: trigger.id, path: trigger.definition_ref, projectRoot: trigger.project_root },
236
+ };
237
+ }
238
+ async function evalResource(deps, id, projectRoot) {
239
+ const located = await locateEval({ store: deps.store, bootCwd: deps.cwd }, projectRoot, id);
240
+ const detail = await buildEvalDetail({
241
+ store: deps.store,
242
+ projectRoot: located.projectRoot,
243
+ absPath: located.ref.absPath,
244
+ ...(deps.agentService !== undefined ? { agents: deps.agentService } : {}),
245
+ });
246
+ const errors = detail.findings.filter((finding) => finding.severity === "error").length;
247
+ const last = detail.last_run;
248
+ return {
249
+ kind: "eval",
250
+ fields: fields([
251
+ ["Path", detail.path],
252
+ ["Target model", detail.target_model],
253
+ ["Judge", detail.judge_default],
254
+ ["Runs", detail.runs_count],
255
+ ["Last run", last ? `#${last.run_number} ${last.status}` : undefined],
256
+ ["Last pass rate", typeof last?.pass_rate === "number" ? `${Math.round(last.pass_rate * 100)}%` : undefined],
257
+ ["Problems", errors > 0 ? errors : undefined],
258
+ ]),
259
+ status: detail.active_run?.status ?? last?.status ?? "not run",
260
+ link: { kind: "eval", id: detail.id, path: detail.path, projectRoot: located.projectRoot },
261
+ };
262
+ }
263
+ function connectionResource(deps, id) {
264
+ if (!deps.channels)
265
+ throw new GuideUiError("guide.ui_unavailable");
266
+ const listing = deps.channels.list();
267
+ const connection = listing.connections.find((item) => item.id === id);
268
+ if (!connection)
269
+ throw new GuideUiError(listing.error ? "guide.ui_read_failed" : "guide.ui_not_found");
270
+ const health = connection.health;
271
+ return {
272
+ kind: "connection",
273
+ fields: fields([
274
+ ["Name", connection.displayName],
275
+ ["Provider", connection.provider],
276
+ ["Identity", connection.identity],
277
+ ["Last check", health ? (health.state === "ok" ? "ok" : (health.error?.code ?? "failed")) : undefined],
278
+ ]),
279
+ status: connection.enabled ? (health?.state === "failed" ? "failing" : "enabled") : "disabled",
280
+ link: { kind: "connection", id: connection.id, label: connection.displayName },
281
+ };
282
+ }
283
+ async function memoryResource(deps, id) {
284
+ if (!deps.memories)
285
+ throw new GuideUiError("guide.ui_unavailable");
286
+ const meta = await deps.memories.readMeta(id);
287
+ const cards = await deps.memories.listCards(id);
288
+ return {
289
+ kind: "memory",
290
+ fields: fields([
291
+ ["Description", meta.description],
292
+ ["Cards", cards.length],
293
+ ]),
294
+ link: { kind: "memory", id: meta.id },
295
+ };
296
+ }
297
+ async function taskResource(deps, id, projectRoot) {
298
+ if (/\.ya?ml$/i.test(id) || id.includes("/")) {
299
+ const root = projectRoot ?? deps.projectRoot ?? deps.cwd;
300
+ const loaded = await loadTaskArtifact(root, id);
301
+ if (!loaded.ok)
302
+ throw new GuideUiError(loaded.status === 404 ? "guide.ui_not_found" : "guide.ui_read_failed");
303
+ const body = loaded.task.body;
304
+ const taskId = str(body.id) ?? stemOf(loaded.taskPath).replace(/\.task$/, "");
305
+ return {
306
+ kind: "task",
307
+ fields: fields([
308
+ ["Goal", str(body.goal)],
309
+ ["Context", str(body.context)],
310
+ ["Constraints", str(body.constraints)],
311
+ ["Checkout", str(body.checkout)],
312
+ ["Repository", str(body.repository)],
313
+ ["Ref", str(body.ref)],
314
+ ["Path", loaded.taskPath],
315
+ ]),
316
+ link: { kind: "task", id: taskId, path: loaded.taskPath, projectRoot: root },
317
+ };
318
+ }
319
+ const listed = await listTasksMultiProject({
320
+ store: deps.store,
321
+ bootCwd: deps.cwd,
322
+ ...(projectRoot !== undefined ? { projectRootFilter: projectRoot } : {}),
323
+ });
324
+ const matches = listed.items.filter((item) => item.id === id);
325
+ if (matches.length === 0)
326
+ throw new GuideUiError("guide.ui_not_found");
327
+ if (matches.length > 1)
328
+ throw new GuideUiError("guide.ui_ambiguous");
329
+ const task = matches[0];
330
+ return {
331
+ kind: "task",
332
+ fields: fields([
333
+ ["Goal", task.goal],
334
+ ["Path", task.path],
335
+ ]),
336
+ link: { kind: "task", id: task.id, path: task.path, projectRoot: task.project_root },
337
+ };
338
+ }
339
+ async function resourceUi(deps, args) {
340
+ const input = parseArgs(resourceArgs, args);
341
+ if (!GUIDE_RESOURCE_KINDS.includes(input.kind))
342
+ throw new GuideUiError("guide.ui_unsupported_kind");
343
+ const kind = input.kind;
344
+ const read = kind === "agent"
345
+ ? await agentResource(deps, input.id)
346
+ : kind === "trigger"
347
+ ? await triggerResource(deps, input.id, input.project_root)
348
+ : kind === "eval"
349
+ ? await evalResource(deps, input.id, input.project_root)
350
+ : kind === "connection"
351
+ ? connectionResource(deps, input.id)
352
+ : kind === "memory"
353
+ ? await memoryResource(deps, input.id)
354
+ : await taskResource(deps, input.id, input.project_root);
355
+ return { component: "resource", title: input.title ?? read.link.label ?? read.link.id, ...read };
356
+ }
357
+ async function evalReportUi(deps, args) {
358
+ const input = parseArgs(evalReportArgs, args);
359
+ const row = await runByIdOr404(deps.store, input.eval_run_id);
360
+ const detail = await buildRunDetail({
361
+ store: deps.store,
362
+ row,
363
+ live: deps.evalRunManager?.getLive(row.evalRunId) ?? null,
364
+ ...(deps.agentService !== undefined ? { agents: deps.agentService } : {}),
365
+ });
366
+ const failures = [];
367
+ for (const status of ["failed", "errored"]) {
368
+ if (failures.length >= MAX_FAILURES)
369
+ break;
370
+ const page = await buildResultsPage(deps.store, row.evalRunId, { status, limit: MAX_FAILURES - failures.length });
371
+ for (const item of page.items) {
372
+ failures.push({
373
+ caseId: item.case_id,
374
+ reason: clip(item.failed_graders.length > 0 ? `Failed ${item.failed_graders.join(", ")}` : status),
375
+ });
376
+ }
377
+ }
378
+ return {
379
+ component: "eval_report",
380
+ title: detail.label ?? `${detail.eval_id} run #${detail.run_number}`,
381
+ evalId: detail.eval_id,
382
+ runId: detail.eval_run_id,
383
+ status: detail.status,
384
+ passRate: detail.stats?.pass_rate ?? null,
385
+ passed: detail.passed,
386
+ cases: detail.progress.cases_total,
387
+ failures,
388
+ costUsd: detail.stats?.cost_total ?? detail.progress.cost_usd,
389
+ link: { kind: "eval_run", id: detail.eval_run_id, path: detail.eval_path },
390
+ };
391
+ }
392
+ function jsonList(value) {
393
+ if (typeof value !== "string")
394
+ return value;
395
+ const trimmed = value.trim();
396
+ if (!trimmed.startsWith("["))
397
+ return value;
398
+ try {
399
+ const parsed = JSON.parse(trimmed);
400
+ return Array.isArray(parsed) ? parsed : value;
401
+ }
402
+ catch {
403
+ return value;
404
+ }
405
+ }
406
+ function normalizePlainArgs(args) {
407
+ const next = { ...args };
408
+ for (const key of ["options", "steps", "links"]) {
409
+ if (key in next)
410
+ next[key] = jsonList(next[key]);
411
+ }
412
+ if (next.allow_other === "true")
413
+ next.allow_other = true;
414
+ if (next.allow_other === "false")
415
+ next.allow_other = false;
416
+ return next;
417
+ }
418
+ function plainUi(args, component) {
419
+ args = normalizePlainArgs(args);
420
+ if (component === "plan") {
421
+ const input = parseArgs(planArgs, args);
422
+ return buildPlanUi({
423
+ title: input.title,
424
+ steps: input.steps.map((step) => ({ title: step.title, ...(step.detail ? { detail: step.detail } : {}), status: step.status })),
425
+ });
426
+ }
427
+ if (component === "choices") {
428
+ const input = parseArgs(choicesArgs, args);
429
+ return buildChoicesUi({
430
+ question: input.question,
431
+ options: input.options.map((option) => ({
432
+ id: option.id,
433
+ label: option.label,
434
+ ...(option.description ? { description: option.description } : {}),
435
+ })),
436
+ allowOther: input.allow_other ?? false,
437
+ });
438
+ }
439
+ const input = parseArgs(linksArgs, args);
440
+ return buildLinksUi({
441
+ ...(input.title ? { title: input.title } : {}),
442
+ links: input.links.map((link) => ({
443
+ kind: link.kind,
444
+ id: link.id,
445
+ ...(link.path ? { path: link.path } : {}),
446
+ ...(link.project_root ? { projectRoot: link.project_root } : {}),
447
+ ...(link.label ? { label: link.label } : {}),
448
+ })),
449
+ });
450
+ }
451
+ function errorCode(err) {
452
+ if (err instanceof GuideUiError || err instanceof GuideCardError)
453
+ return err.code;
454
+ if (err instanceof EvalApiError)
455
+ return err.status === 404 ? "guide.ui_not_found" : err.status === 409 ? "guide.ui_ambiguous" : "guide.ui_read_failed";
456
+ if (isAgentError(err) || err instanceof MemoryError)
457
+ return /not_found/i.test(err.code) ? "guide.ui_not_found" : "guide.ui_read_failed";
458
+ return "guide.ui_read_failed";
459
+ }
460
+ export async function buildGuideUi(deps, args) {
461
+ const component = args.component;
462
+ try {
463
+ let ui;
464
+ if (component === "pipeline")
465
+ ui = await pipelineUi(deps, args);
466
+ else if (component === "resource")
467
+ ui = await resourceUi(deps, args);
468
+ else if (component === "eval_report")
469
+ ui = await evalReportUi(deps, args);
470
+ else if (component === "plan" || component === "choices" || component === "links")
471
+ ui = plainUi(args, component);
472
+ else
473
+ return fail("guide.ui_unknown_component");
474
+ return { ok: true, content: { ui } };
475
+ }
476
+ catch (err) {
477
+ return fail(errorCode(err));
478
+ }
479
+ }
480
+ const DESCRIPTION = `Show a card in your reply. Pass component and its fields:
481
+ - pipeline: { component: "pipeline", path, task_path?, title? } shows a pipeline read from disk (path relative to the project root).
482
+ - resource: { component: "resource", kind: agent|trigger|eval|connection|memory|task, id, project_root?, title? } shows one saved thing. For a task, id is its path or its id.
483
+ - plan: { component: "plan", title, steps: [{ title, detail?, status: todo|current|done }] } (up to ${MAX_PLAN_STEPS} steps).
484
+ - choices: { component: "choices", question, options: [{ id, label, description? }], allow_other? } asks the person to pick (up to ${MAX_CHOICES} options). options, steps, and links are arrays of objects, never a JSON string.
485
+ - eval_report: { component: "eval_report", eval_run_id } shows an eval run's result.
486
+ - links: { component: "links", title?, links: [{ kind, id, path?, project_root?, label? }] } (up to ${MAX_LINKS}).
487
+ Text is at most ${MAX_TEXT} characters. The card shows what is on disk, so do not repeat it in prose.`;
488
+ const closed = { additionalProperties: false };
489
+ const uiText = Type.String({ minLength: 1, maxLength: MAX_TEXT });
490
+ const showUiParameters = Type.Union([
491
+ Type.Object({
492
+ component: Type.Literal("pipeline"),
493
+ path: uiText,
494
+ task_path: Type.Optional(uiText),
495
+ title: Type.Optional(uiText),
496
+ }, closed),
497
+ Type.Object({
498
+ component: Type.Literal("resource"),
499
+ kind: Type.String({ minLength: 1 }),
500
+ id: uiText,
501
+ project_root: Type.Optional(uiText),
502
+ title: Type.Optional(uiText),
503
+ }, closed),
504
+ Type.Object({
505
+ component: Type.Literal("plan"),
506
+ title: uiText,
507
+ steps: Type.Array(Type.Object({
508
+ title: uiText,
509
+ detail: Type.Optional(uiText),
510
+ status: Type.Union([Type.Literal("todo"), Type.Literal("current"), Type.Literal("done")]),
511
+ }, closed), { minItems: 1, maxItems: MAX_PLAN_STEPS }),
512
+ }, closed),
513
+ Type.Object({
514
+ component: Type.Literal("choices"),
515
+ question: uiText,
516
+ options: Type.Array(Type.Object({
517
+ id: uiText,
518
+ label: uiText,
519
+ description: Type.Optional(uiText),
520
+ }, closed), { minItems: 1, maxItems: MAX_CHOICES }),
521
+ allow_other: Type.Optional(Type.Boolean()),
522
+ }, closed),
523
+ Type.Object({
524
+ component: Type.Literal("eval_report"),
525
+ eval_run_id: uiText,
526
+ }, closed),
527
+ Type.Object({
528
+ component: Type.Literal("links"),
529
+ title: Type.Optional(uiText),
530
+ links: Type.Array(Type.Object({
531
+ kind: Type.Union(GUIDE_LINK_KINDS.map((kind) => Type.Literal(kind))),
532
+ id: uiText,
533
+ path: Type.Optional(uiText),
534
+ project_root: Type.Optional(uiText),
535
+ label: Type.Optional(uiText),
536
+ }, closed), { minItems: 1, maxItems: MAX_LINKS }),
537
+ }, closed),
538
+ ]);
539
+ export function createShowUiTool(deps) {
540
+ return {
541
+ name: "show_ui",
542
+ description: DESCRIPTION,
543
+ parameters: showUiParameters,
544
+ handler: (args) => buildGuideUi(deps, args),
545
+ };
546
+ }
@@ -0,0 +1,48 @@
1
+ export type GuideAttachmentMeta = {
2
+ name: string;
3
+ size: number;
4
+ mediaType: string;
5
+ };
6
+ export type GuidePart = {
7
+ type: "text";
8
+ text: string;
9
+ } | {
10
+ type: "tool";
11
+ id: string;
12
+ name: string;
13
+ status: "complete" | "error";
14
+ args?: Record<string, unknown>;
15
+ result?: unknown;
16
+ error?: string;
17
+ };
18
+ export type GuideMessage = {
19
+ id: string;
20
+ role: "user" | "assistant";
21
+ text: string;
22
+ createdAt: string;
23
+ attachments?: GuideAttachmentMeta[];
24
+ parts?: GuidePart[];
25
+ };
26
+ export type GuideThreadRecord = {
27
+ version: 1;
28
+ id: string;
29
+ title: string;
30
+ createdAt: string;
31
+ updatedAt: string;
32
+ messages: GuideMessage[];
33
+ model?: string;
34
+ };
35
+ export type GuideThreadSummary = {
36
+ id: string;
37
+ title: string;
38
+ updatedAt: string;
39
+ };
40
+ export declare function guideThreadsDir(storeRoot?: string): string;
41
+ export declare function guideThreadFilePath(threadId: string, storeRoot?: string): string;
42
+ export declare function parseGuideThread(value: unknown): GuideThreadRecord | null;
43
+ export declare function createGuideThread(storeRoot?: string): GuideThreadRecord;
44
+ export declare function readGuideThread(threadId: string, storeRoot?: string): GuideThreadRecord | null;
45
+ export declare function saveGuideThread(record: GuideThreadRecord, storeRoot?: string): GuideThreadRecord;
46
+ export declare function setGuideThreadModel(threadId: string, model: string | null, storeRoot?: string): GuideThreadRecord | null;
47
+ export declare function listGuideThreads(storeRoot?: string): GuideThreadSummary[];
48
+ export declare function guideTitleFrom(text: string): string;