@ludi-uni/ludi-agent-kit 0.1.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.
Files changed (172) hide show
  1. package/AGENTS.md +55 -0
  2. package/LICENSE +21 -0
  3. package/README.md +107 -0
  4. package/adapters/codex/README.md +24 -0
  5. package/adapters/codex/skill-metadata/visual-verification/agents/openai.yaml +7 -0
  6. package/adapters/pi/README.md +88 -0
  7. package/adapters/pi/browser/agent-browser.mjs +193 -0
  8. package/adapters/pi/lib/invoke.mjs +55 -0
  9. package/adapters/pi/lib/list-models.mjs +29 -0
  10. package/adapters/pi/lib/settings-proposal.mjs +34 -0
  11. package/adapters/pi/lib/subagent.mjs +175 -0
  12. package/adapters/pi/loop-guard/index.js +51 -0
  13. package/adapters/pi/maintenance-policy.json +36 -0
  14. package/adapters/pi/mcp.template.json +4 -0
  15. package/adapters/pi/model-catalog.json +97 -0
  16. package/adapters/pi/models.json +13 -0
  17. package/adapters/pi/models.local.example.json +14 -0
  18. package/adapters/pi/orchestrator-ext/command.mjs +14 -0
  19. package/adapters/pi/orchestrator-ext/index.js +150 -0
  20. package/adapters/pi/settings.template.json +7 -0
  21. package/adapters/pi/shell-gate/index.js +70 -0
  22. package/adapters/pi/sync-pi.ps1 +137 -0
  23. package/agents/README.md +26 -0
  24. package/agents/browser.md +64 -0
  25. package/agents/coder.md +31 -0
  26. package/agents/orchestrator.md +37 -0
  27. package/agents/reviewer.md +32 -0
  28. package/agents/scout.md +35 -0
  29. package/agents/tester.md +28 -0
  30. package/agents/visual.md +28 -0
  31. package/context-pack/SPEC.md +101 -0
  32. package/context-pack/context-pack.schema.json +79 -0
  33. package/context-pack/examples/example-fix.md +44 -0
  34. package/docs/architecture.md +55 -0
  35. package/docs/migration-from-codex-setting.md +44 -0
  36. package/docs/model-maintenance.md +401 -0
  37. package/docs/orchestrator.md +155 -0
  38. package/docs/phase2-report.md +39 -0
  39. package/docs/roadmap.md +27 -0
  40. package/docs/third-party.md +15 -0
  41. package/lib/agents.mjs +79 -0
  42. package/lib/context-pack.mjs +215 -0
  43. package/lib/job.mjs +312 -0
  44. package/lib/language-policy.mjs +27 -0
  45. package/lib/maintenance-exec.mjs +377 -0
  46. package/lib/maintenance-runner.mjs +266 -0
  47. package/lib/maintenance.mjs +422 -0
  48. package/lib/normalize.mjs +101 -0
  49. package/lib/observe/differ.mjs +185 -0
  50. package/lib/observe/observation.mjs +147 -0
  51. package/lib/observe/observers.mjs +134 -0
  52. package/lib/observe/sources.mjs +154 -0
  53. package/lib/orchestrator/activity.mjs +249 -0
  54. package/lib/orchestrator/api.mjs +151 -0
  55. package/lib/orchestrator/contract.mjs +68 -0
  56. package/lib/orchestrator/escalation.mjs +84 -0
  57. package/lib/orchestrator/evaluator.mjs +92 -0
  58. package/lib/orchestrator/failures.mjs +88 -0
  59. package/lib/orchestrator/health.mjs +53 -0
  60. package/lib/orchestrator/orchestrator.mjs +483 -0
  61. package/lib/orchestrator/permissions.mjs +64 -0
  62. package/lib/orchestrator/planner.mjs +194 -0
  63. package/lib/orchestrator/policy.mjs +134 -0
  64. package/lib/orchestrator/router.mjs +45 -0
  65. package/lib/orchestrator/runner.mjs +278 -0
  66. package/lib/orchestrator/shell-policy.mjs +52 -0
  67. package/lib/orchestrator/store.mjs +581 -0
  68. package/lib/orchestrator/task-store.mjs +79 -0
  69. package/lib/orchestrator/turn-budget.mjs +63 -0
  70. package/lib/orchestrator/worktree.mjs +72 -0
  71. package/lib/pipeline.mjs +279 -0
  72. package/lib/registry.mjs +63 -0
  73. package/lib/resolve.mjs +35 -0
  74. package/lib/routing.mjs +137 -0
  75. package/lib/telemetry.mjs +222 -0
  76. package/mcp/README.md +11 -0
  77. package/mcp/servers.json +13 -0
  78. package/orchestration/decision-policy.json +66 -0
  79. package/package.json +56 -0
  80. package/routing/README.md +24 -0
  81. package/routing/routing.json +81 -0
  82. package/routing/routing.schema.json +66 -0
  83. package/rules/README.md +10 -0
  84. package/rules/common.md +52 -0
  85. package/rules/loop-prevention.md +15 -0
  86. package/rules/repo-local.md +6 -0
  87. package/scripts/check-environment.ps1 +22 -0
  88. package/scripts/context-pack.mjs +17 -0
  89. package/scripts/e2e-investigate-repro.mjs +66 -0
  90. package/scripts/model-maintenance-job.mjs +59 -0
  91. package/scripts/observe-models.mjs +97 -0
  92. package/scripts/orchestrate.mjs +137 -0
  93. package/scripts/reevaluate-models.mjs +95 -0
  94. package/scripts/report-model-maintenance.mjs +70 -0
  95. package/scripts/resolve-capabilities.mjs +39 -0
  96. package/scripts/run-pipeline.mjs +56 -0
  97. package/scripts/sync-agents-md.ps1 +10 -0
  98. package/scripts/validate.mjs +71 -0
  99. package/skills/README.md +14 -0
  100. package/skills/pi-workflow/SKILL.md +26 -0
  101. package/skills/pi-workflow/references/code-investigation-and-fix.md +16 -0
  102. package/skills/pi-workflow/references/research.md +14 -0
  103. package/skills/pi-workflow/references/review.md +11 -0
  104. package/skills/pi-workflow/references/visual-work.md +14 -0
  105. package/skills/project-management/SKILL.md +106 -0
  106. package/skills/project-management/references/operations.md +52 -0
  107. package/skills/visual-verification/SKILL.md +88 -0
  108. package/skills/visual-verification/scripts/analyze-speech.ps1 +346 -0
  109. package/skills/visual-verification/scripts/backends/whisperx_backend.py +234 -0
  110. package/skills/visual-verification/scripts/common.ps1 +387 -0
  111. package/skills/visual-verification/scripts/contact-sheet.ps1 +121 -0
  112. package/skills/visual-verification/scripts/desktop-discover.ps1 +45 -0
  113. package/skills/visual-verification/scripts/desktop-inspect.ps1 +67 -0
  114. package/skills/visual-verification/scripts/desktop-record.ps1 +97 -0
  115. package/skills/visual-verification/scripts/desktop-screenshot.ps1 +65 -0
  116. package/skills/visual-verification/scripts/evaluate-sync.ps1 +249 -0
  117. package/skills/visual-verification/scripts/extract-frames.ps1 +79 -0
  118. package/skills/visual-verification/scripts/inspect-media.ps1 +138 -0
  119. package/skills/visual-verification/scripts/record-av.ps1 +102 -0
  120. package/skills/visual-verification/scripts/record.ps1 +72 -0
  121. package/skills/visual-verification/scripts/screenshot.ps1 +44 -0
  122. package/skills/visual-verification/scripts/waveform.ps1 +450 -0
  123. package/skills/visual-verification/scripts/winapp-common.ps1 +465 -0
  124. package/tests/activity.test.mjs +252 -0
  125. package/tests/attempt-budget.test.mjs +102 -0
  126. package/tests/browser.test.mjs +121 -0
  127. package/tests/context-pack.test.mjs +98 -0
  128. package/tests/dirty-gate.test.mjs +211 -0
  129. package/tests/e2e-browser.mjs +66 -0
  130. package/tests/e2e-real-orchestrator-resume.mjs +101 -0
  131. package/tests/e2e-real-orchestrator.mjs +41 -0
  132. package/tests/e2e-real-pi.mjs +27 -0
  133. package/tests/e2e-real-tool-orchestrator.mjs +66 -0
  134. package/tests/fixtures/browser-page/index.html +20 -0
  135. package/tests/fixtures/maintenance/availability.txt +5 -0
  136. package/tests/fixtures/maintenance/catalog.json +74 -0
  137. package/tests/fixtures/maintenance/events.json +13 -0
  138. package/tests/fixtures/math-repo/README.md +3 -0
  139. package/tests/fixtures/math-repo/package.json +7 -0
  140. package/tests/fixtures/math-repo/src/math.js +11 -0
  141. package/tests/fixtures/math-repo/test/math.test.js +7 -0
  142. package/tests/fixtures/observe/announcements.json +8 -0
  143. package/tests/fixtures/orch-concurrent-child.mjs +44 -0
  144. package/tests/fixtures/orch-persist-child.mjs +61 -0
  145. package/tests/job.test.mjs +230 -0
  146. package/tests/kit.test.mjs +79 -0
  147. package/tests/language-policy.test.mjs +93 -0
  148. package/tests/loop-guard.test.mjs +60 -0
  149. package/tests/maintenance-exec.test.mjs +218 -0
  150. package/tests/maintenance-runner.test.mjs +222 -0
  151. package/tests/maintenance.test.mjs +195 -0
  152. package/tests/observe.test.mjs +283 -0
  153. package/tests/observer-registry.test.mjs +157 -0
  154. package/tests/orchestrator-cleanup.test.mjs +358 -0
  155. package/tests/orchestrator-command.test.mjs +14 -0
  156. package/tests/orchestrator-persist.test.mjs +375 -0
  157. package/tests/orchestrator-tools.test.mjs +215 -0
  158. package/tests/orchestrator.test.mjs +396 -0
  159. package/tests/package.test.mjs +37 -0
  160. package/tests/pipeline.test.mjs +239 -0
  161. package/tests/planner-classification.test.mjs +81 -0
  162. package/tests/planner-split.test.mjs +67 -0
  163. package/tests/qoder-observer.test.mjs +266 -0
  164. package/tests/reassign-progression.test.mjs +104 -0
  165. package/tests/retry-escalation.test.mjs +120 -0
  166. package/tests/routing.test.mjs +110 -0
  167. package/tests/sqlite-concurrency.test.mjs +178 -0
  168. package/tests/task-global-e2e.test.mjs +63 -0
  169. package/tests/task-global-failed.test.mjs +134 -0
  170. package/tests/telemetry.test.mjs +173 -0
  171. package/tests/test-sync-pi.ps1 +56 -0
  172. package/tests/turn-budget.test.mjs +106 -0
