@oh-my-pi/pi-coding-agent 15.7.1 → 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.
Files changed (177) hide show
  1. package/CHANGELOG.md +95 -6
  2. package/dist/types/auto-thinking/classifier.d.ts +35 -0
  3. package/dist/types/cli/args.d.ts +1 -1
  4. package/dist/types/cli/extension-flags.d.ts +36 -0
  5. package/dist/types/config/config-file.d.ts +4 -0
  6. package/dist/types/config/file-lock.d.ts +23 -0
  7. package/dist/types/config/keybindings.d.ts +2 -1
  8. package/dist/types/config/model-registry.d.ts +6 -0
  9. package/dist/types/config/settings-schema.d.ts +112 -69
  10. package/dist/types/edit/hashline/diff.d.ts +9 -3
  11. package/dist/types/eval/__tests__/agent-bridge.test.d.ts +1 -0
  12. package/dist/types/eval/__tests__/budget-bridge.test.d.ts +1 -0
  13. package/dist/types/eval/__tests__/idle-timeout.test.d.ts +1 -0
  14. package/dist/types/eval/agent-bridge.d.ts +25 -0
  15. package/dist/types/eval/backend.d.ts +17 -2
  16. package/dist/types/eval/budget-bridge.d.ts +29 -0
  17. package/dist/types/eval/idle-timeout.d.ts +28 -0
  18. package/dist/types/eval/js/executor.d.ts +8 -0
  19. package/dist/types/eval/js/tool-bridge.d.ts +2 -1
  20. package/dist/types/eval/py/executor.d.ts +13 -0
  21. package/dist/types/exec/bash-executor.d.ts +1 -0
  22. package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
  23. package/dist/types/extensibility/extensions/runner.d.ts +7 -0
  24. package/dist/types/extensibility/plugins/git-url.d.ts +11 -1
  25. package/dist/types/extensibility/plugins/manager.d.ts +12 -1
  26. package/dist/types/extensibility/shared-events.d.ts +2 -2
  27. package/dist/types/memory-backend/index.d.ts +1 -1
  28. package/dist/types/memory-backend/resolve.d.ts +1 -1
  29. package/dist/types/memory-backend/types.d.ts +3 -3
  30. package/dist/types/mnemopi/backend.d.ts +4 -0
  31. package/dist/types/mnemopi/config.d.ts +29 -0
  32. package/dist/types/mnemopi/state.d.ts +72 -0
  33. package/dist/types/modes/components/custom-editor.d.ts +2 -2
  34. package/dist/types/modes/components/model-selector.d.ts +3 -2
  35. package/dist/types/modes/components/omfg-panel.d.ts +19 -0
  36. package/dist/types/modes/controllers/command-controller.d.ts +7 -0
  37. package/dist/types/modes/controllers/input-controller.d.ts +1 -3
  38. package/dist/types/modes/controllers/omfg-controller.d.ts +10 -0
  39. package/dist/types/modes/controllers/omfg-rule.d.ts +26 -0
  40. package/dist/types/modes/gradient-highlight.d.ts +5 -1
  41. package/dist/types/modes/interactive-mode.d.ts +7 -3
  42. package/dist/types/modes/magic-keywords.d.ts +14 -0
  43. package/dist/types/modes/markdown-prose.d.ts +27 -0
  44. package/dist/types/modes/orchestrate.d.ts +7 -2
  45. package/dist/types/modes/shared.d.ts +1 -1
  46. package/dist/types/modes/theme/theme.d.ts +2 -1
  47. package/dist/types/modes/turn-budget.d.ts +18 -0
  48. package/dist/types/modes/types.d.ts +7 -3
  49. package/dist/types/modes/ultrathink.d.ts +7 -2
  50. package/dist/types/modes/workflow.d.ts +15 -0
  51. package/dist/types/sdk.d.ts +15 -4
  52. package/dist/types/session/agent-session.d.ts +59 -23
  53. package/dist/types/session/session-manager.d.ts +18 -0
  54. package/dist/types/session/session-storage.d.ts +6 -0
  55. package/dist/types/session/shake-types.d.ts +24 -0
  56. package/dist/types/task/executor.d.ts +2 -2
  57. package/dist/types/thinking.d.ts +39 -1
  58. package/dist/types/tiny/device.d.ts +3 -3
  59. package/dist/types/tiny/models.d.ts +34 -1
  60. package/dist/types/tiny/title-protocol.d.ts +4 -0
  61. package/dist/types/tools/index.d.ts +19 -3
  62. package/dist/types/tools/memory-edit.d.ts +1 -1
  63. package/examples/sdk/09-api-keys-and-oauth.ts +2 -2
  64. package/package.json +10 -10
  65. package/src/auto-thinking/classifier.ts +180 -0
  66. package/src/autoresearch/tools/run-experiment.ts +45 -113
  67. package/src/cli/args.ts +39 -16
  68. package/src/cli/extension-flags.ts +48 -0
  69. package/src/cli/plugin-cli.ts +11 -2
  70. package/src/config/config-file.ts +98 -13
  71. package/src/config/file-lock.ts +60 -17
  72. package/src/config/keybindings.ts +78 -27
  73. package/src/config/model-registry.ts +7 -1
  74. package/src/config/settings-schema.ts +118 -71
  75. package/src/config/settings.ts +12 -0
  76. package/src/edit/hashline/diff.ts +87 -22
  77. package/src/edit/renderer.ts +16 -12
  78. package/src/edit/streaming.ts +17 -6
  79. package/src/eval/__tests__/agent-bridge.test.ts +433 -0
  80. package/src/eval/__tests__/budget-bridge.test.ts +69 -0
  81. package/src/eval/__tests__/idle-timeout.test.ts +66 -0
  82. package/src/eval/__tests__/shared-executors.test.ts +53 -0
  83. package/src/eval/agent-bridge.ts +295 -0
  84. package/src/eval/backend.ts +17 -2
  85. package/src/eval/budget-bridge.ts +48 -0
  86. package/src/eval/idle-timeout.ts +80 -0
  87. package/src/eval/js/executor.ts +35 -7
  88. package/src/eval/js/index.ts +2 -1
  89. package/src/eval/js/shared/local-module-loader.ts +75 -10
  90. package/src/eval/js/shared/prelude.txt +85 -1
  91. package/src/eval/js/tool-bridge.ts +9 -0
  92. package/src/eval/py/executor.ts +41 -14
  93. package/src/eval/py/index.ts +2 -1
  94. package/src/eval/py/prelude.py +132 -1
  95. package/src/exec/bash-executor.ts +2 -3
  96. package/src/extensibility/custom-tools/types.ts +2 -2
  97. package/src/extensibility/extensions/runner.ts +12 -2
  98. package/src/extensibility/plugins/git-url.ts +90 -4
  99. package/src/extensibility/plugins/manager.ts +103 -7
  100. package/src/extensibility/shared-events.ts +2 -2
  101. package/src/internal-urls/docs-index.generated.ts +88 -88
  102. package/src/main.ts +50 -56
  103. package/src/memory-backend/index.ts +1 -1
  104. package/src/memory-backend/resolve.ts +3 -3
  105. package/src/memory-backend/types.ts +3 -3
  106. package/src/{mnemosyne → mnemopi}/backend.ts +70 -70
  107. package/src/{mnemosyne → mnemopi}/config.ts +36 -36
  108. package/src/{mnemosyne → mnemopi}/state.ts +67 -67
  109. package/src/modes/acp/acp-agent.ts +13 -3
  110. package/src/modes/components/agent-dashboard.ts +6 -6
  111. package/src/modes/components/custom-editor.ts +4 -11
  112. package/src/modes/components/extensions/state-manager.ts +3 -4
  113. package/src/modes/components/footer.ts +18 -12
  114. package/src/modes/components/hook-selector.ts +86 -20
  115. package/src/modes/components/model-selector.ts +20 -11
  116. package/src/modes/components/oauth-selector.ts +93 -21
  117. package/src/modes/components/omfg-panel.ts +141 -0
  118. package/src/modes/components/settings-defs.ts +9 -2
  119. package/src/modes/components/settings-selector.ts +4 -1
  120. package/src/modes/components/status-line/segments.ts +13 -5
  121. package/src/modes/components/tips.txt +2 -1
  122. package/src/modes/components/tool-execution.ts +38 -19
  123. package/src/modes/components/tree-selector.ts +4 -3
  124. package/src/modes/components/user-message-selector.ts +94 -19
  125. package/src/modes/components/user-message.ts +8 -1
  126. package/src/modes/controllers/command-controller.ts +57 -0
  127. package/src/modes/controllers/event-controller.ts +65 -3
  128. package/src/modes/controllers/input-controller.ts +14 -11
  129. package/src/modes/controllers/omfg-controller.ts +283 -0
  130. package/src/modes/controllers/omfg-rule.ts +647 -0
  131. package/src/modes/controllers/selector-controller.ts +21 -6
  132. package/src/modes/gradient-highlight.ts +23 -6
  133. package/src/modes/interactive-mode.ts +41 -7
  134. package/src/modes/magic-keywords.ts +20 -0
  135. package/src/modes/markdown-prose.ts +247 -0
  136. package/src/modes/orchestrate.ts +17 -11
  137. package/src/modes/shared.ts +3 -11
  138. package/src/modes/theme/theme.ts +6 -0
  139. package/src/modes/turn-budget.ts +31 -0
  140. package/src/modes/types.ts +7 -1
  141. package/src/modes/ultrathink.ts +16 -10
  142. package/src/modes/utils/hotkeys-markdown.ts +1 -1
  143. package/src/modes/workflow.ts +42 -0
  144. package/src/prompts/system/auto-thinking-difficulty-local.md +14 -0
  145. package/src/prompts/system/auto-thinking-difficulty.md +12 -0
  146. package/src/prompts/system/omfg-user.md +51 -0
  147. package/src/prompts/system/system-prompt.md +1 -0
  148. package/src/prompts/system/workflow-notice.md +70 -0
  149. package/src/prompts/tools/eval.md +13 -1
  150. package/src/prompts/tools/memory-edit.md +1 -1
  151. package/src/sdk.ts +86 -38
  152. package/src/session/agent-session.ts +558 -80
  153. package/src/session/session-manager.ts +32 -0
  154. package/src/session/session-storage.ts +68 -8
  155. package/src/session/shake-types.ts +44 -0
  156. package/src/slash-commands/builtin-registry.ts +41 -16
  157. package/src/task/executor.ts +3 -3
  158. package/src/task/index.ts +6 -6
  159. package/src/thinking.ts +73 -1
  160. package/src/tiny/device.ts +4 -10
  161. package/src/tiny/models.ts +54 -2
  162. package/src/tiny/title-protocol.ts +11 -1
  163. package/src/tiny/worker.ts +19 -7
  164. package/src/tools/eval.ts +202 -26
  165. package/src/tools/grouped-file-output.ts +9 -2
  166. package/src/tools/index.ts +17 -5
  167. package/src/tools/memory-edit.ts +4 -4
  168. package/src/tools/memory-recall.ts +5 -5
  169. package/src/tools/memory-reflect.ts +5 -5
  170. package/src/tools/memory-retain.ts +4 -4
  171. package/src/tools/render-utils.ts +2 -1
  172. package/src/tools/search.ts +480 -76
  173. package/dist/types/mnemosyne/backend.d.ts +0 -4
  174. package/dist/types/mnemosyne/config.d.ts +0 -29
  175. package/dist/types/mnemosyne/state.d.ts +0 -72
  176. /package/dist/types/{mnemosyne → mnemopi}/index.d.ts +0 -0
  177. /package/src/{mnemosyne → mnemopi}/index.ts +0 -0
