@ariaflowagents/config 0.5.3 → 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 +93 -5
- package/dist/agent-architect/index.d.ts +10 -0
- package/dist/agent-architect/index.d.ts.map +1 -0
- package/dist/agent-architect/index.js +131 -0
- package/dist/agent-architect/index.js.map +1 -0
- package/dist/agent-architect/prompt-generator.d.ts +9 -0
- package/dist/agent-architect/prompt-generator.d.ts.map +1 -0
- package/dist/agent-architect/prompt-generator.js +155 -0
- package/dist/agent-architect/prompt-generator.js.map +1 -0
- package/dist/agent-architect/rfc-emitter.d.ts +18 -0
- package/dist/agent-architect/rfc-emitter.d.ts.map +1 -0
- package/dist/agent-architect/rfc-emitter.js +350 -0
- package/dist/agent-architect/rfc-emitter.js.map +1 -0
- package/dist/agent-architect/tool-recommender.d.ts +8 -0
- package/dist/agent-architect/tool-recommender.d.ts.map +1 -0
- package/dist/agent-architect/tool-recommender.js +87 -0
- package/dist/agent-architect/tool-recommender.js.map +1 -0
- package/dist/agent-architect/types.d.ts +904 -0
- package/dist/agent-architect/types.d.ts.map +1 -0
- package/dist/agent-architect/types.js +89 -0
- package/dist/agent-architect/types.js.map +1 -0
- package/dist/agent-architect/use-case-analyzer.d.ts +8 -0
- package/dist/agent-architect/use-case-analyzer.d.ts.map +1 -0
- package/dist/agent-architect/use-case-analyzer.js +76 -0
- package/dist/agent-architect/use-case-analyzer.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1226 -3
- package/dist/cli.js.map +1 -1
- package/dist/flow-codegen.d.ts +6 -0
- package/dist/flow-codegen.d.ts.map +1 -0
- package/dist/flow-codegen.js +31 -0
- package/dist/flow-codegen.js.map +1 -0
- package/dist/flow-generator.d.ts +17 -0
- package/dist/flow-generator.d.ts.map +1 -0
- package/dist/flow-generator.js +202 -0
- package/dist/flow-generator.js.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/llm-flow-generator.d.ts +10 -0
- package/dist/llm-flow-generator.d.ts.map +1 -0
- package/dist/llm-flow-generator.js +244 -0
- package/dist/llm-flow-generator.js.map +1 -0
- package/dist/loader.d.ts +1 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +175 -45
- package/dist/loader.js.map +1 -1
- package/dist/prompt-lint.d.ts +18 -0
- package/dist/prompt-lint.d.ts.map +1 -0
- package/dist/prompt-lint.js +180 -0
- package/dist/prompt-lint.js.map +1 -0
- package/dist/types.d.ts +19 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +12 -11
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { generateObject } from 'ai';
|
|
2
|
+
import { openai } from '@ai-sdk/openai';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { generateFlowTemplate } from './flow-generator.js';
|
|
5
|
+
const fullPromptBlocksSchema = z.object({
|
|
6
|
+
globalPrompt: z
|
|
7
|
+
.string()
|
|
8
|
+
.min(1)
|
|
9
|
+
.describe('Global role prompt with sections for overall goal, language/style rules, tool+transition rules, and reliability rules.'),
|
|
10
|
+
mainAgendaPrompt: z
|
|
11
|
+
.string()
|
|
12
|
+
.min(1)
|
|
13
|
+
.describe('Main agenda prompt with concrete stage tasks, required data, relevant questions, and strict transition success criteria.'),
|
|
14
|
+
});
|
|
15
|
+
const taskBlockSchema = z.object({
|
|
16
|
+
title: z.string().min(1).max(120),
|
|
17
|
+
details: z.array(z.string().min(1).max(280)).min(1).max(6),
|
|
18
|
+
questions: z.array(z.string().min(1).max(280)).min(1).max(6),
|
|
19
|
+
finalActions: z.array(z.string().min(1).max(280)).min(1).max(6),
|
|
20
|
+
});
|
|
21
|
+
const hybridDraftSchema = z.object({
|
|
22
|
+
goalDescription: z.string().min(1).max(420),
|
|
23
|
+
useCases: z.array(z.string().min(1).max(280)).min(1).max(8),
|
|
24
|
+
fallbackOptions: z.array(z.string().min(1).max(280)).min(1).max(6),
|
|
25
|
+
taskBlocks: z.array(taskBlockSchema).min(1).max(6),
|
|
26
|
+
summaryMoveCriteria: z.array(z.string().min(1).max(280)).min(1).max(8),
|
|
27
|
+
});
|
|
28
|
+
function buildFullLlmPrompt(options) {
|
|
29
|
+
const contextSection = options.contextText && options.contextText.trim().length > 0
|
|
30
|
+
? `\n## Additional Context\n${options.contextText.trim()}\n`
|
|
31
|
+
: '';
|
|
32
|
+
return `Generate production-grade flow prompts for a voice-first guided agent.
|
|
33
|
+
|
|
34
|
+
## Use Case
|
|
35
|
+
- agent name: ${options.agentName}
|
|
36
|
+
- direction: ${options.direction}
|
|
37
|
+
- use case: ${options.useCase}
|
|
38
|
+
${contextSection}
|
|
39
|
+
## Output Requirements
|
|
40
|
+
- Return ONLY structured fields via the schema.
|
|
41
|
+
- globalPrompt must include:
|
|
42
|
+
- OVERALL GOAL section
|
|
43
|
+
- response language/style rules
|
|
44
|
+
- tool/function transition discipline
|
|
45
|
+
- reliability / non-hallucination rules
|
|
46
|
+
- mainAgendaPrompt must include:
|
|
47
|
+
- "MAIN ACTION POINT AT THIS STEP"
|
|
48
|
+
- 3-5 task blocks
|
|
49
|
+
- each task block has details/data + relevant questions + final actions
|
|
50
|
+
- explicit success criteria for moving to summary stage
|
|
51
|
+
- Make questions concrete and domain-specific, not generic filler.
|
|
52
|
+
- Enforce deterministic behavior: one question at a time, no mixing text+tool transition output.
|
|
53
|
+
- Keep wording clear for spoken conversations.
|
|
54
|
+
- Do not include markdown code fences.`;
|
|
55
|
+
}
|
|
56
|
+
function buildHybridLlmPrompt(options) {
|
|
57
|
+
const contextSection = options.contextText && options.contextText.trim().length > 0
|
|
58
|
+
? `\n## Additional Context\n${options.contextText.trim()}\n`
|
|
59
|
+
: '';
|
|
60
|
+
return `Create domain-specific variable blocks for a voice flow.
|
|
61
|
+
Do NOT output full prompts. Return only fields in schema.
|
|
62
|
+
|
|
63
|
+
## Use Case
|
|
64
|
+
- agent name: ${options.agentName}
|
|
65
|
+
- direction: ${options.direction}
|
|
66
|
+
- use case: ${options.useCase}
|
|
67
|
+
${contextSection}
|
|
68
|
+
## Constraints
|
|
69
|
+
- Keep content specific and realistic for the use case.
|
|
70
|
+
- Avoid generic filler.
|
|
71
|
+
- Questions should be voice-friendly and one-at-a-time.
|
|
72
|
+
- Include only facts/steps that can be asked or verified in conversation.
|
|
73
|
+
- No markdown code fences.`;
|
|
74
|
+
}
|
|
75
|
+
function composeHybridGlobalPrompt(options, draft) {
|
|
76
|
+
const useCases = draft.useCases.map(item => item.trim()).filter(Boolean);
|
|
77
|
+
const fallbacks = draft.fallbackOptions.map(item => item.trim()).filter(Boolean);
|
|
78
|
+
const effectiveUseCases = useCases.length > 0 ? useCases : ['addressing user requests and collecting required details'];
|
|
79
|
+
const effectiveFallbacks = fallbacks.length > 0 ? fallbacks : ['providing a concise summary and a follow-up option'];
|
|
80
|
+
const goal = draft.goalDescription.trim().length > 0
|
|
81
|
+
? draft.goalDescription.trim()
|
|
82
|
+
: 'handling user requests accurately and moving toward clear resolution';
|
|
83
|
+
const useCaseLines = effectiveUseCases.map(item => `- ${item}`).join('\n');
|
|
84
|
+
const fallbackLines = effectiveFallbacks.map(item => `- ${item}`).join('\n');
|
|
85
|
+
return `# OVERALL GOAL
|
|
86
|
+
|
|
87
|
+
You are ${options.agentName}. You are handling ${options.direction} calls for this use case.
|
|
88
|
+
Primary goal: ${goal}
|
|
89
|
+
|
|
90
|
+
Support these common scenarios:
|
|
91
|
+
${useCaseLines}
|
|
92
|
+
|
|
93
|
+
If the caller is hesitant, confused, or does not wish to continue, offer alternatives such as:
|
|
94
|
+
${fallbackLines}
|
|
95
|
+
|
|
96
|
+
## Response Language
|
|
97
|
+
YOU MUST only REPLY IN the language of the latest user input. Use simple words, keep tone informal but professional, and keep answers concise for voice.
|
|
98
|
+
|
|
99
|
+
## Critical Rules
|
|
100
|
+
- If the last message is not a user message, do not make a function/tool call.
|
|
101
|
+
- Never mix text and tool calls in the same output.
|
|
102
|
+
- Ask one focused question at a time and wait for the user response.
|
|
103
|
+
- If a transition is required, end the turn with the correct tool call or a question, never both.
|
|
104
|
+
|
|
105
|
+
## Reliability Rules
|
|
106
|
+
- Do not invent facts. If uncertain, ask a clarifying question or use a verification tool.
|
|
107
|
+
- Keep collected details consistent across turns and avoid contradictions.
|
|
108
|
+
- Prefer deterministic next actions over vague responses.`;
|
|
109
|
+
}
|
|
110
|
+
function composeHybridMainAgendaPrompt(draft) {
|
|
111
|
+
const blocks = draft.taskBlocks
|
|
112
|
+
.map((block, index) => {
|
|
113
|
+
const detailsList = block.details.map(item => item.trim()).filter(Boolean);
|
|
114
|
+
const questionList = block.questions.map(item => item.trim()).filter(Boolean);
|
|
115
|
+
const actionList = block.finalActions.map(item => item.trim()).filter(Boolean);
|
|
116
|
+
const details = (detailsList.length > 0 ? detailsList : ['Collect the required data for this step.'])
|
|
117
|
+
.map(item => ` - ${item}`).join('\n');
|
|
118
|
+
const questions = (questionList.length > 0 ? questionList : ['What is the key detail needed to proceed?'])
|
|
119
|
+
.map(item => ` - ${item}`).join('\n');
|
|
120
|
+
const actions = (actionList.length > 0 ? actionList : ['Summarize captured inputs and proceed deterministically.'])
|
|
121
|
+
.map(item => ` - ${item}`).join('\n');
|
|
122
|
+
const title = block.title.trim().length > 0 ? block.title.trim() : `Step ${index + 1}`;
|
|
123
|
+
return `### Task ${index + 1}: ${title}
|
|
124
|
+
Details and Data:
|
|
125
|
+
${details}
|
|
126
|
+
Relevant Questions:
|
|
127
|
+
${questions}
|
|
128
|
+
Final Step and Related Actions:
|
|
129
|
+
${actions}`;
|
|
130
|
+
})
|
|
131
|
+
.join('\n\n');
|
|
132
|
+
const successCriteriaList = draft.summaryMoveCriteria
|
|
133
|
+
.map(item => item.trim())
|
|
134
|
+
.filter(Boolean);
|
|
135
|
+
const successCriteria = (successCriteriaList.length > 0
|
|
136
|
+
? successCriteriaList
|
|
137
|
+
: ['Required details are collected and validated', 'A clear next action is identified'])
|
|
138
|
+
.map(item => `- ${item}`)
|
|
139
|
+
.join('\n');
|
|
140
|
+
return `# MAIN ACTION POINT AT THIS STEP
|
|
141
|
+
## Usable details and Main Agenda
|
|
142
|
+
|
|
143
|
+
## USABLE DETAILS and GOALS AT THIS STAGE:
|
|
144
|
+
${blocks}
|
|
145
|
+
|
|
146
|
+
## Flow of call
|
|
147
|
+
Here’s how the flow should work:
|
|
148
|
+
- Ask one question at a time.
|
|
149
|
+
- Handle objections briefly, then continue the agenda.
|
|
150
|
+
- Do not loop or repeat already-confirmed questions.
|
|
151
|
+
- Use transition tools/events to move stages.
|
|
152
|
+
|
|
153
|
+
# Success criteria WHEN you can move to next step
|
|
154
|
+
${successCriteria}
|
|
155
|
+
- Transition to Summary using the designated transition tool/event only.`;
|
|
156
|
+
}
|
|
157
|
+
function runWithTimeout(promise, timeoutMs, timeoutMessage) {
|
|
158
|
+
let timeoutHandle;
|
|
159
|
+
const timeout = new Promise((_, reject) => {
|
|
160
|
+
timeoutHandle = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs);
|
|
161
|
+
});
|
|
162
|
+
return Promise.race([promise, timeout]).finally(() => {
|
|
163
|
+
if (timeoutHandle) {
|
|
164
|
+
clearTimeout(timeoutHandle);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async function generateObjectStrict({ model, schema, system, prompt, }) {
|
|
169
|
+
const result = await generateObject({
|
|
170
|
+
model,
|
|
171
|
+
schema,
|
|
172
|
+
system,
|
|
173
|
+
prompt,
|
|
174
|
+
});
|
|
175
|
+
return result.object;
|
|
176
|
+
}
|
|
177
|
+
function resolveModelSpec(modelInput) {
|
|
178
|
+
const requested = modelInput?.trim() || 'gpt-5-mini';
|
|
179
|
+
const modelId = requested.startsWith('openai:') ? requested.slice('openai:'.length).trim() : requested;
|
|
180
|
+
if (!modelId) {
|
|
181
|
+
throw new Error('Model id cannot be empty');
|
|
182
|
+
}
|
|
183
|
+
if (!process.env.OPENAI_API_KEY || process.env.OPENAI_API_KEY.trim().length === 0) {
|
|
184
|
+
throw new Error('OPENAI_API_KEY is required for LLM flow generation');
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
modelId,
|
|
188
|
+
label: `openai:${modelId}`,
|
|
189
|
+
model: openai(modelId),
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
export async function generateFlowTemplateWithLLM(options) {
|
|
193
|
+
const useCase = options.useCase.trim();
|
|
194
|
+
const direction = options.direction ?? 'inbound';
|
|
195
|
+
const agentName = options.agentName?.trim() || 'Sam';
|
|
196
|
+
const modelSpec = resolveModelSpec(options.model);
|
|
197
|
+
const timeoutMs = options.timeoutMs ?? 45000;
|
|
198
|
+
const llmMode = options.llmMode ?? 'hybrid';
|
|
199
|
+
if (llmMode === 'full') {
|
|
200
|
+
const generate = generateObjectStrict({
|
|
201
|
+
model: modelSpec.model,
|
|
202
|
+
schema: fullPromptBlocksSchema,
|
|
203
|
+
system: 'You are an expert prompt engineer for deterministic conversational flow agents. Produce concise, robust prompts only.',
|
|
204
|
+
prompt: buildFullLlmPrompt({
|
|
205
|
+
useCase,
|
|
206
|
+
direction,
|
|
207
|
+
agentName,
|
|
208
|
+
contextText: options.contextText,
|
|
209
|
+
}),
|
|
210
|
+
});
|
|
211
|
+
const object = await runWithTimeout(generate, timeoutMs, `LLM flow generation timed out after ${timeoutMs}ms (${modelSpec.label})`);
|
|
212
|
+
return generateFlowTemplate({
|
|
213
|
+
...options,
|
|
214
|
+
promptBlocks: {
|
|
215
|
+
...options.promptBlocks,
|
|
216
|
+
globalPrompt: object.globalPrompt.trim(),
|
|
217
|
+
mainAgendaPrompt: object.mainAgendaPrompt.trim(),
|
|
218
|
+
},
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
let draft;
|
|
222
|
+
draft = await runWithTimeout(generateObjectStrict({
|
|
223
|
+
model: modelSpec.model,
|
|
224
|
+
schema: hybridDraftSchema,
|
|
225
|
+
system: 'You generate domain-specific variable blocks for conversational flow prompts. Keep content concrete and deterministic.',
|
|
226
|
+
prompt: buildHybridLlmPrompt({
|
|
227
|
+
useCase,
|
|
228
|
+
direction,
|
|
229
|
+
agentName,
|
|
230
|
+
contextText: options.contextText,
|
|
231
|
+
}),
|
|
232
|
+
}), timeoutMs, `LLM flow generation timed out after ${timeoutMs}ms (${modelSpec.label})`);
|
|
233
|
+
const globalPrompt = composeHybridGlobalPrompt({ direction, agentName }, draft);
|
|
234
|
+
const mainAgendaPrompt = composeHybridMainAgendaPrompt(draft);
|
|
235
|
+
return generateFlowTemplate({
|
|
236
|
+
...options,
|
|
237
|
+
promptBlocks: {
|
|
238
|
+
...options.promptBlocks,
|
|
239
|
+
globalPrompt,
|
|
240
|
+
mainAgendaPrompt,
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=llm-flow-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-flow-generator.js","sourceRoot":"","sources":["../src/llm-flow-generator.ts"],"names":[],"mappings":"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"}
|
package/dist/loader.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type HarnessConfig, type Runtime } from '@ariaflowagents/core';
|
|
2
2
|
import type { LoadedConfig, LoadOptions } from './types.js';
|
|
3
|
-
type WarningType = 'invalid_frontmatter' | 'missing_prompt' | 'missing_template' | 'name_mismatch' | 'missing_ref' | 'invalid_tool_entry' | 'duplicate_agent' | 'duplicate_flow' | 'unresolved_flow_ref' | 'tool_not_found';
|
|
3
|
+
type WarningType = 'invalid_frontmatter' | 'invalid_flow' | 'missing_prompt' | 'missing_template' | 'name_mismatch' | 'missing_ref' | 'invalid_tool_entry' | 'duplicate_agent' | 'duplicate_flow' | 'unresolved_flow_ref' | 'tool_not_found';
|
|
4
4
|
interface ConfigWarning {
|
|
5
5
|
type: WarningType;
|
|
6
6
|
file: string;
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAWA,OAAO,EAUL,KAAK,aAAa,EAElB,KAAK,OAAO,EAGb,MAAM,sBAAsB,CAAC;AAI9B,OAAO,KAAK,EAKV,YAAY,EACZ,WAAW,EAMZ,MAAM,YAAY,CAAC;AAqDpB,KAAK,WAAW,GACZ,qBAAqB,GACrB,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,aAAa,GACb,oBAAoB,GACpB,iBAAiB,GACjB,gBAAgB,GAChB,qBAAqB,GACrB,gBAAgB,CAAC;AAErB,UAAU,aAAa;IACrB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAWA,OAAO,EAUL,KAAK,aAAa,EAElB,KAAK,OAAO,EAGb,MAAM,sBAAsB,CAAC;AAI9B,OAAO,KAAK,EAKV,YAAY,EACZ,WAAW,EAMZ,MAAM,YAAY,CAAC;AAqDpB,KAAK,WAAW,GACZ,qBAAqB,GACrB,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,aAAa,GACb,oBAAoB,GACpB,iBAAiB,GACjB,gBAAgB,GAChB,qBAAqB,GACrB,gBAAgB,CAAC;AAErB,UAAU,aAAa;IACrB,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;CAC5B;AA8rCD,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuQzF;AAED,wBAAsB,4BAA4B,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC;IACrF,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,CAAC;QACrB,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B,CAAC,CA4RD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,CAanH;AA+FD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,YAAY,EACpB,SAAS,GAAE,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,gBAAgB,GAAG,cAAc,CAAC,CAAM,GACzF,OAAO,CAYT"}
|
package/dist/loader.js
CHANGED
|
@@ -108,6 +108,160 @@ function deepMerge(base, override) {
|
|
|
108
108
|
}
|
|
109
109
|
return result;
|
|
110
110
|
}
|
|
111
|
+
const VALID_FLOW_NODE_TYPES = new Set(['start', 'agent', 'end', 'global']);
|
|
112
|
+
function isRecord(value) {
|
|
113
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
114
|
+
}
|
|
115
|
+
function normalizeAndValidateFlowInput(flowId, flowInput, sourcePath) {
|
|
116
|
+
const errors = [];
|
|
117
|
+
if (!Array.isArray(flowInput.nodes) || flowInput.nodes.length === 0) {
|
|
118
|
+
errors.push('must define at least one node');
|
|
119
|
+
}
|
|
120
|
+
const normalizedNodes = [];
|
|
121
|
+
const nodeIds = new Set();
|
|
122
|
+
let startNodeCount = 0;
|
|
123
|
+
let globalNodeCount = 0;
|
|
124
|
+
let detectedStartNodeId;
|
|
125
|
+
for (let i = 0; i < (Array.isArray(flowInput.nodes) ? flowInput.nodes.length : 0); i++) {
|
|
126
|
+
const rawNode = flowInput.nodes[i];
|
|
127
|
+
if (!isRecord(rawNode)) {
|
|
128
|
+
errors.push(`node[${i}] must be an object`);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
const node = rawNode;
|
|
132
|
+
const nodeId = typeof node.id === 'string' ? node.id.trim() : '';
|
|
133
|
+
if (!nodeId) {
|
|
134
|
+
errors.push(`node[${i}] is missing a valid "id"`);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (nodeIds.has(nodeId)) {
|
|
138
|
+
errors.push(`duplicate node id "${nodeId}"`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
nodeIds.add(nodeId);
|
|
142
|
+
if (typeof node.prompt !== 'string' || node.prompt.trim().length === 0) {
|
|
143
|
+
errors.push(`node "${nodeId}" is missing a non-empty "prompt"`);
|
|
144
|
+
}
|
|
145
|
+
const nodeType = typeof node.nodeType === 'string' ? node.nodeType : undefined;
|
|
146
|
+
if (nodeType && !VALID_FLOW_NODE_TYPES.has(nodeType)) {
|
|
147
|
+
errors.push(`node "${nodeId}" has invalid nodeType "${nodeType}" (allowed: start, agent, end, global)`);
|
|
148
|
+
}
|
|
149
|
+
if (nodeType === 'start') {
|
|
150
|
+
startNodeCount += 1;
|
|
151
|
+
detectedStartNodeId = detectedStartNodeId ?? nodeId;
|
|
152
|
+
}
|
|
153
|
+
if (nodeType === 'global') {
|
|
154
|
+
globalNodeCount += 1;
|
|
155
|
+
}
|
|
156
|
+
normalizedNodes.push({
|
|
157
|
+
...node,
|
|
158
|
+
id: nodeId,
|
|
159
|
+
addGlobalPrompt: node.addGlobalPrompt !== false,
|
|
160
|
+
...(nodeType
|
|
161
|
+
? { nodeType: nodeType }
|
|
162
|
+
: {}),
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (startNodeCount > 1) {
|
|
166
|
+
errors.push('must have at most one node with nodeType="start"');
|
|
167
|
+
}
|
|
168
|
+
if (globalNodeCount > 1) {
|
|
169
|
+
errors.push('must have at most one node with nodeType="global"');
|
|
170
|
+
}
|
|
171
|
+
const normalizedTransitions = [];
|
|
172
|
+
if (flowInput.transitions !== undefined && !Array.isArray(flowInput.transitions)) {
|
|
173
|
+
errors.push('"transitions" must be an array when provided');
|
|
174
|
+
}
|
|
175
|
+
if (Array.isArray(flowInput.transitions)) {
|
|
176
|
+
for (let i = 0; i < flowInput.transitions.length; i++) {
|
|
177
|
+
const rawTransition = flowInput.transitions[i];
|
|
178
|
+
if (!isRecord(rawTransition)) {
|
|
179
|
+
errors.push(`transition[${i}] must be an object`);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const transition = rawTransition;
|
|
183
|
+
const from = typeof transition.from === 'string' ? transition.from.trim() : '';
|
|
184
|
+
const to = typeof transition.to === 'string' ? transition.to.trim() : '';
|
|
185
|
+
if (!from || !to) {
|
|
186
|
+
errors.push(`transition[${i}] must include non-empty "from" and "to"`);
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (!nodeIds.has(from)) {
|
|
190
|
+
errors.push(`transition[${i}] references unknown "from" node "${from}"`);
|
|
191
|
+
}
|
|
192
|
+
if (!nodeIds.has(to)) {
|
|
193
|
+
errors.push(`transition[${i}] references unknown "to" node "${to}"`);
|
|
194
|
+
}
|
|
195
|
+
const on = typeof transition.on === 'string' ? transition.on.trim() : transition.on;
|
|
196
|
+
if (transition.on !== undefined && (!on || typeof on !== 'string')) {
|
|
197
|
+
errors.push(`transition[${i}] has invalid "on" value`);
|
|
198
|
+
}
|
|
199
|
+
const hasConditionFn = typeof transition.condition === 'function';
|
|
200
|
+
if (transition.condition !== undefined && !hasConditionFn) {
|
|
201
|
+
errors.push(`transition[${i}] has non-function "condition"`);
|
|
202
|
+
}
|
|
203
|
+
if (!on && !hasConditionFn) {
|
|
204
|
+
errors.push(`transition[${i}] must define either "on" or "condition"`);
|
|
205
|
+
}
|
|
206
|
+
let contract;
|
|
207
|
+
if (transition.contract !== undefined) {
|
|
208
|
+
if (!isRecord(transition.contract)) {
|
|
209
|
+
errors.push(`transition[${i}] has invalid "contract" (must be an object)`);
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
const rawContract = transition.contract;
|
|
213
|
+
contract = {
|
|
214
|
+
label: typeof rawContract.label === 'string' ? rawContract.label : undefined,
|
|
215
|
+
conditionText: typeof rawContract.conditionText === 'string'
|
|
216
|
+
? rawContract.conditionText
|
|
217
|
+
: undefined,
|
|
218
|
+
toolOnly: typeof rawContract.toolOnly === 'boolean' ? rawContract.toolOnly : undefined,
|
|
219
|
+
requiresUserTurn: typeof rawContract.requiresUserTurn === 'boolean'
|
|
220
|
+
? rawContract.requiresUserTurn
|
|
221
|
+
: undefined,
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
normalizedTransitions.push({
|
|
226
|
+
...transition,
|
|
227
|
+
from,
|
|
228
|
+
to,
|
|
229
|
+
...(typeof on === 'string' ? { on } : {}),
|
|
230
|
+
...(contract ? { contract } : {}),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const explicitInitialNode = typeof flowInput.initialNode === 'string' && flowInput.initialNode.trim().length > 0
|
|
235
|
+
? flowInput.initialNode.trim()
|
|
236
|
+
: typeof flowInput.entry === 'string' && flowInput.entry.trim().length > 0
|
|
237
|
+
? flowInput.entry.trim()
|
|
238
|
+
: undefined;
|
|
239
|
+
const initialNode = explicitInitialNode ?? detectedStartNodeId ?? normalizedNodes[0]?.id;
|
|
240
|
+
if (!initialNode) {
|
|
241
|
+
errors.push('could not resolve initial node');
|
|
242
|
+
}
|
|
243
|
+
else if (!nodeIds.has(initialNode)) {
|
|
244
|
+
errors.push(`initial node "${initialNode}" is not present in nodes`);
|
|
245
|
+
}
|
|
246
|
+
if (errors.length > 0) {
|
|
247
|
+
const formatted = errors.map(err => `- ${err}`).join('\n');
|
|
248
|
+
warn('invalid_flow', sourcePath, `Flow "${flowId}" is invalid:\n${formatted}`, 'error');
|
|
249
|
+
throw new Error(`Flow "${flowId}" is invalid in ${sourcePath}:\n${formatted}`);
|
|
250
|
+
}
|
|
251
|
+
const flow = {
|
|
252
|
+
nodes: normalizedNodes,
|
|
253
|
+
transitions: normalizedTransitions.length > 0 ? normalizedTransitions : undefined,
|
|
254
|
+
defaultRolePrompt: flowInput.defaultRolePrompt,
|
|
255
|
+
contextStrategy: flowInput.contextStrategy,
|
|
256
|
+
summaryPrompt: flowInput.summaryPrompt,
|
|
257
|
+
summaryMaxTokens: flowInput.summaryMaxTokens,
|
|
258
|
+
maxSteps: flowInput.maxSteps,
|
|
259
|
+
...(typeof flowInput.summaryTimeoutMs === 'number'
|
|
260
|
+
? { summaryTimeoutMs: flowInput.summaryTimeoutMs }
|
|
261
|
+
: {}),
|
|
262
|
+
};
|
|
263
|
+
return { flow, initialNode: initialNode };
|
|
264
|
+
}
|
|
111
265
|
function resolveConfigFile(target, baseDir) {
|
|
112
266
|
const resolved = path.isAbsolute(target) ? target : path.resolve(baseDir, target);
|
|
113
267
|
if (existsSync(resolved) && !resolved.endsWith('.json') && !resolved.endsWith('.jsonc')) {
|
|
@@ -444,17 +598,11 @@ async function loadFlowFiles(root, sources) {
|
|
|
444
598
|
const content = await readFile(file, 'utf8');
|
|
445
599
|
const data = parseJsoncContent(content, file);
|
|
446
600
|
const id = data.id ?? path.basename(file, path.extname(file));
|
|
447
|
-
const
|
|
448
|
-
|
|
449
|
-
nodes: rest.nodes,
|
|
450
|
-
transitions: rest.transitions,
|
|
451
|
-
defaultRolePrompt: rest.defaultRolePrompt,
|
|
452
|
-
contextStrategy: rest.contextStrategy,
|
|
453
|
-
};
|
|
454
|
-
flows[id] = flowConfig;
|
|
601
|
+
const normalized = normalizeAndValidateFlowInput(id, data, file);
|
|
602
|
+
flows[id] = normalized.flow;
|
|
455
603
|
meta[id] = {
|
|
456
604
|
id,
|
|
457
|
-
initialNode: initialNode
|
|
605
|
+
initialNode: normalized.initialNode,
|
|
458
606
|
path: file,
|
|
459
607
|
};
|
|
460
608
|
sources.flowFiles.push(file);
|
|
@@ -965,13 +1113,9 @@ export async function loadAriaflowConfig(options = {}) {
|
|
|
965
1113
|
continue;
|
|
966
1114
|
}
|
|
967
1115
|
for (const [id, flowInput] of Object.entries(layer.config.flows)) {
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
defaultRolePrompt: flowInput.defaultRolePrompt,
|
|
972
|
-
contextStrategy: flowInput.contextStrategy,
|
|
973
|
-
};
|
|
974
|
-
flowMeta[id] = { id, initialNode: flowInput.initialNode ?? flowInput.entry, path: layer.path };
|
|
1116
|
+
const normalized = normalizeAndValidateFlowInput(id, flowInput, layer.path);
|
|
1117
|
+
flows[id] = normalized.flow;
|
|
1118
|
+
flowMeta[id] = { id, initialNode: normalized.initialNode, path: layer.path };
|
|
975
1119
|
}
|
|
976
1120
|
}
|
|
977
1121
|
for (const root of roots) {
|
|
@@ -981,13 +1125,9 @@ export async function loadAriaflowConfig(options = {}) {
|
|
|
981
1125
|
}
|
|
982
1126
|
if (inlineLayer?.config.flows) {
|
|
983
1127
|
for (const [id, flowInput] of Object.entries(inlineLayer.config.flows)) {
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
defaultRolePrompt: flowInput.defaultRolePrompt,
|
|
988
|
-
contextStrategy: flowInput.contextStrategy,
|
|
989
|
-
};
|
|
990
|
-
flowMeta[id] = { id, initialNode: flowInput.initialNode ?? flowInput.entry, path: inlineLayer.path };
|
|
1128
|
+
const normalized = normalizeAndValidateFlowInput(id, flowInput, inlineLayer.path);
|
|
1129
|
+
flows[id] = normalized.flow;
|
|
1130
|
+
flowMeta[id] = { id, initialNode: normalized.initialNode, path: inlineLayer.path };
|
|
991
1131
|
}
|
|
992
1132
|
}
|
|
993
1133
|
const agentDefs = {};
|
|
@@ -1176,13 +1316,9 @@ export async function loadAriaflowConfigWithResult(options = {}) {
|
|
|
1176
1316
|
if (!layer.config.flows)
|
|
1177
1317
|
continue;
|
|
1178
1318
|
for (const [id, flowInput] of Object.entries(layer.config.flows)) {
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
defaultRolePrompt: flowInput.defaultRolePrompt,
|
|
1183
|
-
contextStrategy: flowInput.contextStrategy,
|
|
1184
|
-
};
|
|
1185
|
-
flowMeta[id] = { id, initialNode: flowInput.initialNode ?? flowInput.entry, path: layer.path };
|
|
1319
|
+
const normalized = normalizeAndValidateFlowInput(id, flowInput, layer.path);
|
|
1320
|
+
flows[id] = normalized.flow;
|
|
1321
|
+
flowMeta[id] = { id, initialNode: normalized.initialNode, path: layer.path };
|
|
1186
1322
|
}
|
|
1187
1323
|
}
|
|
1188
1324
|
for (const root of roots) {
|
|
@@ -1192,13 +1328,9 @@ export async function loadAriaflowConfigWithResult(options = {}) {
|
|
|
1192
1328
|
}
|
|
1193
1329
|
if (inlineLayer?.config.flows) {
|
|
1194
1330
|
for (const [id, flowInput] of Object.entries(inlineLayer.config.flows)) {
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
defaultRolePrompt: flowInput.defaultRolePrompt,
|
|
1199
|
-
contextStrategy: flowInput.contextStrategy,
|
|
1200
|
-
};
|
|
1201
|
-
flowMeta[id] = { id, initialNode: flowInput.initialNode ?? flowInput.entry, path: inlineLayer.path };
|
|
1331
|
+
const normalized = normalizeAndValidateFlowInput(id, flowInput, inlineLayer.path);
|
|
1332
|
+
flows[id] = normalized.flow;
|
|
1333
|
+
flowMeta[id] = { id, initialNode: normalized.initialNode, path: inlineLayer.path };
|
|
1202
1334
|
}
|
|
1203
1335
|
}
|
|
1204
1336
|
const agentDefs = {};
|
|
@@ -1396,13 +1528,11 @@ async function normalizeAgentInput(id, input, baseDir, flows, flowMeta, toolRegi
|
|
|
1396
1528
|
? flowInput.mode
|
|
1397
1529
|
: undefined;
|
|
1398
1530
|
const flowId = flowInput.flowRef ?? flowInput.flow?.id;
|
|
1399
|
-
const
|
|
1400
|
-
? {
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
contextStrategy: flowInput.flow.contextStrategy,
|
|
1405
|
-
}
|
|
1531
|
+
const inlineFlowNormalized = flowInput.flow
|
|
1532
|
+
? normalizeAndValidateFlowInput(flowId ?? `${id}-inline-flow`, flowInput.flow, `${baseDir}#agent:${id}`)
|
|
1533
|
+
: null;
|
|
1534
|
+
const flowConfig = inlineFlowNormalized
|
|
1535
|
+
? inlineFlowNormalized.flow
|
|
1406
1536
|
: flowId
|
|
1407
1537
|
? flows[flowId]
|
|
1408
1538
|
: undefined;
|
|
@@ -1410,7 +1540,7 @@ async function normalizeAgentInput(id, input, baseDir, flows, flowMeta, toolRegi
|
|
|
1410
1540
|
throw new Error(`Flow agent "${id}" references missing flow`);
|
|
1411
1541
|
}
|
|
1412
1542
|
const initialNode = flowInput.initialNode ??
|
|
1413
|
-
|
|
1543
|
+
inlineFlowNormalized?.initialNode ??
|
|
1414
1544
|
flowMeta[flowId ?? '']?.initialNode ??
|
|
1415
1545
|
flowConfig.nodes?.[0]?.id;
|
|
1416
1546
|
if (!initialNode) {
|