micro-models-agent 0.14.3 → 0.15.1
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/dist/cli/main.js +3 -0
- package/dist/cli/repl.js +7 -2
- package/dist/cli/setup.js +1 -1
- package/dist/config/config.js +5 -2
- package/dist/config/defaults.js +1 -1
- package/dist/config/security.js +5 -2
- package/dist/core/agent.js +12 -0
- package/dist/core/bootstrap.js +0 -1
- package/dist/llm/openai-compat.js +25 -1
- package/dist/modules/security/command-validator.js +4 -2
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -36,6 +36,9 @@ async function main() {
|
|
|
36
36
|
iterationCount: result.iterationCount,
|
|
37
37
|
contextUsed: result.contextUsed ?? null,
|
|
38
38
|
contextLimit: result.contextLimit ?? null,
|
|
39
|
+
promptTokens: result.promptTokens ?? null,
|
|
40
|
+
completionTokens: result.completionTokens ?? null,
|
|
41
|
+
totalTokens: result.totalTokens ?? null,
|
|
39
42
|
}, null, 2));
|
|
40
43
|
process.stdout.write("\n");
|
|
41
44
|
process.exit(result.success ? 0 : 1);
|
package/dist/cli/repl.js
CHANGED
|
@@ -358,7 +358,7 @@ export class Repl {
|
|
|
358
358
|
action: (args) => {
|
|
359
359
|
if (args.length === 0) {
|
|
360
360
|
console.log(`/context ${t("repl.context")} ${this.config.contextWindow}`);
|
|
361
|
-
console.log(
|
|
361
|
+
console.log(`Usage: /context <size> (min 1024)`);
|
|
362
362
|
return;
|
|
363
363
|
}
|
|
364
364
|
const size = parseInt(args[0], 10);
|
|
@@ -862,7 +862,12 @@ export class Repl {
|
|
|
862
862
|
result.contextLimit !== undefined &&
|
|
863
863
|
result.contextLimit > 0) {
|
|
864
864
|
console.log();
|
|
865
|
-
|
|
865
|
+
const ctxLine = formatContextBar(result.contextUsed, result.contextLimit);
|
|
866
|
+
console.log(ctxLine);
|
|
867
|
+
if (result.totalTokens !== undefined && result.totalTokens > 0) {
|
|
868
|
+
const apiLine = pc.dim(` API: ${result.promptTokens} prompt + ${result.completionTokens} completion = ${result.totalTokens} total`);
|
|
869
|
+
console.log(apiLine);
|
|
870
|
+
}
|
|
866
871
|
}
|
|
867
872
|
}
|
|
868
873
|
start() {
|
package/dist/cli/setup.js
CHANGED
|
@@ -185,7 +185,7 @@ export async function runSetup() {
|
|
|
185
185
|
}
|
|
186
186
|
console.log(t("setup.agent_settings"));
|
|
187
187
|
const contextWindow = parseInt(await ask(rl, t("setup.context_window"), "32768"));
|
|
188
|
-
const maxIterations = parseInt(await ask(rl, t("setup.max_iters"), "
|
|
188
|
+
const maxIterations = parseInt(await ask(rl, t("setup.max_iters"), "1000"));
|
|
189
189
|
rl.close();
|
|
190
190
|
const answers = {
|
|
191
191
|
provider,
|
package/dist/config/config.js
CHANGED
|
@@ -146,8 +146,11 @@ function forceSecurityUpdate(config) {
|
|
|
146
146
|
...DEFAULT_SECURITY_CONFIG.bash.dangerousFlags,
|
|
147
147
|
...(userBash.dangerousFlags || []),
|
|
148
148
|
])],
|
|
149
|
-
// dangerousOperators:
|
|
150
|
-
dangerousOperators: [...
|
|
149
|
+
// dangerousOperators: merge user's additions with defaults (user can add but not remove critical ones)
|
|
150
|
+
dangerousOperators: [...new Set([
|
|
151
|
+
...DEFAULT_SECURITY_CONFIG.bash.dangerousOperators,
|
|
152
|
+
...(userBash.dangerousOperators || []),
|
|
153
|
+
])],
|
|
151
154
|
blockDangerousFlags: DEFAULT_SECURITY_CONFIG.bash.blockDangerousFlags,
|
|
152
155
|
logCommands: DEFAULT_SECURITY_CONFIG.bash.logCommands,
|
|
153
156
|
};
|
package/dist/config/defaults.js
CHANGED
package/dist/config/security.js
CHANGED
|
@@ -45,7 +45,8 @@ export const DEFAULT_SECURITY_CONFIG = {
|
|
|
45
45
|
// If whitelist is non-empty, only these commands are allowed
|
|
46
46
|
whitelist: [],
|
|
47
47
|
// Block dangerous flags like --force, -rf, etc.
|
|
48
|
-
|
|
48
|
+
// Disabled by default — enable in config if needed.
|
|
49
|
+
blockDangerousFlags: false,
|
|
49
50
|
// Log all executed commands to audit log
|
|
50
51
|
logCommands: true,
|
|
51
52
|
// Dangerous flags that are always blocked
|
|
@@ -65,7 +66,9 @@ export const DEFAULT_SECURITY_CONFIG = {
|
|
|
65
66
|
"--no-confirm",
|
|
66
67
|
],
|
|
67
68
|
// Dangerous operators that are always blocked
|
|
68
|
-
|
|
69
|
+
// Note: "&" (background) is not blocked — "&&" (AND) is a legitimate shell operator.
|
|
70
|
+
// Single "&" for backgrounding is harmless and blocking it breaks "cd dir && npm install".
|
|
71
|
+
dangerousOperators: [">", ">>", "2>", "2>>", "`"],
|
|
69
72
|
},
|
|
70
73
|
paths: {
|
|
71
74
|
// Glob patterns for paths that are always denied
|
package/dist/core/agent.js
CHANGED
|
@@ -110,6 +110,8 @@ export class Agent {
|
|
|
110
110
|
let lastText = "";
|
|
111
111
|
let hallucinationRetries = 0;
|
|
112
112
|
let lastToolSignature = "";
|
|
113
|
+
let apiPromptTokens = 0;
|
|
114
|
+
let apiCompletionTokens = 0;
|
|
113
115
|
const MAX_HALLUCINATION_RETRIES = 3;
|
|
114
116
|
while (iteration < config.maxToolIterations) {
|
|
115
117
|
iteration++;
|
|
@@ -177,6 +179,10 @@ export class Agent {
|
|
|
177
179
|
arguments: parsedArgs,
|
|
178
180
|
});
|
|
179
181
|
}
|
|
182
|
+
if (chunk.type === "done" && chunk.usage) {
|
|
183
|
+
apiPromptTokens += chunk.usage.promptTokens;
|
|
184
|
+
apiCompletionTokens += chunk.usage.completionTokens;
|
|
185
|
+
}
|
|
180
186
|
}
|
|
181
187
|
}
|
|
182
188
|
catch (err) {
|
|
@@ -381,6 +387,9 @@ export class Agent {
|
|
|
381
387
|
iterationCount: iteration,
|
|
382
388
|
contextUsed: tokensUsed,
|
|
383
389
|
contextLimit: budget.history,
|
|
390
|
+
promptTokens: apiPromptTokens,
|
|
391
|
+
completionTokens: apiCompletionTokens,
|
|
392
|
+
totalTokens: apiPromptTokens + apiCompletionTokens,
|
|
384
393
|
};
|
|
385
394
|
}
|
|
386
395
|
return {
|
|
@@ -389,6 +398,9 @@ export class Agent {
|
|
|
389
398
|
iterationCount: iteration,
|
|
390
399
|
contextUsed: tokensUsed,
|
|
391
400
|
contextLimit: budget.history,
|
|
401
|
+
promptTokens: apiPromptTokens,
|
|
402
|
+
completionTokens: apiCompletionTokens,
|
|
403
|
+
totalTokens: apiPromptTokens + apiCompletionTokens,
|
|
392
404
|
};
|
|
393
405
|
}
|
|
394
406
|
clearContext() {
|
package/dist/core/bootstrap.js
CHANGED
|
@@ -33,7 +33,6 @@ function buildSystemInfo(config, baseDir, profileCompressed) {
|
|
|
33
33
|
`Workspace: ${baseDir}`,
|
|
34
34
|
`${profileCompressed}`,
|
|
35
35
|
`Reply in the user's language. Use tools for filesystem, bash, web access.`,
|
|
36
|
-
`When the task is ambiguous or has multiple reasonable options, ask the user via the "question" tool instead of guessing.`,
|
|
37
36
|
`When you need to act, call a tool immediately. Do not describe your plans in text — use tools to perform operations.`,
|
|
38
37
|
`After every tool call, check whether the user's request is fully satisfied. If any files, commands, or checks are still missing, call the next needed tool right away. Do not stop with an empty or "done" response until the task is complete.`,
|
|
39
38
|
`If you create a directory, continue creating the files that belong inside it. A created folder alone is not a completed task.`,
|
|
@@ -98,6 +98,7 @@ export class OpenAICompatProvider {
|
|
|
98
98
|
const decoder = new TextDecoder();
|
|
99
99
|
let buffer = "";
|
|
100
100
|
const toolCallAccs = new Map();
|
|
101
|
+
let usage;
|
|
101
102
|
try {
|
|
102
103
|
while (true) {
|
|
103
104
|
const { done, value } = await reader.read();
|
|
@@ -116,8 +117,17 @@ export class OpenAICompatProvider {
|
|
|
116
117
|
try {
|
|
117
118
|
const parsed = JSON.parse(data);
|
|
118
119
|
const choice = parsed.choices?.[0];
|
|
119
|
-
if (!choice)
|
|
120
|
+
if (!choice) {
|
|
121
|
+
// Usage comes in the last chunk with empty choices
|
|
122
|
+
if (parsed.usage) {
|
|
123
|
+
usage = {
|
|
124
|
+
promptTokens: parsed.usage.prompt_tokens ?? 0,
|
|
125
|
+
completionTokens: parsed.usage.completion_tokens ?? 0,
|
|
126
|
+
totalTokens: parsed.usage.total_tokens ?? 0,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
120
129
|
continue;
|
|
130
|
+
}
|
|
121
131
|
const delta = choice.delta || {};
|
|
122
132
|
const finishReason = choice.finish_reason;
|
|
123
133
|
if (delta.reasoning_content) {
|
|
@@ -163,6 +173,9 @@ export class OpenAICompatProvider {
|
|
|
163
173
|
}
|
|
164
174
|
}
|
|
165
175
|
}
|
|
176
|
+
if (usage) {
|
|
177
|
+
yield { type: "done", usage };
|
|
178
|
+
}
|
|
166
179
|
}
|
|
167
180
|
finally {
|
|
168
181
|
clearTimeout(timeoutId);
|
|
@@ -232,6 +245,17 @@ export class OpenAICompatProvider {
|
|
|
232
245
|
});
|
|
233
246
|
}
|
|
234
247
|
}
|
|
248
|
+
// Append usage from API response
|
|
249
|
+
if (data.usage) {
|
|
250
|
+
chunks.push({
|
|
251
|
+
type: "done",
|
|
252
|
+
usage: {
|
|
253
|
+
promptTokens: data.usage.prompt_tokens ?? 0,
|
|
254
|
+
completionTokens: data.usage.completion_tokens ?? 0,
|
|
255
|
+
totalTokens: data.usage.total_tokens ?? 0,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
235
259
|
return chunks;
|
|
236
260
|
}
|
|
237
261
|
catch (err) {
|
|
@@ -3,9 +3,9 @@ import { DEFAULT_SECURITY_CONFIG } from "../../config/security";
|
|
|
3
3
|
const FALLBACK_BASH_CONFIG = {
|
|
4
4
|
blacklist: ['rm', 'dd', 'chmod', 'wget', 'curl', 'scp', 'ssh', 'nc', 'netcat'],
|
|
5
5
|
whitelist: [],
|
|
6
|
-
blockDangerousFlags:
|
|
6
|
+
blockDangerousFlags: false,
|
|
7
7
|
dangerousFlags: ['--force', '-rf', '--no-preserve-root'],
|
|
8
|
-
dangerousOperators: ['>', '>>', '2>', '2>>', '|', '&&', '||', ';', '
|
|
8
|
+
dangerousOperators: ['>', '>>', '2>', '2>>', '|', '&&', '||', ';', '`'],
|
|
9
9
|
logCommands: true,
|
|
10
10
|
};
|
|
11
11
|
export const DEFAULT_BASH_CONFIG = DEFAULT_SECURITY_CONFIG?.bash || FALLBACK_BASH_CONFIG;
|
|
@@ -55,6 +55,8 @@ function containsOperator(command, op) {
|
|
|
55
55
|
const escaped = op.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
56
56
|
// For single-char operators that are prefixes of multi-char ones,
|
|
57
57
|
// ensure they don't match when part of a longer sequence.
|
|
58
|
+
// Note: "&" is no longer in dangerousOperators (&& is legitimate),
|
|
59
|
+
// but keep the special case for defense-in-depth if manually added.
|
|
58
60
|
if (op === '&')
|
|
59
61
|
return /(?<!&)&(?!&)/.test(command);
|
|
60
62
|
if (op === '|')
|