@galaxy-stack/ai-coder-core 0.3.0-alpha.1 → 0.3.0-alpha.8

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 (122) hide show
  1. package/CHANGELOG.d/2026-09-19-research-rejection-evidence.md +15 -0
  2. package/CHANGELOG.d/2026-09-21-evidence-missing-remediation.md +15 -0
  3. package/CHANGELOG.d/2026-09-21-observation-nudge-context.md +12 -0
  4. package/CHANGELOG.d/2026-09-22-model-retry-budget.md +18 -0
  5. package/CHANGELOG.d/2026-09-22-no-progress-recovery-turn.md +19 -0
  6. package/CHANGELOG.d/2026-09-23-agent-platform.md +5 -0
  7. package/CHANGELOG.d/2026-09-23-conservative-output-reserve.md +16 -0
  8. package/CHANGELOG.d/2026-09-24-approval-workspace-review.md +7 -0
  9. package/CHANGELOG.d/2026-09-24-incremental-ollama.md +5 -0
  10. package/CHANGELOG.md +71 -1
  11. package/README.md +78 -4
  12. package/dist/adapters/node/config/manual-provider-config.d.ts +19 -0
  13. package/dist/adapters/node/config/manual-provider-config.d.ts.map +1 -0
  14. package/dist/adapters/node/config/manual-provider-config.js +91 -0
  15. package/dist/adapters/node/config/manual-provider-config.js.map +1 -0
  16. package/dist/adapters/node/host/command-containment.d.ts +45 -0
  17. package/dist/adapters/node/host/command-containment.d.ts.map +1 -0
  18. package/dist/adapters/node/host/command-containment.js +580 -0
  19. package/dist/adapters/node/host/command-containment.js.map +1 -0
  20. package/dist/adapters/node/host/content-hash.d.ts +2 -0
  21. package/dist/adapters/node/host/content-hash.d.ts.map +1 -0
  22. package/dist/adapters/node/host/content-hash.js +5 -0
  23. package/dist/adapters/node/host/content-hash.js.map +1 -0
  24. package/dist/adapters/node/host/file-run-store.d.ts +29 -0
  25. package/dist/adapters/node/host/file-run-store.d.ts.map +1 -0
  26. package/dist/adapters/node/host/file-run-store.js +94 -0
  27. package/dist/adapters/node/host/file-run-store.js.map +1 -0
  28. package/dist/adapters/node/host/host-environment.d.ts +9 -0
  29. package/dist/adapters/node/host/host-environment.d.ts.map +1 -0
  30. package/dist/adapters/node/host/host-environment.js +29 -0
  31. package/dist/adapters/node/host/host-environment.js.map +1 -0
  32. package/dist/adapters/node/host/node-command-port.d.ts +21 -0
  33. package/dist/adapters/node/host/node-command-port.d.ts.map +1 -0
  34. package/dist/adapters/node/host/node-command-port.js +281 -0
  35. package/dist/adapters/node/host/node-command-port.js.map +1 -0
  36. package/dist/adapters/node/host/node-workspace-evidence-verifier.d.ts +22 -0
  37. package/dist/adapters/node/host/node-workspace-evidence-verifier.d.ts.map +1 -0
  38. package/dist/adapters/node/host/node-workspace-evidence-verifier.js +384 -0
  39. package/dist/adapters/node/host/node-workspace-evidence-verifier.js.map +1 -0
  40. package/dist/adapters/node/host/node-workspace-port.d.ts +87 -0
  41. package/dist/adapters/node/host/node-workspace-port.d.ts.map +1 -0
  42. package/dist/adapters/node/host/node-workspace-port.js +860 -0
  43. package/dist/adapters/node/host/node-workspace-port.js.map +1 -0
  44. package/dist/adapters/node/host/node-workspace-snapshot.d.ts +61 -0
  45. package/dist/adapters/node/host/node-workspace-snapshot.d.ts.map +1 -0
  46. package/dist/adapters/node/host/node-workspace-snapshot.js +281 -0
  47. package/dist/adapters/node/host/node-workspace-snapshot.js.map +1 -0
  48. package/dist/adapters/node/host/path-scope.d.ts +17 -0
  49. package/dist/adapters/node/host/path-scope.d.ts.map +1 -0
  50. package/dist/adapters/node/host/path-scope.js +89 -0
  51. package/dist/adapters/node/host/path-scope.js.map +1 -0
  52. package/dist/adapters/node/host/project-tools.d.ts +42 -0
  53. package/dist/adapters/node/host/project-tools.d.ts.map +1 -0
  54. package/dist/adapters/node/host/project-tools.js +362 -0
  55. package/dist/adapters/node/host/project-tools.js.map +1 -0
  56. package/dist/adapters/node/mcp/mcp-client.d.ts +206 -0
  57. package/dist/adapters/node/mcp/mcp-client.d.ts.map +1 -0
  58. package/dist/adapters/node/mcp/mcp-client.js +128 -0
  59. package/dist/adapters/node/mcp/mcp-client.js.map +1 -0
  60. package/dist/adapters/node/mcp/oauth-provider.d.ts +39 -0
  61. package/dist/adapters/node/mcp/oauth-provider.d.ts.map +1 -0
  62. package/dist/adapters/node/mcp/oauth-provider.js +168 -0
  63. package/dist/adapters/node/mcp/oauth-provider.js.map +1 -0
  64. package/dist/adapters/node/memory/sqlite-memory.d.ts +22 -0
  65. package/dist/adapters/node/memory/sqlite-memory.d.ts.map +1 -0
  66. package/dist/adapters/node/memory/sqlite-memory.js +83 -0
  67. package/dist/adapters/node/memory/sqlite-memory.js.map +1 -0
  68. package/dist/adapters/node/provider/ollama-chat-stream.d.ts +17 -0
  69. package/dist/adapters/node/provider/ollama-chat-stream.d.ts.map +1 -0
  70. package/dist/adapters/node/provider/ollama-chat-stream.js +176 -0
  71. package/dist/adapters/node/provider/ollama-chat-stream.js.map +1 -0
  72. package/dist/adapters/node/provider/ollama-coding-model.d.ts +89 -0
  73. package/dist/adapters/node/provider/ollama-coding-model.d.ts.map +1 -0
  74. package/dist/adapters/node/provider/ollama-coding-model.js +464 -0
  75. package/dist/adapters/node/provider/ollama-coding-model.js.map +1 -0
  76. package/dist/adapters/node/provider/ollama-research-port.d.ts +32 -0
  77. package/dist/adapters/node/provider/ollama-research-port.d.ts.map +1 -0
  78. package/dist/adapters/node/provider/ollama-research-port.js +346 -0
  79. package/dist/adapters/node/provider/ollama-research-port.js.map +1 -0
  80. package/dist/adapters/node/skills/directory-skills.d.ts +12 -0
  81. package/dist/adapters/node/skills/directory-skills.d.ts.map +1 -0
  82. package/dist/adapters/node/skills/directory-skills.js +90 -0
  83. package/dist/adapters/node/skills/directory-skills.js.map +1 -0
  84. package/dist/adapters/node/tools/tool-executor.d.ts +91 -0
  85. package/dist/adapters/node/tools/tool-executor.d.ts.map +1 -0
  86. package/dist/adapters/node/tools/tool-executor.js +948 -0
  87. package/dist/adapters/node/tools/tool-executor.js.map +1 -0
  88. package/dist/adapters/node/tools/workspace-review.d.ts +13 -0
  89. package/dist/adapters/node/tools/workspace-review.d.ts.map +1 -0
  90. package/dist/adapters/node/tools/workspace-review.js +81 -0
  91. package/dist/adapters/node/tools/workspace-review.js.map +1 -0
  92. package/dist/agent/index.d.ts +79 -0
  93. package/dist/agent/index.d.ts.map +1 -0
  94. package/dist/agent/index.js +97 -0
  95. package/dist/agent/index.js.map +1 -0
  96. package/dist/approval/approval-policy.d.ts.map +1 -1
  97. package/dist/approval/approval-policy.js +4 -1
  98. package/dist/approval/approval-policy.js.map +1 -1
  99. package/dist/context/checkpoint.d.ts +2 -0
  100. package/dist/context/checkpoint.d.ts.map +1 -1
  101. package/dist/context/checkpoint.js +5 -2
  102. package/dist/context/checkpoint.js.map +1 -1
  103. package/dist/context/context-manager.d.ts.map +1 -1
  104. package/dist/context/context-manager.js +21 -8
  105. package/dist/context/context-manager.js.map +1 -1
  106. package/dist/context/context-profile.d.ts +1 -1
  107. package/dist/context/context-profile.js +2 -2
  108. package/dist/prompt/prompt-assembler.d.ts +1 -0
  109. package/dist/prompt/prompt-assembler.d.ts.map +1 -1
  110. package/dist/prompt/prompt-assembler.js +16 -2
  111. package/dist/prompt/prompt-assembler.js.map +1 -1
  112. package/dist/runtime/run-controller.d.ts.map +1 -1
  113. package/dist/runtime/run-controller.js +131 -24
  114. package/dist/runtime/run-controller.js.map +1 -1
  115. package/dist/runtime/runtime-types.d.ts +20 -0
  116. package/dist/runtime/runtime-types.d.ts.map +1 -1
  117. package/dist/tools/tool-registry.js +1 -1
  118. package/dist/tools/tool-registry.js.map +1 -1
  119. package/docs/AGENT_PLATFORM.md +91 -0
  120. package/docs/GALAXY_AGENT_PLATFORM_PLAN.md +353 -0
  121. package/docs/GALAXY_AGENT_PLATFORM_TODO.md +176 -0
  122. package/package.json +19 -5
