@oh-my-pi/pi-coding-agent 15.11.3 → 15.11.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 +107 -0
- package/dist/cli.js +692 -607
- package/dist/types/cli/usage-cli.d.ts +10 -1
- package/dist/types/commands/usage.d.ts +9 -0
- package/dist/types/config/api-key-resolver.d.ts +9 -3
- package/dist/types/config/keybindings.d.ts +1 -1
- package/dist/types/config/model-discovery.d.ts +6 -4
- package/dist/types/config/model-registry.d.ts +7 -4
- package/dist/types/config/settings-schema.d.ts +508 -155
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/mnemopi/config.d.ts +3 -1
- package/dist/types/modes/components/reset-usage-selector.d.ts +12 -0
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/components/settings-defs.d.ts +9 -2
- package/dist/types/modes/components/settings-selector.d.ts +9 -4
- package/dist/types/modes/components/tool-execution.d.ts +26 -1
- package/dist/types/modes/components/transcript-container.d.ts +12 -0
- package/dist/types/modes/controllers/input-controller.d.ts +9 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +10 -0
- package/dist/types/modes/session-observer-registry.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +23 -3
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/utils/context-usage.d.ts +6 -1
- package/dist/types/session/agent-session.d.ts +28 -8
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/session/codex-auto-reset.d.ts +107 -0
- package/dist/types/session/snapcompact-inline.d.ts +129 -0
- package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +14 -0
- package/dist/types/slash-commands/helpers/reset-usage.d.ts +27 -0
- package/dist/types/system-prompt.d.ts +3 -1
- package/dist/types/task/render.d.ts +17 -6
- package/dist/types/tools/gh.d.ts +3 -0
- package/dist/types/tools/render-utils.d.ts +8 -16
- package/dist/types/tools/todo.d.ts +0 -11
- package/dist/types/utils/session-color.d.ts +15 -3
- package/dist/types/web/kagi.d.ts +1 -2
- package/dist/types/web/search/providers/codex.d.ts +1 -1
- package/dist/types/web/search/providers/gemini.d.ts +9 -6
- package/package.json +11 -11
- package/src/auto-thinking/classifier.ts +1 -5
- package/src/cli/usage-cli.ts +187 -16
- package/src/commands/usage.ts +8 -0
- package/src/commit/model-selection.ts +3 -6
- package/src/config/api-key-resolver.ts +10 -3
- package/src/config/keybindings.ts +1 -1
- package/src/config/model-discovery.ts +60 -46
- package/src/config/model-registry.ts +21 -8
- package/src/config/model-resolver.ts +57 -3
- package/src/config/settings-schema.ts +654 -153
- package/src/config/settings.ts +9 -0
- package/src/eval/completion-bridge.ts +1 -5
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +13 -6
- package/src/internal-urls/docs-index.generated.ts +6 -6
- package/src/internal-urls/issue-pr-protocol.ts +10 -4
- package/src/memories/index.ts +2 -10
- package/src/mnemopi/backend.ts +30 -8
- package/src/mnemopi/config.ts +6 -1
- package/src/mnemopi/state.ts +6 -0
- package/src/modes/components/extensions/inspector-panel.ts +6 -2
- package/src/modes/components/plan-review-overlay.ts +15 -17
- package/src/modes/components/plugin-settings.ts +22 -5
- package/src/modes/components/reset-usage-selector.ts +161 -0
- package/src/modes/components/session-selector.ts +8 -2
- package/src/modes/components/settings-defs.ts +19 -4
- package/src/modes/components/settings-selector.ts +510 -95
- package/src/modes/components/status-line/component.ts +3 -1
- package/src/modes/components/status-line/segments.ts +3 -1
- package/src/modes/components/tool-execution.ts +87 -12
- package/src/modes/components/transcript-container.ts +49 -1
- package/src/modes/components/tree-selector.ts +16 -6
- package/src/modes/controllers/command-controller.ts +61 -8
- package/src/modes/controllers/event-controller.ts +1 -0
- package/src/modes/controllers/input-controller.ts +68 -6
- package/src/modes/controllers/selector-controller.ts +149 -61
- package/src/modes/interactive-mode.ts +63 -2
- package/src/modes/rpc/rpc-mode.ts +2 -1
- package/src/modes/session-observer-registry.ts +61 -3
- package/src/modes/shared.ts +2 -0
- package/src/modes/theme/theme.ts +102 -9
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/context-usage.ts +78 -2
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/utils/ui-helpers.ts +9 -5
- package/src/prompts/system/personalities/default.md +26 -0
- package/src/prompts/system/personalities/friendly.md +17 -0
- package/src/prompts/system/personalities/pragmatic.md +15 -0
- package/src/prompts/system/snapcompact-context-frames-note.md +1 -0
- package/src/prompts/system/snapcompact-context-stub.md +1 -0
- package/src/prompts/system/snapcompact-system-frames-note.md +1 -0
- package/src/prompts/system/snapcompact-system-stub.md +1 -0
- package/src/prompts/system/snapcompact-toolresult-note.md +1 -0
- package/src/prompts/system/system-prompt.md +5 -22
- package/src/prompts/tools/browser.md +33 -43
- package/src/prompts/tools/eval.md +27 -50
- package/src/prompts/tools/irc.md +29 -31
- package/src/prompts/tools/read.md +31 -37
- package/src/prompts/tools/task.md +3 -3
- package/src/prompts/tools/todo.md +1 -2
- package/src/sdk.ts +23 -1
- package/src/session/agent-session.ts +221 -29
- package/src/session/auth-storage.ts +4 -0
- package/src/session/codex-auto-reset.ts +190 -0
- package/src/session/session-dump-format.ts +8 -1
- package/src/session/session-manager.ts +5 -5
- package/src/session/snapcompact-inline.ts +524 -0
- package/src/slash-commands/builtin-registry.ts +145 -8
- package/src/slash-commands/helpers/active-oauth-account.ts +44 -0
- package/src/slash-commands/helpers/context-report.ts +28 -1
- package/src/slash-commands/helpers/reset-usage.ts +66 -0
- package/src/slash-commands/helpers/usage-report.ts +36 -3
- package/src/system-prompt.ts +15 -1
- package/src/task/index.ts +30 -7
- package/src/task/render.ts +57 -32
- package/src/tool-discovery/tool-index.ts +2 -0
- package/src/tools/bash.ts +10 -3
- package/src/tools/eval-render.ts +13 -8
- package/src/tools/gh.ts +39 -1
- package/src/tools/image-gen.ts +114 -78
- package/src/tools/inspect-image.ts +1 -5
- package/src/tools/job.ts +25 -5
- package/src/tools/read.ts +1 -57
- package/src/tools/render-utils.ts +29 -31
- package/src/tools/ssh.ts +3 -3
- package/src/tools/todo.ts +8 -128
- package/src/tools/tts.ts +40 -20
- package/src/utils/clipboard.ts +56 -4
- package/src/utils/commit-message-generator.ts +1 -5
- package/src/utils/session-color.ts +83 -9
- package/src/utils/title-generator.ts +1 -1
- package/src/web/kagi.ts +26 -27
- package/src/web/search/providers/codex.ts +42 -40
- package/src/web/search/providers/gemini.ts +42 -22
- package/src/web/search/providers/perplexity.ts +22 -10
|
@@ -2,7 +2,7 @@ import type { MnemopiOptions } from "@oh-my-pi/pi-mnemopi";
|
|
|
2
2
|
import type { Settings } from "../config/settings";
|
|
3
3
|
export type MnemopiLlmMode = "none" | "smol" | "remote";
|
|
4
4
|
export type MnemopiScoping = "global" | "per-project" | "per-project-tagged";
|
|
5
|
-
export type MnemopiProviderOptions = Pick<MnemopiOptions, "noEmbeddings" | "embeddingModel" | "embeddingApiUrl" | "embeddingApiKey" | "llm">;
|
|
5
|
+
export type MnemopiProviderOptions = Pick<MnemopiOptions, "noEmbeddings" | "embeddingModel" | "embeddingApiUrl" | "embeddingApiKey" | "llm" | "debug">;
|
|
6
6
|
export interface MnemopiBackendConfig {
|
|
7
7
|
dbPath: string;
|
|
8
8
|
baseBank?: string;
|
|
@@ -13,6 +13,8 @@ export interface MnemopiBackendConfig {
|
|
|
13
13
|
scoping?: MnemopiScoping;
|
|
14
14
|
autoRecall: boolean;
|
|
15
15
|
autoRetain: boolean;
|
|
16
|
+
polyphonicRecall: boolean;
|
|
17
|
+
enhancedRecall: boolean;
|
|
16
18
|
retainEveryNTurns: number;
|
|
17
19
|
recallLimit: number;
|
|
18
20
|
recallContextTurns: number;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Container } from "@oh-my-pi/pi-tui";
|
|
2
|
+
import type { ResetUsageAccount } from "../../slash-commands/helpers/reset-usage";
|
|
3
|
+
/**
|
|
4
|
+
* Account picker for `/usage reset`. Lists Codex accounts with their saved
|
|
5
|
+
* rate-limit reset counts; selecting one redeems a reset. Because a reset is a
|
|
6
|
+
* scarce, irreversible credit, Enter requires a second press to confirm.
|
|
7
|
+
*/
|
|
8
|
+
export declare class ResetUsageSelectorComponent extends Container {
|
|
9
|
+
#private;
|
|
10
|
+
constructor(accounts: ResetUsageAccount[], onSelect: (account: ResetUsageAccount) => void, onCancel: () => void);
|
|
11
|
+
handleInput(keyData: string): void;
|
|
12
|
+
}
|
|
@@ -8,7 +8,7 @@ export type SessionHistoryMatcher = (query: string) => string[];
|
|
|
8
8
|
* Resume search narrows a recency-sorted list: once every query token appears
|
|
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
|
-
* literal matches.
|
|
11
|
+
* literal matches, but weak pure fuzzy tokens are dropped as noise.
|
|
12
12
|
*/
|
|
13
13
|
export declare function rankSessionSearchMatches(allSessions: SessionInfo[], query: string): SessionInfo[];
|
|
14
14
|
/**
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
* settings selector.
|
|
5
5
|
*
|
|
6
6
|
* To add a new setting to the UI: declare it in `settings-schema.ts`
|
|
7
|
-
* with a `ui` block
|
|
7
|
+
* with a `ui` block carrying `tab` and `group` (the group must be listed
|
|
8
|
+
* in `TAB_GROUPS[tab]`). If it needs a submenu, include `options: [...]`
|
|
8
9
|
* (or `options: "runtime"` for runtime-injected lists like themes).
|
|
9
10
|
*/
|
|
10
11
|
import { type SettingPath, type SettingTab, type SubmenuOption } from "../../config/settings-schema";
|
|
@@ -14,6 +15,8 @@ interface BaseSettingDef {
|
|
|
14
15
|
label: string;
|
|
15
16
|
description: string;
|
|
16
17
|
tab: SettingTab;
|
|
18
|
+
/** Section within the tab; items are ordered by TAB_GROUPS[tab] and rendered under a heading row. */
|
|
19
|
+
group?: string;
|
|
17
20
|
/**
|
|
18
21
|
* Optional visibility predicate. When supplied and returning false, the
|
|
19
22
|
* setting is hidden from the UI. Applies to every variant — booleans,
|
|
@@ -41,7 +44,11 @@ export interface TextInputSettingDef extends BaseSettingDef {
|
|
|
41
44
|
export type SettingDef = BooleanSettingDef | EnumSettingDef | SubmenuSettingDef | TextInputSettingDef;
|
|
42
45
|
/** Get all setting definitions with UI */
|
|
43
46
|
export declare function getAllSettingDefs(): SettingDef[];
|
|
44
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Get settings for a specific tab, ordered by the tab's group layout
|
|
49
|
+
* (TAB_GROUPS). Ungrouped settings sort first; within a group, schema
|
|
50
|
+
* declaration order is preserved.
|
|
51
|
+
*/
|
|
45
52
|
export declare function getSettingsForTab(tab: SettingTab): SettingDef[];
|
|
46
53
|
/** Get a setting definition by path */
|
|
47
54
|
export declare function getSettingDef(path: SettingPath): SettingDef | undefined;
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Effort } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import {
|
|
3
|
+
import { type Component } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { type SettingPath } from "../../config/settings";
|
|
5
5
|
import type { StatusLinePreset, StatusLineSegmentId, StatusLineSeparatorStyle } from "../../config/settings-schema";
|
|
6
|
-
import { PluginSettingsComponent } from "./plugin-settings";
|
|
7
6
|
/**
|
|
8
7
|
* Dynamic context for settings that need runtime data.
|
|
9
8
|
* Some settings (like thinking level) are managed by the session, not Settings.
|
|
@@ -45,11 +44,17 @@ export interface SettingsCallbacks {
|
|
|
45
44
|
* Main tabbed settings selector component.
|
|
46
45
|
* Uses declarative settings definitions from settings-defs.ts.
|
|
47
46
|
*/
|
|
48
|
-
export declare class SettingsSelectorComponent
|
|
47
|
+
export declare class SettingsSelectorComponent implements Component {
|
|
49
48
|
#private;
|
|
50
49
|
private readonly context;
|
|
51
50
|
private readonly callbacks;
|
|
52
51
|
constructor(context: SettingsRuntimeContext, callbacks: SettingsCallbacks);
|
|
53
|
-
|
|
52
|
+
invalidate(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Fullscreen frame: title border, tab row, divider, optional search banner,
|
|
55
|
+
* the active content sized to fill the terminal, the appearance preview,
|
|
56
|
+
* then a footer hint pinned above the bottom border.
|
|
57
|
+
*/
|
|
58
|
+
render(width: number): readonly string[];
|
|
54
59
|
handleInput(data: string): void;
|
|
55
60
|
}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
1
|
import type { SnapshotStore } from "@oh-my-pi/hashline";
|
|
2
2
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
3
|
-
import { Container, type TUI } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { type Component, Container, type TUI } from "@oh-my-pi/pi-tui";
|
|
4
|
+
/**
|
|
5
|
+
* Transcript-side probe telling a block whether it is still inside the live
|
|
6
|
+
* (repaintable) region. Implemented by `TranscriptContainer`; injected rather
|
|
7
|
+
* than imported so the component stays decoupled from the transcript.
|
|
8
|
+
*/
|
|
9
|
+
export interface TranscriptLiveRegionProbe {
|
|
10
|
+
isBlockInLiveRegion(component: Component): boolean;
|
|
11
|
+
}
|
|
4
12
|
export interface ToolExecutionOptions {
|
|
5
13
|
snapshots?: SnapshotStore;
|
|
6
14
|
showImages?: boolean;
|
|
7
15
|
editFuzzyThreshold?: number;
|
|
8
16
|
editAllowFuzzy?: boolean;
|
|
17
|
+
/** Live-region probe used to settle detached task progress once the block
|
|
18
|
+
* leaves the repaintable transcript region. */
|
|
19
|
+
liveRegion?: TranscriptLiveRegionProbe;
|
|
9
20
|
}
|
|
10
21
|
export interface ToolExecutionHandle {
|
|
11
22
|
updateArgs(args: any, toolCallId?: string): void;
|
|
@@ -61,6 +72,20 @@ export declare class ToolExecutionComponent extends Container {
|
|
|
61
72
|
* past, or an explicit {@link seal} flips it to `true`.
|
|
62
73
|
*/
|
|
63
74
|
isTranscriptBlockFinalized(): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Whether this still-live block's settled rows may enter native scrollback
|
|
77
|
+
* (see `FinalizableBlock.isTranscriptBlockCommitStable`). A pending
|
|
78
|
+
* collapsed preview is provisional: the tail-window streaming views
|
|
79
|
+
* (edit/bash/eval caps) are re-anchored top-first by the result render, so
|
|
80
|
+
* promoting their visually static head — e.g. an edit preview idling on
|
|
81
|
+
* its last frame while the apply + LSP pass runs — would strand a stale
|
|
82
|
+
* copy of the call box above the final block the moment the result lands.
|
|
83
|
+
* Expanded pending blocks stream top-anchored append-shaped content whose
|
|
84
|
+
* rows the result render preserves byte-stable (the over-tall write/eval
|
|
85
|
+
* scrollback contract), so they stay commit-eligible. Displaceable waiting
|
|
86
|
+
* polls are removed wholesale by the next poll and must never commit.
|
|
87
|
+
*/
|
|
88
|
+
isTranscriptBlockCommitStable(): boolean;
|
|
64
89
|
/**
|
|
65
90
|
* Mark the tool terminal even though no result arrived (the turn aborted or
|
|
66
91
|
* abandoned it) and stop animating, so it can freeze and stops pinning the
|
|
@@ -40,6 +40,18 @@ export declare class TranscriptContainer extends Container implements NativeScro
|
|
|
40
40
|
* only repair by recommitting everything below it — duplication.
|
|
41
41
|
*/
|
|
42
42
|
isWithinLiveRegion(component: Component): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Whether `component` is inside the live (repaintable) region exactly as
|
|
45
|
+
* {@link render} computes it: at/after the first still-mutating block, or
|
|
46
|
+
* the transcript tail when every block has finalized. Unlike
|
|
47
|
+
* {@link isWithinLiveRegion} (strictly below a still-mutating block, i.e.
|
|
48
|
+
* guaranteed-uncommitted), this also counts the trailing block that anchors
|
|
49
|
+
* the live region. Self-animating finalized blocks (a detached task's
|
|
50
|
+
* shimmering progress rows) poll this to stop animating — and settle on
|
|
51
|
+
* static bytes — the moment they sit above the seam, where their rows
|
|
52
|
+
* become commit-eligible native-scrollback history.
|
|
53
|
+
*/
|
|
54
|
+
isBlockInLiveRegion(component: Component): boolean;
|
|
43
55
|
render(width: number): readonly string[];
|
|
44
56
|
}
|
|
45
57
|
/**
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import type { AutocompleteProvider, SlashCommand } from "@oh-my-pi/pi-tui";
|
|
2
2
|
import type { InteractiveModeContext } from "../../modes/types";
|
|
3
|
+
import { readImageFromClipboard, readTextFromClipboard } from "../../utils/clipboard";
|
|
3
4
|
export declare class InputController {
|
|
4
5
|
#private;
|
|
5
6
|
private ctx;
|
|
6
|
-
|
|
7
|
+
/** Injectable clipboard reads so tests can drive paste flows without a real clipboard. */
|
|
8
|
+
private clipboard;
|
|
9
|
+
constructor(ctx: InteractiveModeContext,
|
|
10
|
+
/** Injectable clipboard reads so tests can drive paste flows without a real clipboard. */
|
|
11
|
+
clipboard?: {
|
|
12
|
+
readImage: typeof readImageFromClipboard;
|
|
13
|
+
readText: typeof readTextFromClipboard;
|
|
14
|
+
});
|
|
7
15
|
setupKeyHandlers(): void;
|
|
8
16
|
setupEditorSubmitHandler(): void;
|
|
9
17
|
handleCtrlC(): void;
|
|
@@ -41,6 +41,7 @@ export declare class SelectorController {
|
|
|
41
41
|
handleResumeSession(sessionPath: string): Promise<void>;
|
|
42
42
|
handleSessionDeleteCommand(): Promise<void>;
|
|
43
43
|
showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
|
|
44
|
+
showResetUsageSelector(): Promise<void>;
|
|
44
45
|
showDebugSelector(): Promise<void>;
|
|
45
46
|
showAgentHub(observers: SessionObserverRegistry): void;
|
|
46
47
|
}
|
|
@@ -27,6 +27,7 @@ import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
|
27
27
|
import { TranscriptContainer } from "./components/transcript-container";
|
|
28
28
|
import { type LoopLimitRuntime } from "./loop-limit";
|
|
29
29
|
import { OAuthManualInputManager } from "./oauth-manual-input";
|
|
30
|
+
import type { ObservableSession } from "./session-observer-registry";
|
|
30
31
|
import type { Theme } from "./theme/theme";
|
|
31
32
|
import type { CompactionQueuedMessage, InteractiveModeContext, InteractiveModeInitOptions, InteractiveSelectorDialogOptions, SubmittedUserInput, TodoItem, TodoPhase } from "./types";
|
|
32
33
|
/** Options for creating an InteractiveMode instance (for future API use) */
|
|
@@ -42,6 +43,13 @@ export interface InteractiveModeOptions {
|
|
|
42
43
|
/** Additional initial messages to queue */
|
|
43
44
|
initialMessages?: string[];
|
|
44
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Build the anchored subagent HUD block: a bold accent "Subagents" header plus
|
|
48
|
+
* one hooked row per running agent in the same `Id: description` shape the
|
|
49
|
+
* inline task rows use (muted task preview when no description was given).
|
|
50
|
+
* Returns an empty array when nothing is running so the container can clear.
|
|
51
|
+
*/
|
|
52
|
+
export declare function renderSubagentHudLines(sessions: ObservableSession[], columns: number): string[];
|
|
45
53
|
export declare class InteractiveMode implements InteractiveModeContext {
|
|
46
54
|
#private;
|
|
47
55
|
session: AgentSession;
|
|
@@ -56,6 +64,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
56
64
|
pendingMessagesContainer: Container;
|
|
57
65
|
statusContainer: Container;
|
|
58
66
|
todoContainer: Container;
|
|
67
|
+
subagentContainer: Container;
|
|
59
68
|
btwContainer: Container;
|
|
60
69
|
omfgContainer: Container;
|
|
61
70
|
errorBannerContainer: Container;
|
|
@@ -265,6 +274,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
265
274
|
handleResumeSession(sessionPath: string): Promise<void>;
|
|
266
275
|
handleSessionDeleteCommand(): Promise<void>;
|
|
267
276
|
showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
|
|
277
|
+
showResetUsageSelector(): Promise<void>;
|
|
268
278
|
showProviderSetup(): Promise<void>;
|
|
269
279
|
showHookConfirm(title: string, message: string): Promise<boolean>;
|
|
270
280
|
handleCtrlC(): void;
|
|
@@ -8,6 +8,8 @@ export interface ObservableSession {
|
|
|
8
8
|
description?: string;
|
|
9
9
|
status: "active" | "completed" | "failed" | "aborted";
|
|
10
10
|
sessionFile?: string;
|
|
11
|
+
parentToolCallId?: string;
|
|
12
|
+
index?: number;
|
|
11
13
|
lastUpdate: number;
|
|
12
14
|
/** Latest progress snapshot from the subagent executor */
|
|
13
15
|
progress?: AgentProgress;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Effort } from "@oh-my-pi/pi-ai";
|
|
3
|
-
import type { EditorTheme, MarkdownTheme, SelectListTheme, SymbolTheme } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import type { EditorTheme, MarkdownTheme, SelectListTheme, SettingsListTheme, SymbolTheme } from "@oh-my-pi/pi-tui";
|
|
4
4
|
export { getLanguageFromPath } from "../../utils/lang-from-path";
|
|
5
5
|
export type SymbolPreset = "unicode" | "nerd" | "ascii";
|
|
6
6
|
/**
|
|
7
7
|
* All available symbol keys organized by category.
|
|
8
8
|
*/
|
|
9
|
-
export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.agents" | "icon.job" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.
|
|
9
|
+
export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.agents" | "icon.job" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.files" | "tab.shell" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.inspectImage" | "tool.goal" | "tool.irc";
|
|
10
10
|
export type SpinnerType = "status" | "activity";
|
|
11
11
|
export type ThemeColor = "accent" | "border" | "borderAccent" | "borderMuted" | "success" | "error" | "warning" | "muted" | "dim" | "text" | "thinkingText" | "userMessageText" | "customMessageText" | "customMessageLabel" | "toolTitle" | "toolOutput" | "mdHeading" | "mdLink" | "mdLinkUrl" | "mdCode" | "mdCodeBlock" | "mdCodeBlockBorder" | "mdQuote" | "mdQuoteBorder" | "mdHr" | "mdListBullet" | "toolDiffAdded" | "toolDiffRemoved" | "toolDiffContext" | "syntaxComment" | "syntaxKeyword" | "syntaxFunction" | "syntaxVariable" | "syntaxString" | "syntaxNumber" | "syntaxType" | "syntaxOperator" | "syntaxPunctuation" | "thinkingOff" | "thinkingMinimal" | "thinkingLow" | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" | "bashMode" | "pythonMode" | "statusLineSep" | "statusLineModel" | "statusLinePath" | "statusLineGitClean" | "statusLineGitDirty" | "statusLineContext" | "statusLineSpend" | "statusLineStaged" | "statusLineDirty" | "statusLineUntracked" | "statusLineOutput" | "statusLineCost" | "statusLineSubagents";
|
|
12
12
|
/** Check if a string is a valid ThemeColor value */
|
|
@@ -33,6 +33,26 @@ export declare class Theme {
|
|
|
33
33
|
* dark themes so accents stay vivid. Pass straight to `getSessionAccentHex`.
|
|
34
34
|
*/
|
|
35
35
|
get accentSurfaceLuminance(): number | undefined;
|
|
36
|
+
/**
|
|
37
|
+
* Get the resolved CSS hex string for a foreground theme color.
|
|
38
|
+
*/
|
|
39
|
+
getColorHex(color: ThemeColor): string;
|
|
40
|
+
/**
|
|
41
|
+
* Get all foreground and background theme colors as CSS hex strings.
|
|
42
|
+
* Skips colors resolved to the default terminal color (unstyled).
|
|
43
|
+
*/
|
|
44
|
+
getAllThemeColorHexes(): string[];
|
|
45
|
+
/**
|
|
46
|
+
* Get the most visually dominant theme colors as CSS hex strings — accent,
|
|
47
|
+
* border, success, error, warning, heading, link, diff markers, etc.
|
|
48
|
+
* These are the colors the session accent could visually clash with.
|
|
49
|
+
* Skips colors resolved to the default terminal color (unstyled).
|
|
50
|
+
*/
|
|
51
|
+
getMajorThemeColorHexes(): string[];
|
|
52
|
+
/**
|
|
53
|
+
* Get the resolved CSS hex string for the theme's accent color.
|
|
54
|
+
*/
|
|
55
|
+
getAccentColorHex(): string;
|
|
36
56
|
fg(color: ThemeColor, text: string): string;
|
|
37
57
|
bg(color: ThemeBg, text: string): string;
|
|
38
58
|
bold(text: string): string;
|
|
@@ -305,4 +325,4 @@ export declare function getSymbolTheme(): SymbolTheme;
|
|
|
305
325
|
export declare function getMarkdownTheme(): MarkdownTheme;
|
|
306
326
|
export declare function getSelectListTheme(): SelectListTheme;
|
|
307
327
|
export declare function getEditorTheme(): EditorTheme;
|
|
308
|
-
export declare function getSettingsListTheme():
|
|
328
|
+
export declare function getSettingsListTheme(): SettingsListTheme;
|
|
@@ -66,6 +66,7 @@ export interface InteractiveModeContext {
|
|
|
66
66
|
pendingMessagesContainer: Container;
|
|
67
67
|
statusContainer: Container;
|
|
68
68
|
todoContainer: Container;
|
|
69
|
+
subagentContainer: Container;
|
|
69
70
|
btwContainer: Container;
|
|
70
71
|
omfgContainer: Container;
|
|
71
72
|
errorBannerContainer: Container;
|
|
@@ -264,6 +265,7 @@ export interface InteractiveModeContext {
|
|
|
264
265
|
handleResumeSession(sessionPath: string): Promise<void>;
|
|
265
266
|
handleSessionDeleteCommand(): Promise<void>;
|
|
266
267
|
showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
|
|
268
|
+
showResetUsageSelector(): Promise<void>;
|
|
267
269
|
showProviderSetup(): Promise<void>;
|
|
268
270
|
showHookConfirm(title: string, message: string): Promise<boolean>;
|
|
269
271
|
showDebugSelector(): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Model } from "@oh-my-pi/pi-ai";
|
|
2
2
|
import type { Skill } from "../../extensibility/skills";
|
|
3
3
|
import type { AgentSession } from "../../session/agent-session";
|
|
4
|
+
import { type SnapcompactSavingsEstimate } from "../../session/snapcompact-inline";
|
|
4
5
|
import type { Tool } from "../../tools";
|
|
5
6
|
import type { theme as Theme } from "../theme/theme";
|
|
6
7
|
type CategoryId = "systemPrompt" | "systemContext" | "systemTools" | "skills" | "messages";
|
|
@@ -18,6 +19,8 @@ export interface ContextBreakdown {
|
|
|
18
19
|
usedTokens: number;
|
|
19
20
|
autoCompactBufferTokens: number;
|
|
20
21
|
freeTokens: number;
|
|
22
|
+
/** Estimated snapcompact wire savings; set when requested and a snapcompact.* setting is enabled. */
|
|
23
|
+
snapcompact?: SnapcompactSavingsEstimate;
|
|
21
24
|
}
|
|
22
25
|
export declare function estimateSkillsTokens(skills: readonly Skill[]): number;
|
|
23
26
|
export declare function estimateToolSchemaTokens(tools: ReadonlyArray<Pick<Tool, "name" | "description" | "parameters">>): number;
|
|
@@ -38,7 +41,9 @@ export declare function computeNonMessageTokens(session: AgentSession): number;
|
|
|
38
41
|
* Compute a breakdown of estimated context usage by category for the active
|
|
39
42
|
* session and model.
|
|
40
43
|
*/
|
|
41
|
-
export declare function computeContextBreakdown(session: AgentSession
|
|
44
|
+
export declare function computeContextBreakdown(session: AgentSession, options?: {
|
|
45
|
+
snapcompactSavings?: boolean;
|
|
46
|
+
}): ContextBreakdown;
|
|
42
47
|
/**
|
|
43
48
|
* Render a colorful context-usage panel as ANSI text. Output is a series of
|
|
44
49
|
* lines pairing the grid (left) with the legend (right).
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
|
|
16
16
|
import { type Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
17
17
|
import { type CompactionResult, type ShakeConfig } from "@oh-my-pi/pi-agent-core/compaction";
|
|
18
|
-
import type { AssistantMessage, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
|
|
18
|
+
import type { AssistantMessage, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
|
|
19
19
|
import { Effort } from "@oh-my-pi/pi-ai";
|
|
20
20
|
import { type AsyncJob, type AsyncJobDeliveryState, AsyncJobManager } from "../async";
|
|
21
21
|
import type { Rule } from "../capability/rule";
|
|
@@ -300,6 +300,11 @@ export interface FreshSessionResult {
|
|
|
300
300
|
sessionId: string;
|
|
301
301
|
closedProviderSessions: number;
|
|
302
302
|
}
|
|
303
|
+
/** Entry returned by {@link AgentSession.clearQueue} / {@link AgentSession.popLastQueuedMessage}. */
|
|
304
|
+
export type RestoredQueuedMessage = {
|
|
305
|
+
text: string;
|
|
306
|
+
images?: ImageContent[];
|
|
307
|
+
};
|
|
303
308
|
export declare class AgentSession {
|
|
304
309
|
#private;
|
|
305
310
|
readonly agent: Agent;
|
|
@@ -610,12 +615,14 @@ export declare class AgentSession {
|
|
|
610
615
|
deliverAs?: "steer" | "followUp";
|
|
611
616
|
}): Promise<void>;
|
|
612
617
|
/**
|
|
613
|
-
* Clear queued messages and return them.
|
|
614
|
-
* Useful for restoring to editor when user aborts.
|
|
618
|
+
* Clear queued messages and return them (text plus any attached images).
|
|
619
|
+
* Useful for restoring to editor when user aborts. The internal entry
|
|
620
|
+
* arrays are handed out as-is — a `tag` (if any) is inert once the record
|
|
621
|
+
* leaves the queue.
|
|
615
622
|
*/
|
|
616
623
|
clearQueue(): {
|
|
617
|
-
steering:
|
|
618
|
-
followUp:
|
|
624
|
+
steering: RestoredQueuedMessage[];
|
|
625
|
+
followUp: RestoredQueuedMessage[];
|
|
619
626
|
};
|
|
620
627
|
/** Number of pending messages (includes steering, follow-up, and next-turn messages) */
|
|
621
628
|
get queuedMessageCount(): number;
|
|
@@ -630,10 +637,10 @@ export declare class AgentSession {
|
|
|
630
637
|
/**
|
|
631
638
|
* Pop the last queued message (steering first, then follow-up).
|
|
632
639
|
* Used by dequeue keybinding to restore messages to editor one at a time.
|
|
633
|
-
* Returns the popped entry's
|
|
634
|
-
* record — no orphan state can outlive the queue entry.
|
|
640
|
+
* Returns the popped entry's text and images; the tag (if any) dies with
|
|
641
|
+
* the record — no orphan state can outlive the queue entry.
|
|
635
642
|
*/
|
|
636
|
-
popLastQueuedMessage():
|
|
643
|
+
popLastQueuedMessage(): RestoredQueuedMessage | undefined;
|
|
637
644
|
get skillsSettings(): SkillsSettings | undefined;
|
|
638
645
|
/** Skills loaded by SDK (empty if --no-skills or skills: [] was passed) */
|
|
639
646
|
get skills(): readonly Skill[];
|
|
@@ -1045,6 +1052,19 @@ export declare class AgentSession {
|
|
|
1045
1052
|
contextWindow?: number;
|
|
1046
1053
|
}): ContextUsage | undefined;
|
|
1047
1054
|
fetchUsageReports(signal?: AbortSignal): Promise<UsageReport[] | null>;
|
|
1055
|
+
/**
|
|
1056
|
+
* Redeem one saved Codex rate-limit reset for a specific account, injecting
|
|
1057
|
+
* the provider base URL like {@link AgentSession.fetchUsageReports}. Powers
|
|
1058
|
+
* the `/usage reset` command and auto-redeem. Never throws for business
|
|
1059
|
+
* outcomes — inspect the returned `code`.
|
|
1060
|
+
*/
|
|
1061
|
+
redeemResetCredit(target: ResetCreditTarget, signal?: AbortSignal): Promise<ResetCreditRedeemOutcome>;
|
|
1062
|
+
/**
|
|
1063
|
+
* List saved Codex rate-limit resets per stored account, fetched live from
|
|
1064
|
+
* the dedicated credits endpoint (bypasses the usage cache). Powers the
|
|
1065
|
+
* `/usage reset` account selector.
|
|
1066
|
+
*/
|
|
1067
|
+
listResetCredits(signal?: AbortSignal): Promise<ResetCreditAccountStatus[]>;
|
|
1048
1068
|
/**
|
|
1049
1069
|
* Export session to HTML.
|
|
1050
1070
|
* @param outputPath Optional output path (defaults to session directory)
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Re-exports from @oh-my-pi/pi-ai.
|
|
3
3
|
* All credential storage types and the AuthStorage class now live in the ai package.
|
|
4
4
|
*/
|
|
5
|
-
export type { ApiKeyCredential, AuthCredential, AuthCredentialEntry, AuthCredentialStore, AuthStorageData, AuthStorageOptions, CredentialOrigin, CredentialOriginKind, OAuthCredential, SerializedAuthStorage, SnapshotResponse, StoredAuthCredential, } from "@oh-my-pi/pi-ai";
|
|
5
|
+
export type { ApiKeyCredential, AuthCredential, AuthCredentialEntry, AuthCredentialStore, AuthStorageData, AuthStorageOptions, CredentialOrigin, CredentialOriginKind, OAuthAccountIdentity, OAuthCredential, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, SerializedAuthStorage, SnapshotResponse, StoredAuthCredential, } from "@oh-my-pi/pi-ai";
|
|
6
6
|
export { AuthBrokerClient, AuthStorage, DEFAULT_SNAPSHOT_CACHE_TTL_MS, REMOTE_REFRESH_SENTINEL, RemoteAuthCredentialStore, readAuthBrokerSnapshotCache, SqliteAuthCredentialStore, writeAuthBrokerSnapshotCache, } from "@oh-my-pi/pi-ai";
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure decision predicate for auto-redeeming a saved OpenAI Codex rate-limit
|
|
3
|
+
* reset, plus the process-wide coordinator that serializes attempts.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS IS REACTIVE-ONLY (never proactive):
|
|
6
|
+
* The only trustworthy "blocked right now" signal is a live 429 /
|
|
7
|
+
* `usage_limit_reached` from a request authenticated as the session's active
|
|
8
|
+
* Codex credential. The session hook calls this predicate from the usage-limit
|
|
9
|
+
* branch of the retry pipeline, *after* free remedies (sibling-account switch)
|
|
10
|
+
* fail and *before* model fallback. A proactive surface (the status-line usage
|
|
11
|
+
* poll) cannot be used: at `used_percent < 100` the account is not actually
|
|
12
|
+
* limited, so redeeming would be a credit-wasting no-op; at exactly 100 the
|
|
13
|
+
* user may be idle, so the freshly-reset weekly window would tick away with
|
|
14
|
+
* nobody working. Saved resets are a scarce, ~monthly, effectively
|
|
15
|
+
* irreversible resource — every gate here is biased to precision over recall:
|
|
16
|
+
* we would rather miss a redeem than waste a credit.
|
|
17
|
+
*
|
|
18
|
+
* THE DECISION-2 TRAP (status MUST NOT be used to find the blocker):
|
|
19
|
+
* `openai-codex.ts` applies the top-level `rate_limit.limit_reached` flag to
|
|
20
|
+
* BOTH the primary (5h) and secondary (weekly) `buildUsageLimit` calls, so when
|
|
21
|
+
* an account is blocked, *both* limit entries carry `status: "exhausted"`
|
|
22
|
+
* regardless of which window is actually at 100%. Only `amount.usedFraction`
|
|
23
|
+
* disambiguates which window is the real blocker. This module therefore keys
|
|
24
|
+
* eligibility off exact limit ids (`openai-codex:primary` /
|
|
25
|
+
* `openai-codex:secondary`) and `usedFraction`, never off `status`.
|
|
26
|
+
*
|
|
27
|
+
* ANTI-WASTE GATES (in evaluation order): the policy must be OFF unless opted
|
|
28
|
+
* in; the active model must be Codex (not Spark — a Spark block lives on a
|
|
29
|
+
* separate meter and it is unknown whether a credit even resets it); a fresh
|
|
30
|
+
* usage report for the active account must confirm `limitReached`; the WEEKLY
|
|
31
|
+
* (secondary) window must be genuinely exhausted — a 5h-only block self-heals
|
|
32
|
+
* within the hour, so a credit spent there buys nothing; the natural reset must be far
|
|
33
|
+
* enough away to justify spending a ~30-day credit yet within one plausible
|
|
34
|
+
* window length; a credit must be verifiably available above the reserve; and
|
|
35
|
+
* the same block episode must not have been attempted already (debounce +
|
|
36
|
+
* per-account cooldown). All of this is pure — no fetches, no IO. The only
|
|
37
|
+
* stateful piece is the {@link CodexAutoRedeemCoordinator} container, whose
|
|
38
|
+
* read-only views are passed in so the predicate itself stays deterministic.
|
|
39
|
+
*/
|
|
40
|
+
import type { OAuthAccountIdentity, ResetCreditTarget, UsageReport } from "@oh-my-pi/pi-ai";
|
|
41
|
+
/** Weekly window counts as exhausted at `usedFraction >= 0.999` (used_percent >= 99.9). */
|
|
42
|
+
export declare const WEEKLY_EXHAUSTED_MIN_FRACTION = 0.999;
|
|
43
|
+
/** A weekly reset can never be more than one window length (7d) away; +1h slack for skew. */
|
|
44
|
+
export declare const MAX_PLAUSIBLE_REMAINING_MS: number;
|
|
45
|
+
/** Report must be no older than the 5-min usage cache TTL plus slack. */
|
|
46
|
+
export declare const REPORT_FRESHNESS_MS: number;
|
|
47
|
+
/** Per-account cooldown that catches blockKey drift across a minute boundary. */
|
|
48
|
+
export declare const ATTEMPT_COOLDOWN_MS = 60000;
|
|
49
|
+
/** Minute bucket for blockKey, absorbing `reset_after_seconds`-derived jitter. */
|
|
50
|
+
export declare const DEBOUNCE_BUCKET_MS = 60000;
|
|
51
|
+
export type CodexAutoRedeemSkipReason = "disabled" | "wrong-provider" | "spark-model" | "no-identity" | "no-report" | "stale-report" | "not-limit-reached" | "weekly-not-exhausted" | "no-reset-time" | "reset-too-soon" | "reset-implausible" | "credits-unknown" | "reserve" | "already-attempted" | "cooldown";
|
|
52
|
+
export interface CodexAutoRedeemInput {
|
|
53
|
+
nowMs: number;
|
|
54
|
+
/** `this.model.provider`. */
|
|
55
|
+
provider: string;
|
|
56
|
+
/** `this.model.id`. */
|
|
57
|
+
modelId: string;
|
|
58
|
+
settings: {
|
|
59
|
+
autoRedeem: boolean;
|
|
60
|
+
minBlockedMinutes: number;
|
|
61
|
+
keepCredits: number;
|
|
62
|
+
};
|
|
63
|
+
/** `getOAuthAccountIdentity("openai-codex", sessionId)`, captured at hook entry before any await. */
|
|
64
|
+
identity: OAuthAccountIdentity | undefined;
|
|
65
|
+
/** `session.fetchUsageReports()` (≤5-min cache). */
|
|
66
|
+
reports: UsageReport[] | null;
|
|
67
|
+
attemptedBlockKeys: ReadonlySet<string>;
|
|
68
|
+
lastAttemptAtByAccount: ReadonlyMap<string, number>;
|
|
69
|
+
}
|
|
70
|
+
export type CodexAutoRedeemDecision = {
|
|
71
|
+
redeem: true;
|
|
72
|
+
target: ResetCreditTarget;
|
|
73
|
+
accountKey: string;
|
|
74
|
+
blockKey: string;
|
|
75
|
+
weeklyResetAtMs: number;
|
|
76
|
+
remainingMs: number;
|
|
77
|
+
availableCount: number;
|
|
78
|
+
} | {
|
|
79
|
+
redeem: false;
|
|
80
|
+
reason: CodexAutoRedeemSkipReason;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Decide whether to auto-redeem a saved Codex reset for the active account.
|
|
84
|
+
*
|
|
85
|
+
* Pure: every gate below is a function of the snapshot inputs only. Order
|
|
86
|
+
* matters — cheapest / most-decisive gates first so the common "not eligible"
|
|
87
|
+
* paths short-circuit before any account/report matching.
|
|
88
|
+
*/
|
|
89
|
+
export declare function evaluateCodexAutoRedeem(input: CodexAutoRedeemInput): CodexAutoRedeemDecision;
|
|
90
|
+
/**
|
|
91
|
+
* Process-wide (NOT per-session) coordinator state. Parallel subagent sessions
|
|
92
|
+
* share the same Codex accounts and must not race a double-spend, so this is a
|
|
93
|
+
* single shared container, not a per-session field.
|
|
94
|
+
*
|
|
95
|
+
* - `attemptedBlockKeys`: one attempt EVER per block episode, regardless of
|
|
96
|
+
* outcome — recorded before calling the consume so exceptions can't re-enter.
|
|
97
|
+
* - `lastAttemptAtByAccount`: per-account cooldown timestamps (epoch ms),
|
|
98
|
+
* catching blockKey drift across a minute boundary.
|
|
99
|
+
* - `inFlightByAccount`: serializes per account — a second session for the same
|
|
100
|
+
* account adopts the in-flight promise instead of starting a second consume.
|
|
101
|
+
*/
|
|
102
|
+
export interface CodexAutoRedeemCoordinator {
|
|
103
|
+
attemptedBlockKeys: Set<string>;
|
|
104
|
+
lastAttemptAtByAccount: Map<string, number>;
|
|
105
|
+
inFlightByAccount: Map<string, Promise<boolean>>;
|
|
106
|
+
}
|
|
107
|
+
export declare const defaultCodexAutoRedeemCoordinator: CodexAutoRedeemCoordinator;
|