@oh-my-pi/pi-coding-agent 15.7.2 → 15.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -6
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/extension-flags.d.ts +36 -0
- package/dist/types/config/config-file.d.ts +4 -0
- package/dist/types/config/file-lock.d.ts +23 -0
- package/dist/types/config/keybindings.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +88 -65
- package/dist/types/edit/hashline/diff.d.ts +3 -3
- package/dist/types/eval/__tests__/agent-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/budget-bridge.test.d.ts +1 -0
- package/dist/types/eval/__tests__/idle-timeout.test.d.ts +1 -0
- package/dist/types/eval/agent-bridge.d.ts +25 -0
- package/dist/types/eval/backend.d.ts +17 -2
- package/dist/types/eval/budget-bridge.d.ts +29 -0
- package/dist/types/eval/idle-timeout.d.ts +28 -0
- package/dist/types/eval/js/executor.d.ts +8 -0
- package/dist/types/eval/js/tool-bridge.d.ts +2 -1
- package/dist/types/eval/py/executor.d.ts +13 -0
- package/dist/types/exec/bash-executor.d.ts +1 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/runner.d.ts +7 -0
- package/dist/types/extensibility/plugins/git-url.d.ts +11 -1
- package/dist/types/extensibility/plugins/manager.d.ts +12 -1
- package/dist/types/extensibility/shared-events.d.ts +2 -2
- package/dist/types/memory-backend/index.d.ts +1 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +3 -3
- package/dist/types/mnemopi/backend.d.ts +4 -0
- package/dist/types/mnemopi/config.d.ts +29 -0
- package/dist/types/mnemopi/state.d.ts +72 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -2
- package/dist/types/modes/components/omfg-panel.d.ts +19 -0
- package/dist/types/modes/controllers/command-controller.d.ts +7 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/controllers/omfg-controller.d.ts +10 -0
- package/dist/types/modes/controllers/omfg-rule.d.ts +26 -0
- package/dist/types/modes/gradient-highlight.d.ts +5 -1
- package/dist/types/modes/interactive-mode.d.ts +7 -3
- package/dist/types/modes/magic-keywords.d.ts +14 -0
- package/dist/types/modes/markdown-prose.d.ts +27 -0
- package/dist/types/modes/orchestrate.d.ts +7 -2
- package/dist/types/modes/shared.d.ts +1 -1
- package/dist/types/modes/turn-budget.d.ts +18 -0
- package/dist/types/modes/types.d.ts +7 -3
- package/dist/types/modes/ultrathink.d.ts +7 -2
- package/dist/types/modes/workflow.d.ts +15 -0
- package/dist/types/sdk.d.ts +13 -3
- package/dist/types/session/agent-session.d.ts +40 -17
- package/dist/types/session/session-manager.d.ts +18 -0
- package/dist/types/session/session-storage.d.ts +6 -0
- package/dist/types/session/shake-types.d.ts +24 -0
- package/dist/types/task/executor.d.ts +2 -2
- package/dist/types/tiny/models.d.ts +15 -1
- package/dist/types/tiny/title-protocol.d.ts +4 -0
- package/dist/types/tools/index.d.ts +19 -3
- package/dist/types/tools/memory-edit.d.ts +1 -1
- package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
- package/package.json +10 -10
- package/src/autoresearch/tools/run-experiment.ts +45 -113
- package/src/cli/args.ts +39 -16
- package/src/cli/extension-flags.ts +48 -0
- package/src/cli/plugin-cli.ts +11 -2
- package/src/config/config-file.ts +98 -13
- package/src/config/file-lock.ts +60 -17
- package/src/config/keybindings.ts +78 -27
- package/src/config/model-registry.ts +7 -1
- package/src/config/settings-schema.ts +94 -67
- package/src/config/settings.ts +12 -0
- package/src/edit/hashline/diff.ts +81 -24
- package/src/edit/renderer.ts +16 -12
- package/src/eval/__tests__/agent-bridge.test.ts +433 -0
- package/src/eval/__tests__/budget-bridge.test.ts +69 -0
- package/src/eval/__tests__/idle-timeout.test.ts +66 -0
- package/src/eval/__tests__/shared-executors.test.ts +21 -0
- package/src/eval/agent-bridge.ts +295 -0
- package/src/eval/backend.ts +17 -2
- package/src/eval/budget-bridge.ts +48 -0
- package/src/eval/idle-timeout.ts +80 -0
- package/src/eval/js/executor.ts +35 -7
- package/src/eval/js/index.ts +2 -1
- package/src/eval/js/shared/prelude.txt +85 -1
- package/src/eval/js/tool-bridge.ts +9 -0
- package/src/eval/py/executor.ts +41 -14
- package/src/eval/py/index.ts +2 -1
- package/src/eval/py/prelude.py +132 -1
- package/src/exec/bash-executor.ts +2 -3
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/runner.ts +12 -2
- package/src/extensibility/plugins/git-url.ts +90 -4
- package/src/extensibility/plugins/manager.ts +103 -7
- package/src/extensibility/shared-events.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +88 -88
- package/src/main.ts +44 -55
- package/src/memory-backend/index.ts +1 -1
- package/src/memory-backend/resolve.ts +3 -3
- package/src/memory-backend/types.ts +3 -3
- package/src/{mnemosyne → mnemopi}/backend.ts +70 -70
- package/src/{mnemosyne → mnemopi}/config.ts +36 -36
- package/src/{mnemosyne → mnemopi}/state.ts +67 -67
- package/src/modes/components/agent-dashboard.ts +6 -6
- package/src/modes/components/custom-editor.ts +4 -11
- package/src/modes/components/extensions/state-manager.ts +3 -4
- package/src/modes/components/footer.ts +8 -9
- package/src/modes/components/hook-selector.ts +86 -20
- package/src/modes/components/oauth-selector.ts +93 -21
- package/src/modes/components/omfg-panel.ts +141 -0
- package/src/modes/components/settings-defs.ts +2 -2
- package/src/modes/components/tips.txt +2 -1
- package/src/modes/components/tool-execution.ts +38 -19
- package/src/modes/components/tree-selector.ts +4 -3
- package/src/modes/components/user-message-selector.ts +94 -19
- package/src/modes/components/user-message.ts +8 -1
- package/src/modes/controllers/command-controller.ts +57 -0
- package/src/modes/controllers/event-controller.ts +60 -2
- package/src/modes/controllers/input-controller.ts +14 -11
- package/src/modes/controllers/omfg-controller.ts +283 -0
- package/src/modes/controllers/omfg-rule.ts +647 -0
- package/src/modes/controllers/selector-controller.ts +1 -0
- package/src/modes/gradient-highlight.ts +23 -6
- package/src/modes/interactive-mode.ts +41 -7
- package/src/modes/magic-keywords.ts +20 -0
- package/src/modes/markdown-prose.ts +247 -0
- package/src/modes/orchestrate.ts +17 -11
- package/src/modes/shared.ts +3 -11
- package/src/modes/turn-budget.ts +31 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/ultrathink.ts +16 -10
- package/src/modes/utils/hotkeys-markdown.ts +1 -1
- package/src/modes/workflow.ts +42 -0
- package/src/prompts/system/omfg-user.md +51 -0
- package/src/prompts/system/system-prompt.md +1 -0
- package/src/prompts/system/workflow-notice.md +70 -0
- package/src/prompts/tools/eval.md +13 -1
- package/src/prompts/tools/memory-edit.md +1 -1
- package/src/sdk.ts +63 -33
- package/src/session/agent-session.ts +373 -56
- package/src/session/session-manager.ts +32 -0
- package/src/session/session-storage.ts +68 -8
- package/src/session/shake-types.ts +44 -0
- package/src/slash-commands/builtin-registry.ts +41 -16
- package/src/task/executor.ts +3 -3
- package/src/task/index.ts +6 -6
- package/src/tiny/models.ts +30 -2
- package/src/tiny/title-protocol.ts +11 -1
- package/src/tiny/worker.ts +19 -7
- package/src/tools/eval.ts +202 -26
- package/src/tools/grouped-file-output.ts +9 -2
- package/src/tools/index.ts +17 -5
- package/src/tools/memory-edit.ts +4 -4
- package/src/tools/memory-recall.ts +5 -5
- package/src/tools/memory-reflect.ts +5 -5
- package/src/tools/memory-retain.ts +4 -4
- package/src/tools/render-utils.ts +2 -1
- package/src/tools/search.ts +480 -76
- package/dist/types/mnemosyne/backend.d.ts +0 -4
- package/dist/types/mnemosyne/config.d.ts +0 -29
- package/dist/types/mnemosyne/state.d.ts +0 -72
- /package/dist/types/{mnemosyne → mnemopi}/index.d.ts +0 -0
- /package/src/{mnemosyne → mnemopi}/index.ts +0 -0
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
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
|
-
import { type CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
17
|
+
import { type CompactionResult, type ShakeConfig } from "@oh-my-pi/pi-agent-core/compaction";
|
|
18
18
|
import type { AssistantMessage, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, 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";
|
|
@@ -36,7 +36,7 @@ import { type FileSlashCommand } from "../extensibility/slash-commands";
|
|
|
36
36
|
import { GoalRuntime } from "../goals/runtime";
|
|
37
37
|
import type { Goal, GoalModeState } from "../goals/state";
|
|
38
38
|
import type { HindsightSessionState } from "../hindsight/state";
|
|
39
|
-
import { type
|
|
39
|
+
import { type MnemopiSessionState } from "../mnemopi/state";
|
|
40
40
|
import type { PlanModeState } from "../plan-mode/state";
|
|
41
41
|
import { type AgentRegistry } from "../registry/agent-registry";
|
|
42
42
|
import { type SecretObfuscator } from "../secrets/obfuscator";
|
|
@@ -47,16 +47,17 @@ import { type TodoItem, type TodoPhase } from "../tools/todo-write";
|
|
|
47
47
|
import type { ClientBridge } from "./client-bridge";
|
|
48
48
|
import { type CustomMessage } from "./messages";
|
|
49
49
|
import type { BranchSummaryEntry, NewSessionOptions, SessionContext, SessionManager } from "./session-manager";
|
|
50
|
+
import type { ShakeMode, ShakeResult } from "./shake-types";
|
|
50
51
|
import { ToolChoiceQueue } from "./tool-choice-queue";
|
|
51
52
|
import { YieldQueue } from "./yield-queue";
|
|
52
53
|
/** Session-specific events that extend the core AgentEvent */
|
|
53
54
|
export type AgentSessionEvent = AgentEvent | {
|
|
54
55
|
type: "auto_compaction_start";
|
|
55
56
|
reason: "threshold" | "overflow" | "idle" | "incomplete";
|
|
56
|
-
action: "context-full" | "handoff";
|
|
57
|
+
action: "context-full" | "handoff" | "shake" | "shake-summary";
|
|
57
58
|
} | {
|
|
58
59
|
type: "auto_compaction_end";
|
|
59
|
-
action: "context-full" | "handoff";
|
|
60
|
+
action: "context-full" | "handoff" | "shake" | "shake-summary";
|
|
60
61
|
result: CompactionResult | undefined;
|
|
61
62
|
aborted: boolean;
|
|
62
63
|
willRetry: boolean;
|
|
@@ -121,6 +122,7 @@ export interface AsyncJobSnapshot {
|
|
|
121
122
|
recent: AsyncJobSnapshotItem[];
|
|
122
123
|
delivery: AsyncJobDeliveryState;
|
|
123
124
|
}
|
|
125
|
+
export type { ShakeMode, ShakeResult };
|
|
124
126
|
export interface AgentSessionConfig {
|
|
125
127
|
agent: Agent;
|
|
126
128
|
sessionManager: SessionManager;
|
|
@@ -315,7 +317,7 @@ export declare class AgentSession {
|
|
|
315
317
|
get providerSessionState(): Map<string, ProviderSessionState>;
|
|
316
318
|
getHindsightSessionState(): HindsightSessionState | undefined;
|
|
317
319
|
setHindsightSessionState(state: HindsightSessionState | undefined): HindsightSessionState | undefined;
|
|
318
|
-
|
|
320
|
+
getMnemopiSessionState(): MnemopiSessionState | undefined;
|
|
319
321
|
/** TTSR manager for time-traveling stream rules */
|
|
320
322
|
get ttsrManager(): TtsrManager | undefined;
|
|
321
323
|
/** Whether a TTSR abort is pending (stream was aborted to inject rules) */
|
|
@@ -615,12 +617,13 @@ export declare class AgentSession {
|
|
|
615
617
|
fork(): Promise<boolean>;
|
|
616
618
|
/**
|
|
617
619
|
* Set model directly.
|
|
618
|
-
* Validates API key
|
|
620
|
+
* Validates API key and saves to the active session. Persists settings only when requested.
|
|
619
621
|
* @throws Error if no API key available for the model
|
|
620
622
|
*/
|
|
621
623
|
setModel(model: Model, role?: string, options?: {
|
|
622
624
|
selector?: string;
|
|
623
625
|
thinkingLevel?: ThinkingLevel;
|
|
626
|
+
persist?: boolean;
|
|
624
627
|
}): Promise<void>;
|
|
625
628
|
/**
|
|
626
629
|
* Set model temporarily (for this session only).
|
|
@@ -647,28 +650,26 @@ export declare class AgentSession {
|
|
|
647
650
|
*/
|
|
648
651
|
getRoleModelCycle(roleOrder: readonly string[]): RoleModelCycle | undefined;
|
|
649
652
|
/**
|
|
650
|
-
* Apply a resolved role model as the active model
|
|
651
|
-
* settings
|
|
652
|
-
* {@link cycleRoleModels} and is shared with the plan-approval model slider.
|
|
653
|
+
* Apply a resolved role model as the active model without changing global
|
|
654
|
+
* settings. Shared with role cycling and the plan-approval model slider.
|
|
653
655
|
*/
|
|
654
656
|
applyRoleModel(entry: ResolvedRoleModel): Promise<void>;
|
|
655
657
|
/**
|
|
656
658
|
* Cycle through configured role models in a fixed order.
|
|
657
|
-
* Skips missing roles.
|
|
659
|
+
* Skips missing roles and changes only the active session model.
|
|
658
660
|
* @param roleOrder - Order of roles to cycle through (e.g., ["slow", "default", "smol"])
|
|
659
|
-
* @param
|
|
661
|
+
* @param direction - "forward" (default) or "backward"
|
|
660
662
|
*/
|
|
661
|
-
cycleRoleModels(roleOrder: readonly string[],
|
|
662
|
-
temporary?: boolean;
|
|
663
|
-
}): Promise<RoleModelCycleResult | undefined>;
|
|
663
|
+
cycleRoleModels(roleOrder: readonly string[], direction?: "forward" | "backward"): Promise<RoleModelCycleResult | undefined>;
|
|
664
664
|
/**
|
|
665
665
|
* Get all available models with valid API keys.
|
|
666
666
|
*/
|
|
667
667
|
getAvailableModels(): Model[];
|
|
668
668
|
/**
|
|
669
|
-
* Set the thinking level. `auto` enables per-turn classification
|
|
670
|
-
* never written to the session log
|
|
671
|
-
*
|
|
669
|
+
* Set the thinking level. `auto` enables per-turn classification; the selector
|
|
670
|
+
* itself is never written to the session log, but resolved concrete levels are
|
|
671
|
+
* persisted when real user turns are classified so resumed sessions keep the
|
|
672
|
+
* last resolved effort instead of reverting to pending auto.
|
|
672
673
|
*/
|
|
673
674
|
setThinkingLevel(level: ConfiguredThinkingLevel | undefined, persist?: boolean): void;
|
|
674
675
|
/**
|
|
@@ -730,6 +731,27 @@ export declare class AgentSession {
|
|
|
730
731
|
dropImages(): Promise<{
|
|
731
732
|
removed: number;
|
|
732
733
|
}>;
|
|
734
|
+
/**
|
|
735
|
+
* Surgically reduce context by dropping heavy content ("shake").
|
|
736
|
+
*
|
|
737
|
+
* - `images` delegates to {@link dropImages}.
|
|
738
|
+
* - `elide` replaces whole tool-call results and large fenced/XML blocks
|
|
739
|
+
* with short placeholders that embed an `artifact://` recovery link.
|
|
740
|
+
* - `summary` extractively compresses the same regions with the configured
|
|
741
|
+
* local on-device model (`providers.shakeSummaryModel`), falling back to
|
|
742
|
+
* the elide placeholder per region (or wholesale when the local model is
|
|
743
|
+
* unavailable). Never calls a remote/cloud LLM.
|
|
744
|
+
*
|
|
745
|
+
* Mutates the branch in place, persists via `rewriteEntries`, replays the
|
|
746
|
+
* rebuilt context through the agent, and tears down provider sessions that
|
|
747
|
+
* cache message identity — same rewrite contract as {@link dropImages}.
|
|
748
|
+
*
|
|
749
|
+
* No-op (zero counts) when nothing is eligible.
|
|
750
|
+
*/
|
|
751
|
+
shake(mode: ShakeMode, opts?: {
|
|
752
|
+
config?: ShakeConfig;
|
|
753
|
+
signal?: AbortSignal;
|
|
754
|
+
}): Promise<ShakeResult>;
|
|
733
755
|
/**
|
|
734
756
|
* Manually compact the session context.
|
|
735
757
|
* Aborts current agent operation first.
|
|
@@ -880,6 +902,7 @@ export declare class AgentSession {
|
|
|
880
902
|
promptText: string;
|
|
881
903
|
onTextDelta?: (delta: string) => void;
|
|
882
904
|
signal?: AbortSignal;
|
|
905
|
+
dedupeReply?: boolean;
|
|
883
906
|
}): Promise<{
|
|
884
907
|
replyText: string;
|
|
885
908
|
assistantMessage: AssistantMessage;
|
|
@@ -306,6 +306,24 @@ export declare class SessionManager {
|
|
|
306
306
|
getCwd(): string;
|
|
307
307
|
/** Get usage statistics across all assistant messages in the session. */
|
|
308
308
|
getUsageStatistics(): UsageStatistics;
|
|
309
|
+
/**
|
|
310
|
+
* Open a new per-turn budget window: snapshot the cumulative output baseline,
|
|
311
|
+
* reset the eval-subagent counter, and set the (optional) ceiling. Called once
|
|
312
|
+
* per real user message; `total` is null when no `+Nk` directive was present.
|
|
313
|
+
*/
|
|
314
|
+
beginTurnBudget(total: number | null, hard: boolean): void;
|
|
315
|
+
/** Record output tokens consumed by an eval-spawned subagent in the current turn. */
|
|
316
|
+
recordEvalSubagentOutput(output: number): void;
|
|
317
|
+
/**
|
|
318
|
+
* Current turn budget for the eval `budget` helper: the ceiling (null = none),
|
|
319
|
+
* output tokens spent this turn (main loop + eval-spawned subagents, no
|
|
320
|
+
* double-count), and whether the ceiling is hard.
|
|
321
|
+
*/
|
|
322
|
+
getTurnBudget(): {
|
|
323
|
+
total: number | null;
|
|
324
|
+
spent: number;
|
|
325
|
+
hard: boolean;
|
|
326
|
+
};
|
|
309
327
|
getSessionDir(): string;
|
|
310
328
|
getSessionId(): string;
|
|
311
329
|
getSessionFile(): string | undefined;
|
|
@@ -65,6 +65,12 @@ export declare class MemorySessionStorage implements SessionStorage {
|
|
|
65
65
|
ensureDirSync(_dir: string): void;
|
|
66
66
|
existsSync(path: string): boolean;
|
|
67
67
|
writeTextSync(path: string, content: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* Internal O(1) append used by {@link MemorySessionStorageWriter}. Lazily
|
|
70
|
+
* creates the entry. External callers should go through `openWriter()`
|
|
71
|
+
* rather than touching the mirror directly.
|
|
72
|
+
*/
|
|
73
|
+
appendChunkSync(path: string, chunk: string): void;
|
|
68
74
|
readTextSync(path: string): string;
|
|
69
75
|
statSync(path: string): SessionStorageStat;
|
|
70
76
|
listFilesSync(dir: string, pattern: string): string[];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public shape of the `shake` operation, kept in a dependency-free leaf module
|
|
3
|
+
* so slash-command registries and controllers can import `formatShakeSummary`
|
|
4
|
+
* without pulling in the heavy `agent-session` module graph (which would form
|
|
5
|
+
* an import cycle through the slash-command registry).
|
|
6
|
+
*/
|
|
7
|
+
/** Mode selector for `AgentSession.shake`. */
|
|
8
|
+
export type ShakeMode = "elide" | "summary" | "images";
|
|
9
|
+
/** Outcome of an `AgentSession.shake` run. */
|
|
10
|
+
export interface ShakeResult {
|
|
11
|
+
mode: ShakeMode;
|
|
12
|
+
/** Whole tool-call results dropped/compressed. */
|
|
13
|
+
toolResultsDropped: number;
|
|
14
|
+
/** Large fenced/XML blocks dropped/compressed. */
|
|
15
|
+
blocksDropped: number;
|
|
16
|
+
/** Image blocks removed (images mode only). */
|
|
17
|
+
imagesDropped?: number;
|
|
18
|
+
/** Estimated context tokens reclaimed. */
|
|
19
|
+
tokensFreed: number;
|
|
20
|
+
/** Session artifact holding the dropped originals, when persisted. */
|
|
21
|
+
artifactId?: string;
|
|
22
|
+
}
|
|
23
|
+
/** One-line operator summary of a {@link ShakeResult} (shared by TUI + ACP). */
|
|
24
|
+
export declare function formatShakeSummary(result: ShakeResult): string;
|
|
@@ -11,7 +11,7 @@ import { type Skill } from "../extensibility/skills";
|
|
|
11
11
|
import type { HindsightSessionState } from "../hindsight/state";
|
|
12
12
|
import type { LocalProtocolOptions } from "../internal-urls";
|
|
13
13
|
import type { MCPManager } from "../mcp/manager";
|
|
14
|
-
import type {
|
|
14
|
+
import type { MnemopiSessionState } from "../mnemopi/state";
|
|
15
15
|
import type { ArtifactManager } from "../session/artifacts";
|
|
16
16
|
import type { AuthStorage } from "../session/auth-storage";
|
|
17
17
|
import type { ContextFileEntry } from "../tools";
|
|
@@ -65,7 +65,7 @@ export interface ExecutorOptions {
|
|
|
65
65
|
*/
|
|
66
66
|
parentArtifactManager?: ArtifactManager;
|
|
67
67
|
parentHindsightSessionState?: HindsightSessionState;
|
|
68
|
-
|
|
68
|
+
parentMnemopiSessionState?: MnemopiSessionState;
|
|
69
69
|
/** Parent agent's eval executor session id. Subagents reuse it so eval state is shared. */
|
|
70
70
|
parentEvalSessionId?: string;
|
|
71
71
|
/**
|
|
@@ -65,7 +65,7 @@ export declare const ONLINE_MEMORY_MODEL_KEY = "online";
|
|
|
65
65
|
/** Recommended local model for memory tasks when none is named. */
|
|
66
66
|
export declare const DEFAULT_MEMORY_LOCAL_MODEL_KEY = "qwen3-1.7b";
|
|
67
67
|
/**
|
|
68
|
-
* Local models for
|
|
68
|
+
* Local models for Mnemopi memory tasks (fact extraction + consolidation).
|
|
69
69
|
* These are larger (1B-1.7B) than the title models: structured extraction and
|
|
70
70
|
* faithful summarization need more capacity than 3-6 word titles. All q4.
|
|
71
71
|
* Ranking/recipe rationale lives in docs/local-models.md.
|
|
@@ -113,6 +113,20 @@ export declare const TINY_MEMORY_MODEL_OPTIONS: ({
|
|
|
113
113
|
})[];
|
|
114
114
|
export declare function isTinyMemoryLocalModelKey(value: string): value is TinyMemoryLocalModelKey;
|
|
115
115
|
export declare function getTinyMemoryModelSpec(key: TinyMemoryLocalModelKey): (typeof TINY_MEMORY_LOCAL_MODELS)[number];
|
|
116
|
+
/**
|
|
117
|
+
* Shake-summary models. Shake's `summary` mode (and the `shake-summary`
|
|
118
|
+
* compaction strategy) compress heavy regions strictly on-device — there is no
|
|
119
|
+
* online/remote option, so this registry reuses the local memory models only.
|
|
120
|
+
*/
|
|
121
|
+
export declare const SHAKE_SUMMARY_MODEL_VALUES: readonly ["qwen3-1.7b", "gemma-3-1b", "qwen2.5-1.5b", "lfm2-1.2b"];
|
|
122
|
+
export type ShakeSummaryModelKey = (typeof SHAKE_SUMMARY_MODEL_VALUES)[number];
|
|
123
|
+
export declare const SHAKE_SUMMARY_MODEL_OPTIONS: {
|
|
124
|
+
value: "gemma-3-1b" | "lfm2-1.2b" | "qwen2.5-1.5b" | "qwen3-1.7b";
|
|
125
|
+
label: "Gemma 3 1B" | "LFM2 1.2B" | "Qwen2.5 1.5B" | "Qwen3 1.7B";
|
|
126
|
+
description: "Best consolidation/dedup; lighter footprint, but leaks small talk during extraction." | "Best extraction granularity (atomic facts); weaker consolidation." | "Fastest load; solid all-rounder, slightly noisier extraction labels." | "Recommended; most disciplined extraction (ignores chit-chat), good consolidation, about 1.1 GB cached.";
|
|
127
|
+
}[];
|
|
128
|
+
/** Default shake-summary local model when none is named. */
|
|
129
|
+
export declare const DEFAULT_SHAKE_SUMMARY_MODEL_KEY: ShakeSummaryModelKey;
|
|
116
130
|
/** Any local model key (title or memory), used by the shared inference worker. */
|
|
117
131
|
export type TinyLocalModelKey = TinyTitleLocalModelKey | TinyMemoryLocalModelKey;
|
|
118
132
|
/** Resolve a local model spec by key across both the title and memory registries. */
|
|
@@ -30,6 +30,10 @@ export type TinyTitleWorkerInbound = {
|
|
|
30
30
|
modelKey: TinyLocalModelKey;
|
|
31
31
|
prompt: string;
|
|
32
32
|
maxTokens?: number;
|
|
33
|
+
/** Optional assistant-turn prefix appended after the generation prompt to pin output format. */
|
|
34
|
+
prefill?: string;
|
|
35
|
+
/** Optional literal stop string; generation halts once it appears in the decoded tail. */
|
|
36
|
+
stop?: string;
|
|
33
37
|
} | {
|
|
34
38
|
type: "download";
|
|
35
39
|
id: string;
|
|
@@ -6,7 +6,9 @@ import type { Settings } from "../config/settings";
|
|
|
6
6
|
import type { Skill } from "../extensibility/skills";
|
|
7
7
|
import type { GoalModeState, GoalRuntime } from "../goals";
|
|
8
8
|
import type { HindsightSessionState } from "../hindsight/state";
|
|
9
|
-
import type {
|
|
9
|
+
import type { LocalProtocolOptions } from "../internal-urls";
|
|
10
|
+
import type { MCPManager } from "../mcp";
|
|
11
|
+
import type { MnemopiSessionState } from "../mnemopi/state";
|
|
10
12
|
import type { PlanModeState } from "../plan-mode/state";
|
|
11
13
|
import { type AgentRegistry } from "../registry/agent-registry";
|
|
12
14
|
import type { ArtifactManager } from "../session/artifacts";
|
|
@@ -107,8 +109,8 @@ export interface ToolSession {
|
|
|
107
109
|
getSessionId?: () => string | null;
|
|
108
110
|
/** Get Hindsight runtime state for this agent session. */
|
|
109
111
|
getHindsightSessionState?: () => HindsightSessionState | undefined;
|
|
110
|
-
/** Get
|
|
111
|
-
|
|
112
|
+
/** Get Mnemopi runtime state for this agent session. */
|
|
113
|
+
getMnemopiSessionState?: () => MnemopiSessionState | undefined;
|
|
112
114
|
/** Agent identity used for IRC routing. Returns the registry id (e.g. "0-Main", "0-AuthLoader"). */
|
|
113
115
|
getAgentId?: () => string | null;
|
|
114
116
|
/** Look up a registered tool by name (used by the eval js backend's tool bridge). */
|
|
@@ -136,6 +138,10 @@ export interface ToolSession {
|
|
|
136
138
|
modelRegistry?: import("../config/model-registry").ModelRegistry;
|
|
137
139
|
/** Agent output manager for unique agent:// IDs across task invocations */
|
|
138
140
|
agentOutputManager?: AgentOutputManager;
|
|
141
|
+
/** MCP manager visible to subagents without relying on the process-global singleton. */
|
|
142
|
+
mcpManager?: MCPManager;
|
|
143
|
+
/** Local protocol root to propagate to nested subagents and eval-created agents. */
|
|
144
|
+
localProtocolOptions?: LocalProtocolOptions;
|
|
139
145
|
/** Settings instance for passing to subagents */
|
|
140
146
|
settings: Settings;
|
|
141
147
|
/** Plan mode state (if active) */
|
|
@@ -144,6 +150,16 @@ export interface ToolSession {
|
|
|
144
150
|
getGoalModeState?: () => GoalModeState | undefined;
|
|
145
151
|
/** Goal runtime for the active agent session. */
|
|
146
152
|
getGoalRuntime?: () => GoalRuntime | undefined;
|
|
153
|
+
/** Get cumulative session usage statistics (input/output tokens, cost). */
|
|
154
|
+
getUsageStatistics?: () => import("../session/session-manager").UsageStatistics;
|
|
155
|
+
/** Current per-turn token budget {total, spent, hard} for the eval `budget` helper. */
|
|
156
|
+
getTurnBudget?: () => {
|
|
157
|
+
total: number | null;
|
|
158
|
+
spent: number;
|
|
159
|
+
hard: boolean;
|
|
160
|
+
};
|
|
161
|
+
/** Record output tokens consumed by an eval-spawned subagent toward the current turn budget. */
|
|
162
|
+
recordEvalSubagentUsage?: (output: number) => void;
|
|
147
163
|
/** Bridge to the connected client (e.g. ACP editor host). Tools should route fs/terminal/permission requests through this when available. */
|
|
148
164
|
getClientBridge?: () => ClientBridge | undefined;
|
|
149
165
|
/** Get compact conversation context for subagents (excludes tool results, system prompts) */
|
|
@@ -32,7 +32,7 @@ export declare class MemoryEditTool implements AgentTool<typeof memoryEditSchema
|
|
|
32
32
|
}, z.core.$strip>;
|
|
33
33
|
readonly strict = true;
|
|
34
34
|
readonly loadMode = "discoverable";
|
|
35
|
-
readonly summary = "Update, forget, or invalidate
|
|
35
|
+
readonly summary = "Update, forget, or invalidate Mnemopi memories";
|
|
36
36
|
constructor(session: ToolSession);
|
|
37
37
|
static createIf(session: ToolSession): MemoryEditTool | null;
|
|
38
38
|
execute(_id: string, params: MemoryEditParams): Promise<AgentToolResult>;
|
|
@@ -26,7 +26,7 @@ console.log("Session with default auth storage and model registry");
|
|
|
26
26
|
|
|
27
27
|
// Custom auth storage location
|
|
28
28
|
const customAuthStorage = await AuthStorage.create("/tmp/my-app/agent.db");
|
|
29
|
-
const customModelRegistry =
|
|
29
|
+
const customModelRegistry = await ModelRegistry.create(customAuthStorage, "/tmp/my-app/models.json");
|
|
30
30
|
|
|
31
31
|
await createAgentSession({
|
|
32
32
|
sessionManager: SessionManager.inMemory(),
|
|
@@ -45,7 +45,7 @@ await createAgentSession({
|
|
|
45
45
|
console.log("Session with runtime API key override");
|
|
46
46
|
|
|
47
47
|
// No models.json - only built-in models
|
|
48
|
-
const simpleRegistry =
|
|
48
|
+
const simpleRegistry = await ModelRegistry.create(authStorage); // null = no models.json
|
|
49
49
|
await createAgentSession({
|
|
50
50
|
sessionManager: SessionManager.inMemory(),
|
|
51
51
|
authStorage,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
4
|
-
"version": "15.7.
|
|
4
|
+
"version": "15.7.3",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"check": "biome check . && bun run check:types",
|
|
36
36
|
"check:types": "tsgo -p tsconfig.json --noEmit",
|
|
37
37
|
"lint": "biome lint .",
|
|
38
|
-
"test": "bun test",
|
|
38
|
+
"test": "bun test --parallel",
|
|
39
39
|
"fix": "biome check --write --unsafe . && bun run format-prompts && bun run generate-docs-index",
|
|
40
40
|
"fmt": "biome format --write . && bun run format-prompts",
|
|
41
41
|
"format-prompts": "bun scripts/format-prompts.ts",
|
|
@@ -47,14 +47,14 @@
|
|
|
47
47
|
"@agentclientprotocol/sdk": "0.22.1",
|
|
48
48
|
"@babel/parser": "^7.29.7",
|
|
49
49
|
"@mozilla/readability": "^0.6.0",
|
|
50
|
-
"@oh-my-pi/hashline": "15.7.
|
|
51
|
-
"@oh-my-pi/omp-stats": "15.7.
|
|
52
|
-
"@oh-my-pi/pi-agent-core": "15.7.
|
|
53
|
-
"@oh-my-pi/pi-ai": "15.7.
|
|
54
|
-
"@oh-my-pi/pi-
|
|
55
|
-
"@oh-my-pi/pi-natives": "15.7.
|
|
56
|
-
"@oh-my-pi/pi-tui": "15.7.
|
|
57
|
-
"@oh-my-pi/pi-utils": "15.7.
|
|
50
|
+
"@oh-my-pi/hashline": "15.7.3",
|
|
51
|
+
"@oh-my-pi/omp-stats": "15.7.3",
|
|
52
|
+
"@oh-my-pi/pi-agent-core": "15.7.3",
|
|
53
|
+
"@oh-my-pi/pi-ai": "15.7.3",
|
|
54
|
+
"@oh-my-pi/pi-mnemopi": "15.7.3",
|
|
55
|
+
"@oh-my-pi/pi-natives": "15.7.3",
|
|
56
|
+
"@oh-my-pi/pi-tui": "15.7.3",
|
|
57
|
+
"@oh-my-pi/pi-utils": "15.7.3",
|
|
58
58
|
"@puppeteer/browsers": "^3.0.4",
|
|
59
59
|
"@types/turndown": "5.0.6",
|
|
60
60
|
"@xterm/headless": "^6.0.0",
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import * as childProcess from "node:child_process";
|
|
2
1
|
import * as fs from "node:fs";
|
|
3
2
|
import * as path from "node:path";
|
|
4
3
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
5
4
|
import { formatBytes } from "@oh-my-pi/pi-utils";
|
|
6
5
|
import * as z from "zod/v4";
|
|
6
|
+
import { executeBash } from "../../exec/bash-executor";
|
|
7
7
|
import type { ToolDefinition } from "../../extensibility/extensions";
|
|
8
8
|
import type { Theme } from "../../modes/theme/theme";
|
|
9
|
-
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, truncateTail } from "../../session/streaming-output";
|
|
9
|
+
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, TailBuffer, truncateTail } from "../../session/streaming-output";
|
|
10
10
|
import { replaceTabs, shortenPath } from "../../tools/render-utils";
|
|
11
11
|
import * as git from "../../utils/git";
|
|
12
12
|
import { parseWorkDirDirtyPaths } from "../git";
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
EXPERIMENT_MAX_LINES,
|
|
16
16
|
formatElapsed,
|
|
17
17
|
formatNum,
|
|
18
|
-
killTree,
|
|
19
18
|
parseAsiLines,
|
|
20
19
|
parseMetricLines,
|
|
21
20
|
tryGitPrefix,
|
|
@@ -117,7 +116,7 @@ export function createRunExperimentTool(
|
|
|
117
116
|
let execution: ProcessExecutionResult;
|
|
118
117
|
try {
|
|
119
118
|
execution = await executeProcess({
|
|
120
|
-
command:
|
|
119
|
+
command: resolvedCommand,
|
|
121
120
|
cwd: ctx.cwd,
|
|
122
121
|
logPath: benchmarkLogPath,
|
|
123
122
|
timeoutMs,
|
|
@@ -268,68 +267,18 @@ export function createRunExperimentTool(
|
|
|
268
267
|
};
|
|
269
268
|
}
|
|
270
269
|
async function executeProcess(opts: {
|
|
271
|
-
command: string
|
|
270
|
+
command: string;
|
|
272
271
|
cwd: string;
|
|
273
272
|
logPath: string;
|
|
274
273
|
timeoutMs: number;
|
|
275
274
|
signal?: AbortSignal;
|
|
276
275
|
onProgress?(details: ProgressSnapshot): void;
|
|
277
276
|
}): Promise<ProcessExecutionResult> {
|
|
278
|
-
const
|
|
279
|
-
const child = childProcess.spawn(opts.command[0] ?? "bash", opts.command.slice(1), {
|
|
280
|
-
cwd: opts.cwd,
|
|
281
|
-
detached: true,
|
|
282
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
const tailChunks: Buffer[] = [];
|
|
286
|
-
let chunksBytes = 0;
|
|
287
|
-
let killedByTimeout = false;
|
|
288
|
-
let resolved = false;
|
|
289
|
-
let writeStream: fs.WriteStream | undefined = fs.createWriteStream(opts.logPath);
|
|
290
|
-
let forceKillTimeout: NodeJS.Timeout | undefined;
|
|
291
|
-
|
|
292
|
-
const closeWriteStream = (): Promise<void> => {
|
|
293
|
-
if (!writeStream) return Promise.resolve();
|
|
294
|
-
const stream = writeStream;
|
|
295
|
-
writeStream = undefined;
|
|
296
|
-
return new Promise<void>((resolveClose, rejectClose) => {
|
|
297
|
-
stream.end((error?: Error | null) => {
|
|
298
|
-
if (error) {
|
|
299
|
-
rejectClose(error);
|
|
300
|
-
return;
|
|
301
|
-
}
|
|
302
|
-
resolveClose();
|
|
303
|
-
});
|
|
304
|
-
});
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
const cleanup = (): void => {
|
|
308
|
-
if (progressTimer) clearInterval(progressTimer);
|
|
309
|
-
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
310
|
-
if (forceKillTimeout) clearTimeout(forceKillTimeout);
|
|
311
|
-
opts.signal?.removeEventListener("abort", abortHandler);
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
const finish = (callback: () => void): void => {
|
|
315
|
-
if (resolved) return;
|
|
316
|
-
resolved = true;
|
|
317
|
-
cleanup();
|
|
318
|
-
callback();
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
const appendChunk = (data: Buffer): void => {
|
|
322
|
-
writeStream?.write(data);
|
|
323
|
-
tailChunks.push(data);
|
|
324
|
-
chunksBytes += data.length;
|
|
325
|
-
while (chunksBytes > DEFAULT_MAX_BYTES * 2 && tailChunks.length > 1) {
|
|
326
|
-
const removed = tailChunks.shift();
|
|
327
|
-
if (removed) chunksBytes -= removed.length;
|
|
328
|
-
}
|
|
329
|
-
};
|
|
277
|
+
const tailBuffer = new TailBuffer(DEFAULT_MAX_BYTES * 2);
|
|
330
278
|
|
|
279
|
+
const startedAt = Date.now();
|
|
331
280
|
const snapshot = (): ProgressSnapshot => {
|
|
332
|
-
const tail = truncateTail(
|
|
281
|
+
const tail = truncateTail(tailBuffer.text(), {
|
|
333
282
|
maxBytes: DEFAULT_MAX_BYTES,
|
|
334
283
|
maxLines: DEFAULT_MAX_LINES,
|
|
335
284
|
});
|
|
@@ -342,71 +291,54 @@ async function executeProcess(opts: {
|
|
|
342
291
|
};
|
|
343
292
|
};
|
|
344
293
|
|
|
345
|
-
const killTreeWithEscalation = (): void => {
|
|
346
|
-
if (!child.pid) return;
|
|
347
|
-
killTree(child.pid);
|
|
348
|
-
forceKillTimeout = setTimeout(() => {
|
|
349
|
-
if (child.pid) killTree(child.pid, "SIGKILL");
|
|
350
|
-
}, 1_000);
|
|
351
|
-
forceKillTimeout.unref?.();
|
|
352
|
-
};
|
|
353
|
-
|
|
354
|
-
const startedAt = Date.now();
|
|
355
294
|
const progressTimer = opts.onProgress
|
|
356
295
|
? setInterval(() => {
|
|
357
296
|
opts.onProgress?.(snapshot());
|
|
358
297
|
}, 1000)
|
|
359
298
|
: undefined;
|
|
360
|
-
const timeoutHandle =
|
|
361
|
-
opts.timeoutMs > 0
|
|
362
|
-
? setTimeout(() => {
|
|
363
|
-
killedByTimeout = true;
|
|
364
|
-
killTreeWithEscalation();
|
|
365
|
-
}, opts.timeoutMs)
|
|
366
|
-
: undefined;
|
|
367
299
|
|
|
368
|
-
const
|
|
369
|
-
|
|
300
|
+
const logSink = Bun.file(opts.logPath).writer();
|
|
301
|
+
let logSinkClosed = false;
|
|
302
|
+
const closeLogSink = async (): Promise<void> => {
|
|
303
|
+
if (logSinkClosed) return;
|
|
304
|
+
logSinkClosed = true;
|
|
305
|
+
await logSink.end();
|
|
370
306
|
};
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
});
|
|
383
|
-
child.on("error", error => {
|
|
384
|
-
void closeWriteStream().finally(() => {
|
|
385
|
-
finish(() => reject(error));
|
|
307
|
+
try {
|
|
308
|
+
const result = await executeBash(opts.command, {
|
|
309
|
+
cwd: opts.cwd,
|
|
310
|
+
sessionKey: `autoresearch:${opts.cwd}`,
|
|
311
|
+
timeout: opts.timeoutMs > 0 ? opts.timeoutMs : 2_147_000_000,
|
|
312
|
+
signal: opts.signal,
|
|
313
|
+
chunkThrottleMs: 0,
|
|
314
|
+
onChunk: chunk => {
|
|
315
|
+
tailBuffer.append(chunk);
|
|
316
|
+
logSink.write(chunk);
|
|
317
|
+
},
|
|
386
318
|
});
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
await closeWriteStream();
|
|
391
|
-
if (opts.signal?.aborted) {
|
|
392
|
-
finish(() => reject(new Error("aborted")));
|
|
393
|
-
return;
|
|
394
|
-
}
|
|
395
|
-
const output = await fs.promises.readFile(opts.logPath, "utf8");
|
|
396
|
-
finish(() =>
|
|
397
|
-
resolve({
|
|
398
|
-
exitCode: code,
|
|
399
|
-
killed: killedByTimeout,
|
|
400
|
-
logPath: opts.logPath,
|
|
401
|
-
output,
|
|
402
|
-
}),
|
|
403
|
-
);
|
|
404
|
-
} catch (error) {
|
|
405
|
-
finish(() => reject(error));
|
|
319
|
+
await closeLogSink();
|
|
320
|
+
if (opts.signal?.aborted) {
|
|
321
|
+
throw new Error("aborted");
|
|
406
322
|
}
|
|
407
|
-
});
|
|
408
323
|
|
|
409
|
-
|
|
324
|
+
const output = await fs.promises.readFile(opts.logPath, "utf8");
|
|
325
|
+
|
|
326
|
+
return {
|
|
327
|
+
exitCode: result.exitCode ?? null,
|
|
328
|
+
killed: result.cancelled,
|
|
329
|
+
logPath: opts.logPath,
|
|
330
|
+
output,
|
|
331
|
+
};
|
|
332
|
+
} finally {
|
|
333
|
+
if (progressTimer) clearInterval(progressTimer);
|
|
334
|
+
if (!logSinkClosed) {
|
|
335
|
+
try {
|
|
336
|
+
await closeLogSink();
|
|
337
|
+
} catch {
|
|
338
|
+
// Preserve the command failure when cleanup is best-effort.
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
410
342
|
}
|
|
411
343
|
|
|
412
344
|
function buildRunText(details: RunDetails, outputPreview: string, bestMetric: number | null): string {
|