@@ -0,0 +1,15 @@
1
+ # Lưu evidence khi citation bị từ chối (2026-09-19 23:15 +07:00)
2
+
3
+ ### Added
4
+
5
+ - Event `completion_rejected` lưu nguyên candidate và ba tập URL: fetch thành
6
+ công, chỉ xuất hiện ở search, và citation không có fetch evidence; source
7
+ ledger giữ `toolCallId` và `contentHash` để ghép lại tool result.
8
+ - Feedback cho model liệt kê nguồn đã fetch để model sửa report thay vì lặp
9
+ nguyên candidate hoặc tự đoán URL khác. Đây là phần core của INC-010 trong
10
+ `galaxy-code/docs/TEST_FAILURE_ANALYSIS.md`.
11
+
12
+ ### Tests
13
+
14
+ - Regression runtime tạo search-only + fetched source, từ chối candidate đầu,
15
+ kiểm tra event/feedback có đủ ledger, rồi hoàn thành bằng citation đã fetch.
@@ -0,0 +1,15 @@
1
+ # Remediation cho RESEARCH_EVIDENCE_MISSING (2026-09-21 02:20 +07:00)
2
+
3
+ ### Changed
4
+
5
+ - Completion rejection giờ có dòng remediation riêng cho `RESEARCH_EVIDENCE_MISSING`,
6
+ nêu tên tool (`search_web` cho discovery, `fetch_url` cho đọc nguồn) và nói rõ
7
+ fetch-only không thỏa search requirement. Trước đây issue chỉ nêu số lượng
8
+ ("search calls 0/1") nên model dưới compaction cao không có hướng hành động
9
+ (run [OycseO](../../galaxy-code/.galaxy/audit/2026-09-20T18-36-41-606Z-OycseO/summary.json)
10
+ durable repeat-3: 0 search, 3 fetch, 2 rejection, NO_PROGRESS).
11
+
12
+ ### Tests
13
+
14
+ - Core 108/108 pass, thêm regression: model fetch-only bị từ chối, nhận feedback
15
+ nêu tên tool, gọi `search_web` sau rejection rồi hoàn thành.
@@ -0,0 +1,12 @@
1
+ # Nudge nhận diện bằng arguments hash (2026-09-21 00:55 +07:00)
2
+
3
+ ### Changed
4
+
5
+ - Advisory observation nudge giờ kèm `arguments_hash` để model thấy chính xác
6
+ lệnh nào đang lặp, thay vì chỉ biết có sự lặp. Đây là phiên bản tiết kiệm
7
+ budget của tư tưởng deepseek-harness "giữ full canonical arguments để nhận
8
+ diện": nhận diện vẫn dùng toàn bộ arguments, lời nhắc chỉ mang hash.
9
+
10
+ ### Tests
11
+
12
+ - Core 107/107 pass (`npm test`), không có test assert nội dung nudge cũ bị phá.
@@ -0,0 +1,18 @@
1
+ # Retry delay theo scenario budget + deadline-aware skip (2026-09-22 07:25 +07:00)
2
+
3
+ ### Changed
4
+
5
+ - Bảng backoff giữa các model request retry trở thành budget knob
6
+ `modelRetryDelaysMs` (1-8 số nguyên dương, tối đa 600 000 ms mỗi entry) thay
7
+ vì `MODEL_RETRY_DELAYS` hardcode. Schedule được dùng theo thứ tự attempt và
8
+ báo trong sự kiện `model_retry`.
9
+ - Retry deadline-aware: trước khi sleep, runtime kiểm tra budget còn lại; nếu
10
+ `deadline - now <= delay + thời gian attempt vừa fail` thì bỏ attempt, fail
11
+ loud với message nêu rõ còn bao nhiêu budget, backoff bao nhiêu và attempt
12
+ trước kéo dài bao nhiêu, thay vì dispatch một request chắc chắn chết.
13
+
14
+ ### Tests
15
+
16
+ - Core 111/111 pass: budget schedule được dùng đúng thứ tự và report qua
17
+ `onEvent`; retry không đủ budget bị skip trước khi sleep; 6 case schedule
18
+ invalid fail loud tại validation.
@@ -0,0 +1,19 @@
1
+ # Recovery turn trước no-progress pause (2026-09-22 01:07 +07:00)
2
+
3
+ ### Changed
4
+
5
+ - Khi `noProgressEpisodes` chạm ngưỡng pause lần đầu, runtime không pause ngay
6
+ mà chèn một feedback turn `[GALAXY NO-PROGRESS RECOVERY]` liệt kê failed
7
+ tools của round kèm remediation (re-read vùng đúng, whole-file write, đổi
8
+ nguồn), rồi cho model đúng một round nữa. Nếu round đó vẫn không tiến triển
9
+ thì pause như cũ. Đây là phiên bản two-strike của Gemini CLI
10
+ loopDetectionService cho Galaxy: giữ nguyên ngưỡng 2/2/2, không bỏ pause,
11
+ chỉ thêm đúng một cơ hội phục hồi có kiểm soát.
12
+ - Trace runtime ghi `policy_decision` với `action:
13
+ "no_progress_recovery_turn"` để audit phân biệt lượt recovery với lượt pause.
14
+
15
+ ### Tests
16
+
17
+ - Core 108/108 pass. Hash-cycle, resume-cycle, observation recovery, validation
18
+ recovery có fixture xác minh: recovery round được cấp đúng một lần; round
19
+ phục hồi thành công (đổi chiến lược) thì complete; round vẫn lặp thì pause.
@@ -0,0 +1,5 @@
1
+ # Agent platform foundation
2
+
3
+ Add general agent profiles, optional MCP/skill/SQLite adapters and move the private live/replay lab into testing.
4
+
5
+ Package and repository names are unchanged. See README and architecture/migration docs for current limitations and the release order.
@@ -0,0 +1,16 @@
1
+ ## 0.3.0-alpha.7 — 2026-09-23 07:00 +07:00
2
+
3
+ ### Conservative profile output reserve bump (Mode B fix)
4
+
5
+ **Lỗi:** `INVALID_MODEL_STREAM "length"` — model dùng hết output tokens (conservative profile chỉ reserve 24 000) chỉ để sinh thinking + tool-call JSON, chưa kịp write file nào (0 writes trên 14 chat requests).
6
+
7
+ **Hệ thống khác xử lý:**
8
+ - Codex CLI: tách budget riêng cho thinking và tool-call JSON, không chia sẻ cùng một output cap.
9
+ - Claude Code: mỗi tool call có output budget riêng, không trộn với thinking.
10
+ - Gemini CLI: dùng `thinking_config` để cấp thinking budget riêng khỏi output budget.
11
+
12
+ **Fix Galaxy:** nâng `outputReserveTokens` của profile `conservative` từ 24 000 lên 32 768 (khớp balanced/extended). Không đổi toolDefinitionBudget hay softInputTokens. `AI_CODER_CONTEXT_PROFILE_CONFIG_VERSION` bump thành `"1.1.0"`.
13
+
14
+ **File sửa:** `src/context/context-profile.ts`.
15
+
16
+ **Test:** 112/112 core offline (chạy sau build). Không cần unit test mới — profile không được assert trực tiếp trong unit suite.
@@ -0,0 +1,7 @@
1
+ # Request-scoped approvals and scratch workspace review
2
+
3
+ Abort host approval prompts when their request expires or resolves; reject late approvals without canceling the parent run. Allow NodeToolExecutor hosts to choose their approval timeout.
4
+
5
+ Add the optional NodeWorkspaceReviewExecutor for stable, bounded before/after text review without Git. It attests real diff-review evidence without weakening validation requirements. Update the prompt to use this tool when available.
6
+
7
+ Validation: core verify (121 tests), 16 lab executor regressions and CLI end-to-end scratch-project completion, including a live provider run.
@@ -0,0 +1,5 @@
1
+ # Incremental Ollama streaming
2
+
3
+ Decode NDJSON as bytes arrive instead of buffering the complete HTTP response. Share the stateful normalizer with replay, retain byte limits and UTF-8 correctness, and cancel body readers when requests or consumers stop. Late errors do not emit a duplicate started event.
4
+
5
+ Validation: core verify, 13 transport tests, 7 normalizer tests and recorded replay; delayed HTTP→CLI rendering verifies deltas before EOF.
package/CHANGELOG.md CHANGED
@@ -7,7 +7,77 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
  Times are recorded in Asia/Ho_Chi_Minh (+07:00). Per-fix fragments are filed in
