opencastle 0.32.6 → 0.32.7

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.
Files changed (42) hide show
  1. package/dist/cli/convoy/engine.d.ts.map +1 -1
  2. package/dist/cli/convoy/engine.js +79 -4
  3. package/dist/cli/convoy/engine.js.map +1 -1
  4. package/dist/cli/convoy/engine.test.js +11 -9
  5. package/dist/cli/convoy/engine.test.js.map +1 -1
  6. package/dist/dashboard/scripts/etl.js +17 -2
  7. package/dist/dashboard/scripts/etl.js.map +1 -1
  8. package/package.json +1 -1
  9. package/src/cli/convoy/engine.test.ts +11 -9
  10. package/src/cli/convoy/engine.ts +78 -4
  11. package/src/dashboard/dist/_astro/index.6xXNs4L2.css +1 -0
  12. package/src/dashboard/dist/data/convoy-list.json +27 -13
  13. package/src/dashboard/dist/data/convoys/demo-api-v2.json +16 -10
  14. package/src/dashboard/dist/data/convoys/demo-auth-revamp.json +25 -15
  15. package/src/dashboard/dist/data/convoys/demo-dashboard-ui.json +35 -21
  16. package/src/dashboard/dist/data/convoys/demo-data-pipeline.json +17 -11
  17. package/src/dashboard/dist/data/convoys/demo-deploy-ci.json +8 -4
  18. package/src/dashboard/dist/data/convoys/demo-docs-update.json +13 -9
  19. package/src/dashboard/dist/data/convoys/demo-perf-opt.json +22 -14
  20. package/src/dashboard/dist/data/overall-stats.json +36 -2
  21. package/src/dashboard/dist/index.html +149 -93
  22. package/src/dashboard/node_modules/.vite/deps/_metadata.json +6 -6
  23. package/src/dashboard/public/data/convoy-list.json +27 -13
  24. package/src/dashboard/public/data/convoys/demo-api-v2.json +16 -10
  25. package/src/dashboard/public/data/convoys/demo-auth-revamp.json +25 -15
  26. package/src/dashboard/public/data/convoys/demo-dashboard-ui.json +35 -21
  27. package/src/dashboard/public/data/convoys/demo-data-pipeline.json +17 -11
  28. package/src/dashboard/public/data/convoys/demo-deploy-ci.json +8 -4
  29. package/src/dashboard/public/data/convoys/demo-docs-update.json +13 -9
  30. package/src/dashboard/public/data/convoys/demo-perf-opt.json +22 -14
  31. package/src/dashboard/public/data/overall-stats.json +36 -2
  32. package/src/dashboard/scripts/etl.ts +15 -3
  33. package/src/dashboard/scripts/generate-demo-db.ts +42 -34
  34. package/src/dashboard/src/pages/index.astro +159 -112
  35. package/src/dashboard/src/styles/dashboard.css +58 -3
  36. package/src/dashboard/dist/_astro/index.wyN9vmjZ.css +0 -1
  37. package/src/dashboard/dist/data/convoys/demo-convoy-1.json +0 -111
  38. package/src/dashboard/dist/data/convoys/demo-convoy-2.json +0 -72
  39. package/src/dashboard/dist/data/pipelines.ndjson +0 -5285
  40. package/src/dashboard/public/data/convoys/demo-convoy-1.json +0 -111
  41. package/src/dashboard/public/data/convoys/demo-convoy-2.json +0 -72
  42. package/src/dashboard/public/data/pipelines.ndjson +0 -5285
