@oh-my-pi/pi-coding-agent 17.0.1 → 17.0.2

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 (126) hide show
  1. package/CHANGELOG.md +92 -20
  2. package/dist/cli.js +3485 -3448
  3. package/dist/types/advisor/config.d.ts +14 -6
  4. package/dist/types/advisor/runtime.d.ts +20 -11
  5. package/dist/types/autolearn/controller.d.ts +1 -0
  6. package/dist/types/config/model-discovery.d.ts +17 -0
  7. package/dist/types/config/model-resolver.d.ts +6 -2
  8. package/dist/types/config/settings-schema.d.ts +32 -7
  9. package/dist/types/config/settings.d.ts +50 -0
  10. package/dist/types/cursor.d.ts +11 -0
  11. package/dist/types/discovery/helpers.d.ts +5 -2
  12. package/dist/types/exec/bash-executor.d.ts +2 -0
  13. package/dist/types/extensibility/extensions/managed-timers.d.ts +15 -0
  14. package/dist/types/extensibility/extensions/runner.d.ts +7 -0
  15. package/dist/types/extensibility/extensions/types.d.ts +18 -0
  16. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +40 -0
  17. package/dist/types/extensibility/shared-events.d.ts +6 -0
  18. package/dist/types/extensibility/utils.d.ts +2 -2
  19. package/dist/types/mcp/transports/stdio.d.ts +13 -1
  20. package/dist/types/modes/components/advisor-config.d.ts +8 -1
  21. package/dist/types/modes/components/hook-editor.d.ts +7 -0
  22. package/dist/types/modes/components/model-hub.d.ts +5 -2
  23. package/dist/types/modes/components/session-selector.d.ts +2 -0
  24. package/dist/types/modes/controllers/command-controller.d.ts +8 -0
  25. package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
  26. package/dist/types/modes/print-mode.d.ts +1 -1
  27. package/dist/types/modes/warp-events.d.ts +24 -0
  28. package/dist/types/modes/warp-events.test.d.ts +1 -0
  29. package/dist/types/plan-mode/model-transition.d.ts +47 -0
  30. package/dist/types/plan-mode/model-transition.test.d.ts +1 -0
  31. package/dist/types/registry/agent-lifecycle.d.ts +26 -1
  32. package/dist/types/sdk.d.ts +13 -2
  33. package/dist/types/session/agent-session.d.ts +34 -10
  34. package/dist/types/session/session-history-format.d.ts +10 -0
  35. package/dist/types/session/session-manager.d.ts +14 -0
  36. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +9 -0
  37. package/dist/types/task/label.d.ts +1 -1
  38. package/dist/types/telemetry-export.d.ts +34 -9
  39. package/dist/types/tools/approval.d.ts +8 -0
  40. package/dist/types/tools/bash.d.ts +2 -0
  41. package/dist/types/tools/essential-tools.d.ts +29 -0
  42. package/dist/types/tools/image-gen.d.ts +2 -1
  43. package/dist/types/tools/index.d.ts +1 -0
  44. package/dist/types/tools/xdev.d.ts +11 -2
  45. package/dist/types/utils/title-generator.d.ts +2 -1
  46. package/dist/types/web/search/providers/kimi.d.ts +4 -1
  47. package/dist/types/web/search/types.d.ts +1 -1
  48. package/package.json +21 -16
  49. package/src/advisor/__tests__/advisor.test.ts +1304 -42
  50. package/src/advisor/__tests__/config.test.ts +58 -2
  51. package/src/advisor/config.ts +76 -24
  52. package/src/advisor/runtime.ts +445 -92
  53. package/src/autolearn/controller.ts +23 -28
  54. package/src/cli.ts +5 -1
  55. package/src/config/model-discovery.ts +81 -21
  56. package/src/config/model-registry.ts +25 -6
  57. package/src/config/model-resolver.ts +14 -7
  58. package/src/config/settings-schema.ts +42 -6
  59. package/src/config/settings.ts +405 -25
  60. package/src/cursor.ts +20 -3
  61. package/src/debug/report-bundle.ts +40 -4
  62. package/src/discovery/helpers.ts +28 -5
  63. package/src/exec/bash-executor.ts +14 -5
  64. package/src/extensibility/custom-tools/loader.ts +3 -3
  65. package/src/extensibility/custom-tools/wrapper.ts +2 -1
  66. package/src/extensibility/extensions/loader.ts +3 -3
  67. package/src/extensibility/extensions/managed-timers.ts +83 -0
  68. package/src/extensibility/extensions/runner.ts +26 -0
  69. package/src/extensibility/extensions/types.ts +18 -0
  70. package/src/extensibility/extensions/wrapper.ts +2 -1
  71. package/src/extensibility/hooks/loader.ts +3 -3
  72. package/src/extensibility/legacy-pi-coding-agent-shim.ts +96 -1
  73. package/src/extensibility/plugins/legacy-pi-compat.ts +225 -22
  74. package/src/extensibility/plugins/manager.ts +2 -2
  75. package/src/extensibility/shared-events.ts +6 -0
  76. package/src/extensibility/utils.ts +91 -25
  77. package/src/irc/bus.ts +22 -3
  78. package/src/launch/broker.ts +3 -2
  79. package/src/launch/client.ts +2 -2
  80. package/src/launch/presence.ts +2 -2
  81. package/src/lsp/client.ts +1 -1
  82. package/src/main.ts +11 -8
  83. package/src/mcp/manager.ts +9 -3
  84. package/src/mcp/transports/stdio.ts +103 -23
  85. package/src/modes/components/advisor-config.ts +65 -3
  86. package/src/modes/components/ask-dialog.ts +1 -1
  87. package/src/modes/components/hook-editor.ts +18 -3
  88. package/src/modes/components/model-hub.ts +138 -42
  89. package/src/modes/components/session-selector.ts +4 -0
  90. package/src/modes/components/status-line/component.test.ts +1 -0
  91. package/src/modes/components/status-line/segments.ts +21 -6
  92. package/src/modes/controllers/command-controller.ts +167 -47
  93. package/src/modes/controllers/event-controller.ts +5 -0
  94. package/src/modes/controllers/extension-ui-controller.ts +4 -22
  95. package/src/modes/controllers/input-controller.ts +12 -12
  96. package/src/modes/controllers/selector-controller.ts +191 -31
  97. package/src/modes/interactive-mode.ts +139 -54
  98. package/src/modes/print-mode.ts +3 -3
  99. package/src/modes/rpc/host-tools.ts +2 -1
  100. package/src/modes/rpc/rpc-mode.ts +19 -4
  101. package/src/modes/warp-events.test.ts +794 -0
  102. package/src/modes/warp-events.ts +232 -0
  103. package/src/plan-mode/model-transition.test.ts +60 -0
  104. package/src/plan-mode/model-transition.ts +51 -0
  105. package/src/registry/agent-lifecycle.ts +133 -18
  106. package/src/sdk.ts +221 -42
  107. package/src/session/agent-session.ts +1285 -348
  108. package/src/session/session-history-format.ts +20 -5
  109. package/src/session/session-manager.ts +48 -0
  110. package/src/slash-commands/builtin-registry.ts +7 -0
  111. package/src/slash-commands/helpers/active-oauth-account.ts +16 -0
  112. package/src/task/executor.ts +1 -1
  113. package/src/task/label.ts +2 -0
  114. package/src/telemetry-export.ts +453 -97
  115. package/src/tools/approval.ts +11 -0
  116. package/src/tools/bash.ts +71 -38
  117. package/src/tools/essential-tools.ts +45 -0
  118. package/src/tools/gh.ts +169 -2
  119. package/src/tools/image-gen.ts +69 -7
  120. package/src/tools/index.ts +7 -5
  121. package/src/tools/read.ts +48 -3
  122. package/src/tools/write.ts +22 -4
  123. package/src/tools/xdev.ts +14 -3
  124. package/src/utils/title-generator.ts +15 -4
  125. package/src/web/search/providers/kimi.ts +18 -12
  126. package/src/web/search/types.ts +6 -1
