agent-sh 0.15.3 → 0.15.4
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/agent/providers/openai-compatible.d.ts +4 -2
- package/dist/agent/providers/openai-compatible.js +5 -0
- package/dist/utils/diff-renderer.js +27 -26
- package/dist/utils/palette.d.ts +1 -0
- package/dist/utils/palette.js +5 -4
- package/package.json +1 -1
- package/src/agent/providers/openai-compatible.ts +10 -2
- package/src/utils/diff-renderer.ts +28 -30
- package/src/utils/palette.ts +6 -4
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenAI Chat Completions-compatible local/3rd-party server (Ollama, LM
|
|
3
|
-
* Studio, vLLM, llama.cpp, …).
|
|
4
|
-
*
|
|
3
|
+
* Studio, vLLM, llama.cpp, …). Emits the common `reasoning_effort` shape,
|
|
4
|
+
* with `"none"` to disable — the value most local servers honor. A server
|
|
5
|
+
* wanting a different disable token can override via `reasoningShape` or a
|
|
6
|
+
* user extension.
|
|
5
7
|
*/
|
|
6
8
|
import type { AgentContext } from "../host-types.js";
|
|
7
9
|
export default function activate(ctx: AgentContext): void;
|
|
@@ -5,6 +5,11 @@ export default function activate(ctx) {
|
|
|
5
5
|
// Local servers often need no key; SDK still wants a non-empty string.
|
|
6
6
|
const apiKey = process.env.OPENAI_API_KEY || "no-key";
|
|
7
7
|
const id = "openai-compatible";
|
|
8
|
+
ctx.agent.providers.configure(id, {
|
|
9
|
+
reasoningParams: (level) => level === "off"
|
|
10
|
+
? { reasoning_effort: "none" }
|
|
11
|
+
: { reasoning_effort: level === "xhigh" ? "high" : level },
|
|
12
|
+
});
|
|
8
13
|
ctx.agent.providers.register({ id, apiKey, baseURL, models: [] });
|
|
9
14
|
fetchModels(baseURL, apiKey).then((models) => {
|
|
10
15
|
if (models.length === 0)
|
|
@@ -157,7 +157,7 @@ function highlightInlineChanges(oldLine, newLine, oldPalette, newPalette, useTru
|
|
|
157
157
|
}
|
|
158
158
|
else {
|
|
159
159
|
// Changed tokens: emphasis background, no syntax highlighting (emphasis stands out)
|
|
160
|
-
result += palette.emphBg +
|
|
160
|
+
result += palette.emphBg + tokens[i].text + p.reset;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
return result;
|
|
@@ -246,55 +246,56 @@ function renderUnifiedHunk(hunk, layout) {
|
|
|
246
246
|
const { noW, lineTextW, textWidth, useTrueColor, gutterLine, lang, removedPalette, addedPalette } = layout;
|
|
247
247
|
const out = [];
|
|
248
248
|
const pairs = findChangePairs(hunk);
|
|
249
|
-
const renderedAsPartOfPair = new Set();
|
|
250
249
|
const bgWidth = Math.max(1, textWidth - noW - 3);
|
|
251
250
|
const gutter = (n) => `${p.dim}${n} │${p.reset} `;
|
|
252
251
|
const change = (no, sigil, bg, fg, text) => {
|
|
253
252
|
if (!gutterLine) {
|
|
254
|
-
return `${bg}${fg}${
|
|
253
|
+
return `${bg}${padToWidth(`${fg}${no} ${sigil}${p.diffText} ${preserveBg(text, bg)}`, textWidth)}${p.reset}`;
|
|
255
254
|
}
|
|
256
255
|
if (useTrueColor)
|
|
257
|
-
return gutter(no) + padToWidth(`${bg}${fg}${sigil} ${preserveBg(text, bg)}`, bgWidth) + p.reset;
|
|
256
|
+
return gutter(no) + padToWidth(`${bg}${fg}${sigil}${p.diffText} ${preserveBg(text, bg)}`, bgWidth) + p.reset;
|
|
258
257
|
return `${gutter(no)}${fg}${sigil} ${text}${p.reset}`;
|
|
259
258
|
};
|
|
259
|
+
const hlCache = new Map();
|
|
260
|
+
const highlightedPair = (pair) => {
|
|
261
|
+
let h = hlCache.get(pair);
|
|
262
|
+
if (!h) {
|
|
263
|
+
h = highlightInlineChanges(pair.removed.text, pair.added.text, removedPalette, addedPalette, useTrueColor, lang);
|
|
264
|
+
hlCache.set(pair, h);
|
|
265
|
+
}
|
|
266
|
+
return h;
|
|
267
|
+
};
|
|
260
268
|
for (let i = 0; i < hunk.lines.length; i++) {
|
|
261
269
|
const line = hunk.lines[i];
|
|
262
270
|
const no = String(line.type === "removed" ? (line.oldNo ?? "") : (line.newNo ?? line.oldNo ?? "")).padStart(noW);
|
|
263
271
|
if (line.type === "context") {
|
|
264
272
|
const raw = truncateText(line.text, lineTextW);
|
|
265
273
|
const text = lang ? highlightLine(raw, lang) : raw;
|
|
266
|
-
// The flush gutter dims only the line number; the code stays normal/highlighted.
|
|
267
274
|
out.push(!gutterLine ? `${p.dim}${no}${p.reset} ${text}` : `${gutter(no)} ${p.dim}${text}${p.reset}`);
|
|
268
275
|
continue;
|
|
269
276
|
}
|
|
277
|
+
const pair = pairs.get(i);
|
|
270
278
|
if (line.type === "removed") {
|
|
271
|
-
const pair = pairs.get(i);
|
|
272
279
|
let removedText;
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
if (pair && pair.removedIdx === i) {
|
|
276
|
-
const highlighted = highlightInlineChanges(line.text, pair.added.text, removedPalette, addedPalette, useTrueColor, lang);
|
|
277
|
-
removedText = truncateText(highlighted.old, lineTextW);
|
|
278
|
-
addedText = truncateText(highlighted.new, lineTextW);
|
|
279
|
-
addedNo = String(pair.added.newNo ?? "").padStart(noW);
|
|
280
|
-
renderedAsPartOfPair.add(pair.addedIdx);
|
|
280
|
+
if (pair) {
|
|
281
|
+
removedText = truncateText(highlightedPair(pair).old, lineTextW);
|
|
281
282
|
}
|
|
282
283
|
else {
|
|
283
284
|
const raw = truncateText(line.text, lineTextW);
|
|
284
285
|
removedText = lang ? highlightLine(raw, lang) : raw;
|
|
285
286
|
}
|
|
286
287
|
out.push(change(no, "-", p.errorBg, p.error, removedText));
|
|
287
|
-
if (addedText !== null && addedNo !== null) {
|
|
288
|
-
out.push(change(addedNo, "+", p.successBg, p.success, addedText));
|
|
289
|
-
}
|
|
290
|
-
continue;
|
|
291
288
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
289
|
+
else {
|
|
290
|
+
let addedText;
|
|
291
|
+
if (pair) {
|
|
292
|
+
addedText = truncateText(highlightedPair(pair).new, lineTextW);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
const raw = truncateText(line.text, lineTextW);
|
|
296
|
+
addedText = lang ? highlightLine(raw, lang) : raw;
|
|
297
|
+
}
|
|
298
|
+
out.push(change(no, "+", p.successBg, p.success, addedText));
|
|
298
299
|
}
|
|
299
300
|
}
|
|
300
301
|
return out;
|
|
@@ -362,7 +363,7 @@ function renderSplitHunk(hunk, layout) {
|
|
|
362
363
|
}
|
|
363
364
|
else if (row.left.type === "removed") {
|
|
364
365
|
if (useTrueColor) {
|
|
365
|
-
leftCol = padToWidth(`${p.errorBg}${p.error}${leftNo}
|
|
366
|
+
leftCol = padToWidth(`${p.errorBg}${p.error}${leftNo} │${p.diffText} ${preserveBg(leftText, p.errorBg)}`, colWidth) + p.reset;
|
|
366
367
|
}
|
|
367
368
|
else {
|
|
368
369
|
leftCol = padToWidth(`${p.error}${leftNo} │ ${leftText}${p.reset}`, colWidth);
|
|
@@ -376,7 +377,7 @@ function renderSplitHunk(hunk, layout) {
|
|
|
376
377
|
}
|
|
377
378
|
else if (row.right.type === "added") {
|
|
378
379
|
if (useTrueColor) {
|
|
379
|
-
rightCol = padToWidth(`${p.successBg}${p.success}${rightNo}
|
|
380
|
+
rightCol = padToWidth(`${p.successBg}${p.success}${rightNo} │${p.diffText} ${preserveBg(rightText, p.successBg)}`, colWidth) + p.reset;
|
|
380
381
|
}
|
|
381
382
|
else {
|
|
382
383
|
rightCol = padToWidth(`${p.success}${rightNo} │ ${rightText}${p.reset}`, colWidth);
|
package/dist/utils/palette.d.ts
CHANGED
package/dist/utils/palette.js
CHANGED
|
@@ -14,10 +14,11 @@ const defaultPalette = {
|
|
|
14
14
|
warning: "\x1b[33m", // yellow
|
|
15
15
|
error: "\x1b[31m", // red
|
|
16
16
|
muted: "\x1b[90m", // gray
|
|
17
|
-
successBg: "\x1b[48;2;
|
|
18
|
-
errorBg: "\x1b[48;2;
|
|
19
|
-
successBgEmph: "\x1b[48;2;
|
|
20
|
-
errorBgEmph: "\x1b[48;2;
|
|
17
|
+
successBg: "\x1b[48;2;26;70;34m",
|
|
18
|
+
errorBg: "\x1b[48;2;92;32;42m",
|
|
19
|
+
successBgEmph: "\x1b[48;2;38;104;56m",
|
|
20
|
+
errorBgEmph: "\x1b[48;2;124;50;64m",
|
|
21
|
+
diffText: "\x1b[97m", // bright white — readable on the red/green tints
|
|
21
22
|
bold: "\x1b[1m",
|
|
22
23
|
dim: "\x1b[2m",
|
|
23
24
|
italic: "\x1b[3m",
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* OpenAI Chat Completions-compatible local/3rd-party server (Ollama, LM
|
|
3
|
-
* Studio, vLLM, llama.cpp, …).
|
|
4
|
-
*
|
|
3
|
+
* Studio, vLLM, llama.cpp, …). Emits the common `reasoning_effort` shape,
|
|
4
|
+
* with `"none"` to disable — the value most local servers honor. A server
|
|
5
|
+
* wanting a different disable token can override via `reasoningShape` or a
|
|
6
|
+
* user extension.
|
|
5
7
|
*/
|
|
6
8
|
import type { AgentContext } from "../host-types.js";
|
|
7
9
|
|
|
@@ -13,6 +15,12 @@ export default function activate(ctx: AgentContext): void {
|
|
|
13
15
|
const apiKey = process.env.OPENAI_API_KEY || "no-key";
|
|
14
16
|
const id = "openai-compatible";
|
|
15
17
|
|
|
18
|
+
ctx.agent.providers.configure(id, {
|
|
19
|
+
reasoningParams: (level) =>
|
|
20
|
+
level === "off"
|
|
21
|
+
? { reasoning_effort: "none" }
|
|
22
|
+
: { reasoning_effort: level === "xhigh" ? "high" : level },
|
|
23
|
+
});
|
|
16
24
|
ctx.agent.providers.register({ id, apiKey, baseURL, models: [] });
|
|
17
25
|
fetchModels(baseURL, apiKey).then((models) => {
|
|
18
26
|
if (models.length === 0) return;
|
|
@@ -216,7 +216,7 @@ function highlightInlineChanges(
|
|
|
216
216
|
result += palette.rowBg + preserveBg(text, palette.rowBg);
|
|
217
217
|
} else {
|
|
218
218
|
// Changed tokens: emphasis background, no syntax highlighting (emphasis stands out)
|
|
219
|
-
result += palette.emphBg +
|
|
219
|
+
result += palette.emphBg + tokens[i].text + p.reset;
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
return result;
|
|
@@ -337,18 +337,29 @@ function renderUnifiedHunk(hunk: DiffHunk, layout: UnifiedLayout): string[] {
|
|
|
337
337
|
const out: string[] = [];
|
|
338
338
|
|
|
339
339
|
const pairs = findChangePairs(hunk);
|
|
340
|
-
const renderedAsPartOfPair = new Set<number>();
|
|
341
340
|
const bgWidth = Math.max(1, textWidth - noW - 3);
|
|
342
341
|
const gutter = (n: string): string => `${p.dim}${n} │${p.reset} `;
|
|
343
342
|
|
|
344
343
|
const change = (no: string, sigil: string, bg: string, fg: string, text: string): string => {
|
|
345
344
|
if (!gutterLine) {
|
|
346
|
-
return `${bg}${fg}${
|
|
345
|
+
return `${bg}${padToWidth(`${fg}${no} ${sigil}${p.diffText} ${preserveBg(text, bg)}`, textWidth)}${p.reset}`;
|
|
347
346
|
}
|
|
348
|
-
if (useTrueColor) return gutter(no) + padToWidth(`${bg}${fg}${sigil} ${preserveBg(text, bg)}`, bgWidth) + p.reset;
|
|
347
|
+
if (useTrueColor) return gutter(no) + padToWidth(`${bg}${fg}${sigil}${p.diffText} ${preserveBg(text, bg)}`, bgWidth) + p.reset;
|
|
349
348
|
return `${gutter(no)}${fg}${sigil} ${text}${p.reset}`;
|
|
350
349
|
};
|
|
351
350
|
|
|
351
|
+
const hlCache = new Map<ChangePair, { old: string; new: string }>();
|
|
352
|
+
const highlightedPair = (pair: ChangePair): { old: string; new: string } => {
|
|
353
|
+
let h = hlCache.get(pair);
|
|
354
|
+
if (!h) {
|
|
355
|
+
h = highlightInlineChanges(
|
|
356
|
+
pair.removed.text, pair.added.text, removedPalette, addedPalette, useTrueColor, lang,
|
|
357
|
+
);
|
|
358
|
+
hlCache.set(pair, h);
|
|
359
|
+
}
|
|
360
|
+
return h;
|
|
361
|
+
};
|
|
362
|
+
|
|
352
363
|
for (let i = 0; i < hunk.lines.length; i++) {
|
|
353
364
|
const line = hunk.lines[i];
|
|
354
365
|
const no = String(
|
|
@@ -358,42 +369,29 @@ function renderUnifiedHunk(hunk: DiffHunk, layout: UnifiedLayout): string[] {
|
|
|
358
369
|
if (line.type === "context") {
|
|
359
370
|
const raw = truncateText(line.text, lineTextW);
|
|
360
371
|
const text = lang ? highlightLine(raw, lang) : raw;
|
|
361
|
-
// The flush gutter dims only the line number; the code stays normal/highlighted.
|
|
362
372
|
out.push(!gutterLine ? `${p.dim}${no}${p.reset} ${text}` : `${gutter(no)} ${p.dim}${text}${p.reset}`);
|
|
363
373
|
continue;
|
|
364
374
|
}
|
|
365
375
|
|
|
376
|
+
const pair = pairs.get(i);
|
|
366
377
|
if (line.type === "removed") {
|
|
367
|
-
const pair = pairs.get(i);
|
|
368
378
|
let removedText: string;
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
if (pair && pair.removedIdx === i) {
|
|
373
|
-
const highlighted = highlightInlineChanges(
|
|
374
|
-
line.text, pair.added.text, removedPalette, addedPalette, useTrueColor, lang,
|
|
375
|
-
);
|
|
376
|
-
removedText = truncateText(highlighted.old, lineTextW);
|
|
377
|
-
addedText = truncateText(highlighted.new, lineTextW);
|
|
378
|
-
addedNo = String(pair.added.newNo ?? "").padStart(noW);
|
|
379
|
-
renderedAsPartOfPair.add(pair.addedIdx);
|
|
379
|
+
if (pair) {
|
|
380
|
+
removedText = truncateText(highlightedPair(pair).old, lineTextW);
|
|
380
381
|
} else {
|
|
381
382
|
const raw = truncateText(line.text, lineTextW);
|
|
382
383
|
removedText = lang ? highlightLine(raw, lang) : raw;
|
|
383
384
|
}
|
|
384
|
-
|
|
385
385
|
out.push(change(no, "-", p.errorBg, p.error, removedText));
|
|
386
|
-
|
|
387
|
-
|
|
386
|
+
} else {
|
|
387
|
+
let addedText: string;
|
|
388
|
+
if (pair) {
|
|
389
|
+
addedText = truncateText(highlightedPair(pair).new, lineTextW);
|
|
390
|
+
} else {
|
|
391
|
+
const raw = truncateText(line.text, lineTextW);
|
|
392
|
+
addedText = lang ? highlightLine(raw, lang) : raw;
|
|
388
393
|
}
|
|
389
|
-
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
if (line.type === "added") {
|
|
393
|
-
if (renderedAsPartOfPair.has(i)) continue;
|
|
394
|
-
const raw = truncateText(line.text, lineTextW);
|
|
395
|
-
const text = lang ? highlightLine(raw, lang) : raw;
|
|
396
|
-
out.push(change(no, "+", p.successBg, p.success, text));
|
|
394
|
+
out.push(change(no, "+", p.successBg, p.success, addedText));
|
|
397
395
|
}
|
|
398
396
|
}
|
|
399
397
|
return out;
|
|
@@ -478,7 +476,7 @@ function renderSplitHunk(hunk: DiffHunk, layout: SplitLayout): string[] {
|
|
|
478
476
|
} else if (row.left.type === "removed") {
|
|
479
477
|
if (useTrueColor) {
|
|
480
478
|
leftCol = padToWidth(
|
|
481
|
-
`${p.errorBg}${p.error}${leftNo}
|
|
479
|
+
`${p.errorBg}${p.error}${leftNo} │${p.diffText} ${preserveBg(leftText, p.errorBg)}`, colWidth,
|
|
482
480
|
) + p.reset;
|
|
483
481
|
} else {
|
|
484
482
|
leftCol = padToWidth(`${p.error}${leftNo} │ ${leftText}${p.reset}`, colWidth);
|
|
@@ -492,7 +490,7 @@ function renderSplitHunk(hunk: DiffHunk, layout: SplitLayout): string[] {
|
|
|
492
490
|
} else if (row.right.type === "added") {
|
|
493
491
|
if (useTrueColor) {
|
|
494
492
|
rightCol = padToWidth(
|
|
495
|
-
`${p.successBg}${p.success}${rightNo}
|
|
493
|
+
`${p.successBg}${p.success}${rightNo} │${p.diffText} ${preserveBg(rightText, p.successBg)}`, colWidth,
|
|
496
494
|
) + p.reset;
|
|
497
495
|
} else {
|
|
498
496
|
rightCol = padToWidth(`${p.success}${rightNo} │ ${rightText}${p.reset}`, colWidth);
|
package/src/utils/palette.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface ColorPalette {
|
|
|
22
22
|
errorBg: string; // subtle red tint for removed lines
|
|
23
23
|
successBgEmph: string; // stronger green for changed tokens
|
|
24
24
|
errorBgEmph: string; // stronger red for changed tokens
|
|
25
|
+
diffText: string; // legible fg for diff row text on the tinted rows
|
|
25
26
|
|
|
26
27
|
// ── Style modifiers ───────────────────────────────────────
|
|
27
28
|
bold: string;
|
|
@@ -38,10 +39,11 @@ const defaultPalette: ColorPalette = {
|
|
|
38
39
|
error: "\x1b[31m", // red
|
|
39
40
|
muted: "\x1b[90m", // gray
|
|
40
41
|
|
|
41
|
-
successBg: "\x1b[48;2;
|
|
42
|
-
errorBg: "\x1b[48;2;
|
|
43
|
-
successBgEmph: "\x1b[48;2;
|
|
44
|
-
errorBgEmph: "\x1b[48;2;
|
|
42
|
+
successBg: "\x1b[48;2;26;70;34m",
|
|
43
|
+
errorBg: "\x1b[48;2;92;32;42m",
|
|
44
|
+
successBgEmph: "\x1b[48;2;38;104;56m",
|
|
45
|
+
errorBgEmph: "\x1b[48;2;124;50;64m",
|
|
46
|
+
diffText: "\x1b[97m", // bright white — readable on the red/green tints
|
|
45
47
|
|
|
46
48
|
bold: "\x1b[1m",
|
|
47
49
|
dim: "\x1b[2m",
|