@@ -1 +1 @@
1
- {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/cli/convoy/engine.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,28 @@ import { getArtifactDir, extractArtifactRefs } from './artifacts.js';
29
29
  import { shouldCompact, parseCompactionSummary, saveCompaction, canCompact, getMaxCompactions, generateCompactionPrompt, buildContinuationPrompt } from './compaction.js';
30
30
  import { calculateCost } from './pricing.js';
31
31
  const execFile = promisify(execFileCb);
32
+ /** Map agent names to their default model. Used when adapters don't report model. */
33
+ const AGENT_MODEL_MAP = {
34
+ 'developer': 'claude-sonnet-4-6',
35
+ 'ui-ux-expert': 'claude-sonnet-4-6',
36
+ 'testing-expert': 'claude-sonnet-4-6',
37
+ 'security-expert': 'claude-sonnet-4-6',
38
+ 'performance-expert': 'claude-sonnet-4-6',
39
+ 'devops-expert': 'claude-sonnet-4-6',
40
+ 'data-expert': 'claude-sonnet-4-6',
41
+ 'api-designer': 'claude-sonnet-4-6',
42
+ 'copywriter': 'claude-sonnet-4-6',
43
+ 'content-engineer': 'claude-sonnet-4-6',
44
+ 'database-engineer': 'claude-sonnet-4-6',
45
+ 'researcher': 'claude-sonnet-4-6',
46
+ 'release-manager': 'claude-sonnet-4-6',
47
+ 'architect': 'claude-opus-4-6',
48
+ 'team-lead': 'claude-opus-4-6',
49
+ 'reviewer': 'claude-haiku-3-5',
50
+ 'documentation-writer': 'claude-haiku-3-5',
51
+ 'seo-specialist': 'claude-haiku-3-5',
52
+ 'session-guard': 'claude-haiku-3-5',
53
+ };
32
54
  export class CircuitBreakerManager {
33
55
  states = new Map();
34
56
  threshold;
@@ -976,7 +998,7 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
976
998
  }
977
999
  }
978
1000
  process.stdout.write(` ${c.cyan('▶')} ${c.bold(`[${taskRecord.id}]`)} ${taskRecord.agent}${worktreePath ? c.dim(' (worktree)') : ''}\n`);
979
- events.emit('task_started', { worker_id: workerId }, { convoy_id: convoyId, task_id: taskRecord.id, worker_id: workerId });
1001
+ events.emit('task_started', { worker_id: workerId, mechanism: worktreePath ? 'background' : 'sub-agent' }, { convoy_id: convoyId, task_id: taskRecord.id, worker_id: workerId });
980
1002
  const taskStartTime = Date.now();
981
1003
  // ── Outbound prompt scan — NEVER send a prompt containing secrets ─────────
982
1004
  const promptScan = scanForSecrets(taskRecord.prompt, `task:${taskRecord.id}`);
@@ -1167,10 +1189,20 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1167
1189
  process.stdout.write(` ${c.yellow('⟳')} ${c.bold(`[${taskRecord.id}]`)} timed out, retry ${freshRecord.retries + 1}/${freshRecord.max_retries}\n`);
1168
1190
  }
1169
1191
  else {
1192
+ // Estimate tokens even for timed-out tasks — you still paid for them
1193
+ const estimatedPrompt = Math.ceil(taskRecord.prompt.length / 4);
1194
+ const estimatedCompletion = Math.ceil((result.output?.length ?? 0) / 4);
1195
+ const timeoutModel = taskRecord.model ?? AGENT_MODEL_MAP[taskRecord.agent.toLowerCase()] ?? taskAdapter.name;
1196
+ const timeoutCost = calculateCost(timeoutModel, estimatedPrompt, estimatedCompletion);
1170
1197
  store.withTransaction(() => {
1171
1198
  store.updateTaskStatus(taskRecord.id, convoyId, 'timed-out', {
1172
1199
  finished_at: finishedAt,
1173
1200
  output: result.output,
1201
+ prompt_tokens: estimatedPrompt,
1202
+ completion_tokens: estimatedCompletion,
1203
+ total_tokens: estimatedPrompt + estimatedCompletion,
1204
+ model: timeoutModel,
1205
+ cost_usd: timeoutCost,
1174
1206
  });
1175
1207
  store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt });
1176
1208
  });
@@ -1977,8 +2009,16 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
1977
2009
  if (result.usage.total_tokens != null)
1978
2010
  usageExtra.total_tokens = result.usage.total_tokens;
1979
2011
  }
