@oh-my-pi/pi-coding-agent 16.1.7 → 16.1.8
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 +46 -0
- package/dist/cli.js +3390 -3377
- package/dist/types/cli/session-picker.d.ts +0 -1
- package/dist/types/cli/tiny-models-cli.d.ts +2 -0
- package/dist/types/collab/protocol.d.ts +20 -1
- package/dist/types/config/settings-schema.d.ts +57 -6
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +5 -1
- package/dist/types/internal-urls/filesystem-resource.d.ts +9 -0
- package/dist/types/mcp/loader.d.ts +3 -2
- package/dist/types/mcp/manager.d.ts +4 -3
- package/dist/types/mcp/startup-events.d.ts +21 -4
- package/dist/types/mnemopi/config.d.ts +1 -0
- package/dist/types/modes/components/agent-hub.d.ts +1 -0
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +1 -0
- package/dist/types/modes/components/assistant-message.d.ts +5 -1
- package/dist/types/modes/components/btw-panel.d.ts +2 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +1 -0
- package/dist/types/modes/components/session-selector.d.ts +0 -2
- package/dist/types/modes/controllers/btw-controller.d.ts +2 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/controllers/streaming-reveal.d.ts +3 -2
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/types.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +5 -3
- package/dist/types/session/session-history-format.d.ts +25 -0
- package/dist/types/session/snapcompact-inline.d.ts +1 -1
- package/dist/types/slash-commands/builtin-registry.d.ts +7 -4
- package/dist/types/slash-commands/types.d.ts +2 -0
- package/dist/types/system-prompt.d.ts +1 -0
- package/dist/types/tiny/models.d.ts +11 -7
- package/dist/types/tools/todo.d.ts +1 -0
- package/dist/types/utils/thinking-display.d.ts +2 -0
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +104 -0
- package/src/advisor/runtime.ts +38 -2
- package/src/cli/session-picker.ts +1 -2
- package/src/cli/tiny-models-cli.ts +7 -2
- package/src/collab/guest.ts +172 -20
- package/src/collab/host.ts +47 -5
- package/src/collab/protocol.ts +16 -1
- package/src/config/settings-schema.ts +59 -5
- package/src/edit/renderer.ts +8 -12
- package/src/extensibility/legacy-pi-ai-shim.ts +16 -4
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/internal-urls/filesystem-resource.ts +34 -0
- package/src/internal-urls/local-protocol.ts +7 -1
- package/src/internal-urls/memory-protocol.ts +5 -1
- package/src/internal-urls/skill-protocol.ts +20 -4
- package/src/internal-urls/vault-protocol.ts +5 -2
- package/src/main.ts +8 -8
- package/src/mcp/loader.ts +4 -3
- package/src/mcp/manager.ts +35 -15
- package/src/mcp/startup-events.ts +106 -11
- package/src/mnemopi/config.ts +2 -0
- package/src/mnemopi/state.ts +3 -1
- package/src/modes/components/agent-hub.ts +4 -0
- package/src/modes/components/agent-transcript-viewer.ts +2 -0
- package/src/modes/components/assistant-message.ts +217 -18
- package/src/modes/components/btw-panel.ts +15 -3
- package/src/modes/components/chat-transcript-builder.ts +8 -2
- package/src/modes/components/model-selector.ts +72 -9
- package/src/modes/components/omfg-panel.ts +1 -1
- package/src/modes/components/session-selector.ts +4 -9
- package/src/modes/components/snapcompact-shape-preview.ts +1 -1
- package/src/modes/components/tool-execution.ts +10 -2
- package/src/modes/controllers/btw-controller.ts +32 -7
- package/src/modes/controllers/event-controller.ts +24 -4
- package/src/modes/controllers/input-controller.ts +43 -21
- package/src/modes/controllers/selector-controller.ts +23 -13
- package/src/modes/controllers/streaming-reveal.ts +78 -20
- package/src/modes/controllers/todo-command-controller.ts +9 -10
- package/src/modes/interactive-mode.ts +83 -8
- package/src/modes/types.ts +3 -0
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/prompts/advisor/system.md +1 -1
- package/src/prompts/system/side-channel-no-tools.md +3 -0
- package/src/sdk.ts +12 -8
- package/src/session/agent-session.ts +349 -84
- package/src/session/history-storage.ts +15 -16
- package/src/session/session-history-format.ts +41 -1
- package/src/session/snapcompact-inline.ts +9 -6
- package/src/slash-commands/builtin-registry.ts +147 -21
- package/src/slash-commands/helpers/todo.ts +12 -6
- package/src/slash-commands/types.ts +2 -0
- package/src/system-prompt.ts +6 -11
- package/src/tiny/models.ts +7 -3
- package/src/tiny/title-client.ts +8 -2
- package/src/tiny/worker.ts +1 -0
- package/src/tools/search.ts +10 -1
- package/src/tools/sqlite-reader.ts +59 -3
- package/src/tools/todo.ts +6 -0
- package/src/tools/write.ts +4 -6
- package/src/utils/thinking-display.ts +78 -0
|
@@ -70,7 +70,12 @@ import type { Goal, GoalModeState } from "../goals/state";
|
|
|
70
70
|
import { resolveLocalUrlToPath } from "../internal-urls";
|
|
71
71
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "../lsp/startup-events";
|
|
72
72
|
import type { MCPManager } from "../mcp";
|
|
73
|
-
import {
|
|
73
|
+
import {
|
|
74
|
+
formatMCPConnectionStatusMessage,
|
|
75
|
+
isMcpConnectionStatusEvent,
|
|
76
|
+
MCP_CONNECTION_STATUS_EVENT_CHANNEL,
|
|
77
|
+
type McpConnectionStatusEvent,
|
|
78
|
+
} from "../mcp/startup-events";
|
|
74
79
|
import {
|
|
75
80
|
humanizePlanTitle,
|
|
76
81
|
type PlanApprovalDetails,
|
|
@@ -88,7 +93,7 @@ import type { SessionContext } from "../session/session-context";
|
|
|
88
93
|
import { getRecentSessions } from "../session/session-listing";
|
|
89
94
|
import type { SessionManager } from "../session/session-manager";
|
|
90
95
|
import type { ShakeMode } from "../session/shake-types";
|
|
91
|
-
import { BUILTIN_SLASH_COMMAND_RESERVED_NAMES,
|
|
96
|
+
import { BUILTIN_SLASH_COMMAND_RESERVED_NAMES, buildTuiBuiltinSlashCommands } from "../slash-commands/builtin-registry";
|
|
92
97
|
import { formatDuration } from "../slash-commands/helpers/format";
|
|
93
98
|
import { STTController, type SttState } from "../stt";
|
|
94
99
|
import { discoverTitleSystemPromptFile, resolvePromptInput } from "../system-prompt";
|
|
@@ -401,6 +406,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
401
406
|
#modelCycleClearTimer: NodeJS.Timeout | undefined;
|
|
402
407
|
todoPhases: TodoPhase[] = [];
|
|
403
408
|
hideThinkingBlock = false;
|
|
409
|
+
proseOnlyThinking = true;
|
|
404
410
|
pendingImages: ImageContent[] = [];
|
|
405
411
|
pendingImageLinks: (string | undefined)[] = [];
|
|
406
412
|
compactionQueuedMessages: CompactionQueuedMessage[] = [];
|
|
@@ -506,6 +512,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
506
512
|
this.loadingAnimation.stop();
|
|
507
513
|
this.loadingAnimation = undefined;
|
|
508
514
|
}
|
|
515
|
+
if (this.autoCompactionLoader) {
|
|
516
|
+
this.autoCompactionLoader.stop();
|
|
517
|
+
this.autoCompactionLoader = undefined;
|
|
518
|
+
}
|
|
519
|
+
if (this.retryLoader) {
|
|
520
|
+
this.retryLoader.stop();
|
|
521
|
+
this.retryLoader = undefined;
|
|
522
|
+
}
|
|
509
523
|
this.statusContainer.clear();
|
|
510
524
|
this.pendingMessagesContainer.clear();
|
|
511
525
|
this.#cancelModelCycleClearTimer();
|
|
@@ -526,6 +540,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
526
540
|
#observerRegistry: SessionObserverRegistry;
|
|
527
541
|
#eventBus?: EventBus;
|
|
528
542
|
#eventBusUnsubscribers: Array<() => void> = [];
|
|
543
|
+
#mcpStatusOrder: string[] = [];
|
|
544
|
+
#mcpPendingServers = new Set<string>();
|
|
545
|
+
#mcpConnectedServers = new Set<string>();
|
|
546
|
+
#mcpFailedServers = new Map<string, string>();
|
|
529
547
|
#welcomeComponent?: WelcomeComponent;
|
|
530
548
|
readonly #chatHost: ChatBlockHost = { requestRender: () => this.ui.requestRender() };
|
|
531
549
|
|
|
@@ -559,13 +577,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
559
577
|
}),
|
|
560
578
|
);
|
|
561
579
|
this.#eventBusUnsubscribers.push(
|
|
562
|
-
eventBus.on(
|
|
563
|
-
if (!
|
|
564
|
-
logger.warn("Ignoring malformed mcp:
|
|
580
|
+
eventBus.on(MCP_CONNECTION_STATUS_EVENT_CHANNEL, data => {
|
|
581
|
+
if (!isMcpConnectionStatusEvent(data)) {
|
|
582
|
+
logger.warn("Ignoring malformed mcp:connection-status event", { data });
|
|
565
583
|
return;
|
|
566
584
|
}
|
|
567
|
-
|
|
568
|
-
this.showStatus(formatMCPConnectingMessage(data.serverNames));
|
|
585
|
+
this.#handleMcpConnectionStatusEvent(data);
|
|
569
586
|
}),
|
|
570
587
|
);
|
|
571
588
|
}
|
|
@@ -618,6 +635,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
618
635
|
this.statusLine.setAutoCompactEnabled(session.autoCompactionEnabled);
|
|
619
636
|
|
|
620
637
|
this.hideThinkingBlock = settings.get("hideThinkingBlock");
|
|
638
|
+
this.proseOnlyThinking = settings.get("proseOnlyThinking");
|
|
621
639
|
|
|
622
640
|
const hookCommands: SlashCommand[] = (
|
|
623
641
|
this.session.extensionRunner?.getRegisteredCommands(BUILTIN_SLASH_COMMAND_RESERVED_NAMES) ?? []
|
|
@@ -643,8 +661,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
643
661
|
}
|
|
644
662
|
}
|
|
645
663
|
|
|
664
|
+
const builtinCommands = buildTuiBuiltinSlashCommands({ ctx: this });
|
|
646
665
|
// Store pending commands for init() where file commands are loaded async
|
|
647
|
-
this.#pendingSlashCommands = [...
|
|
666
|
+
this.#pendingSlashCommands = [...builtinCommands, ...hookCommands, ...customCommands, ...skillCommandList];
|
|
648
667
|
|
|
649
668
|
this.#uiHelpers = new UiHelpers(this);
|
|
650
669
|
this.#btwController = new BtwController(this);
|
|
@@ -660,6 +679,54 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
660
679
|
this.#observerRegistry = new SessionObserverRegistry();
|
|
661
680
|
}
|
|
662
681
|
|
|
682
|
+
#handleMcpConnectionStatusEvent(event: McpConnectionStatusEvent): void {
|
|
683
|
+
if (this.settings.get("startup.quiet")) return;
|
|
684
|
+
if (event.type === "connecting") {
|
|
685
|
+
this.#mcpStatusOrder = [];
|
|
686
|
+
this.#mcpPendingServers.clear();
|
|
687
|
+
this.#mcpConnectedServers.clear();
|
|
688
|
+
this.#mcpFailedServers.clear();
|
|
689
|
+
for (const serverName of event.serverNames) {
|
|
690
|
+
this.#trackMcpStatusServer(serverName);
|
|
691
|
+
this.#mcpPendingServers.add(serverName);
|
|
692
|
+
}
|
|
693
|
+
} else if (event.type === "connected") {
|
|
694
|
+
this.#trackMcpStatusServer(event.serverName);
|
|
695
|
+
this.#mcpPendingServers.delete(event.serverName);
|
|
696
|
+
this.#mcpFailedServers.delete(event.serverName);
|
|
697
|
+
this.#mcpConnectedServers.add(event.serverName);
|
|
698
|
+
} else {
|
|
699
|
+
this.#trackMcpStatusServer(event.serverName);
|
|
700
|
+
this.#mcpPendingServers.delete(event.serverName);
|
|
701
|
+
this.#mcpConnectedServers.delete(event.serverName);
|
|
702
|
+
this.#mcpFailedServers.set(event.serverName, event.error);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const message = formatMCPConnectionStatusMessage({
|
|
706
|
+
pendingServers: this.#orderedMcpStatusServers(this.#mcpPendingServers),
|
|
707
|
+
connectedServers: this.#orderedMcpStatusServers(this.#mcpConnectedServers),
|
|
708
|
+
failedServers: this.#orderedMcpStatusFailures(),
|
|
709
|
+
});
|
|
710
|
+
if (message) this.showStatus(message);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
#trackMcpStatusServer(serverName: string): void {
|
|
714
|
+
if (!this.#mcpStatusOrder.includes(serverName)) {
|
|
715
|
+
this.#mcpStatusOrder.push(serverName);
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
#orderedMcpStatusServers(servers: ReadonlySet<string>): string[] {
|
|
720
|
+
return this.#mcpStatusOrder.filter(serverName => servers.has(serverName));
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
#orderedMcpStatusFailures(): Array<{ serverName: string; error: string }> {
|
|
724
|
+
return this.#mcpStatusOrder.flatMap(serverName => {
|
|
725
|
+
const error = this.#mcpFailedServers.get(serverName);
|
|
726
|
+
return error === undefined ? [] : [{ serverName, error }];
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
|
|
663
730
|
playWelcomeIntro(): void {
|
|
664
731
|
const welcome = this.#welcomeComponent;
|
|
665
732
|
// Component-scoped: the intro only mutates the welcome box's own rows,
|
|
@@ -3769,6 +3836,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
3769
3836
|
return this.#btwController.handleBranch();
|
|
3770
3837
|
}
|
|
3771
3838
|
|
|
3839
|
+
canCopyBtw(): boolean {
|
|
3840
|
+
return this.#btwController.canCopy();
|
|
3841
|
+
}
|
|
3842
|
+
|
|
3843
|
+
handleBtwCopyKey(): Promise<boolean> {
|
|
3844
|
+
return this.#btwController.handleCopy();
|
|
3845
|
+
}
|
|
3846
|
+
|
|
3772
3847
|
async handleBtwBranch(question: string, assistantMessage: AssistantMessage): Promise<void> {
|
|
3773
3848
|
try {
|
|
3774
3849
|
const result = await this.session.branchFromBtw(question, assistantMessage);
|
package/src/modes/types.ts
CHANGED
|
@@ -148,6 +148,7 @@ export interface InteractiveModeContext {
|
|
|
148
148
|
loopLimit?: LoopLimitRuntime;
|
|
149
149
|
planModePlanFilePath?: string;
|
|
150
150
|
hideThinkingBlock: boolean;
|
|
151
|
+
proseOnlyThinking: boolean;
|
|
151
152
|
pendingImages: ImageContent[];
|
|
152
153
|
pendingImageLinks: (string | undefined)[];
|
|
153
154
|
compactionQueuedMessages: CompactionQueuedMessage[];
|
|
@@ -348,6 +349,8 @@ export interface InteractiveModeContext {
|
|
|
348
349
|
handleBtwEscape(): boolean;
|
|
349
350
|
handleBtwBranchKey(): Promise<boolean>;
|
|
350
351
|
canBranchBtw(): boolean;
|
|
352
|
+
canCopyBtw(): boolean;
|
|
353
|
+
handleBtwCopyKey(): Promise<boolean>;
|
|
351
354
|
handleBtwBranch(question: string, assistantMessage: AssistantMessage): Promise<void>;
|
|
352
355
|
handleOmfgCommand(complaint: string): Promise<void>;
|
|
353
356
|
hasActiveOmfg(): boolean;
|
|
@@ -332,6 +332,7 @@ export class UiHelpers {
|
|
|
332
332
|
() => this.ctx.ui.requestRender(),
|
|
333
333
|
this.ctx.viewSession.extensionRunner?.getAssistantThinkingRenderers(),
|
|
334
334
|
this.ctx.ui.imageBudget,
|
|
335
|
+
this.ctx.proseOnlyThinking,
|
|
335
336
|
);
|
|
336
337
|
this.ctx.chatContainer.addChild(assistantComponent);
|
|
337
338
|
break;
|
|
@@ -24,7 +24,7 @@ Keep exploration lean:
|
|
|
24
24
|
- Offer alternatives, not lectures.
|
|
25
25
|
- NEVER restate information the agent already has, including errors they have seen.
|
|
26
26
|
- Examples: type errors, LSP diagnostics, failed builds, failing tests, lint.
|
|
27
|
-
- NEVER repeat advice you already gave.
|
|
27
|
+
- NEVER repeat advice you already gave, and NEVER send the same advice twice.
|
|
28
28
|
- NEVER nitpick about things user stated they are okay with. You are the advocate for the user.
|
|
29
29
|
</communication>
|
|
30
30
|
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<system-reminder>
|
|
2
|
+
This is an ephemeral side-channel turn that reuses the current conversation's context. The tool catalog stays attached only to keep the prompt cache warm — tools are NOT available on this turn. Do NOT emit any tool call; reply with plain text only. Any tool call you produce is discarded without executing.
|
|
3
|
+
</system-reminder>
|
package/src/sdk.ts
CHANGED
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
type MCPToolsLoadResult,
|
|
88
88
|
parseMCPToolName,
|
|
89
89
|
} from "./mcp";
|
|
90
|
-
import {
|
|
90
|
+
import { MCP_CONNECTION_STATUS_EVENT_CHANNEL, type McpConnectionStatusEvent } from "./mcp/startup-events";
|
|
91
91
|
import { createSessionMemoryRuntimeContext, resolveMemoryBackend } from "./memory-backend";
|
|
92
92
|
import type { MnemopiSessionState } from "./mnemopi/state";
|
|
93
93
|
import asyncResultTemplate from "./prompts/tools/async-result.md" with { type: "text" };
|
|
@@ -805,6 +805,7 @@ export interface BuildSystemPromptOptions {
|
|
|
805
805
|
* as separate entries so providers can cache prompt prefixes without concatenating blocks.
|
|
806
806
|
*/
|
|
807
807
|
export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}): Promise<BuildSystemPromptResult> {
|
|
808
|
+
const toolMap = options.tools ? new Map(options.tools.map(tool => [tool.name, tool])) : undefined;
|
|
808
809
|
return await buildSystemPromptInternal({
|
|
809
810
|
cwd: options.cwd,
|
|
810
811
|
customPrompt: options.customPrompt,
|
|
@@ -812,6 +813,8 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
812
813
|
contextFiles: options.contextFiles,
|
|
813
814
|
appendSystemPrompt: options.appendPrompt,
|
|
814
815
|
inlineToolDescriptors: options.inlineToolDescriptors,
|
|
816
|
+
toolNames: options.tools?.map(tool => tool.name),
|
|
817
|
+
tools: toolMap ? buildSystemPromptToolMetadata(toolMap) : undefined,
|
|
815
818
|
});
|
|
816
819
|
}
|
|
817
820
|
|
|
@@ -1617,12 +1620,13 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1617
1620
|
| ((liveSession: AgentSession, activation: DeferredMCPActivation) => void)
|
|
1618
1621
|
| undefined;
|
|
1619
1622
|
const startupQuiet = settings.get("startup.quiet");
|
|
1620
|
-
const
|
|
1621
|
-
if (!options.hasUI || startupQuiet
|
|
1622
|
-
|
|
1623
|
+
const onMCPStatus = (event: McpConnectionStatusEvent) => {
|
|
1624
|
+
if (!options.hasUI || startupQuiet) return;
|
|
1625
|
+
if (event.type === "connecting" && event.serverNames.length === 0) return;
|
|
1626
|
+
eventBus.emit(MCP_CONNECTION_STATUS_EVENT_CHANNEL, event);
|
|
1623
1627
|
};
|
|
1624
1628
|
const mcpDiscoverOptions = {
|
|
1625
|
-
|
|
1629
|
+
onStatus: onMCPStatus,
|
|
1626
1630
|
enableProjectConfig: settings.get("mcp.enableProjectConfig") ?? true,
|
|
1627
1631
|
// Always filter Exa - we have native integration
|
|
1628
1632
|
filterExa: true,
|
|
@@ -2412,9 +2416,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2412
2416
|
: undefined;
|
|
2413
2417
|
const transformProviderContext =
|
|
2414
2418
|
obfuscator || snapcompactInline
|
|
2415
|
-
? (context: Context, transformModel: Model): Context => {
|
|
2419
|
+
? async (context: Context, transformModel: Model): Promise<Context> => {
|
|
2416
2420
|
let transformed = obfuscator ? obfuscateProviderContext(obfuscator, context) : context;
|
|
2417
|
-
if (snapcompactInline) transformed = snapcompactInline.transform(transformed, transformModel);
|
|
2421
|
+
if (snapcompactInline) transformed = await snapcompactInline.transform(transformed, transformModel);
|
|
2418
2422
|
return transformed;
|
|
2419
2423
|
}
|
|
2420
2424
|
: undefined;
|
|
@@ -2474,7 +2478,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2474
2478
|
presencePenalty: settings.get("presencePenalty") >= 0 ? settings.get("presencePenalty") : undefined,
|
|
2475
2479
|
repetitionPenalty: settings.get("repetitionPenalty") >= 0 ? settings.get("repetitionPenalty") : undefined,
|
|
2476
2480
|
serviceTier: initialServiceTier,
|
|
2477
|
-
hideThinkingSummary: settings.get("
|
|
2481
|
+
hideThinkingSummary: settings.get("omitThinking"),
|
|
2478
2482
|
kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
|
|
2479
2483
|
preferWebsockets: preferOpenAICodexWebsockets,
|
|
2480
2484
|
getToolContext: tc => toolContextStore.getContext(tc),
|