8
8
  [CHANGELOG.d](CHANGELOG.d/README.md) and compiled here at release time.
9
9
 
10
- ## [0.3.0-alpha.1] - 2026-09-19 12:15 +07:00 (unpublished; first alpha-tagged release)
10
+ ## [0.3.0-alpha.7] - 2026-09-23 07:00 +07:00
11
+
12
+ ### Fixed
13
+
14
+ - Conservative context profile `outputReserveTokens` raised from 24 000 to
15
+ 32 768 (matching balanced/extended) to prevent `INVALID_MODEL_STREAM
16
+ "length"` failures when the model spends the full reserve on thinking plus
17
+ tool-call JSON before writing any file. Profile config version bumped to
18
+ `1.1.0`. See
19
+ [CHANGELOG.d fragment](CHANGELOG.d/2026-09-23-conservative-output-reserve.md).
20
+
21
+ ## [0.3.0-alpha.6] - 2026-09-22 07:25 +07:00
22
+
23
+ ### Changed
24
+
25
+ - Model retry backoff is now a budget knob (`modelRetryDelaysMs`, 1-8 entries,
26
+ up to 600 000 ms each) consumed in order by retry attempt and reported in
27
+ `model_retry` events, replacing the hardcoded delay table. Retries are also
28
+ deadline-aware: when the remaining run budget cannot cover the backoff plus
29
+ the failed attempt's duration, the runtime skips the attempt and fails loud
30
+ with the full budget math. See
31
+ [CHANGELOG.d fragment](CHANGELOG.d/2026-09-22-model-retry-budget.md).
32
+
33
+ ## [0.3.0-alpha.5] - 2026-09-22 01:07 +07:00
34
+
35
+ ### Changed
36
+
37
+ - No-progress pause now grants exactly one recovery feedback round before
38
+ pausing: the runtime injects `[GALAXY NO-PROGRESS RECOVERY]` listing the
39
+ round's failed tools with their remediation and expects a materially
40
+ different strategy. Thresholds (2/2/2), pause semantics, and
41
+ fail-loud-after-budget behavior are unchanged; a trace
42
+ `policy_decision(action: "no_progress_recovery_turn")` marks the granted
43
+ round. Inspired by Gemini CLI's two-strike loop detection; see
44
+ [CHANGELOG.d fragment](CHANGELOG.d/2026-09-22-no-progress-recovery-turn.md).
45
+
46
+ ## [0.3.0-alpha.4] - 2026-09-21 02:20 +07:00
47
+
48
+ ### Changed
49
+
50
+ - `RESEARCH_EVIDENCE_MISSING` completion rejections now carry actionable
51
+ remediation naming `search_web` (discovery) and `fetch_url` (reading), and
52
+ state that fetch-only runs do not satisfy a search requirement.
53
+
54
+ ## [0.3.0-alpha.3] - 2026-09-21 00:55 +07:00
55
+
56
+ ### Changed
57
+
58
+ - Advisory observation nudges include the repeated call's `arguments_hash` so
59
+ the model can identify exactly which call is repeating while the guard keeps
60
+ recognition on the full canonical arguments.
61
+
62
+ ## [0.3.0-alpha.2] - 2026-09-19 23:15 +07:00
63
+
64
+ ### Added
65
+
66
+ - `completion_rejected` runtime events now retain the rejected candidate and a
67
+ structured research ledger: successfully fetched URLs, search-only URLs,
68
+ unsupported citations, and source tool-call correlation. Hosts can persist
69
+ enough evidence to diagnose a repeated citation failure without
70
+ reconstructing model output from prose.
71
+ - README installation, lifecycle usage, public API, adapter ownership, and
72
+ alpha-upgrade guidance.
73
+
74
+ ### Changed
75
+
76
+ - Research citation rejection feedback lists the successfully fetched sources
77
+ available to the model and tells it to fetch or remove unsupported URLs.
78
+ Search snippets and plausible URLs remain insufficient completion evidence.
79
+
80
+ ## [0.3.0-alpha.1] - 2026-09-19 12:17 +07:00 (published; first alpha-tagged release)
11
81
 
