@dastageer_44/eco-code 1.1.0 → 1.2.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/README.md +76 -69
- package/dist/config.d.ts +7 -1
- package/dist/config.js +62 -4
- package/dist/config.js.map +1 -1
- package/dist/harness/agent.d.ts +9 -2
- package/dist/harness/agent.js +69 -20
- package/dist/harness/agent.js.map +1 -1
- package/dist/harness/context.d.ts +6 -1
- package/dist/harness/context.js +57 -6
- package/dist/harness/context.js.map +1 -1
- package/dist/index.js +433 -161
- package/dist/index.js.map +1 -1
- package/dist/services/updater.d.ts +4 -0
- package/dist/services/updater.js +46 -2
- package/dist/services/updater.js.map +1 -1
- package/dist/tools/file-ops.js +7 -0
- package/dist/tools/file-ops.js.map +1 -1
- package/dist/tools/index.js +14 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/ui/banner.d.ts +1 -1
- package/dist/ui/banner.js +20 -11
- package/dist/ui/banner.js.map +1 -1
- package/dist/ui/markdown.d.ts +1 -0
- package/dist/ui/markdown.js +78 -0
- package/dist/ui/markdown.js.map +1 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,105 +1,112 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
> Powered by OpenRouter free models with dynamic discovery and a taste-adaptation harness.
|
|
3
|
+
# 🌍 eco-code
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
[](https://npmjs.com/package/eco-code)
|
|
8
|
-
[](https://nodejs.org/)
|
|
5
|
+
### The coding agent that does it all. Learns the way you code. Until coding feels like thinking.
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
**Code 10× faster. Reviews, 2× quicker. Bugs 5× fewer.** <br>
|
|
8
|
+
*Powered by 100% free open-source frontier models via OpenRouter.*
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
[](https://www.npmjs.com/package/@dastageer_44/eco-code)
|
|
11
|
+
[](https://opensource.org/licenses/MIT)
|
|
13
12
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
<br>
|
|
16
|
+
|
|
17
|
+
## 🚀 Quick Install
|
|
18
|
+
|
|
19
|
+
Get started instantly! Copy the command below for your operating system to install `eco-code` globally on your machine.
|
|
20
|
+
|
|
21
|
+
### 🪟 Windows (PowerShell / Command Prompt)
|
|
22
|
+
```powershell
|
|
23
|
+
npm install -g @dastageer_44/eco-code
|
|
17
24
|
```
|
|
18
25
|
|
|
19
|
-
###
|
|
26
|
+
### 🍎 macOS
|
|
20
27
|
```bash
|
|
21
|
-
npm install -g eco-code
|
|
22
|
-
eco-code
|
|
28
|
+
sudo npm install -g @dastageer_44/eco-code
|
|
23
29
|
```
|
|
24
30
|
|
|
25
|
-
###
|
|
31
|
+
### 🐧 Linux
|
|
26
32
|
```bash
|
|
27
|
-
npm
|
|
33
|
+
sudo npm install -g @dastageer_44/eco-code
|
|
28
34
|
```
|
|
29
35
|
|
|
36
|
+
*(Note: GitHub and npm automatically add a handy "Copy" button to the top right of these code blocks!)*
|
|
37
|
+
|
|
30
38
|
---
|
|
31
39
|
|
|
32
|
-
##
|
|
40
|
+
## ⚡ Why eco-code?
|
|
33
41
|
|
|
34
|
-
- **
|
|
35
|
-
- **Autonomous Tool Harness**: Equipped with file inspection, line-level editing, creation, directory exploration, and shell command execution.
|
|
36
|
-
- **"Taste" Adaptation Engine**: Inspired by modern meta-agent research (such as Command Code), `eco-code` maintains a `.agent/taste.md` style profile that learns your repository conventions, testing frameworks, and formatting preferences.
|
|
37
|
-
- **Dynamic Model Switching**: Switch between available free models on-the-fly using `/model`.
|
|
38
|
-
- **Direct Shell Escape**: Prefix any command with `!` (e.g. `!git status`, `!npm test`) to run terminal commands without exiting.
|
|
39
|
-
- **Auto-Update Notifier**: Notifies you directly in your terminal whenever a new version is released.
|
|
42
|
+
While most coding agents drain expensive API credits, `eco-code` bridges the **Harness Gap**. By engineering a hyper-optimized deterministic runtime—complete with auto-repairing JSON tool calls, chunked file reading, and asynchronous background shells—we make free models (like *DeepSeek*, *Qwen*, and *Llama*) perform like expensive proprietary models.
|
|
40
43
|
|
|
41
|
-
|
|
44
|
+
* **💸 100% Free Inference:** Automatically scrapes OpenRouter for $0/token models.
|
|
45
|
+
* **🧠 Taste Engine:** Learns your specific coding style and injects it into every prompt.
|
|
46
|
+
* **🛡️ Token Optimized:** Prevents context blowouts with 2000-line read limits and streaming shell cursors.
|
|
47
|
+
* **⚡ Slash Commands:** Instantly drop into a menu with `/` to swap models, clear history, or manage context.
|
|
42
48
|
|
|
43
|
-
|
|
49
|
+
---
|
|
44
50
|
|
|
45
|
-
|
|
51
|
+
## 🔑 Setup: OpenRouter API Key
|
|
46
52
|
|
|
47
|
-
|
|
48
|
-
| :--- | :--- |
|
|
49
|
-
| `/help` | Display the interactive help menu |
|
|
50
|
-
| `/model` | Scan & switch between active OpenRouter free models |
|
|
51
|
-
| `/taste` | View or add directives to the project taste memory (`.agent/taste.md`) |
|
|
52
|
-
| `/key` | Update or rotate your OpenRouter API key |
|
|
53
|
-
| `/clear` | Reset conversation history & context |
|
|
54
|
-
| `!<command>` | Execute a direct terminal command (e.g. `!git diff`, `!npm run build`) |
|
|
55
|
-
| `/exit` | Exit the CLI agent |
|
|
53
|
+
`eco-code` connects to OpenRouter to automatically fetch and use the best $0/token free models.
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
1. Get a free API key at [openrouter.ai/keys](https://openrouter.ai/keys).
|
|
56
|
+
2. Set your environment variable:
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
### 🪟 Windows (PowerShell)
|
|
59
|
+
```powershell
|
|
60
|
+
$env:OPENROUTER_API_KEY="sk-or-v1-your-key-here"
|
|
61
|
+
```
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
### 🍎 macOS / 🐧 Linux (Bash / Zsh)
|
|
64
|
+
```bash
|
|
65
|
+
export OPENROUTER_API_KEY="sk-or-v1-your-key-here"
|
|
66
|
+
```
|
|
62
67
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
*(Optional) You can also save it permanently in `~/.eco-code/config.json`:*
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"apiKey": "sk-or-v1-your-key-here"
|
|
72
|
+
}
|
|
73
|
+
```
|
|
68
74
|
|
|
69
75
|
---
|
|
70
76
|
|
|
71
|
-
##
|
|
77
|
+
## 📖 Usage Guide
|
|
78
|
+
|
|
79
|
+
After installing and setting your key, simply navigate to any project folder in your terminal and type:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
eco-code
|
|
83
|
+
```
|
|
84
|
+
*(You can also use the aliases `ecocode` or `eco`)*
|
|
72
85
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
git clone https://github.com/your-username/eco-code.git
|
|
76
|
-
cd eco-code
|
|
77
|
-
```
|
|
86
|
+
### Conversing & Coding
|
|
87
|
+
Just start typing in plain English!
|
|
78
88
|
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
npm install
|
|
82
|
-
```
|
|
89
|
+
> *"Find the login button component and change it to be rounded with a blue background."*
|
|
83
90
|
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
npm run build
|
|
87
|
-
```
|
|
91
|
+
> *"Run my test suite in the background and fix any failing tests."*
|
|
88
92
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
npm link
|
|
92
|
-
eco-code
|
|
93
|
-
```
|
|
93
|
+
### ⚡ Slash Commands & Shortcuts
|
|
94
|
+
Type `/` or `?` at any time to open the interactive command menu:
|
|
94
95
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
96
|
+
* `/plan` - Toggle between **Plan Mode** (read-only safe planning) and **Auto Mode**.
|
|
97
|
+
* `/undo` - Discard all uncommitted working changes (`git reset --hard & clean`).
|
|
98
|
+
* `/rewind` - Revert the last Git commit (`git reset HEAD~1`).
|
|
99
|
+
* `/models` - Browse and switch between the latest free frontier models.
|
|
100
|
+
* `/resume` - Select and restore any past session from your history list.
|
|
101
|
+
* `/compact` - Summarizes older conversation history to save tokens.
|
|
102
|
+
* `/taste` - View or add new project-specific coding directives.
|
|
103
|
+
* `/key` - Update your OpenRouter API Key.
|
|
104
|
+
* `/update` - Check for and install CLI updates directly from npm.
|
|
105
|
+
* `/exit` - Quit the CLI.
|
|
100
106
|
|
|
101
107
|
---
|
|
102
108
|
|
|
103
|
-
##
|
|
109
|
+
## 🛠️ Built for the Community
|
|
110
|
+
`eco-code` is open source. It relies on a rigorous "Tool Repair Pipeline" meaning the agent catches its own mistakes before they crash your code.
|
|
104
111
|
|
|
105
|
-
|
|
112
|
+
Happy Coding! 👋
|
package/dist/config.d.ts
CHANGED
|
@@ -16,11 +16,13 @@ export interface EcoConfig {
|
|
|
16
16
|
systemPromptAddition?: string;
|
|
17
17
|
autoApproveTools?: boolean;
|
|
18
18
|
modelCache?: ModelCache;
|
|
19
|
+
agentMode?: 'plan' | 'auto';
|
|
19
20
|
}
|
|
20
21
|
export interface SavedSession {
|
|
21
22
|
id: string;
|
|
22
23
|
timestamp: number;
|
|
23
24
|
model: string;
|
|
25
|
+
title?: string;
|
|
24
26
|
messages: any[];
|
|
25
27
|
}
|
|
26
28
|
export declare class ConfigManager {
|
|
@@ -36,9 +38,13 @@ export declare class ConfigManager {
|
|
|
36
38
|
setApiKey(key: string): void;
|
|
37
39
|
getDefaultModel(): string | undefined;
|
|
38
40
|
setDefaultModel(model: string): void;
|
|
41
|
+
getAgentMode(): 'plan' | 'auto';
|
|
42
|
+
setAgentMode(mode: 'plan' | 'auto'): void;
|
|
39
43
|
getCachedModels(): FreeModelInfo[] | null;
|
|
40
44
|
setCachedModels(models: FreeModelInfo[]): void;
|
|
41
|
-
saveSession(messages: any[], model: string):
|
|
45
|
+
saveSession(messages: any[], model: string, sessionId?: string): string;
|
|
46
|
+
listSessions(): SavedSession[];
|
|
47
|
+
loadSession(id: string): SavedSession | null;
|
|
42
48
|
loadLatestSession(): SavedSession | null;
|
|
43
49
|
clear(): void;
|
|
44
50
|
}
|
package/dist/config.js
CHANGED
|
@@ -52,6 +52,14 @@ export class ConfigManager {
|
|
|
52
52
|
config.defaultModel = model;
|
|
53
53
|
this.save(config);
|
|
54
54
|
}
|
|
55
|
+
getAgentMode() {
|
|
56
|
+
return this.load().agentMode || 'plan';
|
|
57
|
+
}
|
|
58
|
+
setAgentMode(mode) {
|
|
59
|
+
const config = this.load();
|
|
60
|
+
config.agentMode = mode;
|
|
61
|
+
this.save(config);
|
|
62
|
+
}
|
|
55
63
|
// --- Model Cache (Daily / 24h invalidation) ---
|
|
56
64
|
getCachedModels() {
|
|
57
65
|
const config = this.load();
|
|
@@ -77,19 +85,68 @@ export class ConfigManager {
|
|
|
77
85
|
this.save(config);
|
|
78
86
|
}
|
|
79
87
|
// --- Session Persistence & Resume ---
|
|
80
|
-
saveSession(messages, model) {
|
|
88
|
+
saveSession(messages, model, sessionId) {
|
|
81
89
|
this.ensureDirectoryExists();
|
|
82
|
-
const
|
|
90
|
+
const id = sessionId || `session_${Date.now()}`;
|
|
91
|
+
// Extract title from the first user message
|
|
92
|
+
let title = 'General Session';
|
|
93
|
+
const firstUserMsg = messages.find((m) => m.role === 'user');
|
|
94
|
+
if (firstUserMsg && typeof firstUserMsg.content === 'string') {
|
|
95
|
+
title = firstUserMsg.content.trim().slice(0, 50).replace(/\n/g, ' ');
|
|
96
|
+
}
|
|
83
97
|
const sessionData = {
|
|
84
|
-
id
|
|
98
|
+
id,
|
|
85
99
|
timestamp: Date.now(),
|
|
86
100
|
model,
|
|
101
|
+
title,
|
|
87
102
|
messages,
|
|
88
103
|
};
|
|
89
104
|
try {
|
|
105
|
+
// Save specific session file
|
|
106
|
+
const sessionPath = path.join(this.sessionsDir, `${id}.json`);
|
|
107
|
+
fs.writeFileSync(sessionPath, JSON.stringify(sessionData, null, 2), 'utf-8');
|
|
108
|
+
// Also update latest.json for quick single-resume fallback
|
|
109
|
+
const latestPath = path.join(this.sessionsDir, 'latest.json');
|
|
90
110
|
fs.writeFileSync(latestPath, JSON.stringify(sessionData, null, 2), 'utf-8');
|
|
91
111
|
}
|
|
92
112
|
catch { }
|
|
113
|
+
return id;
|
|
114
|
+
}
|
|
115
|
+
listSessions() {
|
|
116
|
+
this.ensureDirectoryExists();
|
|
117
|
+
try {
|
|
118
|
+
const files = fs.readdirSync(this.sessionsDir);
|
|
119
|
+
const sessions = [];
|
|
120
|
+
for (const file of files) {
|
|
121
|
+
if (!file.endsWith('.json') || file === 'latest.json')
|
|
122
|
+
continue;
|
|
123
|
+
try {
|
|
124
|
+
const raw = fs.readFileSync(path.join(this.sessionsDir, file), 'utf-8');
|
|
125
|
+
const data = JSON.parse(raw);
|
|
126
|
+
if (data && data.messages && data.messages.length > 0) {
|
|
127
|
+
sessions.push(data);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch { }
|
|
131
|
+
}
|
|
132
|
+
return sessions.sort((a, b) => b.timestamp - a.timestamp);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
loadSession(id) {
|
|
139
|
+
this.ensureDirectoryExists();
|
|
140
|
+
const filename = id.endsWith('.json') ? id : `${id}.json`;
|
|
141
|
+
const sessionPath = path.join(this.sessionsDir, filename);
|
|
142
|
+
try {
|
|
143
|
+
if (fs.existsSync(sessionPath)) {
|
|
144
|
+
const raw = fs.readFileSync(sessionPath, 'utf-8');
|
|
145
|
+
return JSON.parse(raw);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch { }
|
|
149
|
+
return null;
|
|
93
150
|
}
|
|
94
151
|
loadLatestSession() {
|
|
95
152
|
const latestPath = path.join(this.sessionsDir, 'latest.json');
|
|
@@ -100,7 +157,8 @@ export class ConfigManager {
|
|
|
100
157
|
}
|
|
101
158
|
}
|
|
102
159
|
catch { }
|
|
103
|
-
|
|
160
|
+
const sessions = this.listSessions();
|
|
161
|
+
return sessions.length > 0 ? sessions[0] : null;
|
|
104
162
|
}
|
|
105
163
|
clear() {
|
|
106
164
|
if (fs.existsSync(this.configFile)) {
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAiCzB,MAAM,OAAO,aAAa;IAChB,SAAS,CAAS;IAClB,UAAU,CAAS;IACnB,WAAW,CAAS;IAE5B;QACE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;QACtD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;QAC3D,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;QACzD,IAAI,CAAC,qBAAqB,EAAE,CAAC;IAC/B,CAAC;IAEO,qBAAqB;QAC3B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC;YACnC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACpD,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;YACrC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED,IAAI;QACF,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;gBACnC,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBACtD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAc,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,IAAI,CAAC,MAAiB;QACpB,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9E,CAAC;IAED,SAAS;QACP,OAAO,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC;IAC9D,CAAC;IAED,SAAS,CAAC,GAAW;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,YAAY,CAAC;IAClC,CAAC;IAED,eAAe,CAAC,KAAa;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,CAAC,YAAY,GAAG,KAAK,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,SAAS,IAAI,MAAM,CAAC;IACzC,CAAC;IAED,YAAY,CAAC,IAAqB;QAChC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAED,iDAAiD;IACjD,eAAe;QACb,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,UAAU,CAAC;QAChC,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxE,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvD,MAAM,eAAe,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,SAAS,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;QAC3E,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC;QAE7C,IAAI,SAAS,IAAI,eAAe,EAAE,CAAC;YACjC,OAAO,KAAK,CAAC,MAAM,CAAC;QACtB,CAAC;QAED,OAAO,IAAI,CAAC,CAAC,mCAAmC;IAClD,CAAC;IAED,eAAe,CAAC,MAAuB;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,CAAC,UAAU,GAAG;YAClB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;YAC9C,MAAM;SACP,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAED,uCAAuC;IACvC,WAAW,CAAC,QAAe,EAAE,KAAa,EAAE,SAAkB;QAC5D,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,MAAM,EAAE,GAAG,SAAS,IAAI,WAAW,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAEhD,4CAA4C;QAC5C,IAAI,KAAK,GAAG,iBAAiB,CAAC;QAC9B,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC;QAC7D,IAAI,YAAY,IAAI,OAAO,YAAY,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YAC7D,KAAK,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,WAAW,GAAiB;YAChC,EAAE;YACF,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,KAAK;YACL,KAAK;YACL,QAAQ;SACT,CAAC;QAEF,IAAI,CAAC;YACH,6BAA6B;YAC7B,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;YAC9D,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;YAE7E,2DAA2D;YAC3D,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;YAC9D,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAC9E,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QAEV,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,YAAY;QACV,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC/C,MAAM,QAAQ,GAAmB,EAAE,CAAC;YACpC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,IAAI,KAAK,aAAa;oBAAE,SAAS;gBAChE,IAAI,CAAC;oBACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;oBACxE,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;oBAC7C,IAAI,IAAI,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACtD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACtB,CAAC;gBACH,CAAC;gBAAC,MAAM,CAAC,CAAA,CAAC;YACZ,CAAC;YACD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;QAC5D,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED,WAAW,CAAC,EAAU;QACpB,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC7B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,OAAO,CAAC;QAC1D,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QAC1D,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;gBAC/B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;gBAClD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;YACzC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iBAAiB;QACf,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;QAC9D,IAAI,CAAC;YACH,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC9B,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;gBACjD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;YACzC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;QACV,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACrC,OAAO,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAClD,CAAC;IAED,KAAK;QACH,IAAI,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YACnC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;CACF"}
|
package/dist/harness/agent.d.ts
CHANGED
|
@@ -10,6 +10,9 @@ export interface ContextStats {
|
|
|
10
10
|
usedTokens: number;
|
|
11
11
|
maxTokens: number;
|
|
12
12
|
sessionTotalTokens: number;
|
|
13
|
+
sessionInputTokens: number;
|
|
14
|
+
sessionOutputTokens: number;
|
|
15
|
+
sessionCacheReadTokens: number;
|
|
13
16
|
percentage: number;
|
|
14
17
|
isWarning: boolean;
|
|
15
18
|
isCritical: boolean;
|
|
@@ -20,13 +23,17 @@ export declare class AgentHarness {
|
|
|
20
23
|
private model;
|
|
21
24
|
private maxTokens;
|
|
22
25
|
private currentTokens;
|
|
23
|
-
private
|
|
26
|
+
private sessionInputTokens;
|
|
27
|
+
private sessionOutputTokens;
|
|
28
|
+
private sessionCacheReadTokens;
|
|
24
29
|
private contextManager;
|
|
25
30
|
private configManager;
|
|
26
31
|
private history;
|
|
27
32
|
private workspaceDir;
|
|
28
33
|
constructor(client: OpenAI, model: string, maxTokens: number, configManager: ConfigManager, workspaceDir?: string);
|
|
29
34
|
resetContext(): void;
|
|
35
|
+
updateSystemPrompt(modeOverride?: 'plan' | 'auto'): void;
|
|
36
|
+
setClient(client: OpenAI): void;
|
|
30
37
|
setModel(newModel: string, maxTokens?: number): void;
|
|
31
38
|
getModel(): string;
|
|
32
39
|
getMaxTokens(): number;
|
|
@@ -47,5 +54,5 @@ export declare class AgentHarness {
|
|
|
47
54
|
after: number;
|
|
48
55
|
savedPercentage: number;
|
|
49
56
|
};
|
|
50
|
-
runTurn(userInput: string, callbacks?: TurnCallbacks): Promise<string>;
|
|
57
|
+
runTurn(userInput: string, callbacks?: TurnCallbacks, modeOverride?: 'plan' | 'auto'): Promise<string>;
|
|
51
58
|
}
|
package/dist/harness/agent.js
CHANGED
|
@@ -5,7 +5,9 @@ export class AgentHarness {
|
|
|
5
5
|
model;
|
|
6
6
|
maxTokens;
|
|
7
7
|
currentTokens = 0;
|
|
8
|
-
|
|
8
|
+
sessionInputTokens = 0;
|
|
9
|
+
sessionOutputTokens = 0;
|
|
10
|
+
sessionCacheReadTokens = 0;
|
|
9
11
|
contextManager;
|
|
10
12
|
configManager;
|
|
11
13
|
history = [];
|
|
@@ -20,14 +22,26 @@ export class AgentHarness {
|
|
|
20
22
|
this.resetContext();
|
|
21
23
|
}
|
|
22
24
|
resetContext() {
|
|
23
|
-
this.history = [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
];
|
|
25
|
+
this.history = [];
|
|
26
|
+
this.sessionInputTokens = 0;
|
|
27
|
+
this.sessionOutputTokens = 0;
|
|
28
|
+
this.sessionCacheReadTokens = 0;
|
|
29
|
+
this.updateSystemPrompt();
|
|
29
30
|
this.recalculateEstimatedTokens();
|
|
30
31
|
}
|
|
32
|
+
updateSystemPrompt(modeOverride) {
|
|
33
|
+
const mode = modeOverride || this.configManager.getAgentMode();
|
|
34
|
+
const systemContent = this.contextManager.buildSystemPrompt(mode);
|
|
35
|
+
if (this.history.length > 0 && this.history[0].role === 'system') {
|
|
36
|
+
this.history[0].content = systemContent;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
this.history.unshift({ role: 'system', content: systemContent });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
setClient(client) {
|
|
43
|
+
this.client = client;
|
|
44
|
+
}
|
|
31
45
|
setModel(newModel, maxTokens) {
|
|
32
46
|
this.model = newModel;
|
|
33
47
|
if (maxTokens) {
|
|
@@ -41,7 +55,7 @@ export class AgentHarness {
|
|
|
41
55
|
return this.maxTokens;
|
|
42
56
|
}
|
|
43
57
|
getSessionTotalTokens() {
|
|
44
|
-
return this.
|
|
58
|
+
return this.sessionInputTokens + this.sessionOutputTokens;
|
|
45
59
|
}
|
|
46
60
|
getContextManager() {
|
|
47
61
|
return this.contextManager;
|
|
@@ -73,10 +87,14 @@ export class AgentHarness {
|
|
|
73
87
|
const filledBars = Math.min(totalBars, Math.round((percentage / 100) * totalBars));
|
|
74
88
|
const emptyBars = totalBars - filledBars;
|
|
75
89
|
const progressBar = `[${'█'.repeat(filledBars)}${'░'.repeat(emptyBars)}]`;
|
|
90
|
+
const totalBilled = this.sessionInputTokens + this.sessionOutputTokens;
|
|
76
91
|
return {
|
|
77
92
|
usedTokens: this.currentTokens,
|
|
78
93
|
maxTokens: this.maxTokens,
|
|
79
|
-
sessionTotalTokens:
|
|
94
|
+
sessionTotalTokens: totalBilled,
|
|
95
|
+
sessionInputTokens: this.sessionInputTokens,
|
|
96
|
+
sessionOutputTokens: this.sessionOutputTokens,
|
|
97
|
+
sessionCacheReadTokens: this.sessionCacheReadTokens,
|
|
80
98
|
percentage,
|
|
81
99
|
isWarning,
|
|
82
100
|
isCritical,
|
|
@@ -96,19 +114,29 @@ export class AgentHarness {
|
|
|
96
114
|
const savedPercentage = Math.max(0, beforeStats.percentage - afterStats.percentage);
|
|
97
115
|
return { before, after, savedPercentage };
|
|
98
116
|
}
|
|
99
|
-
async runTurn(userInput, callbacks = {}) {
|
|
100
|
-
|
|
117
|
+
async runTurn(userInput, callbacks = {}, modeOverride) {
|
|
118
|
+
if (userInput) {
|
|
119
|
+
this.history.push({ role: 'user', content: userInput });
|
|
120
|
+
}
|
|
121
|
+
// Ensure system prompt is synced with the current mode
|
|
122
|
+
const activeMode = modeOverride || this.configManager.getAgentMode();
|
|
123
|
+
this.updateSystemPrompt(activeMode);
|
|
101
124
|
this.history = this.contextManager.autoCompactHistory(this.history);
|
|
102
125
|
let maxSteps = 15;
|
|
103
126
|
let stepCount = 0;
|
|
127
|
+
const writeTools = ['write_file', 'replace_in_file', 'run_command'];
|
|
128
|
+
const activeTools = activeMode === 'plan'
|
|
129
|
+
? TOOL_SCHEMAS.filter(t => !writeTools.includes(t.function.name))
|
|
130
|
+
: TOOL_SCHEMAS.filter(t => t.function.name !== 'submit_plan');
|
|
104
131
|
while (stepCount < maxSteps) {
|
|
105
132
|
stepCount++;
|
|
133
|
+
const payloadMessages = this.contextManager.pruneToolOutputs(this.history);
|
|
106
134
|
let response;
|
|
107
135
|
try {
|
|
108
136
|
response = await this.client.chat.completions.create({
|
|
109
137
|
model: this.model,
|
|
110
|
-
messages:
|
|
111
|
-
tools:
|
|
138
|
+
messages: payloadMessages,
|
|
139
|
+
tools: activeTools,
|
|
112
140
|
tool_choice: 'auto',
|
|
113
141
|
temperature: 0.2,
|
|
114
142
|
});
|
|
@@ -116,16 +144,37 @@ export class AgentHarness {
|
|
|
116
144
|
catch (err) {
|
|
117
145
|
throw new Error(`OpenRouter API error with model [${this.model}]: ${err.message}`);
|
|
118
146
|
}
|
|
119
|
-
// Record live usage from OpenRouter
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
147
|
+
// Record live usage from OpenRouter matching OpenCode standard
|
|
148
|
+
const usage = response.usage;
|
|
149
|
+
if (usage) {
|
|
150
|
+
const promptTokens = usage.prompt_tokens || 0;
|
|
151
|
+
const completionTokens = usage.completion_tokens || 0;
|
|
152
|
+
const cachedTokens = usage.prompt_tokens_details?.cached_tokens || 0;
|
|
153
|
+
this.currentTokens = promptTokens + completionTokens;
|
|
154
|
+
if (stepCount === 1) {
|
|
155
|
+
const freshInput = Math.max(0, promptTokens - cachedTokens);
|
|
156
|
+
this.sessionInputTokens += freshInput;
|
|
157
|
+
this.sessionCacheReadTokens += cachedTokens;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
if (cachedTokens > 0) {
|
|
161
|
+
this.sessionCacheReadTokens += cachedTokens;
|
|
162
|
+
this.sessionInputTokens += Math.max(0, promptTokens - cachedTokens);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
this.sessionCacheReadTokens += promptTokens;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
this.sessionOutputTokens += completionTokens;
|
|
123
169
|
}
|
|
124
170
|
else {
|
|
125
171
|
this.recalculateEstimatedTokens();
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
172
|
+
if (stepCount === 1) {
|
|
173
|
+
this.sessionInputTokens += this.currentTokens;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
this.sessionCacheReadTokens += this.currentTokens;
|
|
177
|
+
}
|
|
129
178
|
}
|
|
130
179
|
const message = response.choices[0]?.message;
|
|
131
180
|
if (!message) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/harness/agent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/harness/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,13 @@ export declare class ContextManager {
|
|
|
4
4
|
private tasteEngine;
|
|
5
5
|
private workspaceDir;
|
|
6
6
|
constructor(workspaceDir?: string);
|
|
7
|
-
buildSystemPrompt(): string;
|
|
7
|
+
buildSystemPrompt(mode: 'plan' | 'auto'): string;
|
|
8
8
|
getTasteEngine(): TasteEngine;
|
|
9
|
+
/**
|
|
10
|
+
* Ephemeral tool output pruning (RTK Pattern):
|
|
11
|
+
* Keeps the latest 3 tool outputs in full, and condenses older large tool outputs.
|
|
12
|
+
*/
|
|
13
|
+
pruneToolOutputs(messages: OpenAI.Chat.Completions.ChatCompletionMessageParam[], keepFullRecent?: number): OpenAI.Chat.Completions.ChatCompletionMessageParam[];
|
|
9
14
|
/**
|
|
10
15
|
* Automatically compacts history if it exceeds rolling limit
|
|
11
16
|
*/
|
package/dist/harness/context.js
CHANGED
|
@@ -7,14 +7,36 @@ export class ContextManager {
|
|
|
7
7
|
this.workspaceDir = workspaceDir;
|
|
8
8
|
this.tasteEngine = new TasteEngine(workspaceDir);
|
|
9
9
|
}
|
|
10
|
-
buildSystemPrompt() {
|
|
10
|
+
buildSystemPrompt(mode) {
|
|
11
11
|
const taste = this.tasteEngine.getTastePrompt();
|
|
12
|
+
let modeDirectives = '';
|
|
13
|
+
if (mode === 'plan') {
|
|
14
|
+
modeDirectives = `
|
|
15
|
+
## PLAN MODE ACTIVE
|
|
16
|
+
1. You MUST NOT execute any commands that modify state (no creating files, no editing code, no destructive shell commands).
|
|
17
|
+
2. You should only use read-only tools to research the user's request.
|
|
18
|
+
3. Once you understand what needs to be done, formulate your plan and call the \`submit_plan\` tool.
|
|
19
|
+
`;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
modeDirectives = `
|
|
23
|
+
## AUTO MODE ACTIVE
|
|
24
|
+
You have full permission to research, write code, edit files, and run commands to complete the user's request autonomously.
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
27
|
+
const toneDirectives = `
|
|
28
|
+
## CONVERSATIONAL TONE (CRITICAL)
|
|
29
|
+
- NEVER announce that you are an AI or explain your limitations.
|
|
30
|
+
- NEVER announce what mode you are in (e.g. do not say "I am in Plan Mode").
|
|
31
|
+
- Be strictly professional, concise, and direct. No fluff, no pleasantries, no AI slop.
|
|
32
|
+
`;
|
|
12
33
|
return `You are eco-code, an autonomous and intelligent CLI coding assistant.
|
|
13
34
|
You are running directly in the developer's terminal environment.
|
|
14
35
|
|
|
15
36
|
Current Workspace: ${this.workspaceDir}
|
|
16
37
|
Operating System: ${os.platform()} (${os.arch()})
|
|
17
|
-
|
|
38
|
+
${modeDirectives}
|
|
39
|
+
${toneDirectives}
|
|
18
40
|
## Tools — IMPORTANT CONTRACT
|
|
19
41
|
Always prefer these deterministic tools:
|
|
20
42
|
- Use \`read_file\` for all file reading. It is windowed and limits reads to 2000 lines. Do not re-read large files from the beginning.
|
|
@@ -26,10 +48,11 @@ Always prefer these deterministic tools:
|
|
|
26
48
|
|
|
27
49
|
## CORE CAPABILITIES & RULES:
|
|
28
50
|
1. Always inspect a file using read_file before attempting to edit it with replace_in_file.
|
|
29
|
-
2.
|
|
30
|
-
3.
|
|
31
|
-
4.
|
|
32
|
-
5.
|
|
51
|
+
2. For editing existing files, ALWAYS prefer replace_in_file (targeted diffs). Do NOT rewrite entire files with write_file unless creating a brand new file.
|
|
52
|
+
3. Be precise with replace_in_file: target_content must match the file content verbatim.
|
|
53
|
+
4. When writing code, write complete, working code without placeholders or omissions.
|
|
54
|
+
5. Verify your changes when appropriate.
|
|
55
|
+
6. Keep conversational replies concise, direct, and token-efficient. Do not pad responses or repeat unchanged code.
|
|
33
56
|
|
|
34
57
|
TASTE & DIRECTIVES:
|
|
35
58
|
${taste}`;
|
|
@@ -37,6 +60,34 @@ ${taste}`;
|
|
|
37
60
|
getTasteEngine() {
|
|
38
61
|
return this.tasteEngine;
|
|
39
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Ephemeral tool output pruning (RTK Pattern):
|
|
65
|
+
* Keeps the latest 3 tool outputs in full, and condenses older large tool outputs.
|
|
66
|
+
*/
|
|
67
|
+
pruneToolOutputs(messages, keepFullRecent = 3) {
|
|
68
|
+
const toolIndices = [];
|
|
69
|
+
messages.forEach((m, idx) => {
|
|
70
|
+
if (m.role === 'tool')
|
|
71
|
+
toolIndices.push(idx);
|
|
72
|
+
});
|
|
73
|
+
if (toolIndices.length <= keepFullRecent) {
|
|
74
|
+
return messages;
|
|
75
|
+
}
|
|
76
|
+
const olderToolIndices = new Set(toolIndices.slice(0, -keepFullRecent));
|
|
77
|
+
return messages.map((m, idx) => {
|
|
78
|
+
if (olderToolIndices.has(idx) && m.role === 'tool' && typeof m.content === 'string') {
|
|
79
|
+
if (m.content.length > 250) {
|
|
80
|
+
const lines = m.content.split('\n');
|
|
81
|
+
const preview = lines.slice(0, 3).join('\n');
|
|
82
|
+
return {
|
|
83
|
+
...m,
|
|
84
|
+
content: `${preview}\n... [${lines.length} lines of older tool output condensed by harness to save tokens]`,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return m;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
40
91
|
/**
|
|
41
92
|
* Automatically compacts history if it exceeds rolling limit
|
|
42
93
|
*/
|