@ai-setting/roy-agent-core 1.7.72 → 1.7.76
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/agent-component.js +6 -6
- package/dist/env/agent/agent-registry.d.ts +4 -1
- package/dist/env/agent/index.js +6 -6
- package/dist/env/error-reply.d.ts +46 -0
- package/dist/env/error-reply.js +3 -1
- package/dist/env/event-source/event-source-handlers.js +13 -12
- package/dist/env/event-source/index.js +14 -13
- package/dist/env/index.js +31 -30
- package/dist/env/llm/index.js +2 -2
- package/dist/env/llm/orphan-toolcall.d.ts +107 -0
- package/dist/env/plugin/index.js +3 -3
- package/dist/env/prompt/index.js +4 -3
- package/dist/env/prompt/prompts-index.d.ts +27 -3
- package/dist/env/session/index.js +4 -4
- package/dist/env/session/storage/index.js +3 -3
- package/dist/env/task/backend/index.js +9 -1
- package/dist/env/task/delegate/delegate-tool.d.ts +8 -0
- package/dist/env/task/delegate/delegate-tool.js +5 -4
- package/dist/env/task/delegate/index.js +5 -4
- package/dist/env/task/hooks/contexts.d.ts +12 -1
- package/dist/env/task/hooks/task-hook-points.d.ts +8 -3
- package/dist/env/task/index.d.ts +1 -0
- package/dist/env/task/index.js +17 -7
- package/dist/env/task/mcp/index.js +3 -2
- package/dist/env/task/plugins/index.d.ts +3 -0
- package/dist/env/task/plugins/index.js +33 -9
- package/dist/env/task/plugins/lark-card-patch-notifier.d.ts +61 -0
- package/dist/env/task/plugins/lark-card-patch-notifier.js +6 -2
- package/dist/env/task/plugins/lark-cli-task-notify-plugin.d.ts +42 -0
- package/dist/env/task/prompt/index.js +2 -1
- package/dist/env/task/prompt/task-discipline.d.ts +9 -3
- package/dist/env/task/task-component.d.ts +79 -0
- package/dist/env/task/tools/cancel-tool.d.ts +36 -0
- package/dist/env/task/tools/completion-copy.d.ts +92 -0
- package/dist/env/task/tools/index.d.ts +2 -0
- package/dist/env/task/tools/index.js +7 -2
- package/dist/env/task/tools/pre-complete-tool.d.ts +32 -0
- package/dist/env/task/tools/task-types.d.ts +71 -17
- package/dist/env/task/types.d.ts +13 -1
- package/dist/env/tool/built-in/compact-session-tool.d.ts +120 -0
- package/dist/env/tool/built-in/index.d.ts +2 -0
- package/dist/env/tool/built-in/index.js +6 -2
- package/dist/env/tool/index.js +4 -4
- package/dist/env/workflow/engine/index.js +6 -6
- package/dist/env/workflow/index.js +15 -13
- package/dist/env/workflow/plugins/index.js +2 -2
- package/dist/env/workflow/tools/ask-user-tool.d.ts +88 -0
- package/dist/env/workflow/tools/index.js +11 -9
- package/dist/env/workflow/tools/run-workflow.d.ts +2 -2
- package/dist/env/workflow/types/index.js +2 -2
- package/dist/env/workflow/types/workflow-hil.d.ts +25 -1
- package/dist/env/workflow/utils/index.js +5 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +43 -33
- package/dist/shared/@ai-setting/{roy-agent-core-sm0sf6sb.js → roy-agent-core-0qyrk5k0.js} +2 -2
- package/dist/shared/@ai-setting/{roy-agent-core-kmbct9yg.js → roy-agent-core-0snm5hc5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-yr1mryb8.js → roy-agent-core-1v4g0d4x.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-rxb00gjm.js → roy-agent-core-264qexac.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-2akfd64z.js +374 -0
- package/dist/shared/@ai-setting/{roy-agent-core-skyc30qx.js → roy-agent-core-3fh1f7s7.js} +2 -2
- package/dist/shared/@ai-setting/roy-agent-core-4rtg69cn.js +26 -0
- package/dist/shared/@ai-setting/{roy-agent-core-add1zqsh.js → roy-agent-core-6cy43nss.js} +22 -1
- package/dist/shared/@ai-setting/{roy-agent-core-vah6g5yx.js → roy-agent-core-6rh8k6ba.js} +5 -5
- package/dist/shared/@ai-setting/{roy-agent-core-kpg25s2q.js → roy-agent-core-8ez6mccb.js} +4 -2
- package/dist/shared/@ai-setting/{roy-agent-core-yhwxpj12.js → roy-agent-core-9vxh6f8h.js} +233 -16
- package/dist/shared/@ai-setting/{roy-agent-core-7qvw65jt.js → roy-agent-core-aa2j7bk9.js} +11 -8
- package/dist/shared/@ai-setting/{roy-agent-core-sjr1kmfz.js → roy-agent-core-acj8ag08.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-mds8tqd0.js → roy-agent-core-cgtq6427.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-34jz9mgh.js → roy-agent-core-cmprygrp.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-wr7mv7k3.js → roy-agent-core-cxy143m4.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-pakhchy7.js → roy-agent-core-ddyk1rc0.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-attpry6g.js → roy-agent-core-dqxec05w.js} +4 -3
- package/dist/shared/@ai-setting/{roy-agent-core-vm8h5zyj.js → roy-agent-core-ed233k5z.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-jrj30vq3.js → roy-agent-core-er070zjq.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-40rv283c.js → roy-agent-core-fghc2m8z.js} +152 -2
- package/dist/shared/@ai-setting/{roy-agent-core-5gw0qa8m.js → roy-agent-core-ghnagzrh.js} +557 -92
- package/dist/shared/@ai-setting/{roy-agent-core-4jjwewvw.js → roy-agent-core-m46fe3x4.js} +41 -30
- package/dist/shared/@ai-setting/{roy-agent-core-e25xkv53.js → roy-agent-core-mkc3zshb.js} +3 -1
- package/dist/shared/@ai-setting/{roy-agent-core-hfyfavp3.js → roy-agent-core-mww0mnd9.js} +231 -27
- package/dist/shared/@ai-setting/{roy-agent-core-46rv4d7d.js → roy-agent-core-nmx9934r.js} +92 -2
- package/dist/shared/@ai-setting/{roy-agent-core-1w9y7mxj.js → roy-agent-core-p3zv1mx5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-jgb3bb42.js → roy-agent-core-q5r75vev.js} +17 -8
- package/dist/shared/@ai-setting/{roy-agent-core-y12kyxwa.js → roy-agent-core-t3rrb959.js} +33 -9
- package/dist/shared/@ai-setting/{roy-agent-core-dt104qa1.js → roy-agent-core-v85n42ve.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-gr48c89p.js → roy-agent-core-v87njmq7.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-7sj9xs9c.js → roy-agent-core-vffccgf6.js} +252 -25
- package/dist/shared/@ai-setting/{roy-agent-core-2gzt2q8c.js → roy-agent-core-z43aj03k.js} +134 -29
- package/dist/shared/@ai-setting/roy-agent-core-zycadbpx.js +662 -0
- package/package.json +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-1p6syv85.js +0 -1083
- package/dist/shared/@ai-setting/roy-agent-core-58804s3j.js +0 -155
|
@@ -0,0 +1,662 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAutoTaskPlugin,
|
|
3
|
+
createLayaDecisionPlugin,
|
|
4
|
+
registerLayaCompletionTaskHook
|
|
5
|
+
} from "./roy-agent-core-ghnagzrh.js";
|
|
6
|
+
import {
|
|
7
|
+
TaskHookPoints
|
|
8
|
+
} from "./roy-agent-core-1pg0fepg.js";
|
|
9
|
+
import {
|
|
10
|
+
ContextError,
|
|
11
|
+
ErrorCodes
|
|
12
|
+
} from "./roy-agent-core-ctdhjv68.js";
|
|
13
|
+
import {
|
|
14
|
+
BaseComponent
|
|
15
|
+
} from "./roy-agent-core-pgvcf91v.js";
|
|
16
|
+
import {
|
|
17
|
+
init_hook
|
|
18
|
+
} from "./roy-agent-core-ax9e9szb.js";
|
|
19
|
+
import {
|
|
20
|
+
init_context
|
|
21
|
+
} from "./roy-agent-core-qqaak24r.js";
|
|
22
|
+
import {
|
|
23
|
+
getEnvContext,
|
|
24
|
+
init_env_context,
|
|
25
|
+
runWithEnvContextAsync
|
|
26
|
+
} from "./roy-agent-core-7cbpmk4q.js";
|
|
27
|
+
import {
|
|
28
|
+
TracedAs,
|
|
29
|
+
envQueryParamFilter,
|
|
30
|
+
init_decorator,
|
|
31
|
+
init_trace_filters
|
|
32
|
+
} from "./roy-agent-core-qq96p0tj.js";
|
|
33
|
+
import {
|
|
34
|
+
createLogger,
|
|
35
|
+
init_logger
|
|
36
|
+
} from "./roy-agent-core-7f7t9wwp.js";
|
|
37
|
+
import {
|
|
38
|
+
__legacyDecorateClassTS
|
|
39
|
+
} from "./roy-agent-core-fs0mn2jk.js";
|
|
40
|
+
|
|
41
|
+
// src/env/environment.ts
|
|
42
|
+
init_logger();
|
|
43
|
+
|
|
44
|
+
// src/utils/id.ts
|
|
45
|
+
function generateId(prefix = "id") {
|
|
46
|
+
const timestamp = Date.now().toString(36);
|
|
47
|
+
const random = Math.random().toString(36).substring(2, 11);
|
|
48
|
+
return `${prefix}_${timestamp}_${random}`;
|
|
49
|
+
}
|
|
50
|
+
function generateDescendingId(prefix = "id") {
|
|
51
|
+
const timestamp = (Number.MAX_SAFE_INTEGER - Date.now()).toString(36);
|
|
52
|
+
const random = Math.random().toString(36).substring(2, 11);
|
|
53
|
+
return `${prefix}_${timestamp}_${random}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// src/env/environment.ts
|
|
57
|
+
init_decorator();
|
|
58
|
+
init_trace_filters();
|
|
59
|
+
init_env_context();
|
|
60
|
+
import * as fsSync from "fs";
|
|
61
|
+
import * as path from "path";
|
|
62
|
+
var logger = createLogger("environment");
|
|
63
|
+
function registerLayaDecisionTaskHook(taskComponent, options) {
|
|
64
|
+
if (!taskComponent) {
|
|
65
|
+
logger.warn("[registerLayaDecisionTaskHook] TaskComponent not available — skip (fail-open)");
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const hook = createLayaDecisionPlugin(options);
|
|
70
|
+
taskComponent.unregisterHook(TaskHookPoints.BEFORE_CREATE, hook.name);
|
|
71
|
+
taskComponent.registerHook(TaskHookPoints.BEFORE_CREATE, {
|
|
72
|
+
name: hook.name,
|
|
73
|
+
priority: hook.priority,
|
|
74
|
+
execute: async (ctx) => {
|
|
75
|
+
try {
|
|
76
|
+
const data = ctx && typeof ctx === "object" && "data" in ctx ? ctx.data : ctx;
|
|
77
|
+
await hook.execute(data);
|
|
78
|
+
} catch (err) {
|
|
79
|
+
logger.warn(`[registerLayaDecisionTaskHook] hook execution failed (ignored): ${err?.message}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
logger.info(`[registerLayaDecisionTaskHook] registered hook "${hook.name}" at ${TaskHookPoints.BEFORE_CREATE} (priority=${hook.priority})`);
|
|
84
|
+
return true;
|
|
85
|
+
} catch (err) {
|
|
86
|
+
logger.warn(`[registerLayaDecisionTaskHook] registration failed (ignored): ${err?.message}`);
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
var DEFAULT_AGENT_NAME = "Roy";
|
|
91
|
+
function injectAgentNamePlaceholder(prompt, context) {
|
|
92
|
+
if (!prompt.includes("{{agent_name}}")) {
|
|
93
|
+
return prompt;
|
|
94
|
+
}
|
|
95
|
+
const metadata = context?.metadata;
|
|
96
|
+
const defaultAgentName = typeof metadata?.defaultAgentName === "string" && metadata.defaultAgentName.length > 0 ? metadata.defaultAgentName : DEFAULT_AGENT_NAME;
|
|
97
|
+
return prompt.replace(/\{\{agent_name\}\}/g, defaultAgentName);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
class BaseEnvironment extends BaseComponent {
|
|
101
|
+
name;
|
|
102
|
+
version;
|
|
103
|
+
components = new Map;
|
|
104
|
+
constructor(config) {
|
|
105
|
+
super();
|
|
106
|
+
this.name = config?.name ?? "base-environment";
|
|
107
|
+
this.version = config?.version ?? "1.0.0";
|
|
108
|
+
this.registerDefaultComponents();
|
|
109
|
+
}
|
|
110
|
+
registerDefaultComponents() {}
|
|
111
|
+
getConfig() {
|
|
112
|
+
return {
|
|
113
|
+
name: this.name,
|
|
114
|
+
version: this.version,
|
|
115
|
+
enabled: true,
|
|
116
|
+
env: this
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
registerComponent(component) {
|
|
120
|
+
this.components.set(component.name, component);
|
|
121
|
+
logger.debug(`Component registered: ${component.name}`);
|
|
122
|
+
}
|
|
123
|
+
unregisterComponent(name) {
|
|
124
|
+
const component = this.components.get(name);
|
|
125
|
+
if (component) {
|
|
126
|
+
this.components.delete(name);
|
|
127
|
+
logger.debug(`Component unregistered: ${name}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
getComponent(name) {
|
|
131
|
+
return this.components.get(name);
|
|
132
|
+
}
|
|
133
|
+
listComponents() {
|
|
134
|
+
return Array.from(this.components.values());
|
|
135
|
+
}
|
|
136
|
+
async handle_query(query, context) {
|
|
137
|
+
const agentComponent = this.getComponent("agent");
|
|
138
|
+
if (!agentComponent) {
|
|
139
|
+
throw new Error("AgentComponent not found. Please register AgentComponent before calling handle_query.");
|
|
140
|
+
}
|
|
141
|
+
const agentName = context?.agentType && context.agentType !== "default" ? context.agentType : "default";
|
|
142
|
+
const registry = agentComponent.getRegistry?.();
|
|
143
|
+
if (registry) {
|
|
144
|
+
const agentDef = registry.get(agentName);
|
|
145
|
+
if (agentDef?.type === "workflow") {
|
|
146
|
+
const existingCtx = getEnvContext();
|
|
147
|
+
const workflowEnvContext = {
|
|
148
|
+
envEvent: context || { type: "workflow" },
|
|
149
|
+
sourceId: "workflow",
|
|
150
|
+
userId: context?.metadata?.userId || "",
|
|
151
|
+
replyChannel: existingCtx?.replyChannel,
|
|
152
|
+
pluginEnabled: existingCtx?.pluginEnabled,
|
|
153
|
+
agentContext: existingCtx?.agentContext ?? {}
|
|
154
|
+
};
|
|
155
|
+
return await runWithEnvContextAsync(workflowEnvContext, async () => {
|
|
156
|
+
return await this.handleWorkflowAgentQuery(agentName, query, agentComponent, context);
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
let systemPrompt = "You are a helpful assistant.";
|
|
161
|
+
let promptSource = "fallback";
|
|
162
|
+
try {
|
|
163
|
+
const promptComponent = this.getComponent("prompt");
|
|
164
|
+
if (promptComponent) {
|
|
165
|
+
const loadedPrompt = await promptComponent.getPrompt("default", {}, {
|
|
166
|
+
agentType: "primary"
|
|
167
|
+
});
|
|
168
|
+
if (loadedPrompt) {
|
|
169
|
+
systemPrompt = loadedPrompt;
|
|
170
|
+
promptSource = "PromptComponent";
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} catch (err) {
|
|
174
|
+
logger.warn(`[handle_query] Failed to get prompt from PromptComponent: ${err}`);
|
|
175
|
+
}
|
|
176
|
+
logger.info(`[handle_query] Using system prompt from ${promptSource}, length: ${systemPrompt.length}`);
|
|
177
|
+
let finalSystemPrompt = systemPrompt;
|
|
178
|
+
if (systemPrompt.includes("{{memory}}")) {
|
|
179
|
+
try {
|
|
180
|
+
const memoryComponent = this.getComponent("memory");
|
|
181
|
+
if (memoryComponent) {
|
|
182
|
+
const memoryContent = await memoryComponent.recallMemory();
|
|
183
|
+
finalSystemPrompt = systemPrompt.replace("{{memory}}", memoryContent || "(No memory)");
|
|
184
|
+
logger.info(`[handle_query] Injected memory content, length: ${memoryContent.length}`);
|
|
185
|
+
} else {
|
|
186
|
+
finalSystemPrompt = systemPrompt.replace("{{memory}}", "(Memory component not available)");
|
|
187
|
+
}
|
|
188
|
+
} catch (err) {
|
|
189
|
+
logger.warn(`[handle_query] Failed to load memory content: ${err}`);
|
|
190
|
+
finalSystemPrompt = systemPrompt.replace("{{memory}}", "(Failed to load memory)");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (finalSystemPrompt.includes("{{workspace_dir}}")) {
|
|
194
|
+
const workspaceDir = process.cwd();
|
|
195
|
+
finalSystemPrompt = finalSystemPrompt.replace("{{workspace_dir}}", workspaceDir);
|
|
196
|
+
logger.debug(`[handle_query] Injected workspace_dir: ${workspaceDir}`);
|
|
197
|
+
}
|
|
198
|
+
{
|
|
199
|
+
const prev = finalSystemPrompt;
|
|
200
|
+
finalSystemPrompt = injectAgentNamePlaceholder(finalSystemPrompt, context);
|
|
201
|
+
if (prev !== finalSystemPrompt) {
|
|
202
|
+
const metadata = context?.metadata;
|
|
203
|
+
const injectedName = typeof metadata?.defaultAgentName === "string" && metadata.defaultAgentName.length > 0 ? metadata.defaultAgentName : DEFAULT_AGENT_NAME;
|
|
204
|
+
logger.debug(`[handle_query] Injected agent_name: ${injectedName}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
let agent = agentComponent.getAgent(agentName);
|
|
208
|
+
if (!agent) {
|
|
209
|
+
if (agentName !== "default") {
|
|
210
|
+
logger.warn(`[handle_query] Agent "${agentName}" not found, falling back to "default"`);
|
|
211
|
+
}
|
|
212
|
+
agent = agentComponent.getAgent("default");
|
|
213
|
+
}
|
|
214
|
+
if (!agent) {
|
|
215
|
+
const defaultDeniedTools = [
|
|
216
|
+
"echo",
|
|
217
|
+
"glob",
|
|
218
|
+
"grep",
|
|
219
|
+
"write_file",
|
|
220
|
+
"edit_file",
|
|
221
|
+
"task_create",
|
|
222
|
+
"task_update",
|
|
223
|
+
"task_delete",
|
|
224
|
+
"task_operation_update",
|
|
225
|
+
"task_operation_delete",
|
|
226
|
+
"skill",
|
|
227
|
+
"record_memory",
|
|
228
|
+
"recall_memory",
|
|
229
|
+
"search_sessions",
|
|
230
|
+
"get_session",
|
|
231
|
+
"write_memory"
|
|
232
|
+
];
|
|
233
|
+
try {
|
|
234
|
+
const toolComponent = this.getComponent("tool");
|
|
235
|
+
if (toolComponent?.listTools) {
|
|
236
|
+
const allTools = toolComponent.listTools();
|
|
237
|
+
const mcpTools = allTools.filter((t) => t.name.startsWith("mcp_")).map((t) => t.name);
|
|
238
|
+
if (mcpTools.length > 0) {
|
|
239
|
+
defaultDeniedTools.push(...mcpTools);
|
|
240
|
+
logger.debug(`[handle_query] Dynamically denied MCP tools: ${mcpTools.join(", ")}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
} catch (err) {
|
|
244
|
+
logger.warn(`[handle_query] Failed to dynamically filter MCP tools: ${err}`);
|
|
245
|
+
}
|
|
246
|
+
agent = agentComponent.registerAgent("default", {
|
|
247
|
+
type: "primary",
|
|
248
|
+
systemPrompt: finalSystemPrompt,
|
|
249
|
+
deniedTools: defaultDeniedTools
|
|
250
|
+
});
|
|
251
|
+
logger.info(`[handle_query] Created default receptionist agent with deniedTools: ${defaultDeniedTools.length} tools denied`);
|
|
252
|
+
try {
|
|
253
|
+
const autoTaskPlugin = createAutoTaskPlugin({
|
|
254
|
+
threshold: 20
|
|
255
|
+
});
|
|
256
|
+
agentComponent.registerPlugin("default", autoTaskPlugin);
|
|
257
|
+
logger.info("[handle_query] AutoTaskPlugin v5.0 registered on default agent (threshold=20)");
|
|
258
|
+
} catch (err) {
|
|
259
|
+
logger.warn(`[handle_query] Failed to register AutoTaskPlugin: ${err}`);
|
|
260
|
+
}
|
|
261
|
+
} else {
|
|
262
|
+
if (agent.config?.systemPrompt) {
|
|
263
|
+
if (agent.config.systemPrompt.includes("{{memory}}")) {
|
|
264
|
+
try {
|
|
265
|
+
const memoryComponent = this.getComponent("memory");
|
|
266
|
+
if (memoryComponent) {
|
|
267
|
+
const memoryContent = await memoryComponent.recallMemory();
|
|
268
|
+
agent.config.systemPrompt = agent.config.systemPrompt.replace("{{memory}}", memoryContent || "(No memory)");
|
|
269
|
+
} else {
|
|
270
|
+
agent.config.systemPrompt = agent.config.systemPrompt.replace("{{memory}}", "(Memory component not available)");
|
|
271
|
+
}
|
|
272
|
+
} catch (err) {
|
|
273
|
+
logger.warn(`[handle_query] Failed to inject memory for agent ${agentName}: ${err}`);
|
|
274
|
+
agent.config.systemPrompt = agent.config.systemPrompt.replace("{{memory}}", "(Failed to load memory)");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (agent.config.systemPrompt.includes("{{workspace_dir}}")) {
|
|
278
|
+
agent.config.systemPrompt = agent.config.systemPrompt.replace("{{workspace_dir}}", process.cwd());
|
|
279
|
+
}
|
|
280
|
+
agent.config.systemPrompt = injectAgentNamePlaceholder(agent.config.systemPrompt, context);
|
|
281
|
+
}
|
|
282
|
+
logger.debug(`[handle_query] Injected memory/workspace_dir for existing agent: ${agentName}`);
|
|
283
|
+
}
|
|
284
|
+
try {
|
|
285
|
+
const taskComponent = this.getComponent("task");
|
|
286
|
+
registerLayaDecisionTaskHook(taskComponent);
|
|
287
|
+
} catch (err) {
|
|
288
|
+
logger.warn(`[handle_query] Failed to register LayaDecisionTaskHook: ${err}`);
|
|
289
|
+
}
|
|
290
|
+
try {
|
|
291
|
+
const taskComponent = this.getComponent("task");
|
|
292
|
+
registerLayaCompletionTaskHook(taskComponent);
|
|
293
|
+
} catch (err) {
|
|
294
|
+
logger.warn(`[handle_query] Failed to register LayaCompletionTaskHook: ${err}`);
|
|
295
|
+
}
|
|
296
|
+
const result = await agentComponent.run(agent.name, query, context);
|
|
297
|
+
if (result.error) {
|
|
298
|
+
if (result.originalError instanceof ContextError) {
|
|
299
|
+
throw result.originalError;
|
|
300
|
+
}
|
|
301
|
+
if (result.error.includes("__ASK_USER_ERROR__:")) {
|
|
302
|
+
throw new Error(result.error);
|
|
303
|
+
}
|
|
304
|
+
const errorMsg = result.error.toLowerCase();
|
|
305
|
+
if (errorMsg.includes("context") || errorMsg.includes("threshold") || errorMsg.includes("token") || result.error.includes("CTX_001")) {
|
|
306
|
+
const usageMatch = result.error.match(/(\d+)\/(\d+)\s*\(([\d.]+)%\)/);
|
|
307
|
+
let usage;
|
|
308
|
+
let contextWindow;
|
|
309
|
+
if (usageMatch) {
|
|
310
|
+
const totalTokens = parseInt(usageMatch[1], 10);
|
|
311
|
+
usage = {
|
|
312
|
+
promptTokens: totalTokens,
|
|
313
|
+
completionTokens: 0,
|
|
314
|
+
totalTokens
|
|
315
|
+
};
|
|
316
|
+
contextWindow = parseInt(usageMatch[2], 10);
|
|
317
|
+
}
|
|
318
|
+
const ctxError = new ContextError(result.error, ErrorCodes.CONTEXT_THRESHOLD_EXCEEDED, context?.sessionId, usage, contextWindow);
|
|
319
|
+
throw ctxError;
|
|
320
|
+
}
|
|
321
|
+
throw new Error(result.error, result.originalError ? { cause: result.originalError } : undefined);
|
|
322
|
+
}
|
|
323
|
+
return result.finalText || "";
|
|
324
|
+
}
|
|
325
|
+
async handleWorkflowAgentQuery(agentName, query, agentComponent, context) {
|
|
326
|
+
const registry = agentComponent.getRegistry?.();
|
|
327
|
+
if (!registry) {
|
|
328
|
+
return null;
|
|
329
|
+
}
|
|
330
|
+
const agentDef = registry.get(agentName);
|
|
331
|
+
if (!agentDef || agentDef.type !== "workflow") {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
const workflowComponent = this.getComponent("workflow");
|
|
335
|
+
if (!workflowComponent) {
|
|
336
|
+
throw new Error(`WorkflowComponent not available — cannot run workflow agent "${agentName}". ` + `Ensure the workflow component is registered.`);
|
|
337
|
+
}
|
|
338
|
+
const workflowName = agentDef.workflow;
|
|
339
|
+
if (!workflowName) {
|
|
340
|
+
throw new Error(`Agent "${agentName}" has type 'workflow' but no workflow configured.`);
|
|
341
|
+
}
|
|
342
|
+
const svc = workflowComponent.getService?.();
|
|
343
|
+
if (!svc || typeof svc.getWorkflowByName !== "function") {
|
|
344
|
+
throw new Error(`WorkflowService not available. Cannot run workflow agent "${agentName}".`);
|
|
345
|
+
}
|
|
346
|
+
const workflow = svc.getWorkflowByName(workflowName);
|
|
347
|
+
if (!workflow) {
|
|
348
|
+
throw new Error(`Workflow "${workflowName}" not found. ` + `Use 'roy-agent workflow add' to register it first.`);
|
|
349
|
+
}
|
|
350
|
+
const wfResult = await workflowComponent.runWorkflow(workflow.definition, { query }, { context });
|
|
351
|
+
if (wfResult.status === "paused") {
|
|
352
|
+
return JSON.stringify({
|
|
353
|
+
status: "paused",
|
|
354
|
+
message: `Workflow "${workflowName}" paused, waiting for user input.`,
|
|
355
|
+
pendingNodeId: wfResult.pendingNodeId,
|
|
356
|
+
query: wfResult.query,
|
|
357
|
+
sessionId: wfResult.sessionId,
|
|
358
|
+
hint: `Resume with: roy-agent workflow run -s ${wfResult.sessionId} --input "your response"`
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
if (wfResult.status === "failed") {
|
|
362
|
+
throw new Error(`Workflow "${workflowName}" execution failed: ${wfResult.error || "Unknown error (status: " + wfResult.status + ")"}`);
|
|
363
|
+
}
|
|
364
|
+
if (typeof wfResult.output === "string") {
|
|
365
|
+
return wfResult.output;
|
|
366
|
+
}
|
|
367
|
+
if (wfResult.output !== undefined && wfResult.output !== null) {
|
|
368
|
+
return JSON.stringify(wfResult.output);
|
|
369
|
+
}
|
|
370
|
+
if (wfResult.error) {
|
|
371
|
+
throw new Error(`Workflow "${workflowName}" completed with error: ${wfResult.error}`);
|
|
372
|
+
}
|
|
373
|
+
return "";
|
|
374
|
+
}
|
|
375
|
+
async handle_action(action, context) {
|
|
376
|
+
throw new Error("handle_action not implemented. Override in subclass.");
|
|
377
|
+
}
|
|
378
|
+
eventHandlers = new Map;
|
|
379
|
+
wildcardHandlers = new Set;
|
|
380
|
+
subscribe(handler) {
|
|
381
|
+
this.wildcardHandlers.add(handler);
|
|
382
|
+
logger.debug(`EnvEvent handler subscribed (wildcard)`);
|
|
383
|
+
return () => {
|
|
384
|
+
this.wildcardHandlers.delete(handler);
|
|
385
|
+
logger.debug(`EnvEvent handler unsubscribed (wildcard)`);
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
subscribeTo(eventType, handler) {
|
|
389
|
+
const types = Array.isArray(eventType) ? eventType : [eventType];
|
|
390
|
+
for (const type of types) {
|
|
391
|
+
if (!this.eventHandlers.has(type)) {
|
|
392
|
+
this.eventHandlers.set(type, new Set);
|
|
393
|
+
}
|
|
394
|
+
this.eventHandlers.get(type).add(handler);
|
|
395
|
+
}
|
|
396
|
+
logger.debug(`EnvEvent handler subscribed for types: ${types.join(", ")}`);
|
|
397
|
+
return () => {
|
|
398
|
+
for (const type of types) {
|
|
399
|
+
this.eventHandlers.get(type)?.delete(handler);
|
|
400
|
+
}
|
|
401
|
+
logger.debug(`EnvEvent handler unsubscribed for types: ${types.join(", ")}`);
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
subscribeAll(handler) {
|
|
405
|
+
return this.subscribe(handler);
|
|
406
|
+
}
|
|
407
|
+
pushEnvEvent(event) {
|
|
408
|
+
const fullEvent = "id" in event && event.id ? event : {
|
|
409
|
+
id: event.id ?? generateId(),
|
|
410
|
+
type: event.type,
|
|
411
|
+
timestamp: event.timestamp ?? Date.now(),
|
|
412
|
+
metadata: {
|
|
413
|
+
...event.metadata,
|
|
414
|
+
env_name: event.metadata?.env_name ?? this.name
|
|
415
|
+
},
|
|
416
|
+
payload: event.payload ?? {}
|
|
417
|
+
};
|
|
418
|
+
for (const handler of this.wildcardHandlers) {
|
|
419
|
+
try {
|
|
420
|
+
handler(fullEvent);
|
|
421
|
+
} catch (error) {
|
|
422
|
+
logger.error(`Error in EnvEvent handler: ${error}`);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
const handlers = this.eventHandlers.get(fullEvent.type);
|
|
426
|
+
if (handlers) {
|
|
427
|
+
for (const handler of handlers) {
|
|
428
|
+
try {
|
|
429
|
+
handler(fullEvent);
|
|
430
|
+
} catch (error) {
|
|
431
|
+
logger.error(`Error in EnvEvent handler for ${fullEvent.type}: ${error}`);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
emit(type, payload, metadata) {
|
|
437
|
+
const event = {
|
|
438
|
+
id: generateId(),
|
|
439
|
+
type,
|
|
440
|
+
timestamp: Date.now(),
|
|
441
|
+
metadata: {
|
|
442
|
+
env_name: this.name,
|
|
443
|
+
...metadata
|
|
444
|
+
},
|
|
445
|
+
payload
|
|
446
|
+
};
|
|
447
|
+
this.pushEnvEvent(event);
|
|
448
|
+
}
|
|
449
|
+
async initializeComponents() {
|
|
450
|
+
logger.debug(`Starting component initialization, total: ${this.components.size}`);
|
|
451
|
+
const configComp = this.components.get("config");
|
|
452
|
+
if (configComp && configComp.getStatus() === "created") {
|
|
453
|
+
logger.debug(`Initializing ConfigComponent first...`);
|
|
454
|
+
await configComp.init({
|
|
455
|
+
name: "config",
|
|
456
|
+
version: configComp.version,
|
|
457
|
+
enabled: true,
|
|
458
|
+
env: this
|
|
459
|
+
});
|
|
460
|
+
logger.debug(`ConfigComponent initialized`);
|
|
461
|
+
} else {
|
|
462
|
+
logger.debug(`No ConfigComponent found, skipping first stage`);
|
|
463
|
+
}
|
|
464
|
+
const otherComponents = Array.from(this.components.values()).filter((c) => c.getStatus() === "created");
|
|
465
|
+
if (otherComponents.length > 0) {
|
|
466
|
+
logger.debug(`Initializing ${otherComponents.length} other components...`);
|
|
467
|
+
for (const component of otherComponents) {
|
|
468
|
+
logger.debug(`Initializing component: ${component.name}`);
|
|
469
|
+
await component.init({
|
|
470
|
+
name: component.name,
|
|
471
|
+
version: component.version,
|
|
472
|
+
enabled: true,
|
|
473
|
+
env: this
|
|
474
|
+
});
|
|
475
|
+
logger.debug(`Component initialized: ${component.name}`);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
logger.debug(`All components initialized`);
|
|
479
|
+
}
|
|
480
|
+
async startComponents() {
|
|
481
|
+
const allComponents = Array.from(this.components.values());
|
|
482
|
+
if (allComponents.length > 0) {
|
|
483
|
+
logger.debug(`Starting ${allComponents.length} components...`);
|
|
484
|
+
for (const component of allComponents) {
|
|
485
|
+
logger.debug(`Starting component: ${component.name} (current status: ${component.getStatus()})`);
|
|
486
|
+
await component.start();
|
|
487
|
+
logger.debug(`Component started: ${component.name}`);
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
async stopComponents() {
|
|
492
|
+
const componentsToStop = Array.from(this.components.values()).filter((c) => c.getStatus() !== "stopped").reverse();
|
|
493
|
+
if (componentsToStop.length > 0) {
|
|
494
|
+
logger.debug(`Stopping ${componentsToStop.length} components...`);
|
|
495
|
+
for (const component of componentsToStop) {
|
|
496
|
+
logger.debug(`Stopping component: ${component.name}`);
|
|
497
|
+
await component.stop();
|
|
498
|
+
logger.debug(`Component stopped: ${component.name}`);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
async onInit() {
|
|
503
|
+
await this.initializeComponents();
|
|
504
|
+
logger.info(`Environment "${this.name}" initialized`);
|
|
505
|
+
}
|
|
506
|
+
async onStart() {
|
|
507
|
+
await this.startComponents();
|
|
508
|
+
logger.info(`Environment "${this.name}" started`);
|
|
509
|
+
}
|
|
510
|
+
async onStop() {
|
|
511
|
+
await this.stopComponents();
|
|
512
|
+
this.eventHandlers.clear();
|
|
513
|
+
this.wildcardHandlers.clear();
|
|
514
|
+
logger.info(`Environment "${this.name}" stopped`);
|
|
515
|
+
}
|
|
516
|
+
async init() {
|
|
517
|
+
Object.defineProperty(this, "env", {
|
|
518
|
+
value: this,
|
|
519
|
+
writable: true,
|
|
520
|
+
enumerable: false,
|
|
521
|
+
configurable: true
|
|
522
|
+
});
|
|
523
|
+
this.setStatus("initializing");
|
|
524
|
+
await this.onInit();
|
|
525
|
+
this.setStatus("running");
|
|
526
|
+
}
|
|
527
|
+
async start() {
|
|
528
|
+
if (this._started)
|
|
529
|
+
return;
|
|
530
|
+
this._started = true;
|
|
531
|
+
await this.onStart();
|
|
532
|
+
this.setStatus("running");
|
|
533
|
+
logger.info(`Environment "${this.name}" started`);
|
|
534
|
+
}
|
|
535
|
+
async stop() {
|
|
536
|
+
this.setStatus("stopping");
|
|
537
|
+
await this.onStop();
|
|
538
|
+
this.setStatus("stopped");
|
|
539
|
+
}
|
|
540
|
+
async loadServiceConfig(configPath) {
|
|
541
|
+
const configComponent = this.getComponent("config");
|
|
542
|
+
if (!configComponent) {
|
|
543
|
+
throw new Error("ConfigComponent not found. Please register ConfigComponent before loading service config.");
|
|
544
|
+
}
|
|
545
|
+
const xdgDataHome = configComponent.getXdgDataHome();
|
|
546
|
+
const fullPath = path.resolve(xdgDataHome, configPath);
|
|
547
|
+
if (!fsSync.existsSync(fullPath)) {
|
|
548
|
+
throw new Error(`Service config file not found: ${fullPath}`);
|
|
549
|
+
}
|
|
550
|
+
const content = fsSync.readFileSync(fullPath, "utf-8");
|
|
551
|
+
let config;
|
|
552
|
+
try {
|
|
553
|
+
config = JSON.parse(content);
|
|
554
|
+
} catch (e) {
|
|
555
|
+
throw new Error(`Failed to parse service config: ${e}`);
|
|
556
|
+
}
|
|
557
|
+
logger.debug(`Service config loaded from: ${fullPath}`);
|
|
558
|
+
return config;
|
|
559
|
+
}
|
|
560
|
+
generateComponentOptions(componentName, configEntry) {
|
|
561
|
+
const configComponent = this.getComponent("config");
|
|
562
|
+
if (!configComponent) {
|
|
563
|
+
throw new Error("ConfigComponent not found. Please register ConfigComponent before generating component options.");
|
|
564
|
+
}
|
|
565
|
+
const options = {
|
|
566
|
+
configComponent,
|
|
567
|
+
configPath: configEntry.configPath,
|
|
568
|
+
envPrefix: configEntry.envPrefix,
|
|
569
|
+
config: configEntry.config
|
|
570
|
+
};
|
|
571
|
+
logger.debug(`Generated options for component: ${componentName}`);
|
|
572
|
+
return options;
|
|
573
|
+
}
|
|
574
|
+
async registerComponentWithConfig(component, configEntry) {
|
|
575
|
+
if (!this.components.has(component.name)) {
|
|
576
|
+
this.registerComponent(component);
|
|
577
|
+
}
|
|
578
|
+
const options = this.generateComponentOptions(component.name, configEntry);
|
|
579
|
+
if (component.getStatus() === "running") {
|
|
580
|
+
logger.debug(`Component ${component.name} already initialized, skipping`);
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
await component.init({
|
|
584
|
+
name: component.name,
|
|
585
|
+
version: component.version,
|
|
586
|
+
enabled: configEntry.enabled ?? true,
|
|
587
|
+
env: this,
|
|
588
|
+
options
|
|
589
|
+
});
|
|
590
|
+
logger.debug(`Component ${component.name} registered and initialized with config`);
|
|
591
|
+
}
|
|
592
|
+
async initFromConfig(configPath) {
|
|
593
|
+
if (!this.env) {
|
|
594
|
+
Object.defineProperty(this, "env", {
|
|
595
|
+
value: this,
|
|
596
|
+
writable: true,
|
|
597
|
+
enumerable: false,
|
|
598
|
+
configurable: true
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
const serviceConfig = await this.loadServiceConfig(configPath);
|
|
602
|
+
if (serviceConfig.environment) {
|
|
603
|
+
if (serviceConfig.environment.name) {
|
|
604
|
+
this.name = serviceConfig.environment.name;
|
|
605
|
+
}
|
|
606
|
+
if (serviceConfig.environment.version) {
|
|
607
|
+
this.version = serviceConfig.environment.version;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
const configComponent = this.getComponent("config");
|
|
611
|
+
if (!configComponent) {
|
|
612
|
+
throw new Error("ConfigComponent not found. Please register ConfigComponent before initFromConfig.");
|
|
613
|
+
}
|
|
614
|
+
if (configComponent.getStatus() === "created") {
|
|
615
|
+
await configComponent.init({
|
|
616
|
+
name: "config",
|
|
617
|
+
version: configComponent.version,
|
|
618
|
+
enabled: true,
|
|
619
|
+
env: this
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
const components = serviceConfig.components || {};
|
|
623
|
+
for (const [componentName, configEntry] of Object.entries(components)) {
|
|
624
|
+
if (configEntry.enabled === false) {
|
|
625
|
+
logger.debug(`Component ${componentName} is disabled, skipping`);
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const component = this.getComponent(componentName);
|
|
629
|
+
if (!component) {
|
|
630
|
+
logger.warn(`Component ${componentName} not registered, skipping`);
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (component.name === "config")
|
|
634
|
+
continue;
|
|
635
|
+
await this.registerComponentWithConfig(component, configEntry);
|
|
636
|
+
}
|
|
637
|
+
this.setStatus("running");
|
|
638
|
+
logger.info(`Environment "${this.name}" initialized from config: ${configPath}`);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
__legacyDecorateClassTS([
|
|
642
|
+
TracedAs("env.handle_query", {
|
|
643
|
+
paramFilter: envQueryParamFilter,
|
|
644
|
+
recordResult: false,
|
|
645
|
+
logResult: true,
|
|
646
|
+
log: true
|
|
647
|
+
})
|
|
648
|
+
], BaseEnvironment.prototype, "handle_query", null);
|
|
649
|
+
__legacyDecorateClassTS([
|
|
650
|
+
TracedAs("env.handle_workflow_agent_query", {
|
|
651
|
+
paramFilter: envQueryParamFilter,
|
|
652
|
+
recordResult: false,
|
|
653
|
+
logResult: true,
|
|
654
|
+
log: true
|
|
655
|
+
})
|
|
656
|
+
], BaseEnvironment.prototype, "handleWorkflowAgentQuery", null);
|
|
657
|
+
|
|
658
|
+
// src/env/index.ts
|
|
659
|
+
init_hook();
|
|
660
|
+
init_context();
|
|
661
|
+
|
|
662
|
+
export { generateId, generateDescendingId, BaseEnvironment };
|