agent-contracts 0.7.1 → 0.8.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/README.md +22 -4
- package/dist/cli.js +428 -31
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +81 -1
- package/dist/index.js +429 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -204,15 +204,30 @@ An **Artifact** defines the objects that move through the workflow:
|
|
|
204
204
|
* required validations
|
|
205
205
|
* visibility
|
|
206
206
|
|
|
207
|
+
### Tool
|
|
208
|
+
|
|
209
|
+
A **Tool** defines an invokable CLI/MCP tool:
|
|
210
|
+
|
|
211
|
+
* kind (cli, mcp, etc.)
|
|
212
|
+
* input/output artifacts
|
|
213
|
+
* invokable_by (which agents can use it)
|
|
214
|
+
* `commands` — structured list of sub-commands with `category`, `reads`, `writes`, and `purpose`
|
|
215
|
+
|
|
207
216
|
### Workflow
|
|
208
217
|
|
|
209
218
|
A **Workflow** defines a phase-level execution sequence:
|
|
210
219
|
|
|
211
|
-
* description
|
|
212
|
-
*
|
|
213
|
-
* trigger
|
|
220
|
+
* `description` — human-readable summary
|
|
221
|
+
* `entry_conditions`
|
|
222
|
+
* `trigger`
|
|
223
|
+
* `external_participants` — actors/participants outside the agent system (e.g., User, external advisory)
|
|
214
224
|
* ordered steps (handoff, validation, decision)
|
|
215
225
|
|
|
226
|
+
Workflow steps support additional properties:
|
|
227
|
+
|
|
228
|
+
* `group` — consecutive steps with the same group are rendered as `par` (parallel) blocks in sequence diagrams
|
|
229
|
+
* `retry` (handoff steps only) — defines a conditional retry loop with `condition`, `fix_task`, and optional `revalidate_task`
|
|
230
|
+
|
|
216
231
|
### Handoff
|
|
217
232
|
|
|
218
233
|
A **Handoff** is a runtime delegation instance.
|
|
@@ -761,7 +776,8 @@ Templates can use these built-in helpers:
|
|
|
761
776
|
| `or` | `{{#if (or a b)}}` | Boolean OR (variadic) |
|
|
762
777
|
| `and` | `{{#if (and a b)}}` | Boolean AND (variadic) |
|
|
763
778
|
| `gt` / `gte` / `lt` | `{{#if (gt a b)}}` | Numeric comparisons |
|
|
764
|
-
| `sequenceDiagram` | `{{{sequenceDiagram}}}` | Generate Mermaid sequence diagram
|
|
779
|
+
| `sequenceDiagram` | `{{{sequenceDiagram}}}` or `{{{sequenceDiagram @key ../dsl}}}` | Generate Mermaid sequence diagram. Supports `external_participants`, `group` (par blocks), `retry` (opt blocks), and read-only agent separation into Audit box |
|
|
780
|
+
| `overviewFlowchart` | `{{{overviewFlowchart dsl}}}` | Generate Mermaid graph showing phases → agents/tools/artifacts relationships (system context) |
|
|
765
781
|
|
|
766
782
|
---
|
|
767
783
|
|
|
@@ -800,6 +816,8 @@ Checks:
|
|
|
800
816
|
* merge integrity
|
|
801
817
|
* read-only write violations
|
|
802
818
|
* prerequisite readability
|
|
819
|
+
* artifact ownership — `produces_artifact`/`reads_artifact` in execution steps vs. artifact producers/editors/consumers
|
|
820
|
+
* tool commands — `commands[].reads`/`commands[].writes` reference valid artifacts and align with `output_artifacts`
|
|
803
821
|
* naming/style issues through Spectral rules
|
|
804
822
|
|
|
805
823
|
---
|
package/dist/cli.js
CHANGED
|
@@ -59180,13 +59180,21 @@ var TaskSchema = z7.object({
|
|
|
59180
59180
|
|
|
59181
59181
|
// src/schema/tool.ts
|
|
59182
59182
|
import { z as z8 } from "zod";
|
|
59183
|
+
var CommandSchema = z8.object({
|
|
59184
|
+
command: z8.string(),
|
|
59185
|
+
category: z8.string(),
|
|
59186
|
+
reads: z8.array(z8.string()).default([]),
|
|
59187
|
+
writes: z8.array(z8.string()).default([]),
|
|
59188
|
+
purpose: z8.string().optional()
|
|
59189
|
+
});
|
|
59183
59190
|
var ToolSchema = z8.object({
|
|
59184
59191
|
kind: z8.string(),
|
|
59185
59192
|
description: z8.string().optional(),
|
|
59186
59193
|
input_artifacts: z8.array(z8.string()).default([]),
|
|
59187
59194
|
output_artifacts: z8.array(z8.string()).default([]),
|
|
59188
59195
|
invokable_by: z8.array(z8.string()),
|
|
59189
|
-
side_effects: z8.array(z8.string()).default([])
|
|
59196
|
+
side_effects: z8.array(z8.string()).default([]),
|
|
59197
|
+
commands: z8.array(CommandSchema).default([])
|
|
59190
59198
|
}).passthrough();
|
|
59191
59199
|
|
|
59192
59200
|
// src/schema/validation.ts
|
|
@@ -59202,23 +59210,38 @@ var ValidationSchema = z9.object({
|
|
|
59202
59210
|
|
|
59203
59211
|
// src/schema/workflow.ts
|
|
59204
59212
|
import { z as z10 } from "zod";
|
|
59213
|
+
var RetrySchema = z10.object({
|
|
59214
|
+
condition: z10.string(),
|
|
59215
|
+
fix_task: z10.string(),
|
|
59216
|
+
revalidate_task: z10.string().optional()
|
|
59217
|
+
});
|
|
59218
|
+
var ExternalParticipantSchema = z10.object({
|
|
59219
|
+
id: z10.string(),
|
|
59220
|
+
kind: z10.enum(["actor", "participant"]),
|
|
59221
|
+
label: z10.string(),
|
|
59222
|
+
description: z10.string().optional()
|
|
59223
|
+
});
|
|
59205
59224
|
var WorkflowHandoffStepSchema = z10.object({
|
|
59206
59225
|
type: z10.literal("handoff"),
|
|
59207
59226
|
description: z10.string().optional(),
|
|
59208
59227
|
handoff_kind: z10.string(),
|
|
59209
59228
|
task: z10.string().optional(),
|
|
59210
|
-
from_agent: z10.string().optional()
|
|
59229
|
+
from_agent: z10.string().optional(),
|
|
59230
|
+
group: z10.string().optional(),
|
|
59231
|
+
retry: RetrySchema.optional()
|
|
59211
59232
|
}).passthrough();
|
|
59212
59233
|
var WorkflowValidationStepSchema = z10.object({
|
|
59213
59234
|
type: z10.literal("validation"),
|
|
59214
59235
|
description: z10.string().optional(),
|
|
59215
|
-
validation: z10.string()
|
|
59236
|
+
validation: z10.string(),
|
|
59237
|
+
group: z10.string().optional()
|
|
59216
59238
|
}).passthrough();
|
|
59217
59239
|
var WorkflowDecisionStepSchema = z10.object({
|
|
59218
59240
|
type: z10.literal("decision"),
|
|
59219
59241
|
description: z10.string().optional(),
|
|
59220
59242
|
on: z10.string(),
|
|
59221
|
-
branches: z10.record(z10.string(), z10.array(z10.string()))
|
|
59243
|
+
branches: z10.record(z10.string(), z10.array(z10.string())),
|
|
59244
|
+
group: z10.string().optional()
|
|
59222
59245
|
}).passthrough();
|
|
59223
59246
|
var WorkflowStepSchema = z10.discriminatedUnion("type", [
|
|
59224
59247
|
WorkflowHandoffStepSchema,
|
|
@@ -59229,7 +59252,8 @@ var WorkflowSchema = z10.object({
|
|
|
59229
59252
|
description: z10.string().optional(),
|
|
59230
59253
|
entry_conditions: z10.array(z10.string()).default([]),
|
|
59231
59254
|
trigger: z10.string().optional(),
|
|
59232
|
-
steps: z10.array(WorkflowStepSchema)
|
|
59255
|
+
steps: z10.array(WorkflowStepSchema),
|
|
59256
|
+
external_participants: z10.array(ExternalParticipantSchema).default([])
|
|
59233
59257
|
}).passthrough();
|
|
59234
59258
|
|
|
59235
59259
|
// src/schema/dsl.ts
|
|
@@ -59846,12 +59870,100 @@ var mergeIntegrityRule = {
|
|
|
59846
59870
|
}
|
|
59847
59871
|
};
|
|
59848
59872
|
|
|
59873
|
+
// src/linter/rules/artifact-ownership.ts
|
|
59874
|
+
var artifactOwnershipRule = {
|
|
59875
|
+
id: "artifact-ownership",
|
|
59876
|
+
description: "Ensure execution_step produces/reads operations are consistent with artifact producers/editors/consumers",
|
|
59877
|
+
run(dsl) {
|
|
59878
|
+
const diagnostics = [];
|
|
59879
|
+
for (const [taskId, task] of Object.entries(dsl.tasks)) {
|
|
59880
|
+
if (!task.execution_steps) continue;
|
|
59881
|
+
const agentId = task.target_agent;
|
|
59882
|
+
for (const step of task.execution_steps) {
|
|
59883
|
+
if (step.produces_artifact) {
|
|
59884
|
+
const artifact = dsl.artifacts[step.produces_artifact];
|
|
59885
|
+
if (artifact) {
|
|
59886
|
+
const canWrite = artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
|
|
59887
|
+
if (!canWrite) {
|
|
59888
|
+
diagnostics.push({
|
|
59889
|
+
ruleId: "artifact-ownership",
|
|
59890
|
+
severity: "warning",
|
|
59891
|
+
path: `tasks.${taskId}.execution_steps`,
|
|
59892
|
+
message: `Agent "${agentId}" produces artifact "${step.produces_artifact}" but is not listed in its producers or editors`
|
|
59893
|
+
});
|
|
59894
|
+
}
|
|
59895
|
+
}
|
|
59896
|
+
}
|
|
59897
|
+
if (step.reads_artifact) {
|
|
59898
|
+
const artifact = dsl.artifacts[step.reads_artifact];
|
|
59899
|
+
if (artifact) {
|
|
59900
|
+
const canRead = artifact.consumers.includes(agentId) || artifact.producers.includes(agentId) || artifact.editors.includes(agentId);
|
|
59901
|
+
if (!canRead) {
|
|
59902
|
+
diagnostics.push({
|
|
59903
|
+
ruleId: "artifact-ownership",
|
|
59904
|
+
severity: "warning",
|
|
59905
|
+
path: `tasks.${taskId}.execution_steps`,
|
|
59906
|
+
message: `Agent "${agentId}" reads artifact "${step.reads_artifact}" but is not listed in its producers, editors, or consumers`
|
|
59907
|
+
});
|
|
59908
|
+
}
|
|
59909
|
+
}
|
|
59910
|
+
}
|
|
59911
|
+
}
|
|
59912
|
+
}
|
|
59913
|
+
return diagnostics;
|
|
59914
|
+
}
|
|
59915
|
+
};
|
|
59916
|
+
|
|
59917
|
+
// src/linter/rules/tool-commands.ts
|
|
59918
|
+
var toolCommandsRule = {
|
|
59919
|
+
id: "tool-commands",
|
|
59920
|
+
description: "Validate tool commands: reads/writes reference existing artifacts; writes align with output_artifacts",
|
|
59921
|
+
run(dsl) {
|
|
59922
|
+
const diagnostics = [];
|
|
59923
|
+
for (const [toolId, tool] of Object.entries(dsl.tools)) {
|
|
59924
|
+
for (const cmd of tool.commands) {
|
|
59925
|
+
for (const ref of cmd.reads) {
|
|
59926
|
+
if (!dsl.artifacts[ref]) {
|
|
59927
|
+
diagnostics.push({
|
|
59928
|
+
ruleId: "tool-commands",
|
|
59929
|
+
severity: "error",
|
|
59930
|
+
path: `tools.${toolId}.commands`,
|
|
59931
|
+
message: `Command "${cmd.command}" reads artifact "${ref}" which does not exist`
|
|
59932
|
+
});
|
|
59933
|
+
}
|
|
59934
|
+
}
|
|
59935
|
+
for (const ref of cmd.writes) {
|
|
59936
|
+
if (!dsl.artifacts[ref]) {
|
|
59937
|
+
diagnostics.push({
|
|
59938
|
+
ruleId: "tool-commands",
|
|
59939
|
+
severity: "error",
|
|
59940
|
+
path: `tools.${toolId}.commands`,
|
|
59941
|
+
message: `Command "${cmd.command}" writes artifact "${ref}" which does not exist`
|
|
59942
|
+
});
|
|
59943
|
+
}
|
|
59944
|
+
if (dsl.artifacts[ref] && !tool.output_artifacts.includes(ref)) {
|
|
59945
|
+
diagnostics.push({
|
|
59946
|
+
ruleId: "tool-commands",
|
|
59947
|
+
severity: "warning",
|
|
59948
|
+
path: `tools.${toolId}.commands`,
|
|
59949
|
+
message: `Command "${cmd.command}" writes artifact "${ref}" but tool's output_artifacts does not include it`
|
|
59950
|
+
});
|
|
59951
|
+
}
|
|
59952
|
+
}
|
|
59953
|
+
}
|
|
59954
|
+
}
|
|
59955
|
+
return diagnostics;
|
|
59956
|
+
}
|
|
59957
|
+
};
|
|
59958
|
+
|
|
59849
59959
|
// src/linter/linter.ts
|
|
59850
59960
|
var builtinRules = [
|
|
59851
59961
|
validationCoverageRule,
|
|
59852
59962
|
toolExecutionRule,
|
|
59853
59963
|
taskAgentBindingRule,
|
|
59854
|
-
mergeIntegrityRule
|
|
59964
|
+
mergeIntegrityRule,
|
|
59965
|
+
artifactOwnershipRule,
|
|
59966
|
+
toolCommandsRule
|
|
59855
59967
|
];
|
|
59856
59968
|
function lint(dsl, rules = builtinRules) {
|
|
59857
59969
|
const diagnostics = [];
|
|
@@ -60813,40 +60925,63 @@ function agentAlias(id, agent) {
|
|
|
60813
60925
|
}
|
|
60814
60926
|
function collectReferencedIds(workflow, dsl, relatedTasks) {
|
|
60815
60927
|
const agents = /* @__PURE__ */ new Set();
|
|
60928
|
+
const auditAgents = /* @__PURE__ */ new Set();
|
|
60816
60929
|
const tools = /* @__PURE__ */ new Set();
|
|
60817
60930
|
const artifacts = /* @__PURE__ */ new Set();
|
|
60818
60931
|
const taskMap = /* @__PURE__ */ new Map();
|
|
60819
60932
|
for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
|
|
60820
60933
|
for (const step of workflow.steps) {
|
|
60821
60934
|
if (step.type === "handoff") {
|
|
60822
|
-
if (step.from_agent)
|
|
60935
|
+
if (step.from_agent) addAgent(step.from_agent);
|
|
60823
60936
|
if (step.task) {
|
|
60824
60937
|
const task = taskMap.get(step.task);
|
|
60825
60938
|
if (task) {
|
|
60826
|
-
|
|
60939
|
+
addAgent(task.target_agent);
|
|
60827
60940
|
for (const es of task.execution_steps ?? []) {
|
|
60828
60941
|
collectExecutionStepIds(es, tools, artifacts);
|
|
60829
60942
|
}
|
|
60830
60943
|
}
|
|
60831
60944
|
}
|
|
60945
|
+
if (step.retry) {
|
|
60946
|
+
const fixTask = taskMap.get(step.retry.fix_task);
|
|
60947
|
+
if (fixTask) {
|
|
60948
|
+
addAgent(fixTask.target_agent);
|
|
60949
|
+
for (const es of fixTask.execution_steps ?? []) {
|
|
60950
|
+
collectExecutionStepIds(es, tools, artifacts);
|
|
60951
|
+
}
|
|
60952
|
+
}
|
|
60953
|
+
if (step.retry.revalidate_task) {
|
|
60954
|
+
const revalTask = taskMap.get(step.retry.revalidate_task);
|
|
60955
|
+
if (revalTask) {
|
|
60956
|
+
addAgent(revalTask.target_agent);
|
|
60957
|
+
}
|
|
60958
|
+
}
|
|
60959
|
+
}
|
|
60832
60960
|
} else if (step.type === "validation") {
|
|
60833
60961
|
const val = dsl.validations[step.validation];
|
|
60834
60962
|
if (val) {
|
|
60835
|
-
if (val.executor_type === "agent")
|
|
60963
|
+
if (val.executor_type === "agent") addAgent(val.executor);
|
|
60836
60964
|
else tools.add(val.executor);
|
|
60837
60965
|
artifacts.add(val.target_artifact);
|
|
60838
60966
|
}
|
|
60839
|
-
} else if (step.type === "decision") {
|
|
60840
60967
|
}
|
|
60841
60968
|
}
|
|
60842
|
-
|
|
60969
|
+
function addAgent(agentId) {
|
|
60970
|
+
const agent = dsl.agents[agentId];
|
|
60971
|
+
if (agent?.mode === "read-only") {
|
|
60972
|
+
auditAgents.add(agentId);
|
|
60973
|
+
} else {
|
|
60974
|
+
agents.add(agentId);
|
|
60975
|
+
}
|
|
60976
|
+
}
|
|
60977
|
+
return { agents, auditAgents, tools, artifacts };
|
|
60843
60978
|
}
|
|
60844
60979
|
function collectExecutionStepIds(es, tools, artifacts) {
|
|
60845
60980
|
if (es.uses_tool) tools.add(es.uses_tool);
|
|
60846
60981
|
if (es.produces_artifact) artifacts.add(es.produces_artifact);
|
|
60847
60982
|
if (es.reads_artifact) artifacts.add(es.reads_artifact);
|
|
60848
60983
|
}
|
|
60849
|
-
function buildParticipants(ids, dsl) {
|
|
60984
|
+
function buildParticipants(ids, externals, dsl) {
|
|
60850
60985
|
const participants = [];
|
|
60851
60986
|
const usedAliases = /* @__PURE__ */ new Set();
|
|
60852
60987
|
function uniqueAlias(preferred) {
|
|
@@ -60859,12 +60994,22 @@ function buildParticipants(ids, dsl) {
|
|
|
60859
60994
|
usedAliases.add(alias);
|
|
60860
60995
|
return alias;
|
|
60861
60996
|
}
|
|
60997
|
+
for (const ep of externals) {
|
|
60998
|
+
const alias = uniqueAlias(sanitizeAlias(ep.id));
|
|
60999
|
+
participants.push({ id: ep.id, alias, label: ep.label, group: "external" });
|
|
61000
|
+
}
|
|
60862
61001
|
for (const id of ids.agents) {
|
|
60863
61002
|
const agent = dsl.agents[id];
|
|
60864
61003
|
if (!agent) continue;
|
|
60865
61004
|
const alias = uniqueAlias(agentAlias(id, agent));
|
|
60866
61005
|
participants.push({ id, alias, label: agent.role_name, group: "agents" });
|
|
60867
61006
|
}
|
|
61007
|
+
for (const id of ids.auditAgents) {
|
|
61008
|
+
const agent = dsl.agents[id];
|
|
61009
|
+
if (!agent) continue;
|
|
61010
|
+
const alias = uniqueAlias(agentAlias(id, agent));
|
|
61011
|
+
participants.push({ id, alias, label: agent.role_name, group: "audit" });
|
|
61012
|
+
}
|
|
60868
61013
|
for (const id of ids.tools) {
|
|
60869
61014
|
const tool = dsl.tools[id];
|
|
60870
61015
|
if (!tool) continue;
|
|
@@ -60883,15 +61028,33 @@ function participantAlias(participants, id) {
|
|
|
60883
61028
|
const p2 = participants.find((pp) => pp.id === id);
|
|
60884
61029
|
return p2 ? p2.alias : sanitizeAlias(id);
|
|
60885
61030
|
}
|
|
60886
|
-
function emitParticipants(participants, lines, indent) {
|
|
61031
|
+
function emitParticipants(participants, externals, lines, indent) {
|
|
60887
61032
|
const groups = {
|
|
61033
|
+
external: [],
|
|
60888
61034
|
agents: [],
|
|
61035
|
+
audit: [],
|
|
60889
61036
|
toolchain: [],
|
|
60890
61037
|
artifacts: []
|
|
60891
61038
|
};
|
|
60892
61039
|
for (const p2 of participants) groups[p2.group].push(p2);
|
|
61040
|
+
const externalMap = /* @__PURE__ */ new Map();
|
|
61041
|
+
for (const ep of externals) externalMap.set(ep.id, ep);
|
|
61042
|
+
if (groups.external.length > 0) {
|
|
61043
|
+
lines.push(`${indent}box rgb(255,245,230) External`);
|
|
61044
|
+
for (const p2 of groups.external) {
|
|
61045
|
+
const ep = externalMap.get(p2.id);
|
|
61046
|
+
const keyword = ep?.kind === "actor" ? "actor" : "participant";
|
|
61047
|
+
if (p2.alias === p2.label) {
|
|
61048
|
+
lines.push(`${indent}${keyword} ${p2.alias}`);
|
|
61049
|
+
} else {
|
|
61050
|
+
lines.push(`${indent}${keyword} ${p2.alias} as ${p2.label}`);
|
|
61051
|
+
}
|
|
61052
|
+
}
|
|
61053
|
+
lines.push(`${indent}end`);
|
|
61054
|
+
}
|
|
60893
61055
|
const groupConfig = [
|
|
60894
61056
|
{ key: "agents", label: "Agents", color: "rgb(200,220,255)" },
|
|
61057
|
+
{ key: "audit", label: "Audit", color: "rgb(255,220,220)" },
|
|
60895
61058
|
{ key: "toolchain", label: "Toolchain", color: "rgb(220,255,220)" },
|
|
60896
61059
|
{ key: "artifacts", label: "Artifacts", color: "rgb(255,230,210)" }
|
|
60897
61060
|
];
|
|
@@ -60967,7 +61130,7 @@ function emitValidationStep(step, participants, dsl, lastFromAgent, lines, inden
|
|
|
60967
61130
|
function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
|
|
60968
61131
|
const branches = Object.entries(step.branches);
|
|
60969
61132
|
if (branches.length === 0) return;
|
|
60970
|
-
const
|
|
61133
|
+
const agentAl = lastFromAgent ? participantAlias(participants, lastFromAgent) : null;
|
|
60971
61134
|
for (let i3 = 0; i3 < branches.length; i3++) {
|
|
60972
61135
|
const [key, values] = branches[i3];
|
|
60973
61136
|
if (i3 === 0) {
|
|
@@ -60975,21 +61138,78 @@ function emitDecisionStep(step, participants, lastFromAgent, lines, indent) {
|
|
|
60975
61138
|
} else {
|
|
60976
61139
|
lines.push(`${indent}else ${key}`);
|
|
60977
61140
|
}
|
|
60978
|
-
if (
|
|
60979
|
-
lines.push(`${indent} Note over ${
|
|
60980
|
-
} else {
|
|
60981
|
-
lines.push(`${indent} Note right of ${participantAlias(participants, [.../* @__PURE__ */ new Set()].join(""))}: ${values.join(", ")}`);
|
|
61141
|
+
if (agentAl) {
|
|
61142
|
+
lines.push(`${indent} Note over ${agentAl}: ${values.join(", ")}`);
|
|
60982
61143
|
}
|
|
60983
61144
|
}
|
|
60984
61145
|
lines.push(`${indent}end`);
|
|
60985
61146
|
}
|
|
61147
|
+
function emitRetryBlock(step, participants, dsl, relatedTasks, lines, indent) {
|
|
61148
|
+
const retry = step.retry;
|
|
61149
|
+
if (!retry) return;
|
|
61150
|
+
const taskMap = /* @__PURE__ */ new Map();
|
|
61151
|
+
for (const t3 of relatedTasks) taskMap.set(t3.id, t3);
|
|
61152
|
+
lines.push(`${indent}opt ${retry.condition}`);
|
|
61153
|
+
const innerIndent = indent + " ";
|
|
61154
|
+
const fixTask = taskMap.get(retry.fix_task);
|
|
61155
|
+
if (fixTask) {
|
|
61156
|
+
const fromAlias = step.from_agent ? participantAlias(participants, step.from_agent) : null;
|
|
61157
|
+
const targetAlias = participantAlias(participants, fixTask.target_agent);
|
|
61158
|
+
if (fromAlias) {
|
|
61159
|
+
lines.push(`${innerIndent}${fromAlias}->>${targetAlias}: fix ${retry.fix_task}`);
|
|
61160
|
+
}
|
|
61161
|
+
for (const es of fixTask.execution_steps ?? []) {
|
|
61162
|
+
emitExecutionStep(es, targetAlias, participants, lines, innerIndent);
|
|
61163
|
+
}
|
|
61164
|
+
if (fromAlias) {
|
|
61165
|
+
lines.push(`${innerIndent}${targetAlias}-->>${fromAlias}: ${fixTask.result_handoff}`);
|
|
61166
|
+
}
|
|
61167
|
+
}
|
|
61168
|
+
if (retry.revalidate_task) {
|
|
61169
|
+
const revalTask = taskMap.get(retry.revalidate_task);
|
|
61170
|
+
if (revalTask) {
|
|
61171
|
+
const fromAlias = step.from_agent ? participantAlias(participants, step.from_agent) : null;
|
|
61172
|
+
const revalAlias = participantAlias(participants, revalTask.target_agent);
|
|
61173
|
+
if (fromAlias) {
|
|
61174
|
+
lines.push(`${innerIndent}${fromAlias}->>${revalAlias}: revalidate ${retry.revalidate_task}`);
|
|
61175
|
+
lines.push(`${innerIndent}${revalAlias}-->>${fromAlias}: ${revalTask.result_handoff}`);
|
|
61176
|
+
}
|
|
61177
|
+
}
|
|
61178
|
+
}
|
|
61179
|
+
lines.push(`${indent}end`);
|
|
61180
|
+
}
|
|
61181
|
+
function groupSteps(steps) {
|
|
61182
|
+
const result = [];
|
|
61183
|
+
let currentGroup = null;
|
|
61184
|
+
for (let i3 = 0; i3 < steps.length; i3++) {
|
|
61185
|
+
const step = steps[i3];
|
|
61186
|
+
const group = "group" in step ? step.group : void 0;
|
|
61187
|
+
if (group) {
|
|
61188
|
+
if (currentGroup && currentGroup.group === group) {
|
|
61189
|
+
currentGroup.steps.push({ step, index: i3 });
|
|
61190
|
+
} else {
|
|
61191
|
+
if (currentGroup) result.push(currentGroup);
|
|
61192
|
+
currentGroup = { group, steps: [{ step, index: i3 }] };
|
|
61193
|
+
}
|
|
61194
|
+
} else {
|
|
61195
|
+
if (currentGroup) {
|
|
61196
|
+
result.push(currentGroup);
|
|
61197
|
+
currentGroup = null;
|
|
61198
|
+
}
|
|
61199
|
+
result.push({ group: null, steps: [{ step, index: i3 }] });
|
|
61200
|
+
}
|
|
61201
|
+
}
|
|
61202
|
+
if (currentGroup) result.push(currentGroup);
|
|
61203
|
+
return result;
|
|
61204
|
+
}
|
|
60986
61205
|
function generateSequenceDiagram(workflow, relatedTasks, dsl) {
|
|
60987
61206
|
const ids = collectReferencedIds(workflow, dsl, relatedTasks);
|
|
60988
|
-
const
|
|
61207
|
+
const externals = workflow.external_participants ?? [];
|
|
61208
|
+
const participants = buildParticipants(ids, externals, dsl);
|
|
60989
61209
|
const lines = [];
|
|
60990
61210
|
const indent = " ";
|
|
60991
61211
|
lines.push("sequenceDiagram");
|
|
60992
|
-
emitParticipants(participants, lines, indent);
|
|
61212
|
+
emitParticipants(participants, externals, lines, indent);
|
|
60993
61213
|
lines.push("");
|
|
60994
61214
|
lines.push(`${indent}rect ${hashToColor(workflow.id, 0.15, 0.95)}`);
|
|
60995
61215
|
const firstP = participants[0];
|
|
@@ -60998,22 +61218,174 @@ function generateSequenceDiagram(workflow, relatedTasks, dsl) {
|
|
|
60998
61218
|
const noteLabel = workflow.description ? `${workflow.id} \u2014 ${workflow.description}` : workflow.id;
|
|
60999
61219
|
lines.push(`${indent}Note over ${firstP.alias},${lastP.alias}: ${noteLabel}`);
|
|
61000
61220
|
}
|
|
61221
|
+
if (workflow.trigger && externals.some((ep) => ep.kind === "actor")) {
|
|
61222
|
+
const actor = externals.find((ep) => ep.kind === "actor");
|
|
61223
|
+
const actorAlias = participantAlias(participants, actor.id);
|
|
61224
|
+
const firstAgent = participants.find((p2) => p2.group === "agents" || p2.group === "audit");
|
|
61225
|
+
if (firstAgent) {
|
|
61226
|
+
lines.push(`${indent}${actorAlias}->>${firstAgent.alias}: ${workflow.trigger}`);
|
|
61227
|
+
}
|
|
61228
|
+
}
|
|
61001
61229
|
let lastFromAgent;
|
|
61002
|
-
|
|
61003
|
-
|
|
61004
|
-
if (
|
|
61005
|
-
|
|
61006
|
-
|
|
61007
|
-
|
|
61008
|
-
|
|
61009
|
-
|
|
61010
|
-
|
|
61230
|
+
const grouped = groupSteps(workflow.steps);
|
|
61231
|
+
for (const g2 of grouped) {
|
|
61232
|
+
if (g2.group && g2.steps.length > 1) {
|
|
61233
|
+
lines.push("");
|
|
61234
|
+
lines.push(`${indent}par ${g2.group}`);
|
|
61235
|
+
const parIndent = indent + " ";
|
|
61236
|
+
for (let i3 = 0; i3 < g2.steps.length; i3++) {
|
|
61237
|
+
const { step } = g2.steps[i3];
|
|
61238
|
+
if (i3 > 0) lines.push(`${indent}and`);
|
|
61239
|
+
emitStep(step, participants, dsl, relatedTasks, lines, parIndent, lastFromAgent, (a3) => {
|
|
61240
|
+
lastFromAgent = a3;
|
|
61241
|
+
});
|
|
61242
|
+
}
|
|
61243
|
+
lines.push(`${indent}end`);
|
|
61244
|
+
} else {
|
|
61245
|
+
for (const { step } of g2.steps) {
|
|
61246
|
+
lines.push("");
|
|
61247
|
+
emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, (a3) => {
|
|
61248
|
+
lastFromAgent = a3;
|
|
61249
|
+
});
|
|
61250
|
+
}
|
|
61011
61251
|
}
|
|
61012
61252
|
}
|
|
61013
61253
|
lines.push("");
|
|
61014
61254
|
lines.push(`${indent}end`);
|
|
61015
61255
|
return lines.join("\n");
|
|
61016
61256
|
}
|
|
61257
|
+
function emitStep(step, participants, dsl, relatedTasks, lines, indent, lastFromAgent, setLastFromAgent) {
|
|
61258
|
+
if (step.type === "handoff") {
|
|
61259
|
+
if (step.from_agent) setLastFromAgent(step.from_agent);
|
|
61260
|
+
emitHandoffStep(step, participants, dsl, relatedTasks, lines, indent);
|
|
61261
|
+
if (step.retry) {
|
|
61262
|
+
emitRetryBlock(step, participants, dsl, relatedTasks, lines, indent);
|
|
61263
|
+
}
|
|
61264
|
+
} else if (step.type === "validation") {
|
|
61265
|
+
emitValidationStep(step, participants, dsl, lastFromAgent, lines, indent);
|
|
61266
|
+
} else if (step.type === "decision") {
|
|
61267
|
+
emitDecisionStep(step, participants, lastFromAgent, lines, indent);
|
|
61268
|
+
}
|
|
61269
|
+
}
|
|
61270
|
+
|
|
61271
|
+
// src/renderer/overview-flowchart.ts
|
|
61272
|
+
function collectPhaseOps(dsl, wfId) {
|
|
61273
|
+
const ctx = buildWorkflowContext(dsl, wfId);
|
|
61274
|
+
const wf = dsl.workflow[wfId];
|
|
61275
|
+
const agentOps = /* @__PURE__ */ new Map();
|
|
61276
|
+
const artifactOps = /* @__PURE__ */ new Map();
|
|
61277
|
+
const toolOps = /* @__PURE__ */ new Map();
|
|
61278
|
+
function addOp(map, id, op) {
|
|
61279
|
+
if (!map.has(id)) map.set(id, /* @__PURE__ */ new Set());
|
|
61280
|
+
map.get(id).add(op);
|
|
61281
|
+
}
|
|
61282
|
+
const taskMap = new Map(ctx.relatedTasks.map((t3) => [t3.id, t3]));
|
|
61283
|
+
for (const step of wf.steps) {
|
|
61284
|
+
if (step.type === "handoff") {
|
|
61285
|
+
if (step.from_agent) addOp(agentOps, step.from_agent, "delegate");
|
|
61286
|
+
if (step.task) {
|
|
61287
|
+
const task = taskMap.get(step.task);
|
|
61288
|
+
if (task) {
|
|
61289
|
+
addOp(agentOps, task.target_agent, "execute");
|
|
61290
|
+
for (const es of task.execution_steps ?? []) {
|
|
61291
|
+
if (es.reads_artifact) addOp(artifactOps, es.reads_artifact, "R");
|
|
61292
|
+
if (es.produces_artifact) addOp(artifactOps, es.produces_artifact, "W");
|
|
61293
|
+
if (es.uses_tool) {
|
|
61294
|
+
const tool = dsl.tools[es.uses_tool];
|
|
61295
|
+
if (tool) {
|
|
61296
|
+
const cats = tool.commands.map((c2) => c2.category).filter((v2, i3, a3) => a3.indexOf(v2) === i3);
|
|
61297
|
+
for (const cat of cats) addOp(toolOps, es.uses_tool, cat);
|
|
61298
|
+
if (cats.length === 0) addOp(toolOps, es.uses_tool, "\u2713");
|
|
61299
|
+
} else {
|
|
61300
|
+
addOp(toolOps, es.uses_tool, "\u2713");
|
|
61301
|
+
}
|
|
61302
|
+
}
|
|
61303
|
+
}
|
|
61304
|
+
}
|
|
61305
|
+
}
|
|
61306
|
+
} else if (step.type === "validation") {
|
|
61307
|
+
const val = dsl.validations[step.validation];
|
|
61308
|
+
if (val) {
|
|
61309
|
+
if (val.executor_type === "agent") {
|
|
61310
|
+
addOp(agentOps, val.executor, "validate");
|
|
61311
|
+
} else {
|
|
61312
|
+
addOp(toolOps, val.executor, "verification");
|
|
61313
|
+
}
|
|
61314
|
+
addOp(artifactOps, val.target_artifact, "V");
|
|
61315
|
+
}
|
|
61316
|
+
}
|
|
61317
|
+
}
|
|
61318
|
+
return { agentOps, artifactOps, toolOps };
|
|
61319
|
+
}
|
|
61320
|
+
function formatOps(ops) {
|
|
61321
|
+
if (!ops || ops.size === 0) return "\u2014";
|
|
61322
|
+
return [...ops].join(", ");
|
|
61323
|
+
}
|
|
61324
|
+
function buildTable(header, rows) {
|
|
61325
|
+
const lines = [];
|
|
61326
|
+
lines.push("| " + header.join(" | ") + " |");
|
|
61327
|
+
lines.push("|" + header.map(() => "---").join("|") + "|");
|
|
61328
|
+
for (const row of rows) {
|
|
61329
|
+
lines.push("| " + row.join(" | ") + " |");
|
|
61330
|
+
}
|
|
61331
|
+
return lines.join("\n");
|
|
61332
|
+
}
|
|
61333
|
+
function generateOverviewFlowchart(dsl) {
|
|
61334
|
+
const workflowOrder = dsl.system.default_workflow_order ?? Object.keys(dsl.workflow);
|
|
61335
|
+
const phases = workflowOrder.filter((id) => dsl.workflow[id]);
|
|
61336
|
+
const phaseData = /* @__PURE__ */ new Map();
|
|
61337
|
+
for (const wfId of phases) {
|
|
61338
|
+
phaseData.set(wfId, collectPhaseOps(dsl, wfId));
|
|
61339
|
+
}
|
|
61340
|
+
const allAgentIds = /* @__PURE__ */ new Set();
|
|
61341
|
+
const allArtifactIds = /* @__PURE__ */ new Set();
|
|
61342
|
+
const allToolIds = /* @__PURE__ */ new Set();
|
|
61343
|
+
for (const ops of phaseData.values()) {
|
|
61344
|
+
for (const id of ops.agentOps.keys()) allAgentIds.add(id);
|
|
61345
|
+
for (const id of ops.artifactOps.keys()) allArtifactIds.add(id);
|
|
61346
|
+
for (const id of ops.toolOps.keys()) allToolIds.add(id);
|
|
61347
|
+
}
|
|
61348
|
+
const sections = [];
|
|
61349
|
+
if (allAgentIds.size > 0) {
|
|
61350
|
+
const header = ["Agent", ...phases];
|
|
61351
|
+
const rows = [];
|
|
61352
|
+
for (const agentId of allAgentIds) {
|
|
61353
|
+
const agent = dsl.agents[agentId];
|
|
61354
|
+
const label = agent ? agent.role_name : agentId;
|
|
61355
|
+
const row = [label];
|
|
61356
|
+
for (const wfId of phases) {
|
|
61357
|
+
row.push(formatOps(phaseData.get(wfId).agentOps.get(agentId)));
|
|
61358
|
+
}
|
|
61359
|
+
rows.push(row);
|
|
61360
|
+
}
|
|
61361
|
+
sections.push("#### Agent \xD7 Phase\n\n" + buildTable(header, rows));
|
|
61362
|
+
}
|
|
61363
|
+
if (allArtifactIds.size > 0) {
|
|
61364
|
+
const header = ["Artifact", ...phases];
|
|
61365
|
+
const rows = [];
|
|
61366
|
+
for (const artId of allArtifactIds) {
|
|
61367
|
+
const row = [artId];
|
|
61368
|
+
for (const wfId of phases) {
|
|
61369
|
+
row.push(formatOps(phaseData.get(wfId).artifactOps.get(artId)));
|
|
61370
|
+
}
|
|
61371
|
+
rows.push(row);
|
|
61372
|
+
}
|
|
61373
|
+
sections.push("#### Artifact \xD7 Phase\n\n" + buildTable(header, rows));
|
|
61374
|
+
}
|
|
61375
|
+
if (allToolIds.size > 0) {
|
|
61376
|
+
const header = ["Tool", ...phases];
|
|
61377
|
+
const rows = [];
|
|
61378
|
+
for (const toolId of allToolIds) {
|
|
61379
|
+
const row = [toolId];
|
|
61380
|
+
for (const wfId of phases) {
|
|
61381
|
+
row.push(formatOps(phaseData.get(wfId).toolOps.get(toolId)));
|
|
61382
|
+
}
|
|
61383
|
+
rows.push(row);
|
|
61384
|
+
}
|
|
61385
|
+
sections.push("#### Tool \xD7 Phase\n\n" + buildTable(header, rows));
|
|
61386
|
+
}
|
|
61387
|
+
return sections.join("\n\n");
|
|
61388
|
+
}
|
|
61017
61389
|
|
|
61018
61390
|
// src/renderer/renderer.ts
|
|
61019
61391
|
Handlebars.registerHelper("eq", (a3, b3) => a3 === b3);
|
|
@@ -61178,14 +61550,39 @@ Handlebars.registerHelper("size", (obj) => {
|
|
|
61178
61550
|
});
|
|
61179
61551
|
Handlebars.registerHelper(
|
|
61180
61552
|
"sequenceDiagram",
|
|
61181
|
-
function() {
|
|
61553
|
+
function(...args) {
|
|
61554
|
+
const opts = args[args.length - 1];
|
|
61555
|
+
const positionalArgs = args.slice(0, -1);
|
|
61556
|
+
if (typeof positionalArgs[0] === "string" && positionalArgs[1]) {
|
|
61557
|
+
const workflowId = positionalArgs[0];
|
|
61558
|
+
const dsl2 = positionalArgs[1];
|
|
61559
|
+
if (!dsl2.workflow[workflowId]) return "";
|
|
61560
|
+
const ctx = buildWorkflowContext(dsl2, workflowId);
|
|
61561
|
+
return generateSequenceDiagram(
|
|
61562
|
+
ctx.workflow,
|
|
61563
|
+
ctx.relatedTasks,
|
|
61564
|
+
dsl2
|
|
61565
|
+
);
|
|
61566
|
+
}
|
|
61182
61567
|
const workflow = this["workflow"];
|
|
61183
61568
|
const relatedTasks = this["relatedTasks"];
|
|
61184
|
-
const dsl = this["dsl"];
|
|
61569
|
+
const dsl = opts?.hash?.["dsl"] ?? this["dsl"];
|
|
61185
61570
|
if (!workflow || !dsl) return "";
|
|
61186
61571
|
return generateSequenceDiagram(workflow, relatedTasks ?? [], dsl);
|
|
61187
61572
|
}
|
|
61188
61573
|
);
|
|
61574
|
+
Handlebars.registerHelper(
|
|
61575
|
+
"overviewFlowchart",
|
|
61576
|
+
function(...args) {
|
|
61577
|
+
const positionalArgs = args.slice(0, -1);
|
|
61578
|
+
if (positionalArgs[0] && typeof positionalArgs[0] === "object") {
|
|
61579
|
+
return generateOverviewFlowchart(positionalArgs[0]);
|
|
61580
|
+
}
|
|
61581
|
+
const dsl = this["dsl"];
|
|
61582
|
+
if (!dsl) return "";
|
|
61583
|
+
return generateOverviewFlowchart(dsl);
|
|
61584
|
+
}
|
|
61585
|
+
);
|
|
61189
61586
|
function getDslSection(dsl, context) {
|
|
61190
61587
|
const sectionMap = {
|
|
61191
61588
|
agent: dsl.agents,
|