@bastani/atomic 0.8.24-alpha.1 → 0.8.24-alpha.3
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/CHANGELOG.md +17 -0
- package/README.md +2 -1
- package/dist/builtin/intercom/CHANGELOG.md +12 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/mcp/CHANGELOG.md +12 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +16 -0
- package/dist/builtin/subagents/README.md +132 -21
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/prompts/parallel-context-build.md +4 -2
- package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +3 -1
- package/dist/builtin/subagents/skills/subagent/SKILL.md +49 -11
- package/dist/builtin/subagents/src/agents/agent-management.ts +79 -16
- package/dist/builtin/subagents/src/agents/agents.ts +47 -16
- package/dist/builtin/subagents/src/agents/chain-serializer.ts +114 -0
- package/dist/builtin/subagents/src/extension/schemas.ts +139 -3
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +92 -6
- package/dist/builtin/subagents/src/runs/background/async-status.ts +11 -1
- package/dist/builtin/subagents/src/runs/background/run-status.ts +4 -1
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +529 -32
- package/dist/builtin/subagents/src/runs/foreground/chain-execution.ts +361 -118
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +75 -7
- package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +33 -0
- package/dist/builtin/subagents/src/runs/shared/acceptance.ts +611 -0
- package/dist/builtin/subagents/src/runs/shared/chain-outputs.ts +101 -0
- package/dist/builtin/subagents/src/runs/shared/dynamic-fanout.ts +293 -0
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +29 -1
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +11 -0
- package/dist/builtin/subagents/src/runs/shared/structured-output.ts +79 -0
- package/dist/builtin/subagents/src/runs/shared/subagent-prompt-runtime.ts +52 -2
- package/dist/builtin/subagents/src/runs/shared/workflow-graph.ts +206 -0
- package/dist/builtin/subagents/src/shared/formatters.ts +2 -2
- package/dist/builtin/subagents/src/shared/settings.ts +53 -4
- package/dist/builtin/subagents/src/shared/types.ts +226 -0
- package/dist/builtin/subagents/src/shared/utils.ts +2 -1
- package/dist/builtin/subagents/src/slash/slash-commands.ts +41 -3
- package/dist/builtin/subagents/src/tui/render.ts +152 -34
- package/dist/builtin/web-access/CHANGELOG.md +12 -0
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +16 -0
- package/dist/builtin/workflows/ambient.d.ts +36 -0
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/create-spec/SKILL.md +1 -1
- package/dist/builtin/workflows/src/authoring.d.ts +197 -0
- package/dist/builtin/workflows/src/runs/shared/model-fallback.ts +11 -1
- package/dist/builtin/workflows/src/shared/authoring-contract.d.ts +523 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +0 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +4 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/docs/packages.md +2 -2
- package/docs/usage.md +1 -0
- package/docs/workflows.md +198 -2
- package/package.json +20 -1
- package/dist/builtin/workflows/src/authoring.ts +0 -410
- package/dist/builtin/workflows/src/shared/authoring-contract.ts +0 -660
|
@@ -5,7 +5,8 @@ import type { ExtensionAPI, ExtensionContext } from "@bastani/atomic";
|
|
|
5
5
|
import { Key, matchesKey } from "@earendil-works/pi-tui";
|
|
6
6
|
import { discoverAgents, discoverAgentsAll, type ChainConfig } from "../agents/agents.ts";
|
|
7
7
|
import type { SubagentParamsLike } from "../runs/foreground/subagent-executor.ts";
|
|
8
|
-
import { isParallelStep, type ChainStep } from "../shared/settings.ts";
|
|
8
|
+
import { isDynamicParallelStep, isParallelStep, type ChainStep } from "../shared/settings.ts";
|
|
9
|
+
import { assertJsonSchemaObject } from "../runs/shared/structured-output.ts";
|
|
9
10
|
import type { SlashSubagentResponse, SlashSubagentUpdate } from "./slash-bridge.ts";
|
|
10
11
|
import {
|
|
11
12
|
applySlashUpdate,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
SLASH_SUBAGENT_RESPONSE_EVENT,
|
|
21
22
|
SLASH_SUBAGENT_STARTED_EVENT,
|
|
22
23
|
SLASH_SUBAGENT_UPDATE_EVENT,
|
|
24
|
+
type JsonSchemaObject,
|
|
23
25
|
type SingleResult,
|
|
24
26
|
type SubagentState,
|
|
25
27
|
} from "../shared/types.ts";
|
|
@@ -123,12 +125,48 @@ const makeChainCompletions = (state: SubagentState) => (prefix: string) => {
|
|
|
123
125
|
.map((chain) => ({ value: chain.name, label: chain.name }));
|
|
124
126
|
};
|
|
125
127
|
|
|
128
|
+
function loadSavedOutputSchema(chain: ChainConfig, stepAgent: string, outputSchema: unknown): JsonSchemaObject | undefined {
|
|
129
|
+
if (outputSchema === undefined) return undefined;
|
|
130
|
+
if (typeof outputSchema === "string") {
|
|
131
|
+
const schemaPath = path.isAbsolute(outputSchema)
|
|
132
|
+
? outputSchema
|
|
133
|
+
: path.join(path.dirname(chain.filePath), outputSchema);
|
|
134
|
+
const parsed = JSON.parse(fs.readFileSync(schemaPath, "utf-8")) as unknown;
|
|
135
|
+
assertJsonSchemaObject(parsed, `outputSchema for chain '${chain.name}' step '${stepAgent}' (${schemaPath})`);
|
|
136
|
+
return parsed;
|
|
137
|
+
}
|
|
138
|
+
assertJsonSchemaObject(outputSchema, `outputSchema for chain '${chain.name}' step '${stepAgent}'`);
|
|
139
|
+
return outputSchema;
|
|
140
|
+
}
|
|
141
|
+
|
|
126
142
|
const mapSavedChainSteps = (chain: ChainConfig, worktree = false): ChainStep[] => {
|
|
127
|
-
return (chain.steps as Array<ChainStep & { skills?: string[] | false }>).map((step) => {
|
|
128
|
-
if (isParallelStep(step))
|
|
143
|
+
return (chain.steps as unknown as Array<ChainStep & { skills?: string[] | false }>).map((step) => {
|
|
144
|
+
if (isParallelStep(step)) {
|
|
145
|
+
const parallel = step.parallel.map((task) => {
|
|
146
|
+
const { outputSchema: rawOutputSchema, ...rest } = task as typeof task & { outputSchema?: unknown };
|
|
147
|
+
const outputSchema = loadSavedOutputSchema(chain, task.agent, rawOutputSchema);
|
|
148
|
+
return { ...rest, ...(outputSchema ? { outputSchema } : {}) };
|
|
149
|
+
});
|
|
150
|
+
return { ...step, parallel, ...(worktree ? { worktree: true } : {}) };
|
|
151
|
+
}
|
|
152
|
+
if (isDynamicParallelStep(step)) {
|
|
153
|
+
const { outputSchema: rawOutputSchema, ...parallelRest } = step.parallel as typeof step.parallel & { outputSchema?: unknown };
|
|
154
|
+
const outputSchema = loadSavedOutputSchema(chain, step.parallel.agent, rawOutputSchema);
|
|
155
|
+
const collectSchema = loadSavedOutputSchema(chain, `${step.collect.as} collection`, step.collect.outputSchema);
|
|
156
|
+
return {
|
|
157
|
+
...step,
|
|
158
|
+
parallel: { ...parallelRest, ...(outputSchema ? { outputSchema } : {}) },
|
|
159
|
+
collect: { ...step.collect, ...(collectSchema ? { outputSchema: collectSchema } : {}) },
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
const outputSchema = loadSavedOutputSchema(chain, step.agent, (step as { outputSchema?: unknown }).outputSchema);
|
|
129
163
|
return {
|
|
130
164
|
agent: step.agent,
|
|
131
165
|
task: step.task || undefined,
|
|
166
|
+
...(step.phase ? { phase: step.phase } : {}),
|
|
167
|
+
...(step.label ? { label: step.label } : {}),
|
|
168
|
+
...(step.as ? { as: step.as } : {}),
|
|
169
|
+
...(outputSchema ? { outputSchema } : {}),
|
|
132
170
|
output: step.output,
|
|
133
171
|
outputMode: step.outputMode,
|
|
134
172
|
reads: step.reads,
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
type Details,
|
|
15
15
|
type NestedRunSummary,
|
|
16
16
|
type NestedStepSummary,
|
|
17
|
+
type WorkflowNodeStatus,
|
|
17
18
|
MAX_WIDGET_JOBS,
|
|
18
19
|
WIDGET_KEY,
|
|
19
20
|
} from "../shared/types.ts";
|
|
@@ -305,6 +306,7 @@ function resultStatusLine(result: Details["results"][number], output: string): s
|
|
|
305
306
|
if (result.detached) return result.detachedReason ? `Detached: ${result.detachedReason}` : "Detached";
|
|
306
307
|
if (result.interrupted) return "Paused";
|
|
307
308
|
if (result.exitCode !== 0) return `Error: ${result.error ?? (firstOutputLine(output) || `exit ${result.exitCode}`)}`;
|
|
309
|
+
if (result.acceptance?.status && result.acceptance.status !== "not-required") return `Done · acceptance: ${result.acceptance.status}`;
|
|
308
310
|
if (hasEmptyTextOutputWithoutOutputTarget(result.task, output)) return "Done (no text output)";
|
|
309
311
|
return "Done";
|
|
310
312
|
}
|
|
@@ -507,26 +509,44 @@ function parseParallelGroupAgentCount(label: string | undefined): number | undef
|
|
|
507
509
|
return inner.split("+").map((part) => part.trim()).filter(Boolean).length;
|
|
508
510
|
}
|
|
509
511
|
|
|
510
|
-
function isChainParallelGroupActive(details: Pick<Details, "mode" | "chainAgents" | "currentStepIndex">): boolean {
|
|
511
|
-
if (details.mode !== "chain") return false;
|
|
512
|
-
if (details.currentStepIndex === undefined) return false;
|
|
513
|
-
const currentLabel = details.chainAgents?.[details.currentStepIndex];
|
|
514
|
-
return parseParallelGroupAgentCount(currentLabel) !== undefined;
|
|
515
|
-
}
|
|
516
|
-
|
|
517
512
|
interface ChainStepSpan {
|
|
518
513
|
stepIndex: number;
|
|
519
514
|
start: number;
|
|
520
515
|
count: number;
|
|
521
516
|
isParallel: boolean;
|
|
522
|
-
|
|
517
|
+
status?: WorkflowNodeStatus;
|
|
518
|
+
label?: string;
|
|
519
|
+
error?: string;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function buildChainStepSpans(details: Pick<Details, "chainAgents" | "workflowGraph">): ChainStepSpan[] {
|
|
523
|
+
if (details.workflowGraph?.nodes?.length) {
|
|
524
|
+
const spans: ChainStepSpan[] = [];
|
|
525
|
+
let flatCursor = 0;
|
|
526
|
+
for (const node of details.workflowGraph.nodes) {
|
|
527
|
+
if (node.stepIndex === undefined) continue;
|
|
528
|
+
if (node.kind === "parallel-group" || node.kind === "dynamic-parallel-group") {
|
|
529
|
+
const childFlatIndexes = (node.children ?? [])
|
|
530
|
+
.map((child) => child.flatIndex)
|
|
531
|
+
.filter((value): value is number => typeof value === "number");
|
|
532
|
+
const start = childFlatIndexes.length ? Math.min(...childFlatIndexes) : flatCursor;
|
|
533
|
+
const count = node.children?.length ?? 0;
|
|
534
|
+
spans.push({ stepIndex: node.stepIndex, start, count, isParallel: true, status: node.status, label: node.label, error: node.error });
|
|
535
|
+
flatCursor = Math.max(flatCursor, start + count);
|
|
536
|
+
continue;
|
|
537
|
+
}
|
|
538
|
+
const start = node.flatIndex ?? flatCursor;
|
|
539
|
+
spans.push({ stepIndex: node.stepIndex, start, count: 1, isParallel: false, status: node.status, label: node.label, error: node.error });
|
|
540
|
+
flatCursor = Math.max(flatCursor, start + 1);
|
|
541
|
+
}
|
|
542
|
+
if (spans.length) return spans.sort((left, right) => left.stepIndex - right.stepIndex);
|
|
543
|
+
}
|
|
523
544
|
|
|
524
|
-
|
|
525
|
-
if (!chainAgents?.length) return [];
|
|
545
|
+
if (!details.chainAgents?.length) return [];
|
|
526
546
|
const spans: ChainStepSpan[] = [];
|
|
527
547
|
let start = 0;
|
|
528
|
-
for (let stepIndex = 0; stepIndex < chainAgents.length; stepIndex++) {
|
|
529
|
-
const label = chainAgents[stepIndex]!;
|
|
548
|
+
for (let stepIndex = 0; stepIndex < details.chainAgents.length; stepIndex++) {
|
|
549
|
+
const label = details.chainAgents[stepIndex]!;
|
|
530
550
|
const parsedCount = parseParallelGroupAgentCount(label);
|
|
531
551
|
const count = parsedCount ?? 1;
|
|
532
552
|
spans.push({ stepIndex, start, count, isParallel: parsedCount !== undefined });
|
|
@@ -535,6 +555,12 @@ function buildChainStepSpans(chainAgents: string[] | undefined): ChainStepSpan[]
|
|
|
535
555
|
return spans;
|
|
536
556
|
}
|
|
537
557
|
|
|
558
|
+
function isChainParallelGroupActive(details: Pick<Details, "mode" | "chainAgents" | "currentStepIndex" | "workflowGraph">): boolean {
|
|
559
|
+
if (details.mode !== "chain") return false;
|
|
560
|
+
if (details.currentStepIndex === undefined) return false;
|
|
561
|
+
return buildChainStepSpans(details).some((span) => span.stepIndex === details.currentStepIndex && span.isParallel);
|
|
562
|
+
}
|
|
563
|
+
|
|
538
564
|
function buildAsyncChainStepSpans(total: number, stepCount: number, parallelGroups: AsyncParallelGroupStatus[] = []): ChainStepSpan[] {
|
|
539
565
|
const spans: ChainStepSpan[] = [];
|
|
540
566
|
let flatIndex = 0;
|
|
@@ -559,6 +585,55 @@ function isDoneResult(result: Details["results"][number]): boolean {
|
|
|
559
585
|
return result.exitCode === 0;
|
|
560
586
|
}
|
|
561
587
|
|
|
588
|
+
function workflowGraphHasStatus(details: Pick<Details, "workflowGraph">, statuses: WorkflowNodeStatus[]): boolean {
|
|
589
|
+
return details.workflowGraph?.nodes.some((node) => statuses.includes(node.status)) ?? false;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
interface ChainRenderResultEntry {
|
|
593
|
+
kind: "result";
|
|
594
|
+
resultIndex: number;
|
|
595
|
+
rowNumber: number;
|
|
596
|
+
agentName: string;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
interface ChainRenderPlaceholderEntry {
|
|
600
|
+
kind: "placeholder";
|
|
601
|
+
rowNumber: number;
|
|
602
|
+
stepLabel: string;
|
|
603
|
+
agentName: string;
|
|
604
|
+
status: WorkflowNodeStatus;
|
|
605
|
+
error?: string;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
type ChainRenderEntry = ChainRenderResultEntry | ChainRenderPlaceholderEntry;
|
|
609
|
+
|
|
610
|
+
function buildChainRenderEntries(details: Details, label: MultiProgressLabel): ChainRenderEntry[] | undefined {
|
|
611
|
+
if (details.mode !== "chain" || !label.hasParallelInChain || label.showActiveGroupOnly) return undefined;
|
|
612
|
+
const entries: ChainRenderEntry[] = [];
|
|
613
|
+
for (const span of buildChainStepSpans(details)) {
|
|
614
|
+
if (span.isParallel && span.count === 0) {
|
|
615
|
+
entries.push({
|
|
616
|
+
kind: "placeholder",
|
|
617
|
+
rowNumber: span.stepIndex + 1,
|
|
618
|
+
stepLabel: `Step ${span.stepIndex + 1}`,
|
|
619
|
+
agentName: span.label ?? details.chainAgents?.[span.stepIndex] ?? `step-${span.stepIndex + 1}`,
|
|
620
|
+
status: span.status ?? "pending",
|
|
621
|
+
error: span.error,
|
|
622
|
+
});
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
for (let index = span.start; index < span.start + span.count; index++) {
|
|
626
|
+
entries.push({
|
|
627
|
+
kind: "result",
|
|
628
|
+
resultIndex: index,
|
|
629
|
+
rowNumber: index + 1,
|
|
630
|
+
agentName: details.results[index]?.agent ?? details.chainAgents?.[span.stepIndex] ?? `step-${span.stepIndex + 1}`,
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return entries;
|
|
635
|
+
}
|
|
636
|
+
|
|
562
637
|
interface MultiProgressLabel {
|
|
563
638
|
headerLabel: string;
|
|
564
639
|
itemTitle: "Step" | "Agent";
|
|
@@ -570,8 +645,8 @@ interface MultiProgressLabel {
|
|
|
570
645
|
showActiveGroupOnly: boolean;
|
|
571
646
|
}
|
|
572
647
|
|
|
573
|
-
function buildMultiProgressLabel(details: Pick<Details, "mode" | "results" | "progress" | "totalSteps" | "currentStepIndex" | "chainAgents">, hasRunning: boolean): MultiProgressLabel {
|
|
574
|
-
const stepSpans = buildChainStepSpans(details
|
|
648
|
+
function buildMultiProgressLabel(details: Pick<Details, "mode" | "results" | "progress" | "totalSteps" | "currentStepIndex" | "chainAgents" | "workflowGraph">, hasRunning: boolean): MultiProgressLabel {
|
|
649
|
+
const stepSpans = buildChainStepSpans(details);
|
|
575
650
|
const hasParallelInChain = details.mode === "chain" && stepSpans.some((span) => span.isParallel);
|
|
576
651
|
const activeParallelGroup = isChainParallelGroupActive(details);
|
|
577
652
|
const itemTitle: "Step" | "Agent" = details.mode === "parallel" || activeParallelGroup ? "Agent" : "Step";
|
|
@@ -635,11 +710,13 @@ function buildMultiProgressLabel(details: Pick<Details, "mode" | "results" | "pr
|
|
|
635
710
|
if (details.mode === "chain" && details.chainAgents?.length) {
|
|
636
711
|
const totalCount = details.totalSteps ?? details.chainAgents.length;
|
|
637
712
|
const doneLogical = stepSpans.filter((span) => {
|
|
713
|
+
if (span.status && span.status !== "completed") return false;
|
|
714
|
+
if (span.count === 0) return span.status === "completed";
|
|
638
715
|
for (let index = span.start; index < span.start + span.count; index++) {
|
|
639
716
|
const progressEntry = details.progress?.find((progress) => progress.index === index);
|
|
640
717
|
const resultEntry = details.results.find((result) => result.progress?.index === index) ?? details.results[index];
|
|
641
|
-
if (progressEntry?.status === "running" || progressEntry?.status === "pending") return false;
|
|
642
|
-
if (resultEntry
|
|
718
|
+
if (progressEntry?.status === "running" || progressEntry?.status === "pending" || progressEntry?.status === "failed") return false;
|
|
719
|
+
if (!resultEntry || !isDoneResult(resultEntry)) return false;
|
|
643
720
|
}
|
|
644
721
|
return true;
|
|
645
722
|
}).length;
|
|
@@ -655,9 +732,9 @@ function buildMultiProgressLabel(details: Pick<Details, "mode" | "results" | "pr
|
|
|
655
732
|
return { headerLabel, itemTitle, totalCount, hasParallelInChain, activeParallelGroup, groupStartIndex: 0, groupEndIndex: details.results.length, showActiveGroupOnly: false };
|
|
656
733
|
}
|
|
657
734
|
|
|
658
|
-
function resultRowLabel(details: Pick<Details, "mode" | "chainAgents">, label: MultiProgressLabel, resultIndex: number, stepNumber: number): string {
|
|
735
|
+
function resultRowLabel(details: Pick<Details, "mode" | "chainAgents" | "workflowGraph">, label: MultiProgressLabel, resultIndex: number, stepNumber: number): string {
|
|
659
736
|
if (details.mode === "chain" && label.hasParallelInChain) {
|
|
660
|
-
const span = buildChainStepSpans(details
|
|
737
|
+
const span = buildChainStepSpans(details).find((candidate) => resultIndex >= candidate.start && resultIndex < candidate.start + candidate.count);
|
|
661
738
|
if (span?.isParallel) return `Agent ${resultIndex - span.start + 1}/${span.count}`;
|
|
662
739
|
if (span) return `Step ${span.stepIndex + 1}`;
|
|
663
740
|
}
|
|
@@ -1216,9 +1293,12 @@ function renderSingleCompact(d: Details, r: Details["results"][number], theme: T
|
|
|
1216
1293
|
|
|
1217
1294
|
function renderMultiCompact(d: Details, theme: Theme, now?: number, spinnerNow?: number): Component {
|
|
1218
1295
|
const hasRunning = d.progress?.some((p) => p.status === "running")
|
|
1219
|
-
|| d.results.some((r) => r.progress?.status === "running")
|
|
1220
|
-
|
|
1221
|
-
const
|
|
1296
|
+
|| d.results.some((r) => r.progress?.status === "running")
|
|
1297
|
+
|| workflowGraphHasStatus(d, ["running"]);
|
|
1298
|
+
const failed = d.results.some((r) => r.exitCode !== 0 && r.progress?.status !== "running")
|
|
1299
|
+
|| workflowGraphHasStatus(d, ["failed"]);
|
|
1300
|
+
const paused = d.results.some((r) => (r.interrupted || r.detached) && r.progress?.status !== "running")
|
|
1301
|
+
|| workflowGraphHasStatus(d, ["paused", "detached"]);
|
|
1222
1302
|
let totalSummary = d.progressSummary;
|
|
1223
1303
|
if (!totalSummary) {
|
|
1224
1304
|
let sawProgress = false;
|
|
@@ -1251,13 +1331,29 @@ function renderMultiCompact(d: Details, theme: Theme, now?: number, spinnerNow?:
|
|
|
1251
1331
|
const useResultsDirectly = multiLabel.hasParallelInChain || !d.chainAgents?.length;
|
|
1252
1332
|
const displayStart = multiLabel.showActiveGroupOnly ? multiLabel.groupStartIndex : 0;
|
|
1253
1333
|
const displayEnd = multiLabel.showActiveGroupOnly ? multiLabel.groupEndIndex : (useResultsDirectly ? d.results.length : d.chainAgents!.length);
|
|
1254
|
-
|
|
1334
|
+
const chainEntries = buildChainRenderEntries(d, multiLabel);
|
|
1335
|
+
const renderEntries = chainEntries ?? Array.from({ length: displayEnd - displayStart }, (_, offset): ChainRenderEntry => {
|
|
1336
|
+
const i = displayStart + offset;
|
|
1255
1337
|
const r = d.results[i];
|
|
1256
1338
|
const fallbackLabel = itemTitle.toLowerCase();
|
|
1257
1339
|
const rowNumber = multiLabel.showActiveGroupOnly ? (i - multiLabel.groupStartIndex + 1) : (i + 1);
|
|
1258
|
-
|
|
1340
|
+
return { kind: "result", resultIndex: i, rowNumber, agentName: useResultsDirectly ? (r?.agent || `${fallbackLabel}-${rowNumber}`) : (d.chainAgents![i] || r?.agent || `${fallbackLabel}-${rowNumber}`) };
|
|
1341
|
+
});
|
|
1342
|
+
for (const entry of renderEntries) {
|
|
1343
|
+
if (entry.kind === "placeholder") {
|
|
1344
|
+
const glyph = widgetStepGlyph(entry.status as AsyncJobStep["status"], theme);
|
|
1345
|
+
const statusLabel = widgetStepStatus(entry.status as AsyncJobStep["status"], theme);
|
|
1346
|
+
c.addChild(new Text(truncLine(` ${glyph} ${entry.stepLabel}: ${themeBold(theme, entry.agentName)} ${theme.fg("dim", "·")} ${statusLabel}`, width), 0, 0));
|
|
1347
|
+
if (entry.error) c.addChild(new Text(truncLine(theme.fg("error", ` ⎿ Error: ${entry.error}`), width), 0, 0));
|
|
1348
|
+
continue;
|
|
1349
|
+
}
|
|
1350
|
+
const i = entry.resultIndex;
|
|
1351
|
+
const r = d.results[i];
|
|
1352
|
+
const rowNumber = entry.rowNumber;
|
|
1353
|
+
const agentName = entry.agentName;
|
|
1259
1354
|
if (!r) {
|
|
1260
|
-
|
|
1355
|
+
const pendingLabel = chainEntries ? resultRowLabel(d, multiLabel, i, rowNumber) : `${itemTitle} ${rowNumber}`;
|
|
1356
|
+
c.addChild(new Text(truncLine(theme.fg("dim", ` ◦ ${pendingLabel}: ${agentName} · pending`), width), 0, 0));
|
|
1261
1357
|
continue;
|
|
1262
1358
|
}
|
|
1263
1359
|
const output = getSingleResultOutput(r);
|
|
@@ -1489,20 +1585,27 @@ export function renderSubagentResult(
|
|
|
1489
1585
|
if (!expanded) return renderMultiCompact(d, theme, options.now, options.spinnerNow);
|
|
1490
1586
|
|
|
1491
1587
|
const hasRunning = d.progress?.some((p) => p.status === "running")
|
|
1492
|
-
|| d.results.some((r) => r.progress?.status === "running")
|
|
1588
|
+
|| d.results.some((r) => r.progress?.status === "running")
|
|
1589
|
+
|| workflowGraphHasStatus(d, ["running"]);
|
|
1493
1590
|
const ok = d.results.filter((r) => r.progress?.status === "completed" || (r.exitCode === 0 && r.progress?.status !== "running")).length;
|
|
1494
1591
|
const hasEmptyWithoutTarget = d.results.some((r) =>
|
|
1495
1592
|
r.exitCode === 0
|
|
1496
1593
|
&& r.progress?.status !== "running"
|
|
1497
1594
|
&& hasEmptyTextOutputWithoutOutputTarget(r.task, getSingleResultOutput(r)),
|
|
1498
1595
|
);
|
|
1596
|
+
const hasWorkflowFailure = workflowGraphHasStatus(d, ["failed"]);
|
|
1597
|
+
const hasWorkflowPause = workflowGraphHasStatus(d, ["paused", "detached"]);
|
|
1499
1598
|
const icon = hasRunning
|
|
1500
1599
|
? theme.fg("warning", "running")
|
|
1501
1600
|
: hasEmptyWithoutTarget
|
|
1502
1601
|
? theme.fg("warning", "warning")
|
|
1503
|
-
:
|
|
1504
|
-
? theme.fg("
|
|
1505
|
-
:
|
|
1602
|
+
: hasWorkflowFailure
|
|
1603
|
+
? theme.fg("error", "failed")
|
|
1604
|
+
: hasWorkflowPause
|
|
1605
|
+
? theme.fg("warning", "paused")
|
|
1606
|
+
: ok === d.results.length
|
|
1607
|
+
? theme.fg("success", "ok")
|
|
1608
|
+
: theme.fg("error", "failed");
|
|
1506
1609
|
|
|
1507
1610
|
const totalSummary =
|
|
1508
1611
|
d.progressSummary ||
|
|
@@ -1573,18 +1676,33 @@ export function renderSubagentResult(
|
|
|
1573
1676
|
const useResultsDirectly = multiLabel.hasParallelInChain || !d.chainAgents?.length;
|
|
1574
1677
|
const displayStart = multiLabel.showActiveGroupOnly ? multiLabel.groupStartIndex : 0;
|
|
1575
1678
|
const displayEnd = multiLabel.showActiveGroupOnly ? multiLabel.groupEndIndex : (useResultsDirectly ? d.results.length : d.chainAgents!.length);
|
|
1679
|
+
const chainEntries = buildChainRenderEntries(d, multiLabel);
|
|
1680
|
+
const renderEntries = chainEntries ?? Array.from({ length: displayEnd - displayStart }, (_, offset): ChainRenderEntry => {
|
|
1681
|
+
const i = displayStart + offset;
|
|
1682
|
+
const r = d.results[i];
|
|
1683
|
+
const rowNumber = multiLabel.showActiveGroupOnly ? (i - multiLabel.groupStartIndex + 1) : (i + 1);
|
|
1684
|
+
return { kind: "result", resultIndex: i, rowNumber, agentName: useResultsDirectly ? (r?.agent || `step-${rowNumber}`) : (d.chainAgents![i] || r?.agent || `step-${rowNumber}`) };
|
|
1685
|
+
});
|
|
1576
1686
|
|
|
1577
1687
|
c.addChild(new Spacer(1));
|
|
1578
1688
|
|
|
1579
|
-
for (
|
|
1689
|
+
for (const entry of renderEntries) {
|
|
1690
|
+
if (entry.kind === "placeholder") {
|
|
1691
|
+
const statusLabel = widgetStepStatus(entry.status as AsyncJobStep["status"], theme);
|
|
1692
|
+
c.addChild(new Text(fit(` ${statusLabel} ${entry.stepLabel}: ${theme.bold(entry.agentName)}`), 0, 0));
|
|
1693
|
+
c.addChild(new Text(theme.fg(entry.status === "failed" ? "error" : "dim", ` status: ${entry.status}`), 0, 0));
|
|
1694
|
+
if (entry.error) c.addChild(new Text(theme.fg("error", ` error: ${entry.error}`), 0, 0));
|
|
1695
|
+
c.addChild(new Spacer(1));
|
|
1696
|
+
continue;
|
|
1697
|
+
}
|
|
1698
|
+
const i = entry.resultIndex;
|
|
1580
1699
|
const r = d.results[i];
|
|
1581
|
-
const rowNumber =
|
|
1582
|
-
const agentName =
|
|
1583
|
-
? (r?.agent || `step-${rowNumber}`)
|
|
1584
|
-
: (d.chainAgents![i] || r?.agent || `step-${rowNumber}`);
|
|
1700
|
+
const rowNumber = entry.rowNumber;
|
|
1701
|
+
const agentName = entry.agentName;
|
|
1585
1702
|
|
|
1586
1703
|
if (!r) {
|
|
1587
|
-
|
|
1704
|
+
const pendingLabel = chainEntries ? resultRowLabel(d, multiLabel, i, rowNumber) : `${itemTitle} ${rowNumber}`;
|
|
1705
|
+
c.addChild(new Text(fit(theme.fg("dim", ` ${pendingLabel}: ${agentName}`)), 0, 0));
|
|
1588
1706
|
c.addChild(new Text(theme.fg("dim", ` status: pending`), 0, 0));
|
|
1589
1707
|
c.addChild(new Spacer(1));
|
|
1590
1708
|
continue;
|
|
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.8.24-alpha.3] - 2026-06-03
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Bumped package version for the Atomic 0.8.24-alpha.3 prerelease.
|
|
12
|
+
|
|
13
|
+
## [0.8.24-alpha.2] - 2026-06-03
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- Bumped package version for the Atomic 0.8.24-alpha.2 prerelease.
|
|
18
|
+
|
|
7
19
|
## [0.8.24-alpha.1] - 2026-06-02
|
|
8
20
|
|
|
9
21
|
### Changed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bastani/web-access",
|
|
3
|
-
"version": "0.8.24-alpha.
|
|
3
|
+
"version": "0.8.24-alpha.3",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
|
|
6
6
|
"contributors": [
|
|
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.8.24-alpha.3] - 2026-06-03
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- Bumped package version for the Atomic 0.8.24-alpha.3 prerelease.
|
|
14
|
+
|
|
15
|
+
## [0.8.24-alpha.2] - 2026-06-03
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- The `@bastani/workflows` authoring SDK types are now externally resolvable in installed packages through `@bastani/atomic`'s new `./workflows` exports and ambient bridge, so workflow files type-check `import { defineWorkflow, Type } from "@bastani/workflows"` (and `@bastani/workflows/builtin/*`) under `tsc` (NodeNext) without a hand-authored `.d.ts`, `declare module` shim, or `paths` alias. Workflow packages declare `@bastani/atomic` and `typebox` as peer dependencies; the package continues to distribute raw TypeScript with no build step, and the runtime virtual-module loader is unchanged ([#1208](https://github.com/bastani-inc/atomic/issues/1208)).
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- Fixed builtin (and any) workflows falling back to the user's currently selected model instead of the stage's defined model. A fully-qualified `provider/model` id that the live model catalog did not list was treated as a hard "not available" failure; because candidate validation throws on any failure and the catalog resolver catches that throw and collapses the whole ordered candidate list down to the user's `currentModel`, a single absent cross-provider fallback discarded the defined primary plus every fallback. Provider-qualified ids are now trusted (passed through with the reasoning suffix split off the last colon), mirroring the subagent resolver, so the defined primary is used and only genuinely failing candidates fall through at runtime. Regressed when bundled workflow model lists were refreshed onto newer multi-provider ids alongside suffix-first reasoning levels ([#1199](https://github.com/bastani-inc/atomic/issues/1199)).
|
|
24
|
+
|
|
9
25
|
## [0.8.24-alpha.1] - 2026-06-02
|
|
10
26
|
|
|
11
27
|
### Breaking Changes
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// AUTO-GENERATED by scripts/copy-builtin-packages.ts (issue #1208). Do not edit by hand.
|
|
2
|
+
//
|
|
3
|
+
// Ambient bridge so the documented bare specifier `@bastani/workflows` (and its
|
|
4
|
+
// `builtin/*` submodules) type-check in installed packages that depend only on
|
|
5
|
+
// @bastani/atomic. Runtime resolution is unchanged: Atomic's jiti virtual-module
|
|
6
|
+
// loader still supplies the real SDK when workflow files load; these declarations
|
|
7
|
+
// only affect `tsc`. Each module is declared in exactly one file to avoid
|
|
8
|
+
// TS2666 / duplicate-identifier errors.
|
|
9
|
+
|
|
10
|
+
declare module "@bastani/workflows" {
|
|
11
|
+
export * from "@bastani/atomic/workflows";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare module "@bastani/workflows/builtin" {
|
|
15
|
+
export * from "@bastani/atomic/workflows/builtin";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
declare module "@bastani/workflows/builtin/deep-research-codebase" {
|
|
19
|
+
export * from "@bastani/atomic/workflows/builtin/deep-research-codebase";
|
|
20
|
+
export { default } from "@bastani/atomic/workflows/builtin/deep-research-codebase";
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
declare module "@bastani/workflows/builtin/goal" {
|
|
24
|
+
export * from "@bastani/atomic/workflows/builtin/goal";
|
|
25
|
+
export { default } from "@bastani/atomic/workflows/builtin/goal";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
declare module "@bastani/workflows/builtin/open-claude-design" {
|
|
29
|
+
export * from "@bastani/atomic/workflows/builtin/open-claude-design";
|
|
30
|
+
export { default } from "@bastani/atomic/workflows/builtin/open-claude-design";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
declare module "@bastani/workflows/builtin/ralph" {
|
|
34
|
+
export * from "@bastani/atomic/workflows/builtin/ralph";
|
|
35
|
+
export { default } from "@bastani/atomic/workflows/builtin/ralph";
|
|
36
|
+
}
|
|
@@ -288,4 +288,4 @@ _Instruction: List known unknowns. These must be resolved before the doc is mark
|
|
|
288
288
|
- [ ] Is `publish_draft` the only door that moves a draft to live, or can the admin panel also publish? (If the latter, the effect is not yet funneled — rubric #8.)
|
|
289
289
|
- [ ] What exactly does `authorize_charge` promise on a partial provider outage — is the guarantee defined? (rubric #2.)
|
|
290
290
|
- [ ] Will the Legal team approve the 3rd-party library for PDF generation?
|
|
291
|
-
- [ ] Does the current VPC peering allow connection to the legacy mainframe?
|
|
291
|
+
- [ ] Does the current VPC peering allow connection to the legacy mainframe?
|