@axiom-lattice/protocols 2.1.41 → 2.1.42

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.
@@ -0,0 +1,347 @@
1
+ /**
2
+ * Workflow DSL
3
+ *
4
+ * Concise workflow definition language. A step's `id` is its node id, state
5
+ * output key, and template reference name. The engine auto-generates nodes,
6
+ * edges, and state fields.
7
+ *
8
+ * Template syntax:
9
+ * {{input}} — initial user input
10
+ * {{id}} — output of step with given id
11
+ * {{item}} — current element in map iterations
12
+ */
13
+
14
+ // ─── Top-level ─────────────────────────────────────────────────────────────
15
+
16
+ export interface WorkflowDSL {
17
+ name: string;
18
+ steps: WorkflowStep[];
19
+ }
20
+
21
+ export type WorkflowStep =
22
+ | AgentStep
23
+ | ConditionStep
24
+ | HumanStep
25
+ | MapStep
26
+ | ParallelStep
27
+ | EndStep;
28
+
29
+ // ─── Steps ─────────────────────────────────────────────────────────────────
30
+
31
+ /** invoke the workflow's built-in agent. type defaults to "agent". */
32
+ export interface AgentStep {
33
+ id?: string;
34
+ type?: "agent";
35
+ name?: string;
36
+ prompt: string;
37
+ schema?: Record<string, unknown>;
38
+ }
39
+
40
+ /** branch on state field or expression. */
41
+ export interface ConditionStep {
42
+ id?: string;
43
+ type: "condition";
44
+ if: string;
45
+ then?: WorkflowStep[] | WorkflowStep;
46
+ else?: WorkflowStep[] | WorkflowStep;
47
+ branches?: Record<string, WorkflowStep[] | WorkflowStep>;
48
+ }
49
+
50
+ /** pause for human input. */
51
+ export interface HumanStep {
52
+ id?: string;
53
+ type: "human";
54
+ prompt: string;
55
+ title?: string;
56
+ schema?: Record<string, unknown>;
57
+ }
58
+
59
+ /** iterate over an array, optionally reducing. */
60
+ export interface MapStep {
61
+ id: string;
62
+ type: "map";
63
+ source: string; // id of the step that produces the array
64
+ each: AgentStep; // applied to every element
65
+ reduce?: AgentStep; // optional aggregation
66
+ batch?: number; // default 50
67
+ concurrency?: number; // default 5
68
+ }
69
+
70
+ /** run steps in parallel, then rejoin. */
71
+ export interface ParallelStep {
72
+ id?: string;
73
+ type: "parallel";
74
+ steps: WorkflowStep[];
75
+ }
76
+
77
+ /** terminal state. */
78
+ export interface EndStep {
79
+ type: "end";
80
+ status?: "success" | "failed"; // default "success"
81
+ }
82
+
83
+ // ─── Examples ─────────────────────────────────────────────────────────────
84
+
85
+ /**
86
+ * Example 1 — Linear: agent → agent → end
87
+ *
88
+ * When `id` is omitted, one is auto-generated. Template uses {{id}} to
89
+ * reference previous step outputs.
90
+ *
91
+ * @example
92
+ * ```json
93
+ * {
94
+ * "name": "知识问答",
95
+ * "steps": [
96
+ * { "id": "researcher", "prompt": "查询: {{input}}" },
97
+ * { "id": "writer", "prompt": "根据 {{researcher}} 写回答" },
98
+ * { "type": "end" }
99
+ * ]
100
+ * }
101
+ * ```
102
+ */
103
+
104
+ /**
105
+ * Example 2 — Structured output with schema
106
+ *
107
+ * `schema: true` tells the agent to return JSON. The model infers the shape
108
+ * from the prompt description. For strict validation, pass a JSON Schema object.
109
+ *
110
+ * @example
111
+ * ```json
112
+ * {
113
+ * "name": "订单提取",
114
+ * "steps": [
115
+ * {
116
+ * "id": "order",
117
+ * "prompt": "提取订单: {items: [{name, qty, price}], total, urgent}",
118
+ * "schema": true
119
+ * },
120
+ * {
121
+ * "type": "condition", "if": "order.urgent",
122
+ * "then": { "id": "fast", "prompt": "加急: {{order}}" },
123
+ * "else": { "id": "normal", "prompt": "常规: {{order}}" }
124
+ * },
125
+ * { "type": "end" }
126
+ * ]
127
+ * }
128
+ * ```
129
+ */
130
+
131
+ /**
132
+ * Example 3 — Custom id for semantic naming
133
+ *
134
+ * @example
135
+ * ```json
136
+ * {
137
+ * "name": "翻译",
138
+ * "steps": [
139
+ * { "id": "原文", "prompt": "翻译: {{input}}" },
140
+ * { "id": "校对", "prompt": "校对: {{原文}}" },
141
+ * { "type": "end" }
142
+ * ]
143
+ * }
144
+ * ```
145
+ */
146
+
147
+ /**
148
+ * Example 4 — Condition (binary if/else)
149
+ *
150
+ * @example
151
+ * ```json
152
+ * {
153
+ * "name": "客服分流",
154
+ * "steps": [
155
+ * { "id": "intent", "prompt": "分类: {{input}}" },
156
+ * {
157
+ * "type": "condition", "if": "intent",
158
+ * "then": { "id": "support", "prompt": "支持: {{input}}" },
159
+ * "else": { "id": "sales", "prompt": "销售: {{input}}" }
160
+ * },
161
+ * { "type": "end" }
162
+ * ]
163
+ * }
164
+ * ```
165
+ */
166
+
167
+ /**
168
+ * Example 4b — Switch (multi-branch condition)
169
+ *
170
+ * When the agent's output is a fixed set of categories, use `branches`
171
+ * instead of nested if/else. The `if` expression evaluates to the state field
172
+ * value, which is matched against the branch keys. `default` is a catch-all.
173
+ *
174
+ * @example
175
+ * ```json
176
+ * {
177
+ * "name": "客服分流",
178
+ * "steps": [
179
+ * { "id": "intent", "prompt": "分类意图: {{input}}" },
180
+ * {
181
+ * "type": "condition", "if": "intent",
182
+ * "branches": {
183
+ * "support": { "id": "support", "prompt": "技术支持: {{input}}" },
184
+ * "sales": { "id": "sales", "prompt": "销售咨询: {{input}}" },
185
+ * "billing": { "id": "billing", "prompt": "账单查询: {{input}}" },
186
+ * "default": { "id": "fallback", "prompt": "转接人工: {{input}}" }
187
+ * }
188
+ * },
189
+ * { "type": "end" }
190
+ * ]
191
+ * }
192
+ * ```
193
+ */
194
+
195
+ /**
196
+ * Example 5 — Condition with expression
197
+ *
198
+ * @example
199
+ * ```json
200
+ * {
201
+ * "name": "评分判定",
202
+ * "steps": [
203
+ * { "id": "score", "prompt": "打分: {{input}}" },
204
+ * {
205
+ * "type": "condition", "if": "score >= 60",
206
+ * "then": [
207
+ * { "id": "congrats", "prompt": "恭喜通过" },
208
+ * { "type": "end" }
209
+ * ],
210
+ * "else": { "type": "end", "status": "failed" }
211
+ * }
212
+ * ]
213
+ * }
214
+ * ```
215
+ */
216
+
217
+ /**
218
+ * Example 6 — Human feedback (agent + clarify middleware)
219
+ *
220
+ * The human step invokes an agent with ask_user_to_clarify middleware.
221
+ * The agent decides what questions to ask based on the prompt. A schema
222
+ * constrains the structured output stored under the step's id.
223
+ *
224
+ * @example
225
+ * ```json
226
+ * {
227
+ * "name": "审批流程",
228
+ * "steps": [
229
+ * { "id": "draft", "prompt": "起草: {{input}}" },
230
+ * { "id": "review", "type": "human",
231
+ * "title": "审批",
232
+ * "prompt": "你是审批员。审核以下方案并请用户选择通过或驳回,附上意见。\\n\\n方案:\\n{{draft}}",
233
+ * "schema": { "type": "object", "properties": { "approved": { "type": "boolean" }, "comments": { "type": "string" } } } },
234
+ * {
235
+ * "type": "condition", "if": "review.approved",
236
+ * "then": { "prompt": "发布: {{draft}}" },
237
+ * "else": { "prompt": "修改: {{review.comments}}" }
238
+ * },
239
+ * { "type": "end" }
240
+ * ]
241
+ * }
242
+ * ```
243
+ */
244
+
245
+ /**
246
+ * Example 7 — Parallel (fixed fan-out)
247
+ *
248
+ * @example
249
+ * ```json
250
+ * {
251
+ * "name": "尽职调查",
252
+ * "steps": [
253
+ * { "id": "info", "prompt": "收集: {{input}}" },
254
+ * {
255
+ * "type": "parallel", "steps": [
256
+ * { "id": "legal", "prompt": "法务: {{info}}" },
257
+ * { "id": "finance", "prompt": "财务: {{info}}" },
258
+ * { "id": "market", "prompt": "市场: {{info}}" }
259
+ * ]
260
+ * },
261
+ * { "id": "report", "prompt": "汇总: {{legal}} {{finance}} {{market}}" },
262
+ * { "type": "end" }
263
+ * ]
264
+ * }
265
+ * ```
266
+ */
267
+
268
+ /**
269
+ * Example 8 — Map (dynamic iteration)
270
+ *
271
+ * @example
272
+ * ```json
273
+ * {
274
+ * "name": "批量审核",
275
+ * "steps": [
276
+ * { "id": "items", "prompt": "提取待审核项: {{input}}" },
277
+ * {
278
+ * "id": "results", "type": "map", "source": "items",
279
+ * "each": { "id": "auditor", "prompt": "审核: {{item}}" },
280
+ * "batch": 10, "concurrency": 3
281
+ * },
282
+ * { "id": "summary", "prompt": "总结: {{results}}" },
283
+ * { "type": "end" }
284
+ * ]
285
+ * }
286
+ * ```
287
+ */
288
+
289
+ /**
290
+ * Example 9 — Map + reduce
291
+ *
292
+ * @example
293
+ * ```json
294
+ * {
295
+ * "name": "舆情分析",
296
+ * "steps": [
297
+ * { "id": "posts", "prompt": "抓取: {{input}}" },
298
+ * {
299
+ * "id": "sentiments", "type": "map", "source": "posts",
300
+ * "each": { "id": "sentiment", "prompt": "分析情感: {{item}}" },
301
+ * "reduce": { "id": "aggregator", "prompt": "汇总: {{sentiments}}" }
302
+ * },
303
+ * { "id": "report", "prompt": "报告: {{aggregator}}" },
304
+ * { "type": "end" }
305
+ * ]
306
+ * }
307
+ * ```
308
+ */
309
+
310
+ /**
311
+ * Example 10 — Full pipeline (all types)
312
+ *
313
+ * @example
314
+ * ```json
315
+ * {
316
+ * "name": "智能客服",
317
+ * "steps": [
318
+ * { "id": "intent", "prompt": "分类: {{input}}" },
319
+ * {
320
+ * "type": "condition", "if": "intent",
321
+ * "then": [
322
+ * { "id": "kb", "prompt": "查知识库: {{input}}" },
323
+ * {
324
+ * "type": "condition", "if": "kb.confidence > 0.8",
325
+ * "then": { "id": "reply", "prompt": "直接回复: {{kb}}" },
326
+ * "else": [
327
+ * { "id": "pre_merge", "prompt": "准备合并" },
328
+ * { "type": "parallel", "steps": [
329
+ * { "id": "faq", "prompt": "FAQ: {{input}}" },
330
+ * { "id": "hist", "prompt": "历史: {{input}}" }
331
+ * ]},
332
+ * { "id": "merged", "prompt": "合并: FAQ={{faq}} 历史={{hist}}" },
333
+ * { "id": "review", "type": "human",
334
+ * "title": "转人工", "prompt": "请处理:\\n{{merged}}",
335
+ * "schema": { "type": "object", "properties": { "action": { "type": "string" } } }
336
+ * },
337
+ * { "id": "response", "prompt": "回复: {{review}}" }
338
+ * ]
339
+ * }
340
+ * ],
341
+ * "else": { "id": "clarify", "prompt": "请用户澄清" }
342
+ * },
343
+ * { "type": "end" }
344
+ * ]
345
+ * }
346
+ * ```
347
+ */
@@ -11,7 +11,7 @@ export interface TopologyEdge {
11
11
  purpose: string;
12
12
  }