@@ -13,12 +13,13 @@ import { type FileSlashCommand } from "./extensibility/slash-commands";
13
13
  import type { HindsightSessionState } from "./hindsight/state";
14
14
  import { type LocalProtocolOptions } from "./internal-urls";
15
15
  import { MCPManager, type MCPToolsLoadResult } from "./mcp";
16
- import { type MnemosyneSessionState } from "./mnemosyne/state";
16
+ import { type MnemopiSessionState } from "./mnemopi/state";
17
17
  import { AgentRegistry } from "./registry/agent-registry";
18
18
  import { AgentSession } from "./session/agent-session";
19
19
  import { AuthStorage } from "./session/auth-storage";
20
20
  import { SessionManager } from "./session/session-manager";
21
21
  import { type BuildSystemPromptResult } from "./system-prompt";
22
+ import { type ConfiguredThinkingLevel } from "./thinking";
22
23
  import { BashTool, BUILTIN_TOOLS, createTools, EditTool, EvalTool, FindTool, HIDDEN_TOOLS, type LspStartupServerInfo, loadSshTool, ReadTool, ResolveTool, SearchTool, type Tool, type ToolSession, WebSearchTool, WriteTool } from "./tools";
23
24
  import { EventBus } from "./utils/event-bus";
24
25
  import { type WorkspaceTree } from "./workspace-tree";