@@ -0,0 +1,106 @@
1
+ // Subagent execution budget: complexity classification, per-role initial turns,
2
+ // deterministic progress evaluation, bounded extension, and timeout classification.
3
+ import test from 'node:test';
4
+ import assert from 'node:assert/strict';
5
+ import { classifyTaskComplexity, initialTurnBudget, progressScore, isNoProgressTimeout, COMPLEXITIES } from '../lib/orchestrator/turn-budget.mjs';
6
+ import { shouldMarkTaskGlobalFailure, isProtocolFailure, FAILURE_CLASSES } from '../lib/orchestrator/failures.mjs';
7
+ import { inspectPiEvents } from '../adapters/pi/lib/subagent.mjs';
8
+ import { planRules } from '../lib/orchestrator/planner.mjs';
9
+ import { loadRouting } from '../lib/routing.mjs';
10
+ import { loadAgents } from '../lib/agents.mjs';
11
+ import { resolve, dirname, join } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+
14
+ const kit = resolve(dirname(fileURLToPath(import.meta.url)), '..');
15
+ const routing = loadRouting(join(kit, 'routing/routing.json'));
16
+ const { agents } = loadAgents(join(kit, 'agents'), routing);
17
+ const RT = { max_turns: 12, extension_turns: 8, max_extensions: 2, absolute_max_turns: 32,
18
+ turn_budgets: { default: { simple: 12, normal: 16, heavy: 20, 'repo-history-heavy': 24 }, scout: { simple: 12, normal: 16, heavy: 20, 'repo-history-heavy': 24 }, coder: { simple: 16, normal: 20, heavy: 24, 'repo-history-heavy': 24 } } };
19
+
20
+ // ---------- complexity classification ----------
21
+ test('complexity: simple/normal/heavy/repo-history-heavy', () => {
22
+ assert.equal(classifyTaskComplexity({ title: 'x', goal: 'read one file', kind: 'investigate' }), 'normal');
23
+ assert.equal(classifyTaskComplexity({ title: 'x', goal: 'analyze the commit history and git log for preferences', kind: 'investigate' }), 'repo-history-heavy');
24
+ assert.equal(classifyTaskComplexity({ title: 'x', goal: 'survey across the whole repo and combine multiple modules', kind: 'investigate' }), 'heavy');
25
+ });
26
+
27
+ test('initial turn budget resolves role+complexity with fallbacks', () => {
28
+ assert.equal(initialTurnBudget(RT, 'scout', 'simple'), 12);
29
+ assert.equal(initialTurnBudget(RT, 'scout', 'repo-history-heavy'), 24);
30
+ assert.equal(initialTurnBudget(RT, 'coder', 'heavy'), 24);
31
+ assert.equal(initialTurnBudget(RT, 'unknown-role', 'normal'), 16); // default
32
+ assert.equal(initialTurnBudget({ max_turns: 12 }, 'scout', 'heavy'), 12); // no budgets -> max_turns
33
+ });
34
+
35
+ // ---------- progress evaluation ----------
36
+ test('progressScore: meaningful vs no-progress', () => {
37
+ assert.equal(progressScore({ toolCalls: 0, commands: [] }).meaningful, false);
38
+ assert.equal(progressScore({ toolCalls: 5, uniqueFiles: new Set(['a.js','b.js']), commands: ['git log','cat a'] }).meaningful, true);
39
+ assert.ok(progressScore({ toolCalls: 0 }).score < 0);
40
+ });
41
+
42
+ test('isNoProgressTimeout distinguishes progress from spinning', () => {
43
+ assert.equal(isNoProgressTimeout({ toolCalls: 0 }), true);
44
+ assert.equal(isNoProgressTimeout({ toolCalls: 6, uniqueFiles: new Set(['x']), commands: ['git log'] }), false);
45
+ });
46
+
47
+ // ---------- timeout classification ----------
48
+ test('timeout classes exist and classify correctly', () => {
49
+ assert.ok(FAILURE_CLASSES.includes('NO_PROGRESS_TIMEOUT'));
50
+ assert.ok(FAILURE_CLASSES.includes('PROGRESS_TIMEOUT'));
51
+ // protocol failure: no-progress advances candidate, progress is recoverable
52
+ assert.equal(isProtocolFailure('NO_PROGRESS_TIMEOUT'), true);
53
+ assert.equal(isProtocolFailure('PROGRESS_TIMEOUT'), false);
54
+ });
55
+
56
+ test('task-global marking: no-progress yes, progress no', () => {
57
+ assert.equal(shouldMarkTaskGlobalFailure('NO_PROGRESS_TIMEOUT'), false, 'missing telemetry cannot establish no progress');
58
+ assert.equal(shouldMarkTaskGlobalFailure('NO_PROGRESS_TIMEOUT', { toolCalls: 0, structuredProgress: false, hasFinalOutput: false }), true);
59
+ assert.equal(shouldMarkTaskGlobalFailure('PROGRESS_TIMEOUT'), false);
60
+ });
61
+
62
+ // ---------- planner sizing ----------
63
+ test('planner splits a multi-concern investigation instead of one giant scout task', () => {
64
+ const p = planRules('コミット履歴から僕の好みを推定して、UXを改善して', { agents });
65
+ const scouts = p.tasks.filter(t => t.agent === 'scout');
66
+ // history + ui concerns -> should produce >1 investigation task (split + synth)
67
+ assert.ok(scouts.length >= 2, `expected split investigation, got ${scouts.length} scout task(s)`);
68
+ // a simple single-concern request stays one scout task
69
+ const simple = planRules('Fix the failing average() test', { agents });
70
+ assert.equal(simple.tasks.filter(t => t.agent === 'scout').length, 1);
71
+ });
72
+
73
+ // ---------- inspectPiEvents telemetry ----------
74
+ test('inspectPiEvents captures tool names, unique files, commands', () => {
75
+ const events = [
76
+ { type: 'message_end', message: { role: 'assistant', content: [
77
+ { type: 'toolCall', name: 'ludi_exec', arguments: { command: 'git log --oneline' } },
78
+ { type: 'toolCall', name: 'read', arguments: { path: 'src/app.ts' } },
79
+ ] } },
80
+ { type: 'message_end', message: { role: 'assistant', content: [
81
+ { type: 'toolCall', name: 'read', arguments: { path: 'src/ui.ts' } },
82
+ { type: 'text', text: 'done' },
83
+ ] } },
84
+ ];
85
+ const seen = inspectPiEvents(events);
86
+ assert.equal(seen.turns, 2);
87
+ assert.equal(seen.toolCalls, 3);
88
+ assert.equal(seen.uniqueFilesInspected, 2);
89
+ assert.equal(seen.toolNames.read, 2);
90
+ assert.equal(seen.toolNames.ludi_exec, 1);
91
+ assert.deepEqual(seen.commands, ['git log --oneline']);
92
+ });
93
+
94
+ // ---------- bounded extension semantics ----------
95
+ test('bounded extension: no-progress stops, progress extends within absolute max', () => {
96
+ // Simulated: a no-progress agent at turn cap gets NO extension.
97
+ const noProg = progressScore({ toolCalls: 0, commands: [] });
98
+ assert.equal(noProg.meaningful, false); // -> would stop, NO_PROGRESS_TIMEOUT
99
+ // A progressing agent gets extended but capped by absolute_max_turns.
100
+ const cap = RT.absolute_max_turns;
101
+ let turnCap = initialTurnBudget(RT, 'scout', 'repo-history-heavy'); // 24
102
+ let ext = 0;
103
+ while (ext < RT.max_extensions && turnCap < cap) { ext++; turnCap = Math.min(turnCap + RT.extension_turns, cap); }
104
+ assert.equal(turnCap, Math.min(24 + 2 * 8, 32)); // 24 -> 32 (capped), extensions bounded
105
+ assert.ok(turnCap <= RT.absolute_max_turns);
106
+ });