@@ -50,7 +50,9 @@ export declare class SelectorController {
50
50
  showCopySelector(): void;
51
51
  showTreeSelector(): void;
52
52
  showSessionSelector(): Promise<void>;
53
- handleResumeSession(sessionPath: string): Promise<void>;
53
+ handleResumeSession(sessionPath: string, options?: {
54
+ settingsFlushed?: boolean;
55
+ }): Promise<boolean>;
54
56
  handleSessionDeleteCommand(): Promise<void>;
55
57
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
56
58
  showResetUsageSelector(): Promise<void>;
@@ -1,5 +1,5 @@
1
1
  import type { ImageContent } from "@oh-my-pi/pi-ai";
2
- import type { AgentSession, AgentSessionEvent } from "../session/agent-session.js";
2
+ import { type AgentSession, type AgentSessionEvent } from "../session/agent-session.js";
3
3
  /**
4
4
  * Options for print mode.
5
5
  */
@@ -0,0 +1,24 @@
1
+ import type { ExtensionFactory } from "../extensibility/extensions/types.js";
2
+ /** True when Warp has negotiated the structured CLI-agent OSC protocol. */
3
+ export declare function isWarpCliAgentProtocolActive(): boolean;
4
+ export type WarpEventValue = string | number | boolean | null | readonly WarpEventValue[] | {
5
+ readonly [key: string]: WarpEventValue | undefined;
6
+ };
7
+ /** Fields added to the Warp CLI-agent event envelope by the event bridge. */
8
+ export type WarpEvent = Readonly<Record<string, WarpEventValue | undefined>>;
9
+ export interface WarpEventEmitterOptions {
10
+ sessionId: string;
11
+ getCwd?: () => string;
12
+ }
13
+ export interface WarpEventEmitter {
14
+ emit(event: WarpEvent): void;
15
+ }
16
+ /**
17
+ * Creates the Warp event transport for a top-level interactive TUI session.
18
+ * The caller MUST enforce that install-site invariant; the sole production
19
+ * caller is gated by `isInteractive`, so ACP, RPC, print, headless, and
20
+ * subagent sessions never construct an emitter.
21
+ */
22
+ export declare function createWarpEventEmitter(options: WarpEventEmitterOptions): WarpEventEmitter | undefined;
23
+ /** Internal event bridge installed only by the top-level interactive TUI runner. */
24
+ export declare function createWarpEventBridgeExtension(): ExtensionFactory;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Plan-mode model transition policy.
3
+ *
4
+ * Plan mode drives the active session model from the `plan` role: it switches
5
+ * to the plan model on entry and restores the pre-plan model on exit. The same
6
+ * policy also runs when the `plan` role is reassigned mid-planning, so a
7
+ * correction to the wrong plan model takes effect at the next turn boundary
8
+ * (issue #5657).
9
+ *
10
+ * This module holds only the pure decision — what transition a given
11
+ * (current model, resolved role, streaming) triple implies — so the branching
12
+ * is testable without a live session or TUI. The interactive mode performs the
13
+ * resulting side effect.
14
+ */
15
+ import type { Model } from "@oh-my-pi/pi-ai";
16
+ import type { ResolvedModelRoleValue } from "../config/model-resolver.js";
17
+ import type { ConfiguredThinkingLevel } from "../thinking.js";
18
+ /** The action implied by resolving the `plan` role against the active model. */
19
+ export type PlanModelTransition =
20
+ /** Already on the plan model with no thinking-level change to apply. */
21
+ {
22
+ kind: "none";
23
+ }
24
+ /** Same model; only the plan role's explicit thinking level differs. */
25
+ | {
26
+ kind: "thinking";
27
+ thinkingLevel: ConfiguredThinkingLevel;
28
+ }
29
+ /**
30
+ * Switch to `model`. `deferred` is set when the session is mid-stream: the
31
+ * switch must wait for the current turn to end (a live `setModelTemporary`
32
+ * resets the provider session), so the caller queues it instead.
33
+ */
34
+ | {
35
+ kind: "apply";
36
+ model: Model;
37
+ thinkingLevel: ConfiguredThinkingLevel | undefined;
38
+ deferred: boolean;
39
+ };
40
+ /**
41
+ * Decide how to reconcile the active model with the resolved `plan` role.
42
+ *
43
+ * @param currentModel - The session's active model, or `undefined` before one is set.
44
+ * @param resolved - The `plan` role resolved against the available models.
45
+ * @param isStreaming - Whether the session is mid-turn (forces a deferred switch).
46
+ */
47
+ export declare function resolvePlanModelTransition(currentModel: Model | undefined, resolved: ResolvedModelRoleValue, isStreaming: boolean): PlanModelTransition;
@@ -0,0 +1 @@
1
+ export {};
@@ -8,6 +8,12 @@
8
8
  * sessionFile), and revives it on demand through
9
9
  * {@link AgentLifecycleManager.ensureLive}. Only this manager flips
10
10
  * `parked` ↔ `idle`.
11
+ *
12
+ * Park/dispose is gated against concurrent ensureLive/hub-send:
13
+ * - A disposing session is never handed out.
14
+ * - ensureLive during an in-flight park either cancels the park (session still
15
+ * live) or waits for detach+park and then revives.
16
+ * - Concurrent ensureLive/park operations coalesce per id.
11
17
  */
12
18
  import type { AgentSession } from "../session/agent-session.js";
13
19
  import { type AgentRef, AgentRegistry } from "./agent-registry.js";
@@ -46,17 +52,36 @@ export declare class AgentLifecycleManager {
46
52
  adopt(id: string, opts: AdoptOptions): void;
47
53
  /** True if the id is adopted (parked or live). */
48
54
  has(id: string): boolean;
49
- /** True while {@link park} is disposing this agent's session (lets dispose hooks distinguish park from teardown). */
55
+ /**
56
+ * True when this manager owns `registry` — i.e. its adopt/park/revive state
57
+ * describes that registry's refs. Lets a caller holding a specific registry
58
+ * (e.g. a custom-registry {@link IrcBus} that fell back to the global
59
+ * manager) skip lifecycle gating that would consult unrelated park state.
60
+ */
61
+ manages(registry: AgentRegistry): boolean;
62
+ /**
63
+ * True while {@link park} is disposing this agent's session (lets dispose
64
+ * hooks distinguish park from teardown). False once the park is cancelled
65
+ * by ensureLive or after detach+dispose completes.
66
+ */
50
67
  isParking(id: string): boolean;
51
68
  /**
52
69
  * Dispose the live session, detach it from the registry, and mark the
53
70
  * agent `parked`. No-op unless the id is adopted and live.
71
+ *
72
+ * The session is detached (and status flipped to `parked`) *before*
73
+ * `session.dispose()` so concurrent {@link ensureLive}/hub-send never
74
+ * observe or inject into a disposing session. A concurrent ensureLive that
75
+ * arrives before detach cancels the park and keeps the live session.
54
76
  */
55
77
  park(id: string): Promise<void>;
56
78
  /**
57
79
  * Return the live session, reviving from the sessionFile if parked.
58
80
  * Throws a plain Error if the id is unknown or parked without a reviver.
59
81
  * Concurrent calls share one in-flight revive.
82
+ *
83
+ * Never returns a session that is mid-dispose: an in-flight park is either
84
+ * cancelled (session still live) or awaited to completion before revive.
60
85
  */
61
86
  ensureLive(id: string): Promise<AgentSession>;
62
87
  /** Hard removal: dispose if live, unregister from registry, drop timers. */
@@ -1,5 +1,5 @@
1
- import { type AgentTelemetryConfig, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import type { Model } from "@oh-my-pi/pi-ai";
1
+ import { Agent, type AgentOptions, type AgentTelemetryConfig, type AgentTool, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
+ import type { Model, SimpleStreamOptions } from "@oh-my-pi/pi-ai";
3
3
  import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
4
4
  import { type Rule } from "./capability/rule.js";
5
5
  import { ModelRegistry } from "./config/model-registry.js";
@@ -346,6 +346,17 @@ export interface BuildSystemPromptOptions {
346
346
  * as separate entries so providers can cache prompt prefixes without concatenating blocks.
347
347
  */
348
348
  export declare function buildSystemPrompt(options?: BuildSystemPromptOptions): Promise<BuildSystemPromptResult>;
349
+ /** Dependencies used to construct an isolated auto-learn capture agent. */
350
+ export interface AutoLearnCaptureRunnerOptions {
351
+ sourceAgent: Agent;
352
+ captureTools: AgentTool[];
353
+ createAgent: (options: AgentOptions) => Agent;
354
+ onPayload?: SimpleStreamOptions["onPayload"];
355
+ onResponse?: SimpleStreamOptions["onResponse"];
356
+ createSessionId?: () => string;
357
+ }
358
+ /** Build a private capture runner over a detached message snapshot and provider session. */
359
+ export declare function createAutoLearnCaptureRunner(options: AutoLearnCaptureRunnerOptions): (content: string, signal?: AbortSignal) => Promise<void>;
349
360
  /**
350
361
  * Create an AgentSession with the specified options.
351
362
  *
@@ -18,7 +18,7 @@ import { type CompactionResult, type ShakeConfig } from "@oh-my-pi/pi-agent-core
18
18
  import type { AssistantMessage, Context, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, ServiceTier, ServiceTierByFamily, ServiceTierFamily, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
19
19
  import { Effort } from "@oh-my-pi/pi-ai";
20
20
  import { postmortem } from "@oh-my-pi/pi-utils";
21
- import { type AdvisorConfig } from "../advisor/index.js";
21
+ import { type AdvisorConfig, type AdvisorRuntimeStatus } from "../advisor/index.js";
22
22
  import { type AsyncJob, type AsyncJobDeliveryState, AsyncJobManager } from "../async/index.js";
23
23
  import type { Rule } from "../capability/rule.js";
24
24
  import type { ModelRegistry } from "../config/model-registry.js";
@@ -224,6 +224,8 @@ export interface AgentSessionConfig {
224
224
  builtInToolNames?: Iterable<string>;
225
225
  /** Update tool-session predicates that render guidance from the live active tool set. */
226
226
  setActiveToolNames?: (names: Iterable<string>) => void;
227
+ /** Register the write transport lazily when runtime xdev mounts first need it. */
228
+ ensureWriteRegistered?: () => Promise<boolean>;
227
229
  /** Current session pre-LLM message transform pipeline */
228
230
  transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => AgentMessage[] | Promise<AgentMessage[]>;
229
231
  /**
@@ -275,7 +277,8 @@ export interface AgentSessionConfig {
275
277
  xdevRegistry?: XdevRegistry;
276
278
  /** Discoverable tools mounted under `xd://` in the initial enabled set (startup partition in `sdk.ts`). */
277
279
  initialMountedXdevToolNames?: string[];
278
- requestedToolNames?: ReadonlySet<string>;
280
+ /** Explicit/effective names pinned top-level during runtime repartitioning. */
281
+ presentationPinnedToolNames?: ReadonlySet<string>;
279
282
  /**
280
283
  * Optional accessor for live MCP server instructions. Read by the session's
281
284
  * `rebuildSystemPrompt`-skip optimization to detect server-side instruction
@@ -491,15 +494,20 @@ export interface AdvisorStats {
491
494
  /** Per-advisor breakdown; one entry per active advisor (single-advisor sessions have one). */
492
495
  advisors: PerAdvisorStat[];
493
496
  }
494
- /** One advisor's slice of {@link AdvisorStats}, surfaced for the multi-advisor status panel. */
497
+ /** One advisor's slice of {@link AdvisorStats}. Active advisors carry full
498
+ * token/cost data; disabled/no-model/quota-exhausted advisors appear with
499
+ * just `name` + `status` so the status line can render a dot for every
500
+ * configured advisor. */
495
501
  export interface PerAdvisorStat {
496
502
  name: string;
497
- model: Model;
503
+ status: AdvisorRuntimeStatus;
504
+ model?: Model;
498
505
  contextWindow: number;
499
506
  contextTokens: number;
500
507
  tokens: AdvisorStats["tokens"];
501
508
  cost: number;
502
509
  messages: AdvisorStats["messages"];
510
+ sessionId?: string;
503
511
  }
504
512
  export interface FreshSessionResult {
505
513
  previousSessionId: string;
@@ -612,6 +620,8 @@ export declare class AgentSession {
612
620
  */
613
621
  subscribe(listener: AgentSessionEventListener): () => void;
614
622
  subscribeCommandMetadataChanged(listener: CommandMetadataChangedListener): () => void;
623
+ /** Run one abortable auto-learn capture outside the primary agent loop. */
624
+ runAutolearnCapture(capture: (signal: AbortSignal) => Promise<void>): Promise<void>;
615
625
  /** True once dispose() has begun; deferred background work (e.g. the deferred
616
626
  * MCP discovery task in sdk.ts) must not touch the session past this point. */
617
627
  get isDisposed(): boolean;
@@ -915,6 +925,12 @@ export declare class AgentSession {
915
925
  get skillWarnings(): readonly SkillWarning[];
916
926
  getTodoPhases(): TodoPhase[];
917
927
  setTodoPhases(phases: TodoPhase[]): void;
928
+ /**
929
+ * Generate an automatic session title tied to this session's lifecycle.
930
+ * Input and replan callers share the signal so disposal cancels provider and
931
+ * local-worker requests instead of leaving background inference alive.
932
+ */
933
+ generateTitle(firstMessage: string): Promise<string | null>;
918
934
  /** Currently-applied {@link TITLE_SYSTEM.md} override, or undefined when the
919
935
  * bundled prompt is in effect. Consumed by {@link InteractiveMode} so the
920
936
  * first-input title path and the replan refresh share one source. */
@@ -1167,8 +1183,7 @@ export declare class AgentSession {
1167
1183
  */
1168
1184
  retry(): Promise<boolean>;
1169
1185
  /**
1170
- * Execute a bash command.
1171
- * Adds result to agent context and session.
1186
+ * Execute a bash command and retain the session/branch that owned its start.
1172
1187
  * @param command The bash command to execute
1173
1188
  * @param onChunk Optional streaming callback for output
1174
1189
  * @param options.excludeFromContext If true, command output won't be sent to LLM (!! prefix)
@@ -1178,10 +1193,7 @@ export declare class AgentSession {
1178
1193
  excludeFromContext?: boolean;
1179
1194
  useUserShell?: boolean;
1180
1195
  }): Promise<BashResult>;
1181
- /**
1182
- * Record a bash execution result in session history.
1183
- * Used by executeBash and by extensions that handle bash execution themselves.
1184
- */
1196
+ /** Record a bash result supplied outside executeBash in the current ownership scope. */
1185
1197
  recordBashResult(command: string, result: BashResult, options?: {
1186
1198
  excludeFromContext?: boolean;
1187
1199
  }): void;
@@ -1471,6 +1483,18 @@ export declare class AgentSession {
1471
1483
  * (`streamFn`, `promptCacheKey`, `providerSessionState`, ...).
1472
1484
  */
1473
1485
  getAdvisorAgent(): Agent | undefined;
1486
+ /**
1487
+ * Lightweight advisor status for the status line: returns just the configured
1488
+ * flag and per-advisor name/status without computing token/cost breakdowns.
1489
+ * Avoids re-tokenizing the advisor transcript on every render frame.
1490
+ */
1491
+ getAdvisorStatusOverview(): {
1492
+ configured: boolean;
1493
+ advisors: {
1494
+ name: string;
1495
+ status: AdvisorRuntimeStatus;
1496
+ }[];
1497
+ };
1474
1498
  /**
1475
1499
  * Return structured advisor stats for the status command and TUI panel.
1476
1500
  */
@@ -1,3 +1,4 @@
1
+ import type { ToolResultMessage } from "@oh-my-pi/pi-ai";
1
2
  export interface HistoryFormatOptions {
2
3
  /** Optional H1 prepended to the transcript. */
3
4
  title?: string;
@@ -24,6 +25,15 @@ export interface HistoryFormatOptions {
24
25
  * this so it sees what changed without re-reading the file.
25
26
  */
26
27
  expandEditDiffs?: boolean;
28
+ /**
29
+ * Chunked rendering support: a caller formatting one logical transcript in
30
+ * several calls (the advisor's chunked delta render) passes a result index
31
+ * built over the WHOLE delta plus one shared consumed-id set, so a toolCall
32
+ * finds its toolResult across chunk boundaries and the result is never
33
+ * re-rendered as an orphan in a later chunk.
34
+ */
35
+ toolResultIndex?: ReadonlyMap<string, ToolResultMessage>;
36
+ consumedToolCallIds?: Set<string>;
27
37
  }
28
38
  /**
29
39
  * Hidden custom messages that inject the primary agent's operative *constraints*
@@ -48,6 +48,15 @@ export declare class SessionManager {
48
48
  /** Synchronous variant of {@link putBlob} for rebuild-only render paths. */
49
49
  putBlobSync(data: Buffer, options?: BlobPutOptions): BlobPutResult;
50
50
  captureState(): SessionManagerStateSnapshot;
51
+ /**
52
+ * Create an independent manager for the current logical session and branch.
53
+ * The clone shares the storage backend but owns its entry index and writer, so
54
+ * callers can finish session-owned work after this manager switches elsewhere.
55
+ * Set `persist` false when the original session is intentionally being dropped.
56
+ */
57
+ cloneCurrentSession(options?: {
58
+ persist?: boolean;
59
+ }): SessionManager;
51
60
  restoreState(snapshot: SessionManagerStateSnapshot): void;
52
61
  /** Switch to a different session file (resume / branch). */
53
62
  setSessionFile(sessionFile: string): Promise<void>;
@@ -140,6 +149,11 @@ export declare class SessionManager {
140
149
  * top-level entries via appendCompaction()/branchWithSummary().
141
150
  */
142
151
  appendMessage(message: Message | CustomMessage | HookMessage | BashExecutionMessage | PythonExecutionMessage | FileMentionMessage): string;
152
+ /**
153
+ * Append to a non-active branch without changing the current leaf.
154
+ * Used by work that retains ownership of a branch across tree navigation.
155
+ */
156
+ appendMessageToBranch(message: Message | CustomMessage | HookMessage | BashExecutionMessage | PythonExecutionMessage | FileMentionMessage, parentId: string | null): string;
143
157
  /** Append a thinking level change as child of current leaf, then advance leaf. Returns entry id. */
144
158
  appendThinkingLevelChange(thinkingLevel?: string, configured?: string): string;
145
159
  appendServiceTierChange(serviceTier: ServiceTierByFamily | null): string;
@@ -1,5 +1,14 @@
1
1
  import type { UsageLimit, UsageReport } from "@oh-my-pi/pi-ai";
2
2
  import type { OAuthAccountIdentity } from "../../session/auth-storage.js";
3
+ /**
4
+ * Session marker label for an active OAuth identity: the base identifier
5
+ * (email → accountId → projectId) suffixed with the organization when present
6
+ * and distinct. Same-email Anthropic multi-org accounts share the base, so the
7
+ * org suffix is the only field that tells the session's quota pool apart —
8
+ * mirrors the account-list rows (`formatUsageReportAccount`) and login success.
9
+ * Returns `undefined` when no identifier is recoverable.
10
+ */
11
+ export declare function formatActiveAccountLabel(identity: OAuthAccountIdentity | undefined): string | undefined;
3
12
  /**
4
13
  * True when a single usage-limit column belongs to the given OAuth identity.
5
14
  *
@@ -1,4 +1,4 @@
1
1
  import type { ModelRegistry } from "../config/model-registry.js";
2
2
  import type { Settings } from "../config/settings.js";
3
3
  /** Compresses a delegated assignment into a one-sentence UI label via the tiny title model — fired by the executor spawn path because the task wire schema no longer carries a `description`; null on empty input or failure. */
4
- export declare function generateTaskLabel(assignment: string, registry: ModelRegistry, settings: Settings, sessionId?: string): Promise<string | null>;
4
+ export declare function generateTaskLabel(assignment: string, registry: ModelRegistry, settings: Settings, sessionId?: string, signal?: AbortSignal): Promise<string | null>;
@@ -1,19 +1,44 @@
1
1
  /**
2
- * Whether {@link initTelemetryExport} registered a real provider. The CLI uses
3
- * this to decide whether to switch on the agent loop's telemetry config — there
4
- * is no point emitting spans into a no-op tracer.
2
+ * OTLP telemetry export bootstrap.
3
+ *
4
+ * oh-my-pi's agent core (`@oh-my-pi/pi-agent-core`) emits OpenTelemetry GenAI
5
+ * spans through the global `@opentelemetry/api` tracer, and exposes run-level
6
+ * callbacks for metrics/log pipelines. This module registers the OTLP/proto
7
+ * trace, log, and metric SDK providers when the standard `OTEL_*` endpoint env
8
+ * vars are set so `omp` can be observed by any OTLP collector without vendor
9
+ * coupling.
10
+ *
11
+ * Only the `http/protobuf` transport is supported — an
12
+ * `OTEL_EXPORTER_OTLP*_PROTOCOL` of `grpc` or `http/json` declines rather than
13
+ * misrouting protobuf payloads. The exporter line is pinned to the 0.218/2.7
14
+ * family validated under Bun; the 1.x OTLP line deadlocks when its
15
+ * `req.on("close")` handler fires after a successful export.
16
+ */
17
+ import type { AgentTelemetryConfig } from "@oh-my-pi/pi-agent-core";
18
+ /**
19
+ * Whether {@link initTelemetryExport} registered any real OTLP signal provider.
20
+ * The CLI uses this to decide whether to switch on the agent loop's telemetry
21
+ * hooks; metrics and structured logs need those callbacks even when traces are
22
+ * disabled.
5
23
  */
6
24
  export declare function isTelemetryExportEnabled(): boolean;
7
25
  /**
8
- * Register the global TracerProvider + OTLP exporter when an OTLP endpoint is
9
- * configured via env. Idempotent, and a no-op when no endpoint is set (or when
10
- * the OTEL kill-switches are engaged), so it is safe to call unconditionally at
11
- * startup.
26
+ * Merge OTLP metrics/log hooks into an existing agent telemetry config.
27
+ *
28
+ * The caller still owns content-capture policy, cost estimation, and custom
29
+ * attributes. This only appends host-level metrics/log forwarding for the
30
+ * providers registered by {@link initTelemetryExport}.
31
+ */
32
+ export declare function createTelemetryExportConfig(config: AgentTelemetryConfig | undefined): AgentTelemetryConfig | undefined;
33
+ /**
34
+ * Register global trace/log/meter providers when OTLP endpoints are configured
35
+ * through env. Idempotent, and a no-op when no signal has an endpoint (or when
36
+ * the OTEL kill-switches are engaged), so startup can call it unconditionally.
12
37
  */
13
38
  export declare function initTelemetryExport(): Promise<void>;
14
39
  /**
15
- * Flush any buffered spans to the exporter. No-op when export is disabled.
40
+ * Flush buffered spans, log records, and metrics. No-op when export is disabled.
16
41
  * Hosts embedding the agent can call this at natural boundaries (e.g. the end
17
- * of a turn) so traces surface promptly rather than on the batch interval.
42
+ * of a turn) so telemetry surfaces promptly rather than on the batch interval.
18
43
  */
19
44
  export declare function flushTelemetryExport(): Promise<void>;
@@ -17,6 +17,14 @@ export interface ResolvedApproval {
17
17
  reason?: string;
18
18
  override: boolean;
19
19
  }
20
+ /**
21
+ * Evaluate a tool's own approval declaration against `args` and return the
22
+ * resulting capability tier, defaulting to `exec` when the tool omits an
23
+ * approval. Unlike reading `tool.approval` directly, this runs function-valued
24
+ * approvals — the write tool's `xd://` gate uses it to take a mounted device's
25
+ * argument-dependent tier instead of falling back to `exec`.
26
+ */
27
+ export declare function resolveToolTier(tool: ApprovalSubject, args: unknown): ToolTier;
20
28
  /**
21
29
  * Resolve approval policy for a tool call.
22
30
  *
@@ -76,6 +76,8 @@ export interface BashToolDetails {
76
76
  wallTimeMs?: number;
77
77
  /** Exit code of a command that ran to completion but failed (non-zero). */
78
78
  exitCode?: number;
79
+ /** True when the command was killed by its timeout deadline (not a failure). */
80
+ timedOut?: boolean;
79
81
  terminalId?: string;
80
82
  async?: {
81
83
  state: "running" | "completed" | "failed";
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Canonical set of built-in tools that must stay top-level.
3
+ *
4
+ * These are the coding essentials the model always needs directly in its
5
+ * callable schema. `read`/`write` are additionally the `xd://` transport
6
+ * (`read xd://` lists devices, `write xd://<tool>` executes them), so demoting
7
+ * them under xdev makes every mounted device unreachable.
8
+ *
9
+ * Adapter boundaries (extension `registerTool`, SDK custom tools, RPC host
10
+ * tools) default an omitted `loadMode` to `"discoverable"`. A UI-only
11
+ * re-register of a built-in — e.g. wrapping `read`/`write`/`bash`/`edit`/`glob`
12
+ * to customize rendering — would then silently demote it to `discoverable` and,
13
+ * with `tools.xdev` on, unmount it from the top-level schema (issue #5764).
14
+ * {@link defaultLoadModeForToolName} pins these names to `"essential"` when the
15
+ * definition omits `loadMode`, so re-registering a built-in never demotes it.
16
+ */
17
+ import type { ToolLoadMode } from "@oh-my-pi/pi-agent-core";
18
+ /**
19
+ * Built-in tool names whose classes declare `loadMode = "essential"`. Kept in
20
+ * sync with the tool classes by `essential-tools.test.ts` (drift guard).
21
+ */
22
+ export declare const ESSENTIAL_BUILTIN_TOOL_NAMES: Record<string, true>;
23
+ /**
24
+ * Resolve a tool's presentation mode at an adapter boundary. An explicit
25
+ * `declared` mode always wins. When omitted, known essential built-in names
26
+ * default to `"essential"` (so a re-register never demotes them); everything
27
+ * else defaults to `"discoverable"`.
28
+ */
29
+ export declare function defaultLoadModeForToolName(name: string, declared?: ToolLoadMode): ToolLoadMode;
@@ -2,7 +2,7 @@ import { type Model } from "@oh-my-pi/pi-ai";
2
2
  import { type ModelRegistry } from "../config/model-registry.js";
3
3
  import type { CustomTool } from "../extensibility/custom-tools/types.js";
4
4
  export type ImageProvider = "antigravity" | "gemini" | "openai" | "openai-codex" | "openrouter" | "xai";
5
- export type ImageProviderPreference = Exclude<ImageProvider, "openai-codex"> | "auto";
5
+ export type ImageProviderPreference = ImageProvider | "auto";
6
6
  declare const responseModalitySchema: import("arktype/internal/variants/string.ts").StringType<"IMAGE" | "TEXT", {}>;
7
7
  export declare const imageGenSchema: import("arktype/internal/variants/object.ts").ObjectType<{
8
8
  subject: string;
@@ -20,6 +20,7 @@ export declare const imageGenSchema: import("arktype/internal/variants/object.ts
20
20
  data?: string | undefined;
21
21
  mime_type?: string | undefined;
22
22
  }[] | undefined;
23
+ provider?: "antigravity" | "auto" | "gemini" | "openai" | "openai-codex" | "openrouter" | "xai" | undefined;
23
24
  }, {}>;
24
25
  export type ImageGenParams = typeof imageGenSchema.infer;
25
26
  export type GeminiResponseModality = typeof responseModalitySchema.infer;
@@ -40,6 +40,7 @@ export * from "./bash.js";
40
40
  export * from "./browser.js";
41
41
  export * from "./checkpoint.js";
42
42
  export * from "./debug.js";
43
+ export * from "./essential-tools.js";
43
44
  export * from "./eval.js";
44
45
  export * from "./eval-backends.js";
45
46
  export * from "./gh.js";
@@ -37,11 +37,20 @@ import type { ToolRenderer } from "./renderers.js";
37
37
  * behind dispatch.
38
38
  */
39
39
  export declare const XDEV_KEEP_TOP_LEVEL: Record<string, true>;
40
+ /**
41
+ * Tools that carry the `xd://` transport itself and therefore can never be
42
+ * mounted as devices: `read xd://` lists/documents devices and
43
+ * `write xd://<tool>` executes them. Demoting either leaves every mounted
44
+ * device unreachable (issue #5764), so they stay top-level regardless of a
45
+ * declared `loadMode`.
46
+ */
47
+ export declare const XDEV_TRANSPORT_TOOLS: Record<string, true>;
40
48
  /**
41
49
  * Whether an enabled tool is presented under `xd://` (rather than top-level)
42
50
  * while the `xd://` transport is active. Discoverable tools mount unless they
43
- * are pinned top-level by {@link XDEV_KEEP_TOP_LEVEL}; essential tools never do.
44
- * The caller gates this on the transport being active (a session-owned
51
+ * are pinned top-level by {@link XDEV_KEEP_TOP_LEVEL} or carry the transport
52
+ * itself ({@link XDEV_TRANSPORT_TOOLS}); essential tools never do. The caller
53
+ * gates this on the transport being active (a session-owned
45
54
  * {@link XdevRegistry} existing).
46
55
  */
47
56
  export declare function isMountableUnderXdev(tool: {
@@ -14,8 +14,9 @@ import type { Settings } from "../config/settings.js";
14
14
  * resolver instead of a pre-evaluated value ensures the metadata's account_uuid
15
15
  * reflects the credential actually selected for this request.
16
16
  * @param customSystemPrompt Optional title-specific system prompt override
17
+ * @param signal Session-lifecycle cancellation for background title requests
17
18
  */
18
- export declare function generateSessionTitle(firstMessage: string, registry: ModelRegistry, settings: Settings, sessionId?: string, currentModel?: Model<Api>, metadataResolver?: (provider: string) => Record<string, unknown> | undefined, customSystemPrompt?: string): Promise<string | null>;
19
+ export declare function generateSessionTitle(firstMessage: string, registry: ModelRegistry, settings: Settings, sessionId?: string, currentModel?: Model<Api>, metadataResolver?: (provider: string) => Record<string, unknown> | undefined, customSystemPrompt?: string, signal?: AbortSignal): Promise<string | null>;
19
20
  export declare function generateTitleOnline(firstMessage: string, registry: ModelRegistry, settings: Settings, sessionId?: string, currentModel?: Model<Api>, metadataResolver?: (provider: string) => Record<string, unknown> | undefined, signal?: AbortSignal, customSystemPrompt?: string): Promise<string | null>;
20
21
  export declare function formatSessionTerminalTitle(sessionName: string | undefined, cwd?: string): string;
21
22
  /**
@@ -1,7 +1,10 @@
1
1
  /**
2
2
  * Kimi Web Search Provider
3
3
  *
4
- * Uses Moonshot Kimi Code search API to retrieve web results.
4
+ * Uses the Kimi Code search API to retrieve web results. This is the Kimi Code
5
+ * membership service, distinct from the Moonshot Open Platform — it requires a
6
+ * Kimi Code Console credential (`omp /login kimi-code` or an explicit
7
+ * `MOONSHOT_SEARCH_API_KEY` / `KIMI_SEARCH_API_KEY`), not `MOONSHOT_API_KEY`.
5
8
  * Endpoint: POST https://api.kimi.com/coding/v1/search
6
9
  */
7
10
  import { type AuthStorage, type FetchImpl } from "@oh-my-pi/pi-ai";
@@ -62,7 +62,7 @@ export declare const SEARCH_PROVIDER_OPTIONS: readonly [{
62
62
  }, {
63
63
  readonly value: "kimi";
64
64
  readonly label: "Kimi";
65
- readonly description: "Requires MOONSHOT_SEARCH_API_KEY or MOONSHOT_API_KEY";
65
+ readonly description: "Kimi Code search (requires a Kimi Code Console key via KIMI_SEARCH_API_KEY/MOONSHOT_SEARCH_API_KEY or /login kimi-code; not MOONSHOT_API_KEY)";
66
66
  }, {
67
67
  readonly value: "parallel";
68
68
  readonly label: "Parallel";
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": "17.0.1",
4
+ "version": "17.0.2",
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",
@@ -52,23 +52,28 @@
52
52
  "@agentclientprotocol/sdk": "1.2.1",
53
53
  "@babel/parser": "^7.29.7",
54
54
  "@mozilla/readability": "^0.6.0",
55
- "@oh-my-pi/hashline": "17.0.1",
56
- "@oh-my-pi/omp-stats": "17.0.1",
57
- "@oh-my-pi/pi-agent-core": "17.0.1",
58
- "@oh-my-pi/pi-ai": "17.0.1",
59
- "@oh-my-pi/pi-catalog": "17.0.1",
60
- "@oh-my-pi/pi-mnemopi": "17.0.1",
61
- "@oh-my-pi/pi-natives": "17.0.1",
62
- "@oh-my-pi/pi-tui": "17.0.1",
63
- "@oh-my-pi/pi-utils": "17.0.1",
64
- "@oh-my-pi/pi-wire": "17.0.1",
65
- "@oh-my-pi/snapcompact": "17.0.1",
55
+ "@oh-my-pi/hashline": "17.0.2",
56
+ "@oh-my-pi/omp-stats": "17.0.2",
57
+ "@oh-my-pi/pi-agent-core": "17.0.2",
58
+ "@oh-my-pi/pi-ai": "17.0.2",
59
+ "@oh-my-pi/pi-catalog": "17.0.2",
60
+ "@oh-my-pi/pi-mnemopi": "17.0.2",
61
+ "@oh-my-pi/pi-natives": "17.0.2",
62
+ "@oh-my-pi/pi-tui": "17.0.2",
63
+ "@oh-my-pi/pi-utils": "17.0.2",
64
+ "@oh-my-pi/pi-wire": "17.0.2",
65
+ "@oh-my-pi/snapcompact": "17.0.2",
66
66
  "@opentelemetry/api": "^1.9.1",
67
- "@opentelemetry/context-async-hooks": "^2.7.1",
67
+ "@opentelemetry/api-logs": "^0.220.0",
68
+ "@opentelemetry/context-async-hooks": "^2.9.0",
69
+ "@opentelemetry/exporter-logs-otlp-proto": "^0.220.0",
70
+ "@opentelemetry/exporter-metrics-otlp-proto": "^0.220.0",
68
71
  "@opentelemetry/exporter-trace-otlp-proto": "^0.220.0",
69
- "@opentelemetry/resources": "^2.7.1",
70
- "@opentelemetry/sdk-trace-base": "^2.7.1",
71
- "@opentelemetry/sdk-trace-node": "^2.7.1",
72
+ "@opentelemetry/resources": "^2.9.0",
73
+ "@opentelemetry/sdk-logs": "^0.220.0",
74
+ "@opentelemetry/sdk-metrics": "^2.9.0",
75
+ "@opentelemetry/sdk-trace-base": "^2.9.0",
76
+ "@opentelemetry/sdk-trace-node": "^2.9.0",
72
77
  "@puppeteer/browsers": "^3.0.6",
73
78
  "@types/turndown": "5.0.6",
74
79
  "@xterm/headless": "^6.0.0",