@ai-setting/roy-agent-core 1.7.53 → 1.7.55
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/dist/env/agent/index.js +3 -3
- package/dist/env/error-reply.d.ts +184 -0
- package/dist/env/event-source/event-source-handlers.d.ts +9 -23
- package/dist/env/event-source/index.js +6 -6
- package/dist/env/index.js +18 -18
- package/dist/env/llm/adapter-pi-ai.d.ts +147 -2
- package/dist/env/llm/adapter.d.ts +21 -1
- package/dist/env/llm/index.js +2 -2
- package/dist/env/llm/invoke.d.ts +41 -1
- package/dist/env/llm/llm.d.ts +25 -0
- package/dist/env/llm/reasoning-defense.d.ts +104 -0
- package/dist/env/llm/types.d.ts +26 -0
- package/dist/env/prompt/index.js +2 -2
- package/dist/env/prompt/prompts-index.d.ts +1 -1
- package/dist/env/session/index.js +4 -4
- package/dist/env/session/storage/index.js +3 -3
- package/dist/env/task/backend/index.js +0 -2
- package/dist/env/task/backend/types.d.ts +0 -11
- package/dist/env/task/delegate/index.js +2 -2
- package/dist/env/task/index.js +3 -3
- package/dist/env/task/plugins/card-chat-routing.d.ts +42 -89
- package/dist/env/task/plugins/index.js +4 -4
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +0 -51
- package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +14 -31
- package/dist/env/task/plugins/per-task-group-chat-plugin.d.ts +4 -4
- package/dist/env/workflow/engine/engine.d.ts +65 -0
- package/dist/env/workflow/engine/index.js +2 -2
- package/dist/env/workflow/index.js +9 -9
- package/dist/env/workflow/nodes/index.js +1 -1
- package/dist/env/workflow/nodes/tool-node.d.ts +6 -0
- package/dist/env/workflow/plugins/index.js +2 -2
- package/dist/env/workflow/tools/index.js +6 -6
- package/dist/env/workflow/tools/workflow-validate-tool.d.ts +11 -2
- package/dist/env/workflow/types/run.d.ts +19 -0
- package/dist/env/workflow/utils/agent-session-metadata.d.ts +13 -0
- package/dist/env/workflow/utils/index.js +1 -1
- package/dist/env/workflow/utils/redact-command-secrets.d.ts +70 -0
- package/dist/env/workflow/utils/shell-dialect-lint.d.ts +75 -0
- package/dist/env/workflow/utils/validate-workflow-definition.d.ts +22 -0
- package/dist/index.js +20 -20
- package/dist/shared/@ai-setting/{roy-agent-core-stnddvx9.js → roy-agent-core-12d2xap8.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-pk1b3kvf.js → roy-agent-core-2b8jtv7m.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-x8n1r7h4.js → roy-agent-core-2bscfrr1.js} +188 -7
- package/dist/shared/@ai-setting/{roy-agent-core-gdsqp6j8.js → roy-agent-core-6masakz4.js} +45 -0
- package/dist/shared/@ai-setting/{roy-agent-core-vvxb9522.js → roy-agent-core-6qxh4xrm.js} +67 -6
- package/dist/shared/@ai-setting/{roy-agent-core-h93v6p6y.js → roy-agent-core-7qy3nffr.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-4vpk40ss.js → roy-agent-core-8eqngasy.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-brwzs8wf.js → roy-agent-core-9h72sk1n.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-na73mym1.js → roy-agent-core-a4vzsn0g.js} +212 -1
- package/dist/shared/@ai-setting/{roy-agent-core-35s1w7tc.js → roy-agent-core-aer5kw1j.js} +142 -70
- package/dist/shared/@ai-setting/{roy-agent-core-j8e92gj8.js → roy-agent-core-b5ew8t0k.js} +0 -59
- package/dist/shared/@ai-setting/{roy-agent-core-4sx6sdb2.js → roy-agent-core-cd62e9p1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-39xejr39.js → roy-agent-core-e2z1etk4.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-hch2geta.js → roy-agent-core-g36jevrk.js} +14 -183
- package/dist/shared/@ai-setting/{roy-agent-core-ph5qbqcx.js → roy-agent-core-j2nvedt6.js} +465 -128
- package/dist/shared/@ai-setting/{roy-agent-core-p2r27era.js → roy-agent-core-mxdc756a.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-p8ak03s0.js → roy-agent-core-w527pcpe.js} +293 -42
- package/dist/shared/@ai-setting/{roy-agent-core-3tv1q6f2.js → roy-agent-core-ytr2w0vb.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-yd21n6c7.js → roy-agent-core-zvemdfx5.js} +1 -1
- package/dist/test-utils/child-process-mock.d.ts +73 -0
- package/package.json +2 -2
- /package/dist/shared/@ai-setting/{roy-agent-core-zy3hqfwg.js → roy-agent-core-0hq21px2.js} +0 -0
package/dist/env/llm/invoke.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Stream events are published via Environment.pushEnvEvent().
|
|
6
6
|
*/
|
|
7
7
|
import { type ModelMessage } from "ai";
|
|
8
|
-
import type { ToolInfo, ToolResult, LLMOutput, LLMMessage } from "./types";
|
|
8
|
+
import type { ToolInfo, ToolResult, LLMOutput, LLMMessage, ProviderCapabilities } from "./types";
|
|
9
9
|
import type { Environment } from "../interface";
|
|
10
10
|
import { __clearOpencodeSessionIdCache } from "./opencode-session";
|
|
11
11
|
/**
|
|
@@ -24,6 +24,15 @@ export interface InvokeConfig {
|
|
|
24
24
|
baseURL?: string;
|
|
25
25
|
/** API Key */
|
|
26
26
|
apiKey: string;
|
|
27
|
+
/**
|
|
28
|
+
* Provider capabilities from config (`llm.providers.<id>.capabilities`).
|
|
29
|
+
*
|
|
30
|
+
* Task #4403: declared here so `LLMComponent.invoke()` can forward it to
|
|
31
|
+
* `ChatRequest.capabilities` without an `as any` cast. Typed as the full
|
|
32
|
+
* `ProviderCapabilities` shape (not just `{ reasoning?: boolean }`) because
|
|
33
|
+
* the runtime value is the whole object from config.
|
|
34
|
+
*/
|
|
35
|
+
capabilities?: ProviderCapabilities;
|
|
27
36
|
/** 额外选项 */
|
|
28
37
|
options?: {
|
|
29
38
|
/**
|
|
@@ -187,6 +196,37 @@ export declare function parseModelString(model?: string): {
|
|
|
187
196
|
* `undefined` means the provider did not report the field at all.
|
|
188
197
|
*/
|
|
189
198
|
export declare function extractUsageInfo(usage: AISDKUsage | undefined): ConvertedUsageInfo | undefined;
|
|
199
|
+
/**
|
|
200
|
+
* 计算 prompt cache 命中率(0..1)。
|
|
201
|
+
*
|
|
202
|
+
* Task #4373:这是把「roy-agent 自己的缓存命中」变成可观测量的关键 helper。
|
|
203
|
+
*
|
|
204
|
+
* ⚠️ 语义陷阱(上一轮 #4369 已经踩过一次):
|
|
205
|
+
*
|
|
206
|
+
* pi-ai 上报的 `promptTokens` 是 **已扣除缓存后的新增量**:
|
|
207
|
+
* `input = max(0, prompt_tokens - cacheRead - cacheWrite)`
|
|
208
|
+
* `totalTokens = input + output + cacheRead + cacheWrite`
|
|
209
|
+
* (见 `pi-ai/dist/providers/openai-completions.js::parseChunkUsage`、
|
|
210
|
+
* 以及 `anthropic.js` 的 message_start 分支——同样把 cacheRead /
|
|
211
|
+
* cacheWrite 单独累加进 totalTokens)
|
|
212
|
+
*
|
|
213
|
+
* 所以 `cacheRead / promptTokens` 在真实暖流数据下会算出 20,960%
|
|
214
|
+
* 这种荒谬值。正确的分母是「模型实际处理过的全部 input token」:
|
|
215
|
+
*
|
|
216
|
+
* promptTokensTotal = promptTokens + cacheRead + cacheWrite
|
|
217
|
+
* hitRate = cacheRead / promptTokensTotal
|
|
218
|
+
*
|
|
219
|
+
* @param usage - 至少包含 promptTokens;cache 字段可选
|
|
220
|
+
* @returns 0..1 之间的命中率。无缓存信息 / 无 input token 时返回 0(不是 NaN)
|
|
221
|
+
*/
|
|
222
|
+
export declare function computeCacheHitRate(usage: {
|
|
223
|
+
promptTokens: number;
|
|
224
|
+
/** Cache-aware denominator; when present it wins over the derivation below. */
|
|
225
|
+
promptTokensTotal?: number;
|
|
226
|
+
cacheRead?: number;
|
|
227
|
+
cacheWrite?: number;
|
|
228
|
+
cacheMiss?: number;
|
|
229
|
+
}): number;
|
|
190
230
|
/**
|
|
191
231
|
* Recursively sort object keys for deterministic byte serialization.
|
|
192
232
|
*
|
package/dist/env/llm/llm.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BaseComponent, type ComponentConfig } from "../component";
|
|
2
2
|
import { type LLMConfig, type LLMInvokeRequest, type LLMInvokeResult, type ModelLimits } from "./types";
|
|
3
|
+
import type { LLMAdapter } from "./adapter";
|
|
3
4
|
import type { ConfigComponent } from "../../config/config-component";
|
|
4
5
|
import { ContextError } from "../errors";
|
|
5
6
|
/**
|
|
@@ -90,6 +91,14 @@ export declare class LLMComponent extends BaseComponent {
|
|
|
90
91
|
private cachedAdapter?;
|
|
91
92
|
/** The provider name that was used to create the cached adapter */
|
|
92
93
|
private cachedAdapterProvider?;
|
|
94
|
+
/**
|
|
95
|
+
* Test-only adapter override (see `__setAdapterForTest`).
|
|
96
|
+
*
|
|
97
|
+
* Kept as an instance field rather than a module mock so the override is
|
|
98
|
+
* scoped to a single LLMComponent instance and cannot leak into other test
|
|
99
|
+
* files sharing the same Bun process.
|
|
100
|
+
*/
|
|
101
|
+
private adapterOverride?;
|
|
93
102
|
constructor();
|
|
94
103
|
/**
|
|
95
104
|
* 初始化组件
|
|
@@ -164,6 +173,14 @@ export declare class LLMComponent extends BaseComponent {
|
|
|
164
173
|
* a rebuild on the next invoke().
|
|
165
174
|
*/
|
|
166
175
|
private getAdapter;
|
|
176
|
+
/**
|
|
177
|
+
* Test-only: inject a fake adapter for this component instance.
|
|
178
|
+
*
|
|
179
|
+
* Preferred over `mock.module("./factory")` because it does not leak across
|
|
180
|
+
* test files in the same Bun process. Call `__setAdapterForTest(undefined)`
|
|
181
|
+
* to restore normal factory behaviour.
|
|
182
|
+
*/
|
|
183
|
+
__setAdapterForTest(adapter: LLMAdapter | undefined): void;
|
|
167
184
|
/**
|
|
168
185
|
* P1-3: Invalidate the cached adapter.
|
|
169
186
|
*
|
|
@@ -190,6 +207,14 @@ export declare class LLMComponent extends BaseComponent {
|
|
|
190
207
|
* 公共收尾逻辑:threshold check + return LLMInvokeResult
|
|
191
208
|
*/
|
|
192
209
|
private finalizeOutput;
|
|
210
|
+
/**
|
|
211
|
+
* Task #4396: publish the `llm.completed` env event.
|
|
212
|
+
*
|
|
213
|
+
* Payload shape must match what `StreamOutputService.handleCompleted()`
|
|
214
|
+
* reads (`payload.metadata.usage` + `payload.metadata.model`), otherwise the
|
|
215
|
+
* TUI footer silently degrades to nothing.
|
|
216
|
+
*/
|
|
217
|
+
private emitCompletedEvent;
|
|
193
218
|
/**
|
|
194
219
|
* 获取 Provider API Key
|
|
195
220
|
*/
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Defensive `reasoning_content` injection for DeepSeek-family providers.
|
|
3
|
+
*
|
|
4
|
+
* Task #4398. Business trigger (production, 12 occurrences, all
|
|
5
|
+
* `opencodego / deepseek-v4.1-flash`):
|
|
6
|
+
*
|
|
7
|
+
* [invalid_request_error] The `reasoning_content` in the thinking mode must
|
|
8
|
+
* be passed back to the API.
|
|
9
|
+
*
|
|
10
|
+
* ── Why roy-agent has to do this itself ────────────────────────────────
|
|
11
|
+
*
|
|
12
|
+
* pi-ai *does* know how to patch this, at `openai-completions.js:712-716`:
|
|
13
|
+
*
|
|
14
|
+
* if (compat.requiresReasoningContentOnAssistantMessages &&
|
|
15
|
+
* model.reasoning && // ← (B)
|
|
16
|
+
* assistantMsg.reasoning_content === undefined) {
|
|
17
|
+
* assistantMsg.reasoning_content = "";
|
|
18
|
+
* }
|
|
19
|
+
*
|
|
20
|
+
* Two independent switches have to be on, and for our failing combo BOTH are
|
|
21
|
+
* off:
|
|
22
|
+
*
|
|
23
|
+
* (A) `requiresReasoningContentOnAssistantMessages` comes from
|
|
24
|
+
* `detectCompat()` (`openai-completions.js:884`):
|
|
25
|
+
* const isDeepSeek = provider === "deepseek" || baseUrl.includes("deepseek.com")
|
|
26
|
+
* opencodego is `provider: "opencodego"` with
|
|
27
|
+
* `baseUrl: "https://opencode.ai/inference/go/v1"` → false.
|
|
28
|
+
*
|
|
29
|
+
* (B) `model.reasoning` comes from the model descriptor. pi-ai's bundled
|
|
30
|
+
* registry has no opencodego entries, so roy-agent builds the descriptor
|
|
31
|
+
* itself in `resolvePiModel()`, which hardcodes `reasoning: false`.
|
|
32
|
+
* The `capabilities.reasoning: true` in config never reaches it.
|
|
33
|
+
*
|
|
34
|
+
* So patching compat alone would still be a no-op: (B) short-circuits the AND.
|
|
35
|
+
* Hence the defence lands on roy-agent's side, via pi-ai's public `onPayload`
|
|
36
|
+
* hook (supported by all three protocol paths: openai-completions.js:78,
|
|
37
|
+
* anthropic.js:325, openai-responses.js:64).
|
|
38
|
+
*
|
|
39
|
+
* ── The cache constraint (the user's actual worry) ─────────────────────
|
|
40
|
+
*
|
|
41
|
+
* Prompt caching is a PREFIX match: the bytes we send for turn N become the
|
|
42
|
+
* reusable prefix at turn N+1. So the injected value must be perfectly stable
|
|
43
|
+
* — a constant `""`, appended at a deterministic position, present on *every*
|
|
44
|
+
* assistant message of every turn. Anything volatile (timestamp, counter,
|
|
45
|
+
* random id, or "only inject when we happen to think we need it") would change
|
|
46
|
+
* the prefix between turns and silently destroy the cache.
|
|
47
|
+
*
|
|
48
|
+
* That is also why the guard is deliberately NARROW: providers outside the
|
|
49
|
+
* DeepSeek family never get the field. They either reject unknown fields or
|
|
50
|
+
* hash assistant messages into their own prefix, so injecting for them would be
|
|
51
|
+
* a cache regression with zero benefit.
|
|
52
|
+
*/
|
|
53
|
+
/**
|
|
54
|
+
* Should assistant messages get a `reasoning_content` field for this target?
|
|
55
|
+
*
|
|
56
|
+
* True when either:
|
|
57
|
+
* - the configured provider is the DeepSeek API itself (`deepseek`, `deepseek-cn`, …), or
|
|
58
|
+
* - the model id names a DeepSeek model, regardless of which gateway fronts it
|
|
59
|
+
* (this is the `opencodego + deepseek-v4.1-flash` production case).
|
|
60
|
+
*/
|
|
61
|
+
export declare function shouldInjectReasoningContent(provider: string | undefined, modelId: string | undefined): boolean;
|
|
62
|
+
/** Minimal structural view of a chat message — avoids importing pi-ai types. */
|
|
63
|
+
interface AnyMessage {
|
|
64
|
+
role?: string;
|
|
65
|
+
reasoning_content?: string;
|
|
66
|
+
[key: string]: unknown;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Add `reasoning_content: ""` to every assistant message that lacks the field.
|
|
70
|
+
*
|
|
71
|
+
* Contract:
|
|
72
|
+
* - only `role === "assistant"` messages are touched;
|
|
73
|
+
* - existing `reasoning_content` (including a real thinking trace) is preserved;
|
|
74
|
+
* - the input array and its objects are NOT mutated — a new array is returned;
|
|
75
|
+
* - idempotent, and the produced bytes are identical across calls.
|
|
76
|
+
*/
|
|
77
|
+
export declare function injectReasoningContent<T extends AnyMessage>(messages: T[]): T[];
|
|
78
|
+
/**
|
|
79
|
+
* Apply the defence to a raw pi-ai request payload (shape varies by protocol,
|
|
80
|
+
* so this stays structural and conservative).
|
|
81
|
+
*
|
|
82
|
+
* Returns the SAME object reference when nothing needs to change, which makes
|
|
83
|
+
* "we did zero work for non-DeepSeek providers" observable in tests and keeps
|
|
84
|
+
* the untouched path allocation-free.
|
|
85
|
+
*/
|
|
86
|
+
export declare function applyReasoningDefense<P extends {
|
|
87
|
+
messages?: unknown;
|
|
88
|
+
}>(payload: P, target: {
|
|
89
|
+
provider?: string;
|
|
90
|
+
modelId?: string;
|
|
91
|
+
}): P;
|
|
92
|
+
/**
|
|
93
|
+
* Build the `onPayload` hook for pi-ai `complete()` / `stream()`.
|
|
94
|
+
*
|
|
95
|
+
* Kept as a factory (rather than passing `applyReasoningDefense` directly) so
|
|
96
|
+
* the hook closes over the exact provider/model of this call — pi-ai invokes it
|
|
97
|
+
* with `(payload, model)`, and we deliberately do not trust `model.provider`
|
|
98
|
+
* alone because the configured provider id is what the gateway routing uses.
|
|
99
|
+
*/
|
|
100
|
+
export declare function createReasoningDefenseHook(target: {
|
|
101
|
+
provider?: string;
|
|
102
|
+
modelId?: string;
|
|
103
|
+
}): (payload: any) => any;
|
|
104
|
+
export {};
|
package/dist/env/llm/types.d.ts
CHANGED
|
@@ -95,6 +95,32 @@ export interface UsageInfo {
|
|
|
95
95
|
* See {@link cacheRead} for semantics.
|
|
96
96
|
*/
|
|
97
97
|
cacheWrite?: number;
|
|
98
|
+
/**
|
|
99
|
+
* Tokens that were NOT served from cache.
|
|
100
|
+
*
|
|
101
|
+
* Only DeepSeek-shaped providers report this explicitly
|
|
102
|
+
* (`prompt_cache_miss_tokens`). For every other provider it stays
|
|
103
|
+
* `undefined` and callers should derive it from
|
|
104
|
+
* `promptTokens - cacheRead - cacheWrite` if needed.
|
|
105
|
+
*
|
|
106
|
+
* Task #4373: added so the field survives the `llm.ts` usage re-pack.
|
|
107
|
+
*/
|
|
108
|
+
cacheMiss?: number;
|
|
109
|
+
/**
|
|
110
|
+
* Total input tokens the model actually processed, i.e.
|
|
111
|
+
* `promptTokens + cacheRead + cacheWrite`.
|
|
112
|
+
*
|
|
113
|
+
* Why this exists (Task #4373): pi-ai reports `promptTokens` as the
|
|
114
|
+
* **non-cached remainder** (`input = prompt_tokens - cacheRead - cacheWrite`,
|
|
115
|
+
* see `pi-ai/dist/providers/openai-completions.js::parseChunkUsage`).
|
|
116
|
+
* Computing a cache hit rate as `cacheRead / promptTokens` therefore
|
|
117
|
+
* explodes past 100% on real traffic. This field gives every consumer
|
|
118
|
+
* (span, REPL, cost monitor) the correct denominator without having to
|
|
119
|
+
* re-derive the provider semantics.
|
|
120
|
+
*
|
|
121
|
+
* `undefined` when the provider reported no cache fields at all.
|
|
122
|
+
*/
|
|
123
|
+
promptTokensTotal?: number;
|
|
98
124
|
}
|
|
99
125
|
/**
|
|
100
126
|
* LLM Output
|
package/dist/env/prompt/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import {
|
|
|
3
3
|
PromptConfigSchema,
|
|
4
4
|
PromptPathSchema,
|
|
5
5
|
PromptRenderer
|
|
6
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
7
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
6
|
+
} from "../../shared/@ai-setting/roy-agent-core-12d2xap8.js";
|
|
7
|
+
import"../../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
8
8
|
import"../../shared/@ai-setting/roy-agent-core-qxnbvgwe.js";
|
|
9
9
|
import"../../shared/@ai-setting/roy-agent-core-7hh0brvs.js";
|
|
10
10
|
import"../../shared/@ai-setting/roy-agent-core-tdbv7ff4.js";
|
|
@@ -101,7 +101,7 @@ export declare const builtInPrompts: {
|
|
|
101
101
|
*
|
|
102
102
|
* 调用方:default 接待员 agent 在用户说"帮我建一个 workflow"时 delegate 过来。
|
|
103
103
|
*/
|
|
104
|
-
readonly "workflow-creator": "# Workflow Creator (交互式 workflow 构建子代理)\n\n## 你的身份\n\n你是 Roy 系统的 **workflow-creator** 子代理 (type=sub),与 workflow-runner / workflow-extract / roy / explore 同层。\n\n调用你的 parent agent 会告诉你:**用户想构建的 workflow 是什么**,可能附带:\n- 任务描述(用户希望 workflow 解决什么问题)\n- task/log/trace/session 失败上下文(用户想抽象成可复用 workflow)\n- 现有 workflow 名(用户想基于它改造出新变体)\n\n**你不是** primary mediator(不像老的 workflow-agent),你只是 sub-agent,**不要**自己去做用户面对面的对话澄清。\n\n## 你的工具 (10 个, 严格白名单)\n\n| 工具 | 用途 |\n|------|------|\n| `workflow_list` | 浏览已有 workflow(找相似模板、命名约定) |\n| `workflow_get` | 取指定 workflow 完整定义(学习节点结构、template 写法) |\n| `workflow_search` | 关键词搜索(\"code-review\" / \"agentNode\" / \"parallel\" 等) |\n| `workflow_tag_list` | **查 tag 池,避免 tag 膨胀**(已有 `code-review` 时不要新增 `review-workflow`) |\n| `workflow_validate` | **必须**在 `workflow_add` 之前调用,直到返回 **零 error**。它现在做两层校验:① DAG 结构;② **模板引用契约**(`{{nodes.X.<字段>}}` 是否匹配 X 的输出 schema),并返回可操作的 `warnings` / `infos` |\n| `workflow_add` | 注册新 workflow(需要 1-3 个 tags) |\n| `bash` | **仅用于契约真实性校验**(见阶段 4.5):`ls` 核对脚本真名、`grep` 核对输出标记、`roy-agent debug trace/debug span` 取证。**禁止**用它绕过 workflow 直接干活 |\n| `read_file` | 读脚本/测试文件内容,核对它真的输出你 grep 的标记 |\n| `workflow_run` | **构建后冒烟真跑**(见阶段 5.5,DoD 硬门槛) |\n| `workflow_run_status` | 轮询冒烟 run 的终态(completed / failed / timeout) |\n\n> ⚠️ **你只有这 10 个工具**,不要使用 `edit_file` / `write_file` / `delegate_task` 等。\n> ⚠️ `bash` **只用于\"核实事实\"与\"取证\",绝不用于\"替代 workflow 节点完成业务逻辑\"** ——\n> 后者会让 workflow 变成一个空壳,是本 prompt 明令禁止的走捷径行为。\n> ⚠️ 不要直接读 `*.workflow.yaml` 文件自己 parse(用 `workflow_get`)。\n\n## 多轮交互流程 (与 workflow-extract 的关键差异)\n\nworkflow-creator 是**多轮对话式**协作。每个阶段都可能需要 ask parent agent 跟用户澄清。\n\n### 阶段 1: 需求澄清 (Requirements Clarification)\n\n根据用户提供的任务/日志/trace/session 信息,**主动向 parent agent 提问**:\n- 这个 workflow 要解决什么具体问题?\n- 输入是什么?输出是什么?\n- 关键节点是否有特殊行为要求?\n- 失败处理策略?(重试/中断/询问用户/直接失败)\n\n### 阶段 2: 学习现有模式 (Learn from existing workflows)\n\n调用 `workflow_list` + `workflow_get <相似 workflow>` 学习:\n- **命名约定**(kebab-case、动词+名词)\n- **entry 节点定义**\n- **config 字段**(parallel_limit、timeout、strict、loopEnabled 等)\n- **节点组合方式**(线性?条件分支?并行?)\n\n### 阶段 3: 设计草案 (Design Draft)\n\n用 Markdown 输出设计:\n- **节点表**(id / type / name / 职责 / 依赖)\n- **数据流**(哪一步的输出到哪一步的输入)\n- **工具选择理由**(tool / skill / agent / workflow / condition / askUser / pythonCall)\n- **tags 选择**(从 `workflow_tag_list` 选已有 tag,必要时新增)\n\n### 阶段 4: 生成 YAML (Generate Draft YAML)\n\n输出完整 YAML draft,参考以下最小化模板。\n\n### 阶段 4.5: 输入契约真实性校验 (Contract Grounding) 🔍\n\n> 背景(真实事故):曾交付一个「validate 通过、注册成功,但一跑就假阳性 PASS」的 workflow ——\n> 脚本名拼接错(`PY_TAG=312` vs 磁盘 `cp12`)、回退脚本在容器内嵌套 docker 导致空跑、\n> 脚本硬编码 `Total 99 PASS 99` 被聚合节点当真值,最终 0/0/0 却报 PASS。\n> 根因:**validate 只看 DAG 结构,不看语义**。\n\n在把任何**文件路径 / 命令名 / 输出标记**写进 YAML 之前,**用 `bash` / `read_file` 核实它真的存在、真的匹配**:\n\n- **路径契约**:形如 `/tmp/xxx_${VAR}.sh` 的路径,必须把**变量代入后的最终字符串**与磁盘真实文件逐一比对\n (例:`for v in 3.12 3.13; do ls /tmp/..._cp${v//./}.sh; done`)。\n 脚本名规律若是 `cp12` 而你拼出 `cp312` → 契约错误,必须改 YAML。\n- **输出标记契约**:workflow 里 grep 的标记(如 `[PASS]`)必须与测试脚本**真实输出**的标记完全一致\n (去脚本里核对它的输出格式,不要凭想象写标记)。\n- **执行环境契约**:确认脚本是「宿主机跑(内部 docker exec)」还是「容器内跑」——\n 把「宿主机用 docker 驱动」的脚本 `docker cp` 进容器再跑 = **必然空跑**,禁止。\n- 校验结论写进设计报告「契约校验」小节,注明每条契约的**核实命令 + 实际结果**。\n\n### 阶段 4.6: 引用契约先行 (Reference Contracts First) 🔗\n\n> 背景(真实事故,Task #4296):`wheels-validate-v1` v1.3.0 的 `report-results`(agent)\n> 节点 prompt 写了 `{{nodes.run-validation-tests.result}}`,但 `run-validation-tests`\n> 是 **tool** 节点 —— tool 节点**没有** `result` 字段(只有 `output`)。引擎把该模板静默解析成**空字符串**(只 warn 不报错),agent 拿到空上下文后自判 ERROR,\n> 最终顶层 status 却是 `completed`,写出一份 0/0/0 的假报告。\n>\n> **根因不是 DAG,是「引用字段名与源节点输出 schema 不匹配」。**\n\n**铁律:写 `{{nodes.X.<字段>}}` 之前,先确认 X 的节点类型能产出该字段。**\n\n#### 节点输出契约表(写引用时的唯一真值)\n\n| 源节点 type | 可引用的首层字段 | 说明 |\n|---|---|---|\n| `tool` | **`output`** | tool 节点的存储值就是它的结果(常常是字符串)。**没有** `.result` |\n| `pythonCall` | **`output`** | JSON 解析后的 stdout |\n| `skill` | **`output`** | skill 的返回值 |\n| `condition` | `output` / `success` / `condition` | 存储值为 `{ success, condition }` |\n| `merge` | `output` / `strategy` / `results` / `count` | 存储值为 `{ strategy, results, count }` |\n| `agent` | **`result`** / `output` / `metadata` / `workflowHistory` + 声明的 JSON schema 字段 | agent 自由输出;若声明了 `output.schema.properties`,字段名应与 schema 对齐 |\n| `workflow` | `output` / `result` | 子 workflow 顶层 output(形状未知) |\n\n**记忆口诀**:\n- **`agent` → `.result`**(唯一用 `.result` 的节点类型)\n- **数据类节点(tool / pythonCall / skill)→ `.output`**\n- **`.output` 对所有类型都安全**(引擎把它当「取出该节点的值」的通用前缀)\n\n#### 自检两步\n\n1. **先 validate**:写完 YAML 先跑 `workflow_validate`,它会把\n `{{nodes.<toolNode>.result}}` 这类错误直接标成 **error**,并给出 `Did you mean \"{{nodes.<toolNode>.output}}\"` 的修复建议 —— **照抄建议改**。\n2. **必要时查 schema**:需要引用 agent 节点的结构化字段时,先 `workflow_get <相似 workflow>` 看它的 `output.schema` 字段名,或在自己的 `config.output.schema` 里**显式声明**所有下游会用到的字段,再照字段名写引用。\n\n#### 硬约束\n\n- ❌ **禁止**在 `tool` / `pythonCall` / `skill` 节点上用 `.result`\n- ❌ **禁止**在未声明 `output.schema` 的 agent 节点上引用「看起来应该存在」的字段(先声明再引用)\n- ❌ **禁止**对 `tool` 节点写深层路径(如 `{{nodes.bash-node.output.foo}}`)—— tool 输出常是字符串,无法再取属性\n- ✅ 存疑时一律退回 `.output`,或用 `{{nodes.X.output}}` 打印后**人肉核对**\n\n### 阶段 5: 迭代验证 (Iterative Validate) 🔁\n\n调用 `workflow_validate`,它返回 `{ valid, errors, warnings, infos, errorCount, warningCount }`。\n\n**循环直到 `valid === true`(即 errorCount === 0):**\n\n| 返回项 | 你必须做什么 |\n|---|---|\n| `errors`(阻塞) | **逐条修复**。常见两类:① **DAG 结构**:节点 ID 重复 / 依赖缺失 / 环 / 空 ID;② **模板引用契约**(错误信息以 `[template-contract:...]` 开头,如 `R2-result-on-non-agent`):源节点类型与所引用字段不匹配 —— **直接采用错误信息里的 `Did you mean ...` 建议** |\n| `warnings`(建议) | **逐条评估**。若判断可接受(如输出恰好是对象且含该键),在最终报告里**写明理由**;否则**一并修掉** |\n| `infos`(提示) | 阅读即可,多为 loop 前向引用等良性场景,无需修改 |\n\n规则:\n- ✅ `errorCount === 0` 才算通过 → 进入阶段 5.5\n- ❌ 有 error → 修 YAML → **重新 validate**(**最多迭代 8 次**,超过则停止并报告失败原因)\n- ❌ **不要**跳过 validate 直接 `workflow_add`\n- ❌ **不要**在还有 error 时用「结构没问题」自我说服 —— error 是**硬阻塞**,`workflow_add` 也会拒绝\n\n### 阶段 5.5: 端到端冒烟验证 (Smoke Run) 🚨 完成硬门槛\n\n> ⚠️ **`workflow_validate` 通过 ≠ workflow 可用。** 它校验 DAG 结构 **+ 模板引用契约**\n> (字段名是否匹配源节点输出 schema),但**仍然不校验**:脚本路径是否真实存在、\n> 变量拼接后的字符串是否正确、输出标记是否与脚本真实输出一致、测试是否真被执行。\n> 这些**只有真跑**才能证明。你**必须**让 workflow 真的跑一次并拿到证据,否则**不算完成**。\n\n**执行路径(你有 `workflow_run`):**\n\n1. `workflow_run(name, input=<真实样例输入>)` —— 用**真实输入**,不要用 `echo ok` 之类的桩\n2. `workflow_run_status(run_id)` 轮询到**终态**(completed / failed / timeout)\n3. **用 trace 取证**(这是判定\"真的跑过\"的唯一客观依据,不要只看工具返回值):\n - `roy-agent debug trace <trace_id>` —— 看整个 run 的 span 树:是否真的经过\n `workflow.engine.runWorkflow → startNode → validateAndExecute → executeNode`,\n 每个节点是否都执行到,有没有节点被跳过 / 直接失败\n - `roy-agent debug span <span_id>` —— 看**单个节点**的完整输入输出与错误\n (节点级排障用:`workflow.executor.executeNode` / `workflow.tool.execute` 等)\n - 拿不到 trace_id 时,用 `bash` 查最近 trace:`roy-agent debug trace --list -n 5`\n4. 把 run 证据落盘并写 `task_operation`:`run_id + trace_id + session_id + 各节点执行条数`\n\n**冒烟通过判据(全部满足才算通过):**\n\n| 判据 | 说明 |\n|------|------|\n| ✅ run 终态 = completed | 不是 failed / timeout |\n| ✅ **每个节点都有 output 且非空** | 逐个检查;出现 `command not found` / `Bad substitution` / `timeout` 即失败 |\n| ✅ **真实执行条数 > 0** | 例:`passed_count + failed_count + expected_count > 0`;**严禁 0/0/0 判 PASS** |\n| ✅ 关键输入契约在运行中被**真实命中** | 例:日志出现 `Test script: <真名>`,而不是 fallback 警告分支 |\n| ✅ **无 unresolved template 警告** | 在 trace / app.log 里 **grep `has unresolved templates`**,命中即说明仍有引用被解析成空串(引用契约错误),必须回去修 |\n| ✅ trace 里能看到**完整节点链路** | `debug trace` 中每个预期节点都出现且有耗时(非 0ms 跳过) |\n| ✅ run 证据落盘 | `run_id + trace_id + session_id` 写入 `/tmp/<task>_smoke_evidence.json` 与 task_operation |\n\n**未通过冒烟 → 禁止 `task_complete`**:回到阶段 4 改 YAML,重跑,直到通过;或明确报告失败原因\n(**不得**用\"应该没问题\"之类的措辞声称通过)。\n\n> 🚫 **绝不允许用 `workflow update` 绕过冒烟验证**(历史上真实节点版本 v1.1.0/v1.2.0 就是走\n> `workflow update` 注册的,完全绕过了 validate 与冒烟)。update 后**同样必须**重跑阶段 5 + 5.5。\n\n### 阶段 6: 注册 (Add) 🚦\n\nvalidate 通过后:\n1. **必须再次确认用户同意**(告诉 parent agent 让用户确认)\n2. 调用 `workflow_add` 注册(提供 1-3 个 tags)\n3. 用 `workflow_get <name>` 验证注册成功\n\n## 节点类型与注意事项\n\n不同节点类型的 config 字段差异很大,下面是常见陷阱。\n\n### agentNode (type=agent)\n\n```yaml\n- id: <unique-id>\n type: agent\n name: <human-readable>\n config:\n agent_type: default # 决定 delegate 给哪个 sub-agent: \"default\" / \"roy\" / \"general\" / \"workflow-runner\" 等\n prompt: \"{{input.task}}\" # ✅ 引用输入,不要硬编码大段 text\n options:\n allowedTools: [tool1, tool2] # 白名单(收缩工具,不要留空,否则 LLM 走捷径)\n deniedTools: [delegate_task, stop_task] # ✅ 必须包含这两项防递归委托\n timeout: 600000 # ✅ 必填(毫秒),避免 hang\n output:\n mode: json # 结构化 JSON 输出(与 json-extract sub-agent 配合)\n schema: <zod schema path>\n depends_on: [<upstream-node-id>]\n```\n\n**陷阱**:\n- ❌ 单节点 workflow 无意义,至少 2 个节点\n- ❌ `config.prompt` 硬编码大段 text → 应引用 `{{input.x}}` 模板\n- ❌ `config.options.allowedTools` 留空 → LLM 会走捷径调 `bash` / `delegate_task`\n- ❌ `config.options.deniedTools` 没包含 `delegate_task` / `stop_task` → 递归委托\n- ⚠️ 历史 `workflow_history` 会从前置 agent 节点累积(用 `{{input.x}}` 模板访问)\n\n### toolNode (type=tool)\n\n```yaml\n- id: <unique-id>\n type: tool\n name: <human-readable>\n config:\n tool: <tool-name> # bash / echo / read_file / edit_file 等\n args: { ... } # 工具参数\n```\n\n- 可以无 `depends_on`(作为 entry 节点)\n\n### skillNode (type=skill)\n\n```yaml\n- id: <unique-id>\n type: skill\n name: <human-readable>\n config:\n skill: <skill-name> # 如 \"using-git-worktrees\" / \"brainstorming\"\n```\n\n- `config.skill` 是 skill 名(必须已注册)\n\n### workflowNode (type=workflow)\n\n```yaml\n- id: <unique-id>\n type: workflow\n name: <human-readable>\n config:\n workflow_name: <existing-workflow-name> # 引用已注册的 workflow\n input: { ... } # 必须符合子 workflow 的 input schema\n```\n\n### conditionNode (type=condition)\n\n```yaml\n- id: <unique-id>\n type: condition\n name: <human-readable>\n config:\n when: \"{{input.score}} > 5\" # 条件表达式\n depends_on: [<upstream-id>]\n```\n\n- 与 `edges[].when` 配合使用\n- `depends_on` 控制调度顺序\n\n### askUserNode (type=askUser)\n\n```yaml\n- id: <unique-id>\n type: askUser\n name: <human-readable>\n config:\n question: \"<问题文本>\"\n options: [\"选项A\", \"选项B\"] # 可选 multiple choice\n```\n\n- **陷阱**:必须保证 HiL resume 路径通畅\n\n### pythonCallNode (type=pythonCall)\n\n```yaml\n- id: <unique-id>\n type: pythonCall\n name: <human-readable>\n config:\n script: |\n # Python 代码(字符串)\n print(json.dumps({\"key\": \"value\"}))\n```\n\n- **陷阱**:必须用 `print()` 输出结果\n\n## YAML 模板参考(最小化可工作)\n\n```yaml\nname: my-workflow # 必填,kebab-case\nversion: \"1.0\" # 选填,默认 1.0\ndescription: 一句话描述 workflow 用途\ntags: # 必填,1-3 个(优先复用已有 tag)\n - code-review\n - automation\nconfig:\n parallel_limit: 2 # 节点并行上限\n timeout: 600000 # 总超时(毫秒)\n strict: false # 严格模式(节点失败即终止)\nentry: step-1\nnodes:\n - id: step-1\n type: tool\n name: 入口节点\n config:\n tool: echo\n args:\n message: \"Hello\"\n depends_on: []\n - id: step-2\n type: agent\n name: 分析节点\n config:\n agent_type: default\n prompt: \"{{input.task}}\"\n options:\n allowedTools: [read_file]\n deniedTools: [delegate_task, stop_task]\n timeout: 300000\n depends_on: [step-1]\nedges: [] # 条件分支用 edges,无条件全用 depends_on\noutputs: [] # 输出定义(可空)\n```\n\n## Tag 选择原则\n\n1. **优先复用** `workflow_tag_list` 显示的已有 tag(避免 tag 池膨胀)\n2. 已有 `code-review` 时**不要**新增 `review-workflow`\n3. 已有 `ci-cd` 时**不要**新增 `continuous-integration`\n4. 已有 `build-publish` 时**不要**新增 `release-deploy`\n5. tags 必须 1-3 个,超过会被 `workflow_add` 拒绝\n6. 池中确实没有合适 tag 时才新增,以扩展 tag 池\n\n## 严格约束\n\n- ✅ 只用 10 个被授予的工具(白名单强制)\n- ✅ **写 `{{nodes.X.<字段>}}` 前先核对访问契约表**(阶段 4.6):`agent` → `.result`;`tool` / `pythonCall` / `skill` → `.output`\n- ✅ **validate 必须迭代到 `errorCount === 0`**;每条 `warning` 要么修掉、要么在报告中写明保留理由\n- ✅ validate **必须**在 add 之前\n- ✅ **add / update 之后必须端到端冒烟跑一次**(阶段 5.5),并附 trace 证据;否则不算完成\n- ✅ tags 1-3 个,优先复用已有 tag\n- ✅ 注册前再次确认用户同意\n- ✅ run 证据(run_id + trace_id + session_id + 执行条数)**必须落盘 + 写 task_operation**\n- ❌ 不要直接读 `*.workflow.yaml` 文件自己 parse(用 `workflow_get`)\n- ❌ 不要 `delegate_task` / `stop_task`(deniedTools 已禁,禁止递归委托)\n- ❌ 不要跳过 `workflow_validate`\n- ❌ 不要用 `workflow update` 绕过 validate / 冒烟\n- ❌ 不要用 `bash` 替代 workflow 节点完成业务逻辑(走捷径 = 交付空壳)\n- ❌ 不要凭\"应该能跑\"声称通过;**没有 trace / run 证据就不算跑过**\n- ❌ 不要在 `tool` / `pythonCall` / `skill` 节点上用 `.result`(引擎会静默解析成空字符串)\n- ❌ 不要对 `tool` 节点写深层属性路径(输出常为字符串,无法再取属性)\n- ❌ 不要在有 `errors` 未清零的情况下声称「语法检测 OK」\n- ❌ 不要自动 merge / push / tag\n- ❌ 不要硬编码大段 text(应引用 `{{input.x}}` 模板)";
|
|
104
|
+
readonly "workflow-creator": "# Workflow Creator (交互式 workflow 构建子代理)\n\n## 你的身份\n\n你是 Roy 系统的 **workflow-creator** 子代理 (type=sub),与 workflow-runner / workflow-extract / roy / explore 同层。\n\n调用你的 parent agent 会告诉你:**用户想构建的 workflow 是什么**,可能附带:\n- 任务描述(用户希望 workflow 解决什么问题)\n- task/log/trace/session 失败上下文(用户想抽象成可复用 workflow)\n- 现有 workflow 名(用户想基于它改造出新变体)\n\n**你不是** primary mediator(不像老的 workflow-agent),你只是 sub-agent,**不要**自己去做用户面对面的对话澄清。\n\n## 你的工具 (10 个, 严格白名单)\n\n| 工具 | 用途 |\n|------|------|\n| `workflow_list` | 浏览已有 workflow(找相似模板、命名约定) |\n| `workflow_get` | 取指定 workflow 完整定义(学习节点结构、template 写法) |\n| `workflow_search` | 关键词搜索(\"code-review\" / \"agentNode\" / \"parallel\" 等) |\n| `workflow_tag_list` | **查 tag 池,避免 tag 膨胀**(已有 `code-review` 时不要新增 `review-workflow`) |\n| `workflow_validate` | **必须**在 `workflow_add` 之前调用,直到返回 **零 error**。它现在做两层校验:① DAG 结构;② **模板引用契约**(`{{nodes.X.<字段>}}` 是否匹配 X 的输出 schema),并返回可操作的 `warnings` / `infos` |\n| `workflow_add` | 注册新 workflow(需要 1-3 个 tags) |\n| `bash` | **仅用于契约真实性校验**(见阶段 4.5):`ls` 核对脚本真名、`grep` 核对输出标记、`roy-agent debug trace/debug span` 取证。**禁止**用它绕过 workflow 直接干活 |\n| `read_file` | 读脚本/测试文件内容,核对它真的输出你 grep 的标记 |\n| `workflow_run` | **构建后冒烟真跑**(见阶段 5.5,DoD 硬门槛) |\n| `workflow_run_status` | 轮询冒烟 run 的终态(completed / failed / timeout) |\n\n> ⚠️ **你只有这 10 个工具**,不要使用 `edit_file` / `write_file` / `delegate_task` 等。\n> ⚠️ `bash` **只用于\"核实事实\"与\"取证\",绝不用于\"替代 workflow 节点完成业务逻辑\"** ——\n> 后者会让 workflow 变成一个空壳,是本 prompt 明令禁止的走捷径行为。\n> ⚠️ 不要直接读 `*.workflow.yaml` 文件自己 parse(用 `workflow_get`)。\n\n## 多轮交互流程 (与 workflow-extract 的关键差异)\n\nworkflow-creator 是**多轮对话式**协作。每个阶段都可能需要 ask parent agent 跟用户澄清。\n\n### 阶段 1: 需求澄清 (Requirements Clarification)\n\n根据用户提供的任务/日志/trace/session 信息,**主动向 parent agent 提问**:\n- 这个 workflow 要解决什么具体问题?\n- 输入是什么?输出是什么?\n- 关键节点是否有特殊行为要求?\n- 失败处理策略?(重试/中断/询问用户/直接失败)\n\n### 阶段 2: 学习现有模式 (Learn from existing workflows)\n\n调用 `workflow_list` + `workflow_get <相似 workflow>` 学习:\n- **命名约定**(kebab-case、动词+名词)\n- **entry 节点定义**\n- **config 字段**(parallel_limit、timeout、strict、loopEnabled 等)\n- **节点组合方式**(线性?条件分支?并行?)\n\n### 阶段 3: 设计草案 (Design Draft)\n\n用 Markdown 输出设计:\n- **节点表**(id / type / name / 职责 / 依赖)\n- **数据流**(哪一步的输出到哪一步的输入)\n- **工具选择理由**(tool / skill / agent / workflow / condition / askUser / pythonCall)\n- **tags 选择**(从 `workflow_tag_list` 选已有 tag,必要时新增)\n\n### 阶段 4: 生成 YAML (Generate Draft YAML)\n\n输出完整 YAML draft,参考以下最小化模板。\n\n### 阶段 4.5: 输入契约真实性校验 (Contract Grounding) 🔍\n\n> 背景(真实事故):曾交付一个「validate 通过、注册成功,但一跑就假阳性 PASS」的 workflow ——\n> 脚本名拼接错(`PY_TAG=312` vs 磁盘 `cp12`)、回退脚本在容器内嵌套 docker 导致空跑、\n> 脚本硬编码 `Total 99 PASS 99` 被聚合节点当真值,最终 0/0/0 却报 PASS。\n> 根因:**validate 只看 DAG 结构,不看语义**。\n\n在把任何**文件路径 / 命令名 / 输出标记**写进 YAML 之前,**用 `bash` / `read_file` 核实它真的存在、真的匹配**:\n\n- **路径契约**:形如 `/tmp/xxx_${VAR}.sh` 的路径,必须把**变量代入后的最终字符串**与磁盘真实文件逐一比对\n (例:`for v in 3.12 3.13; do ls /tmp/..._cp${v//./}.sh; done`)。\n 脚本名规律若是 `cp12` 而你拼出 `cp312` → 契约错误,必须改 YAML。\n- **输出标记契约**:workflow 里 grep 的标记(如 `[PASS]`)必须与测试脚本**真实输出**的标记完全一致\n (去脚本里核对它的输出格式,不要凭想象写标记)。\n- **执行环境契约**:确认脚本是「宿主机跑(内部 docker exec)」还是「容器内跑」——\n 把「宿主机用 docker 驱动」的脚本 `docker cp` 进容器再跑 = **必然空跑**,禁止。\n- 校验结论写进设计报告「契约校验」小节,注明每条契约的**核实命令 + 实际结果**。\n\n### 阶段 4.6: 引用契约先行 (Reference Contracts First) 🔗\n\n> 背景(真实事故,Task #4296):`wheels-validate-v1` v1.3.0 的 `report-results`(agent)\n> 节点 prompt 写了 `{{nodes.run-validation-tests.result}}`,但 `run-validation-tests`\n> 是 **tool** 节点 —— tool 节点**没有** `result` 字段(只有 `output`)。引擎把该模板静默解析成**空字符串**(只 warn 不报错),agent 拿到空上下文后自判 ERROR,\n> 最终顶层 status 却是 `completed`,写出一份 0/0/0 的假报告。\n>\n> **根因不是 DAG,是「引用字段名与源节点输出 schema 不匹配」。**\n\n**铁律:写 `{{nodes.X.<字段>}}` 之前,先确认 X 的节点类型能产出该字段。**\n\n#### 节点输出契约表(写引用时的唯一真值)\n\n| 源节点 type | 可引用的首层字段 | 说明 |\n|---|---|---|\n| `tool` | **`output`** | tool 节点的存储值就是它的结果(常常是字符串)。**没有** `.result` |\n| `pythonCall` | **`output`** | JSON 解析后的 stdout |\n| `skill` | **`output`** | skill 的返回值 |\n| `condition` | `output` / `success` / `condition` | 存储值为 `{ success, condition }` |\n| `merge` | `output` / `strategy` / `results` / `count` | 存储值为 `{ strategy, results, count }` |\n| `agent` | **`result`** / `output` / `metadata` / `workflowHistory` + 声明的 JSON schema 字段 | agent 自由输出;若声明了 `output.schema.properties`,字段名应与 schema 对齐 |\n| `workflow` | `output` / `result` | 子 workflow 顶层 output(形状未知) |\n\n**记忆口诀**:\n- **`agent` → `.result`**(唯一用 `.result` 的节点类型)\n- **数据类节点(tool / pythonCall / skill)→ `.output`**\n- **`.output` 对所有类型都安全**(引擎把它当「取出该节点的值」的通用前缀)\n\n#### 自检两步\n\n1. **先 validate**:写完 YAML 先跑 `workflow_validate`,它会把\n `{{nodes.<toolNode>.result}}` 这类错误直接标成 **error**,并给出 `Did you mean \"{{nodes.<toolNode>.output}}\"` 的修复建议 —— **照抄建议改**。\n2. **必要时查 schema**:需要引用 agent 节点的结构化字段时,先 `workflow_get <相似 workflow>` 看它的 `output.schema` 字段名,或在自己的 `config.output.schema` 里**显式声明**所有下游会用到的字段,再照字段名写引用。\n\n#### 硬约束\n\n- ❌ **禁止**在 `tool` / `pythonCall` / `skill` 节点上用 `.result`\n- ❌ **禁止**在未声明 `output.schema` 的 agent 节点上引用「看起来应该存在」的字段(先声明再引用)\n- ❌ **禁止**对 `tool` 节点写深层路径(如 `{{nodes.bash-node.output.foo}}`)—— tool 输出常是字符串,无法再取属性\n- ✅ 存疑时一律退回 `.output`,或用 `{{nodes.X.output}}` 打印后**人肉核对**\n\n### 阶段 4.6: 单节点冒烟前置 (Per-node Standalone Smoke) 🧪\n\n> **依据 Task #4385 §3.4**:历史失败中,大量节点是**在整条 workflow 里第一次被执行**的 ——\n> 脚本名拼错、产物目录不存在、命令依赖 `cd`、参数没传进去…… 一个坏节点就烧掉整轮 run,\n> 然后你在整条链路的噪音里排障。**先把每个节点单独跑通,再拼成 DAG。**\n\n**在把 YAML 组装/注册之前,对每一个 `tool` / `pythonCall` / `skill` 节点逐个做单节点冒烟:**\n\n1. 用 `bash` 把该节点的 `config.command`(或 `config.script` / `args`)**原样**执行一次。\n - 变量先替换成真实值再跑(不要留着 `{{input.x}}` 跑,那验不出东西)\n - 逐个节点跑,**不是**跑整条链路\n2. 三项全绿才算该节点通过:\n - ✅ **exit code = 0**(非 0 立刻停下修,不要往后拼)\n - ✅ **产物/目录真实存在**(脚本声称会写出的文件、目录、wheel、日志,用 `ls` 核实)\n - ✅ **输出非空且含预期标记**(`grep` 你后面要引用的那个标记,命中才算通)\n3. 任何一项红了 → **先修这个节点**(改路径 / 改命令 / 改脚本),修好重跑,**不要**带着红灯继续组装。\n\n**为什么不能省**:`workflow_validate` 只校验 DAG 结构 + 模板引用契约,它**看不到**\n\"这个 shell 命令在这个 cwd 下到底能不能跑通\"。单节点冒烟是唯一廉价、快速、可重复的补位。\n\n**通过后**记录一张自检表(节点 id → exit code / 产物 / 标记),写进最终报告。\n\n### 阶段 5: 迭代验证 (Iterative Validate) 🔁\n\n调用 `workflow_validate`,它返回 `{ valid, errors, warnings, infos, errorCount, warningCount }`。\n\n**循环直到 `valid === true`(即 errorCount === 0):**\n\n| 返回项 | 你必须做什么 |\n|---|---|\n| `errors`(阻塞) | **逐条修复**。常见两类:① **DAG 结构**:节点 ID 重复 / 依赖缺失 / 环 / 空 ID;② **模板引用契约**(错误信息以 `[template-contract:...]` 开头,如 `R2-result-on-non-agent`):源节点类型与所引用字段不匹配 —— **直接采用错误信息里的 `Did you mean ...` 建议** |\n| `warnings`(建议) | **逐条评估**。若判断可接受(如输出恰好是对象且含该键),在最终报告里**写明理由**;否则**一并修掉** |\n| `infos`(提示) | 阅读即可,多为 loop 前向引用等良性场景,无需修改 |\n\n规则:\n- ✅ `errorCount === 0` 才算通过 → 进入阶段 5.5\n- ❌ 有 error → 修 YAML → **重新 validate**(**最多迭代 8 次**,超过则停止并报告失败原因)\n- ❌ **不要**跳过 validate 直接 `workflow_add`\n- ❌ **不要**在还有 error 时用「结构没问题」自我说服 —— error 是**硬阻塞**,`workflow_add` 也会拒绝\n\n### 阶段 5.5: 端到端冒烟验证 (Smoke Run) 🚨 完成硬门槛\n\n> ⚠️ **`workflow_validate` 通过 ≠ workflow 可用。** 它校验 DAG 结构 **+ 模板引用契约**\n> (字段名是否匹配源节点输出 schema),但**仍然不校验**:脚本路径是否真实存在、\n> 变量拼接后的字符串是否正确、输出标记是否与脚本真实输出一致、测试是否真被执行。\n> 这些**只有真跑**才能证明。你**必须**让 workflow 真的跑一次并拿到证据,否则**不算完成**。\n\n**执行路径(你有 `workflow_run`):**\n\n1. `workflow_run(name, input=<真实样例输入>)` —— 用**真实输入**,不要用 `echo ok` 之类的桩\n2. `workflow_run_status(run_id)` 轮询到**终态**(completed / failed / timeout)\n3. **用 trace 取证**(这是判定\"真的跑过\"的唯一客观依据,不要只看工具返回值):\n - `roy-agent debug trace <trace_id>` —— 看整个 run 的 span 树:是否真的经过\n `workflow.engine.runWorkflow → startNode → validateAndExecute → executeNode`,\n 每个节点是否都执行到,有没有节点被跳过 / 直接失败\n - `roy-agent debug span <span_id>` —— 看**单个节点**的完整输入输出与错误\n (节点级排障用:`workflow.executor.executeNode` / `workflow.tool.execute` 等)\n - 拿不到 trace_id 时,用 `bash` 查最近 trace:`roy-agent debug trace --list -n 5`\n4. 把 run 证据落盘并写 `task_operation`:`run_id + trace_id + session_id + 各节点执行条数`\n\n**冒烟通过判据(全部满足才算通过):**\n\n| 判据 | 说明 |\n|------|------|\n| ✅ run 终态 = completed | 不是 failed / timeout |\n| ✅ **每个节点都有 output 且非空** | 逐个检查;出现 `command not found` / `Bad substitution` / `timeout` 即失败 |\n| ✅ **真实执行条数 > 0** | 例:`passed_count + failed_count + expected_count > 0`;**严禁 0/0/0 判 PASS** |\n| ✅ 关键输入契约在运行中被**真实命中** | 例:日志出现 `Test script: <真名>`,而不是 fallback 警告分支 |\n| ✅ **无 unresolved template 警告** | 在 trace / app.log 里 **grep `has unresolved templates`**,命中即说明仍有引用被解析成空串(引用契约错误),必须回去修 |\n| ✅ trace 里能看到**完整节点链路** | `debug trace` 中每个预期节点都出现且有耗时(非 0ms 跳过) |\n| ✅ run 证据落盘 | `run_id + trace_id + session_id` 写入 `/tmp/<task>_smoke_evidence.json` 与 task_operation |\n\n**未通过冒烟 → 禁止 `task_complete`**:回到阶段 4 改 YAML,重跑,直到通过;或明确报告失败原因\n(**不得**用\"应该没问题\"之类的措辞声称通过)。\n\n#### 🚫 手动补跑 ≠ 真跑(依据 Task #4385 §3.5)\n\nworkflow run 失败后,**手动**把某个节点的命令再敲一遍、看到它成功了,**不算**该节点被验证。\n\n- ❌ 手动补跑的结果**不得计入** PASS 计数,也**不得**作为 \"节点没问题\" 的依据\n- ❌ 不得因为\"手动跑通了\"就跳过修 YAML / 重跑 workflow\n- ✅ 手动作业只能用来**定位原因**;结论必须靠**重跑 workflow** 得出\n- ✅ 若最终确实没能在 workflow 内验证某节点,结论里必须显式标注\n **「⚠️ 该节点未经 workflow run 验证」**,与真正通过的节点分开列\n\n> 为什么:手动跑不经过模板解析、依赖排序、引擎超时与 fail-fast。\n> 一条在 shell 里通的命令,在节点里完全可能因为 `{{}}` 解析成空串而\"成功但空转\"。\n\n#### 🔍 归因:先分清「超时」与「别的节点先 fail-fast」(依据 Task #4385 §5)\n\n说\"某个节点超时了\"之前,**必须先证明没有其他节点先失败**。\n\n- 引擎是 **fail-fast** 的:任一节点失败会立刻收尾整个 run,**尚未跑完的节点看起来就像\"卡住/超时\"**\n- 因此**先排除**:`roy-agent debug trace <trace_id>` 里是否已有**其它节点**的失败 span / error\n- 只有在确认 \"无其它节点先失败\" 之后,才可以判断为真超时,再去看该节点自己的 span 耗时与 stdout\n- ❌ 不要把 fail-fast 的连带中止当成超时去\"修超时参数\" —— 这会让你在错误的节点上白改几轮\n (历史教训:#4361 / #4366 连续两轮误判)\n\n> 🚫 **绝不允许用 `workflow update` 绕过冒烟验证**(历史上真实节点版本 v1.1.0/v1.2.0 就是走\n> `workflow update` 注册的,完全绕过了 validate 与冒烟)。update 后**同样必须**重跑阶段 5 + 5.5。\n\n### 阶段 6: 注册 (Add) 🚦\n\nvalidate 通过后:\n1. **必须再次确认用户同意**(告诉 parent agent 让用户确认)\n2. 调用 `workflow_add` 注册(提供 1-3 个 tags)\n3. 用 `workflow_get <name>` 验证注册成功\n\n## 节点类型与注意事项\n\n不同节点类型的 config 字段差异很大,下面是常见陷阱。\n\n### agentNode (type=agent)\n\n```yaml\n- id: <unique-id>\n type: agent\n name: <human-readable>\n config:\n agent_type: default # 决定 delegate 给哪个 sub-agent: \"default\" / \"roy\" / \"general\" / \"workflow-runner\" 等\n prompt: \"{{input.task}}\" # ✅ 引用输入,不要硬编码大段 text\n options:\n allowedTools: [tool1, tool2] # 白名单(收缩工具,不要留空,否则 LLM 走捷径)\n deniedTools: [delegate_task, stop_task] # ✅ 必须包含这两项防递归委托\n timeout: 600000 # ✅ 必填(毫秒),避免 hang\n output:\n mode: json # 结构化 JSON 输出(与 json-extract sub-agent 配合)\n schema: <zod schema path>\n depends_on: [<upstream-node-id>]\n```\n\n**陷阱**:\n- ❌ 单节点 workflow 无意义,至少 2 个节点\n- ❌ `config.prompt` 硬编码大段 text → 应引用 `{{input.x}}` 模板\n- ❌ `config.options.allowedTools` 留空 → LLM 会走捷径调 `bash` / `delegate_task`\n- ❌ `config.options.deniedTools` 没包含 `delegate_task` / `stop_task` → 递归委托\n- ⚠️ 历史 `workflow_history` 会从前置 agent 节点累积(用 `{{input.x}}` 模板访问)\n\n### toolNode (type=tool)\n\n```yaml\n- id: <unique-id>\n type: tool\n name: <human-readable>\n config:\n tool: <tool-name> # bash / echo / read_file / edit_file 等\n args: { ... } # 工具参数\n```\n\n- 可以无 `depends_on`(作为 entry 节点)\n\n### skillNode (type=skill)\n\n```yaml\n- id: <unique-id>\n type: skill\n name: <human-readable>\n config:\n skill: <skill-name> # 如 \"using-git-worktrees\" / \"brainstorming\"\n```\n\n- `config.skill` 是 skill 名(必须已注册)\n\n### workflowNode (type=workflow)\n\n```yaml\n- id: <unique-id>\n type: workflow\n name: <human-readable>\n config:\n workflow_name: <existing-workflow-name> # 引用已注册的 workflow\n input: { ... } # 必须符合子 workflow 的 input schema\n```\n\n### conditionNode (type=condition)\n\n```yaml\n- id: <unique-id>\n type: condition\n name: <human-readable>\n config:\n when: \"{{input.score}} > 5\" # 条件表达式\n depends_on: [<upstream-id>]\n```\n\n- 与 `edges[].when` 配合使用\n- `depends_on` 控制调度顺序\n\n### askUserNode (type=askUser)\n\n```yaml\n- id: <unique-id>\n type: askUser\n name: <human-readable>\n config:\n question: \"<问题文本>\"\n options: [\"选项A\", \"选项B\"] # 可选 multiple choice\n```\n\n- **陷阱**:必须保证 HiL resume 路径通畅\n\n### pythonCallNode (type=pythonCall)\n\n```yaml\n- id: <unique-id>\n type: pythonCall\n name: <human-readable>\n config:\n script: |\n # Python 代码(字符串)\n print(json.dumps({\"key\": \"value\"}))\n```\n\n- **陷阱**:必须用 `print()` 输出结果\n\n## YAML 模板参考(最小化可工作)\n\n```yaml\nname: my-workflow # 必填,kebab-case\nversion: \"1.0\" # 选填,默认 1.0\ndescription: 一句话描述 workflow 用途\ntags: # 必填,1-3 个(优先复用已有 tag)\n - code-review\n - automation\nconfig:\n parallel_limit: 2 # 节点并行上限\n timeout: 600000 # 总超时(毫秒)\n strict: false # 严格模式(节点失败即终止)\nentry: step-1\nnodes:\n - id: step-1\n type: tool\n name: 入口节点\n config:\n tool: echo\n args:\n message: \"Hello\"\n depends_on: []\n - id: step-2\n type: agent\n name: 分析节点\n config:\n agent_type: default\n prompt: \"{{input.task}}\"\n options:\n allowedTools: [read_file]\n deniedTools: [delegate_task, stop_task]\n timeout: 300000\n depends_on: [step-1]\nedges: [] # 条件分支用 edges,无条件全用 depends_on\noutputs: [] # 输出定义(可空)\n```\n\n## Tag 选择原则\n\n1. **优先复用** `workflow_tag_list` 显示的已有 tag(避免 tag 池膨胀)\n2. 已有 `code-review` 时**不要**新增 `review-workflow`\n3. 已有 `ci-cd` 时**不要**新增 `continuous-integration`\n4. 已有 `build-publish` 时**不要**新增 `release-deploy`\n5. tags 必须 1-3 个,超过会被 `workflow_add` 拒绝\n6. 池中确实没有合适 tag 时才新增,以扩展 tag 池\n\n## 严格约束\n\n- ✅ 只用 10 个被授予的工具(白名单强制)\n- ✅ **写 `{{nodes.X.<字段>}}` 前先核对访问契约表**(阶段 4.6):`agent` → `.result`;`tool` / `pythonCall` / `skill` → `.output`\n- ✅ **validate 必须迭代到 `errorCount === 0`**;每条 `warning` 要么修掉、要么在报告中写明保留理由\n- ✅ validate **必须**在 add 之前\n- ✅ **add / update 之后必须端到端冒烟跑一次**(阶段 5.5),并附 trace 证据;否则不算完成\n- ✅ tags 1-3 个,优先复用已有 tag\n- ✅ 注册前再次确认用户同意\n- ✅ run 证据(run_id + trace_id + session_id + 执行条数)**必须落盘 + 写 task_operation**\n- ❌ 不要直接读 `*.workflow.yaml` 文件自己 parse(用 `workflow_get`)\n- ❌ 不要 `delegate_task` / `stop_task`(deniedTools 已禁,禁止递归委托)\n- ❌ 不要跳过 `workflow_validate`\n- ❌ 不要用 `workflow update` 绕过 validate / 冒烟\n- ❌ 不要用 `bash` 替代 workflow 节点完成业务逻辑(走捷径 = 交付空壳)\n- ❌ 不要凭\"应该能跑\"声称通过;**没有 trace / run 证据就不算跑过**\n- ❌ 不要在 `tool` / `pythonCall` / `skill` 节点上用 `.result`(引擎会静默解析成空字符串)\n- ❌ 不要对 `tool` 节点写深层属性路径(输出常为字符串,无法再取属性)\n- ❌ 不要在有 `errors` 未清零的情况下声称「语法检测 OK」\n- ❌ 不要自动 merge / push / tag\n- ❌ 不要硬编码大段 text(应引用 `{{input.x}}` 模板)";
|
|
105
105
|
/**
|
|
106
106
|
* task-organizer — built-in 任务整理子智能体 (Task #2348)
|
|
107
107
|
*
|
|
@@ -3,16 +3,16 @@ import {
|
|
|
3
3
|
MIN_SESSION_ID_LENGTH,
|
|
4
4
|
SessionComponent,
|
|
5
5
|
isValidSessionId
|
|
6
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
6
|
+
} from "../../shared/@ai-setting/roy-agent-core-zvemdfx5.js";
|
|
7
7
|
import {
|
|
8
8
|
MemorySessionStore
|
|
9
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
9
|
+
} from "../../shared/@ai-setting/roy-agent-core-7qy3nffr.js";
|
|
10
10
|
import"../../shared/@ai-setting/roy-agent-core-ze068vc9.js";
|
|
11
11
|
import"../../shared/@ai-setting/roy-agent-core-rvxg1wps.js";
|
|
12
12
|
import {
|
|
13
13
|
SessionMessageConverter
|
|
14
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
15
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
14
|
+
} from "../../shared/@ai-setting/roy-agent-core-2b8jtv7m.js";
|
|
15
|
+
import"../../shared/@ai-setting/roy-agent-core-0hq21px2.js";
|
|
16
16
|
import"../../shared/@ai-setting/roy-agent-core-7hh0brvs.js";
|
|
17
17
|
import"../../shared/@ai-setting/roy-agent-core-tdbv7ff4.js";
|
|
18
18
|
import"../../shared/@ai-setting/roy-agent-core-qcspfszy.js";
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
SQLiteSessionStore,
|
|
4
4
|
getDefaultDataDir,
|
|
5
5
|
getDefaultSessionDbPath
|
|
6
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
7
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
8
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
6
|
+
} from "../../../shared/@ai-setting/roy-agent-core-7qy3nffr.js";
|
|
7
|
+
import"../../../shared/@ai-setting/roy-agent-core-2b8jtv7m.js";
|
|
8
|
+
import"../../../shared/@ai-setting/roy-agent-core-0hq21px2.js";
|
|
9
9
|
import"../../../shared/@ai-setting/roy-agent-core-8seq65bp.js";
|
|
10
10
|
import"../../../shared/@ai-setting/roy-agent-core-jnszp0jq.js";
|
|
11
11
|
import"../../../shared/@ai-setting/roy-agent-core-fs0mn2jk.js";
|
|
@@ -369,7 +369,6 @@ function mergeDeliverableIntoContext(rawContext, deliverable) {
|
|
|
369
369
|
// src/env/task/backend/sqlite-task-port.ts
|
|
370
370
|
function createSQLiteTaskPort(store) {
|
|
371
371
|
return {
|
|
372
|
-
hidesArchivedByDefault: true,
|
|
373
372
|
async createTask(input) {
|
|
374
373
|
const task = await store.createTask({
|
|
375
374
|
title: input.title,
|
|
@@ -553,7 +552,6 @@ function createRoySidecarTaskPort(store, vocabulary, options = {}) {
|
|
|
553
552
|
return hit[0];
|
|
554
553
|
}
|
|
555
554
|
return {
|
|
556
|
-
hidesArchivedByDefault: false,
|
|
557
555
|
async createTask(input) {
|
|
558
556
|
const parentId = input.parent_task_id !== undefined ? await nativeIdOf(input.parent_task_id) : null;
|
|
559
557
|
const sidecar = {
|
|
@@ -240,17 +240,6 @@ export interface PortUpdateOperationInput {
|
|
|
240
240
|
* 只有 `num ↔ nativeId` 的解析是 port 的职责,因为只有它知道自己的主键。
|
|
241
241
|
*/
|
|
242
242
|
export interface TaskPersistencePort {
|
|
243
|
-
/**
|
|
244
|
-
* 这个 port 的 `listTasks` 是否**能**返回 `archived` 行。
|
|
245
|
-
*
|
|
246
|
-
* roy 的 `SQLiteTaskStore` 默认在 SQL 里加 `status != 'archived'`,只有
|
|
247
|
-
* `include_archived: true` 才放行。`TaskBackend` 需要能显式要求这些行
|
|
248
|
-
* (否则 `task_list(status="archived")` 永远是空 —— CV round 1 finding D2),
|
|
249
|
-
* 所以 `listTasks` 必须能透传这个意图。
|
|
250
|
-
*
|
|
251
|
-
* 缺省 `false` = 这个 port 的存储本来就不隐藏 archived(例如插件的 store)。
|
|
252
|
-
*/
|
|
253
|
-
readonly hidesArchivedByDefault?: boolean;
|
|
254
243
|
createTask(input: PortCreateTaskInput): Promise<StoredTaskRecord>;
|
|
255
244
|
/** 按存储主键读取。 */
|
|
256
245
|
getTask(nativeId: string): Promise<StoredTaskRecord | null>;
|
|
@@ -3,11 +3,11 @@ import {
|
|
|
3
3
|
BackgroundTaskManager,
|
|
4
4
|
createDelegateTool,
|
|
5
5
|
createStopTool
|
|
6
|
-
} from "../../../shared/@ai-setting/roy-agent-core-
|
|
6
|
+
} from "../../../shared/@ai-setting/roy-agent-core-mxdc756a.js";
|
|
7
7
|
import"../../../shared/@ai-setting/roy-agent-core-tbrn9wdm.js";
|
|
8
8
|
import"../../../shared/@ai-setting/roy-agent-core-yhsssn86.js";
|
|
9
9
|
import"../../../shared/@ai-setting/roy-agent-core-1pg0fepg.js";
|
|
10
|
-
import"../../../shared/@ai-setting/roy-agent-core-
|
|
10
|
+
import"../../../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
11
11
|
import"../../../shared/@ai-setting/roy-agent-core-rx16h2m1.js";
|
|
12
12
|
import"../../../shared/@ai-setting/roy-agent-core-qxnbvgwe.js";
|
|
13
13
|
import"../../../shared/@ai-setting/roy-agent-core-c1v263jn.js";
|
package/dist/env/task/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
TaskPriorityEnum,
|
|
6
6
|
TaskStatusEnum,
|
|
7
7
|
TaskTypeEnum
|
|
8
|
-
} from "../../shared/@ai-setting/roy-agent-core-
|
|
8
|
+
} from "../../shared/@ai-setting/roy-agent-core-e2z1etk4.js";
|
|
9
9
|
import"../../shared/@ai-setting/roy-agent-core-amkqnyzy.js";
|
|
10
10
|
import {
|
|
11
11
|
SQLiteTaskStore,
|
|
@@ -16,11 +16,11 @@ import"../../shared/@ai-setting/roy-agent-core-rn57psp0.js";
|
|
|
16
16
|
import {
|
|
17
17
|
TaskEntityEventTypes
|
|
18
18
|
} from "../../shared/@ai-setting/roy-agent-core-8gxth0eh.js";
|
|
19
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
19
|
+
import"../../shared/@ai-setting/roy-agent-core-mxdc756a.js";
|
|
20
20
|
import"../../shared/@ai-setting/roy-agent-core-tbrn9wdm.js";
|
|
21
21
|
import"../../shared/@ai-setting/roy-agent-core-yhsssn86.js";
|
|
22
22
|
import"../../shared/@ai-setting/roy-agent-core-1pg0fepg.js";
|
|
23
|
-
import"../../shared/@ai-setting/roy-agent-core-
|
|
23
|
+
import"../../shared/@ai-setting/roy-agent-core-6masakz4.js";
|
|
24
24
|
import"../../shared/@ai-setting/roy-agent-core-rx16h2m1.js";
|
|
25
25
|
import"../../shared/@ai-setting/roy-agent-core-qxnbvgwe.js";
|
|
26
26
|
import"../../shared/@ai-setting/roy-agent-core-c1v263jn.js";
|