13
13
 
14
- export type WorkflowRunStatus = 'running' | 'completed' | 'failed' | 'cancelled';
14
+ export type WorkflowRunStatus = 'running' | 'completed' | 'failed' | 'cancelled' | 'interrupted';
15
15
 
16
16
  export interface WorkflowRun {
17
17
  id: string;
@@ -25,12 +25,12 @@ export interface WorkflowRun {
25
25
  errorMessage?: string;
26
26
  metadata?: Record<string, any>;
27
27
  startedAt: Date;
28
- completedAt?: Date;
28
+ completedAt?: Date | null;
29
29
  createdAt: Date;
30
30
  updatedAt: Date;
31
31
  }
32
32
 
33
- export type StepType = 'task_delegation' | 'tool_call' | 'human_in_loop' | 'topology_transition';
33
+ export type StepType = 'task_delegation' | 'tool_call' | 'human_in_loop' | 'topology_transition' | 'agent' | 'human_feedback' | 'map' | 'input' | 'terminal';
34
34
  export type StepStatus = 'running' | 'completed' | 'failed' | 'interrupted';
35
35
 
36
36
  export interface RunStep {
@@ -47,7 +47,7 @@ export interface RunStep {
47
47
  status: StepStatus;
48
48
  errorMessage?: string;
49
49
  startedAt: Date;
50
- completedAt?: Date;
50
+ completedAt?: Date | null;
51
51
  durationMs?: number;
52
52
  createdAt: Date;
53
53
  updatedAt: Date;
@@ -65,7 +65,7 @@ export interface UpdateWorkflowRunRequest {
65
65
  status?: WorkflowRunStatus;
66
66
  completedEdges?: number;
67
67
  errorMessage?: string;
68
- completedAt?: Date;
68
+ completedAt?: Date | null;
69
69
  metadata?: Record<string, any>;
70
70
  }
71
71
 
@@ -84,7 +84,7 @@ export interface UpdateRunStepRequest {
84
84
  status?: StepStatus;
85
85
  output?: Record<string, any>;
86
86
  errorMessage?: string;
87
- completedAt?: Date;
87
+ completedAt?: Date | null;
88
88
  durationMs?: number;
89
89
  }
90
90
 
@@ -100,6 +100,8 @@ export interface WorkflowTrackingStore {
100
100
 
101
101
  // RunStep CRUD
102
102
  createRunStep(request: CreateRunStepRequest): Promise<RunStep>;
103
+ /** Idempotent create — uses (runId, stepType, stepName) as unique key. Returns existing step if one already exists. */
104
+ upsertRunStep(request: CreateRunStepRequest): Promise<RunStep>;
103
105
  updateRunStep(runId: string, stepId: string, updates: UpdateRunStepRequest): Promise<RunStep | null>;
104
106
  getRunSteps(runId: string): Promise<RunStep[]>;
105
107
  getRunStepsByType(runId: string, stepType: StepType): Promise<RunStep[]>;
package/src/index.ts CHANGED
@@ -37,5 +37,11 @@ export * from "./ChannelAdapterProtocol";
37
37
  export * from "./A2AProtocol";
38
38
  export * from "./A2AApiKeyStoreProtocol";
39
39
 
40
+ // Workflow DSL (concise, public API)
41
+ export * from "./WorkflowDSL";
42
+
43
+ // Internal DSL (expanded IR, internal use)
44
+ export * from "./InternalDSL";
45
+
40
46
  // 导出通用类型
41
47
  export * from "./types";