@geekbeer/minion 3.17.0 → 3.23.0

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.
@@ -18,6 +18,8 @@ const routineStore = require('../core/stores/routine-store')
18
18
  const logManager = require('../core/lib/log-manager')
19
19
  const { activeSessions } = require('./workflow-runner')
20
20
  const { expandSkillTemplates, restoreSkillTemplates } = require('../core/lib/template-expander')
21
+ const { getActivePrimary } = require('../core/llm-plugins/lib/active')
22
+ const os = require('os')
21
23
 
22
24
  const activeJobs = new Map()
23
25
  const runningExecutions = new Map()
@@ -48,11 +50,16 @@ async function executeRoutineSession(routine, executionId, skillNames) {
48
50
  const homeDir = config.HOME_DIR
49
51
  const sessionName = generateSessionName(routine.id, executionId)
50
52
 
51
- const skillCommands = skillNames.map(name => `/${name}`).join(', then ')
53
+ const primary = getActivePrimary()
54
+ const formatSkill = primary && typeof primary.formatSkillInvocation === 'function'
55
+ ? primary.formatSkillInvocation.bind(primary)
56
+ : (name) => `/${name}`
57
+ const skillCommands = skillNames.map(name => formatSkill(name)).join(', then ')
52
58
  const contextPrefix = routine.context
53
59
  ? `## Context\n\n${routine.context}\n\n---\n\n`
54
60
  : ''
55
- const prompt = `${contextPrefix}Run the following skills in order: ${skillCommands}. After completing all skills, run /execution-report to report the results.`
61
+ const reportSkill = formatSkill('execution-report')
62
+ const prompt = `${contextPrefix}Run the following skills in order: ${skillCommands}. After completing all skills, run ${reportSkill} to report the results.`
56
63
 
57
64
  const logFile = logManager.getLogPath(executionId)
58
65
 
@@ -82,11 +89,18 @@ async function executeRoutineSession(routine, executionId, skillNames) {
82
89
  activeSessions.delete(sessionName)
83
90
  }
84
91
 
85
- if (!config.LLM_COMMAND) {
86
- throw new Error('LLM_COMMAND is not configured. Set LLM_COMMAND in minion.env')
92
+ let llmCommand
93
+ const primary = getActivePrimary()
94
+ if (primary && typeof primary.buildShellInvocation === 'function') {
95
+ const promptFile = path.join(os.tmpdir(), `minion-routine-prompt-${sessionName}.txt`)
96
+ await fs.writeFile(promptFile, prompt, 'utf-8')
97
+ llmCommand = primary.buildShellInvocation({ promptFile })
98
+ } else if (config.LLM_COMMAND) {
99
+ const escapedPrompt = prompt.replace(/'/g, "''")
100
+ llmCommand = config.LLM_COMMAND.replace(/\{prompt\}/g, escapedPrompt)
101
+ } else {
102
+ throw new Error('No LLM configured. Set a Primary plugin via /api/llm/config or LLM_COMMAND in minion.env')
87
103
  }
88
- const escapedPrompt = prompt.replace(/'/g, "''")
89
- const llmCommand = config.LLM_COMMAND.replace(/\{prompt\}/g, escapedPrompt)
90
104
 
91
105
  // PATH, HOME, USERPROFILE, and minion secrets are already set in
92
106
  // process.env at server startup. Per-execution identifiers are added here.
package/win/server.js CHANGED
@@ -62,6 +62,7 @@ const { threadRoutes } = require('../core/routes/threads')
62
62
  const { todoRoutes } = require('../core/routes/todos')
63
63
  const { emailRoutes } = require('../core/routes/emails')
64
64
  const { daemonRoutes } = require('../core/routes/daemons')
65
+ const { llmRoutes } = require('../core/routes/llm')
65
66
 
66
67
  // Validate configuration
67
68
  validate()
@@ -224,6 +225,7 @@ async function registerRoutes(app) {
224
225
  await app.register(todoRoutes)
225
226
  await app.register(emailRoutes)
226
227
  await app.register(daemonRoutes, { heartbeatStatus: () => ({ running: !!heartbeatTimer, last_beat_at: lastBeatAt }) })
228
+ await app.register(llmRoutes)
227
229
 
228
230
  // Shutdown endpoint — allows detached restart/update scripts to trigger
229
231
  // graceful shutdown (offline heartbeat) before force-killing the process.
@@ -24,6 +24,8 @@ const executionStore = require('../core/stores/execution-store')
24
24
  const workflowStore = require('../core/stores/workflow-store')
25
25
  const logManager = require('../core/lib/log-manager')
26
26
  const { expandSkillTemplates, restoreSkillTemplates } = require('../core/lib/template-expander')
27
+ const { getActivePrimary } = require('../core/llm-plugins/lib/active')
28
+ const os = require('os')
27
29
 
28
30
  // Active cron jobs keyed by workflow ID
29
31
  const activeJobs = new Map()
@@ -73,10 +75,14 @@ async function executeWorkflowSession(workflow, executionId, skillNames, options
73
75
  const sessionName = generateSessionName(workflow.id, executionId)
74
76
 
75
77
  // Build prompt
76
- const skillCommands = skillNames.map(name => `/${name}`).join(', then ')
78
+ const primary = getActivePrimary()
79
+ const formatSkill = primary && typeof primary.formatSkillInvocation === 'function'
80
+ ? primary.formatSkillInvocation.bind(primary)
81
+ : (name) => `/${name}`
82
+ const skillCommands = skillNames.map(name => formatSkill(name)).join(', then ')
77
83
 
78
84
  const rolePrefix = options.role
79
- ? `You are acting as the "${options.role}" role in this session. Read ~/.minion/roles/${options.role}.md for your role guidelines before proceeding.\n\n`
85
+ ? `You are acting as the ${options.role} role in this session. Read ~/.minion/roles/${options.role}.md for your role guidelines before proceeding.\n\n`
80
86
  : ''
81
87
 
82
88
  const revisionContext = options.revisionFeedback
@@ -115,12 +121,19 @@ async function executeWorkflowSession(workflow, executionId, skillNames, options
115
121
  activeSessions.delete(sessionName)
116
122
  }
117
123
 
118
- // Build the LLM command
119
- if (!config.LLM_COMMAND) {
120
- throw new Error('LLM_COMMAND is not configured. Set LLM_COMMAND in minion.env')
124
+ // Build the LLM command (prefer plugin system, fall back to LLM_COMMAND)
125
+ let llmCommand
126
+ const primary = getActivePrimary()
127
+ if (primary && typeof primary.buildShellInvocation === 'function') {
128
+ const promptFile = path.join(os.tmpdir(), `minion-workflow-prompt-${sessionName}.txt`)
129
+ await fs.writeFile(promptFile, prompt, 'utf-8')
130
+ llmCommand = primary.buildShellInvocation({ promptFile })
131
+ } else if (config.LLM_COMMAND) {
132
+ const escapedPrompt = prompt.replace(/'/g, "''")
133
+ llmCommand = config.LLM_COMMAND.replace(/\{prompt\}/g, escapedPrompt)
134
+ } else {
135
+ throw new Error('No LLM configured. Set a Primary plugin via /api/llm/config or LLM_COMMAND in minion.env')
121
136
  }
122
- const escapedPrompt = prompt.replace(/'/g, "''")
123
- const llmCommand = config.LLM_COMMAND.replace(/\{prompt\}/g, escapedPrompt)
124
137
 
125
138
  // PATH, HOME, USERPROFILE, and minion secrets are already set in
126
139
  // process.env at server startup, so child processes inherit them automatically.