@oh-my-pi/pi-coding-agent 16.4.4 → 16.4.5
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 +33 -0
- package/dist/cli.js +3563 -3540
- package/dist/types/async/job-manager.d.ts +8 -0
- package/dist/types/config/settings-schema.d.ts +18 -8
- 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/index.d.ts +2 -1
- package/dist/types/modes/components/model-browser.d.ts +97 -0
- package/dist/types/modes/components/model-hub.d.ts +51 -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/interactive-mode.d.ts +1 -0
- package/dist/types/modes/shared.d.ts +1 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +1 -1
- 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/src/async/job-manager.ts +9 -0
- package/src/commit/agentic/tools/analyze-file.ts +2 -3
- package/src/config/settings-schema.ts +17 -6
- 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 +30 -22
- package/src/modes/components/ask-dialog.ts +888 -0
- package/src/modes/components/index.ts +2 -1
- package/src/modes/components/model-browser.ts +688 -0
- package/src/modes/components/model-hub.ts +1655 -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/controllers/event-controller.ts +8 -2
- package/src/modes/controllers/extension-ui-controller.ts +252 -5
- package/src/modes/controllers/selector-controller.ts +143 -87
- package/src/modes/controllers/tan-command-controller.ts +1 -1
- package/src/modes/interactive-mode.ts +3 -0
- package/src/modes/shared.ts +1 -1
- package/src/modes/theme/theme.ts +3 -3
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +31 -4
- 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 +2 -1
- package/src/session/session-context.test.ts +73 -0
- package/src/session/session-context.ts +43 -26
- package/src/slash-commands/builtin-registry.ts +9 -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;
|
|
@@ -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 {};
|
|
@@ -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,97 @@
|
|
|
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 ConfiguredThinkingLevel } from "../../thinking.js";
|
|
5
|
+
/** One selectable model row. `selector` is the canonical `provider/id` key. */
|
|
6
|
+
export interface ModelBrowserItem {
|
|
7
|
+
provider: string;
|
|
8
|
+
id: string;
|
|
9
|
+
model: Model;
|
|
10
|
+
selector: string;
|
|
11
|
+
}
|
|
12
|
+
/** Resolved role assignment as displayed by the browser and the hub. */
|
|
13
|
+
export interface RoleAssignment {
|
|
14
|
+
model: Model;
|
|
15
|
+
thinkingLevel: ConfiguredThinkingLevel;
|
|
16
|
+
/** True when the role has no configured value and fell back to auto-selection. */
|
|
17
|
+
autoSelected: boolean;
|
|
18
|
+
}
|
|
19
|
+
/** Map of role id to its resolved assignment (absent roles are unresolved). */
|
|
20
|
+
export type RoleAssignments = Record<string, RoleAssignment | undefined>;
|
|
21
|
+
/** Wrap raw models into browser items. */
|
|
22
|
+
export declare function buildBrowserItems(models: ReadonlyArray<Model>): ModelBrowserItem[];
|
|
23
|
+
/** Options for {@link sortModelItems}. */
|
|
24
|
+
export interface SortModelItemsOptions {
|
|
25
|
+
roles?: RoleAssignments;
|
|
26
|
+
mruOrder?: ReadonlyArray<string>;
|
|
27
|
+
/**
|
|
28
|
+
* When a search query is narrowing the list, role assignments should NOT
|
|
29
|
+
* promote a weakly-matching default model above a perfect text match —
|
|
30
|
+
* defer to MRU/version instead so user affinity drives the order.
|
|
31
|
+
*/
|
|
32
|
+
skipRoleRank?: boolean;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Order models for display: role-assigned first, then most-recently-used,
|
|
36
|
+
* then per provider by priority, version, and recency.
|
|
37
|
+
*/
|
|
38
|
+
export declare function sortModelItems(items: ModelBrowserItem[], options?: SortModelItemsOptions): void;
|
|
39
|
+
/** Compact glyph for a configured thinking level; empty for `inherit` (nothing to show). */
|
|
40
|
+
export declare function thinkingLevelGlyph(level: ConfiguredThinkingLevel): string;
|
|
41
|
+
/**
|
|
42
|
+
* A slim role chip: `●default ◉` — solid dot for configured assignments,
|
|
43
|
+
* hollow for auto-selected fallbacks, thinking glyph attached when set.
|
|
44
|
+
*/
|
|
45
|
+
export declare function formatRoleChip(role: string, assignment: RoleAssignment, settings: Settings): string;
|
|
46
|
+
/** Behavior switches for {@link ModelBrowser}. */
|
|
47
|
+
export interface ModelBrowserOptions {
|
|
48
|
+
/** Render the dim `provider/` prefix before model ids. Default true. */
|
|
49
|
+
showProvider?: boolean;
|
|
50
|
+
/** Session token count used to disable models whose context window is exceeded. */
|
|
51
|
+
currentContextTokens?: number;
|
|
52
|
+
/** When true, rows over the current context are unselectable (session-switch mode). */
|
|
53
|
+
disableOverContext?: boolean;
|
|
54
|
+
/** Host-provided empty-state text (e.g. provider discovery status). */
|
|
55
|
+
emptyText?: () => string | undefined;
|
|
56
|
+
initialQuery?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The reusable browser component. Renders a fixed-height block
|
|
60
|
+
* (`maxVisible + LIST_ROW_START + DETAIL_ROWS` rows) so host mouse geometry
|
|
61
|
+
* stays stable across renders.
|
|
62
|
+
*/
|
|
63
|
+
export declare class ModelBrowser implements Component {
|
|
64
|
+
#private;
|
|
65
|
+
/** Enter or click-on-selected. */
|
|
66
|
+
onActivate?: (item: ModelBrowserItem) => void;
|
|
67
|
+
onSelectionChange?: (item: ModelBrowserItem | undefined) => void;
|
|
68
|
+
onQueryChange?: (query: string) => void;
|
|
69
|
+
/** Cancel key with an empty query (a non-empty query is cleared first). */
|
|
70
|
+
onCancel?: () => void;
|
|
71
|
+
constructor(settings: Settings, options?: ModelBrowserOptions);
|
|
72
|
+
/** Replace the scope's base items; the live query re-applies and selection is pinned by selector. */
|
|
73
|
+
setItems(items: ModelBrowserItem[]): void;
|
|
74
|
+
setRoles(roles: RoleAssignments): void;
|
|
75
|
+
setMruOrder(order: ReadonlyArray<string>): void;
|
|
76
|
+
setMaxVisible(rows: number): void;
|
|
77
|
+
setShowProvider(show: boolean): void;
|
|
78
|
+
/** Total rendered height for the current `maxVisible` (host layout budgeting). */
|
|
79
|
+
get renderedRows(): number;
|
|
80
|
+
get query(): string;
|
|
81
|
+
setQuery(query: string): void;
|
|
82
|
+
getSelected(): ModelBrowserItem | undefined;
|
|
83
|
+
get visibleCount(): number;
|
|
84
|
+
/** Move selection to `selector`; false when it is not in the current view. */
|
|
85
|
+
selectSelector(selector: string): boolean;
|
|
86
|
+
moveSelection(delta: number): void;
|
|
87
|
+
handleInput(data: string): void;
|
|
88
|
+
/** Cancel-key ladder: clear a non-empty query first, then bubble to the host. */
|
|
89
|
+
handleCancel(): void;
|
|
90
|
+
/**
|
|
91
|
+
* Route a mouse event. `line` is relative to the browser's first rendered
|
|
92
|
+
* row (the search row).
|
|
93
|
+
*/
|
|
94
|
+
routeMouse(event: SgrMouseEvent, line: number): void;
|
|
95
|
+
render(width: number): string[];
|
|
96
|
+
invalidate(): void;
|
|
97
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
export type ModelHubAction = "modelRole" | "retryFallback";
|
|
9
|
+
/** A `--models` scope entry (mirrors the session's scoped model list). */
|
|
10
|
+
export interface ScopedModelItem {
|
|
11
|
+
model: Model;
|
|
12
|
+
thinkingLevel?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ModelHubCallbacks {
|
|
15
|
+
/** Persist a role assignment (or a retry-fallback registration). */
|
|
16
|
+
onAssign: (model: Model, role: string, thinkingLevel: ConfiguredThinkingLevel | undefined, selector: string, action: ModelHubAction) => void;
|
|
17
|
+
/** Clear a configured role back to auto-selection. */
|
|
18
|
+
onUnassign: (role: string) => void;
|
|
19
|
+
/** Pick-mode activation: session-only switch or embedded pick. */
|
|
20
|
+
onPick?: (model: Model, selector: string) => void;
|
|
21
|
+
/** Locked provider activation: forward to the /login flow. */
|
|
22
|
+
onLoginRequest?: (providerId: string) => void;
|
|
23
|
+
/** Persist a new quick-switch cycle order (the ctrl+p role cycle). */
|
|
24
|
+
onCycleOrderChange?: (order: string[]) => void;
|
|
25
|
+
onCancel: () => void;
|
|
26
|
+
}
|
|
27
|
+
export interface ModelHubOptions {
|
|
28
|
+
mode?: ModelHubMode;
|
|
29
|
+
/** Session token count; in pick mode, models with smaller context windows are disabled. */
|
|
30
|
+
currentContextTokens?: number;
|
|
31
|
+
/** Preselect this provider's sidebar entry (e.g. when reopening after /login). */
|
|
32
|
+
initialProviderId?: string;
|
|
33
|
+
/** Status-row hint shown in pick mode. */
|
|
34
|
+
pickerHint?: string;
|
|
35
|
+
initialQuery?: string;
|
|
36
|
+
}
|
|
37
|
+
/** Test hook: forget which providers were auto-refreshed this process. */
|
|
38
|
+
export declare function resetProviderAutoRefreshGuard(): void;
|
|
39
|
+
/**
|
|
40
|
+
* The fullscreen model hub component. Hosted via `ui.showOverlay(..., { fullscreen: true })`;
|
|
41
|
+
* the host must call {@link ModelHubComponent.dispose} when the overlay closes.
|
|
42
|
+
*/
|
|
43
|
+
export declare class ModelHubComponent implements Component {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(tui: TUI, settings: Settings, registry: ModelRegistry, scopedModels: ReadonlyArray<ScopedModelItem>, callbacks: ModelHubCallbacks, options?: ModelHubOptions);
|
|
46
|
+
/** Cancel pending provider refresh timers and the spinner. Host calls this on overlay close. */
|
|
47
|
+
dispose(): void;
|
|
48
|
+
invalidate(): void;
|
|
49
|
+
handleInput(data: string): void;
|
|
50
|
+
render(width: number): string[];
|
|
51
|
+
}
|
|
@@ -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
|
*/
|
|
@@ -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>;
|
|
@@ -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. */
|
|
@@ -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. */
|
|
@@ -40,5 +40,14 @@ export interface BuildSessionContextOptions {
|
|
|
40
40
|
transcript?: boolean;
|
|
41
41
|
/** In transcript mode, elide entries replaced by the latest compaction. */
|
|
42
42
|
collapseCompactedHistory?: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Transcript mode only: keep `toolCall` blocks that have no matching
|
|
45
|
+
* `toolResult` on the path instead of stripping them. Pass this when the
|
|
46
|
+
* session is mid-turn (a tool is still executing, its result not yet
|
|
47
|
+
* persisted) so the rebuilt transcript renders the in-flight call as
|
|
48
|
+
* pending; without it a focus/unfocus or overlay-close rebuild silently
|
|
49
|
+
* hides the call the agent is still waiting on.
|
|
50
|
+
*/
|
|
51
|
+
keepDanglingToolCalls?: boolean;
|
|
43
52
|
}
|
|
44
53
|
export declare function buildSessionContext(entries: SessionEntry[], leafId?: string | null, byId?: Map<string, SessionEntry>, options?: BuildSessionContextOptions): SessionContext;
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Runs each subagent on the main thread and forwards AgentEvents for progress tracking.
|
|
5
5
|
*/
|
|
6
|
-
import type { AgentTelemetryConfig
|
|
6
|
+
import type { AgentTelemetryConfig } from "@oh-my-pi/pi-agent-core";
|
|
7
7
|
import type { ServiceTierByFamily } from "@oh-my-pi/pi-ai";
|
|
8
8
|
import type { Rule } from "../capability/rule.js";
|
|
9
9
|
import { ModelRegistry } from "../config/model-registry.js";
|
|
@@ -20,23 +20,27 @@ import type { MnemopiSessionState } from "../mnemopi/state.js";
|
|
|
20
20
|
import type { AgentSession } from "../session/agent-session.js";
|
|
21
21
|
import type { ArtifactManager } from "../session/artifacts.js";
|
|
22
22
|
import type { AuthStorage } from "../session/auth-storage.js";
|
|
23
|
+
import type { ConfiguredThinkingLevel } from "../thinking.js";
|
|
23
24
|
import type { ContextFileEntry } from "../tools/index.js";
|
|
24
25
|
import type { EventBus } from "../utils/event-bus.js";
|
|
25
26
|
import type { WorkspaceTree } from "../workspace-tree.js";
|
|
26
27
|
import { type AgentDefinition, type AgentProgress, type ReviewFinding, type SingleResult, type YieldItem } from "./types.js";
|
|
27
28
|
export type { YieldItem } from "./types.js";
|
|
28
29
|
/**
|
|
29
|
-
* Soft per-agent request budgets (assistant requests per run).
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* `
|
|
30
|
+
* Soft per-agent request budgets (assistant requests per run). Crossing the
|
|
31
|
+
* budget injects a wrap-up steering notice (`task.softRequestBudgetNotice`,
|
|
32
|
+
* on by default). At 1.5x the budget the free-running turn is stopped and the
|
|
33
|
+
* agent is driven to one forced final `yield` so partial findings come back
|
|
34
|
+
* as a real report; only if it still refuses to yield within
|
|
35
|
+
* {@link BUDGET_STOP_GRACE_REQUESTS} more requests is the run hard-aborted.
|
|
36
|
+
* The `default` key applies to agents without an explicit entry and can be
|
|
37
|
+
* overridden via the `task.softRequestBudget` setting (0 disables the guard).
|
|
36
38
|
*/
|
|
37
39
|
export declare const SOFT_REQUEST_BUDGET: Record<string, number>;
|
|
38
|
-
/**
|
|
39
|
-
export declare
|
|
40
|
+
/** Extra requests allowed after a budget stop for the forced yield to land before the run is hard-aborted. */
|
|
41
|
+
export declare const BUDGET_STOP_GRACE_REQUESTS = 5;
|
|
42
|
+
/** Steering notice injected when a subagent crosses its soft request budget. */
|
|
43
|
+
export declare function buildBudgetNotice(requests: number, budget: number): string;
|
|
40
44
|
/** Options for subagent execution */
|
|
41
45
|
export interface ExecutorOptions {
|
|
42
46
|
cwd: string;
|
|
@@ -55,9 +59,8 @@ export interface ExecutorOptions {
|
|
|
55
59
|
path: string;
|
|
56
60
|
content: string;
|
|
57
61
|
};
|
|
62
|
+
/** Pre-set UI label (e.g. eval bridge label). When absent, a tiny-model label is generated from the assignment. */
|
|
58
63
|
description?: string;
|
|
59
|
-
/** Specialist role/expertise for this spawn; drives the system-prompt preamble, display name, and telemetry identity. */
|
|
60
|
-
role?: string;
|
|
61
64
|
index: number;
|
|
62
65
|
id: string;
|
|
63
66
|
parentToolCallId?: string;
|
|
@@ -74,7 +77,7 @@ export interface ExecutorOptions {
|
|
|
74
77
|
* if the resolved subagent model has no working credentials. See #985.
|
|
75
78
|
*/
|
|
76
79
|
parentActiveModelPattern?: string;
|
|
77
|
-
thinkingLevel?:
|
|
80
|
+
thinkingLevel?: ConfiguredThinkingLevel;
|
|
78
81
|
outputSchema?: unknown;
|
|
79
82
|
/**
|
|
80
83
|
* Caller supplied a schema that supersedes the agent's native output prompt.
|
|
@@ -199,10 +202,20 @@ export declare function finalizeSubprocessOutput(args: FinalizeSubprocessOutputA
|
|
|
199
202
|
*/
|
|
200
203
|
export declare function createMCPProxyTools(mcpManager: MCPManager): CustomTool[];
|
|
201
204
|
export declare function createSubagentSettings(baseSettings: Settings, overrides?: Partial<Record<SettingPath, unknown>>, inheritedServiceTier?: ServiceTierByFamily | null): Settings;
|
|
205
|
+
export type AbortReason = "signal" | "terminate" | "timeout" | "budget";
|
|
206
|
+
/**
|
|
207
|
+
* Settle a subagent's registry lifecycle after a run: terminal teardown for
|
|
208
|
+
* hard aborts, unregister for one-shot helpers, park for isolated runs, and
|
|
209
|
+
* idle + lifecycle adoption for kept-alive agents. A soft-budget abort on a
|
|
210
|
+
* kept-alive, revivable agent is treated as a self-inflicted stop rather than
|
|
211
|
+
* a kill — the agent stays interrogable and resumable (irc wake / revival).
|
|
212
|
+
*/
|
|
202
213
|
export declare function finalizeSubagentLifecycle(args: {
|
|
203
214
|
id: string;
|
|
204
215
|
session: AgentSession;
|
|
205
216
|
aborted: boolean;
|
|
217
|
+
/** Which watchdog (if any) requested the abort; decides revivability. */
|
|
218
|
+
abortKind?: AbortReason;
|
|
206
219
|
keepAlive: boolean;
|
|
207
220
|
isolated: boolean;
|
|
208
221
|
agentIdleTtlMs: number;
|