@oh-my-pi/pi-coding-agent 15.10.2 → 15.10.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/CHANGELOG.md +66 -1
- package/dist/types/cli/gallery-fixtures/types.d.ts +7 -1
- package/dist/types/edit/index.d.ts +0 -1
- package/dist/types/eval/__tests__/js-context-manager.test.d.ts +1 -0
- package/dist/types/eval/bridge-timeout.d.ts +1 -1
- package/dist/types/eval/{llm-bridge.d.ts → completion-bridge.d.ts} +8 -8
- package/dist/types/eval/idle-timeout.d.ts +1 -1
- package/dist/types/lsp/index.d.ts +0 -5
- package/dist/types/main.d.ts +11 -0
- package/dist/types/modes/components/assistant-message.d.ts +0 -9
- package/dist/types/modes/components/late-diagnostics-message.d.ts +20 -0
- package/dist/types/modes/components/read-tool-group.d.ts +6 -0
- package/dist/types/modes/components/session-selector.d.ts +16 -7
- package/dist/types/modes/components/tool-execution.d.ts +0 -18
- package/dist/types/modes/types.d.ts +4 -0
- package/dist/types/session/messages.d.ts +11 -8
- package/dist/types/session/yield-queue.d.ts +10 -1
- package/dist/types/tools/eval-render.d.ts +0 -1
- package/dist/types/tools/index.d.ts +31 -0
- package/dist/types/tools/path-utils.d.ts +5 -1
- package/dist/types/tools/read.d.ts +2 -1
- package/dist/types/tools/render-utils.d.ts +3 -1
- package/dist/types/tools/renderers.d.ts +0 -15
- package/dist/types/tools/write.d.ts +0 -2
- package/dist/types/tui/code-cell.d.ts +0 -2
- package/dist/types/tui/hyperlink.d.ts +5 -7
- package/dist/types/tui/output-block.d.ts +0 -18
- package/package.json +9 -9
- package/src/cli/gallery-cli.ts +4 -0
- package/src/cli/gallery-fixtures/codeintel.ts +0 -1
- package/src/cli/gallery-fixtures/fs.ts +68 -1
- package/src/cli/gallery-fixtures/types.ts +8 -1
- package/src/commit/agentic/agent.ts +1 -0
- package/src/edit/hashline/diff.ts +86 -0
- package/src/edit/hashline/execute.ts +14 -1
- package/src/edit/index.ts +31 -17
- package/src/edit/renderer.ts +116 -31
- package/src/eval/__tests__/agent-bridge.test.ts +13 -0
- package/src/eval/__tests__/{llm-bridge.test.ts → completion-bridge.test.ts} +60 -54
- package/src/eval/__tests__/js-context-manager.test.ts +241 -0
- package/src/eval/agent-bridge.ts +6 -1
- package/src/eval/bridge-timeout.ts +1 -1
- package/src/eval/{llm-bridge.ts → completion-bridge.ts} +30 -27
- package/src/eval/idle-timeout.ts +1 -1
- package/src/eval/js/context-manager.ts +66 -6
- package/src/eval/js/shared/prelude.txt +28 -12
- package/src/eval/js/tool-bridge.ts +3 -3
- package/src/eval/js/worker-entry.ts +6 -0
- package/src/eval/py/prelude.py +3 -3
- package/src/internal-urls/docs-index.generated.ts +8 -7
- package/src/lsp/index.ts +128 -52
- package/src/main.ts +54 -14
- package/src/modes/components/assistant-message.ts +3 -15
- package/src/modes/components/late-diagnostics-message.ts +60 -0
- package/src/modes/components/plan-review-overlay.ts +26 -5
- package/src/modes/components/read-tool-group.ts +415 -35
- package/src/modes/components/session-selector.ts +89 -35
- package/src/modes/components/tips.txt +1 -1
- package/src/modes/components/tool-execution.ts +7 -49
- package/src/modes/components/transcript-container.ts +108 -32
- package/src/modes/controllers/event-controller.ts +6 -1
- package/src/modes/controllers/input-controller.ts +10 -2
- package/src/modes/types.ts +4 -0
- package/src/modes/utils/ui-helpers.ts +26 -5
- package/src/prompts/system/manual-continue.md +7 -0
- package/src/prompts/system/plan-mode-active.md +56 -72
- package/src/prompts/system/tiny-title-system.md +1 -1
- package/src/prompts/system/title-system.md +16 -3
- package/src/prompts/system/workflow-notice.md +1 -1
- package/src/prompts/tools/eval.md +6 -4
- package/src/prompts/tools/lsp-late-diagnostic.md +8 -0
- package/src/sdk.ts +59 -1
- package/src/session/agent-session.ts +5 -3
- package/src/session/messages.ts +21 -14
- package/src/session/session-manager.ts +2 -2
- package/src/session/yield-queue.ts +20 -2
- package/src/task/executor.ts +1 -0
- package/src/tiny/title-client.ts +6 -1
- package/src/tools/bash.ts +0 -7
- package/src/tools/eval-render.ts +6 -25
- package/src/tools/eval.ts +1 -1
- package/src/tools/find.ts +148 -106
- package/src/tools/index.ts +32 -0
- package/src/tools/path-utils.ts +19 -22
- package/src/tools/read.ts +16 -8
- package/src/tools/render-utils.ts +3 -1
- package/src/tools/renderers.ts +0 -15
- package/src/tools/ssh.ts +0 -1
- package/src/tools/todo.ts +1 -0
- package/src/tools/write.ts +3 -12
- package/src/tui/code-cell.ts +1 -6
- package/src/tui/hyperlink.ts +13 -23
- package/src/tui/output-block.ts +2 -97
- package/src/utils/title-generator.ts +2 -2
- /package/dist/types/eval/__tests__/{llm-bridge.test.d.ts → completion-bridge.test.d.ts} +0 -0
package/src/tools/todo.ts
CHANGED
package/src/tools/write.ts
CHANGED
|
@@ -277,7 +277,6 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
|
|
|
277
277
|
readonly label = "Write";
|
|
278
278
|
readonly description: string;
|
|
279
279
|
readonly parameters = writeSchema;
|
|
280
|
-
readonly nonAbortable = true;
|
|
281
280
|
readonly strict = true;
|
|
282
281
|
readonly concurrency = "exclusive";
|
|
283
282
|
readonly loadMode = "discoverable";
|
|
@@ -582,6 +581,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
|
|
|
582
581
|
const batchRequest = getLspBatchRequest(context?.toolCall);
|
|
583
582
|
const diagnostics = await this.#writethrough(absolutePath, newContent, signal, undefined, batchRequest);
|
|
584
583
|
invalidateFsScanAfterWrite(absolutePath);
|
|
584
|
+
this.session.bumpFileMutationVersion?.(absolutePath);
|
|
585
585
|
this.session.fileSnapshotStore?.invalidate(absolutePath);
|
|
586
586
|
this.session.conflictHistory?.invalidate(entry.id);
|
|
587
587
|
|
|
@@ -707,6 +707,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
|
|
|
707
707
|
|
|
708
708
|
const diagnostics = await this.#writethrough(absolutePath, text, signal, undefined, batchRequest);
|
|
709
709
|
invalidateFsScanAfterWrite(absolutePath);
|
|
710
|
+
this.session.bumpFileMutationVersion?.(absolutePath);
|
|
710
711
|
this.session.fileSnapshotStore?.invalidate(absolutePath);
|
|
711
712
|
for (const entry of fileEntries) history.invalidate(entry.id);
|
|
712
713
|
const header = maybeWriteSnapshotHeader(this.session, absolutePath, text);
|
|
@@ -886,6 +887,7 @@ export class WriteTool implements AgentTool<typeof writeSchema, WriteToolDetails
|
|
|
886
887
|
|
|
887
888
|
const diagnostics = await this.#writethrough(absolutePath, cleanContent, signal, undefined, batchRequest);
|
|
888
889
|
invalidateFsScanAfterWrite(absolutePath);
|
|
890
|
+
this.session.bumpFileMutationVersion?.(absolutePath);
|
|
889
891
|
const madeExecutable = await maybeMarkExecutableForShebang(absolutePath, cleanContent);
|
|
890
892
|
|
|
891
893
|
const displayPath = formatPathRelativeToCwd(absolutePath, this.session.cwd);
|
|
@@ -1039,17 +1041,6 @@ export const writeToolRenderer = {
|
|
|
1039
1041
|
});
|
|
1040
1042
|
},
|
|
1041
1043
|
|
|
1042
|
-
// Only the expanded (Ctrl+O) preview is append-only: it renders the whole
|
|
1043
|
-
// content top-anchored, so streamed chunks only append rows at the bottom.
|
|
1044
|
-
// The collapsed preview slides a bounded tail window (`formatStreamingContent`
|
|
1045
|
-
// with `WRITE_STREAMING_PREVIEW_LINES`) whose visible rows re-layout as the
|
|
1046
|
-
// window moves — not append-only, but it never overflows the viewport, so its
|
|
1047
|
-
// head is never at risk of being dropped regardless. `write` has no partial
|
|
1048
|
-
// result (content streams as args), so `result` is ignored here.
|
|
1049
|
-
isStreamingPreviewAppendOnly(args: WriteRenderArgs, options: RenderResultOptions, _result?: unknown): boolean {
|
|
1050
|
-
return Boolean(options?.expanded && args.content);
|
|
1051
|
-
},
|
|
1052
|
-
|
|
1053
1044
|
renderResult(
|
|
1054
1045
|
result: { content: Array<{ type: string; text?: string }>; details?: WriteToolDetails; isError?: boolean },
|
|
1055
1046
|
options: RenderResultOptions,
|
package/src/tui/code-cell.ts
CHANGED
|
@@ -32,8 +32,6 @@ export interface CodeCellOptions {
|
|
|
32
32
|
*/
|
|
33
33
|
codeTail?: boolean;
|
|
34
34
|
expanded?: boolean;
|
|
35
|
-
/** Animate the cell border with a sweeping segment while pending/running. */
|
|
36
|
-
animate?: boolean;
|
|
37
35
|
width: number;
|
|
38
36
|
}
|
|
39
37
|
|
|
@@ -147,10 +145,7 @@ export function renderCodeCell(options: CodeCellOptions, theme: Theme): string[]
|
|
|
147
145
|
sections.push({ label: theme.fg("toolTitle", "Output"), lines: outputLines });
|
|
148
146
|
}
|
|
149
147
|
|
|
150
|
-
return renderOutputBlock(
|
|
151
|
-
{ header: title, headerMeta: meta, state, sections, width, animate: options.animate },
|
|
152
|
-
theme,
|
|
153
|
-
);
|
|
148
|
+
return renderOutputBlock({ header: title, headerMeta: meta, state, sections, width }, theme);
|
|
154
149
|
}
|
|
155
150
|
|
|
156
151
|
export interface MarkdownCellOptions {
|
package/src/tui/hyperlink.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* sequences when the active terminal supports hyperlinks and the user setting
|
|
6
6
|
* permits it. Falls back to plain text when disabled.
|
|
7
7
|
*/
|
|
8
|
+
import * as url from "node:url";
|
|
8
9
|
import { TERMINAL } from "@oh-my-pi/pi-tui";
|
|
9
10
|
import { settings } from "../config/settings";
|
|
10
11
|
import {
|
|
@@ -28,21 +29,12 @@ function buildLinkId(uri: string): string {
|
|
|
28
29
|
return (h >>> 0).toString(16).padStart(8, "0");
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
/** Build a `file://` URI
|
|
32
|
-
function buildFileUri(
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const encoded = normalized
|
|
38
|
-
.split("/")
|
|
39
|
-
.map(segment => encodeURIComponent(segment))
|
|
40
|
-
.join("/");
|
|
41
|
-
const params: string[] = [];
|
|
42
|
-
if (opts?.line !== undefined) params.push(`line=${opts.line}`);
|
|
43
|
-
if (opts?.col !== undefined) params.push(`col=${opts.col}`);
|
|
44
|
-
const query = params.length > 0 ? `?${params.join("&")}` : "";
|
|
45
|
-
return `${prefix}${encoded}${query}`;
|
|
32
|
+
/** Build a properly encoded `file://` URI with optional line/col query params. */
|
|
33
|
+
function buildFileUri(filePath: string, opts?: { line?: number; col?: number }): string {
|
|
34
|
+
const uri = url.pathToFileURL(filePath);
|
|
35
|
+
if (opts?.line !== undefined) uri.searchParams.set("line", String(opts.line));
|
|
36
|
+
if (opts?.col !== undefined) uri.searchParams.set("col", String(opts.col));
|
|
37
|
+
return uri.href;
|
|
46
38
|
}
|
|
47
39
|
|
|
48
40
|
/**
|
|
@@ -104,21 +96,19 @@ export function urlHyperlink(url: string, displayText: string): string {
|
|
|
104
96
|
}
|
|
105
97
|
|
|
106
98
|
/**
|
|
107
|
-
* Wrap `displayText` in an OSC 8 hyperlink pointing at
|
|
99
|
+
* Wrap `displayText` in an OSC 8 hyperlink pointing at a filesystem path.
|
|
108
100
|
*
|
|
109
101
|
* Returns `displayText` unchanged when hyperlinks are disabled or when
|
|
110
102
|
* the text already contains an OSC 8 sequence (prevents double-wrapping).
|
|
103
|
+
* Relative paths resolve against the current working directory before URI
|
|
104
|
+
* encoding so the OSC 8 target is always a valid `file://` URL.
|
|
111
105
|
*
|
|
112
|
-
*
|
|
113
|
-
* produce invalid `file://` URIs and are accepted silently to avoid runtime
|
|
114
|
-
* errors in renderer hot paths.
|
|
115
|
-
*
|
|
116
|
-
* @param absPath - Absolute filesystem path
|
|
106
|
+
* @param filePath - Filesystem path
|
|
117
107
|
* @param displayText - Text to render as the hyperlink anchor (may contain ANSI codes)
|
|
118
108
|
* @param opts - Optional line/col position appended as `?line=N&col=M` query params
|
|
119
109
|
*/
|
|
120
|
-
export function fileHyperlink(
|
|
121
|
-
return wrapHyperlink(buildFileUri(
|
|
110
|
+
export function fileHyperlink(filePath: string, displayText: string, opts?: { line?: number; col?: number }): string {
|
|
111
|
+
return wrapHyperlink(buildFileUri(filePath, opts), displayText);
|
|
122
112
|
}
|
|
123
113
|
|
|
124
114
|
/**
|
package/src/tui/output-block.ts
CHANGED
|
@@ -17,8 +17,6 @@ export interface OutputBlockOptions {
|
|
|
17
17
|
width: number;
|
|
18
18
|
applyBg?: boolean;
|
|
19
19
|
contentPaddingLeft?: number;
|
|
20
|
-
/** Animate the border with a sweeping dark segment (pending/running state). */
|
|
21
|
-
animate?: boolean;
|
|
22
20
|
/** Override the state-derived border color. Used for muted "legacy" tool
|
|
23
21
|
* frames that should not visually compete with framed-output tools. */
|
|
24
22
|
borderColor?: ThemeColor;
|
|
@@ -37,59 +35,6 @@ export function isFramedBlockComponent(component: Component): boolean {
|
|
|
37
35
|
return (component as FramedBlockComponent)[FRAMED_BLOCK_COMPONENT] === true;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
const BORDER_SHIMMER_TICK_MS = 1000 / 30;
|
|
41
|
-
/** Duration of one full left↔right↔left bounce of the bottom-edge segment, in
|
|
42
|
-
* ms. Position is derived from the wall clock against this fixed cycle so a
|
|
43
|
-
* resize only nudges the segment proportionally instead of teleporting it. */
|
|
44
|
-
const BORDER_BOUNCE_MS = 3000;
|
|
45
|
-
/** Length, in border cells, of the moving segment. */
|
|
46
|
-
const BORDER_SEGMENT_LEN = 8;
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Monotonic frame counter for animated borders, quantized to the TUI's ~30fps
|
|
50
|
-
* render cap so the cache key advances once per animation frame — fine enough
|
|
51
|
-
* for a smooth segment sweep, coarse enough to coalesce multiple render passes
|
|
52
|
-
* land inside the same frame.
|
|
53
|
-
*/
|
|
54
|
-
export function borderShimmerTick(): number {
|
|
55
|
-
return Math.floor(Date.now() / BORDER_SHIMMER_TICK_MS);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Ease-in-out so the segment decelerates into and accelerates out of each wall. */
|
|
59
|
-
function easeInOutQuad(t: number): number {
|
|
60
|
-
return t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Column of the travelling segment's center on the bottom edge for a box of
|
|
65
|
-
* inner width `W` at time `now`. The segment bounces left → right → left across
|
|
66
|
-
* the bottom border: a triangle wave over one full there-and-back cycle, eased
|
|
67
|
-
* per leg so it slows as it nears each wall before reversing. Position is
|
|
68
|
-
* derived from the wall clock against a fixed cycle, so a resize shifts the
|
|
69
|
-
* center proportionally — no reset.
|
|
70
|
-
*/
|
|
71
|
-
export function borderSegmentHeadCol(W: number, now: number): number {
|
|
72
|
-
if (W <= 1) return 0;
|
|
73
|
-
const phase = (((now % BORDER_BOUNCE_MS) + BORDER_BOUNCE_MS) % BORDER_BOUNCE_MS) / BORDER_BOUNCE_MS;
|
|
74
|
-
// Triangle: 0→1 rightward over the first half, 1→0 leftward over the second.
|
|
75
|
-
const leg = phase < 0.5 ? phase * 2 : 2 - phase * 2;
|
|
76
|
-
return easeInOutQuad(leg) * (W - 1);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Scale a truecolor foreground escape toward black by `factor`. Returns
|
|
81
|
-
* undefined for 256-color escapes (no RGB to scale) so callers fall back to a
|
|
82
|
-
* dimmer theme color.
|
|
83
|
-
*/
|
|
84
|
-
function darkenFgAnsi(ansi: string, factor: number): string | undefined {
|
|
85
|
-
const m = /38;2;(\d+);(\d+);(\d+)/.exec(ansi);
|
|
86
|
-
if (!m) return undefined;
|
|
87
|
-
const r = Math.round(Number(m[1]) * factor);
|
|
88
|
-
const g = Math.round(Number(m[2]) * factor);
|
|
89
|
-
const b = Math.round(Number(m[3]) * factor);
|
|
90
|
-
return `\x1b[38;2;${r};${g};${b}m`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
38
|
type BlockRow =
|
|
94
39
|
| { kind: "bar"; leftChar: string; rightChar: string; label?: string; meta?: string }
|
|
95
40
|
| { kind: "bottom"; leftChar: string; rightChar: string }
|
|
@@ -135,8 +80,7 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
135
80
|
const contentWidth = Math.max(0, lineWidth - visibleWidth(v) - contentPaddingLeft - visibleWidth(v));
|
|
136
81
|
const contentLeftPadding = contentPaddingLeft > 0 ? padding(contentPaddingLeft) : "";
|
|
137
82
|
|
|
138
|
-
// ── Layout pass: collect row descriptors
|
|
139
|
-
// known before the moving segment is positioned. ──
|
|
83
|
+
// ── Layout pass: collect row descriptors before emitting the bordered lines. ──
|
|
140
84
|
const rows: BlockRow[] = [];
|
|
141
85
|
rows.push({
|
|
142
86
|
kind: "bar",
|
|
@@ -185,39 +129,6 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
185
129
|
rows.push({ kind: "bottom", leftChar: theme.boxSharp.bottomLeft, rightChar: theme.boxSharp.bottomRight });
|
|
186
130
|
|
|
187
131
|
const H = rows.length;
|
|
188
|
-
const W = lineWidth;
|
|
189
|
-
const animate = (options.animate ?? false) && (state === "running" || state === "pending") && W >= 2 && H >= 2;
|
|
190
|
-
|
|
191
|
-
// ── Segment geometry: one dark run bounces left ↔ right along the bottom
|
|
192
|
-
// edge only. The top, interior separators, and side borders stay the flat
|
|
193
|
-
// accent color. ──
|
|
194
|
-
const segLen = animate ? Math.min(BORDER_SEGMENT_LEN, W) : 0;
|
|
195
|
-
const head = animate ? borderSegmentHeadCol(W, Date.now()) : 0;
|
|
196
|
-
const segHalf = segLen / 2;
|
|
197
|
-
const segAnsi = animate ? (darkenFgAnsi(theme.getFgAnsi(borderColor), 0.4) ?? theme.getFgAnsi("borderMuted")) : "";
|
|
198
|
-
const seg = (text: string) => `${segAnsi}${text}\x1b[39m`;
|
|
199
|
-
|
|
200
|
-
// A bottom-edge column is lit when it lies within half a segment of the
|
|
201
|
-
// travelling center.
|
|
202
|
-
const isLit = (col: number): boolean => Math.abs(col - head) < segHalf;
|
|
203
|
-
// Color a run of bottom-edge glyphs starting at column `startCol`, grouping
|
|
204
|
-
// consecutive same-state cells so each run emits a single escape pair.
|
|
205
|
-
const colorEdge = (glyphs: string, startCol: number): string => {
|
|
206
|
-
let out = "";
|
|
207
|
-
let runLit: boolean | null = null;
|
|
208
|
-
let buf = "";
|
|
209
|
-
for (let i = 0; i < glyphs.length; i++) {
|
|
210
|
-
const lit = isLit(startCol + i);
|
|
211
|
-
if (lit !== runLit) {
|
|
212
|
-
if (runLit !== null) out += (runLit ? seg : border)(buf);
|
|
213
|
-
buf = "";
|
|
214
|
-
runLit = lit;
|
|
215
|
-
}
|
|
216
|
-
buf += glyphs[i];
|
|
217
|
-
}
|
|
218
|
-
if (runLit !== null) out += (runLit ? seg : border)(buf);
|
|
219
|
-
return out;
|
|
220
|
-
};
|
|
221
132
|
|
|
222
133
|
const renderBar = (row: { leftChar: string; rightChar: string; label?: string; meta?: string }): string => {
|
|
223
134
|
const leftGlyphs = `${row.leftChar}${cap}`;
|
|
@@ -245,11 +156,7 @@ export function renderOutputBlock(options: OutputBlockOptions, theme: Theme): st
|
|
|
245
156
|
const rightGlyph = row.rightChar;
|
|
246
157
|
const fillCount = Math.max(0, lineWidth - visibleWidth(leftGlyphs) - visibleWidth(rightGlyph));
|
|
247
158
|
const fillGlyphs = h.repeat(fillCount);
|
|
248
|
-
|
|
249
|
-
const leftStr = colorEdge(leftGlyphs, 0);
|
|
250
|
-
const fillStr = colorEdge(fillGlyphs, visibleWidth(leftGlyphs));
|
|
251
|
-
const rightStr = colorEdge(rightGlyph, lineWidth - visibleWidth(rightGlyph));
|
|
252
|
-
return `${leftStr}${fillStr}${rightStr}`;
|
|
159
|
+
return `${border(leftGlyphs)}${border(fillGlyphs)}${border(rightGlyph)}`;
|
|
253
160
|
};
|
|
254
161
|
|
|
255
162
|
const renderContent = (inner: string): string => `${border(v)}${contentLeftPadding}${inner}${border(v)}`;
|
|
@@ -302,8 +209,6 @@ export class CachedOutputBlock {
|
|
|
302
209
|
h.optional(options.state);
|
|
303
210
|
h.optional(options.borderColor);
|
|
304
211
|
h.bool(options.applyBg ?? true);
|
|
305
|
-
h.bool(options.animate ?? false);
|
|
306
|
-
if (options.animate) h.u32(borderShimmerTick());
|
|
307
212
|
if (options.sections) {
|
|
308
213
|
for (const s of options.sections) {
|
|
309
214
|
h.optional(s.label);
|
|
@@ -33,7 +33,7 @@ const setTitleTool: Tool = {
|
|
|
33
33
|
title: {
|
|
34
34
|
type: "string",
|
|
35
35
|
description:
|
|
36
|
-
'A concise 3-
|
|
36
|
+
'A concise, sentence-case 3-7 word title for the session (capitalize only the first word and proper nouns), or exactly "none" when the message carries no concrete task yet (greeting, small talk, vague).',
|
|
37
37
|
},
|
|
38
38
|
},
|
|
39
39
|
required: ["title"],
|
|
@@ -224,7 +224,7 @@ export async function generateTitleOnline(
|
|
|
224
224
|
// account_uuid rather than the snapshot-at-call-site value.
|
|
225
225
|
const metadata = metadataResolver?.(model.provider);
|
|
226
226
|
|
|
227
|
-
// Title generation is a 3-
|
|
227
|
+
// Title generation is a 3-7 word task, but some reasoning backends ignore
|
|
228
228
|
// disableReasoning. Keep the normal cheap budget for non-reasoning models
|
|
229
229
|
// while reserving enough output room for reasoning models to still emit
|
|
230
230
|
// the forced tool call after any unavoidable thinking tokens.
|
|
File without changes
|