granclaw 0.0.1-beta.91 → 0.0.1-beta.92

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.
@@ -98,15 +98,25 @@ async function executeLlmStep(config, prevOutput, allResults, workspaceDir, agen
98
98
  process.env[envKey] = prevValue;
99
99
  }
100
100
  }
101
- async function executeAgentStep(config, prevOutput, allResults, agent, channelId) {
101
+ async function executeAgentStep(config, prevOutput, allResults, agent, channelId, onEvent) {
102
102
  const rawPrompt = config.prompt;
103
103
  const timeoutMs = config.timeout_ms ?? 300_000;
104
104
  const prompt = resolveTemplates(rawPrompt, prevOutput, allResults);
105
105
  let responseText = '';
106
106
  await Promise.race([
107
107
  (0, runner_pi_js_1.runAgent)(agent, prompt, (chunk) => {
108
- if (chunk.type === 'text')
108
+ if (chunk.type === 'text') {
109
109
  responseText += chunk.text;
110
+ }
111
+ else if (chunk.type === 'tool_call') {
112
+ onEvent({ type: 'tool_call', ts: Date.now(), tool: chunk.tool, input: chunk.input });
113
+ }
114
+ else if (chunk.type === 'tool_result') {
115
+ onEvent({ type: 'tool_result', ts: Date.now(), tool: chunk.tool, output: chunk.output });
116
+ }
117
+ else if (chunk.type === 'error') {
118
+ onEvent({ type: 'error', ts: Date.now(), message: chunk.message });
119
+ }
110
120
  }, { channelId }),
111
121
  new Promise((_, reject) => setTimeout(() => reject(new Error('Agent step timed out')), timeoutMs)),
112
122
  ]);
@@ -178,7 +188,39 @@ async function executeWorkflow(agentId, workflowId, trigger) {
178
188
  }
179
189
  else if (currentStep.type === 'agent') {
180
190
  const stepChannelId = `wf-${run.id}-s${currentStep.position}`;
181
- output = await executeAgentStep(currentStep.config, prevOutput, allResults, agent, stepChannelId);
191
+ const events = [];
192
+ let pendingFlush = null;
193
+ let lastFlushAt = 0;
194
+ const flush = () => {
195
+ pendingFlush = null;
196
+ lastFlushAt = Date.now();
197
+ try {
198
+ (0, workflows_db_js_1.writeRunStepEvents)(agentId, runStepId, events);
199
+ }
200
+ catch { }
201
+ };
202
+ const scheduleFlush = () => {
203
+ if (pendingFlush)
204
+ return;
205
+ const elapsed = Date.now() - lastFlushAt;
206
+ const delay = elapsed >= 1000 ? 0 : 1000 - elapsed;
207
+ pendingFlush = setTimeout(flush, delay);
208
+ };
209
+ try {
210
+ output = await executeAgentStep(currentStep.config, prevOutput, allResults, agent, stepChannelId, (event) => { events.push(event); scheduleFlush(); });
211
+ }
212
+ finally {
213
+ if (pendingFlush) {
214
+ clearTimeout(pendingFlush);
215
+ pendingFlush = null;
216
+ }
217
+ if (events.length > 0) {
218
+ try {
219
+ (0, workflows_db_js_1.writeRunStepEvents)(agentId, runStepId, events);
220
+ }
221
+ catch { }
222
+ }
223
+ }
182
224
  }
183
225
  else {
184
226
  output = await executeLlmStep(currentStep.config, prevOutput, allResults, workspaceDir, agent.model);
@@ -17,6 +17,7 @@ exports.listRuns = listRuns;
17
17
  exports.getRun = getRun;
18
18
  exports.createRunStep = createRunStep;
19
19
  exports.updateRunStep = updateRunStep;
20
+ exports.writeRunStepEvents = writeRunStepEvents;
20
21
  exports.getRunningRuns = getRunningRuns;
21
22
  exports.finalizeRunningRuns = finalizeRunningRuns;
22
23
  exports.getLatestRun = getLatestRun;
@@ -71,6 +72,7 @@ function rowToRunStep(r) {
71
72
  input: r.input ? JSON.parse(r.input) : null,
72
73
  output: r.output ? JSON.parse(r.output) : null,
73
74
  error: r.error ?? null,
75
+ events: r.events ? JSON.parse(r.events) : null,
74
76
  startedAt: r.started_at ?? null,
75
77
  finishedAt: r.finished_at ?? null,
76
78
  durationMs: r.duration_ms ?? null,
@@ -196,6 +198,10 @@ function updateRunStep(agentId, runStepId, data) {
196
198
  WHERE id = ?
197
199
  `).run(data.status, data.input !== undefined ? JSON.stringify(data.input) : null, data.output !== undefined ? JSON.stringify(data.output) : null, data.error ?? null, data.startedAt ?? null, data.finishedAt ?? null, data.durationMs ?? null, runStepId);
198
200
  }
201
+ function writeRunStepEvents(agentId, runStepId, events) {
202
+ getDb(agentId).prepare(`UPDATE run_steps SET events = ? WHERE id = ?`)
203
+ .run(JSON.stringify(events), runStepId);
204
+ }
199
205
  function getRunningRuns(agentId) {
200
206
  try {
201
207
  const db = getDb(agentId);
@@ -110,12 +110,18 @@ function getWorkspaceDb(workspaceDir) {
110
110
  input TEXT,
111
111
  output TEXT,
112
112
  error TEXT,
113
+ events TEXT,
113
114
  started_at INTEGER,
114
115
  finished_at INTEGER,
115
116
  duration_ms INTEGER
116
117
  );
117
118
  CREATE INDEX IF NOT EXISTS idx_run_steps_run ON run_steps(run_id, started_at);
118
119
  `);
120
+ const runStepsCols = db.prepare(`PRAGMA table_info(run_steps)`).all();
121
+ if (runStepsCols.length > 0 && !runStepsCols.some(c => c.name === 'events')) {
122
+ db.exec(`ALTER TABLE run_steps ADD COLUMN events TEXT`);
123
+ console.log('[workspace-pool] migrated run_steps table (added events column)');
124
+ }
119
125
  const tasksSchema = db.prepare(`SELECT sql FROM sqlite_master WHERE type='table' AND name='tasks'`).get();
120
126
  if (tasksSchema?.sql && !tasksSchema.sql.includes('cancelled')) {
121
127
  db.exec(`