12
82
  The first release after `0.1.0` is alpha-tagged because the no-progress guard
13
83
  policy changes the default runtime behavior. All changes since `0.1.0` ship in
package/README.md CHANGED
@@ -44,6 +44,70 @@ Pre-release versions publish under the `alpha` dist tag, so
44
44
  `npm install @galaxy-stack/ai-coder-core@latest` never jumps to an unverified
45
45
  alpha.
46
46
 
47
+ ## Installation
48
+
49
+ Install the current development line explicitly; `latest` intentionally stays
50
+ on the last non-alpha release:
51
+
52
+ ```sh
53
+ npm install @galaxy-stack/ai-coder-core@alpha
54
+ ```
55
+
56
+ The package is ESM-only and requires Node.js 20 or newer. It does not bundle a
57
+ model provider, filesystem adapter, command runner, credential store, or UI.
58
+ Each host supplies those capabilities through typed ports.
59
+
60
+ ## Basic usage
61
+
62
+ `AiCoderRunController` owns each run lifecycle; one controller may host
63
+ multiple distinct run IDs, while every run still has exactly one AI. A host
64
+ constructs the adapter set once, passes a complete request to `start`, observes
65
+ typed runtime events, and awaits the handle result. The same request fields
66
+ plus a trusted durable checkpoint are used by `resume`.
67
+
68
+ ```ts
69
+ import {
70
+ AiCoderRunController,
71
+ type AiCoderRunDependencies,
72
+ type AiCoderRunRequest,
73
+ } from "@galaxy-stack/ai-coder-core";
74
+
75
+ export async function runCoder(
76
+ dependencies: AiCoderRunDependencies,
77
+ request: AiCoderRunRequest,
78
+ ) {
79
+ const controller = new AiCoderRunController(dependencies);
80
+ const handle = controller.start(request);
81
+
82
+ // A UI may call handle.pause(), handle.cancel(), or
83
+ // handle.resolveApproval(requestId, decision) while result is pending.
84
+ return await handle.result;
85
+ }
86
+ ```
87
+
88
+ Required dependencies are a `CodingModelAdapter` and an
89
+ `AiCoderRuntimeToolExecutor`. Production hosts should also provide a trusted
90
+ run store, trace port, workspace verifier, and output-spill adapter when their
91
+ completion requirements enable those guarantees. `galaxy-code` is the
92
+ reference implementation and conformance test host.
93
+
94
+ ## Public API
95
+
96
+ | Export | Purpose |
97
+ | --- | --- |
98
+ | `AiCoderRunController` | Start, resume, pause, cancel, and resolve approvals for a run. |
99
+ | `AiCoderRunRequest` / `AiCoderRunResult` | Typed task input, budgets, completion requirements, and terminal result. |
100
+ | `AiCoderRunDependencies` | Model, tools, persistence, trace, workspace verification, clock, and event adapters. |
101
+ | `AiCoderRuntimeEvent` | Model, tool, checkpoint, retry, context-pressure, state, and completion-rejection telemetry. |
102
+ | `evaluateAiCoderCompletion` | Pure completion-evidence evaluation for tests and host diagnostics. |
103
+ | `createAiCoderRunCheckpoint` / `assertAiCoderRunCheckpoint` | Durable checkpoint creation and validation. |
104
+ | `AiCoderToolRegistry` | Canonical tool registration and model-facing registry snapshots. |
105
+
106
+ Focused subpath exports are available at `/ports`, `/tools`, `/context`,
107
+ `/prompt`, `/approval`, `/retrieval`, and `/runtime`. The API is pre-1.0:
108
+ pin an exact alpha version in production-like hosts and review
109
+ [CHANGELOG.md](CHANGELOG.md) before upgrading.
110
+
47
111
  ## Non-negotiable invariants