1980
- else if (verbose) {
1981
- process.stdout.write(` ${c.dim('ℹ')} No token usage data returned by adapter ${taskAdapter.name}\n`);
2012
+ else {
2013
+ // Estimate tokens from prompt/output text length (~4 chars per token)
2014
+ const estimatedPrompt = Math.ceil(taskRecord.prompt.length / 4);
2015
+ const estimatedCompletion = Math.ceil((result.output?.length ?? 0) / 4);
2016
+ usageExtra.prompt_tokens = estimatedPrompt;
2017
+ usageExtra.completion_tokens = estimatedCompletion;
2018
+ usageExtra.total_tokens = estimatedPrompt + estimatedCompletion;
2019
+ if (verbose) {
2020
+ process.stdout.write(` ${c.dim('ℹ')} Estimated ${usageExtra.total_tokens} tokens (adapter ${taskAdapter.name} returned no usage data)\n`);
2021
+ }
1982
2022
  }
1983
2023
  // ── Context compaction check (Phase 44) ─────────────────────────────
1984
2024
  const compactionConfig = spec.defaults?.compaction;
@@ -2091,6 +2131,31 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
2091
2131
  catch (err) {
2092
2132
  process.stderr.write(`[artifacts] Warning: extraction failed for task ${taskRecord.id}: ${err.message}\n`);
2093
2133
  }
2134
+ // ── Create file artifacts from task file list ────────────────────────
2135
+ if (taskRecord.files && !taskRecord.outputs) {
2136
+ try {
2137
+ const fileList = JSON.parse(taskRecord.files);
2138
+ for (const filePath of fileList.slice(0, 20)) {
2139
+ try {
2140
+ store.insertArtifact({
2141
+ id: `artifact-${taskRecord.id}-file-${filePath.replace(/[^a-z0-9]/gi, '-')}-${Date.now()}`,
2142
+ convoy_id: convoyId,
2143
+ task_id: taskRecord.id,
2144
+ name: filePath,
2145
+ type: 'file',
2146
+ content: '',
2147
+ created_at: new Date().toISOString(),
2148
+ });
2149
+ }
2150
+ catch (err) {
2151
+ if (err instanceof ConvoyArtifactLimitError)
2152
+ break;
2153
+ // Other errors are non-critical
2154
+ }
2155
+ }
2156
+ }
2157
+ catch { /* files not parseable */ }
2158
+ }
2094
2159
  // ── Output contract validation ────────────────────────────────────────
2095
2160
  const contractResult = validateOutput(taskRecord.agent, result.output);
2096
2161
  if (!contractResult.valid) {
@@ -2153,7 +2218,7 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
2153
2218
  }
2154
2219
  catch { /* non-critical */ }
2155
2220
  }
2156
- const taskModel = taskRecord.model ?? taskAdapter.name;
2221
+ const taskModel = taskRecord.model ?? AGENT_MODEL_MAP[taskRecord.agent.toLowerCase()] ?? taskAdapter.name;
2157
2222
  const taskCost = calculateCost(taskModel, usageExtra.prompt_tokens, usageExtra.completion_tokens);
2158
2223
  store.withTransaction(() => {
2159
2224
  store.updateTaskStatus(taskRecord.id, convoyId, 'done', {
@@ -2236,11 +2301,21 @@ async function runConvoy(convoyId, spec, adapter, store, events, wtManager, merg
2236
2301
  process.stdout.write(` ${c.yellow('⟳')} ${c.bold(`[${taskRecord.id}]`)} retry ${freshRecord.retries + 1}/${freshRecord.max_retries}\n`);
2237
2302
  }
2238
2303
  else {
2304
+ // Estimate tokens even for failed tasks — you still paid for them
2305
+ const estimatedPrompt = Math.ceil(taskRecord.prompt.length / 4);
2306
+ const estimatedCompletion = Math.ceil((result.output?.length ?? 0) / 4);
2307
+ const failModel = taskRecord.model ?? AGENT_MODEL_MAP[taskRecord.agent.toLowerCase()] ?? taskAdapter.name;
2308
+ const failCost = calculateCost(failModel, estimatedPrompt, estimatedCompletion);
2239
2309
  store.withTransaction(() => {
2240
2310
  store.updateTaskStatus(taskRecord.id, convoyId, 'failed', {
2241
2311
  finished_at: finishedAt,
2242
2312
  output: result.output,
2243
2313
  exit_code: result.exitCode,
2314
+ prompt_tokens: estimatedPrompt,
2315
+ completion_tokens: estimatedCompletion,
2316
+ total_tokens: estimatedPrompt + estimatedCompletion,
2317
+ model: failModel,
2318
+ cost_usd: failCost,
2244
2319
  });
2245
2320
  store.updateWorkerStatus(workerId, 'failed', { finished_at: finishedAt });
2246
2321
  });