nolo-cli 0.1.9 → 0.1.11
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 +0 -32
- package/agentRuntimeCommands.ts +3 -3
- package/commandRegistry.ts +2 -2
- package/machineCommands.ts +31 -6
- package/package.json +6 -8
- package/ai/agent/_executeModel.ts +0 -118
- package/ai/agent/agentSlice.ts +0 -525
- package/ai/agent/appWorkingMemory.ts +0 -126
- package/ai/agent/avatarUtils.ts +0 -24
- package/ai/agent/buildEditingContext.ts +0 -373
- package/ai/agent/buildSystemPrompt.ts +0 -532
- package/ai/agent/cleanAgentMessages.ts +0 -140
- package/ai/agent/cliChatClient.ts +0 -119
- package/ai/agent/cliExecutor.ts +0 -733
- package/ai/agent/cliPrompt.ts +0 -10
- package/ai/agent/contextCompiler.ts +0 -107
- package/ai/agent/contextLayerContract.ts +0 -44
- package/ai/agent/createAgentSchema.ts +0 -234
- package/ai/agent/executeToolCall.ts +0 -58
- package/ai/agent/fetchAgentContexts.ts +0 -42
- package/ai/agent/generatePrompt.ts +0 -3
- package/ai/agent/getFullChatContextKeys.ts +0 -168
- package/ai/agent/hooks/fetchPublicAgents.ts +0 -133
- package/ai/agent/hooks/useAgentConfig.ts +0 -61
- package/ai/agent/hooks/useAgentDialog.ts +0 -35
- package/ai/agent/hooks/useAgentFormValidation.ts +0 -202
- package/ai/agent/hooks/usePublicAgents.ts +0 -473
- package/ai/agent/machineRunPermissions.ts +0 -95
- package/ai/agent/persistMessageWithFixedId.ts +0 -37
- package/ai/agent/planSlice.ts +0 -259
- package/ai/agent/referenceUtils.ts +0 -229
- package/ai/agent/runAgentBackground.ts +0 -238
- package/ai/agent/runAgentClientLoop.ts +0 -138
- package/ai/agent/runtimeGuidance.ts +0 -97
- package/ai/agent/runtimeServerBase.ts +0 -37
- package/ai/agent/server/fetchPublicAgents.ts +0 -128
- package/ai/agent/startParallelAgentStreams.ts +0 -424
- package/ai/agent/startupProtocol.ts +0 -53
- package/ai/agent/streamAgentChatTurn.ts +0 -1278
- package/ai/agent/streamAgentChatTurnUtils.ts +0 -738
- package/ai/agent/types.ts +0 -71
- package/ai/agent/utils/imageOutput.ts +0 -33
- package/ai/agent/utils/sortUtils.ts +0 -250
- package/ai/agent/web/referencePickerUtils.ts +0 -146
- package/ai/ai.locale.ts +0 -1075
- package/ai/chat/accumulateToolCallChunks.ts +0 -95
- package/ai/chat/fetchUtils.native.ts +0 -276
- package/ai/chat/fetchUtils.ts +0 -153
- package/ai/chat/parseApiError.ts +0 -64
- package/ai/chat/parseMultilineSSE.ts +0 -95
- package/ai/chat/sendOpenAICompletionsRequest.native.ts +0 -682
- package/ai/chat/sendOpenAICompletionsRequest.ts +0 -703
- package/ai/chat/sendOpenAIResponseRequest.ts +0 -491
- package/ai/chat/shouldUseServerProxy.ts +0 -18
- package/ai/chat/sseClient.native.ts +0 -91
- package/ai/chat/sseClient.ts +0 -67
- package/ai/chat/streamReader.native.ts +0 -31
- package/ai/chat/streamReader.ts +0 -62
- package/ai/chat/updateTotalUsage.ts +0 -72
- package/ai/context/buildReferenceContext.ts +0 -437
- package/ai/context/calculateContextUsage.ts +0 -133
- package/ai/context/retention.ts +0 -165
- package/ai/context/tokenUtils.ts +0 -78
- package/ai/index.ts +0 -1
- package/ai/llm/calculateGeminiImageTokens.ts +0 -57
- package/ai/llm/deepinfra.ts +0 -28
- package/ai/llm/fireworks.ts +0 -50
- package/ai/llm/generateRequestBody.ts +0 -165
- package/ai/llm/getModelContextWindow.ts +0 -84
- package/ai/llm/getNoloKey.ts +0 -31
- package/ai/llm/getPricing.ts +0 -199
- package/ai/llm/hooks/useModelPricing.ts +0 -75
- package/ai/llm/imagePricing.ts +0 -40
- package/ai/llm/isResponseAPIModel.ts +0 -13
- package/ai/llm/mimo.ts +0 -71
- package/ai/llm/mistral.ts +0 -22
- package/ai/llm/modelAvatar.ts +0 -427
- package/ai/llm/models.ts +0 -45
- package/ai/llm/openrouterModels.ts +0 -269
- package/ai/llm/providers.ts +0 -306
- package/ai/llm/reasoningModels.ts +0 -28
- package/ai/llm/types.ts +0 -59
- package/ai/llm/usageRequestOptions.ts +0 -59
- package/ai/memory/capture.ts +0 -148
- package/ai/memory/consolidate.ts +0 -104
- package/ai/memory/delete.ts +0 -147
- package/ai/memory/overlay.ts +0 -84
- package/ai/memory/query.ts +0 -38
- package/ai/memory/queryShared.ts +0 -160
- package/ai/memory/rank.ts +0 -105
- package/ai/memory/recentRelationshipRecap.ts +0 -249
- package/ai/memory/remember.ts +0 -167
- package/ai/memory/runtime.ts +0 -76
- package/ai/memory/store.ts +0 -20
- package/ai/memory/storeShared.ts +0 -76
- package/ai/memory/types.ts +0 -46
- package/ai/memory/understanding.ts +0 -349
- package/ai/memory/understandingGreeting.ts +0 -264
- package/ai/messages/type.ts +0 -20
- package/ai/policy/personalizationDialog.ts +0 -333
- package/ai/policy/runtimePolicy.ts +0 -440
- package/ai/policy/selfUpdateFields.ts +0 -48
- package/ai/policy/types.ts +0 -64
- package/ai/skills/referenceRuntime.ts +0 -274
- package/ai/skills/skillDiagnostics.ts +0 -251
- package/ai/skills/skillDocBuilder.ts +0 -139
- package/ai/skills/skillDocProtocol.ts +0 -434
- package/ai/skills/skillReferenceSummary.ts +0 -63
- package/ai/skills/skillSummaryMarker.ts +0 -26
- package/ai/token/calculatePrice.ts +0 -544
- package/ai/token/db.ts +0 -98
- package/ai/token/externalToolCost.ts +0 -330
- package/ai/token/hooks/useRecords.ts +0 -65
- package/ai/token/missingUsageEstimate.ts +0 -42
- package/ai/token/modelUsageQuery.ts +0 -252
- package/ai/token/normalizeUsage.ts +0 -84
- package/ai/token/openaiImageGenerationUsage.ts +0 -56
- package/ai/token/prepareTokenUsageData.ts +0 -88
- package/ai/token/query.ts +0 -88
- package/ai/token/queryUserTokens.ts +0 -59
- package/ai/token/resolveBillingTarget.ts +0 -52
- package/ai/token/saveTokenRecord.ts +0 -53
- package/ai/token/serverDialogProjection.ts +0 -78
- package/ai/token/serverTokenWriter.ts +0 -143
- package/ai/token/stats.ts +0 -21
- package/ai/token/tokenThunks.ts +0 -24
- package/ai/token/types.ts +0 -93
- package/ai/tools/agent/agentTools.ts +0 -176
- package/ai/tools/agent/agentUpdateShared.ts +0 -311
- package/ai/tools/agent/callAgentTool.ts +0 -139
- package/ai/tools/agent/createAgentTool.ts +0 -512
- package/ai/tools/agent/createDialogTool.ts +0 -69
- package/ai/tools/agent/createSkillAgentTool.ts +0 -62
- package/ai/tools/agent/parallelBudget.ts +0 -221
- package/ai/tools/agent/presets/appBuilderPreset.ts +0 -145
- package/ai/tools/agent/runLlmTool.ts +0 -96
- package/ai/tools/agent/runStreamingAgentTool.ts +0 -73
- package/ai/tools/agent/skillAgentArgs.ts +0 -106
- package/ai/tools/agent/skillAgentPreset.ts +0 -89
- package/ai/tools/agent/streamParallelAgentsTool.ts +0 -122
- package/ai/tools/agent/updateAgentTool.ts +0 -96
- package/ai/tools/agent/updateSelfTool.ts +0 -113
- package/ai/tools/amazonProductScraperTool.ts +0 -86
- package/ai/tools/apifyActorClient.ts +0 -45
- package/ai/tools/appEditGuard.ts +0 -372
- package/ai/tools/appReadSnapshot.ts +0 -153
- package/ai/tools/appTools.ts +0 -1549
- package/ai/tools/applyEditTool.ts +0 -256
- package/ai/tools/applyLineEditsTool.ts +0 -312
- package/ai/tools/browserTools/click.ts +0 -33
- package/ai/tools/browserTools/closeSession.ts +0 -29
- package/ai/tools/browserTools/common.ts +0 -27
- package/ai/tools/browserTools/openSession.ts +0 -48
- package/ai/tools/browserTools/readContent.ts +0 -38
- package/ai/tools/browserTools/selectOption.ts +0 -46
- package/ai/tools/browserTools/typeText.ts +0 -42
- package/ai/tools/category/createCategoryTool.ts +0 -66
- package/ai/tools/category/queryContentsByCategoryTool.ts +0 -69
- package/ai/tools/category/updateContentCategoryTool.ts +0 -75
- package/ai/tools/cfBrowserTools.ts +0 -319
- package/ai/tools/cfSpeechToTextTool.ts +0 -49
- package/ai/tools/checkEnvTool.ts +0 -65
- package/ai/tools/cloudflareCrawlTool.ts +0 -289
- package/ai/tools/codeSearchTool.ts +0 -111
- package/ai/tools/codeTools.ts +0 -101
- package/ai/tools/createDocTool.ts +0 -132
- package/ai/tools/createPlanTool.ts +0 -999
- package/ai/tools/createSkillDocTool.ts +0 -155
- package/ai/tools/createWorkflowTool.ts +0 -154
- package/ai/tools/deepseekOcrTool.ts +0 -34
- package/ai/tools/delayTool.ts +0 -31
- package/ai/tools/deleteSpacesTool.ts +0 -325
- package/ai/tools/deleteSpacesToolModel.ts +0 -159
- package/ai/tools/devReloadUtils.ts +0 -29
- package/ai/tools/dialogMessageSearch.ts +0 -137
- package/ai/tools/doctorSkillTool.ts +0 -72
- package/ai/tools/ecommerceScraperTool.ts +0 -86
- package/ai/tools/emailTools.ts +0 -549
- package/ai/tools/evalSkillTool.ts +0 -92
- package/ai/tools/exaSearchTool.ts +0 -64
- package/ai/tools/execBashTool.ts +0 -379
- package/ai/tools/executeSqlTool.ts +0 -192
- package/ai/tools/fetchWebpageSupport.ts +0 -309
- package/ai/tools/fetchWebpageTool.ts +0 -84
- package/ai/tools/geminiImagePreviewTool.ts +0 -361
- package/ai/tools/generateDocxTool.ts +0 -215
- package/ai/tools/googleSearchScraperTool.ts +0 -106
- package/ai/tools/importDataTool.ts +0 -133
- package/ai/tools/importSkillTool.ts +0 -162
- package/ai/tools/index.ts +0 -1858
- package/ai/tools/listFilesTool.ts +0 -82
- package/ai/tools/listUserSpacesTool.ts +0 -113
- package/ai/tools/modelUsageTools.ts +0 -142
- package/ai/tools/olmOcrTool.ts +0 -34
- package/ai/tools/openaiImageTool.ts +0 -218
- package/ai/tools/paddleOcrTool.ts +0 -34
- package/ai/tools/prepareTools.ts +0 -23
- package/ai/tools/readDocTool.ts +0 -84
- package/ai/tools/readFileTool.ts +0 -211
- package/ai/tools/readTool.ts +0 -163
- package/ai/tools/readXPostTool.ts +0 -233
- package/ai/tools/rememberMemoryTool.ts +0 -84
- package/ai/tools/remotionVideoTool.ts +0 -151
- package/ai/tools/searchDialogMessagesTool.ts +0 -222
- package/ai/tools/searchRepoTool.ts +0 -115
- package/ai/tools/searchWorkspaceTool.ts +0 -259
- package/ai/tools/skillFollowup.ts +0 -86
- package/ai/tools/surfWeatherTool.ts +0 -169
- package/ai/tools/table/addTableRowTool.ts +0 -217
- package/ai/tools/table/createTableTool.ts +0 -315
- package/ai/tools/table/rowTools.ts +0 -366
- package/ai/tools/table/schemaTools.ts +0 -244
- package/ai/tools/table/shareTableTool.ts +0 -148
- package/ai/tools/table/toolShared.ts +0 -129
- package/ai/tools/toolApiClient.ts +0 -198
- package/ai/tools/toolNameAliases.ts +0 -57
- package/ai/tools/toolResultError.ts +0 -42
- package/ai/tools/toolRunSlice.ts +0 -303
- package/ai/tools/toolSchemaCompatibility.ts +0 -53
- package/ai/tools/toolVisibility.ts +0 -4
- package/ai/tools/types.ts +0 -20
- package/ai/tools/uiAskChoiceTool.ts +0 -104
- package/ai/tools/updateContentTitleTool.ts +0 -84
- package/ai/tools/updateDocTool.ts +0 -105
- package/ai/tools/updateUserPreferenceProfileTool.ts +0 -145
- package/ai/tools/whisperTool.ts +0 -77
- package/ai/tools/writeFileTool.ts +0 -210
- package/ai/tools/youtubeScraperTool.ts +0 -116
- package/ai/tools/ziweiChartTool.ts +0 -678
- package/ai/types.ts +0 -55
- package/ai/workflow/workflowExecutor.ts +0 -323
- package/ai/workflow/workflowSlice.ts +0 -73
- package/ai/workflow/workflowTypes.ts +0 -106
- package/client/compactDialog.ts +0 -222
- package/connector-experimental/capabilities.ts +0 -73
- package/connector-experimental/codexBinary.ts +0 -41
- package/connector-experimental/heartbeatLoop.ts +0 -22
- package/connector-experimental/index.ts +0 -5
- package/connector-experimental/machineInfo.ts +0 -46
- package/connector-experimental/protocol.ts +0 -54
package/ai/types.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
// packages/ai/types.ts
|
|
2
|
-
|
|
3
|
-
export type ModeType =
|
|
4
|
-
| "text"
|
|
5
|
-
| "image"
|
|
6
|
-
| "stream"
|
|
7
|
-
| "audio"
|
|
8
|
-
| "speech"
|
|
9
|
-
| "surf"
|
|
10
|
-
| "vision";
|
|
11
|
-
|
|
12
|
-
export interface PromptFormData {
|
|
13
|
-
name: string;
|
|
14
|
-
content: string;
|
|
15
|
-
category?: string;
|
|
16
|
-
tags?: string[];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface Contexts {
|
|
20
|
-
// High priority: context from the user's current input for this request.
|
|
21
|
-
currentInputContext?: string | null;
|
|
22
|
-
|
|
23
|
-
// Medium priority: references from past conversation messages.
|
|
24
|
-
historyContext?: string | null;
|
|
25
|
-
|
|
26
|
-
// Specific rules and processes for the bot/agent.
|
|
27
|
-
botInstructionsContext?: string | null;
|
|
28
|
-
|
|
29
|
-
// General knowledge base documents for lookup.
|
|
30
|
-
botKnowledgeContext?: string | null;
|
|
31
|
-
|
|
32
|
-
// 🔹 新增:用户级通用提示词
|
|
33
|
-
userGlobalPrompt?: string;
|
|
34
|
-
|
|
35
|
-
/** 当前正在编辑的对象描述(表格 / 页面 / 文章等),由 buildEditingContextSummary 构造 */
|
|
36
|
-
editingContext?: string | null;
|
|
37
|
-
|
|
38
|
-
/** 当前对话里最近一次 app 相关工具调用提炼出的工作记忆,不依赖右侧 editing target */
|
|
39
|
-
appWorkingMemory?: string | null;
|
|
40
|
-
|
|
41
|
-
/** 当前所在的 Space 信息(Agent 所处的工作台),包含标题、描述等 */
|
|
42
|
-
spaceContext?: string | null;
|
|
43
|
-
|
|
44
|
-
/** 用户偏好与自动化边界(tone / capture / read policy) */
|
|
45
|
-
userPolicyContext?: string | null;
|
|
46
|
-
|
|
47
|
-
/** 对话增量摘要:已压缩的历史消息概要 */
|
|
48
|
-
dialogSummary?: string | null;
|
|
49
|
-
|
|
50
|
-
/** 主动工作摘要:阶段性沉淀,不代表原始消息已被裁剪 */
|
|
51
|
-
proactiveSummary?: string | null;
|
|
52
|
-
|
|
53
|
-
/** 压缩消息中提取的引用 Key */
|
|
54
|
-
referenceKeys?: string[];
|
|
55
|
-
}
|
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Workflow Executor
|
|
3
|
-
*
|
|
4
|
-
* Deterministic execution engine — zero LLM orchestration tokens.
|
|
5
|
-
* Each step runs directly without asking LLM "what to do next".
|
|
6
|
-
* Only "llm" type steps call the model (single call, no tool loop).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { createAsyncThunk } from "@reduxjs/toolkit";
|
|
10
|
-
import type { RootState } from "app/store";
|
|
11
|
-
import { runLlm } from "ai/agent/agentSlice";
|
|
12
|
-
import { toolExecutors } from "ai/tools";
|
|
13
|
-
import {
|
|
14
|
-
setWorkflow,
|
|
15
|
-
updateStep,
|
|
16
|
-
incrementStepsExecuted,
|
|
17
|
-
incrementFailedSteps,
|
|
18
|
-
} from "./workflowSlice";
|
|
19
|
-
import type {
|
|
20
|
-
WorkflowDefinition,
|
|
21
|
-
WorkflowStep,
|
|
22
|
-
WorkflowToolStep,
|
|
23
|
-
WorkflowLlmStep,
|
|
24
|
-
WorkflowParallelStep,
|
|
25
|
-
WorkflowStepState,
|
|
26
|
-
WorkflowResult,
|
|
27
|
-
} from "./workflowTypes";
|
|
28
|
-
|
|
29
|
-
// --- Template Resolution ---
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Resolves {{steps.<id>.result}} and {{steps.<id>.result[N]}} templates.
|
|
33
|
-
* Walks nested objects/arrays recursively.
|
|
34
|
-
*/
|
|
35
|
-
function resolveTemplates(
|
|
36
|
-
value: any,
|
|
37
|
-
results: Record<string, any>
|
|
38
|
-
): any {
|
|
39
|
-
if (typeof value === "string") {
|
|
40
|
-
return value.replace(
|
|
41
|
-
/\{\{steps\.([^.}\s]+)\.result(\[\d+\])?\}\}/g,
|
|
42
|
-
(match, stepId, indexPart) => {
|
|
43
|
-
const stepResult = results[stepId];
|
|
44
|
-
if (stepResult === undefined) {
|
|
45
|
-
console.warn(`Workflow: cannot resolve {{steps.${stepId}.result}} — step not completed yet`);
|
|
46
|
-
return match;
|
|
47
|
-
}
|
|
48
|
-
let resolved = stepResult;
|
|
49
|
-
if (indexPart) {
|
|
50
|
-
const idx = parseInt(indexPart.slice(1, -1), 10);
|
|
51
|
-
if (Array.isArray(resolved) && idx < resolved.length) {
|
|
52
|
-
resolved = resolved[idx];
|
|
53
|
-
} else {
|
|
54
|
-
console.warn(`Workflow: index ${idx} out of range for steps.${stepId}.result`);
|
|
55
|
-
return match;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return typeof resolved === "object" ? JSON.stringify(resolved) : String(resolved);
|
|
59
|
-
}
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
if (Array.isArray(value)) {
|
|
63
|
-
return value.map((v) => resolveTemplates(v, results));
|
|
64
|
-
}
|
|
65
|
-
if (value !== null && typeof value === "object") {
|
|
66
|
-
return Object.fromEntries(
|
|
67
|
-
Object.entries(value).map(([k, v]) => [k, resolveTemplates(v, results)])
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
return value;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// --- Condition Evaluation (safe allowlist interpreter) ---
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Validates that an expression contains ONLY:
|
|
77
|
-
* - steps.<identifier> property paths
|
|
78
|
-
* - comparison operators: === !== > < >= <=
|
|
79
|
-
* - logical operators: && || !
|
|
80
|
-
* - string literals, number literals, boolean/null keywords
|
|
81
|
-
* - parentheses and whitespace
|
|
82
|
-
*
|
|
83
|
-
* Strategy: substitute every safe token with a placeholder, then assert
|
|
84
|
-
* nothing else remains. This allowlist approach is far more robust than a
|
|
85
|
-
* blocklist, which can be bypassed with Unicode escapes or bracket notation.
|
|
86
|
-
*/
|
|
87
|
-
function isSafeConditionExpression(expr: string): boolean {
|
|
88
|
-
let s = expr.trim();
|
|
89
|
-
if (!s) return false;
|
|
90
|
-
|
|
91
|
-
// 1. Replace double/single-quoted string literals (no newlines inside)
|
|
92
|
-
s = s.replace(/"[^"\n\\]*(?:\\.[^"\n\\]*)*"/g, "0");
|
|
93
|
-
s = s.replace(/'[^'\n\\]*(?:\\.[^'\n\\]*)*/g, "0");
|
|
94
|
-
|
|
95
|
-
// 2. Replace number literals (int / float)
|
|
96
|
-
s = s.replace(/\b\d+(?:\.\d+)?\b/g, "0");
|
|
97
|
-
|
|
98
|
-
// 3. Replace allowed keywords
|
|
99
|
-
s = s.replace(/\b(true|false|null|undefined)\b/g, "0");
|
|
100
|
-
|
|
101
|
-
// 4. Replace steps.<dotted-path> (e.g. steps.fetchData.output)
|
|
102
|
-
s = s.replace(/\bsteps\.[a-zA-Z_][a-zA-Z0-9_.]*\b/g, "0");
|
|
103
|
-
|
|
104
|
-
// 5. What's left should only be operators, parens, whitespace
|
|
105
|
-
// Allowed characters: 0 (placeholder) space ( ) ! & | = < >
|
|
106
|
-
return /^[0\s()!&|=<>]+$/.test(s);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Safely resolves a dotted property path like "steps.fetchData.output"
|
|
111
|
-
* against the given results object. Returns undefined for any unknown path.
|
|
112
|
-
*/
|
|
113
|
-
function resolvePath(path: string, results: Record<string, any>): unknown {
|
|
114
|
-
// path must be "steps.<segment>[.<segment>...]"
|
|
115
|
-
const parts = path.split(".");
|
|
116
|
-
if (parts[0] !== "steps" || parts.length < 2) return undefined;
|
|
117
|
-
let cur: any = results;
|
|
118
|
-
for (let i = 1; i < parts.length; i++) {
|
|
119
|
-
if (cur === null || cur === undefined || typeof cur !== "object") return undefined;
|
|
120
|
-
cur = cur[parts[i]];
|
|
121
|
-
}
|
|
122
|
-
return cur;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Evaluates a condition expression against step results.
|
|
127
|
-
*
|
|
128
|
-
* Uses an allowlist validator to guarantee the expression contains nothing
|
|
129
|
-
* but property lookups, comparison/logical operators, and literals before
|
|
130
|
-
* delegating to the JS engine. This eliminates the code-execution surface
|
|
131
|
-
* that a keyword blocklist cannot reliably close.
|
|
132
|
-
*/
|
|
133
|
-
function evaluateCondition(
|
|
134
|
-
expression: string,
|
|
135
|
-
results: Record<string, any>
|
|
136
|
-
): boolean {
|
|
137
|
-
if (!isSafeConditionExpression(expression)) {
|
|
138
|
-
console.warn(
|
|
139
|
-
`Workflow: condition expression rejected by allowlist: "${expression}"`
|
|
140
|
-
);
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
try {
|
|
144
|
-
// At this point the expression has been validated to contain only safe
|
|
145
|
-
// tokens. We substitute all steps.* paths with their runtime values so
|
|
146
|
-
// the final eval string never needs to reference external globals.
|
|
147
|
-
const resolved = expression.replace(
|
|
148
|
-
/\bsteps\.[a-zA-Z_][a-zA-Z0-9_.]*\b/g,
|
|
149
|
-
(match) => JSON.stringify(resolvePath(match, results))
|
|
150
|
-
);
|
|
151
|
-
// eslint-disable-next-line no-new-func
|
|
152
|
-
const fn = new Function(`"use strict"; return !!(${resolved})`);
|
|
153
|
-
return fn();
|
|
154
|
-
} catch (e) {
|
|
155
|
-
console.warn(`Workflow: condition eval failed: "${expression}"`, e);
|
|
156
|
-
return false;
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Executes `fn` up to `maxRetries + 1` times total.
|
|
164
|
-
* Throws the last error if all attempts fail.
|
|
165
|
-
*/
|
|
166
|
-
async function executeWithRetry<T>(
|
|
167
|
-
fn: () => Promise<T>,
|
|
168
|
-
maxRetries: number
|
|
169
|
-
): Promise<T> {
|
|
170
|
-
let lastError: any;
|
|
171
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
172
|
-
try {
|
|
173
|
-
return await fn();
|
|
174
|
-
} catch (err) {
|
|
175
|
-
lastError = err;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
throw lastError;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// --- Single Step Executors ---
|
|
182
|
-
|
|
183
|
-
async function executeToolStep(
|
|
184
|
-
step: WorkflowToolStep,
|
|
185
|
-
results: Record<string, any>,
|
|
186
|
-
thunkApi: any
|
|
187
|
-
): Promise<any> {
|
|
188
|
-
const executor = toolExecutors[step.tool];
|
|
189
|
-
if (!executor) throw new Error(`Workflow: unknown tool "${step.tool}"`);
|
|
190
|
-
const resolvedArgs = resolveTemplates(step.args, results);
|
|
191
|
-
const result = await executor(resolvedArgs, thunkApi);
|
|
192
|
-
return result?.rawData ?? result;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
async function executeLlmStep(
|
|
196
|
-
step: WorkflowLlmStep,
|
|
197
|
-
results: Record<string, any>,
|
|
198
|
-
thunkApi: any
|
|
199
|
-
): Promise<any> {
|
|
200
|
-
const { dispatch } = thunkApi;
|
|
201
|
-
const resolvedPrompt = resolveTemplates(step.prompt, results);
|
|
202
|
-
const result = await dispatch(
|
|
203
|
-
runLlm({
|
|
204
|
-
content: resolvedPrompt,
|
|
205
|
-
isStreaming: false,
|
|
206
|
-
...(step.model && { modelOverride: step.model }),
|
|
207
|
-
})
|
|
208
|
-
).unwrap();
|
|
209
|
-
return result;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
async function executeParallelStep(
|
|
213
|
-
step: WorkflowParallelStep,
|
|
214
|
-
results: Record<string, any>,
|
|
215
|
-
thunkApi: any
|
|
216
|
-
): Promise<Record<string, any>> {
|
|
217
|
-
const subResults = await Promise.all(
|
|
218
|
-
step.steps.map(async (sub) => {
|
|
219
|
-
const subResult =
|
|
220
|
-
sub.type === "tool"
|
|
221
|
-
? await executeToolStep(sub as WorkflowToolStep, results, thunkApi)
|
|
222
|
-
: await executeLlmStep(sub as WorkflowLlmStep, results, thunkApi);
|
|
223
|
-
return [sub.id, subResult] as [string, any];
|
|
224
|
-
})
|
|
225
|
-
);
|
|
226
|
-
return Object.fromEntries(subResults);
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// --- Main Executor Thunk ---
|
|
230
|
-
|
|
231
|
-
export const runWorkflow = createAsyncThunk<
|
|
232
|
-
WorkflowResult,
|
|
233
|
-
{ definition: WorkflowDefinition; dialogKey?: string },
|
|
234
|
-
{ state: RootState }
|
|
235
|
-
>("workflow/run", async ({ definition }, thunkApi) => {
|
|
236
|
-
const { dispatch } = thunkApi;
|
|
237
|
-
|
|
238
|
-
// Initialize Redux state for UI visibility
|
|
239
|
-
const initialStepStates: WorkflowStepState[] = definition.steps.map((s) => ({
|
|
240
|
-
id: s.id,
|
|
241
|
-
title: s.title,
|
|
242
|
-
type: s.type,
|
|
243
|
-
status: "pending",
|
|
244
|
-
}));
|
|
245
|
-
dispatch(setWorkflow({ title: definition.title, steps: initialStepStates }));
|
|
246
|
-
|
|
247
|
-
const results: Record<string, any> = {};
|
|
248
|
-
// Set of step IDs to skip (controlled by condition steps)
|
|
249
|
-
const skippedIds = new Set<string>();
|
|
250
|
-
|
|
251
|
-
for (const step of definition.steps) {
|
|
252
|
-
if (skippedIds.has(step.id)) {
|
|
253
|
-
dispatch(updateStep({ id: step.id, updates: { status: "skipped" } }));
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
dispatch(updateStep({ id: step.id, updates: { status: "in-progress" } }));
|
|
258
|
-
|
|
259
|
-
try {
|
|
260
|
-
let result: any;
|
|
261
|
-
|
|
262
|
-
if (step.type === "tool" || step.type === "llm") {
|
|
263
|
-
const retryable = step as WorkflowToolStep | WorkflowLlmStep;
|
|
264
|
-
const policy = retryable.onError ?? "stop";
|
|
265
|
-
const maxRetries =
|
|
266
|
-
policy === "retry" ? ((retryable as WorkflowToolStep).retryCount ?? 1) : 0;
|
|
267
|
-
|
|
268
|
-
result = await executeWithRetry(
|
|
269
|
-
() =>
|
|
270
|
-
step.type === "tool"
|
|
271
|
-
? executeToolStep(step as WorkflowToolStep, results, thunkApi)
|
|
272
|
-
: executeLlmStep(step as WorkflowLlmStep, results, thunkApi),
|
|
273
|
-
maxRetries
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
} else if (step.type === "parallel") {
|
|
277
|
-
result = await executeParallelStep(step, results, thunkApi);
|
|
278
|
-
// Flatten sub-step results into the top-level map so subsequent steps
|
|
279
|
-
// can reference them directly via {{steps.<subId>.result}}.
|
|
280
|
-
for (const [subId, subResult] of Object.entries(
|
|
281
|
-
result as Record<string, any>
|
|
282
|
-
)) {
|
|
283
|
-
results[subId] = subResult;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
} else if (step.type === "condition") {
|
|
287
|
-
const passed = evaluateCondition(step.check, results);
|
|
288
|
-
result = { passed, check: step.check };
|
|
289
|
-
const active = passed ? step.ifTrue : step.ifFalse;
|
|
290
|
-
const inactive = passed ? step.ifFalse : step.ifTrue;
|
|
291
|
-
// Mark steps not on the active branch as skipped
|
|
292
|
-
if (inactive) inactive.forEach((id) => skippedIds.add(id));
|
|
293
|
-
// Steps on the active branch are explicitly NOT skipped
|
|
294
|
-
if (active) active.forEach((id) => skippedIds.delete(id));
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
results[step.id] = result;
|
|
298
|
-
dispatch(updateStep({ id: step.id, updates: { status: "completed", result } }));
|
|
299
|
-
dispatch(incrementStepsExecuted());
|
|
300
|
-
|
|
301
|
-
} catch (err: any) {
|
|
302
|
-
dispatch(incrementFailedSteps());
|
|
303
|
-
dispatch(
|
|
304
|
-
updateStep({ id: step.id, updates: { status: "failed", error: err?.message ?? String(err) } })
|
|
305
|
-
);
|
|
306
|
-
|
|
307
|
-
const policy = (step as WorkflowToolStep | WorkflowLlmStep).onError ?? "stop";
|
|
308
|
-
|
|
309
|
-
if (policy === "stop") {
|
|
310
|
-
return {
|
|
311
|
-
success: false,
|
|
312
|
-
results,
|
|
313
|
-
failedStep: step.id,
|
|
314
|
-
error: err?.message ?? String(err),
|
|
315
|
-
};
|
|
316
|
-
}
|
|
317
|
-
// skip / retry-exhausted: record null and continue
|
|
318
|
-
results[step.id] = null;
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
return { success: true, results };
|
|
323
|
-
});
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { type PayloadAction, createSlice } from "@reduxjs/toolkit";
|
|
2
|
-
import type { RootState } from "app/store";
|
|
3
|
-
import type {
|
|
4
|
-
WorkflowStepState,
|
|
5
|
-
WorkflowExecutionStats,
|
|
6
|
-
} from "./workflowTypes";
|
|
7
|
-
|
|
8
|
-
interface WorkflowSliceState {
|
|
9
|
-
title: string | null;
|
|
10
|
-
steps: WorkflowStepState[];
|
|
11
|
-
stats: WorkflowExecutionStats;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const initialState: WorkflowSliceState = {
|
|
15
|
-
title: null,
|
|
16
|
-
steps: [],
|
|
17
|
-
stats: {
|
|
18
|
-
startTime: null,
|
|
19
|
-
totalStepsExecuted: 0,
|
|
20
|
-
failedSteps: 0,
|
|
21
|
-
},
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const workflowSlice = createSlice({
|
|
25
|
-
name: "workflow",
|
|
26
|
-
initialState,
|
|
27
|
-
reducers: {
|
|
28
|
-
setWorkflow: (
|
|
29
|
-
state,
|
|
30
|
-
action: PayloadAction<{ title: string; steps: WorkflowStepState[] }>
|
|
31
|
-
) => {
|
|
32
|
-
state.title = action.payload.title;
|
|
33
|
-
state.steps = action.payload.steps;
|
|
34
|
-
state.stats = { startTime: Date.now(), totalStepsExecuted: 0, failedSteps: 0 };
|
|
35
|
-
},
|
|
36
|
-
|
|
37
|
-
updateStep: (
|
|
38
|
-
state,
|
|
39
|
-
action: PayloadAction<{ id: string; updates: Partial<WorkflowStepState> }>
|
|
40
|
-
) => {
|
|
41
|
-
const step = state.steps.find((s) => s.id === action.payload.id);
|
|
42
|
-
if (step) Object.assign(step, action.payload.updates);
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
incrementStepsExecuted: (state) => {
|
|
46
|
-
state.stats.totalStepsExecuted += 1;
|
|
47
|
-
},
|
|
48
|
-
|
|
49
|
-
incrementFailedSteps: (state) => {
|
|
50
|
-
state.stats.failedSteps += 1;
|
|
51
|
-
},
|
|
52
|
-
|
|
53
|
-
clearWorkflow: () => initialState,
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
export const {
|
|
58
|
-
setWorkflow,
|
|
59
|
-
updateStep,
|
|
60
|
-
incrementStepsExecuted,
|
|
61
|
-
incrementFailedSteps,
|
|
62
|
-
clearWorkflow,
|
|
63
|
-
} = workflowSlice.actions;
|
|
64
|
-
|
|
65
|
-
export const selectWorkflowSteps = (state: RootState) => state.workflow.steps;
|
|
66
|
-
export const selectWorkflowTitle = (state: RootState) => state.workflow.title;
|
|
67
|
-
export const selectWorkflowStats = (state: RootState) => state.workflow.stats;
|
|
68
|
-
export const selectPendingSteps = (state: RootState) =>
|
|
69
|
-
state.workflow.steps.filter((s) => s.status === "pending");
|
|
70
|
-
export const selectCompletedSteps = (state: RootState) =>
|
|
71
|
-
state.workflow.steps.filter((s) => s.status === "completed");
|
|
72
|
-
|
|
73
|
-
export default workflowSlice.reducer;
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
// Workflow: deterministic execution engine, zero LLM orchestration tokens.
|
|
2
|
-
// LLM calls createWorkflow once to define steps; engine executes without further LLM involvement.
|
|
3
|
-
// Only "llm" type steps invoke the model; all others run as pure tool calls.
|
|
4
|
-
|
|
5
|
-
export type WorkflowStepStatus = "pending" | "in-progress" | "completed" | "failed" | "skipped";
|
|
6
|
-
|
|
7
|
-
export type OnErrorPolicy = "stop" | "skip" | "retry";
|
|
8
|
-
|
|
9
|
-
// --- Step Types ---
|
|
10
|
-
|
|
11
|
-
export interface WorkflowToolStep {
|
|
12
|
-
id: string;
|
|
13
|
-
type: "tool";
|
|
14
|
-
title?: string;
|
|
15
|
-
/** Registered tool name */
|
|
16
|
-
tool: string;
|
|
17
|
-
/** Args supporting {{steps.<id>.result}} and {{steps.<id>.result[N]}} templates */
|
|
18
|
-
args: Record<string, any>;
|
|
19
|
-
onError?: OnErrorPolicy;
|
|
20
|
-
retryCount?: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface WorkflowLlmStep {
|
|
24
|
-
id: string;
|
|
25
|
-
type: "llm";
|
|
26
|
-
title?: string;
|
|
27
|
-
/** Prompt supporting {{steps.<id>.result}} templates */
|
|
28
|
-
prompt: string;
|
|
29
|
-
model?: string;
|
|
30
|
-
onError?: OnErrorPolicy;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** All steps inside run concurrently via Promise.all */
|
|
34
|
-
export interface WorkflowParallelStep {
|
|
35
|
-
id: string;
|
|
36
|
-
type: "parallel";
|
|
37
|
-
title?: string;
|
|
38
|
-
steps: (WorkflowToolStep | WorkflowLlmStep)[];
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Pure JS condition check — no LLM.
|
|
43
|
-
* `check` is a JS expression string evaluated with step results in scope.
|
|
44
|
-
*
|
|
45
|
-
* Supported syntax (allowlist):
|
|
46
|
-
* - Dotted property access: `steps.<stepId>.<property>[.<nested>...]`
|
|
47
|
-
* - Comparison operators: === !== > < >= <=
|
|
48
|
-
* - Logical operators: && || !
|
|
49
|
-
* - String / number / boolean / null literals
|
|
50
|
-
* - Parentheses for grouping
|
|
51
|
-
*
|
|
52
|
-
* Note: bracket notation (`steps['id']`) and `.result` wrappers are NOT supported.
|
|
53
|
-
* The value stored for each step is the raw executor return value, accessed directly:
|
|
54
|
-
* e.g. `"steps.validate.isValid === true"`
|
|
55
|
-
* `"steps.score.value >= 80 && steps.flag.ok !== false"`
|
|
56
|
-
*/
|
|
57
|
-
export interface WorkflowConditionStep {
|
|
58
|
-
id: string;
|
|
59
|
-
type: "condition";
|
|
60
|
-
title?: string;
|
|
61
|
-
check: string;
|
|
62
|
-
/** Step IDs to execute when check is truthy (skip others) */
|
|
63
|
-
ifTrue?: string[];
|
|
64
|
-
/** Step IDs to execute when check is falsy (skip others) */
|
|
65
|
-
ifFalse?: string[];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export type WorkflowStep =
|
|
69
|
-
| WorkflowToolStep
|
|
70
|
-
| WorkflowLlmStep
|
|
71
|
-
| WorkflowParallelStep
|
|
72
|
-
| WorkflowConditionStep;
|
|
73
|
-
|
|
74
|
-
// --- Workflow Definition ---
|
|
75
|
-
|
|
76
|
-
export interface WorkflowDefinition {
|
|
77
|
-
title: string;
|
|
78
|
-
steps: WorkflowStep[];
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// --- Execution State (stored in Redux) ---
|
|
82
|
-
|
|
83
|
-
export interface WorkflowStepState {
|
|
84
|
-
id: string;
|
|
85
|
-
title?: string;
|
|
86
|
-
type: WorkflowStep["type"];
|
|
87
|
-
status: WorkflowStepStatus;
|
|
88
|
-
result?: any;
|
|
89
|
-
error?: string;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface WorkflowExecutionStats {
|
|
93
|
-
startTime: number | null;
|
|
94
|
-
totalStepsExecuted: number;
|
|
95
|
-
failedSteps: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// --- Result ---
|
|
99
|
-
|
|
100
|
-
export interface WorkflowResult {
|
|
101
|
-
success: boolean;
|
|
102
|
-
/** Results keyed by step id */
|
|
103
|
-
results: Record<string, any>;
|
|
104
|
-
failedStep?: string;
|
|
105
|
-
error?: string;
|
|
106
|
-
}
|