deepclause-sdk 0.1.1 → 0.1.3
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.d.ts +12 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +116 -9
- package/dist/agent.js.map +1 -1
- package/dist/cli/config.d.ts +24 -24
- package/dist/cli/repl.d.ts +21 -4
- package/dist/cli/repl.d.ts.map +1 -1
- package/dist/cli/repl.js +293 -44
- package/dist/cli/repl.js.map +1 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +10 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/prolog/loader.d.ts +32 -0
- package/dist/prolog/loader.d.ts.map +1 -1
- package/dist/prolog/loader.js +87 -0
- package/dist/prolog/loader.js.map +1 -1
- package/dist/prolog-src/deepclause_mi.pl +1028 -118
- package/dist/repl/agent.d.ts +15 -1
- package/dist/repl/agent.d.ts.map +1 -1
- package/dist/repl/agent.js +44 -5
- package/dist/repl/agent.js.map +1 -1
- package/dist/repl/backend.d.ts.map +1 -1
- package/dist/repl/backend.js +18 -5
- package/dist/repl/backend.js.map +1 -1
- package/dist/repl/harness-tools.d.ts +24 -2
- package/dist/repl/harness-tools.d.ts.map +1 -1
- package/dist/repl/harness-tools.js +14 -5
- package/dist/repl/harness-tools.js.map +1 -1
- package/dist/repl/index.d.ts +8 -0
- package/dist/repl/index.d.ts.map +1 -1
- package/dist/repl/index.js +1 -0
- package/dist/repl/index.js.map +1 -1
- package/dist/repl/render.d.ts +60 -3
- package/dist/repl/render.d.ts.map +1 -1
- package/dist/repl/render.js +114 -28
- package/dist/repl/render.js.map +1 -1
- package/dist/repl/session.d.ts +61 -4
- package/dist/repl/session.d.ts.map +1 -1
- package/dist/repl/session.js +174 -9
- package/dist/repl/session.js.map +1 -1
- package/dist/repl/status.d.ts +3 -1
- package/dist/repl/status.d.ts.map +1 -1
- package/dist/repl/status.js +4 -0
- package/dist/repl/status.js.map +1 -1
- package/dist/repl/tool-arguments.d.ts +36 -0
- package/dist/repl/tool-arguments.d.ts.map +1 -0
- package/dist/repl/tool-arguments.js +123 -0
- package/dist/repl/tool-arguments.js.map +1 -0
- package/dist/repl/toolset.d.ts +28 -1
- package/dist/repl/toolset.d.ts.map +1 -1
- package/dist/repl/toolset.js +52 -4
- package/dist/repl/toolset.js.map +1 -1
- package/dist/repl/tui/autocomplete.d.ts +19 -0
- package/dist/repl/tui/autocomplete.d.ts.map +1 -0
- package/dist/repl/tui/autocomplete.js +41 -0
- package/dist/repl/tui/autocomplete.js.map +1 -0
- package/dist/repl/tui/document.d.ts +51 -0
- package/dist/repl/tui/document.d.ts.map +1 -0
- package/dist/repl/tui/document.js +160 -0
- package/dist/repl/tui/document.js.map +1 -0
- package/dist/repl/tui/picker.d.ts +31 -0
- package/dist/repl/tui/picker.d.ts.map +1 -0
- package/dist/repl/tui/picker.js +43 -0
- package/dist/repl/tui/picker.js.map +1 -0
- package/dist/repl/tui/renderer.d.ts +98 -0
- package/dist/repl/tui/renderer.d.ts.map +1 -0
- package/dist/repl/tui/renderer.js +284 -0
- package/dist/repl/tui/renderer.js.map +1 -0
- package/dist/repl/tui/status-bar.d.ts +4 -2
- package/dist/repl/tui/status-bar.d.ts.map +1 -1
- package/dist/repl/tui/status-bar.js +80 -24
- package/dist/repl/tui/status-bar.js.map +1 -1
- package/dist/repl/tui/terminal.d.ts +28 -0
- package/dist/repl/tui/terminal.d.ts.map +1 -0
- package/dist/repl/tui/terminal.js +94 -0
- package/dist/repl/tui/terminal.js.map +1 -0
- package/dist/repl/tui/theme.d.ts +60 -0
- package/dist/repl/tui/theme.d.ts.map +1 -1
- package/dist/repl/tui/theme.js +142 -0
- package/dist/repl/tui/theme.js.map +1 -1
- package/dist/repl/tui/tool-pane.d.ts +68 -0
- package/dist/repl/tui/tool-pane.d.ts.map +1 -0
- package/dist/repl/tui/tool-pane.js +257 -0
- package/dist/repl/tui/tool-pane.js.map +1 -0
- package/dist/repl/tui/working-line.d.ts +23 -0
- package/dist/repl/tui/working-line.d.ts.map +1 -0
- package/dist/repl/tui/working-line.js +58 -0
- package/dist/repl/tui/working-line.js.map +1 -0
- package/dist/runner.d.ts +31 -0
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +192 -17
- package/dist/runner.js.map +1 -1
- package/dist/system/assets/docs/AGENT_PROMPT.md +925 -43
- package/dist/system/assets/docs/DML_AUTHORING.md +96 -17
- package/dist/system/assets/docs/DML_REFERENCE.md +620 -39
- package/dist/system/assets/docs/PROLOG_SNIPPETS.md +45 -1
- package/dist/system/assets/docs/TASK_PROMPT.md +2 -0
- package/dist/system/environment.d.ts +36 -0
- package/dist/system/environment.d.ts.map +1 -0
- package/dist/system/environment.js +81 -0
- package/dist/system/environment.js.map +1 -0
- package/dist/system/runtime/shell-manager.d.ts +40 -2
- package/dist/system/runtime/shell-manager.d.ts.map +1 -1
- package/dist/system/runtime/shell-manager.js +82 -16
- package/dist/system/runtime/shell-manager.js.map +1 -1
- package/dist/system/runtime/shell-tool-events.js +25 -1
- package/dist/system/runtime/shell-tool-events.js.map +1 -1
- package/dist/types.d.ts +27 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/prolog-src/deepclause_mi.pl +1028 -118
- package/dist/compaction.d.ts +0 -98
- package/dist/compaction.d.ts.map +0 -1
- package/dist/compaction.js +0 -471
- package/dist/compaction.js.map +0 -1
- package/dist/repl/tools.d.ts +0 -53
- package/dist/repl/tools.d.ts.map +0 -1
- package/dist/repl/tools.js +0 -307
- package/dist/repl/tools.js.map +0 -1
- package/dist/system/assets/compactors/default-loop-compactor.dml +0 -43
- package/dist/system/assets/compactors/default-session-compactor.dml +0 -30
- package/dist/system/assets/docs/META_PROMPT.md +0 -68
package/dist/cli/repl.d.ts
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { Command } from 'commander';
|
|
10
10
|
import { type HarnessRepl } from '../repl/index.js';
|
|
11
|
-
import {
|
|
11
|
+
import { type ReplEventRenderer } from '../repl/render.js';
|
|
12
12
|
import { type ReplStatusSnapshot } from '../repl/status.js';
|
|
13
13
|
import { type ReplToolset } from '../repl/toolset.js';
|
|
14
|
+
import { type ModelResolver } from '../repl/model-resolver.js';
|
|
14
15
|
import type { ImageBackend } from '../types.js';
|
|
15
16
|
import { type DiagramMode, type GraphicsMode } from '../visualize/index.js';
|
|
16
17
|
export interface ReplCliOptions {
|
|
@@ -52,6 +53,8 @@ export interface ReplCliOptions {
|
|
|
52
53
|
tools?: string;
|
|
53
54
|
noTools?: boolean;
|
|
54
55
|
sandbox?: boolean;
|
|
56
|
+
/** Refuse to start unless the effective shell backend is a sandbox. */
|
|
57
|
+
requireSandbox?: boolean;
|
|
55
58
|
noAsk?: boolean;
|
|
56
59
|
answer?: string;
|
|
57
60
|
interactiveInput?: boolean;
|
|
@@ -83,6 +86,11 @@ export type ReplInput = {
|
|
|
83
86
|
} | {
|
|
84
87
|
kind: 'model';
|
|
85
88
|
model?: string;
|
|
89
|
+
} | {
|
|
90
|
+
kind: 'reasoning';
|
|
91
|
+
level?: string;
|
|
92
|
+
} | {
|
|
93
|
+
kind: 'show-reasoning';
|
|
86
94
|
} | {
|
|
87
95
|
kind: 'export';
|
|
88
96
|
path?: string;
|
|
@@ -139,7 +147,7 @@ export declare function classifyReplInput(line: string): ReplInput;
|
|
|
139
147
|
/** Run one goal and render its solutions. Returns a process exit code. */
|
|
140
148
|
export declare function runGoalWithRenderer(repl: HarnessRepl, goal: string, options: {
|
|
141
149
|
first?: boolean;
|
|
142
|
-
renderer:
|
|
150
|
+
renderer: ReplEventRenderer;
|
|
143
151
|
signal?: AbortSignal;
|
|
144
152
|
}): Promise<number>;
|
|
145
153
|
/**
|
|
@@ -151,7 +159,8 @@ export declare function runGoalWithRenderer(repl: HarnessRepl, goal: string, opt
|
|
|
151
159
|
export declare function buildCliOnInput(options: ReplCliOptions): ((prompt: string, choices?: string[]) => Promise<string | undefined>) | undefined;
|
|
152
160
|
export interface ReplRuntime {
|
|
153
161
|
repl: HarnessRepl;
|
|
154
|
-
renderer
|
|
162
|
+
/** String renderer for plain/json output, or the TUI's component renderer. */
|
|
163
|
+
renderer: ReplEventRenderer;
|
|
155
164
|
workspace: string;
|
|
156
165
|
promptPrefix: string;
|
|
157
166
|
toolset: ReplToolset;
|
|
@@ -163,6 +172,14 @@ export interface ReplRuntime {
|
|
|
163
172
|
/** Active model capabilities (pi backend), used by the status bar. */
|
|
164
173
|
contextWindow?: number;
|
|
165
174
|
reasoning: boolean;
|
|
175
|
+
/** How much model reasoning the renderer shows (the picker changes this live). */
|
|
176
|
+
reasoningMode: 'off' | 'summary' | 'full';
|
|
177
|
+
/** Models this session can switch to, for the model picker. */
|
|
178
|
+
modelResolver?: ModelResolver;
|
|
179
|
+
/** The backend, so a picker can change the reasoning level live. */
|
|
180
|
+
llmBackend?: import('../types.js').LLMBackend;
|
|
181
|
+
/** Set the reasoning level shown in the status bar. */
|
|
182
|
+
setThinkingLevel?: (level: string | undefined) => void;
|
|
166
183
|
thinkingLevel?: string;
|
|
167
184
|
/** Session id of this run. */
|
|
168
185
|
sessionId: string;
|
|
@@ -196,7 +213,7 @@ export declare function dispatchReplInput(runtime: ReplRuntime, input: ReplInput
|
|
|
196
213
|
exportPath?: string;
|
|
197
214
|
signal?: AbortSignal;
|
|
198
215
|
}): Promise<boolean>;
|
|
199
|
-
export declare function runInteractiveGoal(repl: HarnessRepl, renderer:
|
|
216
|
+
export declare function runInteractiveGoal(repl: HarnessRepl, renderer: ReplEventRenderer, goal: string, options: ReplCliOptions, ask: (query: string) => Promise<string | null>, signal?: AbortSignal): Promise<void>;
|
|
200
217
|
/**
|
|
201
218
|
* Interactive TUI for the REPL: a scrolling transcript, a fixed editor, and a
|
|
202
219
|
* fixed status bar below the input. It reuses `ReplRenderer` (rich mode) for all
|
package/dist/cli/repl.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/cli/repl.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMzC,OAAO,EAAqB,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGvE,OAAO,
|
|
1
|
+
{"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../../src/cli/repl.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/repl.js
CHANGED
|
@@ -14,15 +14,22 @@ import { createHarnessRepl } from '../repl/index.js';
|
|
|
14
14
|
import { HistoryStore } from '../repl/history.js';
|
|
15
15
|
import { resolveReplJudgeSelection } from '../repl/judge.js';
|
|
16
16
|
import { ReplRenderer } from '../repl/render.js';
|
|
17
|
+
import { TranscriptDocument } from '../repl/tui/document.js';
|
|
18
|
+
import { ChoicePicker } from '../repl/tui/picker.js';
|
|
19
|
+
import { TuiRenderer } from '../repl/tui/renderer.js';
|
|
20
|
+
import { WorkingLine } from '../repl/tui/working-line.js';
|
|
21
|
+
import { createReplAutocomplete } from '../repl/tui/autocomplete.js';
|
|
22
|
+
import { initTuiTheme, scrollbarStyles } from '../repl/tui/theme.js';
|
|
23
|
+
import { SizedTerminal } from '../repl/tui/terminal.js';
|
|
17
24
|
import { ReplStatusTracker } from '../repl/status.js';
|
|
18
|
-
import { LineSink, TranscriptComponent } from '../repl/tui/transcript.js';
|
|
19
25
|
import { StatusBarComponent } from '../repl/tui/status-bar.js';
|
|
20
|
-
import { Container,
|
|
26
|
+
import { Container, ScrollView, Spacer, TuiAltScreen, VStack, matchesKey, } from '@earendil-works/pi-tui';
|
|
21
27
|
import { editorTheme, formatInputAnswer } from '../repl/tui/theme.js';
|
|
22
28
|
import { PromptEditor } from '../repl/tui/editor.js';
|
|
23
29
|
import { loadProjectContext } from '../repl/project-context.js';
|
|
24
|
-
import { createPiBackend } from '../repl/backend.js';
|
|
30
|
+
import { createPiBackend, THINKING_LEVELS } from '../repl/backend.js';
|
|
25
31
|
import { createReplToolset } from '../repl/toolset.js';
|
|
32
|
+
import { takeStartupPrologMessages } from '../prolog/loader.js';
|
|
26
33
|
import { createPiImageBackend } from '../repl/imagegen.js';
|
|
27
34
|
import { EnvModelResolver, PiModelResolver } from '../repl/model-resolver.js';
|
|
28
35
|
import { parseModelId, resolveModelSlotConfig } from '../system/config/model-slots.js';
|
|
@@ -112,6 +119,12 @@ export function classifyReplInput(line) {
|
|
|
112
119
|
return { kind: 'export', path: arg || undefined };
|
|
113
120
|
case 'model':
|
|
114
121
|
return { kind: 'model', model: arg || undefined };
|
|
122
|
+
case 'reasoning':
|
|
123
|
+
case 'reasoning-level':
|
|
124
|
+
return { kind: 'reasoning', level: arg || undefined };
|
|
125
|
+
case 'show-reasoning':
|
|
126
|
+
case 'reasoning-summary':
|
|
127
|
+
return { kind: 'show-reasoning' };
|
|
115
128
|
case 'freeze':
|
|
116
129
|
return { kind: 'freeze' };
|
|
117
130
|
case 'unfreeze':
|
|
@@ -294,6 +307,13 @@ export async function createReplRuntime(options) {
|
|
|
294
307
|
}
|
|
295
308
|
},
|
|
296
309
|
});
|
|
310
|
+
// The CLI counterpart of `:- require_sandbox.`: enforce it without editing the
|
|
311
|
+
// harness, for CI and for a run you do not want to be quietly unsandboxed.
|
|
312
|
+
if (options.requireSandbox && !toolset.environment.sandboxed) {
|
|
313
|
+
throw new Error(`--require-sandbox: the effective shell backend is ${toolset.environment.backendLabel}, `
|
|
314
|
+
+ 'which is not sandboxed. Install bubblewrap (Linux), grant sandbox-exec (macOS), '
|
|
315
|
+
+ 'or run with --sandbox (AgentVM).');
|
|
316
|
+
}
|
|
297
317
|
const backendKind = options.backend ?? config.backend?.kind ?? 'pi';
|
|
298
318
|
let llmBackend;
|
|
299
319
|
let harnessModel = resolved.model;
|
|
@@ -429,6 +449,7 @@ export async function createReplRuntime(options) {
|
|
|
429
449
|
maxModelCalls: options.maxModelCalls ?? config.repl.maxModelCalls,
|
|
430
450
|
tools: toolset.tools,
|
|
431
451
|
hostToolsCatalog: toolset.catalog,
|
|
452
|
+
executionBackend: toolset.environment.kind,
|
|
432
453
|
llmBackend,
|
|
433
454
|
judgeSelection,
|
|
434
455
|
imageBackend,
|
|
@@ -475,6 +496,10 @@ export async function createReplRuntime(options) {
|
|
|
475
496
|
backend: backendKind,
|
|
476
497
|
contextWindow,
|
|
477
498
|
reasoning,
|
|
499
|
+
reasoningMode: options.showReasoning ?? config.repl.showReasoning,
|
|
500
|
+
modelResolver,
|
|
501
|
+
llmBackend,
|
|
502
|
+
setThinkingLevel: (level) => statusTracker.setThinkingLevel(level),
|
|
478
503
|
thinkingLevel,
|
|
479
504
|
sessionId: repl.session.getSessionId(),
|
|
480
505
|
harnessName,
|
|
@@ -765,23 +790,23 @@ async function executeLoad(runtime, files) {
|
|
|
765
790
|
return 1;
|
|
766
791
|
}
|
|
767
792
|
runtime.renderer.writeLine(`loaded ${file}`);
|
|
793
|
+
for (const warning of result.warnings ?? []) {
|
|
794
|
+
runtime.renderer.writeErrorLine(`warning: ${warning}`);
|
|
795
|
+
}
|
|
768
796
|
}
|
|
769
797
|
return 0;
|
|
770
798
|
}
|
|
771
799
|
/** Non-interactive mode: read classified inputs line by line until EOF. */
|
|
772
800
|
/**
|
|
773
|
-
*
|
|
774
|
-
*
|
|
775
|
-
*
|
|
801
|
+
* Ctrl-C exits, in every mode: this is the plain/readline path, where there is no
|
|
802
|
+
* raw key to distinguish Escape from an editing sequence, so the TUI's
|
|
803
|
+
* "Esc interrupts, Ctrl-C exits" cannot be mirrored exactly. A running turn is
|
|
804
|
+
* aborted first, so nothing keeps writing after the UI is gone.
|
|
776
805
|
*/
|
|
777
|
-
function installSigint(
|
|
806
|
+
function installSigint(holder, rl, onExit) {
|
|
778
807
|
const handler = () => {
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
runtime.renderer.writeErrorLine('(cancelling current turn… press Ctrl-C again to exit)');
|
|
782
|
-
}
|
|
783
|
-
else if (onExit) {
|
|
784
|
-
// Save the harness before exiting (Ctrl-C while idle).
|
|
808
|
+
holder.turn?.abort(new Error('cancelled by user'));
|
|
809
|
+
if (onExit) {
|
|
785
810
|
void onExit().finally(() => process.exit(130));
|
|
786
811
|
}
|
|
787
812
|
else {
|
|
@@ -799,7 +824,7 @@ async function runNonInteractive(runtime, options, onExit) {
|
|
|
799
824
|
let exitCode = 0;
|
|
800
825
|
const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
|
|
801
826
|
const holder = { turn: null };
|
|
802
|
-
const removeSigint = installSigint(
|
|
827
|
+
const removeSigint = installSigint(holder, rl, onExit);
|
|
803
828
|
try {
|
|
804
829
|
for await (const line of rl) {
|
|
805
830
|
const input = classifyReplInput(line);
|
|
@@ -869,7 +894,7 @@ async function runInteractive(runtime, options, onExit) {
|
|
|
869
894
|
return answer === null ? undefined : answer;
|
|
870
895
|
});
|
|
871
896
|
const holder = { turn: null };
|
|
872
|
-
const removeSigint = installSigint(
|
|
897
|
+
const removeSigint = installSigint(holder, rl, onExit);
|
|
873
898
|
try {
|
|
874
899
|
while (true) {
|
|
875
900
|
const line = await ask(promptPrefix);
|
|
@@ -964,10 +989,33 @@ export async function runInteractiveGoal(repl, renderer, goal, options, ask, sig
|
|
|
964
989
|
* input prompts never fight the main prompt for stdin.
|
|
965
990
|
*/
|
|
966
991
|
export async function runTui(runtime, options, onExit, loaded = []) {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
const
|
|
992
|
+
initTuiTheme();
|
|
993
|
+
// Sized, because pi-tui falls back to a hard 24 rows when the stream reports no
|
|
994
|
+
// size, which leaves the bottom of a taller terminal untouched.
|
|
995
|
+
const terminal = new SizedTerminal();
|
|
996
|
+
// Fullscreen: an application-owned viewport (ScrollView) with the editor and
|
|
997
|
+
// status bar pinned in a dock. In this mode pi-tui hands scrolling, mouse wheel,
|
|
998
|
+
// text selection and search to the viewport, and reassigns layout on resize —
|
|
999
|
+
// which is what makes the transcript scroll inside the app and the input box
|
|
1000
|
+
// behave when the terminal changes size.
|
|
1001
|
+
const tui = new TuiAltScreen(terminal, undefined, undefined, {
|
|
1002
|
+
mouse: true,
|
|
1003
|
+
wheelScrollLines: 'auto',
|
|
1004
|
+
copyOnSelect: true,
|
|
1005
|
+
});
|
|
1006
|
+
const document = new TranscriptDocument();
|
|
1007
|
+
const transcript = document;
|
|
1008
|
+
// The TUI renders components rather than lines: tool calls become panes and
|
|
1009
|
+
// streamed text becomes markdown. There is no external sink to wire.
|
|
1010
|
+
const working = new WorkingLine(tui);
|
|
1011
|
+
const renderer = new TuiRenderer({
|
|
1012
|
+
document,
|
|
1013
|
+
onWorking: (label) => {
|
|
1014
|
+
working.set(label);
|
|
1015
|
+
tui.requestRender();
|
|
1016
|
+
},
|
|
1017
|
+
});
|
|
1018
|
+
runtime.renderer = renderer;
|
|
971
1019
|
const runState = { running: false, steerable: false };
|
|
972
1020
|
/** Lines typed during a goal query, consumed by the solution pager. */
|
|
973
1021
|
const bufferedInput = [];
|
|
@@ -981,12 +1029,14 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
981
1029
|
isRunning: () => runState.running,
|
|
982
1030
|
});
|
|
983
1031
|
transcript.onChange = () => tui.requestRender();
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
1032
|
+
renderer.setImageSink((lines) => document.appendImageLines(lines));
|
|
1033
|
+
renderer.setWidth(terminal.columns);
|
|
1034
|
+
// pi-tui re-renders on resize but does not invalidate the component tree, and a
|
|
1035
|
+
// component that caches by width (a tool pane, markdown) would draw stale lines.
|
|
988
1036
|
const onResize = () => {
|
|
989
|
-
|
|
1037
|
+
terminal.refreshSize();
|
|
1038
|
+
renderer.setWidth(terminal.columns);
|
|
1039
|
+
tui.invalidate();
|
|
990
1040
|
tui.requestRender();
|
|
991
1041
|
};
|
|
992
1042
|
process.stdout.on('resize', onResize);
|
|
@@ -1015,7 +1065,9 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1015
1065
|
}
|
|
1016
1066
|
else if (activePrompt === runtime.promptPrefix) {
|
|
1017
1067
|
// A user turn: separate it from the previous output and from the
|
|
1018
|
-
// response that follows; render it as a pi-style blue block.
|
|
1068
|
+
// response that follows; render it as a pi-style blue block. The previous
|
|
1069
|
+
// turn's text block is closed first, so the new response starts below this.
|
|
1070
|
+
runtime.renderer.endTextBlock?.();
|
|
1019
1071
|
if (transcript.getLines().length > 0)
|
|
1020
1072
|
transcript.append('');
|
|
1021
1073
|
transcript.append(text, 'user');
|
|
@@ -1026,6 +1078,7 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1026
1078
|
else if (text.trim()) {
|
|
1027
1079
|
// No pending ask means a turn is running.
|
|
1028
1080
|
if (runState.steerable) {
|
|
1081
|
+
runtime.renderer.endTextBlock?.();
|
|
1029
1082
|
transcript.append(text, 'steer');
|
|
1030
1083
|
runtime.repl.steer(text);
|
|
1031
1084
|
}
|
|
@@ -1047,6 +1100,7 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1047
1100
|
};
|
|
1048
1101
|
const createEditor = () => {
|
|
1049
1102
|
editor = new PromptEditor(tui, editorTheme());
|
|
1103
|
+
editor.setAutocompleteProvider(createReplAutocomplete(runtime.workspace));
|
|
1050
1104
|
editor.onSubmit = handleSubmit;
|
|
1051
1105
|
editorContainer.clear();
|
|
1052
1106
|
editorContainer.addChild(editor);
|
|
@@ -1085,40 +1139,206 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1085
1139
|
const answer = await ask(`${prompt}${suffix}`, true);
|
|
1086
1140
|
return answer === null ? undefined : answer;
|
|
1087
1141
|
});
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1142
|
+
/** Interrupt the running turn, if any. Returns whether there was one. */
|
|
1143
|
+
const interruptTurn = () => {
|
|
1144
|
+
if (!holder.turn)
|
|
1145
|
+
return false;
|
|
1146
|
+
holder.turn.abort(new Error('cancelled by user'));
|
|
1147
|
+
transcript.append('(interrupted — Ctrl-C exits)');
|
|
1148
|
+
tui.requestRender();
|
|
1149
|
+
return true;
|
|
1150
|
+
};
|
|
1151
|
+
/** Leave the REPL, aborting anything still running so nothing outlives the UI. */
|
|
1152
|
+
const exitRepl = () => {
|
|
1153
|
+
holder.turn?.abort(new Error('cancelled by user'));
|
|
1095
1154
|
void (onExit ? onExit() : Promise.resolve()).finally(() => {
|
|
1096
1155
|
tui.stop();
|
|
1097
1156
|
process.exit(130);
|
|
1098
1157
|
});
|
|
1099
1158
|
};
|
|
1100
|
-
// Ctrl-C
|
|
1101
|
-
//
|
|
1159
|
+
// Esc interrupts, Ctrl-C exits, Ctrl-D (on an empty editor) exits. Escape is
|
|
1160
|
+
// left alone while a completion list or an overlay owns it, so it keeps its
|
|
1161
|
+
// usual meaning there. Use pi's key matcher so kitty/meta encodings are
|
|
1162
|
+
// recognized, not just raw bytes.
|
|
1102
1163
|
tui.addInputListener((data) => {
|
|
1103
1164
|
if (matchesKey(data, 'ctrl+c')) {
|
|
1104
|
-
|
|
1165
|
+
exitRepl();
|
|
1105
1166
|
return { consume: true };
|
|
1106
1167
|
}
|
|
1107
1168
|
if (matchesKey(data, 'ctrl+d') && !holder.turn && (editor?.getText().length ?? 0) === 0) {
|
|
1108
|
-
|
|
1169
|
+
exitRepl();
|
|
1109
1170
|
return { consume: true };
|
|
1110
1171
|
}
|
|
1172
|
+
if (matchesKey(data, 'escape')
|
|
1173
|
+
&& !tui.hasOverlay()
|
|
1174
|
+
&& !(editor?.isShowingAutocomplete() ?? false)) {
|
|
1175
|
+
if (interruptTurn())
|
|
1176
|
+
return { consume: true };
|
|
1177
|
+
return undefined;
|
|
1178
|
+
}
|
|
1179
|
+
// ctrl+o expands or collapses the most recent tool call, the way pi reveals
|
|
1180
|
+
// full tool output on demand.
|
|
1181
|
+
if (matchesKey(data, 'ctrl+o')) {
|
|
1182
|
+
if (renderer.toggleLastPane())
|
|
1183
|
+
return { consume: true };
|
|
1184
|
+
return undefined;
|
|
1185
|
+
}
|
|
1111
1186
|
return undefined;
|
|
1112
1187
|
});
|
|
1113
|
-
// Fallback for terminals/raw-mode setups that deliver SIGINT instead of \x03
|
|
1114
|
-
|
|
1188
|
+
// Fallback for terminals/raw-mode setups that deliver SIGINT instead of \x03:
|
|
1189
|
+
// the terminal's own Ctrl-C, which now exits.
|
|
1190
|
+
process.on('SIGINT', exitRepl);
|
|
1115
1191
|
createEditor();
|
|
1116
1192
|
for (const line of runtime.inputHistory)
|
|
1117
1193
|
editor?.addToHistory(line);
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1194
|
+
/**
|
|
1195
|
+
* Show a chooser over the transcript and resolve when it closes.
|
|
1196
|
+
*
|
|
1197
|
+
* The overlay owns input while it is up (pi-tui routes keys to the focused
|
|
1198
|
+
* overlay), so the editor does not see the keys the list is using.
|
|
1199
|
+
*/
|
|
1200
|
+
const choose = (build) => {
|
|
1201
|
+
return new Promise((resolve) => {
|
|
1202
|
+
let handle;
|
|
1203
|
+
const done = (picked) => {
|
|
1204
|
+
handle?.hide();
|
|
1205
|
+
if (editor)
|
|
1206
|
+
tui.setFocus(editor);
|
|
1207
|
+
tui.requestRender();
|
|
1208
|
+
resolve(picked);
|
|
1209
|
+
};
|
|
1210
|
+
const picker = build(done);
|
|
1211
|
+
handle = tui.showOverlay(picker, {
|
|
1212
|
+
anchor: 'center',
|
|
1213
|
+
width: '70%',
|
|
1214
|
+
maxHeight: picker.contentHeight + 2,
|
|
1215
|
+
});
|
|
1216
|
+
});
|
|
1217
|
+
};
|
|
1218
|
+
const pickReasoningMode = async () => {
|
|
1219
|
+
const modes = ['off', 'summary', 'full'];
|
|
1220
|
+
const picked = await choose((done) => new ChoicePicker({
|
|
1221
|
+
title: 'Reasoning',
|
|
1222
|
+
hint: 'How much of the model\'s thinking to show in the transcript',
|
|
1223
|
+
current: runtime.reasoningMode,
|
|
1224
|
+
items: [
|
|
1225
|
+
{ value: 'off', label: 'off', description: 'hide reasoning entirely' },
|
|
1226
|
+
{ value: 'summary', label: 'summary', description: 'a bounded preview' },
|
|
1227
|
+
{ value: 'full', label: 'full', description: 'everything the model emits' },
|
|
1228
|
+
].filter((item) => modes.includes(item.value)),
|
|
1229
|
+
onSelect: (item) => done(item.value),
|
|
1230
|
+
onCancel: () => done(),
|
|
1231
|
+
}));
|
|
1232
|
+
if (!picked)
|
|
1233
|
+
return;
|
|
1234
|
+
const mode = picked;
|
|
1235
|
+
runtime.reasoningMode = mode;
|
|
1236
|
+
runtime.renderer.setReasoningMode?.(mode);
|
|
1237
|
+
await persistSetting({ repl: { showReasoning: mode } }, 'reasoning display');
|
|
1238
|
+
renderer.writeLine(`reasoning display: ${mode}`);
|
|
1239
|
+
};
|
|
1240
|
+
/**
|
|
1241
|
+
* The model's reasoning level (its thinking effort), as opposed to how much of
|
|
1242
|
+
* that reasoning is displayed — `/show-reasoning` is the other one.
|
|
1243
|
+
*/
|
|
1244
|
+
/**
|
|
1245
|
+
* Persist a setting, but never let that failure stop it applying.
|
|
1246
|
+
*
|
|
1247
|
+
* `updateConfig` requires an existing config file (`deepclause init`), and a
|
|
1248
|
+
* picker that threw before applying the change left the selection doing nothing at
|
|
1249
|
+
* all — which read as "I cannot adjust the reasoning".
|
|
1250
|
+
*/
|
|
1251
|
+
const persistSetting = async (patch, label) => {
|
|
1252
|
+
try {
|
|
1253
|
+
await updateConfig(runtime.workspace, patch);
|
|
1254
|
+
}
|
|
1255
|
+
catch (error) {
|
|
1256
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1257
|
+
renderer.writeLine(`${label} applied to this session, but not saved: ${message.split('\n')[0]}`);
|
|
1258
|
+
}
|
|
1259
|
+
};
|
|
1260
|
+
const pickReasoningLevel = async (level) => {
|
|
1261
|
+
const backend = runtime.llmBackend;
|
|
1262
|
+
const supported = (backend?.supportedThinkingLevels?.() ?? THINKING_LEVELS.slice());
|
|
1263
|
+
const apply = async (chosen) => {
|
|
1264
|
+
backend?.setThinkingLevel?.(chosen);
|
|
1265
|
+
runtime.thinkingLevel = chosen;
|
|
1266
|
+
runtime.setThinkingLevel?.(chosen);
|
|
1267
|
+
await persistSetting({ backend: { kind: 'pi', thinkingLevel: chosen } }, 'reasoning level');
|
|
1268
|
+
renderer.writeLine(`reasoning level: ${chosen}`);
|
|
1269
|
+
};
|
|
1270
|
+
if (level) {
|
|
1271
|
+
if (!supported.includes(level)) {
|
|
1272
|
+
renderer.writeLine(`unknown reasoning level '${level}'; supported: ${supported.join(', ')}`);
|
|
1273
|
+
return;
|
|
1274
|
+
}
|
|
1275
|
+
await apply(level);
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
const chosen = await choose((done) => new ChoicePicker({
|
|
1279
|
+
title: 'Reasoning level',
|
|
1280
|
+
hint: 'How hard the model is asked to think (not how much is shown)',
|
|
1281
|
+
current: runtime.thinkingLevel,
|
|
1282
|
+
items: supported.map((value) => ({
|
|
1283
|
+
value,
|
|
1284
|
+
label: value,
|
|
1285
|
+
description: value === 'off' ? 'no reasoning requested' : undefined,
|
|
1286
|
+
})),
|
|
1287
|
+
onSelect: (item) => done(item.value),
|
|
1288
|
+
onCancel: () => done(),
|
|
1289
|
+
}));
|
|
1290
|
+
if (chosen)
|
|
1291
|
+
await apply(chosen);
|
|
1292
|
+
};
|
|
1293
|
+
const pickModel = async () => {
|
|
1294
|
+
const catalog = runtime.modelResolver?.catalog() ?? [];
|
|
1295
|
+
if (catalog.length === 0) {
|
|
1296
|
+
renderer.writeLine(`model: ${runtime.model} (no catalog to choose from; set one in config)`);
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
const current = runtime.model.includes(':') ? runtime.model : undefined;
|
|
1300
|
+
const picked = await choose((done) => new ChoicePicker({
|
|
1301
|
+
title: 'Model',
|
|
1302
|
+
hint: 'The default for this workspace (applies to the next session)',
|
|
1303
|
+
current,
|
|
1304
|
+
items: catalog.map((entry) => ({
|
|
1305
|
+
value: entry.model,
|
|
1306
|
+
label: entry.model,
|
|
1307
|
+
description: entry.inputCost !== undefined
|
|
1308
|
+
? `$${entry.inputCost}/$${entry.outputCost ?? '?'} per 1M in/out`
|
|
1309
|
+
: (entry.contextWindow ? `${Math.round(entry.contextWindow / 1000)}k context` : undefined),
|
|
1310
|
+
})),
|
|
1311
|
+
onSelect: (item) => done(item.value),
|
|
1312
|
+
onCancel: () => done(),
|
|
1313
|
+
}));
|
|
1314
|
+
if (!picked)
|
|
1315
|
+
return;
|
|
1316
|
+
await persistSetting({ backend: { kind: 'pi', model: picked } }, 'model');
|
|
1317
|
+
renderer.writeLine(`default model set to ${picked} (takes effect on the next start)`);
|
|
1318
|
+
};
|
|
1319
|
+
// Transcript grows and scrolls; everything below it stays put.
|
|
1320
|
+
const scroll = new ScrollView(document, {
|
|
1321
|
+
follow: 'end',
|
|
1322
|
+
primary: true,
|
|
1323
|
+
scrollbar: 'auto',
|
|
1324
|
+
scrollbarTrackStyle: scrollbarStyles.track,
|
|
1325
|
+
scrollbarThumbStyle: scrollbarStyles.thumb,
|
|
1326
|
+
});
|
|
1327
|
+
// Margins: a blank row above the transcript and one between it and the editor, so
|
|
1328
|
+
// the first and last line of output are not jammed against the chrome. Fixed
|
|
1329
|
+
// spacers rather than padding inside the scroll view: they do not scroll away and
|
|
1330
|
+
// do not consume scrollback.
|
|
1331
|
+
const dock = new VStack([
|
|
1332
|
+
{ component: working, basis: 'auto', grow: 0, shrink: 1, minSize: 0 },
|
|
1333
|
+
{ component: new Spacer(1), basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1334
|
+
{ component: editorContainer, basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1335
|
+
{ component: statusBar, basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1336
|
+
]);
|
|
1337
|
+
tui.setLayoutRoot(new VStack([
|
|
1338
|
+
{ component: new Spacer(1), basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1339
|
+
{ component: scroll, basis: 0, grow: 1, shrink: 1, minSize: 1 },
|
|
1340
|
+
{ component: dock, basis: 'auto', grow: 0, shrink: 1, minSize: 1 },
|
|
1341
|
+
]));
|
|
1122
1342
|
tui.start();
|
|
1123
1343
|
await printBanner(runtime, loaded);
|
|
1124
1344
|
tui.requestRender();
|
|
@@ -1130,6 +1350,20 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1130
1350
|
const input = classifyReplInput(line);
|
|
1131
1351
|
if (input.kind === 'halt')
|
|
1132
1352
|
break;
|
|
1353
|
+
// The pickers are overlays over the transcript, so they need the TUI and are
|
|
1354
|
+
// handled here rather than in the command dispatcher the readline path shares.
|
|
1355
|
+
if (input.kind === 'model' && !input.model) {
|
|
1356
|
+
await pickModel();
|
|
1357
|
+
continue;
|
|
1358
|
+
}
|
|
1359
|
+
if (input.kind === 'reasoning') {
|
|
1360
|
+
await pickReasoningLevel(input.level);
|
|
1361
|
+
continue;
|
|
1362
|
+
}
|
|
1363
|
+
if (input.kind === 'show-reasoning') {
|
|
1364
|
+
await pickReasoningMode();
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1133
1367
|
const controller = new AbortController();
|
|
1134
1368
|
holder.turn = controller;
|
|
1135
1369
|
runState.running = true;
|
|
@@ -1159,8 +1393,9 @@ export async function runTui(runtime, options, onExit, loaded = []) {
|
|
|
1159
1393
|
}
|
|
1160
1394
|
finally {
|
|
1161
1395
|
tui.stop();
|
|
1162
|
-
process.off('SIGINT',
|
|
1396
|
+
process.off('SIGINT', exitRepl);
|
|
1163
1397
|
process.stdout.off('resize', onResize);
|
|
1398
|
+
working.stop();
|
|
1164
1399
|
// Restore stdout so the exit footer and any later output are visible.
|
|
1165
1400
|
runtime.renderer.setSink((text) => process.stdout.write(text), (text) => process.stderr.write(text));
|
|
1166
1401
|
}
|
|
@@ -1171,6 +1406,17 @@ export async function startRepl(options) {
|
|
|
1171
1406
|
let runtime;
|
|
1172
1407
|
try {
|
|
1173
1408
|
runtime = await createReplRuntime(options);
|
|
1409
|
+
// Diagnostics from loading the runtime itself, rendered once and through the
|
|
1410
|
+
// renderer. Before this they were printed by Emscripten straight to the
|
|
1411
|
+
// terminal, in the middle of whatever the UI was drawing.
|
|
1412
|
+
for (const message of takeStartupPrologMessages()) {
|
|
1413
|
+
runtime.renderer.render({
|
|
1414
|
+
type: message.channel === 'stdout' ? 'output' : 'log',
|
|
1415
|
+
content: message.text,
|
|
1416
|
+
level: message.level,
|
|
1417
|
+
channel: message.channel,
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1174
1420
|
}
|
|
1175
1421
|
catch (error) {
|
|
1176
1422
|
process.stderr.write(`ERROR: ${error.message}\n`);
|
|
@@ -1216,7 +1462,7 @@ export async function startRepl(options) {
|
|
|
1216
1462
|
if (goals.length > 0) {
|
|
1217
1463
|
let exitCode = 0;
|
|
1218
1464
|
const controller = new AbortController();
|
|
1219
|
-
const removeSigint = installSigint(
|
|
1465
|
+
const removeSigint = installSigint({ turn: controller });
|
|
1220
1466
|
try {
|
|
1221
1467
|
for (const goal of goals) {
|
|
1222
1468
|
if (controller.signal.aborted)
|
|
@@ -1306,6 +1552,7 @@ export function registerReplCommand(program) {
|
|
|
1306
1552
|
.option('--tools <list>', 'comma-separated capability host tools (default: bash)')
|
|
1307
1553
|
.option('--no-tools', 'register no capability host tools')
|
|
1308
1554
|
.option('--sandbox', 'run shell tools in AgentVM')
|
|
1555
|
+
.option('--require-sandbox', 'refuse to run unless the shell is sandboxed (bwrap/AgentVM/sandbox-exec)')
|
|
1309
1556
|
.option('--no-ask', 'make ask_user / input/2 fail instead of prompting')
|
|
1310
1557
|
.option('--image-model <provider:id>', 'image model for generation (default: first available)')
|
|
1311
1558
|
.option('--no-open', 'do not hand images to the OS viewer on terminals without inline images')
|
|
@@ -1329,6 +1576,7 @@ export function registerReplCommand(program) {
|
|
|
1329
1576
|
goal: options.goal,
|
|
1330
1577
|
load: options.load,
|
|
1331
1578
|
session: options.session,
|
|
1579
|
+
harness: options.harness,
|
|
1332
1580
|
first: options.first,
|
|
1333
1581
|
plain: options.plain,
|
|
1334
1582
|
json: options.json,
|
|
@@ -1349,6 +1597,7 @@ export function registerReplCommand(program) {
|
|
|
1349
1597
|
tools: typeof options.tools === 'string' ? options.tools : undefined,
|
|
1350
1598
|
noTools: options.tools === false,
|
|
1351
1599
|
sandbox: options.sandbox,
|
|
1600
|
+
requireSandbox: options.requireSandbox,
|
|
1352
1601
|
noAsk: options.ask === false,
|
|
1353
1602
|
imageModel: options.imageModel,
|
|
1354
1603
|
open: options.open,
|