48
112
 
49
113
  1. One AI owns the run state. There is no hidden planner/reviewer agent.
@@ -138,7 +202,7 @@ src/
138
202
 
139
203
  ## Development
140
204
 
141
- Requires Node.js 20 or newer.
205
+ The platform-neutral root supports Node.js 20+. Full development checks and optional SQLite adapters require Node.js 22.13+ (CI covers Node 22 and 24).
142
206
 
143
207
  ```bash
144
208
  npm install
@@ -160,9 +224,19 @@ before publishing or consuming the package from another repository.
160
224
  commit and source fingerprint. The reporter is development-only and runs without
161
225
  a galaxy-code checkout. Raw `tsx --test` invocations bypass this reporter.
162
226
 
163
- The deterministic end-to-end host gate lives in `galaxy-code`:
227
+ The deterministic/live/replay host gate lives in the private `testing/` workspace:
164
228
 
165
229
  ```bash
166
- cd ../../galaxy-code
167
- npm run check
230
+ cd testing
231
+ npm ci
232
+ npm run test:local
168
233
  ```
234
+
235
+
236
+ ## Agent platform and optional adapters
237
+
238
+ The runtime also supports `prompt.agentProfile: "assistant" | "research"` alongside the default coding profile. `contextData` is bounded, snapshotted and wrapped as untrusted context; it never changes approval or validation evidence.
239
+
240
+ `@galaxy-stack/ai-coder-core/agent` exports `AgentMemoryPort`, `AgentSkillsPort`, `AgentToolExecutor`, `CompositeToolExecutor`, memory/skill tool factories and profile types. Optional `.../adapters/node/*` exports provide the shared Ollama/Node tools, MCP SDK client, directory skill loader and SQLite memory. They are not imported through the platform-neutral root. The SQLite adapter requires Node >=22.13.
241
+
242
+ The executable lab moved into [testing/](testing/README.md); it is private and excluded from the npm package. Production CLI/TUI lives in the sibling `galaxy-code` repository. See [docs/AGENT_PLATFORM.md](docs/AGENT_PLATFORM.md) for APIs, current scope, commands and rollout boundaries.
@@ -0,0 +1,19 @@
1
+ export type CredentialSource = "environment" | "manual-config" | "none";
2
+ export interface ResolvedOllamaConnection {
3
+ readonly apiKey?: string;
4
+ readonly baseUrl: string;
5
+ readonly configPath: string;
6
+ readonly credentialSource: CredentialSource;
7
+ readonly model: string;
8
+ }
9
+ export interface ResolveOllamaConnectionOptions {
10
+ readonly baseUrl?: string;
11
+ readonly configPath?: string;
12
+ readonly environment?: Readonly<Record<string, string | undefined>>;
13
+ readonly model?: string;
14
+ }
15
+ export declare function resolveOllamaConnection(options?: ResolveOllamaConnectionOptions): Promise<ResolvedOllamaConnection>;
16
+ export declare function publicOllamaConnection(connection: ResolvedOllamaConnection): Omit<ResolvedOllamaConnection, "apiKey" | "configPath"> & Readonly<{
17
+ configPath: string;
18
+ }>;
19
+ //# sourceMappingURL=manual-provider-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual-provider-config.d.ts","sourceRoot":"","sources":["../../../../src/adapters/node/config/manual-provider-config.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,eAAe,GAAG,MAAM,CAAC;AAExE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,gBAAgB,EAAE,gBAAgB,CAAC;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC;IACpE,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAkDD,wBAAsB,uBAAuB,CAC3C,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,wBAAwB,CAAC,CA2BnC;AAED,wBAAgB,sBAAsB,CACpC,UAAU,EAAE,wBAAwB,GACnC,IAAI,CAAC,wBAAwB,EAAE,QAAQ,GAAG,YAAY,CAAC,GAAG,QAAQ,CAAC;IAAE,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC,CAO5F"}
@@ -0,0 +1,91 @@
1
+ import { DEFAULT_AI_CODER_CORE_SETTINGS } from "../../../index.js";
2
+ import { readFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { join } from "node:path";
5
+ function isObject(value) {
6
+ return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ }
8
+ function optionalNonEmpty(value) {
9
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
10
+ }
11
+ function safeProviderBaseUrl(value) {
12
+ let parsed;
13
+ try {
14
+ parsed = new URL(value);
15
+ }
16
+ catch {
17
+ throw new Error("Ollama base URL must be an absolute HTTP(S) URL.");
18
+ }
19
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
20
+ throw new Error("Ollama base URL must use HTTP or HTTPS.");
21
+ }
22
+ if (parsed.username || parsed.password || parsed.search || parsed.hash) {
23
+ throw new Error("Ollama base URL must not contain credentials, query parameters, or a fragment.");
24
+ }
25
+ return parsed.href.replace(/\/+$/, "");
26
+ }
27
+ async function readManualAgent(configPath) {
28
+ let raw;
29
+ try {
30
+ raw = await readFile(configPath, "utf8");
31
+ }
32
+ catch (error) {
33
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT")
34
+ return null;
35
+ throw new Error(`Unable to read Galaxy manual config: ${error instanceof Error ? error.message : String(error)}`);
36
+ }
37
+ if (Buffer.byteLength(raw, "utf8") > 1024 * 1024)
38
+ throw new Error("Galaxy manual config exceeds 1 MiB.");
39
+ let parsed;
40
+ try {
41
+ parsed = JSON.parse(raw);
42
+ }
43
+ catch {
44
+ throw new Error("Galaxy manual config is not valid JSON.");
45
+ }
46
+ if (!isObject(parsed) || !Array.isArray(parsed.agent)) {
47
+ throw new Error("Galaxy manual config must contain an agent array.");
48
+ }
49
+ const manual = parsed.agent.find((entry) => isObject(entry) && entry.type === "manual");
50
+ if (manual === undefined)
51
+ return null;
52
+ if (!isObject(manual))
53
+ throw new Error("Galaxy manual provider entry is invalid.");
54
+ return manual;
55
+ }
56
+ export async function resolveOllamaConnection(options = {}) {
57
+ const configPath = options.configPath ?? join(homedir(), ".galaxy", "config.json");
58
+ const manual = await readManualAgent(configPath);
59
+ const manualApiKey = optionalNonEmpty(manual?.apiKey);
60
+ const environmentApiKey = optionalNonEmpty((options.environment ?? process.env).OLLAMA_API_KEY);
61
+ const apiKey = manualApiKey ?? environmentApiKey;
62
+ const credentialSource = manualApiKey !== undefined
63
+ ? "manual-config"
64
+ : environmentApiKey !== undefined
65
+ ? "environment"
66
+ : "none";
67
+ const baseUrl = safeProviderBaseUrl(options.baseUrl
68
+ ?? optionalNonEmpty(manual?.baseUrl)
69
+ ?? DEFAULT_AI_CODER_CORE_SETTINGS.singleAgent.baseUrl);
70
+ const model = options.model
71
+ ?? optionalNonEmpty(manual?.model)
72
+ ?? DEFAULT_AI_CODER_CORE_SETTINGS.singleAgent.model;
73
+ if (model.trim().length === 0)
74
+ throw new Error("Ollama model must be non-empty.");
75
+ return Object.freeze({
76
+ ...(apiKey === undefined ? {} : { apiKey }),
77
+ baseUrl,
78
+ configPath,
79
+ credentialSource,
80
+ model: model.trim(),
81
+ });
82
+ }
83
+ export function publicOllamaConnection(connection) {
84
+ return Object.freeze({
85
+ baseUrl: connection.baseUrl,
86
+ configPath: connection.configPath.replace(homedir(), "~"),
87
+ credentialSource: connection.credentialSource,
88
+ model: connection.model,
89
+ });
90
+ }
91
+ //# sourceMappingURL=manual-provider-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manual-provider-config.js","sourceRoot":"","sources":["../../../../src/adapters/node/config/manual-provider-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ export type CommandContainmentMode = "best_effort" | "required";
2
+ export type CommandContainmentBackend = "linux_bubblewrap" | "macos_sandbox_exec" | "none";
3
+ export interface CommandContainmentProbeResult {
4
+ readonly available: boolean;
5
+ readonly backend: CommandContainmentBackend;
6
+ readonly descendantChildSpawned: boolean;
7
+ readonly descendantQuiescent: boolean;
8
+ readonly executable: string | null;
9
+ readonly hardLinkWriteDenied: boolean;
10
+ readonly networkDenied: boolean;
11
+ readonly outsideWriteDenied: boolean;
12
+ readonly privateTempWrite: boolean;
13
+ readonly reason: string | null;
14
+ readonly systemRead: boolean;
15
+ readonly toolchainExecution: boolean;
16
+ readonly verified: boolean;
17
+ readonly workspaceWrite: boolean;
18
+ }
19
+ export interface CommandContainmentStatus {
20
+ readonly active: boolean;
21
+ readonly backend: CommandContainmentBackend;
22
+ readonly executable: string | null;
23
+ readonly filesystemReads: "host_visible" | "system_and_workspace";
24
+ readonly filesystemWrites: "uncontained" | "workspace_and_private_temp";
25
+ readonly mode: CommandContainmentMode;
26
+ readonly network: "denied" | "uncontained";
27
+ readonly reason: string | null;
28
+ readonly state: "active" | "probe_failed" | "unavailable" | "unverified";
29
+ readonly verified: boolean;
30
+ }
31
+ /**
32
+ * Run the host conformance check once per process. A binary merely existing is
33
+ * not enough. Only a backend that passes every probe assertion can activate.
34
+ */
35
+ export declare function probeCommandContainment(): Promise<CommandContainmentProbeResult>;
36
+ export declare function containmentStatus(mode: CommandContainmentMode, probe: CommandContainmentProbeResult): CommandContainmentStatus;
37
+ export declare function buildBubblewrapArguments(input: Readonly<{
38
+ command: string;
39
+ commandArguments: readonly string[];
40
+ cwd: string;
41
+ environment: NodeJS.ProcessEnv;
42
+ workspace: string;
43
+ }>): readonly string[];
44
+ export declare function assertWorkspaceHasNoHardLinks(workspace: string): Promise<void>;
45
+ //# sourceMappingURL=command-containment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-containment.d.ts","sourceRoot":"","sources":["../../../../src/adapters/node/host/command-containment.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEhE,MAAM,MAAM,yBAAyB,GACjC,kBAAkB,GAClB,oBAAoB,GACpB,MAAM,CAAC;AAEX,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;IAC5C,QAAQ,CAAC,sBAAsB,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,eAAe,EAAE,cAAc,GAAG,sBAAsB,CAAC;IAClE,QAAQ,CAAC,gBAAgB,EAAE,aAAa,GAAG,4BAA4B,CAAC;IACxE,QAAQ,CAAC,IAAI,EAAE,sBAAsB,CAAC;IACtC,QAAQ,CAAC,OAAO,EAAE,QAAQ,GAAG,aAAa,CAAC;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC;IACzE,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAohBD;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,6BAA6B,CAAC,CAGtF;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,sBAAsB,EAC5B,KAAK,EAAE,6BAA6B,GACnC,wBAAwB,CAmC1B;AAMD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,QAAQ,CAAC;IACvD,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC,UAAU,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,GAAG,SAAS,MAAM,EAAE,CAuBrB;AAED,wBAAsB,6BAA6B,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBpF"}