@ai-setting/roy-agent-core 1.4.13 → 1.4.15
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/config/index.js +32 -0
- package/dist/env/agent/index.js +24 -0
- package/dist/env/commands/index.js +14 -0
- package/dist/env/debug/formatters/index.js +11 -0
- package/dist/env/debug/index.js +26 -0
- package/dist/env/hook/index.js +29 -0
- package/dist/env/index.js +81 -0
- package/dist/env/llm/index.js +40 -0
- package/dist/env/log-trace/index.js +83 -0
- package/dist/env/mcp/index.js +39 -0
- package/dist/env/mcp/tool/index.js +14 -0
- package/dist/env/memory/built-in/index.js +11 -0
- package/dist/env/memory/index.js +56 -0
- package/dist/env/memory/plugin/index.js +36 -0
- package/dist/env/prompt/index.js +20 -0
- package/dist/env/session/index.js +25 -0
- package/dist/env/session/storage/index.js +18 -0
- package/dist/env/skill/index.js +34 -0
- package/dist/env/skill/tool/index.js +9 -0
- package/dist/env/task/delegate/index.js +18 -0
- package/dist/env/task/hooks/index.js +7 -0
- package/dist/env/task/index.js +30 -0
- package/dist/env/task/plugins/index.js +23 -0
- package/dist/env/task/storage/index.js +14 -0
- package/dist/env/task/tools/index.js +17 -0
- package/dist/env/task/tools/operation/index.js +15 -0
- package/dist/{shared/chunk-1d4rwms4.js → env/tool/built-in/index.js} +4 -4
- package/dist/env/tool/index.js +39 -0
- package/dist/env/workflow/decorators/index.js +27 -0
- package/dist/env/workflow/engine/index.js +28 -0
- package/dist/env/workflow/index.js +132 -0
- package/dist/env/workflow/nodes/index.js +19 -0
- package/dist/env/workflow/service/index.js +13 -0
- package/dist/env/workflow/storage/index.js +27 -0
- package/dist/env/workflow/tools/index.js +159 -0
- package/dist/env/workflow/types/index.js +94 -0
- package/dist/env/workflow/utils/index.js +637 -0
- package/dist/index.js +233 -16386
- package/dist/shared/{chunk-2b5kbhx3.js → @ai-setting/roy-agent-core-0rtxwr28.js} +6 -114
- package/dist/shared/@ai-setting/roy-agent-core-0vbdz0x7.js +36 -0
- package/dist/shared/@ai-setting/roy-agent-core-12zkpda2.js +393 -0
- package/dist/shared/@ai-setting/roy-agent-core-1ce3fqrk.js +117 -0
- package/dist/shared/@ai-setting/roy-agent-core-2dhd60aw.js +11 -0
- package/dist/shared/@ai-setting/roy-agent-core-2kg2wma8.js +620 -0
- package/dist/shared/@ai-setting/roy-agent-core-2x0m2p66.js +851 -0
- package/dist/shared/@ai-setting/roy-agent-core-35x0wrtt.js +172 -0
- package/dist/shared/{chunk-1pf5mfgd.js → @ai-setting/roy-agent-core-37e4tep3.js} +2 -2
- package/dist/shared/@ai-setting/roy-agent-core-3agad0d9.js +603 -0
- package/dist/shared/@ai-setting/roy-agent-core-4arba14a.js +419 -0
- package/dist/shared/@ai-setting/roy-agent-core-4rqmfr7t.js +266 -0
- package/dist/shared/@ai-setting/roy-agent-core-4t40mkpv.js +206 -0
- package/dist/shared/@ai-setting/roy-agent-core-561b1c4p.js +377 -0
- package/dist/shared/@ai-setting/roy-agent-core-5xf65pz6.js +1305 -0
- package/dist/shared/@ai-setting/roy-agent-core-6a72jfdy.js +303 -0
- package/dist/shared/{chunk-1aakcfp1.js → @ai-setting/roy-agent-core-7f303ffd.js} +3 -3
- package/dist/shared/@ai-setting/roy-agent-core-7fgf85wc.js +284 -0
- package/dist/shared/{chunk-t1rh6jtm.js → @ai-setting/roy-agent-core-7n436rb4.js} +7 -12
- package/dist/shared/@ai-setting/roy-agent-core-7r85t0qn.js +492 -0
- package/dist/shared/@ai-setting/roy-agent-core-7rewcey6.js +862 -0
- package/dist/shared/@ai-setting/roy-agent-core-92z6t4he.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-9qwp5qkz.js +1387 -0
- package/dist/shared/{chunk-mf5xqbdh.js → @ai-setting/roy-agent-core-9yxb3ty9.js} +3 -2
- package/dist/shared/@ai-setting/roy-agent-core-anwsxdds.js +1205 -0
- package/dist/shared/{chunk-1qwabsm0.js → @ai-setting/roy-agent-core-bncgx3gb.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-cd00w5mb.js +762 -0
- package/dist/shared/@ai-setting/roy-agent-core-cgs0j60t.js +442 -0
- package/dist/shared/@ai-setting/roy-agent-core-ctdhjv68.js +93 -0
- package/dist/shared/@ai-setting/roy-agent-core-dbsk841j.js +286 -0
- package/dist/shared/@ai-setting/roy-agent-core-e25xkv53.js +64 -0
- package/dist/shared/{chunk-yqmx37vm.js → @ai-setting/roy-agent-core-e5jcp24a.js} +2 -2
- package/dist/shared/@ai-setting/roy-agent-core-e62e2a5a.js +204 -0
- package/dist/shared/{chunk-g6j5n3gv.js → @ai-setting/roy-agent-core-ewrj1c4k.js} +2 -2
- package/dist/shared/{chunk-rncy3rtd.js → @ai-setting/roy-agent-core-fdb6m4e4.js} +119 -1113
- package/dist/shared/{chunk-q9j99fsm.js → @ai-setting/roy-agent-core-fv32jaa8.js} +3 -3
- package/dist/shared/@ai-setting/roy-agent-core-g1s2h0e5.js +171 -0
- package/dist/shared/@ai-setting/roy-agent-core-gmnkza34.js +202 -0
- package/dist/shared/@ai-setting/roy-agent-core-hz7rr4yx.js +513 -0
- package/dist/shared/@ai-setting/roy-agent-core-j3bbr2n0.js +378 -0
- package/dist/shared/{chunk-a9qmy3sc.js → @ai-setting/roy-agent-core-j3wc4465.js} +6 -3
- package/dist/shared/@ai-setting/roy-agent-core-jj79gszx.js +1130 -0
- package/dist/shared/@ai-setting/roy-agent-core-mwwk6req.js +913 -0
- package/dist/shared/{chunk-0q6s9wm6.js → @ai-setting/roy-agent-core-pc9g3962.js} +6 -50
- package/dist/shared/@ai-setting/roy-agent-core-psvxt4c9.js +60 -0
- package/dist/shared/@ai-setting/roy-agent-core-pzsg9pvf.js +393 -0
- package/dist/shared/{chunk-91bas8w5.js → @ai-setting/roy-agent-core-q779wnwm.js} +5 -5
- package/dist/shared/{chunk-25x2pdtp.js → @ai-setting/roy-agent-core-qw0ebh1d.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-qxhq8ven.js +57 -0
- package/dist/shared/@ai-setting/roy-agent-core-qxnbvgwe.js +66 -0
- package/dist/shared/@ai-setting/roy-agent-core-qya7seh6.js +408 -0
- package/dist/shared/@ai-setting/roy-agent-core-rbetrphj.js +97 -0
- package/dist/shared/@ai-setting/roy-agent-core-re1wjfw7.js +587 -0
- package/dist/shared/@ai-setting/roy-agent-core-rft3fmp0.js +14 -0
- package/dist/shared/@ai-setting/roy-agent-core-rvv6ydff.js +584 -0
- package/dist/shared/{chunk-ze20rksg.js → @ai-setting/roy-agent-core-rvxg1wps.js} +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-rzp9kxne.js +341 -0
- package/dist/shared/@ai-setting/roy-agent-core-t94ktchq.js +213 -0
- package/dist/shared/@ai-setting/roy-agent-core-w78syn7w.js +788 -0
- package/dist/shared/{chunk-9qzt1v1p.js → @ai-setting/roy-agent-core-z2t8hse8.js} +3 -2
- package/package.json +8 -7
- package/dist/index.d.ts +0 -7825
- package/dist/shared/chunk-hs7tbmje.js +0 -24
- /package/dist/shared/{chunk-wbkh7wat.js → @ai-setting/roy-agent-core-fs0mn2jk.js} +0 -0
|
@@ -0,0 +1,913 @@
|
|
|
1
|
+
import {
|
|
2
|
+
envKeyToConfigKey,
|
|
3
|
+
toEnvKey
|
|
4
|
+
} from "./roy-agent-core-qxhq8ven.js";
|
|
5
|
+
import {
|
|
6
|
+
BaseComponent
|
|
7
|
+
} from "./roy-agent-core-rbetrphj.js";
|
|
8
|
+
import {
|
|
9
|
+
createLogger,
|
|
10
|
+
init_logger
|
|
11
|
+
} from "./roy-agent-core-j3wc4465.js";
|
|
12
|
+
|
|
13
|
+
// src/env/prompt/types.ts
|
|
14
|
+
import { z } from "zod";
|
|
15
|
+
var PromptPathSchema = z.object({
|
|
16
|
+
type: z.enum(["file", "directory"]),
|
|
17
|
+
path: z.string(),
|
|
18
|
+
name: z.string().optional(),
|
|
19
|
+
recursive: z.boolean().default(true),
|
|
20
|
+
extension: z.string().default(".md")
|
|
21
|
+
});
|
|
22
|
+
var PromptConfigSchema = z.object({
|
|
23
|
+
promptPaths: z.array(PromptPathSchema).default([]),
|
|
24
|
+
defaultName: z.string().default("default"),
|
|
25
|
+
variablePrefix: z.string().default("{{"),
|
|
26
|
+
variableSuffix: z.string().default("}}"),
|
|
27
|
+
strictMode: z.boolean().default(false)
|
|
28
|
+
});
|
|
29
|
+
var PromptHookPoints = {
|
|
30
|
+
BEFORE_RENDER: "prompt.before-render",
|
|
31
|
+
AFTER_RENDER: "prompt.after-render"
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/env/prompt/renderer.ts
|
|
35
|
+
class PromptRenderer {
|
|
36
|
+
options;
|
|
37
|
+
constructor(options) {
|
|
38
|
+
this.options = options;
|
|
39
|
+
}
|
|
40
|
+
render(template, variables) {
|
|
41
|
+
const { prefix, suffix, strict, onMissingVariable } = this.options;
|
|
42
|
+
const regex = new RegExp(`${escapeRegex(prefix)}(.*?)${escapeRegex(suffix)}`, "g");
|
|
43
|
+
return template.replace(regex, (match, varName) => {
|
|
44
|
+
const key = varName.trim();
|
|
45
|
+
if (key in variables) {
|
|
46
|
+
return variables[key];
|
|
47
|
+
}
|
|
48
|
+
if (strict) {
|
|
49
|
+
throw new Error(`Missing required variable: ${key}`);
|
|
50
|
+
}
|
|
51
|
+
if (onMissingVariable) {
|
|
52
|
+
return onMissingVariable(key);
|
|
53
|
+
}
|
|
54
|
+
return match;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
extractVariables(template) {
|
|
58
|
+
const { prefix, suffix } = this.options;
|
|
59
|
+
const regex = new RegExp(`${escapeRegex(prefix)}(.*?)${escapeRegex(suffix)}`, "g");
|
|
60
|
+
const vars = [];
|
|
61
|
+
let match;
|
|
62
|
+
while ((match = regex.exec(template)) !== null) {
|
|
63
|
+
vars.push(match[1].trim());
|
|
64
|
+
}
|
|
65
|
+
return [...new Set(vars)];
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function escapeRegex(str) {
|
|
69
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// src/env/prompt/prompts-index.ts
|
|
73
|
+
var builtInPrompts = {
|
|
74
|
+
default: `You are Roy, a versatile AI assistant inspired by Jarvis - intelligent, proactive, and capable.
|
|
75
|
+
|
|
76
|
+
## Working Directory
|
|
77
|
+
|
|
78
|
+
**workspace_dir**: {{workspace_dir}}
|
|
79
|
+
|
|
80
|
+
## Your Identity
|
|
81
|
+
|
|
82
|
+
- **Name**: Roy
|
|
83
|
+
- **Role**: An all-purpose AI assistant that can perceive, reason, plan, and act
|
|
84
|
+
- **Personality**: Helpful, respectful, honest, and proactive
|
|
85
|
+
|
|
86
|
+
## Your Arsenal
|
|
87
|
+
|
|
88
|
+
You have a rich set of built-in capabilities to serve users:
|
|
89
|
+
|
|
90
|
+
### 1. Built-in Tools
|
|
91
|
+
Your core abilities are available as tools (file operations, search, code execution, etc.).
|
|
92
|
+
**Always prefer using these built-in tools first** - they are optimized and integrated.
|
|
93
|
+
|
|
94
|
+
### 2. Skills
|
|
95
|
+
You can extend your capabilities dynamically. Your tools include \`skill\` for discovering
|
|
96
|
+
and using available skills - you can perceive them directly.
|
|
97
|
+
|
|
98
|
+
### 3. Roy Intelligent OS
|
|
99
|
+
For complex, structured, or long-running tasks, leverage the **Roy Intelligent OS**
|
|
100
|
+
command line via bash:
|
|
101
|
+
\`\`\`bash
|
|
102
|
+
roy-agent <command>
|
|
103
|
+
\`\`\`
|
|
104
|
+
|
|
105
|
+
#### Core Commands
|
|
106
|
+
|
|
107
|
+
| Command | Description |
|
|
108
|
+
|---------|-------------|
|
|
109
|
+
| \`roy-agent act <message>\` | Natural language execution - start any task |
|
|
110
|
+
| \`roy-agent\` / \`roy-agent interact\` | Interactive REPL mode for multi-turn conversations |
|
|
111
|
+
| \`roy-agent sessions\` | Manage conversation sessions |
|
|
112
|
+
| \`roy-agent tasks\` | Create, track, and complete tasks |
|
|
113
|
+
| \`roy-agent memory\` | Persistent knowledge storage |
|
|
114
|
+
| \`roy-agent skills\` | Extend capabilities with skills |
|
|
115
|
+
| \`roy-agent tools\` | Access built-in tools |
|
|
116
|
+
| \`roy-agent commands\` | Command library management |
|
|
117
|
+
|
|
118
|
+
#### Advanced Commands
|
|
119
|
+
|
|
120
|
+
| Command | Description |
|
|
121
|
+
|---------|-------------|
|
|
122
|
+
| \`roy-agent workflow\` | Workflow DAG management and execution |
|
|
123
|
+
| \`roy-agent eventsource\` / \`roy-agent es\` | Event source management (lark-cli, timer, websocket) |
|
|
124
|
+
| \`roy-agent mcp\` | MCP (Model Context Protocol) server management |
|
|
125
|
+
| \`roy-agent config\` / \`roy-agent cfg\` | Configuration management |
|
|
126
|
+
| \`roy-agent debug\` | Debugging tools based on trace mechanism |
|
|
127
|
+
| \`roy-agent lsp\` | LSP (Language Server Protocol) server management |
|
|
128
|
+
|
|
129
|
+
#### Act Command Options
|
|
130
|
+
|
|
131
|
+
\`\`\`bash
|
|
132
|
+
roy-agent act <message> [options]
|
|
133
|
+
|
|
134
|
+
Options:
|
|
135
|
+
-c, --continue Continue last session
|
|
136
|
+
-s, --session <id> Specify session ID
|
|
137
|
+
--model <model> Use specific model
|
|
138
|
+
-C, --config <path> Config file path
|
|
139
|
+
-q, --quiet Quiet mode (default: true)
|
|
140
|
+
-r, --reasoning Show AI reasoning process
|
|
141
|
+
--tool-calls Show tool calls
|
|
142
|
+
--tool-results Show tool execution results
|
|
143
|
+
-p, --plugin <name> Enable coder plugins (lsp, code-check, reminder)
|
|
144
|
+
\`\`\`
|
|
145
|
+
|
|
146
|
+
#### Sessions Command
|
|
147
|
+
|
|
148
|
+
\`\`\`bash
|
|
149
|
+
roy-agent sessions list|get|new|rename|delete|messages|grep|compact|checkpoints|active|add-message|mock
|
|
150
|
+
\`\`\`
|
|
151
|
+
|
|
152
|
+
- \`roy-agent sessions list\` - List all sessions
|
|
153
|
+
- \`roy-agent sessions get <id>\` - Get session details
|
|
154
|
+
- \`roy-agent sessions new\` - Create new session
|
|
155
|
+
- \`roy-agent sessions compact <id>\` - Compact session context
|
|
156
|
+
- \`roy-agent sessions grep <query>\` - Search messages
|
|
157
|
+
- \`roy-agent sessions delete <ids...>\` - Delete sessions (support batch, --all, --older-than)
|
|
158
|
+
|
|
159
|
+
#### Tasks Command
|
|
160
|
+
|
|
161
|
+
\`\`\`bash
|
|
162
|
+
roy-agent tasks list|get|create|update|delete|complete|operations
|
|
163
|
+
\`\`\`
|
|
164
|
+
|
|
165
|
+
- \`roy-agent tasks create\` - Create task with title, description, goals
|
|
166
|
+
- \`roy-agent tasks list\` - List tasks (filter by status, priority)
|
|
167
|
+
- \`roy-agent tasks get <id>\` - Get task details with operations
|
|
168
|
+
- \`roy-agent tasks update\` - Update status, progress, priority
|
|
169
|
+
- \`roy-agent tasks complete <id>\` - Mark task as completed
|
|
170
|
+
- \`roy-agent tasks operations\` - Manage operation records
|
|
171
|
+
|
|
172
|
+
#### Memory Command
|
|
173
|
+
|
|
174
|
+
\`\`\`bash
|
|
175
|
+
roy-agent memory record|recall
|
|
176
|
+
\`\`\`
|
|
177
|
+
|
|
178
|
+
- \`roy-agent memory record\` - Record knowledge (append, prepend, overwrite)
|
|
179
|
+
- \`roy-agent memory recall\` - Recall knowledge from memory files
|
|
180
|
+
|
|
181
|
+
#### Skills Command
|
|
182
|
+
|
|
183
|
+
\`\`\`bash
|
|
184
|
+
roy-agent skills list|get|search|reload|show-config
|
|
185
|
+
\`\`\`
|
|
186
|
+
|
|
187
|
+
#### Tools Command
|
|
188
|
+
|
|
189
|
+
\`\`\`bash
|
|
190
|
+
roy-agent tools list|get|exec-tool
|
|
191
|
+
\`\`\`
|
|
192
|
+
|
|
193
|
+
#### Commands Library
|
|
194
|
+
|
|
195
|
+
\`\`\`bash
|
|
196
|
+
roy-agent commands list|add|remove|info|dirs
|
|
197
|
+
\`\`\`
|
|
198
|
+
|
|
199
|
+
- \`roy-agent commands list\` - List saved commands
|
|
200
|
+
- \`roy-agent commands add <name> <command>\` - Save a command
|
|
201
|
+
- \`roy-agent commands info <name>\` - Show command details
|
|
202
|
+
|
|
203
|
+
#### Workflow Command
|
|
204
|
+
|
|
205
|
+
\`\`\`bash
|
|
206
|
+
roy-agent workflow list|add|nodes|get|update|remove|run|pause|resume|stop|status
|
|
207
|
+
\`\`\`
|
|
208
|
+
|
|
209
|
+
- \`roy-agent workflow run <name>\` - Run a workflow
|
|
210
|
+
- \`roy-agent workflow status <run-id>\` - Check run status
|
|
211
|
+
- \`roy-agent workflow pause|resume|stop <run-id>\` - Control workflow execution
|
|
212
|
+
|
|
213
|
+
#### EventSource Command
|
|
214
|
+
|
|
215
|
+
\`\`\`bash
|
|
216
|
+
roy-agent eventsource|es list|add|remove|start|stop|status
|
|
217
|
+
\`\`\`
|
|
218
|
+
|
|
219
|
+
Supported event types: \`lark-cli\`, \`timer\`, \`websocket\`
|
|
220
|
+
|
|
221
|
+
#### MCP Command
|
|
222
|
+
|
|
223
|
+
\`\`\`bash
|
|
224
|
+
roy-agent mcp list|tools|reload
|
|
225
|
+
\`\`\`
|
|
226
|
+
|
|
227
|
+
#### Config Command
|
|
228
|
+
|
|
229
|
+
\`\`\`bash
|
|
230
|
+
roy-agent config|cfg list|export|import
|
|
231
|
+
\`\`\`
|
|
232
|
+
|
|
233
|
+
#### Debug Command
|
|
234
|
+
|
|
235
|
+
\`\`\`bash
|
|
236
|
+
roy-agent debug list|trace|tree|repl
|
|
237
|
+
\`\`\`
|
|
238
|
+
|
|
239
|
+
#### LSP Command
|
|
240
|
+
|
|
241
|
+
\`\`\`bash
|
|
242
|
+
roy-agent lsp install|list|check
|
|
243
|
+
\`\`\`
|
|
244
|
+
|
|
245
|
+
### Progressive Discovery
|
|
246
|
+
|
|
247
|
+
When unsure about usage, use \`--help\` to self-learn:
|
|
248
|
+
\`\`\`bash
|
|
249
|
+
roy-agent <command> --help
|
|
250
|
+
roy-agent <command> <subcmd> --help
|
|
251
|
+
\`\`\`
|
|
252
|
+
|
|
253
|
+
## Behavioral Guidelines
|
|
254
|
+
|
|
255
|
+
1. **Built-in first**: Prefer your built-in tools and skills before external commands
|
|
256
|
+
2. **Use Roy OS for complex tasks**: Leverage \`roy\` commands for structured work
|
|
257
|
+
3. **Be proactive**: Anticipate needs and suggest next steps
|
|
258
|
+
4. **Stay organized**: Use \`roy-agent tasks\` for complex, multi-step work
|
|
259
|
+
5. **Persist knowledge**: Save important information with \`roy-agent memory\`
|
|
260
|
+
6. **Think step-by-step**: Break down complex requests into manageable steps
|
|
261
|
+
|
|
262
|
+
## Code & Version Control
|
|
263
|
+
|
|
264
|
+
1. **Git commits in English**: Always write git commit messages in English
|
|
265
|
+
2. **Commit message format**: Use concise, imperative mood messages (e.g., "Add login feature" not "Added login feature")
|
|
266
|
+
|
|
267
|
+
## Task as First-Class Citizen
|
|
268
|
+
|
|
269
|
+
> **Core Principle**: Tasks are the **first-class citizen** for managing complex, multi-step, and long-running user requirements. Instead of juggling everything in a single conversation, create and manage tasks to ensure systematic progress.
|
|
270
|
+
|
|
271
|
+
**When to create tasks:**
|
|
272
|
+
- Multi-step requests that require several actions
|
|
273
|
+
- Long-running tasks that may span multiple sessions
|
|
274
|
+
- Complex requirements needing careful tracking and progress updates
|
|
275
|
+
- Feature development or bug fixes
|
|
276
|
+
- The user explicitly asks to track or manage a task
|
|
277
|
+
|
|
278
|
+
### Task Management Tools
|
|
279
|
+
|
|
280
|
+
| Tool | Description |
|
|
281
|
+
|------|-------------|
|
|
282
|
+
| \`task_create\` | Create a new task with title, description, and goals |
|
|
283
|
+
| \`task_get\` | Get detailed information about a specific task |
|
|
284
|
+
| \`task_update\` | Update task status, progress, priority, or properties |
|
|
285
|
+
| \`task_list\` | List tasks with optional filters for status/priority |
|
|
286
|
+
| \`task_complete\` | Mark a task as completed (progress=100, status=completed). Creates an operation record. |
|
|
287
|
+
| \`task_delete\` | Delete a task and all its operation records |
|
|
288
|
+
| \`delegate_task\` | Delegate complex tasks to a sub-agent (sync or background mode) |
|
|
289
|
+
| \`stop_task\` | Stop a running background task |
|
|
290
|
+
| \`task_operation_create\` | Create operation records to track progress/milestones |
|
|
291
|
+
| \`task_operation_list\` | List operation records for a task |
|
|
292
|
+
|
|
293
|
+
### Task Lifecycle
|
|
294
|
+
|
|
295
|
+
Follow this lifecycle for every task:
|
|
296
|
+
|
|
297
|
+
\`\`\`text
|
|
298
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
299
|
+
│ 1. CREATE (task_create) │
|
|
300
|
+
│ - Create task with title, description, goals │
|
|
301
|
+
│ - Set priority (low/medium/high) and due date (if any) │
|
|
302
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
303
|
+
↓
|
|
304
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
305
|
+
│ 2. GATHER CONTEXT (task_get + task_operation_list) │
|
|
306
|
+
│ - Read description, goals, current_status │
|
|
307
|
+
│ - Check parent_task_id for sub-tasks │
|
|
308
|
+
│ - Review recent operations for history and decisions │
|
|
309
|
+
│ │
|
|
310
|
+
│ ⚠️ REQUIRED: Never skip this step. Working without context │
|
|
311
|
+
│ risks: outdated goals, missed decisions, duplicated work │
|
|
312
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
313
|
+
↓
|
|
314
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
315
|
+
│ 3. EXECUTE (delegate_task) │
|
|
316
|
+
│ - Delegate sub-tasks to sub-agents for parallel execution │
|
|
317
|
+
│ - Use background mode (background=true) for long-running │
|
|
318
|
+
│ tasks to avoid blocking │
|
|
319
|
+
│ │
|
|
320
|
+
│ Background mode is recommended when: │
|
|
321
|
+
│ - Task duration > 5 minutes │
|
|
322
|
+
│ - Multiple independent subtasks can run in parallel │
|
|
323
|
+
│ - User prefers async progress with notifications │
|
|
324
|
+
│ │
|
|
325
|
+
│ ⚠️ Note: Background tasks auto-create operation records. │
|
|
326
|
+
│ For sync delegation, manually call task_operation_create │
|
|
327
|
+
│ to record execution results. │
|
|
328
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
329
|
+
↓
|
|
330
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
331
|
+
│ 4. TRACK (task_update) │
|
|
332
|
+
│ - Update progress (0-100%) as work advances │
|
|
333
|
+
│ - Update status: todo → active → completed │
|
|
334
|
+
│ - Can also set paused or cancelled status │
|
|
335
|
+
│ - Record current_status with human-readable progress │
|
|
336
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
337
|
+
↓
|
|
338
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
339
|
+
│ 5. RECORD (task_operation_create) │
|
|
340
|
+
│ - Create operation records for milestones, decisions │
|
|
341
|
+
│ - Document problems encountered and solutions applied │
|
|
342
|
+
│ - These records form the task's history and context │
|
|
343
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
344
|
+
↓
|
|
345
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
346
|
+
│ 6. COMPLETE (task_complete) │
|
|
347
|
+
│ - Mark task as completed (progress=100%, status=completed) │
|
|
348
|
+
│ - Verify all goals_and_expected_deliverables are met │
|
|
349
|
+
│ - Create completion operation record │
|
|
350
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
351
|
+
\`\`\`
|
|
352
|
+
|
|
353
|
+
### Task Properties
|
|
354
|
+
|
|
355
|
+
| Property | Description |
|
|
356
|
+
|----------|-------------|
|
|
357
|
+
| **title** | Brief task title |
|
|
358
|
+
| **description** | Detailed description of what needs to be done |
|
|
359
|
+
| **goals_and_expected_deliverables** | Clear success criteria and expected outputs |
|
|
360
|
+
| **status** | todo → active → completed (or paused, cancelled) |
|
|
361
|
+
| **progress** | 0-100 percentage of completion |
|
|
362
|
+
| **current_status** | Human-readable status describing current work |
|
|
363
|
+
| **priority** | low, medium, high |
|
|
364
|
+
| **parent_task_id** | Parent task ID (if this is a sub-task) |
|
|
365
|
+
|
|
366
|
+
### Task Context Awareness
|
|
367
|
+
|
|
368
|
+
**Before starting any task-related work, you MUST gather context:**
|
|
369
|
+
|
|
370
|
+
1. **Read task details**: Use \`task_get\` to read description, goals, status
|
|
371
|
+
2. **Read operation history**: Use \`task_operation_list\` to get the last ~20 operation records
|
|
372
|
+
3. **Read parent context** (if \`parent_task_id\` exists): Understand overall goal
|
|
373
|
+
|
|
374
|
+
**Why context matters**: Without it, you risk:
|
|
375
|
+
- Working on outdated or wrong goals
|
|
376
|
+
- Missing critical decisions made in operations
|
|
377
|
+
- Losing parent task alignment
|
|
378
|
+
- Duplicating or conflicting work
|
|
379
|
+
|
|
380
|
+
### {{memory}}`,
|
|
381
|
+
coding: `You are an expert coding assistant.
|
|
382
|
+
|
|
383
|
+
## Your Approach
|
|
384
|
+
|
|
385
|
+
1. **Understand first**: Make sure you understand the user's requirements before writing code
|
|
386
|
+
2. **Best practices**: Follow language-specific best practices and coding standards
|
|
387
|
+
3. **Readable code**: Write clean, readable, and maintainable code
|
|
388
|
+
4. **Error handling**: Always consider error cases and handle them appropriately
|
|
389
|
+
5. **Testing**: Write tests when appropriate to verify correctness
|
|
390
|
+
|
|
391
|
+
## Code Generation Guidelines
|
|
392
|
+
|
|
393
|
+
- Use clear variable and function names
|
|
394
|
+
- Add comments for complex logic
|
|
395
|
+
- Follow the existing code style in the project
|
|
396
|
+
- Consider performance implications
|
|
397
|
+
- Think about edge cases`,
|
|
398
|
+
review: `You are a code review expert.
|
|
399
|
+
|
|
400
|
+
## Review Focus Areas
|
|
401
|
+
|
|
402
|
+
1. **Correctness**: Does the code do what it's supposed to do?
|
|
403
|
+
2. **Security**: Are there any security vulnerabilities?
|
|
404
|
+
3. **Performance**: Could the code be more efficient?
|
|
405
|
+
4. **Readability**: Is the code easy to understand and maintain?
|
|
406
|
+
5. **Testing**: Are there adequate tests?
|
|
407
|
+
|
|
408
|
+
## Feedback Style
|
|
409
|
+
|
|
410
|
+
- Be specific and actionable
|
|
411
|
+
- Explain why something is a problem
|
|
412
|
+
- Suggest improvements with examples
|
|
413
|
+
- Acknowledge good practices`,
|
|
414
|
+
"project-memory": `# 角色
|
|
415
|
+
你是一个项目记忆管理专家,负责从会话历史中提炼项目的关键知识。
|
|
416
|
+
|
|
417
|
+
# 你的职责
|
|
418
|
+
1. **信息收集**:在提炼记忆前,先收集项目上下文信息(重要!)
|
|
419
|
+
2. **提炼项目知识**:从对话中提取技术栈、架构、设计决策
|
|
420
|
+
3. **抽象规范**:将具体的指令和反馈提炼成通用规则
|
|
421
|
+
4. **保持一致性**:确保新旧知识不冲突,冲突时整合最优方案
|
|
422
|
+
5. **主动遗忘**:标记或移除过时、不再适用的信息
|
|
423
|
+
|
|
424
|
+
# 项目记忆内容类型
|
|
425
|
+
- 项目简介:项目是什么、解决什么问题
|
|
426
|
+
- 技术栈:框架、语言、数据库、中间件等
|
|
427
|
+
- 架构设计:目录结构、模块划分、核心组件
|
|
428
|
+
- 开发规范:命名规范、代码风格、提交规范、PR 规范
|
|
429
|
+
- 工作流程:开发流程、测试要求、部署流程
|
|
430
|
+
- 约定俗成:团队共识、非文档化的惯例
|
|
431
|
+
- 已知约束:性能要求、兼容性要求、安全考虑
|
|
432
|
+
|
|
433
|
+
# 提炼原则
|
|
434
|
+
1. **具体→抽象**:将具体指令"这里要用下划线" → "命名: snake_case"
|
|
435
|
+
2. **保留上下文**:保留为什么的答案,不只是是什么
|
|
436
|
+
3. **可执行性**:规则要具体可执行,不要模糊描述
|
|
437
|
+
4. **优先级**:重要的放前面,细节放后面
|
|
438
|
+
|
|
439
|
+
# 信息收集步骤(必须执行!)
|
|
440
|
+
|
|
441
|
+
在提炼项目记忆之前,**必须先收集项目上下文**:
|
|
442
|
+
|
|
443
|
+
1. **阅读项目 README**
|
|
444
|
+
- 使用 \`glob("README*.md")\` 查找 README 文件
|
|
445
|
+
- 使用 \`read_file("README.md")\` 阅读项目说明
|
|
446
|
+
- 了解项目概述、功能定位、使用方法
|
|
447
|
+
|
|
448
|
+
2. **检查设计文档**
|
|
449
|
+
- 使用 \`glob("docs/**/*.md")\` 查找设计文档
|
|
450
|
+
- 使用 \`read_file()\` 阅读架构设计、SPEC 等文档
|
|
451
|
+
- 了解设计决策及其理由
|
|
452
|
+
|
|
453
|
+
3. **查看代码实现**
|
|
454
|
+
- 使用 \`glob("**/package.json")\` 了解项目依赖和技术栈
|
|
455
|
+
- 使用 \`glob("**/*.ts")\` 或 \`glob("**/*.tsx")\` 了解代码结构
|
|
456
|
+
- 使用 \`bash("ls -la src/")\` 或 \`bash("ls -la packages/")\` 查看目录结构
|
|
457
|
+
|
|
458
|
+
4. **回顾现有项目记忆**
|
|
459
|
+
- 已有记忆路径:\`{CURRENT_MEMORY}\` 中的内容
|
|
460
|
+
- 了解已有的项目记忆,避免重复记录
|
|
461
|
+
|
|
462
|
+
5. **搜索会话历史(可选)**
|
|
463
|
+
- 使用 \`search_sessions("项目 技术栈 架构")\` 搜索相关会话
|
|
464
|
+
- 使用 \`get_session(session_id)\` 获取感兴趣的会话详情
|
|
465
|
+
|
|
466
|
+
# 用户指导
|
|
467
|
+
{USER_REQUIREMENT}
|
|
468
|
+
|
|
469
|
+
# 作用域
|
|
470
|
+
{SCOPE}
|
|
471
|
+
|
|
472
|
+
# 现有项目记忆
|
|
473
|
+
{CURRENT_MEMORY}
|
|
474
|
+
|
|
475
|
+
# 可用工具
|
|
476
|
+
- search_sessions(query, session_id?, limit?): 搜索会话历史
|
|
477
|
+
- get_session(session_id): 获取指定会话
|
|
478
|
+
- record_memory({ scope, mode, content, title }): 写入记忆文件
|
|
479
|
+
- glob(pattern, cwd?): 查找匹配的文件
|
|
480
|
+
- bash(command, workdir?): 执行命令
|
|
481
|
+
- read_file(path, offset?, limit?): 读取文件内容
|
|
482
|
+
|
|
483
|
+
# 执行流程
|
|
484
|
+
1. **收集项目信息**(必须步骤)
|
|
485
|
+
- 使用 glob + read_file 阅读 README.md、设计文档
|
|
486
|
+
- 使用 bash + glob 了解代码结构和依赖
|
|
487
|
+
- 回顾现有项目记忆
|
|
488
|
+
|
|
489
|
+
2. 理解现有项目记忆
|
|
490
|
+
3. 根据用户指导确定提炼重点
|
|
491
|
+
4. 分析提炼新知识
|
|
492
|
+
5. 整合新旧知识,生成完整的项目记忆
|
|
493
|
+
6. 使用 record_memory({ scope: "project", mode: "overwrite", content, title }) 写入
|
|
494
|
+
|
|
495
|
+
# 输出要求
|
|
496
|
+
直接调用 record_memory 工具,写入新的项目记忆。
|
|
497
|
+
输出格式为 Markdown,保持结构清晰。`,
|
|
498
|
+
"global-memory": `# 角色
|
|
499
|
+
你是一个全局记忆管理专家,负责提炼跨项目的通用知识和用户偏好。
|
|
500
|
+
|
|
501
|
+
# 你的职责
|
|
502
|
+
1. **用户画像**:提炼用户的沟通风格、技术偏好、工作习惯
|
|
503
|
+
2. **目标追踪**:记录用户的长期目标、当前任务、进度
|
|
504
|
+
3. **通用规则**:提炼跨项目都适用的行为规范
|
|
505
|
+
4. **遗忘处理**:标记或移除不再相关的目标和信息
|
|
506
|
+
|
|
507
|
+
# 全局记忆内容类型
|
|
508
|
+
- 用户偏好:沟通风格(简洁/详细)、反馈偏好、决策风格
|
|
509
|
+
- 技术倾向:偏好的技术栈、框架、语言、开发工具
|
|
510
|
+
- 工作习惯:工作时间、专注周期、偏好时段
|
|
511
|
+
- 当前目标:正在进行的事项、短期目标(1-3月)
|
|
512
|
+
- 长期愿景:大方向、战略目标、人生阶段
|
|
513
|
+
- 跨项目规范:所有项目都遵循的通用规则
|
|
514
|
+
|
|
515
|
+
# 提炼原则
|
|
516
|
+
1. **以用户为中心**:关注用户怎么说、怎么想,不只是做什么
|
|
517
|
+
2. **目标导向**:区分已完成、进行中、计划中
|
|
518
|
+
3. **可操作性**:偏好要具体,如"用户喜欢先看结论"而非"用户很忙"
|
|
519
|
+
4. **时间敏感**:标记有时间限制的目标
|
|
520
|
+
|
|
521
|
+
# 用户指导
|
|
522
|
+
{USER_REQUIREMENT}
|
|
523
|
+
|
|
524
|
+
# 作用域
|
|
525
|
+
{SCOPE}
|
|
526
|
+
|
|
527
|
+
# 现有全局记忆
|
|
528
|
+
{CURRENT_MEMORY}
|
|
529
|
+
|
|
530
|
+
# 可用工具
|
|
531
|
+
- search_sessions(query, session_id?, limit?): 搜索会话历史
|
|
532
|
+
- get_session(session_id): 获取指定会话
|
|
533
|
+
- record_memory({ scope, mode, content, title }): 写入记忆文件
|
|
534
|
+
|
|
535
|
+
# 执行流程
|
|
536
|
+
1. 理解现有全局记忆
|
|
537
|
+
2. 根据用户指导确定提炼重点
|
|
538
|
+
3. 使用工具搜索相关会话历史
|
|
539
|
+
4. 分析提炼新知识
|
|
540
|
+
5. 整合新旧知识,生成完整的全局记忆
|
|
541
|
+
6. 使用 record_memory({ scope: "global", mode: "overwrite", content, title }) 写入
|
|
542
|
+
|
|
543
|
+
# 输出要求
|
|
544
|
+
直接调用 record_memory 工具,写入新的全局记忆。
|
|
545
|
+
输出格式为 Markdown,保持结构清晰。`
|
|
546
|
+
};
|
|
547
|
+
function getBuiltInPromptNames() {
|
|
548
|
+
return Object.keys(builtInPrompts);
|
|
549
|
+
}
|
|
550
|
+
function getBuiltInPrompt(name) {
|
|
551
|
+
return builtInPrompts[name];
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// src/env/prompt/prompt-component.ts
|
|
555
|
+
init_logger();
|
|
556
|
+
import { readFile, readdir } from "fs/promises";
|
|
557
|
+
import { join, basename, extname } from "path";
|
|
558
|
+
|
|
559
|
+
// src/env/prompt/prompt-config-registration.ts
|
|
560
|
+
var PROMPT_DEFAULTS = {
|
|
561
|
+
"prompt.defaultName": "default",
|
|
562
|
+
"prompt.variablePrefix": "{{",
|
|
563
|
+
"prompt.variableSuffix": "}}"
|
|
564
|
+
};
|
|
565
|
+
var PROMPT_CONFIG_REGISTRATION = {
|
|
566
|
+
name: "prompt",
|
|
567
|
+
sources: [
|
|
568
|
+
{ type: "env", envPrefix: "PROMPT", priority: 20, watch: false }
|
|
569
|
+
],
|
|
570
|
+
keys: [
|
|
571
|
+
{ key: "prompt.promptPaths", sources: ["env", "file"] },
|
|
572
|
+
{ key: "prompt.defaultName", sources: ["env", "file"] },
|
|
573
|
+
{ key: "prompt.variablePrefix", sources: ["env", "file"] },
|
|
574
|
+
{ key: "prompt.variableSuffix", sources: ["env", "file"] }
|
|
575
|
+
]
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
// src/env/prompt/prompt-component.ts
|
|
579
|
+
var logger = createLogger("prompt");
|
|
580
|
+
|
|
581
|
+
class PromptComponent extends BaseComponent {
|
|
582
|
+
name = "prompt";
|
|
583
|
+
version = "1.0.0";
|
|
584
|
+
prompts = new Map;
|
|
585
|
+
config;
|
|
586
|
+
configComponent;
|
|
587
|
+
renderer;
|
|
588
|
+
configWatcher;
|
|
589
|
+
constructor() {
|
|
590
|
+
super();
|
|
591
|
+
}
|
|
592
|
+
async init(config) {
|
|
593
|
+
await super.init(config);
|
|
594
|
+
const options = config.options;
|
|
595
|
+
if (!options?.configComponent) {
|
|
596
|
+
throw new Error("ConfigComponent is required for PromptComponent initialization");
|
|
597
|
+
}
|
|
598
|
+
this.configComponent = options.configComponent;
|
|
599
|
+
await this.registerConfig(options);
|
|
600
|
+
this.initRenderer();
|
|
601
|
+
await this.loadPrompts();
|
|
602
|
+
this.setStatus("running");
|
|
603
|
+
logger.info(`[PromptComponent] Initialized with ${this.prompts.size} prompts`);
|
|
604
|
+
}
|
|
605
|
+
async registerConfig(options) {
|
|
606
|
+
const configComponent = options.configComponent;
|
|
607
|
+
if (!configComponent)
|
|
608
|
+
return;
|
|
609
|
+
const { config, defaultName, promptPaths, variablePrefix, variableSuffix } = options;
|
|
610
|
+
configComponent.registerComponent(PROMPT_CONFIG_REGISTRATION);
|
|
611
|
+
await configComponent.load("prompt");
|
|
612
|
+
const prefix = "PROMPT";
|
|
613
|
+
const promptKeys = [
|
|
614
|
+
"prompt.defaultName",
|
|
615
|
+
"prompt.promptPaths",
|
|
616
|
+
"prompt.variablePrefix",
|
|
617
|
+
"prompt.variableSuffix",
|
|
618
|
+
"prompt.strictMode"
|
|
619
|
+
];
|
|
620
|
+
for (const key of promptKeys) {
|
|
621
|
+
const envKey = toEnvKey(key, prefix);
|
|
622
|
+
const value = process.env[envKey];
|
|
623
|
+
if (value !== undefined) {
|
|
624
|
+
await configComponent.set(key, value);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
const loadedKeys = new Set(promptKeys);
|
|
628
|
+
for (const envKey of Object.keys(process.env)) {
|
|
629
|
+
const configKey = envKeyToConfigKey(envKey, prefix, "prompt");
|
|
630
|
+
if (!configKey)
|
|
631
|
+
continue;
|
|
632
|
+
if (loadedKeys.has(configKey))
|
|
633
|
+
continue;
|
|
634
|
+
loadedKeys.add(configKey);
|
|
635
|
+
const value = process.env[envKey];
|
|
636
|
+
if (value !== undefined) {
|
|
637
|
+
await configComponent.set(configKey, value);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
for (const [key, value] of Object.entries(PROMPT_DEFAULTS)) {
|
|
641
|
+
if (configComponent.get(key) === undefined) {
|
|
642
|
+
await configComponent.set(key, value);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (config) {
|
|
646
|
+
const flatConfig = this.flattenConfig(config);
|
|
647
|
+
for (const [key, value] of Object.entries(flatConfig)) {
|
|
648
|
+
await configComponent.set(key, value);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
if (defaultName !== undefined) {
|
|
652
|
+
await configComponent.set("prompt.defaultName", defaultName);
|
|
653
|
+
}
|
|
654
|
+
if (promptPaths !== undefined) {
|
|
655
|
+
await configComponent.set("prompt.promptPaths", promptPaths);
|
|
656
|
+
}
|
|
657
|
+
if (variablePrefix !== undefined) {
|
|
658
|
+
await configComponent.set("prompt.variablePrefix", variablePrefix);
|
|
659
|
+
}
|
|
660
|
+
if (variableSuffix !== undefined) {
|
|
661
|
+
await configComponent.set("prompt.variableSuffix", variableSuffix);
|
|
662
|
+
}
|
|
663
|
+
this.registerConfigWatcher(configComponent);
|
|
664
|
+
this.config = {
|
|
665
|
+
defaultName: configComponent.get("prompt.defaultName") || "default",
|
|
666
|
+
promptPaths: configComponent.get("prompt.promptPaths") || [],
|
|
667
|
+
variablePrefix: configComponent.get("prompt.variablePrefix") || "{{",
|
|
668
|
+
variableSuffix: configComponent.get("prompt.variableSuffix") || "}}",
|
|
669
|
+
strictMode: configComponent.get("prompt.strictMode") || false
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
flattenConfig(obj, prefix = "prompt") {
|
|
673
|
+
const result = {};
|
|
674
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
675
|
+
const fullKey = `${prefix}.${key}`;
|
|
676
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
677
|
+
Object.assign(result, this.flattenConfig(value, fullKey));
|
|
678
|
+
} else {
|
|
679
|
+
result[fullKey] = value;
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
return result;
|
|
683
|
+
}
|
|
684
|
+
registerConfigWatcher(configComponent) {
|
|
685
|
+
if (typeof configComponent.watch !== "function") {
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
this.configWatcher = configComponent.watch("prompt.*", (event) => {
|
|
689
|
+
this.onConfigChange(event);
|
|
690
|
+
});
|
|
691
|
+
}
|
|
692
|
+
onConfigChange(event) {
|
|
693
|
+
const key = event.key;
|
|
694
|
+
const value = event.newValue;
|
|
695
|
+
if (value === undefined)
|
|
696
|
+
return;
|
|
697
|
+
logger.debug(`[PromptComponent] Config updated: ${key} = ${JSON.stringify(value)}`);
|
|
698
|
+
switch (key) {
|
|
699
|
+
case "prompt.defaultName":
|
|
700
|
+
if (this.config)
|
|
701
|
+
this.config.defaultName = value;
|
|
702
|
+
break;
|
|
703
|
+
case "prompt.promptPaths":
|
|
704
|
+
if (this.config)
|
|
705
|
+
this.config.promptPaths = value;
|
|
706
|
+
break;
|
|
707
|
+
case "prompt.variablePrefix":
|
|
708
|
+
if (this.config) {
|
|
709
|
+
this.config.variablePrefix = value;
|
|
710
|
+
this.initRenderer();
|
|
711
|
+
}
|
|
712
|
+
break;
|
|
713
|
+
case "prompt.variableSuffix":
|
|
714
|
+
if (this.config) {
|
|
715
|
+
this.config.variableSuffix = value;
|
|
716
|
+
this.initRenderer();
|
|
717
|
+
}
|
|
718
|
+
break;
|
|
719
|
+
case "prompt.strictMode":
|
|
720
|
+
if (this.config)
|
|
721
|
+
this.config.strictMode = value;
|
|
722
|
+
break;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
initRenderer() {
|
|
726
|
+
const config = this.config || {
|
|
727
|
+
defaultName: "default",
|
|
728
|
+
promptPaths: [],
|
|
729
|
+
variablePrefix: "{{",
|
|
730
|
+
variableSuffix: "}}",
|
|
731
|
+
strictMode: false
|
|
732
|
+
};
|
|
733
|
+
this.renderer = new PromptRenderer({
|
|
734
|
+
prefix: config.variablePrefix,
|
|
735
|
+
suffix: config.variableSuffix,
|
|
736
|
+
strict: config.strictMode,
|
|
737
|
+
onMissingVariable: (name) => {
|
|
738
|
+
logger.warn(`Undefined variable: ${name}`);
|
|
739
|
+
return `{{${name}}}`;
|
|
740
|
+
}
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
async onStart() {
|
|
744
|
+
logger.info("[PromptComponent] Started");
|
|
745
|
+
}
|
|
746
|
+
async onStop() {
|
|
747
|
+
this.prompts.clear();
|
|
748
|
+
this.setStatus("stopped");
|
|
749
|
+
logger.info("[PromptComponent] Stopped");
|
|
750
|
+
}
|
|
751
|
+
getPromptConfig(key, defaultValue) {
|
|
752
|
+
if (this.config && key in this.config) {
|
|
753
|
+
return this.config[key] ?? defaultValue;
|
|
754
|
+
}
|
|
755
|
+
return defaultValue;
|
|
756
|
+
}
|
|
757
|
+
add(name, content, source = "inline") {
|
|
758
|
+
const entry = {
|
|
759
|
+
name,
|
|
760
|
+
content,
|
|
761
|
+
source,
|
|
762
|
+
overridable: true,
|
|
763
|
+
loadedAt: Date.now()
|
|
764
|
+
};
|
|
765
|
+
const existing = this.prompts.get(name);
|
|
766
|
+
if (existing && !existing.overridable) {
|
|
767
|
+
logger.debug(`[PromptComponent] Skip override for non-overridable prompt: ${name}`);
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
this.prompts.set(name, entry);
|
|
771
|
+
logger.debug(`[PromptComponent] Added prompt: ${name} (${source})`);
|
|
772
|
+
}
|
|
773
|
+
get(name) {
|
|
774
|
+
return this.prompts.get(name)?.content;
|
|
775
|
+
}
|
|
776
|
+
getEntry(name) {
|
|
777
|
+
return this.prompts.get(name);
|
|
778
|
+
}
|
|
779
|
+
has(name) {
|
|
780
|
+
return this.prompts.has(name);
|
|
781
|
+
}
|
|
782
|
+
delete(name) {
|
|
783
|
+
return this.prompts.delete(name);
|
|
784
|
+
}
|
|
785
|
+
list() {
|
|
786
|
+
return Array.from(this.prompts.keys());
|
|
787
|
+
}
|
|
788
|
+
size() {
|
|
789
|
+
return this.prompts.size;
|
|
790
|
+
}
|
|
791
|
+
async getPrompt(name, variables = {}) {
|
|
792
|
+
const defaultName = this.getPromptConfig("defaultName", "default");
|
|
793
|
+
const targetName = this.has(name) ? name : defaultName;
|
|
794
|
+
const entry = this.prompts.get(targetName);
|
|
795
|
+
if (!entry) {
|
|
796
|
+
logger.warn(`[PromptComponent] Prompt not found: ${name}, using fallback`);
|
|
797
|
+
return "You are a helpful assistant.";
|
|
798
|
+
}
|
|
799
|
+
return this.render(entry.content, variables, { name: targetName });
|
|
800
|
+
}
|
|
801
|
+
async render(content, variables = {}, context) {
|
|
802
|
+
const hookContext = {
|
|
803
|
+
name: context?.name || "anonymous",
|
|
804
|
+
originalContent: content,
|
|
805
|
+
renderedContent: content,
|
|
806
|
+
variables
|
|
807
|
+
};
|
|
808
|
+
await this.executeHooks(PromptHookPoints.BEFORE_RENDER, hookContext);
|
|
809
|
+
hookContext.renderedContent = this.renderer.render(hookContext.originalContent, variables);
|
|
810
|
+
await this.executeHooks(PromptHookPoints.AFTER_RENDER, hookContext);
|
|
811
|
+
return hookContext.renderedContent;
|
|
812
|
+
}
|
|
813
|
+
extractVariables(content) {
|
|
814
|
+
return this.renderer.extractVariables(content);
|
|
815
|
+
}
|
|
816
|
+
async loadPrompts() {
|
|
817
|
+
await this.loadBuiltInPrompts();
|
|
818
|
+
await this.loadExternalPrompts();
|
|
819
|
+
}
|
|
820
|
+
async loadBuiltInPrompts() {
|
|
821
|
+
for (const [name, content] of Object.entries(builtInPrompts)) {
|
|
822
|
+
if (content) {
|
|
823
|
+
this.prompts.set(name, {
|
|
824
|
+
name,
|
|
825
|
+
content,
|
|
826
|
+
source: "built-in",
|
|
827
|
+
overridable: false,
|
|
828
|
+
loadedAt: Date.now()
|
|
829
|
+
});
|
|
830
|
+
logger.debug(`[PromptComponent] Loaded built-in prompt: ${name}`);
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
logger.info(`[PromptComponent] Loaded ${this.prompts.size} built-in prompts`);
|
|
834
|
+
}
|
|
835
|
+
async loadExternalPrompts() {
|
|
836
|
+
const promptPaths = this.getPromptConfig("promptPaths", []);
|
|
837
|
+
for (const pathConfig of promptPaths) {
|
|
838
|
+
try {
|
|
839
|
+
if (pathConfig.type === "file") {
|
|
840
|
+
await this.loadFromFile(pathConfig.path, pathConfig.name);
|
|
841
|
+
} else if (pathConfig.type === "directory") {
|
|
842
|
+
await this.loadFromDirectory(pathConfig.path, pathConfig.extension || ".md", pathConfig.recursive !== false);
|
|
843
|
+
}
|
|
844
|
+
} catch (error) {
|
|
845
|
+
logger.error(`[PromptComponent] Failed to load from ${pathConfig.path}:`, error);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
async loadFromFile(filePath, name) {
|
|
850
|
+
try {
|
|
851
|
+
const content = await readFile(filePath, "utf-8");
|
|
852
|
+
const promptName = name || basename(filePath, extname(filePath));
|
|
853
|
+
this.add(promptName, content.trim(), "file");
|
|
854
|
+
const entry = this.prompts.get(promptName);
|
|
855
|
+
if (entry)
|
|
856
|
+
entry.filePath = filePath;
|
|
857
|
+
logger.debug(`[PromptComponent] Loaded prompt from file: ${filePath}`);
|
|
858
|
+
return true;
|
|
859
|
+
} catch (error) {
|
|
860
|
+
logger.error(`[PromptComponent] Failed to load file ${filePath}:`, error);
|
|
861
|
+
return false;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
async loadFromDirectory(directory, extension = ".md", recursive = true) {
|
|
865
|
+
let loaded = 0;
|
|
866
|
+
try {
|
|
867
|
+
const files = await this.findFiles(directory, extension, recursive);
|
|
868
|
+
for (const filePath of files) {
|
|
869
|
+
const relativePath = filePath.replace(directory + "/", "");
|
|
870
|
+
const promptName = relativePath.replace(/\\/g, "/").replace(new RegExp(escapeRegex2(extension) + "$"), "").replace(/\//g, "-");
|
|
871
|
+
const content = await readFile(filePath, "utf-8");
|
|
872
|
+
this.add(promptName, content.trim(), "directory");
|
|
873
|
+
const entry = this.prompts.get(promptName);
|
|
874
|
+
if (entry)
|
|
875
|
+
entry.filePath = filePath;
|
|
876
|
+
loaded++;
|
|
877
|
+
}
|
|
878
|
+
logger.info(`[PromptComponent] Loaded ${loaded} prompts from directory: ${directory}`);
|
|
879
|
+
} catch (error) {
|
|
880
|
+
logger.error(`[PromptComponent] Failed to load directory ${directory}:`, error);
|
|
881
|
+
}
|
|
882
|
+
return loaded;
|
|
883
|
+
}
|
|
884
|
+
async findFiles(dir, extension, recursive) {
|
|
885
|
+
const files = [];
|
|
886
|
+
try {
|
|
887
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
888
|
+
for (const entry of entries) {
|
|
889
|
+
const fullPath = join(dir, entry.name);
|
|
890
|
+
if (entry.isDirectory() && recursive) {
|
|
891
|
+
const subFiles = await this.findFiles(fullPath, extension, true);
|
|
892
|
+
files.push(...subFiles);
|
|
893
|
+
} else if (entry.isFile() && entry.name.endsWith(extension)) {
|
|
894
|
+
files.push(fullPath);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
} catch (error) {
|
|
898
|
+
logger.warn(`[PromptComponent] Cannot read directory ${dir}:`, error);
|
|
899
|
+
}
|
|
900
|
+
return files;
|
|
901
|
+
}
|
|
902
|
+
registerPromptHook(hookPoint, name, fn, priority) {
|
|
903
|
+
this.addHook(hookPoint, name, fn, priority);
|
|
904
|
+
}
|
|
905
|
+
getHookPoints() {
|
|
906
|
+
return [PromptHookPoints.BEFORE_RENDER, PromptHookPoints.AFTER_RENDER];
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
function escapeRegex2(str) {
|
|
910
|
+
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
export { PromptPathSchema, PromptConfigSchema, PromptRenderer, getBuiltInPromptNames, getBuiltInPrompt, PromptComponent };
|