@ddse/acm-aicoder 0.5.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.
- package/.aicoder/index.json +304 -0
- package/AICODER_IMPLEMENTATION_PLAN_PHASE2.md +284 -0
- package/LICENSE +21 -0
- package/README.md +490 -0
- package/bin/interactive.tsx +232 -0
- package/dist/bin/interactive.d.ts +3 -0
- package/dist/bin/interactive.d.ts.map +1 -0
- package/dist/bin/interactive.js +155 -0
- package/dist/bin/interactive.js.map +1 -0
- package/dist/src/config/providers.d.ts +15 -0
- package/dist/src/config/providers.d.ts.map +1 -0
- package/dist/src/config/providers.js +142 -0
- package/dist/src/config/providers.js.map +1 -0
- package/dist/src/config/session.d.ts +25 -0
- package/dist/src/config/session.d.ts.map +1 -0
- package/dist/src/config/session.js +97 -0
- package/dist/src/config/session.js.map +1 -0
- package/dist/src/context/bm25.d.ts +68 -0
- package/dist/src/context/bm25.d.ts.map +1 -0
- package/dist/src/context/bm25.js +131 -0
- package/dist/src/context/bm25.js.map +1 -0
- package/dist/src/context/code-search.d.ts +30 -0
- package/dist/src/context/code-search.d.ts.map +1 -0
- package/dist/src/context/code-search.js +150 -0
- package/dist/src/context/code-search.js.map +1 -0
- package/dist/src/context/context-pack.d.ts +25 -0
- package/dist/src/context/context-pack.d.ts.map +1 -0
- package/dist/src/context/context-pack.js +92 -0
- package/dist/src/context/context-pack.js.map +1 -0
- package/dist/src/context/dependency-mapper.d.ts +10 -0
- package/dist/src/context/dependency-mapper.d.ts.map +1 -0
- package/dist/src/context/dependency-mapper.js +62 -0
- package/dist/src/context/dependency-mapper.js.map +1 -0
- package/dist/src/context/index.d.ts +8 -0
- package/dist/src/context/index.d.ts.map +1 -0
- package/dist/src/context/index.js +9 -0
- package/dist/src/context/index.js.map +1 -0
- package/dist/src/context/symbol-extractor.d.ts +26 -0
- package/dist/src/context/symbol-extractor.d.ts.map +1 -0
- package/dist/src/context/symbol-extractor.js +129 -0
- package/dist/src/context/symbol-extractor.js.map +1 -0
- package/dist/src/context/test-mapper.d.ts +16 -0
- package/dist/src/context/test-mapper.d.ts.map +1 -0
- package/dist/src/context/test-mapper.js +66 -0
- package/dist/src/context/test-mapper.js.map +1 -0
- package/dist/src/context/types.d.ts +61 -0
- package/dist/src/context/types.d.ts.map +1 -0
- package/dist/src/context/types.js +3 -0
- package/dist/src/context/types.js.map +1 -0
- package/dist/src/context/workspace-indexer.d.ts +39 -0
- package/dist/src/context/workspace-indexer.d.ts.map +1 -0
- package/dist/src/context/workspace-indexer.js +222 -0
- package/dist/src/context/workspace-indexer.js.map +1 -0
- package/dist/src/index.d.ts +5 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/registries.d.ts +34 -0
- package/dist/src/registries.d.ts.map +1 -0
- package/dist/src/registries.js +87 -0
- package/dist/src/registries.js.map +1 -0
- package/dist/src/runtime/budget-manager.d.ts +42 -0
- package/dist/src/runtime/budget-manager.d.ts.map +1 -0
- package/dist/src/runtime/budget-manager.js +82 -0
- package/dist/src/runtime/budget-manager.js.map +1 -0
- package/dist/src/runtime/interactive-runtime.d.ts +39 -0
- package/dist/src/runtime/interactive-runtime.d.ts.map +1 -0
- package/dist/src/runtime/interactive-runtime.js +321 -0
- package/dist/src/runtime/interactive-runtime.js.map +1 -0
- package/dist/src/tasks-v2/analysis-tasks.d.ts +117 -0
- package/dist/src/tasks-v2/analysis-tasks.d.ts.map +1 -0
- package/dist/src/tasks-v2/analysis-tasks.js +209 -0
- package/dist/src/tasks-v2/analysis-tasks.js.map +1 -0
- package/dist/src/tasks-v2/developer-tasks.d.ts +226 -0
- package/dist/src/tasks-v2/developer-tasks.d.ts.map +1 -0
- package/dist/src/tasks-v2/developer-tasks.js +322 -0
- package/dist/src/tasks-v2/developer-tasks.js.map +1 -0
- package/dist/src/tasks-v2/index.d.ts +3 -0
- package/dist/src/tasks-v2/index.d.ts.map +1 -0
- package/dist/src/tasks-v2/index.js +4 -0
- package/dist/src/tasks-v2/index.js.map +1 -0
- package/dist/src/tools-v2/edit-tools.d.ts +67 -0
- package/dist/src/tools-v2/edit-tools.d.ts.map +1 -0
- package/dist/src/tools-v2/edit-tools.js +117 -0
- package/dist/src/tools-v2/edit-tools.js.map +1 -0
- package/dist/src/tools-v2/index.d.ts +6 -0
- package/dist/src/tools-v2/index.d.ts.map +1 -0
- package/dist/src/tools-v2/index.js +7 -0
- package/dist/src/tools-v2/index.js.map +1 -0
- package/dist/src/tools-v2/read-tools.d.ts +129 -0
- package/dist/src/tools-v2/read-tools.d.ts.map +1 -0
- package/dist/src/tools-v2/read-tools.js +216 -0
- package/dist/src/tools-v2/read-tools.js.map +1 -0
- package/dist/src/tools-v2/search-tools.d.ts +73 -0
- package/dist/src/tools-v2/search-tools.d.ts.map +1 -0
- package/dist/src/tools-v2/search-tools.js +132 -0
- package/dist/src/tools-v2/search-tools.js.map +1 -0
- package/dist/src/tools-v2/test-tools.d.ts +59 -0
- package/dist/src/tools-v2/test-tools.d.ts.map +1 -0
- package/dist/src/tools-v2/test-tools.js +111 -0
- package/dist/src/tools-v2/test-tools.js.map +1 -0
- package/dist/src/tools-v2/workspace-context.d.ts +65 -0
- package/dist/src/tools-v2/workspace-context.d.ts.map +1 -0
- package/dist/src/tools-v2/workspace-context.js +336 -0
- package/dist/src/tools-v2/workspace-context.js.map +1 -0
- package/dist/src/ui/App.d.ts +9 -0
- package/dist/src/ui/App.d.ts.map +1 -0
- package/dist/src/ui/App.js +257 -0
- package/dist/src/ui/App.js.map +1 -0
- package/dist/src/ui/components/ChatPane.d.ts +12 -0
- package/dist/src/ui/components/ChatPane.d.ts.map +1 -0
- package/dist/src/ui/components/ChatPane.js +41 -0
- package/dist/src/ui/components/ChatPane.js.map +1 -0
- package/dist/src/ui/components/EventsPane.d.ts +12 -0
- package/dist/src/ui/components/EventsPane.d.ts.map +1 -0
- package/dist/src/ui/components/EventsPane.js +48 -0
- package/dist/src/ui/components/EventsPane.js.map +1 -0
- package/dist/src/ui/components/GoalsTasksPane.d.ts +18 -0
- package/dist/src/ui/components/GoalsTasksPane.d.ts.map +1 -0
- package/dist/src/ui/components/GoalsTasksPane.js +83 -0
- package/dist/src/ui/components/GoalsTasksPane.js.map +1 -0
- package/dist/src/ui/store.d.ts +74 -0
- package/dist/src/ui/store.d.ts.map +1 -0
- package/dist/src/ui/store.js +260 -0
- package/dist/src/ui/store.js.map +1 -0
- package/dist/tests/integration.test.d.ts +2 -0
- package/dist/tests/integration.test.d.ts.map +1 -0
- package/dist/tests/integration.test.js +415 -0
- package/dist/tests/integration.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/docs/AICODER.png +0 -0
- package/docs/INTERACTIVE_CLI_GUIDE.md +201 -0
- package/docs/TUI_MOCKUP.md +180 -0
- package/package.json +52 -0
- package/src/config/providers.ts +174 -0
- package/src/config/session.ts +143 -0
- package/src/context/bm25.ts +173 -0
- package/src/context/code-search.ts +188 -0
- package/src/context/context-pack.ts +133 -0
- package/src/context/dependency-mapper.ts +72 -0
- package/src/context/index.ts +8 -0
- package/src/context/symbol-extractor.ts +149 -0
- package/src/context/test-mapper.ts +77 -0
- package/src/context/types.ts +69 -0
- package/src/context/workspace-indexer.ts +249 -0
- package/src/index.ts +5 -0
- package/src/registries.ts +118 -0
- package/src/runtime/budget-manager.ts +118 -0
- package/src/runtime/interactive-runtime.ts +423 -0
- package/src/tasks-v2/analysis-tasks.ts +311 -0
- package/src/tasks-v2/developer-tasks.ts +437 -0
- package/src/tasks-v2/index.ts +3 -0
- package/src/tools-v2/edit-tools.ts +153 -0
- package/src/tools-v2/index.ts +6 -0
- package/src/tools-v2/read-tools.ts +286 -0
- package/src/tools-v2/search-tools.ts +175 -0
- package/src/tools-v2/test-tools.ts +147 -0
- package/src/tools-v2/workspace-context.ts +428 -0
- package/src/ui/App.tsx +392 -0
- package/src/ui/components/ChatPane.tsx +84 -0
- package/src/ui/components/EventsPane.tsx +81 -0
- package/src/ui/components/GoalsTasksPane.tsx +149 -0
- package/src/ui/store.ts +362 -0
- package/tests/integration.test.ts +537 -0
- package/tsconfig.json +22 -0
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# ACM AI Coder - Interactive TUI Mockup
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
╔═══════════════════════════════════════════════════════════════════════════════╗
|
|
5
|
+
║ ACM AI Coder - Interactive Mode ⟳ Processing║
|
|
6
|
+
╠═════════════════════════╤═════════════════════════════╤═════════════════════════╣
|
|
7
|
+
║ │ │ ║
|
|
8
|
+
║ ┌─────────────────┐ │ ┌─────────────────────┐ │ ┌─────────────────┐ ║
|
|
9
|
+
║ │ Chat │ │ │ Goal/Tasks/Progress │ │ │ Event Stream │ ║
|
|
10
|
+
║ └─────────────────┘ │ └─────────────────────┘ │ └─────────────────┘ ║
|
|
11
|
+
║ │ │ ║
|
|
12
|
+
║ System: │ Goal: │ [14:23:45] GOAL_ ║
|
|
13
|
+
║ Welcome to ACM AI │ Analyze src/index.ts │ CREATED: goal-123 ║
|
|
14
|
+
║ Coder (Phase 2) │ and find bugs │ ║
|
|
15
|
+
║ │ │ [14:23:46] BUDGET_ ║
|
|
16
|
+
║ Configuration: │ Tasks: │ CHECK: $0.0024 ║
|
|
17
|
+
║ Model: gpt-4o │ ○ analyze_workspace │ ║
|
|
18
|
+
║ Engine: langgraph │ ○ collect_context_pack │ [14:23:47] PLAN_ ║
|
|
19
|
+
║ Workspace: /project │ ○ search_code │ SELECTED: plan-456 ║
|
|
20
|
+
║ Budget: $10.00 │ │ ║
|
|
21
|
+
║ │ Budget: │ [14:23:48] TASK_ ║
|
|
22
|
+
║ Type your goal to │ Spent: $0.0024 / $10.00 │ START: task-0 ║
|
|
23
|
+
║ start planning. │ Used: 0.0% │ ║
|
|
24
|
+
║ │ Remaining: $9.9976 │ [14:23:49] CONTEXT_ ║
|
|
25
|
+
║ You: │ Calls: 1 │ INTERNALIZED: 3 files ║
|
|
26
|
+
║ Analyze src/index.ts │ │ ║
|
|
27
|
+
║ and find bugs │ │ [14:23:50] TASK_ ║
|
|
28
|
+
║ │ │ END: task-0 ║
|
|
29
|
+
║ Planner (streaming...):│ │ ║
|
|
30
|
+
║ I'll analyze the file │ │ [14:23:51] NUCLEUS_ ║
|
|
31
|
+
║ by first collecting │ │ INFERENCE: context ok ║
|
|
32
|
+
║ context from the │ │ ║
|
|
33
|
+
║ workspace, then... │ │ ║
|
|
34
|
+
║ │ │ ║
|
|
35
|
+
║ │ │ ║
|
|
36
|
+
║ │ │ ║
|
|
37
|
+
╠═════════════════════════╧═════════════════════════════╧═════════════════════════╣
|
|
38
|
+
║ > Type your goal or command (e.g., /help)... ║
|
|
39
|
+
╚═══════════════════════════════════════════════════════════════════════════════╝
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Layout Breakdown
|
|
43
|
+
|
|
44
|
+
### Left Column (40%) - Chat Pane
|
|
45
|
+
- **Purpose:** User messages, planner reasoning, nucleus thoughts, system messages
|
|
46
|
+
- **Colors:**
|
|
47
|
+
- User: white
|
|
48
|
+
- Planner: yellow (streaming indicator when active)
|
|
49
|
+
- Nucleus: magenta
|
|
50
|
+
- System: gray
|
|
51
|
+
- **Scrolling:** Shows most recent messages that fit in viewport
|
|
52
|
+
|
|
53
|
+
### Middle Column (30%) - Goals/Tasks/Progress
|
|
54
|
+
- **Goal Section:** Current goal intent
|
|
55
|
+
- **Tasks Section:** Live task list with status icons
|
|
56
|
+
- ○ pending (gray)
|
|
57
|
+
- ◐ running (yellow)
|
|
58
|
+
- ● succeeded (green)
|
|
59
|
+
- ✗ failed (red)
|
|
60
|
+
- ⟳ retrying (yellow)
|
|
61
|
+
- **Budget Section:** Real-time spend tracking
|
|
62
|
+
- Total spent vs. limit
|
|
63
|
+
- Percentage used (color-coded)
|
|
64
|
+
- Remaining budget
|
|
65
|
+
- API call count
|
|
66
|
+
|
|
67
|
+
### Right Column (30%) - Event Stream
|
|
68
|
+
- **Purpose:** Ledger entries, tool calls, context updates, policy decisions
|
|
69
|
+
- **Format:** [timestamp] TYPE: data
|
|
70
|
+
- **Colors:**
|
|
71
|
+
- PLAN_SELECTED, TASK_END: green
|
|
72
|
+
- TASK_START: blue
|
|
73
|
+
- ERROR: red
|
|
74
|
+
- POLICY_DECISION: yellow
|
|
75
|
+
- Others: gray
|
|
76
|
+
- **Pruning:** Keeps last 100 events
|
|
77
|
+
|
|
78
|
+
### Bottom - Command Input
|
|
79
|
+
- **Text input:** Accepts goals or commands
|
|
80
|
+
- **Commands:** /exit, /help, /budget, /context, /reset
|
|
81
|
+
- **File mentions:** #path/to/file syntax
|
|
82
|
+
- **Submit:** Press Enter to send
|
|
83
|
+
|
|
84
|
+
## Example Session Flow
|
|
85
|
+
|
|
86
|
+
### 1. Startup
|
|
87
|
+
```
|
|
88
|
+
> acm-aicoder --provider vllm --model gpt-4o --base-url https://api.openai.com \
|
|
89
|
+
--workspace /myproject
|
|
90
|
+
|
|
91
|
+
[TUI launches with welcome message]
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 2. User Types Goal
|
|
95
|
+
```
|
|
96
|
+
> Find all TypeScript errors in src/ directory
|
|
97
|
+
[ENTER]
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### 3. Budget Check
|
|
101
|
+
```
|
|
102
|
+
Event Stream:
|
|
103
|
+
[14:25:01] BUDGET_CHECK: estimated $0.0035, 1200 tokens
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 4. Planner Streams Reasoning
|
|
107
|
+
```
|
|
108
|
+
Chat Pane:
|
|
109
|
+
Planner (streaming...):
|
|
110
|
+
First, I'll analyze the TypeScript files in src/...
|
|
111
|
+
Then I'll run the type checker...
|
|
112
|
+
Finally, I'll categorize the errors...
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### 5. Tasks Execute
|
|
116
|
+
```
|
|
117
|
+
Tasks Pane:
|
|
118
|
+
◐ analyze_workspace (running)
|
|
119
|
+
○ collect_context_pack
|
|
120
|
+
○ fix_type_error
|
|
121
|
+
|
|
122
|
+
Event Stream:
|
|
123
|
+
[14:25:02] TASK_START: task-0
|
|
124
|
+
[14:25:03] CONTEXT_INTERNALIZED: 15 files
|
|
125
|
+
[14:25:04] TASK_END: task-0
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### 6. Completion
|
|
129
|
+
```
|
|
130
|
+
System:
|
|
131
|
+
Goal completed successfully!
|
|
132
|
+
Replay bundle saved to: /myproject/.aicoder/replays/2025-01-04T14-25-05
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Interactive Commands
|
|
136
|
+
|
|
137
|
+
### /help
|
|
138
|
+
Shows available commands and usage examples.
|
|
139
|
+
|
|
140
|
+
### /budget
|
|
141
|
+
```
|
|
142
|
+
Budget Status:
|
|
143
|
+
Total Spent: $0.0124
|
|
144
|
+
Limit: $10.00
|
|
145
|
+
Remaining: $9.9876
|
|
146
|
+
Used: 0.1%
|
|
147
|
+
API Calls: 4
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### /context
|
|
151
|
+
```
|
|
152
|
+
Current Context:
|
|
153
|
+
ID: ctx-1735998305123
|
|
154
|
+
Facts: 3 entries
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### /reset
|
|
158
|
+
Clears current goal and tasks, resets budget, keeps chat history.
|
|
159
|
+
|
|
160
|
+
### /exit or /quit
|
|
161
|
+
Saves replay bundle and exits cleanly.
|
|
162
|
+
|
|
163
|
+
## Visual Styling
|
|
164
|
+
|
|
165
|
+
- **Borders:** Single-line for panes, double-line for header/footer
|
|
166
|
+
- **Colors:** ANSI terminal colors (cyan, yellow, green, red, blue, magenta)
|
|
167
|
+
- **Responsive:** Adjusts to terminal size (minimum 80 columns)
|
|
168
|
+
- **Updates:** Real-time re-renders on state changes
|
|
169
|
+
|
|
170
|
+
## Terminal Requirements
|
|
171
|
+
|
|
172
|
+
- **Minimum Width:** 80 columns
|
|
173
|
+
- **Minimum Height:** 24 rows
|
|
174
|
+
- **Terminal Type:** xterm-compatible (supports ANSI colors)
|
|
175
|
+
- **Not Recommended:** tmux/screen nested sessions (may cause layout issues)
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
This mockup represents the actual TUI layout implemented in Phase 2.
|
|
180
|
+
All components are functional and wired to the ACM framework.
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ddse/acm-aicoder",
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "ACM AI Coder Demo - Production-ready developer workflow automation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/src/index.js",
|
|
7
|
+
"types": "./dist/src/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"acm-aicoder": "./dist/bin/interactive.js"
|
|
10
|
+
},
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/src/index.d.ts",
|
|
14
|
+
"import": "./dist/src/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"enquirer": "^2.4.1",
|
|
19
|
+
"chalk": "^5.3.0",
|
|
20
|
+
"ora": "^8.0.1",
|
|
21
|
+
"execa": "^9.0.0",
|
|
22
|
+
"ink": "^5.0.1",
|
|
23
|
+
"ink-text-input": "^6.0.0",
|
|
24
|
+
"react": "^18.3.1",
|
|
25
|
+
"@ddse/acm-sdk": "0.5.0",
|
|
26
|
+
"@ddse/acm-runtime": "0.5.0",
|
|
27
|
+
"@ddse/acm-planner": "0.5.0",
|
|
28
|
+
"@ddse/acm-replay": "0.5.0",
|
|
29
|
+
"@ddse/acm-framework": "0.5.0",
|
|
30
|
+
"@ddse/acm-llm": "0.5.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^20.0.0",
|
|
34
|
+
"@types/react": "^18.3.3",
|
|
35
|
+
"typescript": "^5.3.0"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"acm",
|
|
39
|
+
"ai",
|
|
40
|
+
"coder",
|
|
41
|
+
"developer",
|
|
42
|
+
"automation"
|
|
43
|
+
],
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc",
|
|
47
|
+
"clean": "rm -rf dist",
|
|
48
|
+
"test": "tsc && node ./dist/tests/integration.test.js",
|
|
49
|
+
"dev": "tsc --watch",
|
|
50
|
+
"acm-aicoder": "node ./dist/bin/interactive.js"
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// Provider metadata for budget governance
|
|
2
|
+
// Token costs and context limits per model/provider
|
|
3
|
+
|
|
4
|
+
export interface ProviderMetadata {
|
|
5
|
+
provider: string;
|
|
6
|
+
model: string;
|
|
7
|
+
|
|
8
|
+
// Cost per 1M tokens (USD)
|
|
9
|
+
inputCostPer1M?: number;
|
|
10
|
+
outputCostPer1M?: number;
|
|
11
|
+
|
|
12
|
+
// Context window
|
|
13
|
+
maxContextTokens?: number;
|
|
14
|
+
|
|
15
|
+
// Concurrency limits
|
|
16
|
+
maxConcurrentRequests?: number;
|
|
17
|
+
|
|
18
|
+
// Recommended settings
|
|
19
|
+
recommendedTemperature?: number;
|
|
20
|
+
supportsStreaming: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Provider metadata registry
|
|
24
|
+
// Sources: OpenAI pricing, Anthropic pricing, Azure OpenAI, local models
|
|
25
|
+
export const PROVIDER_METADATA: Record<string, ProviderMetadata> = {
|
|
26
|
+
// OpenAI models
|
|
27
|
+
'gpt-4o': {
|
|
28
|
+
provider: 'openai',
|
|
29
|
+
model: 'gpt-4o',
|
|
30
|
+
inputCostPer1M: 2.50,
|
|
31
|
+
outputCostPer1M: 10.00,
|
|
32
|
+
maxContextTokens: 128000,
|
|
33
|
+
maxConcurrentRequests: 10,
|
|
34
|
+
recommendedTemperature: 0.7,
|
|
35
|
+
supportsStreaming: true,
|
|
36
|
+
},
|
|
37
|
+
'gpt-4o-mini': {
|
|
38
|
+
provider: 'openai',
|
|
39
|
+
model: 'gpt-4o-mini',
|
|
40
|
+
inputCostPer1M: 0.15,
|
|
41
|
+
outputCostPer1M: 0.60,
|
|
42
|
+
maxContextTokens: 128000,
|
|
43
|
+
maxConcurrentRequests: 10,
|
|
44
|
+
recommendedTemperature: 0.7,
|
|
45
|
+
supportsStreaming: true,
|
|
46
|
+
},
|
|
47
|
+
'gpt-4-turbo': {
|
|
48
|
+
provider: 'openai',
|
|
49
|
+
model: 'gpt-4-turbo',
|
|
50
|
+
inputCostPer1M: 10.00,
|
|
51
|
+
outputCostPer1M: 30.00,
|
|
52
|
+
maxContextTokens: 128000,
|
|
53
|
+
maxConcurrentRequests: 10,
|
|
54
|
+
recommendedTemperature: 0.7,
|
|
55
|
+
supportsStreaming: true,
|
|
56
|
+
},
|
|
57
|
+
'gpt-3.5-turbo': {
|
|
58
|
+
provider: 'openai',
|
|
59
|
+
model: 'gpt-3.5-turbo',
|
|
60
|
+
inputCostPer1M: 0.50,
|
|
61
|
+
outputCostPer1M: 1.50,
|
|
62
|
+
maxContextTokens: 16385,
|
|
63
|
+
maxConcurrentRequests: 10,
|
|
64
|
+
recommendedTemperature: 0.7,
|
|
65
|
+
supportsStreaming: true,
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
// Anthropic models
|
|
69
|
+
'claude-3-opus-20240229': {
|
|
70
|
+
provider: 'anthropic',
|
|
71
|
+
model: 'claude-3-opus-20240229',
|
|
72
|
+
inputCostPer1M: 15.00,
|
|
73
|
+
outputCostPer1M: 75.00,
|
|
74
|
+
maxContextTokens: 200000,
|
|
75
|
+
maxConcurrentRequests: 5,
|
|
76
|
+
recommendedTemperature: 0.7,
|
|
77
|
+
supportsStreaming: true,
|
|
78
|
+
},
|
|
79
|
+
'claude-3-sonnet-20240229': {
|
|
80
|
+
provider: 'anthropic',
|
|
81
|
+
model: 'claude-3-sonnet-20240229',
|
|
82
|
+
inputCostPer1M: 3.00,
|
|
83
|
+
outputCostPer1M: 15.00,
|
|
84
|
+
maxContextTokens: 200000,
|
|
85
|
+
maxConcurrentRequests: 5,
|
|
86
|
+
recommendedTemperature: 0.7,
|
|
87
|
+
supportsStreaming: true,
|
|
88
|
+
},
|
|
89
|
+
'claude-3-haiku-20240307': {
|
|
90
|
+
provider: 'anthropic',
|
|
91
|
+
model: 'claude-3-haiku-20240307',
|
|
92
|
+
inputCostPer1M: 0.25,
|
|
93
|
+
outputCostPer1M: 1.25,
|
|
94
|
+
maxContextTokens: 200000,
|
|
95
|
+
maxConcurrentRequests: 5,
|
|
96
|
+
recommendedTemperature: 0.7,
|
|
97
|
+
supportsStreaming: true,
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// Local/self-hosted models (no cost)
|
|
101
|
+
'llama3.1': {
|
|
102
|
+
provider: 'ollama',
|
|
103
|
+
model: 'llama3.1',
|
|
104
|
+
inputCostPer1M: 0,
|
|
105
|
+
outputCostPer1M: 0,
|
|
106
|
+
maxContextTokens: 128000,
|
|
107
|
+
recommendedTemperature: 0.7,
|
|
108
|
+
supportsStreaming: true,
|
|
109
|
+
},
|
|
110
|
+
'qwen2.5:7b': {
|
|
111
|
+
provider: 'ollama',
|
|
112
|
+
model: 'qwen2.5:7b',
|
|
113
|
+
inputCostPer1M: 0,
|
|
114
|
+
outputCostPer1M: 0,
|
|
115
|
+
maxContextTokens: 32768,
|
|
116
|
+
recommendedTemperature: 0.7,
|
|
117
|
+
supportsStreaming: true,
|
|
118
|
+
},
|
|
119
|
+
'deepseek-coder': {
|
|
120
|
+
provider: 'ollama',
|
|
121
|
+
model: 'deepseek-coder',
|
|
122
|
+
inputCostPer1M: 0,
|
|
123
|
+
outputCostPer1M: 0,
|
|
124
|
+
maxContextTokens: 16000,
|
|
125
|
+
recommendedTemperature: 0.7,
|
|
126
|
+
supportsStreaming: true,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export function getProviderMetadata(model: string): ProviderMetadata {
|
|
131
|
+
// Try exact match first
|
|
132
|
+
if (PROVIDER_METADATA[model]) {
|
|
133
|
+
return PROVIDER_METADATA[model];
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Try prefix match (e.g., "gpt-4o-2024-05-13" matches "gpt-4o")
|
|
137
|
+
for (const [key, metadata] of Object.entries(PROVIDER_METADATA)) {
|
|
138
|
+
if (model.startsWith(key)) {
|
|
139
|
+
return metadata;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Default metadata for unknown models (assume local/free)
|
|
144
|
+
return {
|
|
145
|
+
provider: 'unknown',
|
|
146
|
+
model,
|
|
147
|
+
inputCostPer1M: 0,
|
|
148
|
+
outputCostPer1M: 0,
|
|
149
|
+
maxContextTokens: 8192,
|
|
150
|
+
recommendedTemperature: 0.7,
|
|
151
|
+
supportsStreaming: true,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function estimateTokenCount(text: string): number {
|
|
156
|
+
// Rough approximation: 1 token ≈ 4 characters for English text
|
|
157
|
+
// More accurate would use tiktoken library, but this is sufficient for budget estimation
|
|
158
|
+
return Math.ceil(text.length / 4);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export function estimateCost(
|
|
162
|
+
inputTokens: number,
|
|
163
|
+
outputTokens: number,
|
|
164
|
+
metadata: ProviderMetadata
|
|
165
|
+
): number {
|
|
166
|
+
if (!metadata.inputCostPer1M || !metadata.outputCostPer1M) {
|
|
167
|
+
return 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const inputCost = (inputTokens / 1_000_000) * metadata.inputCostPer1M;
|
|
171
|
+
const outputCost = (outputTokens / 1_000_000) * metadata.outputCostPer1M;
|
|
172
|
+
|
|
173
|
+
return inputCost + outputCost;
|
|
174
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// Session configuration for AI Coder Phase 2
|
|
2
|
+
// Manages CLI arguments and session metadata using provider/model semantics
|
|
3
|
+
|
|
4
|
+
import { existsSync, statSync } from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
|
|
8
|
+
export type Provider = 'ollama' | 'vllm';
|
|
9
|
+
|
|
10
|
+
export interface SessionConfig {
|
|
11
|
+
provider: Provider;
|
|
12
|
+
model: string;
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
workspace: string;
|
|
15
|
+
temperature: number;
|
|
16
|
+
seed?: number;
|
|
17
|
+
planCount: 1 | 2;
|
|
18
|
+
sessionId: string;
|
|
19
|
+
timestamp: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface CLIArgs {
|
|
23
|
+
provider?: string;
|
|
24
|
+
model?: string;
|
|
25
|
+
'base-url'?: string;
|
|
26
|
+
workspace?: string;
|
|
27
|
+
temperature?: string;
|
|
28
|
+
seed?: string;
|
|
29
|
+
plans?: string;
|
|
30
|
+
[key: string]: string | undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function parseCliArgs(argv: string[]): CLIArgs {
|
|
34
|
+
const args: CLIArgs = {};
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const arg = argv[i];
|
|
38
|
+
if (arg.startsWith('--')) {
|
|
39
|
+
// Support --key=value form
|
|
40
|
+
if (arg.includes('=')) {
|
|
41
|
+
const pair = arg.slice(2);
|
|
42
|
+
const eqIndex = pair.indexOf('=');
|
|
43
|
+
const key = pair.slice(0, eqIndex);
|
|
44
|
+
const value = pair.slice(eqIndex + 1);
|
|
45
|
+
if (key.length > 0) {
|
|
46
|
+
args[key] = value;
|
|
47
|
+
}
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Support space-separated --key value form
|
|
52
|
+
const key = arg.slice(2);
|
|
53
|
+
const value = argv[i + 1];
|
|
54
|
+
if (value && !value.startsWith('--')) {
|
|
55
|
+
args[key] = value;
|
|
56
|
+
i++;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return args;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function validateAndNormalizeConfig(args: CLIArgs): SessionConfig {
|
|
65
|
+
const provider = (args.provider as Provider) || 'ollama';
|
|
66
|
+
if (!['ollama', 'vllm'].includes(provider)) {
|
|
67
|
+
throw new Error(`Invalid --provider: ${args.provider}. Must be "ollama" or "vllm".`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const model = args.model || (provider === 'ollama' ? 'llama3.1' : undefined);
|
|
71
|
+
const missing: string[] = [];
|
|
72
|
+
|
|
73
|
+
if (!model) missing.push('--model');
|
|
74
|
+
if (!args.workspace || args.workspace.trim().length === 0) missing.push('--workspace');
|
|
75
|
+
|
|
76
|
+
if (missing.length > 0) {
|
|
77
|
+
throw new Error(
|
|
78
|
+
`Missing required parameters: ${missing.join(', ')}\n\n` +
|
|
79
|
+
`ACM AI Coder requires these parameters to start:\n` +
|
|
80
|
+
` --provider <ollama|vllm> LLM provider (default: ollama)\n` +
|
|
81
|
+
` --model <name> Model identifier (e.g., llama3.1, gpt-4o)\n` +
|
|
82
|
+
` --workspace <path> REQUIRED: absolute or relative path to project root\n\n` +
|
|
83
|
+
`Optional parameters:\n` +
|
|
84
|
+
` --base-url <url> Override provider base URL\n` +
|
|
85
|
+
` --temperature <0-2> LLM temperature (default: 0.7)\n` +
|
|
86
|
+
` --seed <number> Random seed for reproducibility\n` +
|
|
87
|
+
` --plans <1|2> Number of alternative plans (default: 1)\n\n` +
|
|
88
|
+
`Examples:\n` +
|
|
89
|
+
` acm-aicoder --provider vllm --model gpt-4o --workspace /abs/path\n` +
|
|
90
|
+
` acm-aicoder --provider ollama --model llama3.1 --workspace=~/myproject`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const temperature = args.temperature ? parseFloat(args.temperature) : 0.7;
|
|
95
|
+
if (isNaN(temperature) || temperature < 0 || temperature > 2) {
|
|
96
|
+
throw new Error(`Invalid --temperature: must be between 0 and 2`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const seed = args.seed ? parseInt(args.seed, 10) : undefined;
|
|
100
|
+
if (seed !== undefined && Number.isNaN(seed)) {
|
|
101
|
+
throw new Error(`Invalid --seed: must be a number`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const planCount = args.plans === '2' ? 2 : 1;
|
|
105
|
+
|
|
106
|
+
// Enforce explicit workspace and normalize
|
|
107
|
+
const baseCwd = process.env.INIT_CWD || process.env.PWD || process.cwd();
|
|
108
|
+
let workspaceInput = args.workspace!;
|
|
109
|
+
|
|
110
|
+
// Expand ~ to user home
|
|
111
|
+
if (workspaceInput.startsWith('~/')) {
|
|
112
|
+
workspaceInput = path.join(os.homedir(), workspaceInput.slice(2));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const resolvedWorkspace = path.isAbsolute(workspaceInput)
|
|
116
|
+
? workspaceInput
|
|
117
|
+
: path.resolve(baseCwd, workspaceInput);
|
|
118
|
+
|
|
119
|
+
if (!existsSync(resolvedWorkspace)) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`Workspace path "${resolvedWorkspace}" does not exist. Please provide a valid --workspace.`
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const stats = statSync(resolvedWorkspace);
|
|
126
|
+
if (!stats.isDirectory()) {
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Workspace path "${resolvedWorkspace}" is not a directory. Please provide a valid --workspace.`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
provider,
|
|
134
|
+
model: model!,
|
|
135
|
+
baseUrl: args['base-url'],
|
|
136
|
+
workspace: resolvedWorkspace,
|
|
137
|
+
temperature,
|
|
138
|
+
seed,
|
|
139
|
+
planCount,
|
|
140
|
+
sessionId: `session-${Date.now()}`,
|
|
141
|
+
timestamp: Date.now(),
|
|
142
|
+
};
|
|
143
|
+
}
|