@oh-my-pi/pi-coding-agent 16.4.4 → 16.4.6
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 +62 -0
- package/dist/cli.js +3799 -3729
- package/dist/types/async/job-manager.d.ts +8 -0
- package/dist/types/cli/bench-cli.d.ts +1 -7
- package/dist/types/cli/usage-cli.d.ts +1 -0
- package/dist/types/commands/usage.d.ts +7 -0
- package/dist/types/config/settings-schema.d.ts +19 -9
- package/dist/types/config/settings.d.ts +3 -2
- package/dist/types/discovery/helpers.d.ts +2 -2
- package/dist/types/extensibility/extensions/types.d.ts +36 -0
- package/dist/types/irc/bus.d.ts +4 -0
- package/dist/types/modes/components/__tests__/pause-screen.test.d.ts +1 -0
- package/dist/types/modes/components/ask-dialog.d.ts +27 -0
- package/dist/types/modes/components/custom-editor.d.ts +3 -8
- package/dist/types/modes/components/index.d.ts +2 -1
- package/dist/types/modes/components/model-browser.d.ts +100 -0
- package/dist/types/modes/components/model-hub.d.ts +52 -0
- package/dist/types/modes/components/pause-screen.d.ts +43 -0
- package/dist/types/modes/components/session-selector.d.ts +13 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +2 -1
- package/dist/types/modes/controllers/input-controller.d.ts +2 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/queue-input.d.ts +8 -0
- package/dist/types/modes/shared.d.ts +1 -1
- package/dist/types/modes/types.d.ts +4 -0
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/agent-storage.d.ts +57 -0
- package/dist/types/session/session-context.d.ts +9 -0
- package/dist/types/task/executor.d.ts +26 -13
- package/dist/types/task/index.d.ts +12 -11
- package/dist/types/task/label.d.ts +4 -0
- package/dist/types/task/repair-args.d.ts +8 -8
- package/dist/types/task/types.d.ts +31 -56
- package/dist/types/tools/ask.d.ts +12 -0
- package/dist/types/tools/conflict-detect.d.ts +17 -1
- package/dist/types/tools/job.d.ts +16 -0
- package/package.json +12 -12
- package/scripts/build-binary.ts +0 -1
- package/scripts/compile-binary.ts +4 -3
- package/src/async/job-manager.ts +9 -0
- package/src/cli/bench-cli.ts +7 -26
- package/src/cli/usage-cli.ts +11 -0
- package/src/commands/usage.ts +13 -2
- package/src/commit/agentic/tools/analyze-file.ts +2 -3
- package/src/config/settings-schema.ts +18 -7
- package/src/config/settings.ts +13 -4
- package/src/discovery/helpers.ts +3 -4
- package/src/extensibility/custom-tools/loader.ts +70 -37
- package/src/extensibility/extensions/types.ts +46 -0
- package/src/irc/bus.ts +61 -20
- package/src/modes/components/__tests__/pause-screen.test.ts +143 -0
- package/src/modes/components/advisor-config.ts +32 -22
- package/src/modes/components/ask-dialog.ts +888 -0
- package/src/modes/components/custom-editor.test.ts +58 -1
- package/src/modes/components/custom-editor.ts +42 -11
- package/src/modes/components/index.ts +2 -1
- package/src/modes/components/model-browser.ts +769 -0
- package/src/modes/components/model-hub.ts +2002 -0
- package/src/modes/components/pause-screen.ts +208 -0
- package/src/modes/components/session-selector.ts +299 -42
- package/src/modes/components/tool-execution.ts +2 -0
- package/src/modes/components/usage-row.ts +5 -6
- package/src/modes/controllers/event-controller.ts +8 -2
- package/src/modes/controllers/extension-ui-controller.ts +252 -5
- package/src/modes/controllers/input-controller.ts +140 -6
- package/src/modes/controllers/selector-controller.ts +160 -97
- package/src/modes/controllers/tan-command-controller.ts +1 -1
- package/src/modes/controllers/todo-command-controller.ts +1 -2
- package/src/modes/interactive-mode.ts +8 -0
- package/src/modes/queue-input.ts +132 -0
- package/src/modes/shared.ts +1 -1
- package/src/modes/theme/theme.ts +3 -3
- package/src/modes/types.ts +4 -0
- package/src/modes/utils/ui-helpers.ts +50 -24
- package/src/prompts/agents/scout.md +0 -1
- package/src/prompts/agents/task.md +1 -1
- package/src/prompts/system/subagent-system-prompt.md +1 -5
- package/src/prompts/system/subagent-yield-reminder.md +10 -0
- package/src/prompts/system/task-label.md +23 -0
- package/src/prompts/tools/job.md +1 -1
- package/src/prompts/tools/task-summary.md +3 -0
- package/src/prompts/tools/task.md +17 -18
- package/src/session/agent-session.ts +186 -49
- package/src/session/agent-storage.ts +330 -3
- package/src/session/history-storage.ts +1 -34
- package/src/session/session-context.test.ts +73 -0
- package/src/session/session-context.ts +43 -26
- package/src/slash-commands/builtin-registry.ts +18 -0
- package/src/task/agents.ts +2 -0
- package/src/task/executor.ts +159 -46
- package/src/task/index.ts +377 -239
- package/src/task/label.ts +38 -0
- package/src/task/render.ts +74 -22
- package/src/task/repair-args.ts +20 -31
- package/src/task/spawn-policy.test.ts +4 -4
- package/src/task/types.ts +46 -66
- package/src/tools/ask.ts +233 -40
- package/src/tools/conflict-detect.ts +102 -5
- package/src/tools/index.ts +1 -0
- package/src/tools/irc.ts +20 -11
- package/src/tools/job.ts +158 -18
- package/src/tools/write.ts +70 -6
- package/src/vibe/runtime.ts +1 -1
- package/src/web/search/providers/browser-headers.ts +30 -13
- package/dist/types/modes/components/model-selector.d.ts +0 -37
- package/dist/types/tools/bash-command-fixup.d.ts +0 -3
- package/src/modes/components/model-selector.ts +0 -1291
- package/src/tools/bash-command-fixup.ts +0 -4
|
@@ -15,6 +15,12 @@ export interface AsyncJob {
|
|
|
15
15
|
* supply an id (e.g. legacy tests, SDK consumers without an agent context).
|
|
16
16
|
*/
|
|
17
17
|
ownerId?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Registry id of the subagent this job runs (task/tan/vibe jobs). Lets
|
|
20
|
+
* job-view code link a job row to its AgentRegistry ref even when the job
|
|
21
|
+
* id differs from the agent id (vibe turn jobs, tan clones).
|
|
22
|
+
*/
|
|
23
|
+
agentId?: string;
|
|
18
24
|
/**
|
|
19
25
|
* Job is registered but parked behind a caller-managed gate (e.g. a task
|
|
20
26
|
* batch semaphore). Queued jobs do not count toward the running-job limit
|
|
@@ -37,6 +43,8 @@ export interface AsyncJobRegisterOptions {
|
|
|
37
43
|
id?: string;
|
|
38
44
|
/** Registry id of the agent that owns this job; used to scope cancelAll. */
|
|
39
45
|
ownerId?: string;
|
|
46
|
+
/** Registry id of the subagent this job runs; see {@link AsyncJob.agentId}. */
|
|
47
|
+
agentId?: string;
|
|
40
48
|
onProgress?: (text: string, details?: Record<string, unknown>) => void | Promise<void>;
|
|
41
49
|
/** Register the job in queued state; see {@link AsyncJob.queued}. */
|
|
42
50
|
queued?: boolean;
|
|
@@ -30,7 +30,7 @@ export interface BenchRunSuccess {
|
|
|
30
30
|
ttftMs: number;
|
|
31
31
|
durationMs: number;
|
|
32
32
|
outputTokens: number;
|
|
33
|
-
/**
|
|
33
|
+
/** Output tokens/sec over the total request duration. */
|
|
34
34
|
tokensPerSecond: number;
|
|
35
35
|
}
|
|
36
36
|
export interface BenchRunFailure {
|
|
@@ -74,12 +74,6 @@ export interface BenchDependencies {
|
|
|
74
74
|
now?: () => number;
|
|
75
75
|
stdoutIsTTY?: boolean;
|
|
76
76
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Tokens/s over the generation window (duration minus TTFT) so queue/prefill
|
|
79
|
-
* latency does not dilute throughput. Falls back to total duration when the
|
|
80
|
-
* response arrived as a single chunk (TTFT ~ duration).
|
|
81
|
-
*/
|
|
82
|
-
export declare function computeTokensPerSecond(outputTokens: number, durationMs: number, ttftMs: number, deltaChunkCount: number): number;
|
|
83
77
|
export declare function formatBenchTable(summary: BenchSummary): string;
|
|
84
78
|
export declare function runBenchCommand(command: BenchCommandArgs, deps?: BenchDependencies): Promise<BenchSummary>;
|
|
85
79
|
export {};
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
import { Command } from "@oh-my-pi/pi-utils/cli";
|
|
5
5
|
export default class Usage extends Command {
|
|
6
6
|
static description: string;
|
|
7
|
+
static args: {
|
|
8
|
+
action: import("@oh-my-pi/pi-utils/cli").ArgDescriptor & {
|
|
9
|
+
description: string;
|
|
10
|
+
required: false;
|
|
11
|
+
options: string[];
|
|
12
|
+
};
|
|
13
|
+
};
|
|
7
14
|
static flags: {
|
|
8
15
|
json: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
|
|
9
16
|
char: string;
|
|
@@ -1384,7 +1384,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
1384
1384
|
readonly tab: "model";
|
|
1385
1385
|
readonly group: "Retry & Fallback";
|
|
1386
1386
|
readonly label: "Retry Fallback Chains";
|
|
1387
|
-
readonly description: 'JSON object mapping model roles to ordered fallback
|
|
1387
|
+
readonly description: 'JSON object mapping model roles, model selectors ("provider/model-id"), or provider wildcards ("provider/*") to ordered fallback selectors, e.g. {"default":["openai/gpt-4o-mini"],"google-antigravity/*":["google/*","google-vertex/*"]}. Model-oriented keys apply whenever that model/provider is active, regardless of role; a "provider/*" entry keeps the failing model\'s id and swaps the provider.';
|
|
1388
1388
|
};
|
|
1389
1389
|
};
|
|
1390
1390
|
readonly "retry.fallbackRevertPolicy": {
|
|
@@ -3749,6 +3749,16 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
3749
3749
|
readonly description: "Enable the web_search tool for live web results";
|
|
3750
3750
|
};
|
|
3751
3751
|
};
|
|
3752
|
+
readonly "ask.enabled": {
|
|
3753
|
+
readonly type: "boolean";
|
|
3754
|
+
readonly default: true;
|
|
3755
|
+
readonly ui: {
|
|
3756
|
+
readonly tab: "tools";
|
|
3757
|
+
readonly group: "Available Tools";
|
|
3758
|
+
readonly label: "Ask";
|
|
3759
|
+
readonly description: "Enable the ask tool for interactive user questions";
|
|
3760
|
+
};
|
|
3761
|
+
};
|
|
3752
3762
|
readonly "browser.enabled": {
|
|
3753
3763
|
readonly type: "boolean";
|
|
3754
3764
|
readonly default: true;
|
|
@@ -4291,36 +4301,36 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
4291
4301
|
};
|
|
4292
4302
|
readonly "task.softRequestBudget": {
|
|
4293
4303
|
readonly type: "number";
|
|
4294
|
-
readonly default:
|
|
4304
|
+
readonly default: 200;
|
|
4295
4305
|
readonly ui: {
|
|
4296
4306
|
readonly tab: "tasks";
|
|
4297
4307
|
readonly group: "Subagents";
|
|
4298
4308
|
readonly label: "Soft Subagent Request Budget";
|
|
4299
|
-
readonly description: "Soft per-subagent request budget (assistant requests per run). Crossing it
|
|
4309
|
+
readonly description: "Soft per-subagent request budget (assistant requests per run). Crossing it injects a wrap-up steering notice (see task.softRequestBudgetNotice); at 1.5x the budget the run is force-stopped and the agent must yield its partial findings. 0 disables the guard. Bundled scout/sonic agents use a lower built-in budget.";
|
|
4300
4310
|
readonly options: readonly [{
|
|
4301
4311
|
readonly value: "0";
|
|
4302
4312
|
readonly label: "Disabled";
|
|
4303
|
-
}, {
|
|
4304
|
-
readonly value: "40";
|
|
4305
|
-
readonly label: "40 requests";
|
|
4306
4313
|
}, {
|
|
4307
4314
|
readonly value: "90";
|
|
4308
4315
|
readonly label: "90 requests";
|
|
4309
|
-
readonly description: "Default";
|
|
4310
4316
|
}, {
|
|
4311
4317
|
readonly value: "150";
|
|
4312
4318
|
readonly label: "150 requests";
|
|
4319
|
+
}, {
|
|
4320
|
+
readonly value: "200";
|
|
4321
|
+
readonly label: "200 requests";
|
|
4322
|
+
readonly description: "Default";
|
|
4313
4323
|
}];
|
|
4314
4324
|
};
|
|
4315
4325
|
};
|
|
4316
4326
|
readonly "task.softRequestBudgetNotice": {
|
|
4317
4327
|
readonly type: "boolean";
|
|
4318
|
-
readonly default:
|
|
4328
|
+
readonly default: true;
|
|
4319
4329
|
readonly ui: {
|
|
4320
4330
|
readonly tab: "tasks";
|
|
4321
4331
|
readonly group: "Subagents";
|
|
4322
4332
|
readonly label: "Soft Request Budget Notice";
|
|
4323
|
-
readonly description: "Inject one steering notice when a subagent crosses its soft request budget
|
|
4333
|
+
readonly description: "Inject one steering notice when a subagent crosses its soft request budget, asking it to wrap up before the 1.5x forced-yield stop.";
|
|
4324
4334
|
};
|
|
4325
4335
|
};
|
|
4326
4336
|
readonly "task.disabledAgents": {
|
|
@@ -129,9 +129,10 @@ export declare class Settings {
|
|
|
129
129
|
*/
|
|
130
130
|
getBashInterceptorRules(): BashInterceptorRule[];
|
|
131
131
|
/**
|
|
132
|
-
* Set a model role (helper for modelRoles record).
|
|
132
|
+
* Set a model role (helper for modelRoles record). Passing `undefined`
|
|
133
|
+
* clears the role from the persisted record and any runtime override.
|
|
133
134
|
*/
|
|
134
|
-
setModelRole(role: ModelRole | string, modelId: string): void;
|
|
135
|
+
setModelRole(role: ModelRole | string, modelId: string | undefined): void;
|
|
135
136
|
/**
|
|
136
137
|
* Get a model role (helper for modelRoles record).
|
|
137
138
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
1
|
import type { ExtensionModule } from "../capability/extension-module.js";
|
|
3
2
|
import { type Rule } from "../capability/rule.js";
|
|
4
3
|
import type { Skill } from "../capability/skill.js";
|
|
5
4
|
import type { LoadContext, LoadResult, SourceMeta } from "../capability/types.js";
|
|
5
|
+
import { type ConfiguredThinkingLevel } from "../thinking.js";
|
|
6
6
|
/**
|
|
7
7
|
* Standard paths for each config source.
|
|
8
8
|
*/
|
|
@@ -107,7 +107,7 @@ export interface ParsedAgentFields {
|
|
|
107
107
|
spawns?: string[] | "*";
|
|
108
108
|
model?: string[];
|
|
109
109
|
output?: unknown;
|
|
110
|
-
thinkingLevel?:
|
|
110
|
+
thinkingLevel?: ConfiguredThinkingLevel;
|
|
111
111
|
autoloadSkills?: string[];
|
|
112
112
|
readSummarize?: boolean;
|
|
113
113
|
blocking?: boolean;
|
|
@@ -42,6 +42,40 @@ export interface ExtensionUISelectOption {
|
|
|
42
42
|
description?: string;
|
|
43
43
|
}
|
|
44
44
|
export type ExtensionUISelectItem = string | ExtensionUISelectOption;
|
|
45
|
+
export interface ExtensionAskDialogOption {
|
|
46
|
+
label: string;
|
|
47
|
+
description?: string;
|
|
48
|
+
preview?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface ExtensionAskDialogQuestion {
|
|
51
|
+
id: string;
|
|
52
|
+
question: string;
|
|
53
|
+
header?: string;
|
|
54
|
+
options: ExtensionAskDialogOption[];
|
|
55
|
+
multi?: boolean;
|
|
56
|
+
recommended?: number;
|
|
57
|
+
}
|
|
58
|
+
export interface ExtensionAskDialogResultItem {
|
|
59
|
+
id: string;
|
|
60
|
+
question: string;
|
|
61
|
+
options: string[];
|
|
62
|
+
multi: boolean;
|
|
63
|
+
selectedOptions: string[];
|
|
64
|
+
customInput?: string;
|
|
65
|
+
note?: string;
|
|
66
|
+
timedOut?: boolean;
|
|
67
|
+
}
|
|
68
|
+
export interface ExtensionAskDialogSubmitResult {
|
|
69
|
+
kind: "submit";
|
|
70
|
+
results: ExtensionAskDialogResultItem[];
|
|
71
|
+
}
|
|
72
|
+
/** Chat-redirect result: the user chose "Chat about this" instead of
|
|
73
|
+
* answering. Distinct from `undefined` (cancel) so AskTool can hand off to
|
|
74
|
+
* the chat loop rather than aborting. */
|
|
75
|
+
export interface ExtensionAskDialogChatResult {
|
|
76
|
+
kind: "chat";
|
|
77
|
+
}
|
|
78
|
+
export type ExtensionAskDialogResult = ExtensionAskDialogSubmitResult | ExtensionAskDialogChatResult;
|
|
45
79
|
export declare function getExtensionUISelectOptionLabel(option: ExtensionUISelectItem): string;
|
|
46
80
|
/**
|
|
47
81
|
* UI dialog options for extensions.
|
|
@@ -108,6 +142,8 @@ export interface ExtensionUIContext {
|
|
|
108
142
|
confirm(title: string, message: string, dialogOptions?: ExtensionUIDialogOptions): Promise<boolean>;
|
|
109
143
|
/** Show a text input dialog. */
|
|
110
144
|
input(title: string, placeholder?: string, dialogOptions?: ExtensionUIDialogOptions): Promise<string | undefined>;
|
|
145
|
+
/** Show the rich ask dialog when the interactive TUI surface is available. */
|
|
146
|
+
askDialog?(questions: ExtensionAskDialogQuestion[], dialogOptions?: ExtensionUIDialogOptions): Promise<ExtensionAskDialogResult | undefined>;
|
|
111
147
|
/** Show a notification to the user. */
|
|
112
148
|
notify(message: string, type?: "info" | "warning" | "error"): void;
|
|
113
149
|
/** Listen to raw terminal input (interactive mode only). Returns an unsubscribe function. */
|
package/dist/types/irc/bus.d.ts
CHANGED
|
@@ -77,6 +77,10 @@ export declare class IrcBus {
|
|
|
77
77
|
from?: string;
|
|
78
78
|
}, timeoutMs: number, signal?: AbortSignal, options?: {
|
|
79
79
|
drainPending?: boolean;
|
|
80
|
+
liveness?: {
|
|
81
|
+
registry: AgentRegistry;
|
|
82
|
+
senderId: string;
|
|
83
|
+
};
|
|
80
84
|
}): Promise<IrcMessage | null>;
|
|
81
85
|
/** Drain (or peek) pending messages for `agentId`. */
|
|
82
86
|
inbox(agentId: string, opts?: {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type Component, type TUI } from "@oh-my-pi/pi-tui";
|
|
2
|
+
import type { ExtensionAskDialogQuestion, ExtensionAskDialogSubmitResult } from "../../extensibility/extensions/index.js";
|
|
3
|
+
/** Bound a prompt editor title to a fixed row/width budget so long or
|
|
4
|
+
* multi-line questions stay usable inside the small prompt overlay. */
|
|
5
|
+
export declare function boundPromptTitle(prefix: string, question: string): string;
|
|
6
|
+
interface AskDialogCallbacks {
|
|
7
|
+
onSubmit(result: ExtensionAskDialogSubmitResult): void;
|
|
8
|
+
onCancel(): void;
|
|
9
|
+
onPrompt(title: string, prefill?: string): Promise<string | undefined>;
|
|
10
|
+
}
|
|
11
|
+
interface AskDialogOptions {
|
|
12
|
+
timeout?: number;
|
|
13
|
+
onTimeout?: () => void;
|
|
14
|
+
tui?: TUI;
|
|
15
|
+
}
|
|
16
|
+
export declare class AskDialogComponent implements Component {
|
|
17
|
+
#private;
|
|
18
|
+
private readonly questions;
|
|
19
|
+
private readonly callbacks;
|
|
20
|
+
private readonly options;
|
|
21
|
+
constructor(questions: ExtensionAskDialogQuestion[], callbacks: AskDialogCallbacks, options?: AskDialogOptions);
|
|
22
|
+
invalidate(): void;
|
|
23
|
+
dispose(): void;
|
|
24
|
+
handleInput(keyData: string): void;
|
|
25
|
+
render(width: number): readonly string[];
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
@@ -86,14 +86,9 @@ export declare class CustomEditor extends Editor {
|
|
|
86
86
|
static readonly SHIMMER_FRAME_MS = 70;
|
|
87
87
|
/** Time for the gradient to sweep one full cycle across each keyword. */
|
|
88
88
|
static readonly SHIMMER_PERIOD_MS = 1800;
|
|
89
|
-
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* When the editor is focused, the buffer contains a magic keyword, and `magicKeywords.enabled`
|
|
93
|
-
* is on, the gradient shifts every frame to produce a Claude-Code-style shimmer; each render
|
|
94
|
-
* schedules the next frame, so losing focus, deleting the keyword, or flipping the setting
|
|
95
|
-
* stops the animation on its own. The static glow itself runs even when shimmering is gated
|
|
96
|
-
* off, matching existing behavior for the editor and sent bubbles. */
|
|
89
|
+
/** Decorate magic keywords, attachments, and the queue-composer header/list markers.
|
|
90
|
+
* Queue shorthand reserves its first logical line as a dim `Queueing` label; sequential
|
|
91
|
+
* item markers use the accent color so separate follow-ups remain visible while composing. */
|
|
97
92
|
decorateText: (text: string) => string;
|
|
98
93
|
/** Optional test/host override for the magic-keyword shimmer gate. When
|
|
99
94
|
* defined, takes precedence over the global `magicKeywords.enabled` setting,
|
|
@@ -16,7 +16,8 @@ export * from "./hook-selector.js";
|
|
|
16
16
|
export * from "./keybinding-hints.js";
|
|
17
17
|
export * from "./login-dialog.js";
|
|
18
18
|
export * from "./logout-account-selector.js";
|
|
19
|
-
export * from "./model-
|
|
19
|
+
export * from "./model-browser.js";
|
|
20
|
+
export * from "./model-hub.js";
|
|
20
21
|
export * from "./oauth-selector.js";
|
|
21
22
|
export * from "./queue-mode-selector.js";
|
|
22
23
|
export * from "./read-tool-group.js";
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type { Model } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import { type Component, type SgrMouseEvent } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import type { Settings } from "../../config/settings.js";
|
|
4
|
+
import type { ModelPerfStats } from "../../session/agent-storage.js";
|
|
5
|
+
import { type ConfiguredThinkingLevel } from "../../thinking.js";
|
|
6
|
+
/** One selectable model row. `selector` is the canonical `provider/id` key. */
|
|
7
|
+
export interface ModelBrowserItem {
|
|
8
|
+
provider: string;
|
|
9
|
+
id: string;
|
|
10
|
+
model: Model;
|
|
11
|
+
selector: string;
|
|
12
|
+
}
|
|
13
|
+
/** Resolved role assignment as displayed by the browser and the hub. */
|
|
14
|
+
export interface RoleAssignment {
|
|
15
|
+
model: Model;
|
|
16
|
+
thinkingLevel: ConfiguredThinkingLevel;
|
|
17
|
+
/** True when the role has no configured value and fell back to auto-selection. */
|
|
18
|
+
autoSelected: boolean;
|
|
19
|
+
}
|
|
20
|
+
/** Map of role id to its resolved assignment (absent roles are unresolved). */
|
|
21
|
+
export type RoleAssignments = Record<string, RoleAssignment | undefined>;
|
|
22
|
+
/** Wrap raw models into browser items. */
|
|
23
|
+
export declare function buildBrowserItems(models: ReadonlyArray<Model>): ModelBrowserItem[];
|
|
24
|
+
/** Options for {@link sortModelItems}. */
|
|
25
|
+
export interface SortModelItemsOptions {
|
|
26
|
+
roles?: RoleAssignments;
|
|
27
|
+
mruOrder?: ReadonlyArray<string>;
|
|
28
|
+
/**
|
|
29
|
+
* When a search query is narrowing the list, role assignments should NOT
|
|
30
|
+
* promote a weakly-matching default model above a perfect text match —
|
|
31
|
+
* defer to MRU/version instead so user affinity drives the order.
|
|
32
|
+
*/
|
|
33
|
+
skipRoleRank?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Order models for display: role-assigned first, then most-recently-used,
|
|
37
|
+
* then per provider by priority, version, and recency.
|
|
38
|
+
*/
|
|
39
|
+
export declare function sortModelItems(items: ModelBrowserItem[], options?: SortModelItemsOptions): void;
|
|
40
|
+
/** Compact glyph for a configured thinking level; empty for `inherit` (nothing to show). */
|
|
41
|
+
export declare function thinkingLevelGlyph(level: ConfiguredThinkingLevel): string;
|
|
42
|
+
/**
|
|
43
|
+
* A slim role chip: `●default ◉` — solid dot for configured assignments,
|
|
44
|
+
* hollow for auto-selected fallbacks, thinking glyph attached when set.
|
|
45
|
+
*/
|
|
46
|
+
export declare function formatRoleChip(role: string, assignment: RoleAssignment, settings: Settings): string;
|
|
47
|
+
/** Behavior switches for {@link ModelBrowser}. */
|
|
48
|
+
export interface ModelBrowserOptions {
|
|
49
|
+
/** Render the dim `provider/` prefix before model ids. Default true. */
|
|
50
|
+
showProvider?: boolean;
|
|
51
|
+
/** Session token count used to disable models whose context window is exceeded. */
|
|
52
|
+
currentContextTokens?: number;
|
|
53
|
+
/** When true, rows over the current context are unselectable (session-switch mode). */
|
|
54
|
+
disableOverContext?: boolean;
|
|
55
|
+
/** Host-provided empty-state text (e.g. provider discovery status). */
|
|
56
|
+
emptyText?: () => string | undefined;
|
|
57
|
+
initialQuery?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The reusable browser component. Renders a fixed-height block
|
|
61
|
+
* (`maxVisible + LIST_ROW_START + DETAIL_ROWS` rows) so host mouse geometry
|
|
62
|
+
* stays stable across renders.
|
|
63
|
+
*/
|
|
64
|
+
export declare class ModelBrowser implements Component {
|
|
65
|
+
#private;
|
|
66
|
+
/** Enter or click-on-selected. */
|
|
67
|
+
onActivate?: (item: ModelBrowserItem) => void;
|
|
68
|
+
onSelectionChange?: (item: ModelBrowserItem | undefined) => void;
|
|
69
|
+
onQueryChange?: (query: string) => void;
|
|
70
|
+
/** Cancel key with an empty query (a non-empty query is cleared first). */
|
|
71
|
+
onCancel?: () => void;
|
|
72
|
+
constructor(settings: Settings, options?: ModelBrowserOptions);
|
|
73
|
+
/** Replace the scope's base items; the live query re-applies and selection is pinned by selector. */
|
|
74
|
+
setItems(items: ModelBrowserItem[]): void;
|
|
75
|
+
setRoles(roles: RoleAssignments): void;
|
|
76
|
+
setMruOrder(order: ReadonlyArray<string>): void;
|
|
77
|
+
/** Measured TPS/TTFT averages keyed by `provider/id` selector (see AgentStorage.getModelPerf). */
|
|
78
|
+
setPerfStats(perf: ReadonlyMap<string, ModelPerfStats>): void;
|
|
79
|
+
setMaxVisible(rows: number): void;
|
|
80
|
+
setShowProvider(show: boolean): void;
|
|
81
|
+
/** Total rendered height for the current `maxVisible` (host layout budgeting). */
|
|
82
|
+
get renderedRows(): number;
|
|
83
|
+
get query(): string;
|
|
84
|
+
setQuery(query: string): void;
|
|
85
|
+
getSelected(): ModelBrowserItem | undefined;
|
|
86
|
+
get visibleCount(): number;
|
|
87
|
+
/** Move selection to `selector`; false when it is not in the current view. */
|
|
88
|
+
selectSelector(selector: string): boolean;
|
|
89
|
+
moveSelection(delta: number): void;
|
|
90
|
+
handleInput(data: string): void;
|
|
91
|
+
/** Cancel-key ladder: clear a non-empty query first, then bubble to the host. */
|
|
92
|
+
handleCancel(): void;
|
|
93
|
+
/**
|
|
94
|
+
* Route a mouse event. `line` is relative to the browser's first rendered
|
|
95
|
+
* row (the search row).
|
|
96
|
+
*/
|
|
97
|
+
routeMouse(event: SgrMouseEvent, line: number): void;
|
|
98
|
+
render(width: number): string[];
|
|
99
|
+
invalidate(): void;
|
|
100
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { Model } from "@oh-my-pi/pi-ai";
|
|
2
|
+
import { type Component, type TUI } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import type { ModelRegistry } from "../../config/model-registry.js";
|
|
4
|
+
import type { Settings } from "../../config/settings.js";
|
|
5
|
+
import { type ConfiguredThinkingLevel } from "../../thinking.js";
|
|
6
|
+
/** `roles` is the full /models hub; `pick` is a one-shot session/embedded picker. */
|
|
7
|
+
export type ModelHubMode = "roles" | "pick";
|
|
8
|
+
/** A `--models` scope entry (mirrors the session's scoped model list). */
|
|
9
|
+
export interface ScopedModelItem {
|
|
10
|
+
model: Model;
|
|
11
|
+
thinkingLevel?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface ModelHubCallbacks {
|
|
14
|
+
/** Persist a role assignment. */
|
|
15
|
+
onAssign: (model: Model, role: string, thinkingLevel: ConfiguredThinkingLevel | undefined, selector: string) => void;
|
|
16
|
+
/** Clear a configured role back to auto-selection. */
|
|
17
|
+
onUnassign: (role: string) => void;
|
|
18
|
+
/** Persist a `retry.fallbackChains` entry — keyed by a role, `provider/model-id`, or `provider/*`; an empty chain clears the key. */
|
|
19
|
+
onFallbackChainChange?: (role: string, chain: string[]) => void;
|
|
20
|
+
/** Pick-mode activation: session-only switch or embedded pick. */
|
|
21
|
+
onPick?: (model: Model, selector: string) => void;
|
|
22
|
+
/** Locked provider activation: forward to the /login flow. */
|
|
23
|
+
onLoginRequest?: (providerId: string) => void;
|
|
24
|
+
/** Persist a new quick-switch cycle order (the ctrl+p role cycle). */
|
|
25
|
+
onCycleOrderChange?: (order: string[]) => void;
|
|
26
|
+
onCancel: () => void;
|
|
27
|
+
}
|
|
28
|
+
export interface ModelHubOptions {
|
|
29
|
+
mode?: ModelHubMode;
|
|
30
|
+
/** Session token count; in pick mode, models with smaller context windows are disabled. */
|
|
31
|
+
currentContextTokens?: number;
|
|
32
|
+
/** Preselect this provider's sidebar entry (e.g. when reopening after /login). */
|
|
33
|
+
initialProviderId?: string;
|
|
34
|
+
/** Status-row hint shown in pick mode. */
|
|
35
|
+
pickerHint?: string;
|
|
36
|
+
initialQuery?: string;
|
|
37
|
+
}
|
|
38
|
+
/** Test hook: forget which providers were auto-refreshed this process. */
|
|
39
|
+
export declare function resetProviderAutoRefreshGuard(): void;
|
|
40
|
+
/**
|
|
41
|
+
* The fullscreen model hub component. Hosted via `ui.showOverlay(..., { fullscreen: true })`;
|
|
42
|
+
* the host must call {@link ModelHubComponent.dispose} when the overlay closes.
|
|
43
|
+
*/
|
|
44
|
+
export declare class ModelHubComponent implements Component {
|
|
45
|
+
#private;
|
|
46
|
+
constructor(tui: TUI, settings: Settings, registry: ModelRegistry, scopedModels: ReadonlyArray<ScopedModelItem>, callbacks: ModelHubCallbacks, options?: ModelHubOptions);
|
|
47
|
+
/** Cancel pending provider refresh timers and the spinner. Host calls this on overlay close. */
|
|
48
|
+
dispose(): void;
|
|
49
|
+
invalidate(): void;
|
|
50
|
+
handleInput(data: string): void;
|
|
51
|
+
render(width: number): string[];
|
|
52
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type Component, type OverlayFocusOwner, type OverlayHandle, type OverlayOptions } from "@oh-my-pi/pi-tui";
|
|
2
|
+
/**
|
|
3
|
+
* Slice of `InteractiveModeContext` the pause screen drives. Narrow so tests
|
|
4
|
+
* can exercise the full engage → hold → release lifecycle without a real TUI.
|
|
5
|
+
*/
|
|
6
|
+
export interface PauseScreenHost {
|
|
7
|
+
ui: {
|
|
8
|
+
showOverlay(component: Component, options?: OverlayOptions): OverlayHandle;
|
|
9
|
+
setFocus(component: Component): void;
|
|
10
|
+
requestRender(): void;
|
|
11
|
+
readonly terminal: {
|
|
12
|
+
readonly rows: number;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
showStatus(message: string, options?: {
|
|
16
|
+
dim?: boolean;
|
|
17
|
+
}): void;
|
|
18
|
+
readonly sessionName?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Paint the pause scene as exactly `height` rows, vertically centered.
|
|
22
|
+
* Exported for tests.
|
|
23
|
+
*/
|
|
24
|
+
export declare function renderPauseScreen(width: number, height: number, elapsedMs: number, sessionName?: string): string[];
|
|
25
|
+
/** Fullscreen overlay component; resolves {@link run} when a resume key lands. */
|
|
26
|
+
export declare class PauseScreenComponent implements Component, OverlayFocusOwner {
|
|
27
|
+
#private;
|
|
28
|
+
readonly host: PauseScreenHost;
|
|
29
|
+
constructor(host: PauseScreenHost);
|
|
30
|
+
/** Start the clock; resolves once the user asks to resume. */
|
|
31
|
+
run(): Promise<void>;
|
|
32
|
+
dispose(): void;
|
|
33
|
+
ownsOverlayFocusTarget(component: Component): boolean;
|
|
34
|
+
handleInput(data: string): void;
|
|
35
|
+
render(width: number): readonly string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Engage the global pause gate and hold the fullscreen pause screen until the
|
|
39
|
+
* user resumes. No-op when the gate is already engaged. Always releases the
|
|
40
|
+
* gate on the way out (including teardown throws) — a leaked pause would
|
|
41
|
+
* freeze every agent in the process with no UI left to release it.
|
|
42
|
+
*/
|
|
43
|
+
export declare function runPauseScreen(host: PauseScreenHost): Promise<void>;
|
|
@@ -9,6 +9,9 @@ export type SessionHistoryMatcher = (query: string) => string[];
|
|
|
9
9
|
* as a literal substring, newer sessions should beat a slightly better fuzzy
|
|
10
10
|
* position match. Pure fuzzy/acronym matches still sort by fuzzy score after
|
|
11
11
|
* literal matches, but weak pure fuzzy tokens are dropped as noise.
|
|
12
|
+
*
|
|
13
|
+
* This is the synchronous reference implementation; {@link SessionList} runs
|
|
14
|
+
* the same primitives incrementally so huge listings never block a keystroke.
|
|
12
15
|
*/
|
|
13
16
|
export declare function rankSessionSearchMatches(allSessions: SessionInfo[], query: string): SessionInfo[];
|
|
14
17
|
/**
|
|
@@ -35,9 +38,13 @@ declare class SessionList implements Component {
|
|
|
35
38
|
onExit: () => void;
|
|
36
39
|
onToggleScope?: () => void;
|
|
37
40
|
onDeleteRequest?: (session: SessionInfo) => void;
|
|
41
|
+
/** Re-render hook for async list updates (fuzzy scan chunks, history merge). */
|
|
42
|
+
onRequestRender?: () => void;
|
|
38
43
|
constructor(sessions: SessionInfo[], showCwd?: boolean, historyMatcher?: SessionHistoryMatcher, getTerminalRows?: () => number);
|
|
39
44
|
/** Replace the visible dataset, e.g. when toggling folder/all-projects scope. */
|
|
40
45
|
setSessions(sessions: SessionInfo[], showCwd: boolean): void;
|
|
46
|
+
/** Cancel pending async search work; idempotent, called on every picker exit path. */
|
|
47
|
+
dispose(): void;
|
|
41
48
|
removeSession(sessionPath: string): void;
|
|
42
49
|
/** Resolve a list-local rendered-line index to a filtered-session index. */
|
|
43
50
|
hitTestSession(line: number): number | undefined;
|
|
@@ -76,6 +83,12 @@ export declare class SessionSelectorComponent extends Container {
|
|
|
76
83
|
#private;
|
|
77
84
|
constructor(sessions: SessionInfo[], onSelect: (session: SessionInfo) => void, onCancel: () => void, onExit: () => void, options?: SessionSelectorOptions);
|
|
78
85
|
setOnRequestRender(callback: () => void): void;
|
|
86
|
+
/**
|
|
87
|
+
* Dispose the session list explicitly: while the delete-confirmation dialog
|
|
88
|
+
* is mounted the list is detached from the child tree, so Container's
|
|
89
|
+
* child-walking dispose would miss its pending history-merge timer.
|
|
90
|
+
*/
|
|
91
|
+
dispose(): void;
|
|
79
92
|
/**
|
|
80
93
|
* Concatenate the children's renders (like {@link Container}) while recording
|
|
81
94
|
* the line where the session list begins, so the fullscreen picker can hit-
|
|
@@ -32,6 +32,8 @@ export interface ToolExecutionHandle extends Component {
|
|
|
32
32
|
}, isPartial?: boolean, toolCallId?: string): void;
|
|
33
33
|
setArgsComplete(toolCallId?: string): void;
|
|
34
34
|
setExpanded(expanded: boolean): void;
|
|
35
|
+
/** Freeze the block as final history: stop spinners and let it commit to scrollback. */
|
|
36
|
+
seal(): void;
|
|
35
37
|
}
|
|
36
38
|
/** Redraw live tool blocks at the spinner's glyph-advance rate. Rendering more
|
|
37
39
|
* often produced identical frames — the previous 30fps cadence emitted ~2.4
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Component, TUI } from "@oh-my-pi/pi-tui";
|
|
2
2
|
import { KeybindingsManager } from "../../config/keybindings.js";
|
|
3
|
-
import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions, TerminalInputHandler } from "../../extensibility/extensions/index.js";
|
|
3
|
+
import type { ExtensionAskDialogQuestion, ExtensionAskDialogResult, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions, TerminalInputHandler } from "../../extensibility/extensions/index.js";
|
|
4
4
|
import { type HookSelectorSlider } from "../../modes/components/hook-selector.js";
|
|
5
5
|
import { type Theme } from "../../modes/theme/theme.js";
|
|
6
6
|
import type { InteractiveModeContext, InteractiveSelectorDialogOptions } from "../../modes/types.js";
|
|
@@ -32,6 +32,7 @@ export declare class ExtensionUiController {
|
|
|
32
32
|
showCollabAwareEditor(title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: {
|
|
33
33
|
promptStyle?: boolean;
|
|
34
34
|
}): Promise<string | undefined>;
|
|
35
|
+
showAskDialog(questions: ExtensionAskDialogQuestion[], dialogOptions?: ExtensionUIDialogOptions): Promise<ExtensionAskDialogResult | undefined>;
|
|
35
36
|
/**
|
|
36
37
|
* Show a selector for hooks.
|
|
37
38
|
*/
|
|
@@ -33,6 +33,8 @@ export declare class InputController {
|
|
|
33
33
|
handleCtrlZ(): void;
|
|
34
34
|
handleDequeue(): void;
|
|
35
35
|
handleRetry(): Promise<void>;
|
|
36
|
+
/** Queue `/queue` input behind an active turn, or start it immediately when idle. */
|
|
37
|
+
handleQueueCommand(text: string): Promise<void>;
|
|
36
38
|
/** Send editor text as a follow-up message (queued behind current stream). */
|
|
37
39
|
handleFollowUp(): Promise<void>;
|
|
38
40
|
restoreQueuedMessagesToEditor(options?: {
|
|
@@ -166,6 +166,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
166
166
|
get eventBus(): EventBus | undefined;
|
|
167
167
|
get viewSession(): AgentSession;
|
|
168
168
|
get focusedAgentId(): string | undefined;
|
|
169
|
+
get sessionName(): string | undefined;
|
|
169
170
|
focusAgentSession(id: string): Promise<void>;
|
|
170
171
|
focusParentSession(): Promise<void>;
|
|
171
172
|
unfocusSession(): Promise<void>;
|
|
@@ -364,6 +365,8 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
364
365
|
handleCtrlZ(): void;
|
|
365
366
|
handleDequeue(): void;
|
|
366
367
|
handleImagePaste(): Promise<boolean>;
|
|
368
|
+
/** Queue slash-command input behind the active turn. */
|
|
369
|
+
handleQueueCommand(message: string): Promise<void>;
|
|
367
370
|
handleBtwCommand(question: string): Promise<void>;
|
|
368
371
|
handleTanCommand(work: string): Promise<void>;
|
|
369
372
|
hasActiveBtw(): boolean;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Prefix matcher shared by queue-list parsing and editor highlighting. */
|
|
2
|
+
export declare const QUEUE_LIST_MARKER_RE: RegExp;
|
|
3
|
+
/** Extract the message body from the `->` / `=>` yield-queue shorthand. */
|
|
4
|
+
export declare function parseQueueShorthand(text: string): string | undefined;
|
|
5
|
+
/** Whether text currently forms a sequential queue list, including an unfinished trailing item. */
|
|
6
|
+
export declare function isQueuedMessageList(text: string): boolean;
|
|
7
|
+
/** Split a sequential numeric, Roman-numeral, or alphabetic list into queue entries. */
|
|
8
|
+
export declare function splitQueuedMessages(text: string): string[];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { TabBarTheme } from "@oh-my-pi/pi-tui";
|
|
2
2
|
/** Sanitize text for display in a single-line status. Strips ANSI/VT escape sequences, maps remaining C0/C1 control characters to spaces, collapses whitespace, trims. */
|
|
3
3
|
export declare function sanitizeStatusText(text: string): string;
|
|
4
|
-
/** Shared tab bar theme used by
|
|
4
|
+
/** Shared tab bar theme used by fullscreen overlays (settings, agent hub). */
|
|
5
5
|
export declare function getTabBarTheme(): TabBarTheme;
|
|
6
6
|
/**
|
|
7
7
|
* Suffix appended to the loader's working message to remind users they can
|
|
@@ -95,6 +95,8 @@ export interface InteractiveModeContext {
|
|
|
95
95
|
statusLine: StatusLineComponent;
|
|
96
96
|
session: AgentSession;
|
|
97
97
|
sessionManager: SessionManager;
|
|
98
|
+
/** The current session display name / title. */
|
|
99
|
+
readonly sessionName: string | undefined;
|
|
98
100
|
/** Session the transcript/editor/status are attached to: the focused agent's, else `session`. */
|
|
99
101
|
readonly viewSession: AgentSession;
|
|
100
102
|
/** Id of the focused agent, undefined when the main session is attached. */
|
|
@@ -350,6 +352,8 @@ export interface InteractiveModeContext {
|
|
|
350
352
|
handleCtrlZ(): void;
|
|
351
353
|
handleDequeue(): void;
|
|
352
354
|
handleImagePaste(): Promise<boolean>;
|
|
355
|
+
/** Queue a message for delivery only after the active agent turn would stop. */
|
|
356
|
+
handleQueueCommand(message: string): Promise<void>;
|
|
353
357
|
handleBtwCommand(question: string): Promise<void>;
|
|
354
358
|
handleTanCommand(work: string): Promise<void>;
|
|
355
359
|
hasActiveBtw(): boolean;
|
|
@@ -711,7 +711,7 @@ export declare class AgentSession {
|
|
|
711
711
|
* surface bounded. Display-only — NEVER feed the result to
|
|
712
712
|
* `agent.replaceMessages` or a provider.
|
|
713
713
|
*/
|
|
714
|
-
buildTranscriptSessionContext(options?: Pick<BuildSessionContextOptions, "collapseCompactedHistory">): SessionContext;
|
|
714
|
+
buildTranscriptSessionContext(options?: Pick<BuildSessionContextOptions, "collapseCompactedHistory" | "keepDanglingToolCalls">): SessionContext;
|
|
715
715
|
/** Convert session messages using the same pre-LLM pipeline as the active session. */
|
|
716
716
|
convertMessagesToLlm(messages: AgentMessage[], signal?: AbortSignal): Promise<Message[]>;
|
|
717
717
|
/** Apply session-level stream hooks to a direct side request. */
|