@@ -39,7 +40,7 @@ export interface CreateAgentSessionOptions {
39
40
  * Used when model lookup is deferred because extension-provided models aren't registered yet. */
40
41
  modelPattern?: string;
41
42
  /** Thinking selector. Default: from settings, else unset */
42
- thinkingLevel?: ThinkingLevel;
43
+ thinkingLevel?: ConfiguredThinkingLevel;
43
44
  /** Models available for cycling (Ctrl+P in interactive mode) */
44
45
  scopedModels?: Array<{
45
46
  model: Model;
@@ -98,8 +99,8 @@ export interface CreateAgentSessionOptions {
98
99
  taskDepth?: number;
99
100
  /** Parent Hindsight state to alias for subagent memory tools. */
100
101
  parentHindsightSessionState?: HindsightSessionState;
101
- /** Parent Mnemosyne state to alias for subagent memory tools. */
102
- parentMnemosyneSessionState?: MnemosyneSessionState;
102
+ /** Parent Mnemopi state to alias for subagent memory tools. */
103
+ parentMnemopiSessionState?: MnemopiSessionState;
103
104
  /** Pre-allocated agent identity for IRC routing. Default: "0-Main" for top-level, parentTaskPrefix-derived for sub. */
104
105
  agentId?: string;
105
106
  /** Display name for the agent in IRC. Default: "main" or "sub". */
@@ -175,6 +176,16 @@ export declare function discoverAuthStorage(agentDir?: string): Promise<AuthStor
175
176
  * Discover extensions from cwd.
176
177
  */
177
178
  export declare function discoverExtensions(cwd?: string): Promise<LoadExtensionsResult>;
179
+ /**
180
+ * Load the discovered/configured extensions for a session — everything {@link
181
+ * createAgentSession} would load except the inline factory extensions it appends
182
+ * itself. Extracted so the CLI can resolve extension-registered flags (and thus
183
+ * classify `@file` arguments extension-aware) *before* a session — and its
184
+ * terminal breadcrumb — is created, then hand the result back through
185
+ * {@link CreateAgentSessionOptions.preloadedExtensions} so the work is not
186
+ * repeated. Keep this the single source of the discovery branch logic.
187
+ */
188
+ export declare function loadSessionExtensions(options: Pick<CreateAgentSessionOptions, "disableExtensionDiscovery" | "additionalExtensionPaths">, cwd: string, settings: Settings, eventBus: EventBus): Promise<LoadExtensionsResult>;
178
189
  /**
179
190
  * Discover skills from cwd and agentDir.
180
191
  */
@@ -14,8 +14,9 @@
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";
18
- import type { AssistantMessage, Effort, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
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";
19
+ import { Effort } from "@oh-my-pi/pi-ai";
19
20
  import { type AsyncJob, type AsyncJobDeliveryState, AsyncJobManager } from "../async";
20
21
  import type { Rule } from "../capability/rule";
21
22
  import { type ModelRegistry } from "../config/model-registry";
@@ -35,26 +36,28 @@ import { type FileSlashCommand } from "../extensibility/slash-commands";
35
36
  import { GoalRuntime } from "../goals/runtime";
36
37
  import type { Goal, GoalModeState } from "../goals/state";
37
38
  import type { HindsightSessionState } from "../hindsight/state";
38
- import { type MnemosyneSessionState } from "../mnemosyne/state";
39
+ import { type MnemopiSessionState } from "../mnemopi/state";
39
40
  import type { PlanModeState } from "../plan-mode/state";
40
41
  import { type AgentRegistry } from "../registry/agent-registry";
41
42
  import { type SecretObfuscator } from "../secrets/obfuscator";
43
+ import { type ConfiguredThinkingLevel } from "../thinking";
42
44
  import { type DiscoverableTool, type DiscoverableToolSearchIndex } from "../tool-discovery/tool-index";
43
45
  import type { CheckpointState } from "../tools/checkpoint";
44
46
  import { type TodoItem, type TodoPhase } from "../tools/todo-write";
45
47
  import type { ClientBridge } from "./client-bridge";
46
48
  import { type CustomMessage } from "./messages";
47
49
  import type { BranchSummaryEntry, NewSessionOptions, SessionContext, SessionManager } from "./session-manager";
50
+ import type { ShakeMode, ShakeResult } from "./shake-types";
48
51
  import { ToolChoiceQueue } from "./tool-choice-queue";
49
52
  import { YieldQueue } from "./yield-queue";
50
53
  /** Session-specific events that extend the core AgentEvent */
51
54
  export type AgentSessionEvent = AgentEvent | {
52
55
  type: "auto_compaction_start";
53
56
  reason: "threshold" | "overflow" | "idle" | "incomplete";
54
- action: "context-full" | "handoff";
57
+ action: "context-full" | "handoff" | "shake" | "shake-summary";
55
58
  } | {
56
59
  type: "auto_compaction_end";
57
- action: "context-full" | "handoff";
60
+ action: "context-full" | "handoff" | "shake" | "shake-summary";
58
61
  result: CompactionResult | undefined;
59
62
  aborted: boolean;
60
63
  willRetry: boolean;
@@ -102,6 +105,10 @@ export type AgentSessionEvent = AgentEvent | {
102
105
  } | {
103
106
  type: "thinking_level_changed";
104
107
  thinkingLevel: ThinkingLevel | undefined;
108
+ /** The user-configured selector when it differs from the effective level (e.g. `auto`). */
109
+ configured?: ConfiguredThinkingLevel;
110
+ /** The level `auto` resolved to this turn, once classified. */
111
+ resolved?: Effort;
105
112
  } | {
106
113
  type: "goal_updated";
107
114
  goal: Goal | null;
@@ -115,6 +122,7 @@ export interface AsyncJobSnapshot {
115
122
  recent: AsyncJobSnapshotItem[];
116
123
  delivery: AsyncJobDeliveryState;
117
124
  }
125
+ export type { ShakeMode, ShakeResult };
118
126
  export interface AgentSessionConfig {
119
127
  agent: Agent;
120
128
  sessionManager: SessionManager;
@@ -125,7 +133,7 @@ export interface AgentSessionConfig {
125
133
  thinkingLevel?: ThinkingLevel;
126
134
  }>;
127
135
  /** Initial session thinking selector. */
128
- thinkingLevel?: ThinkingLevel;
136
+ thinkingLevel?: ConfiguredThinkingLevel;
129
137
  /** Prompt templates for expansion */
130
138
  promptTemplates?: PromptTemplate[];
131
139
  /** File-based slash commands for expansion */
@@ -309,7 +317,7 @@ export declare class AgentSession {
309
317
  get providerSessionState(): Map<string, ProviderSessionState>;
310
318
  getHindsightSessionState(): HindsightSessionState | undefined;
311
319
  setHindsightSessionState(state: HindsightSessionState | undefined): HindsightSessionState | undefined;
312
- getMnemosyneSessionState(): MnemosyneSessionState | undefined;
320
+ getMnemopiSessionState(): MnemopiSessionState | undefined;
313
321
  /** TTSR manager for time-traveling stream rules */
314
322
  get ttsrManager(): TtsrManager | undefined;
315
323
  /** Whether a TTSR abort is pending (stream was aborted to inject rules) */
@@ -364,8 +372,14 @@ export declare class AgentSession {
364
372
  get state(): AgentState;
365
373
  /** Current model (may be undefined if not yet selected) */
366
374
  get model(): Model | undefined;
367
- /** Current thinking level */
375
+ /** Effective thinking level applied to the agent (the resolved level when `auto`). */
368
376
  get thinkingLevel(): ThinkingLevel | undefined;
377
+ /** The selector the user configured: `auto` when auto mode is active, else the effective level. */
378
+ configuredThinkingLevel(): ConfiguredThinkingLevel | undefined;
379
+ /** True when `auto` thinking mode is active. */
380
+ get isAutoThinking(): boolean;
381
+ /** The level `auto` resolved to for the current turn (undefined until classified). */
382
+ autoResolvedThinkingLevel(): Effort | undefined;
369
383
  get serviceTier(): ServiceTier | undefined;
370
384
  /** Whether agent is currently streaming a response */
371
385
  get isStreaming(): boolean;
@@ -603,12 +617,13 @@ export declare class AgentSession {
603
617
  fork(): Promise<boolean>;
604
618
  /**
605
619
  * Set model directly.
606
- * Validates API key, saves to session and settings.
620
+ * Validates API key and saves to the active session. Persists settings only when requested.
607
621
  * @throws Error if no API key available for the model
608
622
  */
609
623
  setModel(model: Model, role?: string, options?: {
610
624
  selector?: string;
611
625
  thinkingLevel?: ThinkingLevel;
626
+ persist?: boolean;
612
627
  }): Promise<void>;
613
628
  /**
614
629
  * Set model temporarily (for this session only).
@@ -635,34 +650,33 @@ export declare class AgentSession {
635
650
  */
636
651
  getRoleModelCycle(roleOrder: readonly string[]): RoleModelCycle | undefined;
637
652
  /**
638
- * Apply a resolved role model as the active model, persisting the choice to
639
- * settings under its role. Mirrors the non-temporary branch of
640
- * {@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.
641
655
  */
642
656
  applyRoleModel(entry: ResolvedRoleModel): Promise<void>;
643
657
  /**
644
658
  * Cycle through configured role models in a fixed order.
645
- * Skips missing roles.
659
+ * Skips missing roles and changes only the active session model.
646
660
  * @param roleOrder - Order of roles to cycle through (e.g., ["slow", "default", "smol"])
647
- * @param options - Optional settings: `temporary` to not persist to settings
661
+ * @param direction - "forward" (default) or "backward"
648
662
  */
649
- cycleRoleModels(roleOrder: readonly string[], options?: {
650
- temporary?: boolean;
651
- }): Promise<RoleModelCycleResult | undefined>;
663
+ cycleRoleModels(roleOrder: readonly string[], direction?: "forward" | "backward"): Promise<RoleModelCycleResult | undefined>;
652
664
  /**
653
665
  * Get all available models with valid API keys.
654
666
  */
655
667
  getAvailableModels(): Model[];
656
668
  /**
657
- * Set thinking level.
658
- * Saves the effective metadata-clamped level to session and settings only if it changes.
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.
659
673
  */
660
- setThinkingLevel(level: ThinkingLevel | undefined, persist?: boolean): void;
674
+ setThinkingLevel(level: ConfiguredThinkingLevel | undefined, persist?: boolean): void;
661
675
  /**
662
- * Cycle to next thinking level.
663
- * @returns New level, or undefined if model doesn't support thinking
676
+ * Cycle to next thinking level: off → auto → minimal..xhigh → off.
677
+ * @returns New selector, or undefined if model doesn't support thinking
664
678
  */
665
- cycleThinkingLevel(): ThinkingLevel | undefined;
679
+ cycleThinkingLevel(): ConfiguredThinkingLevel | undefined;
666
680
  /**
667
681
  * True when *any* fast-mode-granting service tier is configured, regardless
668
682
  * of whether the active model's provider actually realizes it. Used by the
@@ -717,6 +731,27 @@ export declare class AgentSession {
717
731
  dropImages(): Promise<{
718
732
  removed: number;
719
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>;
720
755
  /**
721
756
  * Manually compact the session context.
722
757
  * Aborts current agent operation first.
@@ -867,6 +902,7 @@ export declare class AgentSession {
867
902
  promptText: string;
868
903
  onTextDelta?: (delta: string) => void;
869
904
  signal?: AbortSignal;
905
+ dedupeReply?: boolean;
870
906
  }): Promise<{
871
907
  replyText: string;
872
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 { MnemosyneSessionState } from "../mnemosyne/state";
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
- parentMnemosyneSessionState?: MnemosyneSessionState;
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
  /**
@@ -1,5 +1,5 @@
1
1
  import { type ResolvedThinkingLevel, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import { type Effort, type Model } from "@oh-my-pi/pi-ai";
2
+ import { Effort, type Model } from "@oh-my-pi/pi-ai";
3
3
  /**
4
4
  * Metadata used to render thinking selector values in the coding-agent UI.
5
5
  */
@@ -28,3 +28,41 @@ export declare function toReasoningEffort(level: ThinkingLevel | undefined): Eff
28
28
  * Resolves a selector against the current model while preserving explicit "off".
29
29
  */
30
30
  export declare function resolveThinkingLevelForModel(model: Model | undefined, level: ThinkingLevel | undefined): ResolvedThinkingLevel | undefined;
31
+ /**
32
+ * Sentinel selector for the coding-agent "auto" thinking mode. Kept entirely
33
+ * inside the coding-agent layer: it is never an {@link Effort} or
34
+ * {@link ThinkingLevel}, so provider mapping/clamping keeps seeing concrete
35
+ * efforts. The session resolves `auto` to a concrete effort each turn.
36
+ */
37
+ export declare const AUTO_THINKING: "auto";
38
+ /** A thinking selector as configured by the user — a concrete level or `auto`. */
39
+ export type ConfiguredThinkingLevel = ThinkingLevel | typeof AUTO_THINKING;
40
+ /** Metadata used to render the `auto` selector value alongside concrete levels. */
41
+ export interface ConfiguredThinkingLevelMetadata {
42
+ value: ConfiguredThinkingLevel;
43
+ label: string;
44
+ description: string;
45
+ }
46
+ /**
47
+ * Parses a configured thinking selector, accepting `auto` in addition to every
48
+ * value {@link parseThinkingLevel} accepts. {@link parseThinkingLevel} itself
49
+ * stays strict so model-suffix parsing (`model:high`) keeps rejecting `auto`.
50
+ */
51
+ export declare function parseConfiguredThinkingLevel(value: string | null | undefined): ConfiguredThinkingLevel | undefined;
52
+ /** Returns display metadata for a configured selector, including `auto`. */
53
+ export declare function getConfiguredThinkingLevelMetadata(level: ConfiguredThinkingLevel): ConfiguredThinkingLevelMetadata;
54
+ /**
55
+ * Resolves an auto-classified effort against the active model's supported
56
+ * range. Unlike {@link clampThinkingLevelForModel}, `auto` never resolves below
57
+ * {@link Effort.Low}: the eligible pool is the model's supported efforts at or
58
+ * above Low (falling back to the full supported set only when the model maxes
59
+ * out below Low). Within that pool the request snaps to the highest level not
60
+ * exceeding it, or the pool minimum when the request is below the pool.
61
+ */
62
+ export declare function clampAutoThinkingEffort(model: Model | undefined, effort: Effort): Effort;
63
+ /**
64
+ * The provisional concrete level shown while `auto` is configured but before a
65
+ * turn has been classified. Prefers the model's `defaultLevel`, otherwise High,
66
+ * clamped into the auto range. Returns `undefined` for non-reasoning models.
67
+ */
68
+ export declare function resolveProvisionalAutoLevel(model: Model | undefined): Effort | undefined;
@@ -7,7 +7,7 @@ export interface TinyModelDevicePreference {
7
7
  export declare function normalizeTinyModelDevice(value: string | undefined): TinyModelDevice | undefined;
8
8
  export declare function resolveTinyModelDevicePreference(value?: string | undefined): TinyModelDevicePreference;
9
9
  export declare function tinyModelDeviceLoadOrder(preference: TinyModelDevicePreference): readonly TinyModelDevice[];
10
- /** Sentinel `providers.tinyModelDevice` value meaning "use the built-in platform default". */
10
+ /** Sentinel `providers.tinyModelDevice` value meaning "use the built-in CPU default". */
11
11
  export declare const TINY_MODEL_DEVICE_DEFAULT = "default";
12
12
  /** Accepted values for the `providers.tinyModelDevice` setting (validation + UI). */
13
13
  export declare const TINY_MODEL_DEVICE_SETTING_VALUES: readonly ["default", "gpu", "cpu", "metal", "webgpu", "cuda", "dml", "coreml", "auto", "wasm", "webnn", "webnn-gpu", "webnn-cpu", "webnn-npu"];
@@ -15,7 +15,7 @@ export declare const TINY_MODEL_DEVICE_SETTING_VALUES: readonly ["default", "gpu
15
15
  export declare const TINY_MODEL_DEVICE_SETTING_OPTIONS: readonly [{
16
16
  readonly value: "default";
17
17
  readonly label: "Default";
18
- readonly description: "DirectML on Windows, CUDA on Linux x64, CPU elsewhere";
18
+ readonly description: "CPU-only inference";
19
19
  }, {
20
20
  readonly value: "gpu";
21
21
  readonly label: "GPU";
@@ -72,7 +72,7 @@ export declare const TINY_MODEL_DEVICE_SETTING_OPTIONS: readonly [{
72
72
  /**
73
73
  * Map a `providers.tinyModelDevice` setting value onto a `PI_TINY_DEVICE` env
74
74
  * value for the worker. Returns `undefined` for the default sentinel so the
75
- * worker keeps its built-in platform default; the worker still validates the
75
+ * worker keeps its built-in CPU default; the worker still validates the
76
76
  * forwarded value via {@link normalizeTinyModelDevice}.
77
77
  */
78
78
  export declare function tinyModelDeviceSettingToEnv(value: string | undefined): string | undefined;
@@ -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 Mnemosyne memory tasks (fact extraction + consolidation).
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. */
@@ -183,3 +197,22 @@ export declare const TINY_LOCAL_MODELS: readonly [{
183
197
  readonly description: "Fastest load; solid all-rounder, slightly noisier extraction labels.";
184
198
  readonly contextNote: "Use when local startup cost is the priority.";
185
199
  }];
200
+ /**
201
+ * Difficulty-classifier model for the `auto` thinking level. Defaults to the
202
+ * online smol path; the local options reuse the memory-model registry because
203
+ * the shared worker's `complete()` only accepts memory local keys, and the
204
+ * 1B+ memory models classify coding difficulty far more reliably than the
205
+ * sub-1B title models.
206
+ */
207
+ export declare const ONLINE_AUTO_THINKING_MODEL_KEY = "online";
208
+ export declare const AUTO_THINKING_MODEL_VALUES: readonly ["online", "qwen3-1.7b", "gemma-3-1b", "qwen2.5-1.5b", "lfm2-1.2b"];
209
+ export type AutoThinkingModelKey = TinyMemoryModelKey;
210
+ export declare const AUTO_THINKING_MODEL_OPTIONS: ({
211
+ value: "online";
212
+ label: string;
213
+ description: string;
214
+ } | {
215
+ value: "gemma-3-1b" | "lfm2-1.2b" | "qwen2.5-1.5b" | "qwen3-1.7b";
216
+ label: "Gemma 3 1B" | "LFM2 1.2B" | "Qwen2.5 1.5B" | "Qwen3 1.7B";
217
+ 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.";
218
+ })[];
@@ -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 { MnemosyneSessionState } from "../mnemosyne/state";
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 Mnemosyne runtime state for this agent session. */
111
- getMnemosyneSessionState?: () => MnemosyneSessionState | undefined;
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 Mnemosyne memories";
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 = new ModelRegistry(customAuthStorage, "/tmp/my-app/models.json");
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 = new ModelRegistry(authStorage); // null = no models.json
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.1",
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.1",
51
- "@oh-my-pi/omp-stats": "15.7.1",
52
- "@oh-my-pi/pi-agent-core": "15.7.1",
53
- "@oh-my-pi/pi-ai": "15.7.1",
54
- "@oh-my-pi/pi-mnemosyne": "15.7.1",
55
- "@oh-my-pi/pi-natives": "15.7.1",
56
- "@oh-my-pi/pi-tui": "15.7.1",
57
- "@oh-my-pi/pi-utils": "15.7.1",
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",