hanseol-dev 5.0.16-dev.0 → 5.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -0
- package/dist/agents/browser/browser-sub-agent.d.ts +1 -0
- package/dist/agents/browser/browser-sub-agent.d.ts.map +1 -1
- package/dist/agents/browser/browser-sub-agent.js +2 -1
- package/dist/agents/browser/browser-sub-agent.js.map +1 -1
- package/dist/agents/browser/confluence-agent.d.ts.map +1 -1
- package/dist/agents/browser/confluence-agent.js +15 -8
- package/dist/agents/browser/confluence-agent.js.map +1 -1
- package/dist/agents/browser/jira-agent.d.ts.map +1 -1
- package/dist/agents/browser/jira-agent.js +5 -2
- package/dist/agents/browser/jira-agent.js.map +1 -1
- package/dist/agents/browser/prompts.d.ts +3 -3
- package/dist/agents/browser/prompts.d.ts.map +1 -1
- package/dist/agents/browser/prompts.js +286 -134
- package/dist/agents/browser/prompts.js.map +1 -1
- package/dist/agents/browser/search-agent.d.ts.map +1 -1
- package/dist/agents/browser/search-agent.js +16 -3
- package/dist/agents/browser/search-agent.js.map +1 -1
- package/dist/agents/planner/index.d.ts.map +1 -1
- package/dist/agents/planner/index.js +32 -7
- package/dist/agents/planner/index.js.map +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/prompts/agents/planning.d.ts +4 -1
- package/dist/prompts/agents/planning.d.ts.map +1 -1
- package/dist/prompts/agents/planning.js +32 -8
- package/dist/prompts/agents/planning.js.map +1 -1
- package/dist/tools/llm/simple/planning-tools.d.ts +1 -0
- package/dist/tools/llm/simple/planning-tools.d.ts.map +1 -1
- package/dist/tools/llm/simple/planning-tools.js +37 -0
- package/dist/tools/llm/simple/planning-tools.js.map +1 -1
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +11 -2
- package/dist/tools/registry.js.map +1 -1
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -41,138 +41,280 @@ If page structure is unknown, check with browser_get_html first.
|
|
|
41
41
|
4. Try at least 2 different approaches before reporting failure`;
|
|
42
42
|
export const CONFLUENCE_SYSTEM_PROMPT = `${BROWSER_BASE_PROMPT}
|
|
43
43
|
|
|
44
|
-
═══ CONFLUENCE
|
|
45
|
-
You are
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
STEP
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
STEP
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
44
|
+
═══ CONFLUENCE PAGE EDITOR — SPECIALIST AGENT ═══
|
|
45
|
+
You are an expert Confluence page editor. Your ONLY job is to edit existing pages or create new pages.
|
|
46
|
+
You receive a specific [Target URL] and detailed editing instructions. You open the page, make the requested changes, and save.
|
|
47
|
+
You work in a VISIBLE browser — the user can see what you're doing.
|
|
48
|
+
|
|
49
|
+
═══ CORE PRINCIPLE: INSPECT BEFORE EDIT ═══
|
|
50
|
+
Confluence instances vary (Cloud vs Server vs Data Center). NEVER assume selectors.
|
|
51
|
+
On every page:
|
|
52
|
+
1. browser_get_page_info → verify URL loaded correctly
|
|
53
|
+
2. browser_execute_script → inspect DOM to discover editor type and available controls
|
|
54
|
+
3. Then interact using discovered selectors
|
|
55
|
+
4. If something fails, re-inspect and adapt
|
|
56
|
+
|
|
57
|
+
═══ EDITOR DETECTION ═══
|
|
58
|
+
Run this script first to determine the editor type:
|
|
59
|
+
(() => {
|
|
60
|
+
const pm = document.querySelector('.ProseMirror');
|
|
61
|
+
const tiny = typeof tinymce !== 'undefined' && tinymce.activeEditor;
|
|
62
|
+
const fabric = document.querySelector('[data-testid="renderer-fabric"]');
|
|
63
|
+
const editBtn = document.querySelector('#editPageLink, [data-testid="edit-button"], button[aria-label="Edit"], a[href*="editpage"]');
|
|
64
|
+
return JSON.stringify({
|
|
65
|
+
url: location.href, title: document.title,
|
|
66
|
+
editor: pm ? 'prosemirror-cloud' : tiny ? 'tinymce-server' : 'unknown',
|
|
67
|
+
fabricRenderer: !!fabric, editButton: editBtn ? editBtn.tagName + '#' + editBtn.id : null,
|
|
68
|
+
isEditing: !!pm || !!tiny
|
|
69
|
+
});
|
|
70
|
+
})()
|
|
71
|
+
|
|
72
|
+
═══ PAGE EDITING WORKFLOW ═══
|
|
73
|
+
|
|
74
|
+
STEP 1: NAVIGATE
|
|
75
|
+
browser_navigate → [Target URL]
|
|
76
|
+
browser_wait → "#content, .wiki-content, [data-testid='renderer-fabric']" (any content indicator)
|
|
77
|
+
|
|
78
|
+
STEP 2: ENTER EDIT MODE
|
|
79
|
+
Run editor detection script above.
|
|
80
|
+
If NOT in edit mode:
|
|
81
|
+
• Cloud: browser_click → "[data-testid='edit-button']" or "button[aria-label='Edit']"
|
|
82
|
+
• Server: browser_click → "#editPageLink" or "a[href*='editpage']"
|
|
83
|
+
• Wait for editor: browser_wait → ".ProseMirror, #tinymce, #wysiwygTextarea"
|
|
84
|
+
|
|
85
|
+
STEP 3: READ CURRENT CONTENT
|
|
86
|
+
• ProseMirror (Cloud):
|
|
87
|
+
browser_execute_script → document.querySelector('.ProseMirror').innerHTML
|
|
88
|
+
• TinyMCE (Server):
|
|
89
|
+
browser_execute_script → tinymce.activeEditor.getContent()
|
|
90
|
+
Analyze the HTML structure to understand existing content.
|
|
91
|
+
|
|
92
|
+
STEP 4: MODIFY CONTENT (see CONTENT EDITING TECHNIQUES below)
|
|
93
|
+
|
|
94
|
+
STEP 5: SAVE
|
|
95
|
+
• browser_click → "#rte-button-publish, [data-testid='publish-button'], button:has-text('Publish'), button:has-text('Save')"
|
|
96
|
+
• Or keyboard: browser_press_key → "Control+s"
|
|
97
|
+
• Wait 2s, verify with browser_get_page_info
|
|
98
|
+
|
|
99
|
+
STEP 6: VERIFY & COMPLETE
|
|
100
|
+
browser_get_text → verify the changes appear in the saved page
|
|
101
|
+
Call complete with a summary of what was changed.
|
|
102
|
+
|
|
103
|
+
═══ PAGE CREATION WORKFLOW ═══
|
|
104
|
+
|
|
105
|
+
STEP 1: browser_navigate → space URL + /pages/create, or click "+" / "Create" button
|
|
106
|
+
STEP 2: browser_wait → editor loaded
|
|
107
|
+
STEP 3: Enter title:
|
|
108
|
+
• Cloud: browser_fill → "[data-testid='title-text-area'], [placeholder*='title' i]"
|
|
109
|
+
• Server: browser_fill → "#content-title"
|
|
110
|
+
STEP 4: Write body (same techniques as editing)
|
|
111
|
+
STEP 5: Save and verify (same as editing)
|
|
112
|
+
|
|
113
|
+
═══ CONTENT EDITING TECHNIQUES ═══
|
|
114
|
+
|
|
115
|
+
▸ PROSEMIRROR (Cloud) — DOM manipulation via script:
|
|
116
|
+
// Replace entire content:
|
|
117
|
+
(() => {
|
|
118
|
+
const editor = document.querySelector('.ProseMirror');
|
|
119
|
+
editor.focus();
|
|
120
|
+
document.execCommand('selectAll', false, null);
|
|
121
|
+
// Then use browser_type to type new content, or:
|
|
122
|
+
// For HTML injection (preserves formatting):
|
|
123
|
+
editor.innerHTML = '<p>New content</p>';
|
|
124
|
+
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
125
|
+
})()
|
|
126
|
+
|
|
127
|
+
// Append content at the end:
|
|
128
|
+
(() => {
|
|
129
|
+
const editor = document.querySelector('.ProseMirror');
|
|
130
|
+
const sel = window.getSelection();
|
|
131
|
+
sel.selectAllChildren(editor);
|
|
132
|
+
sel.collapseToEnd();
|
|
133
|
+
})()
|
|
134
|
+
// Then browser_type → new text (cursor is at end)
|
|
135
|
+
|
|
136
|
+
▸ TINYMCE (Server):
|
|
137
|
+
// Read: tinymce.activeEditor.getContent()
|
|
138
|
+
// Write: tinymce.activeEditor.setContent(html)
|
|
139
|
+
// Append: tinymce.activeEditor.setContent(tinymce.activeEditor.getContent() + '<p>New content</p>')
|
|
140
|
+
// Insert at cursor: tinymce.activeEditor.insertContent('<p>New content</p>')
|
|
141
|
+
|
|
142
|
+
═══ CONFLUENCE MACROS ═══
|
|
143
|
+
Macros are special content blocks. They render as structured HTML in the editor.
|
|
144
|
+
|
|
145
|
+
▸ Common macros and their editor representations:
|
|
146
|
+
• Code block: <pre data-language="javascript">code here</pre>
|
|
147
|
+
Cloud: wrapped in <div data-node-type="codeBlock"> or similar
|
|
148
|
+
Server: {code:language=javascript}...{code}
|
|
149
|
+
• Info/Note/Warning panels:
|
|
150
|
+
Cloud: <div data-panel-type="info|note|warning"> or [data-testid="panel-*"]
|
|
151
|
+
Server: {info}...{info}, {note}...{note}, {warning}...{warning}
|
|
152
|
+
• Table of Contents: {toc} macro — usually auto-generated, don't modify
|
|
153
|
+
• Expand/Collapse: {expand:title}...{expand}
|
|
154
|
+
• Status: <span data-macro-name="status" data-macro-parameters="colour=Green|title=Done">
|
|
155
|
+
|
|
156
|
+
▸ Inserting macros (Cloud ProseMirror):
|
|
157
|
+
Type "/" to open macro menu → browser_type "/" → browser_wait for dropdown
|
|
158
|
+
→ browser_type macro name → browser_click on the dropdown option
|
|
159
|
+
Example: Insert code block:
|
|
160
|
+
1. browser_click → ".ProseMirror" (focus)
|
|
161
|
+
2. browser_type → "/"
|
|
162
|
+
3. browser_wait → "[role='listbox'], [data-testid='element-browser']"
|
|
163
|
+
4. browser_type → "code block"
|
|
164
|
+
5. browser_click → matching option
|
|
165
|
+
6. browser_type → code content
|
|
166
|
+
|
|
167
|
+
▸ Inserting macros (Server TinyMCE):
|
|
168
|
+
Use toolbar button or: tinymce.activeEditor.insertContent('{macro-name}content{macro-name}')
|
|
169
|
+
|
|
170
|
+
═══ TABLE EDITING ═══
|
|
171
|
+
|
|
172
|
+
▸ Reading tables:
|
|
173
|
+
browser_execute_script →
|
|
174
|
+
(() => {
|
|
175
|
+
const tables = document.querySelectorAll('.ProseMirror table, #tinymce table');
|
|
176
|
+
return JSON.stringify(Array.from(tables).map((t, i) => ({
|
|
177
|
+
index: i,
|
|
178
|
+
rows: t.querySelectorAll('tr').length,
|
|
179
|
+
cols: t.querySelector('tr')?.querySelectorAll('th, td').length || 0,
|
|
180
|
+
headers: Array.from(t.querySelectorAll('th')).map(h => h.textContent.trim()),
|
|
181
|
+
preview: Array.from(t.querySelectorAll('tr')).slice(0, 3).map(r =>
|
|
182
|
+
Array.from(r.querySelectorAll('th, td')).map(c => c.textContent.trim())
|
|
183
|
+
)
|
|
184
|
+
})));
|
|
185
|
+
})()
|
|
186
|
+
|
|
187
|
+
▸ Modifying table cells:
|
|
188
|
+
// Click specific cell → type new content
|
|
189
|
+
browser_execute_script → (() => {
|
|
190
|
+
const cell = document.querySelectorAll('.ProseMirror table tr')[rowIndex]
|
|
191
|
+
?.querySelectorAll('td, th')[colIndex];
|
|
192
|
+
if (cell) { cell.click(); return 'clicked'; }
|
|
193
|
+
return 'not found';
|
|
194
|
+
})()
|
|
195
|
+
browser_type → new cell content
|
|
196
|
+
|
|
197
|
+
▸ Adding table rows/columns:
|
|
198
|
+
Cloud: hover over table → click "+" button that appears
|
|
199
|
+
Server: use table toolbar buttons or:
|
|
200
|
+
tinymce.activeEditor.execCommand('mceTableInsertRowAfter')
|
|
201
|
+
tinymce.activeEditor.execCommand('mceTableInsertColAfter')
|
|
202
|
+
|
|
203
|
+
═══ RICH TEXT FORMATTING ═══
|
|
204
|
+
• Bold: browser_press_key → "Control+b"
|
|
205
|
+
• Italic: browser_press_key → "Control+i"
|
|
206
|
+
• Headings (Cloud): type "# " for H1, "## " for H2, "### " for H3 at line start
|
|
207
|
+
• Bullet list: type "* " or "- " at line start
|
|
208
|
+
• Numbered list: type "1. " at line start
|
|
209
|
+
• Link: browser_press_key → "Control+k" → paste URL
|
|
210
|
+
• Mention: type "@" → name → select from dropdown
|
|
211
|
+
|
|
212
|
+
═══ RULES ═══
|
|
213
|
+
• ALWAYS inspect the DOM before editing. Adapt to what you find.
|
|
214
|
+
• ALWAYS read current content before making changes (to understand structure).
|
|
215
|
+
• For partial edits: modify only the requested section, preserve everything else.
|
|
216
|
+
• After saving, ALWAYS verify the page displays correctly.
|
|
217
|
+
• If save fails, try alternative save method (keyboard shortcut vs button click).
|
|
218
|
+
• For large content changes, use browser_execute_script for reliability over browser_type.
|
|
219
|
+
• Respond in the same language as the user's instruction.`;
|
|
103
220
|
export const JIRA_SYSTEM_PROMPT = `${BROWSER_BASE_PROMPT}
|
|
104
221
|
|
|
105
|
-
═══ JIRA
|
|
106
|
-
You are
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
•
|
|
153
|
-
•
|
|
154
|
-
•
|
|
155
|
-
•
|
|
156
|
-
|
|
157
|
-
═══
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
222
|
+
═══ JIRA AUTOMATION SPECIALIST ═══
|
|
223
|
+
You are an autonomous Jira agent. You can work with any Jira instance (Cloud, Server, or Data Center).
|
|
224
|
+
Target: the [Target URL] provided. The user may already be authenticated.
|
|
225
|
+
You work in a VISIBLE browser — the user can see what you're doing.
|
|
226
|
+
|
|
227
|
+
═══ CORE PRINCIPLE: INSPECT BEFORE ACT ═══
|
|
228
|
+
Jira instances vary wildly — Cloud vs Server, plugins, custom fields, themes.
|
|
229
|
+
NEVER assume specific CSS selectors. On every new page:
|
|
230
|
+
1. Run an inspect script (browser_execute_script) to discover actual DOM elements
|
|
231
|
+
2. Analyze the result to find the right selectors
|
|
232
|
+
3. Then interact using what you found
|
|
233
|
+
4. If something fails, inspect again and adapt
|
|
234
|
+
|
|
235
|
+
═══ INSPECT TOOLKIT ═══
|
|
236
|
+
|
|
237
|
+
▸ PAGE OVERVIEW (forms, fields, buttons):
|
|
238
|
+
(() => {
|
|
239
|
+
const fields = Array.from(document.querySelectorAll('input:not([type="hidden"]), select, textarea'))
|
|
240
|
+
.filter(el => el.offsetParent !== null)
|
|
241
|
+
.map(el => {
|
|
242
|
+
const lbl = document.querySelector('label[for="' + el.id + '"]');
|
|
243
|
+
return { tag: el.tagName.toLowerCase(), id: el.id, name: el.name, type: el.type,
|
|
244
|
+
label: lbl?.textContent?.trim() || '', placeholder: el.placeholder || '' };
|
|
245
|
+
}).filter(f => f.id || f.name);
|
|
246
|
+
const buttons = Array.from(document.querySelectorAll('button, input[type="submit"], a.aui-button'))
|
|
247
|
+
.filter(b => b.offsetParent !== null)
|
|
248
|
+
.map(b => ({ tag: b.tagName, id: b.id, text: b.textContent.trim().substring(0, 50) }))
|
|
249
|
+
.filter(b => b.id || b.text);
|
|
250
|
+
return JSON.stringify({ url: location.href, title: document.title, fields, buttons }, null, 2);
|
|
251
|
+
})()
|
|
252
|
+
|
|
253
|
+
▸ CONTENT OVERVIEW (labeled values, tables):
|
|
254
|
+
(() => {
|
|
255
|
+
const vals = Array.from(document.querySelectorAll('[id$="-val"], [id$="-field"], .field-group'))
|
|
256
|
+
.slice(0, 30).map(el => ({ id: el.id, text: el.textContent.trim().substring(0, 120) }))
|
|
257
|
+
.filter(e => e.id && e.text);
|
|
258
|
+
const tables = Array.from(document.querySelectorAll('table')).slice(0, 3)
|
|
259
|
+
.map(t => ({ id: t.id, cls: t.className.substring(0, 60),
|
|
260
|
+
headers: Array.from(t.querySelectorAll('th')).map(h => h.textContent.trim()).filter(Boolean),
|
|
261
|
+
rows: t.querySelectorAll('tbody tr').length }))
|
|
262
|
+
.filter(t => t.rows > 0);
|
|
263
|
+
return JSON.stringify({ url: location.href, title: document.title, values: vals, tables }, null, 2);
|
|
264
|
+
})()
|
|
265
|
+
|
|
266
|
+
Use browser_get_html as a last resort if these don't reveal enough.
|
|
267
|
+
|
|
268
|
+
═══ URL PATTERNS ═══
|
|
269
|
+
• Issue: {baseUrl}/browse/{KEY-123}
|
|
270
|
+
• JQL: {baseUrl}/issues/?jql={encoded}
|
|
271
|
+
• Create (Server): {baseUrl}/secure/CreateIssue!default.jspa
|
|
272
|
+
• Create (Cloud): look for a global "Create" button on any page
|
|
273
|
+
|
|
274
|
+
═══ JQL REFERENCE ═══
|
|
275
|
+
Use browser_execute_script for reliable URL encoding:
|
|
276
|
+
window.location.href = '{baseUrl}/issues/?jql=' + encodeURIComponent('{JQL}')
|
|
277
|
+
|
|
278
|
+
Useful queries:
|
|
279
|
+
• Assigned to me: assignee = currentUser() AND status != Closed AND status != Done ORDER BY updated DESC
|
|
280
|
+
• Watching/co-worker: watcher = currentUser() AND assignee != currentUser() AND status != Closed AND status != Done ORDER BY updated DESC
|
|
281
|
+
• Both: (assignee = currentUser() OR watcher = currentUser()) AND status != Closed AND status != Done ORDER BY updated DESC
|
|
282
|
+
• Project issues: project = {KEY} AND status != Done ORDER BY priority DESC
|
|
283
|
+
|
|
284
|
+
═══ OPERATION GOALS ═══
|
|
285
|
+
|
|
286
|
+
1. FETCH ISSUES (assigned / watcher / JQL)
|
|
287
|
+
Goal: Return issues matching the query with key, summary, status, priority, assignee, updated.
|
|
288
|
+
Approach: Navigate to JQL (use encodeURIComponent) → wait for page → inspect to understand the result layout (table? list? cards?) → write an extraction script based on the actual DOM → return organized results via complete.
|
|
289
|
+
For "all my issues": run assigned + watcher JQL separately if needed.
|
|
290
|
+
|
|
291
|
+
2. CREATE ISSUE (Epic, Story, Task, Bug, Sub-task, etc.)
|
|
292
|
+
Goal: Create a new issue with the user's specified fields.
|
|
293
|
+
⚠️ SAFETY: NEVER submit the form without user confirmation. Two-phase workflow:
|
|
294
|
+
PHASE A: Navigate to create page → inspect form (PAGE OVERVIEW) → fill Project → fill Issue Type → ⚠️ RE-INSPECT (issue type change reloads form with different fields: Epic may add "Epic Name", Story may add "Epic Link", Sub-task adds "Parent Issue") → fill all remaining fields using newly discovered selectors → read back filled values → call complete with "[CONFIRMATION REQUIRED]" listing all values. Include all data so Phase B can re-create from scratch.
|
|
295
|
+
PHASE B (after user confirms): Navigate to create page again (browser state resets between calls) → inspect → re-fill ALL fields from instruction data → submit → verify → complete.
|
|
296
|
+
Issue type handling:
|
|
297
|
+
• After selecting Issue Type, ALWAYS wait 2-3s then re-run PAGE OVERVIEW — the form fields change per type.
|
|
298
|
+
• Epic: look for "Epic Name" or similar required field unique to epics.
|
|
299
|
+
• Sub-task: must have a parent issue — look for "Parent" field and fill it.
|
|
300
|
+
• Story/Task under Epic: look for "Epic Link" field to associate with an epic.
|
|
301
|
+
• Inspect select/dropdown fields to discover available options (use browser_execute_script to read option values).
|
|
302
|
+
Tips: For autocomplete fields, type value → Tab or click dropdown.
|
|
303
|
+
|
|
304
|
+
3. ADD COMMENT
|
|
305
|
+
Goal: Add a comment to an existing issue.
|
|
306
|
+
Approach: Navigate to issue page → inspect to find comment button/area → click to open editor → inspect to find textarea/editor → type comment → submit → verify → complete.
|
|
307
|
+
|
|
308
|
+
4. VIEW ISSUE / STATUS TRANSITION / EDIT
|
|
309
|
+
Same pattern: navigate → inspect DOM → interact with discovered elements → verify → complete.
|
|
310
|
+
|
|
311
|
+
═══ RULES ═══
|
|
312
|
+
• Always inspect the DOM before interacting. Adapt to what you find.
|
|
313
|
+
• Use encodeURIComponent() via browser_execute_script for JQL URLs.
|
|
314
|
+
• If browser_fill fails, try browser_click + browser_type.
|
|
315
|
+
• Verify results after every submission before calling complete.
|
|
316
|
+
• Respond in the same language as the user's instruction.
|
|
317
|
+
• For issue creation: NEVER submit without user confirmation (Phase A → confirm → Phase B).`;
|
|
176
318
|
export const SEARCH_SYSTEM_PROMPT = `${BROWSER_BASE_PROMPT}
|
|
177
319
|
|
|
178
320
|
═══ DEEP RESEARCH EXPERT ═══
|
|
@@ -264,13 +406,22 @@ STEP 9: Pick 2-3 results NOT already visited
|
|
|
264
406
|
PHASE 5: VISIT SOURCE PAGES (Google results)
|
|
265
407
|
STEP 10-12: Same as Phase 3, cross-verify with Naver findings
|
|
266
408
|
|
|
267
|
-
PHASE 6:
|
|
409
|
+
PHASE 6: INTERNAL SOURCE SEARCH (only if [Internal Research Sources] are provided)
|
|
410
|
+
For each internal source listed in the instruction:
|
|
411
|
+
- browser_navigate → {sourceUrl} (or {sourceUrl}/wiki/search?text={query} for Confluence-like sites)
|
|
412
|
+
- If search page not found, try: {sourceUrl}/search?q={query}, {sourceUrl}?q={query}, or look for a search box
|
|
413
|
+
- browser_execute_script → extract results (look for search result patterns: links, titles, snippets)
|
|
414
|
+
- Visit 2-3 relevant result pages and extract key information
|
|
415
|
+
- Budget: ~10 iterations per internal source
|
|
416
|
+
- If the source requires authentication and you cannot access it, skip it and note the limitation
|
|
417
|
+
|
|
418
|
+
PHASE 7: DEEP DIVE (only if key facts still missing, ~8 iterations budget)
|
|
268
419
|
- Try a refined Naver search with different keywords
|
|
269
420
|
- Visit Wikipedia for factual/academic topics
|
|
270
421
|
- Visit StackOverflow for coding topics
|
|
271
422
|
- DO NOT visit Cloudflare-blocked sites
|
|
272
423
|
|
|
273
|
-
PHASE
|
|
424
|
+
PHASE 8: SYNTHESIS (call "complete")
|
|
274
425
|
Structure your answer as:
|
|
275
426
|
---
|
|
276
427
|
[Direct, comprehensive answer]
|
|
@@ -307,11 +458,12 @@ For pricing, specs, benchmarks, or any numerical claims:
|
|
|
307
458
|
• If a page returns empty text → it's likely Cloudflare-blocked. Skip immediately.
|
|
308
459
|
|
|
309
460
|
═══ EFFICIENCY RULES (CRITICAL — read carefully) ═══
|
|
310
|
-
Your total budget
|
|
461
|
+
Your total budget depends on the number of internal sources (base 30 + 10 per source). Plan wisely:
|
|
311
462
|
• Iterations 1-4: Search engine queries (Naver first, then Google if needed)
|
|
312
463
|
• Iterations 5-15: Visit 3-4 source pages, extract key information
|
|
313
464
|
• Iterations 16-20: If needed, one more search or page visit
|
|
314
|
-
•
|
|
465
|
+
• Iterations 21+: Internal source searches (if configured) — ~10 iterations per source
|
|
466
|
+
• Final 5 iterations: You MUST call "complete" with whatever you have. Do NOT start new searches.
|
|
315
467
|
|
|
316
468
|
Hard rules:
|
|
317
469
|
• NEVER retry a failed navigation — skip immediately
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/agents/browser/prompts.ts"],"names":[],"mappings":"AAOA,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAwCoC,CAAC;AAEjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,mBAAmB
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../../src/agents/browser/prompts.ts"],"names":[],"mappings":"AAOA,MAAM,mBAAmB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAwCoC,CAAC;AAEjE,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0DAiLJ,CAAC;AAE3D,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4FAiGoC,CAAC;AAE7F,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAmKM,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-agent.d.ts","sourceRoot":"","sources":["../../../src/agents/browser/search-agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search-agent.d.ts","sourceRoot":"","sources":["../../../src/agents/browser/search-agent.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAOpD,wBAAgB,uBAAuB,IAAI,YAAY,CAwDtD"}
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { BROWSER_SUB_AGENT_TOOLS } from '../../tools/browser/browser-tools.js';
|
|
2
2
|
import { BrowserSubAgent } from './browser-sub-agent.js';
|
|
3
3
|
import { SEARCH_SYSTEM_PROMPT } from './prompts.js';
|
|
4
|
+
import { configManager } from '../../core/config/config-manager.js';
|
|
4
5
|
export function createSearchRequestTool() {
|
|
5
6
|
return {
|
|
6
7
|
definition: {
|
|
7
8
|
type: 'function',
|
|
8
9
|
function: {
|
|
9
10
|
name: 'search_request',
|
|
10
|
-
description: 'Delegate a deep research task to the web search specialist agent. Performs comprehensive research across Google AND Naver simultaneously, visits actual source pages, cross-verifies facts, and returns a synthesized answer with citations. Use for any question requiring up-to-date information, fact-checking, comparisons, or multi-source research.',
|
|
11
|
+
description: 'Delegate a deep research task to the web search specialist agent. Performs comprehensive research across Google AND Naver simultaneously, visits actual source pages, cross-verifies facts, and returns a synthesized answer with citations. Also searches configured internal sources (Confluence, wikis, etc.) if available. Use for any question requiring up-to-date information, fact-checking, comparisons, or multi-source research.',
|
|
11
12
|
parameters: {
|
|
12
13
|
type: 'object',
|
|
13
14
|
properties: {
|
|
@@ -23,8 +24,20 @@ export function createSearchRequestTool() {
|
|
|
23
24
|
execute: async (args, llmClient) => {
|
|
24
25
|
const today = new Date().toISOString().split('T')[0];
|
|
25
26
|
const rawInstruction = args['instruction'];
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
let researchUrls = [];
|
|
28
|
+
try {
|
|
29
|
+
const config = configManager.getConfig();
|
|
30
|
+
researchUrls = config.researchUrls || [];
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
}
|
|
34
|
+
let instruction = `[Today's Date: ${today}]\n\n${rawInstruction}`;
|
|
35
|
+
if (researchUrls.length > 0) {
|
|
36
|
+
const urlList = researchUrls.map(r => ` - ${r.name}: ${r.url}`).join('\n');
|
|
37
|
+
instruction += `\n\n[Internal Research Sources]\nSearch these additional sources after web search:\n${urlList}`;
|
|
38
|
+
}
|
|
39
|
+
const maxIterations = 30 + researchUrls.length * 10;
|
|
40
|
+
const agent = new BrowserSubAgent(llmClient, 'search', BROWSER_SUB_AGENT_TOOLS, SEARCH_SYSTEM_PROMPT, { requiresAuth: false, serviceType: 'search', maxIterations });
|
|
28
41
|
return agent.run(instruction);
|
|
29
42
|
},
|
|
30
43
|
categories: ['llm-agent'],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-agent.js","sourceRoot":"","sources":["../../../src/agents/browser/search-agent.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search-agent.js","sourceRoot":"","sources":["../../../src/agents/browser/search-agent.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAC/E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAGpE,MAAM,UAAU,uBAAuB;IACrC,OAAO;QACL,UAAU,EAAE;YACV,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE;gBACR,IAAI,EAAE,gBAAgB;gBACtB,WAAW,EACT,6aAA6a;gBAC/a,UAAU,EAAE;oBACV,IAAI,EAAE,QAAQ;oBACd,UAAU,EAAE;wBACV,WAAW,EAAE;4BACX,IAAI,EAAE,QAAQ;4BACd,WAAW,EAAE,wHAAwH;yBACtI;qBACF;oBACD,QAAQ,EAAE,CAAC,aAAa,CAAC;iBAC1B;aACF;SACF;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;YAEjC,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACrD,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAW,CAAC;YAGrD,IAAI,YAAY,GAAwB,EAAE,CAAC;YAC3C,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,CAAC;gBACzC,YAAY,GAAG,MAAM,CAAC,YAAY,IAAI,EAAE,CAAC;YAC3C,CAAC;YAAC,MAAM,CAAC;YAET,CAAC;YAGD,IAAI,WAAW,GAAG,kBAAkB,KAAK,QAAQ,cAAc,EAAE,CAAC;YAClE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC5E,WAAW,IAAI,uFAAuF,OAAO,EAAE,CAAC;YAClH,CAAC;YAGD,MAAM,aAAa,GAAG,EAAE,GAAG,YAAY,CAAC,MAAM,GAAG,EAAE,CAAC;YAEpD,MAAM,KAAK,GAAG,IAAI,eAAe,CAC/B,SAAS,EACT,QAAQ,EACR,uBAAuB,EACvB,oBAAoB,EACpB,EAAE,YAAY,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,CAC9D,CAAC;YACF,OAAO,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAChC,CAAC;QACD,UAAU,EAAE,CAAC,WAAW,CAAC;QACzB,cAAc,EAAE,IAAI;KACrB,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agents/planner/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,OAAO,EAAY,cAAc,EAAc,MAAM,sBAAsB,CAAC;AASrF,OAAO,EAEL,eAAe,EAChB,MAAM,kDAAkD,CAAC;AAO1D,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,eAAe,CAAgC;gBAE3C,SAAS,EAAE,SAAS;IAQhC,kBAAkB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAQnD,oBAAoB,IAAI,IAAI;IAatB,gBAAgB,CACpB,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,OAAO,EAAE,GAC1B,OAAO,CAAC,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/agents/planner/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,OAAO,EAAY,cAAc,EAAc,MAAM,sBAAsB,CAAC;AASrF,OAAO,EAEL,eAAe,EAChB,MAAM,kDAAkD,CAAC;AAO1D,qBAAa,WAAW;IACtB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,eAAe,CAAgC;gBAE3C,SAAS,EAAE,SAAS;IAQhC,kBAAkB,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;IAQnD,oBAAoB,IAAI,IAAI;IAatB,gBAAgB,CACpB,WAAW,EAAE,MAAM,EACnB,eAAe,CAAC,EAAE,OAAO,EAAE,GAC1B,OAAO,CAAC,cAAc,CAAC;IA8Y1B,OAAO,CAAC,0BAA0B;CA8CnC;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -23,7 +23,12 @@ export class PlanningLLM {
|
|
|
23
23
|
async generateTODOList(userRequest, contextMessages) {
|
|
24
24
|
const toolSummary = toolRegistry.getToolSummaryForPlanning();
|
|
25
25
|
const optionalToolsInfo = toolRegistry.getEnabledOptionalToolsInfo();
|
|
26
|
-
|
|
26
|
+
let researchUrls;
|
|
27
|
+
try {
|
|
28
|
+
researchUrls = configManager.getConfig().researchUrls;
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
const systemPrompt = buildPlanningSystemPrompt(toolSummary, optionalToolsInfo, getWindowsUserDesktopPath() || undefined, researchUrls);
|
|
27
32
|
const clarificationMessages = [];
|
|
28
33
|
const messages = [
|
|
29
34
|
{
|
|
@@ -64,17 +69,18 @@ export class PlanningLLM {
|
|
|
64
69
|
role: 'user',
|
|
65
70
|
content: `[RETRY ${attempt}/${MAX_RETRIES}] ⚠️ CRITICAL: You are the PLANNING LLM, not the Execution LLM.
|
|
66
71
|
|
|
67
|
-
You have ONLY
|
|
72
|
+
You have ONLY 4 tools available:
|
|
68
73
|
1. 'ask_to_user' - To clarify ambiguous requirements (use FIRST if unclear)
|
|
69
74
|
2. 'create_todos' - For ANY action/implementation request
|
|
70
75
|
3. 'respond_to_user' - For pure knowledge questions/greetings only
|
|
76
|
+
4. 'tell_to_user' - To send a message and then continue with create_todos
|
|
71
77
|
|
|
72
78
|
❌ DO NOT use tools like 'write_todos', 'read_file', 'bash', etc. Those are for Execution LLM, NOT you.
|
|
73
79
|
❌ You saw those tools in conversation history, but they are NOT available to you.
|
|
74
80
|
|
|
75
81
|
Previous error: ${lastError?.message || 'Invalid response'}
|
|
76
82
|
|
|
77
|
-
Choose one of your
|
|
83
|
+
Choose one of your 4 tools now.`,
|
|
78
84
|
});
|
|
79
85
|
logger.warn(`Planning LLM retry attempt ${attempt}/${MAX_RETRIES}`, { lastError: lastError?.message });
|
|
80
86
|
}
|
|
@@ -175,6 +181,25 @@ Choose one of your 3 tools now.`,
|
|
|
175
181
|
continue;
|
|
176
182
|
}
|
|
177
183
|
}
|
|
184
|
+
if (toolName === 'tell_to_user') {
|
|
185
|
+
logger.flow('Planning LLM sending message to user via tell_to_user');
|
|
186
|
+
const tellMessage = toolArgs.message;
|
|
187
|
+
if (tellMessage) {
|
|
188
|
+
const assistantMsg = {
|
|
189
|
+
role: 'assistant',
|
|
190
|
+
content: tellMessage,
|
|
191
|
+
};
|
|
192
|
+
messages.push(assistantMsg);
|
|
193
|
+
clarificationMessages.push(assistantMsg);
|
|
194
|
+
}
|
|
195
|
+
messages.push({
|
|
196
|
+
role: 'user',
|
|
197
|
+
content: '[Message delivered] Now call create_todos to plan the tasks.',
|
|
198
|
+
});
|
|
199
|
+
askIterations++;
|
|
200
|
+
shouldContinueMainLoop = true;
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
178
203
|
if (toolName === 'create_todos') {
|
|
179
204
|
logger.flow('TODO list created via create_todos tool');
|
|
180
205
|
let rawTodos = toolArgs.todos;
|
|
@@ -225,7 +250,7 @@ Choose one of your 3 tools now.`,
|
|
|
225
250
|
};
|
|
226
251
|
}
|
|
227
252
|
logger.warn(`Unknown tool called: ${toolName}`);
|
|
228
|
-
lastError = new Error(`Invalid tool "${toolName}". You only have
|
|
253
|
+
lastError = new Error(`Invalid tool "${toolName}". You only have 4 tools: ask_to_user, create_todos, respond_to_user, or tell_to_user. Tools like write_todos are for Execution LLM, not Planning LLM.`);
|
|
229
254
|
continue;
|
|
230
255
|
}
|
|
231
256
|
const contentOnly = message?.content;
|
|
@@ -264,11 +289,11 @@ Choose one of your 3 tools now.`,
|
|
|
264
289
|
logger.warn(`Planning LLM returned content without tool call (attempt ${attempt}/${MAX_RETRIES})`, {
|
|
265
290
|
contentPreview: contentOnly.substring(0, 100),
|
|
266
291
|
});
|
|
267
|
-
lastError = new Error('You MUST call one of your tools: ask_to_user, create_todos, or
|
|
292
|
+
lastError = new Error('You MUST call one of your tools: ask_to_user, create_todos, respond_to_user, or tell_to_user. Do NOT respond with plain text.');
|
|
268
293
|
}
|
|
269
294
|
else {
|
|
270
295
|
logger.warn(`Planning LLM returned no tool call and no content (attempt ${attempt}/${MAX_RETRIES})`);
|
|
271
|
-
lastError = new Error('Planning LLM must use one of: ask_to_user, create_todos, or
|
|
296
|
+
lastError = new Error('Planning LLM must use one of: ask_to_user, create_todos, respond_to_user, or tell_to_user');
|
|
272
297
|
}
|
|
273
298
|
}
|
|
274
299
|
catch (error) {
|
|
@@ -302,7 +327,7 @@ Choose one of your 3 tools now.`,
|
|
|
302
327
|
};
|
|
303
328
|
}
|
|
304
329
|
extractToolCallFromContent(content) {
|
|
305
|
-
const toolNames = ['create_todos', 'respond_to_user', 'ask_to_user'];
|
|
330
|
+
const toolNames = ['create_todos', 'respond_to_user', 'ask_to_user', 'tell_to_user'];
|
|
306
331
|
for (const toolName of toolNames) {
|
|
307
332
|
const funcPattern = new RegExp(`\\{[^{}]*"name"\\s*:\\s*"${toolName}"[^{}]*"arguments"\\s*:\\s*(\\{[\\s\\S]*?\\})\\s*\\}`);
|
|
308
333
|
const funcMatch = content.match(funcPattern);
|