dsh-my-go 0.1.26 → 0.1.28
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/lib/index.js +11 -4
- package/package.json +1 -1
- package/preset/tools/broker.mjs +86 -23
package/lib/index.js
CHANGED
|
@@ -38,14 +38,21 @@ async function ensurePresetInstalled() {
|
|
|
38
38
|
try {
|
|
39
39
|
const here = dirname(fileURLToPath(import.meta.url)) // .../dsh-my-go/lib
|
|
40
40
|
const packageRoot = dirname(here) // .../dsh-my-go
|
|
41
|
-
const source = join(packageRoot, 'preset')
|
|
42
41
|
const dshHome = process.env.DSH_HOME || join(homedir(), '.dsh')
|
|
43
42
|
const userPresetRoot = join(dshHome, '.agent-presets')
|
|
44
43
|
const target = join(userPresetRoot, 'dsh-my-go')
|
|
45
|
-
await access(source)
|
|
46
44
|
await mkdir(userPresetRoot, { recursive: true })
|
|
47
|
-
//
|
|
48
|
-
|
|
45
|
+
// Sync preset/ directory (composition + tools)
|
|
46
|
+
const presetSource = join(packageRoot, 'preset')
|
|
47
|
+
await access(presetSource)
|
|
48
|
+
await cp(presetSource, target, { recursive: true, force: true })
|
|
49
|
+
// Sync prompts/ directory (persona markdown files)
|
|
50
|
+
const promptsSource = join(packageRoot, 'prompts')
|
|
51
|
+
const promptsTarget = join(target, 'prompts')
|
|
52
|
+
try {
|
|
53
|
+
await access(promptsSource)
|
|
54
|
+
await cp(promptsSource, promptsTarget, { recursive: true, force: true })
|
|
55
|
+
} catch { /* prompts/ optional — degrade gracefully */ }
|
|
49
56
|
console.log(`[dsh-my-go] preset synced to ${target}`)
|
|
50
57
|
} catch (error) {
|
|
51
58
|
console.error(`[dsh-my-go] could not sync preset: ${String(error)}`)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-my-go",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.28",
|
|
4
4
|
"description": "DSH plugin: Sisyphus agent orchestration — star topology, single-line blocking, 7 specialist sub-agents (Hermes/Explore/Librarian/Looker/Hephaestus/Prometheus/Oracle) with per-type model binding, go_work/continue/need_help/forward communication tools, Web UI tree panel and settings.",
|
|
5
5
|
"author": "daizihan233",
|
|
6
6
|
"license": "MIT",
|
package/preset/tools/broker.mjs
CHANGED
|
@@ -18,10 +18,40 @@ export const name = 'dsh-my-go-broker'
|
|
|
18
18
|
|
|
19
19
|
export const inject = ['tools', 'subagents', 'systemPrompt', 'llm', 'settings']
|
|
20
20
|
|
|
21
|
+
import { readFile } from 'node:fs/promises'
|
|
22
|
+
import { dirname, join } from 'node:path'
|
|
23
|
+
import { fileURLToPath } from 'node:url'
|
|
24
|
+
|
|
21
25
|
const AGENT_TYPES = ['hermes', 'explore', 'librarian', 'looker', 'hephaestus', 'prometheus', 'oracle']
|
|
22
26
|
|
|
23
27
|
const AGENT_TYPE_PREFIX = 'dsh-my-go:'
|
|
24
28
|
|
|
29
|
+
// ── prompt file loading ───────────────────────────────────────────────────
|
|
30
|
+
// Prompt files live in the prompts/ directory alongside the preset.
|
|
31
|
+
// They are copied to ~/.dsh/.agent-presets/dsh-my-go/prompts/ by
|
|
32
|
+
// ensurePresetInstalled (lib/index.js).
|
|
33
|
+
const promptCache = new Map()
|
|
34
|
+
async function loadPrompt(agentType) {
|
|
35
|
+
if (promptCache.has(agentType)) return promptCache.get(agentType)
|
|
36
|
+
try {
|
|
37
|
+
const here = dirname(fileURLToPath(import.meta.url)) // .../dsh-my-go/tools
|
|
38
|
+
const presetRoot = dirname(here) // .../dsh-my-go
|
|
39
|
+
const promptsDir = join(presetRoot, 'prompts')
|
|
40
|
+
const content = await readFile(join(promptsDir, `${agentType}.md`), 'utf-8')
|
|
41
|
+
promptCache.set(agentType, content)
|
|
42
|
+
return content
|
|
43
|
+
} catch {
|
|
44
|
+
promptCache.set(agentType, null)
|
|
45
|
+
return null
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// Pre-load all prompts at startup (non-blocking, errors swallowed)
|
|
49
|
+
async function loadAllPrompts() {
|
|
50
|
+
for (const type of [...AGENT_TYPES, 'sisyphus']) {
|
|
51
|
+
await loadPrompt(type)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
25
55
|
function agentLabel(type, summary) {
|
|
26
56
|
return `${AGENT_TYPE_PREFIX}${type}${summary ? `: ${summary}` : ''}`
|
|
27
57
|
}
|
|
@@ -217,6 +247,9 @@ export async function apply(ctx, config = {}) {
|
|
|
217
247
|
// bundle), not here — when this file loads from the preset copy,
|
|
218
248
|
// import.meta.url points to the copy, not the npm package source.
|
|
219
249
|
|
|
250
|
+
// Load all prompt files from the prompts/ directory at startup
|
|
251
|
+
void loadAllPrompts()
|
|
252
|
+
|
|
220
253
|
const orchestration = new Orchestration()
|
|
221
254
|
const sessionTypes = new Map()
|
|
222
255
|
let bindings = { ...defaultBindings(), ...(config.bindings ?? {}) }
|
|
@@ -340,22 +373,59 @@ export async function apply(ctx, config = {}) {
|
|
|
340
373
|
3. 收到 intent=replan 时,必须切换智能体类型,而不是原地升级模型。
|
|
341
374
|
4. Prometheus 只做规划不执行;它的计划必须由你按步骤重新调度。`
|
|
342
375
|
|
|
343
|
-
//
|
|
344
|
-
//
|
|
345
|
-
//
|
|
346
|
-
//
|
|
347
|
-
//
|
|
376
|
+
// ── per-agent persona + orchestration via systemPrompt ────────────────────
|
|
377
|
+
//
|
|
378
|
+
// Sub-agents inherit the preset's scope, so they DO see these sections.
|
|
379
|
+
// We use text functions with parentSession detection (no race condition)
|
|
380
|
+
// to differentiate Sisyphus from sub-agents.
|
|
381
|
+
//
|
|
382
|
+
// For sub-agents:
|
|
383
|
+
// - deployment:persona: empty (sub-agent persona is injected via context)
|
|
384
|
+
// - dsh-my-go:orchestration: empty (sub-agents don't orchestrate)
|
|
385
|
+
// - systemPrompt.context: injects the sub-agent's role description
|
|
386
|
+
//
|
|
387
|
+
// For Sisyphus:
|
|
388
|
+
// - deployment:persona: full Sisyphus persona
|
|
389
|
+
// - dsh-my-go:orchestration: full orchestration rules
|
|
390
|
+
// - systemPrompt.context: empty (Sisyphus has no extra context)
|
|
391
|
+
|
|
392
|
+
const isSubAgentContext = (context) => {
|
|
393
|
+
// context = { agent, scope: agent } from assembleContextFor()
|
|
394
|
+
// Sub-agents have parentSession set in their session header
|
|
395
|
+
return context?.agent?.session?.header?.parentSession != null
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// Use loaded prompt files for persona. SISYPHUS_PERSONA is the fallback
|
|
399
|
+
// if the file hasn't loaded yet (async startup).
|
|
348
400
|
ctx.effect(() => ctx.systemPrompt.section({
|
|
349
401
|
name: 'deployment:persona',
|
|
350
402
|
order: 0,
|
|
351
|
-
text:
|
|
403
|
+
text: (context) => {
|
|
404
|
+
if (isSubAgentContext(context)) return ''
|
|
405
|
+
return promptCache.get('sisyphus') || SISYPHUS_PERSONA
|
|
406
|
+
},
|
|
352
407
|
}), 'dsh-my-go-broker.persona()')
|
|
353
408
|
ctx.effect(() => ctx.systemPrompt.section({
|
|
354
409
|
name: 'dsh-my-go:orchestration',
|
|
355
410
|
order: 20,
|
|
356
|
-
text: ORCHESTRATION_TEXT,
|
|
411
|
+
text: (context) => isSubAgentContext(context) ? '' : ORCHESTRATION_TEXT,
|
|
357
412
|
}), 'dsh-my-go-broker.orchestration()')
|
|
358
413
|
|
|
414
|
+
// Inject sub-agent identity via systemPrompt.context (system prompt level).
|
|
415
|
+
// The text function checks parentSession — no race condition.
|
|
416
|
+
// Uses loaded prompt files when available.
|
|
417
|
+
ctx.effect(() => ctx.systemPrompt.context({
|
|
418
|
+
name: 'dsh-my-go:subagent-role',
|
|
419
|
+
order: 10,
|
|
420
|
+
text: (context) => {
|
|
421
|
+
if (!isSubAgentContext(context)) return ''
|
|
422
|
+
// Try to find the matching prompt from cache by checking all agent types
|
|
423
|
+
// The context doesn't carry the agent type, but we can check if any
|
|
424
|
+
// loaded prompt matches. Use a generic fallback.
|
|
425
|
+
return 'You are a specialist sub-agent in the dsh-my-go orchestration system. Execute one focused task and report results to Sisyphus. You do not delegate further.'
|
|
426
|
+
},
|
|
427
|
+
}), 'dsh-my-go-broker.subagent-role()')
|
|
428
|
+
|
|
359
429
|
// ── internal go_work implementation (shared by the tool, forward, queue) ─
|
|
360
430
|
async function dispatchWork(agentType, prompt, parent, signal) {
|
|
361
431
|
if (!AGENT_TYPES.includes(agentType)) throw new Error(`unknown agent type: ${String(agentType)}`)
|
|
@@ -390,24 +460,17 @@ export async function apply(ctx, config = {}) {
|
|
|
390
460
|
// No provider available — set model anyway, agent/request handler will validate
|
|
391
461
|
agentOpts.model = binding.model
|
|
392
462
|
}
|
|
393
|
-
// Inject sub-agent
|
|
394
|
-
//
|
|
395
|
-
//
|
|
396
|
-
//
|
|
397
|
-
const
|
|
398
|
-
|
|
399
|
-
explore: 'You are Explore, the fast searcher. You grep, read files, locate symbols, and scan directory structures — quick reconnaissance.',
|
|
400
|
-
librarian: 'You are Librarian, the document reader. You read READMEs, API references, historical docs, and extract comments — document intelligence.',
|
|
401
|
-
looker: 'You are Looker, the multimodal recognizer. You identify UI screenshots, design mockups, PDF charts — visual understanding.',
|
|
402
|
-
hephaestus: 'You are Hephaestus, the code crafter. You do single-file refactors, module implementations, unit tests, and routine code generation.',
|
|
403
|
-
prometheus: 'You are Prometheus, the requirement planner. You understand vague requirements, decompose them into executable steps, and output a plan. You do NOT execute — only plan.',
|
|
404
|
-
oracle: 'You are Oracle, the architect debugger and final validator. You do cross-module dependency analysis, deep bug localization, code review, and final acceptance.',
|
|
405
|
-
}
|
|
406
|
-
const rolePrefix = roleDescriptions[agentType] || `You are a ${agentType} sub-agent.`
|
|
407
|
-
const identityPrefix = `${rolePrefix}\n\nYou report your results to Sisyphus. Execute the following task and report back.\n\n`
|
|
463
|
+
// Inject sub-agent persona from prompts/ files via <system-reminder>.
|
|
464
|
+
// The loaded prompt contains full role description, responsibilities,
|
|
465
|
+
// work style, output format, and constraints — much richer than a
|
|
466
|
+
// one-line hardcoded string.
|
|
467
|
+
const loadedPrompt = promptCache.get(agentType)
|
|
468
|
+
const roleInfo = loadedPrompt || `You are a ${agentType} sub-agent in the dsh-my-go orchestration system. Execute one focused task and report results to Sisyphus.`
|
|
408
469
|
const request = {
|
|
409
470
|
label: agentLabel(agentType, prompt.slice(0, 60)),
|
|
410
|
-
prompt: [
|
|
471
|
+
prompt: [
|
|
472
|
+
{ type: 'text', text: `<system-reminder>\n${roleInfo}\n</system-reminder>\n\n${prompt}` },
|
|
473
|
+
],
|
|
411
474
|
parent,
|
|
412
475
|
...(Object.keys(agentOpts).length > 0 ? { agentOptions: agentOpts } : {}),
|
|
413
476
|
signal,
|