@oh-my-pi/pi-coding-agent 15.0.2 → 15.1.0
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 +56 -1
- package/examples/custom-tools/README.md +11 -7
- package/examples/custom-tools/hello/index.ts +2 -2
- package/examples/extensions/README.md +19 -8
- package/examples/extensions/api-demo.ts +15 -19
- package/examples/extensions/hello.ts +5 -6
- package/examples/extensions/plan-mode.ts +1 -1
- package/examples/extensions/reload-runtime.ts +4 -3
- package/examples/extensions/with-deps/index.ts +4 -3
- package/examples/sdk/06-extensions.ts +4 -2
- package/package.json +7 -17
- package/src/autoresearch/tools/init-experiment.ts +38 -41
- package/src/autoresearch/tools/log-experiment.ts +32 -41
- package/src/autoresearch/tools/run-experiment.ts +3 -3
- package/src/autoresearch/tools/update-notes.ts +11 -11
- package/src/commit/agentic/tools/analyze-file.ts +4 -4
- package/src/commit/agentic/tools/git-file-diff.ts +4 -4
- package/src/commit/agentic/tools/git-hunk.ts +5 -5
- package/src/commit/agentic/tools/git-overview.ts +4 -4
- package/src/commit/agentic/tools/propose-changelog.ts +13 -13
- package/src/commit/agentic/tools/propose-commit.ts +6 -6
- package/src/commit/agentic/tools/recent-commits.ts +3 -3
- package/src/commit/agentic/tools/schemas.ts +28 -28
- package/src/commit/agentic/tools/split-commit.ts +22 -21
- package/src/commit/analysis/summary.ts +4 -4
- package/src/commit/changelog/generate.ts +7 -11
- package/src/commit/shared-llm.ts +22 -34
- package/src/config/config-file.ts +35 -13
- package/src/config/model-registry.ts +9 -190
- package/src/config/models-config-schema.ts +166 -0
- package/src/config/settings-schema.ts +18 -0
- package/src/edit/index.ts +2 -2
- package/src/edit/modes/apply-patch.ts +7 -6
- package/src/edit/modes/patch.ts +18 -25
- package/src/edit/modes/replace.ts +18 -20
- package/src/eval/js/shared/rewrite-imports.ts +131 -10
- package/src/eval/py/executor.ts +233 -623
- package/src/eval/py/kernel.ts +27 -2
- package/src/exa/factory.ts +5 -4
- package/src/exa/mcp-client.ts +1 -1
- package/src/exa/researcher.ts +9 -20
- package/src/exa/search.ts +26 -52
- package/src/exa/types.ts +1 -1
- package/src/exa/websets.ts +54 -53
- package/src/exec/bash-executor.ts +2 -1
- package/src/extensibility/custom-commands/loader.ts +5 -3
- package/src/extensibility/custom-commands/types.ts +4 -2
- package/src/extensibility/custom-tools/loader.ts +5 -3
- package/src/extensibility/custom-tools/types.ts +7 -6
- package/src/extensibility/custom-tools/wrapper.ts +1 -1
- package/src/extensibility/extensions/loader.ts +7 -3
- package/src/extensibility/extensions/types.ts +9 -5
- package/src/extensibility/extensions/wrapper.ts +1 -2
- package/src/extensibility/hooks/loader.ts +3 -1
- package/src/extensibility/hooks/tool-wrapper.ts +1 -1
- package/src/extensibility/hooks/types.ts +4 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +30 -0
- package/src/extensibility/shared-events.ts +1 -1
- package/src/extensibility/typebox.ts +391 -0
- package/src/goals/tools/goal-tool.ts +6 -12
- package/src/hashline/types.ts +4 -4
- package/src/hindsight/state.ts +2 -2
- package/src/index.ts +0 -2
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/lsp/types.ts +30 -38
- package/src/mcp/manager.ts +1 -1
- package/src/mcp/tool-bridge.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +12 -1
- package/src/modes/components/status-line/segments.ts +2 -1
- package/src/modes/controllers/command-controller.ts +27 -2
- package/src/modes/controllers/event-controller.ts +3 -4
- package/src/modes/interactive-mode.ts +1 -1
- package/src/modes/rpc/host-tools.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/modes/theme/theme.ts +111 -117
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/context-usage.ts +2 -2
- package/src/sdk.ts +31 -8
- package/src/session/agent-session.ts +74 -104
- package/src/session/messages.ts +16 -51
- package/src/session/session-manager.ts +22 -2
- package/src/session/streaming-output.ts +16 -6
- package/src/task/executor.ts +208 -86
- package/src/task/index.ts +15 -11
- package/src/task/render.ts +32 -5
- package/src/task/types.ts +54 -39
- package/src/tools/ask.ts +12 -12
- package/src/tools/ast-edit.ts +11 -15
- package/src/tools/ast-grep.ts +9 -10
- package/src/tools/bash.ts +9 -23
- package/src/tools/browser.ts +39 -53
- package/src/tools/calculator.ts +12 -11
- package/src/tools/checkpoint.ts +7 -7
- package/src/tools/debug.ts +40 -43
- package/src/tools/eval.ts +6 -8
- package/src/tools/find.ts +10 -13
- package/src/tools/gh.ts +71 -128
- package/src/tools/hindsight-recall.ts +4 -6
- package/src/tools/hindsight-reflect.ts +5 -5
- package/src/tools/hindsight-retain.ts +15 -17
- package/src/tools/image-gen.ts +31 -81
- package/src/tools/index.ts +4 -1
- package/src/tools/inspect-image.ts +8 -9
- package/src/tools/irc.ts +15 -27
- package/src/tools/job.ts +14 -21
- package/src/tools/read.ts +7 -8
- package/src/tools/recipe/index.ts +7 -9
- package/src/tools/render-mermaid.ts +12 -12
- package/src/tools/report-tool-issue.ts +4 -4
- package/src/tools/resolve.ts +11 -11
- package/src/tools/review.ts +14 -26
- package/src/tools/search-tool-bm25.ts +7 -9
- package/src/tools/search.ts +19 -22
- package/src/tools/ssh.ts +7 -7
- package/src/tools/todo-write.ts +26 -34
- package/src/tools/vim.ts +10 -26
- package/src/tools/write.ts +5 -5
- package/src/tools/yield.ts +100 -54
- package/src/web/search/index.ts +9 -24
- package/src/prompts/compaction/branch-summary-context.md +0 -5
- package/src/prompts/compaction/branch-summary-preamble.md +0 -2
- package/src/prompts/compaction/branch-summary.md +0 -30
- package/src/prompts/compaction/compaction-short-summary.md +0 -9
- package/src/prompts/compaction/compaction-summary-context.md +0 -5
- package/src/prompts/compaction/compaction-summary.md +0 -38
- package/src/prompts/compaction/compaction-turn-prefix.md +0 -17
- package/src/prompts/compaction/compaction-update-summary.md +0 -45
- package/src/prompts/system/auto-handoff-threshold-focus.md +0 -1
- package/src/prompts/system/file-operations.md +0 -10
- package/src/prompts/system/handoff-document.md +0 -49
- package/src/prompts/system/summarization-system.md +0 -3
- package/src/session/compaction/branch-summarization.ts +0 -324
- package/src/session/compaction/compaction.ts +0 -1420
- package/src/session/compaction/errors.ts +0 -31
- package/src/session/compaction/index.ts +0 -8
- package/src/session/compaction/pruning.ts +0 -91
- package/src/session/compaction/utils.ts +0 -184
package/src/lsp/types.ts
CHANGED
|
@@ -1,49 +1,41 @@
|
|
|
1
|
-
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
2
1
|
import type { ptree } from "@oh-my-pi/pi-utils";
|
|
3
|
-
import
|
|
2
|
+
import * as z from "zod/v4";
|
|
4
3
|
|
|
5
4
|
// =============================================================================
|
|
6
5
|
// Tool Schema
|
|
7
6
|
// =============================================================================
|
|
8
7
|
|
|
9
|
-
export const lspSchema =
|
|
10
|
-
action:
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
),
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
timeout: Type.Optional(Type.Number({ description: "Request timeout in seconds" })),
|
|
38
|
-
payload: Type.Optional(
|
|
39
|
-
Type.String({
|
|
40
|
-
description:
|
|
41
|
-
"JSON-encoded params for action=request. When omitted, params are auto-built from file/line/symbol.",
|
|
42
|
-
}),
|
|
43
|
-
),
|
|
8
|
+
export const lspSchema = z.object({
|
|
9
|
+
action: z.enum([
|
|
10
|
+
"diagnostics",
|
|
11
|
+
"definition",
|
|
12
|
+
"references",
|
|
13
|
+
"hover",
|
|
14
|
+
"symbols",
|
|
15
|
+
"rename",
|
|
16
|
+
"rename_file",
|
|
17
|
+
"code_actions",
|
|
18
|
+
"type_definition",
|
|
19
|
+
"implementation",
|
|
20
|
+
"status",
|
|
21
|
+
"reload",
|
|
22
|
+
"capabilities",
|
|
23
|
+
"request",
|
|
24
|
+
]),
|
|
25
|
+
file: z.string().describe("File path or source path for rename_file").optional(),
|
|
26
|
+
line: z.number().describe("Line number (1-indexed)").optional(),
|
|
27
|
+
symbol: z.string().describe("Symbol/substring to locate on the line").optional(),
|
|
28
|
+
query: z.string().describe("Search query, code-action selector, or LSP method name for action=request").optional(),
|
|
29
|
+
new_name: z.string().describe("New name for rename, or destination path for rename_file").optional(),
|
|
30
|
+
apply: z.boolean().describe("Apply edits (default: true for rename/rename_file)").optional(),
|
|
31
|
+
timeout: z.number().describe("Request timeout in seconds").optional(),
|
|
32
|
+
payload: z
|
|
33
|
+
.string()
|
|
34
|
+
.describe("JSON-encoded params for action=request. When omitted, params are auto-built from file/line/symbol.")
|
|
35
|
+
.optional(),
|
|
44
36
|
});
|
|
45
37
|
|
|
46
|
-
export type LspParams =
|
|
38
|
+
export type LspParams = z.infer<typeof lspSchema>;
|
|
47
39
|
|
|
48
40
|
export interface LspToolDetails {
|
|
49
41
|
serverName?: string;
|
package/src/mcp/manager.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import * as url from "node:url";
|
|
9
|
+
import type { TSchema } from "@oh-my-pi/pi-ai";
|
|
9
10
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
10
|
-
import type { TSchema } from "@sinclair/typebox";
|
|
11
11
|
import type { SourceMeta } from "../capability/types";
|
|
12
12
|
import { resolveConfigValue } from "../config/resolve-config-value";
|
|
13
13
|
import type { CustomTool } from "../extensibility/custom-tools/types";
|
package/src/mcp/tool-bridge.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Converts MCP tool definitions to CustomTool format for the agent.
|
|
5
5
|
*/
|
|
6
6
|
import type { AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
7
|
+
import type { TSchema } from "@oh-my-pi/pi-ai";
|
|
7
8
|
import { sanitizeSchemaForMCP } from "@oh-my-pi/pi-ai/utils/schema";
|
|
8
9
|
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
9
|
-
import type { TSchema } from "@sinclair/typebox";
|
|
10
10
|
import type { SourceMeta } from "../capability/types";
|
|
11
11
|
import type {
|
|
12
12
|
CustomTool,
|
|
@@ -266,7 +266,18 @@ export class SessionObserverOverlayComponent extends Container {
|
|
|
266
266
|
if (!progress) return "";
|
|
267
267
|
const stats: string[] = [];
|
|
268
268
|
if (progress.toolCount > 0) stats.push(`${formatNumber(progress.toolCount)} tools`);
|
|
269
|
-
|
|
269
|
+
// Current per-turn context — what the user reads as "how full is the context".
|
|
270
|
+
// Falls back to cumulative billing volume (Σ-prefixed) when context size is unknown.
|
|
271
|
+
if (progress.contextTokens && progress.contextTokens > 0) {
|
|
272
|
+
const ctx =
|
|
273
|
+
progress.contextWindow && progress.contextWindow > 0
|
|
274
|
+
? `${formatNumber(progress.contextTokens)}/${formatNumber(progress.contextWindow)} ctx`
|
|
275
|
+
: `${formatNumber(progress.contextTokens)} ctx`;
|
|
276
|
+
stats.push(ctx);
|
|
277
|
+
if (progress.tokens > 0) stats.push(`Σ${formatNumber(progress.tokens)}`);
|
|
278
|
+
} else if (progress.tokens > 0) {
|
|
279
|
+
stats.push(`Σ${formatNumber(progress.tokens)}`);
|
|
280
|
+
}
|
|
270
281
|
if (progress.durationMs > 0) stats.push(formatDuration(progress.durationMs));
|
|
271
282
|
const parts: string[] = [];
|
|
272
283
|
if (stats.length > 0) parts.push(theme.fg("dim", stats.join(theme.sep.dot)));
|
|
@@ -199,7 +199,8 @@ const pathSegment: StatusLineSegment = {
|
|
|
199
199
|
pwd = `${ellipsis}${pwd.slice(-sliceLen)}`;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
const
|
|
202
|
+
const showScratchIcon = scratch && opts.stripWorkPrefix !== false;
|
|
203
|
+
const icon = showScratchIcon ? theme.icon.scratchFolder : theme.icon.folder;
|
|
203
204
|
const content = withIcon(icon, pwd);
|
|
204
205
|
return { content: theme.fg("statusLinePath", content), visible: true };
|
|
205
206
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import * as os from "node:os";
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { CompactionCancelledError, type CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction";
|
|
4
5
|
import {
|
|
5
6
|
getEnvApiKey,
|
|
6
7
|
getProviderDetails,
|
|
@@ -37,7 +38,6 @@ import { buildHotkeysMarkdown } from "../../modes/utils/hotkeys-markdown";
|
|
|
37
38
|
import { buildToolsMarkdown } from "../../modes/utils/tools-markdown";
|
|
38
39
|
import type { AsyncJobSnapshotItem } from "../../session/agent-session";
|
|
39
40
|
import type { AuthStorage } from "../../session/auth-storage";
|
|
40
|
-
import { CompactionCancelledError, type CompactionOutcome } from "../../session/compaction";
|
|
41
41
|
import type { NewSessionOptions } from "../../session/session-manager";
|
|
42
42
|
import { outputMeta } from "../../tools/output-meta";
|
|
43
43
|
import { resolveToCwd, stripOuterDoubleQuotes } from "../../tools/path-utils";
|
|
@@ -1175,8 +1175,29 @@ export class CommandController {
|
|
|
1175
1175
|
return;
|
|
1176
1176
|
}
|
|
1177
1177
|
|
|
1178
|
+
if (this.ctx.loadingAnimation) {
|
|
1179
|
+
this.ctx.loadingAnimation.stop();
|
|
1180
|
+
this.ctx.loadingAnimation = undefined;
|
|
1181
|
+
}
|
|
1182
|
+
this.ctx.statusContainer.clear();
|
|
1183
|
+
|
|
1184
|
+
const originalOnEscape = this.ctx.editor.onEscape;
|
|
1185
|
+
this.ctx.editor.onEscape = () => {
|
|
1186
|
+
this.ctx.session.abortHandoff();
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
const handoffLoader = new Loader(
|
|
1190
|
+
this.ctx.ui,
|
|
1191
|
+
spinner => theme.fg("accent", spinner),
|
|
1192
|
+
text => theme.fg("muted", text),
|
|
1193
|
+
"Generating handoff… (esc to cancel)",
|
|
1194
|
+
getSymbolTheme().spinnerFrames,
|
|
1195
|
+
);
|
|
1196
|
+
this.ctx.statusContainer.addChild(handoffLoader);
|
|
1197
|
+
this.ctx.ui.requestRender();
|
|
1198
|
+
|
|
1178
1199
|
try {
|
|
1179
|
-
//
|
|
1200
|
+
// Handoff generation runs as a oneshot request; the new session is shown after it completes.
|
|
1180
1201
|
const result = await this.ctx.session.handoff(customInstructions);
|
|
1181
1202
|
|
|
1182
1203
|
if (!result) {
|
|
@@ -1206,6 +1227,10 @@ export class CommandController {
|
|
|
1206
1227
|
} else {
|
|
1207
1228
|
this.ctx.showError(`Handoff failed: ${message}`);
|
|
1208
1229
|
}
|
|
1230
|
+
} finally {
|
|
1231
|
+
handoffLoader.stop();
|
|
1232
|
+
this.ctx.statusContainer.clear();
|
|
1233
|
+
this.ctx.editor.onEscape = originalOnEscape;
|
|
1209
1234
|
}
|
|
1210
1235
|
this.ctx.ui.requestRender();
|
|
1211
1236
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INTENT_FIELD } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { calculatePromptTokens } from "@oh-my-pi/pi-agent-core/compaction/compaction";
|
|
2
3
|
import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
|
|
3
4
|
import { type Component, Loader, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
4
5
|
import { settings } from "../../config/settings";
|
|
@@ -15,7 +16,6 @@ import { getSymbolTheme, theme } from "../../modes/theme/theme";
|
|
|
15
16
|
import type { InteractiveModeContext, TodoPhase } from "../../modes/types";
|
|
16
17
|
import type { PlanApprovalDetails } from "../../plan-mode/approved-plan";
|
|
17
18
|
import type { AgentSessionEvent } from "../../session/agent-session";
|
|
18
|
-
import { calculatePromptTokens } from "../../session/compaction/compaction";
|
|
19
19
|
import { isSilentAbort, readPendingDisplayTag } from "../../session/messages";
|
|
20
20
|
import type { ResolveToolDetails } from "../../tools/resolve";
|
|
21
21
|
|
|
@@ -719,9 +719,8 @@ export class EventController {
|
|
|
719
719
|
|
|
720
720
|
#scheduleIdleCompaction(): void {
|
|
721
721
|
this.#cancelIdleCompaction();
|
|
722
|
-
// Don't schedule while
|
|
723
|
-
//
|
|
724
|
-
// here would fire after the session resets, trying to handoff an empty session.
|
|
722
|
+
// Don't schedule idle work while context maintenance is already running; the
|
|
723
|
+
// maintenance flow may reset the session before this timer fires.
|
|
725
724
|
if (this.ctx.session.isCompacting) return;
|
|
726
725
|
|
|
727
726
|
const idleSettings = settings.getGroup("compaction");
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import { type Agent, type AgentMessage, type AgentToolResult, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
8
|
+
import type { CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction";
|
|
8
9
|
import {
|
|
9
10
|
type AssistantMessage,
|
|
10
11
|
type ImageContent,
|
|
@@ -46,7 +47,6 @@ import planModeCompactInstructionsPrompt from "../prompts/system/plan-mode-compa
|
|
|
46
47
|
type: "text",
|
|
47
48
|
};
|
|
48
49
|
import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
|
|
49
|
-
import type { CompactionOutcome } from "../session/compaction";
|
|
50
50
|
import { HistoryStorage } from "../session/history-storage";
|
|
51
51
|
import type { SessionContext, SessionManager } from "../session/session-manager";
|
|
52
52
|
import { getRecentSessions } from "../session/session-manager";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { Static, TSchema } from "@oh-my-pi/pi-ai";
|
|
2
3
|
import { Snowflake } from "@oh-my-pi/pi-utils";
|
|
3
|
-
import type { Static, TSchema } from "@sinclair/typebox";
|
|
4
4
|
import { applyToolProxy } from "../../extensibility/tool-proxy";
|
|
5
5
|
import type { Theme } from "../../modes/theme/theme";
|
|
6
6
|
import type {
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
* Spawns the agent in RPC mode and provides a typed API for all operations.
|
|
5
5
|
*/
|
|
6
6
|
import type { AgentEvent, AgentMessage, AgentToolResult, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
7
|
+
import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
7
8
|
import type { ImageContent, Model } from "@oh-my-pi/pi-ai";
|
|
8
9
|
import { isRecord, ptree, readJsonl } from "@oh-my-pi/pi-utils";
|
|
9
10
|
import type { BashResult } from "../../exec/bash-executor";
|
|
10
11
|
import type { SessionStats } from "../../session/agent-session";
|
|
11
|
-
import type { CompactionResult } from "../../session/compaction";
|
|
12
12
|
import type {
|
|
13
13
|
RpcCommand,
|
|
14
14
|
RpcExtensionUIRequest,
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* Responses and events are emitted as JSON lines on stdout.
|
|
6
6
|
*/
|
|
7
7
|
import type { AgentMessage, AgentToolResult, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
8
|
+
import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
8
9
|
import type { Effort, ImageContent, Model } from "@oh-my-pi/pi-ai";
|
|
9
10
|
import type { BashResult } from "../../exec/bash-executor";
|
|
10
11
|
import type { ContextUsage } from "../../extensibility/extensions/types";
|
|
11
12
|
import type { SessionStats } from "../../session/agent-session";
|
|
12
|
-
import type { CompactionResult } from "../../session/compaction";
|
|
13
13
|
import type { TodoPhase } from "../../tools/todo-write";
|
|
14
14
|
|
|
15
15
|
// ============================================================================
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -11,9 +11,8 @@ import {
|
|
|
11
11
|
} from "@oh-my-pi/pi-natives";
|
|
12
12
|
import type { EditorTheme, MarkdownTheme, SelectListTheme, SymbolTheme } from "@oh-my-pi/pi-tui";
|
|
13
13
|
import { adjustHsv, getCustomThemesDir, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
14
|
-
import { type Static, Type } from "@sinclair/typebox";
|
|
15
|
-
import { TypeCompiler } from "@sinclair/typebox/compiler";
|
|
16
14
|
import chalk from "chalk";
|
|
15
|
+
import * as z from "zod/v4";
|
|
17
16
|
// Embed theme JSON files at build time
|
|
18
17
|
import darkThemeJson from "./dark.json" with { type: "json" };
|
|
19
18
|
import { defaultThemes } from "./defaults";
|
|
@@ -807,118 +806,111 @@ const SPINNER_FRAMES: Record<SymbolPreset, Record<SpinnerType, string[]>> = {
|
|
|
807
806
|
// Types & Schema
|
|
808
807
|
// ============================================================================
|
|
809
808
|
|
|
810
|
-
const
|
|
811
|
-
|
|
812
|
-
|
|
809
|
+
const colorValueSchema = z.union([
|
|
810
|
+
z.string(), // hex "#ff0000", var ref "primary", or empty ""
|
|
811
|
+
z.number().int().min(0).max(255), // 256-color index
|
|
813
812
|
]);
|
|
814
813
|
|
|
815
|
-
type ColorValue =
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
814
|
+
type ColorValue = z.infer<typeof colorValueSchema>;
|
|
815
|
+
|
|
816
|
+
const THEME_COLOR_KEYS = [
|
|
817
|
+
"accent",
|
|
818
|
+
"border",
|
|
819
|
+
"borderAccent",
|
|
820
|
+
"borderMuted",
|
|
821
|
+
"success",
|
|
822
|
+
"error",
|
|
823
|
+
"warning",
|
|
824
|
+
"muted",
|
|
825
|
+
"dim",
|
|
826
|
+
"text",
|
|
827
|
+
"thinkingText",
|
|
828
|
+
"selectedBg",
|
|
829
|
+
"userMessageBg",
|
|
830
|
+
"userMessageText",
|
|
831
|
+
"customMessageBg",
|
|
832
|
+
"customMessageText",
|
|
833
|
+
"customMessageLabel",
|
|
834
|
+
"toolPendingBg",
|
|
835
|
+
"toolSuccessBg",
|
|
836
|
+
"toolErrorBg",
|
|
837
|
+
"toolTitle",
|
|
838
|
+
"toolOutput",
|
|
839
|
+
"mdHeading",
|
|
840
|
+
"mdLink",
|
|
841
|
+
"mdLinkUrl",
|
|
842
|
+
"mdCode",
|
|
843
|
+
"mdCodeBlock",
|
|
844
|
+
"mdCodeBlockBorder",
|
|
845
|
+
"mdQuote",
|
|
846
|
+
"mdQuoteBorder",
|
|
847
|
+
"mdHr",
|
|
848
|
+
"mdListBullet",
|
|
849
|
+
"toolDiffAdded",
|
|
850
|
+
"toolDiffRemoved",
|
|
851
|
+
"toolDiffContext",
|
|
852
|
+
"syntaxComment",
|
|
853
|
+
"syntaxKeyword",
|
|
854
|
+
"syntaxFunction",
|
|
855
|
+
"syntaxVariable",
|
|
856
|
+
"syntaxString",
|
|
857
|
+
"syntaxNumber",
|
|
858
|
+
"syntaxType",
|
|
859
|
+
"syntaxOperator",
|
|
860
|
+
"syntaxPunctuation",
|
|
861
|
+
"thinkingOff",
|
|
862
|
+
"thinkingMinimal",
|
|
863
|
+
"thinkingLow",
|
|
864
|
+
"thinkingMedium",
|
|
865
|
+
"thinkingHigh",
|
|
866
|
+
"thinkingXhigh",
|
|
867
|
+
"bashMode",
|
|
868
|
+
"pythonMode",
|
|
869
|
+
"statusLineBg",
|
|
870
|
+
"statusLineSep",
|
|
871
|
+
"statusLineModel",
|
|
872
|
+
"statusLinePath",
|
|
873
|
+
"statusLineGitClean",
|
|
874
|
+
"statusLineGitDirty",
|
|
875
|
+
"statusLineContext",
|
|
876
|
+
"statusLineSpend",
|
|
877
|
+
"statusLineStaged",
|
|
878
|
+
"statusLineDirty",
|
|
879
|
+
"statusLineUntracked",
|
|
880
|
+
"statusLineOutput",
|
|
881
|
+
"statusLineCost",
|
|
882
|
+
"statusLineSubagents",
|
|
883
|
+
] as const;
|
|
884
|
+
|
|
885
|
+
const themeColorsSchema = z.object(
|
|
886
|
+
Object.fromEntries(THEME_COLOR_KEYS.map(key => [key, colorValueSchema])) as unknown as {
|
|
887
|
+
[K in (typeof THEME_COLOR_KEYS)[number]]: typeof colorValueSchema;
|
|
888
|
+
},
|
|
825
889
|
);
|
|
826
890
|
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
userMessageText: ColorValueSchema,
|
|
848
|
-
customMessageBg: ColorValueSchema,
|
|
849
|
-
customMessageText: ColorValueSchema,
|
|
850
|
-
customMessageLabel: ColorValueSchema,
|
|
851
|
-
toolPendingBg: ColorValueSchema,
|
|
852
|
-
toolSuccessBg: ColorValueSchema,
|
|
853
|
-
toolErrorBg: ColorValueSchema,
|
|
854
|
-
toolTitle: ColorValueSchema,
|
|
855
|
-
toolOutput: ColorValueSchema,
|
|
856
|
-
// Markdown (10 colors)
|
|
857
|
-
mdHeading: ColorValueSchema,
|
|
858
|
-
mdLink: ColorValueSchema,
|
|
859
|
-
mdLinkUrl: ColorValueSchema,
|
|
860
|
-
mdCode: ColorValueSchema,
|
|
861
|
-
mdCodeBlock: ColorValueSchema,
|
|
862
|
-
mdCodeBlockBorder: ColorValueSchema,
|
|
863
|
-
mdQuote: ColorValueSchema,
|
|
864
|
-
mdQuoteBorder: ColorValueSchema,
|
|
865
|
-
mdHr: ColorValueSchema,
|
|
866
|
-
mdListBullet: ColorValueSchema,
|
|
867
|
-
// Tool Diffs (3 colors)
|
|
868
|
-
toolDiffAdded: ColorValueSchema,
|
|
869
|
-
toolDiffRemoved: ColorValueSchema,
|
|
870
|
-
toolDiffContext: ColorValueSchema,
|
|
871
|
-
// Syntax Highlighting (9 colors)
|
|
872
|
-
syntaxComment: ColorValueSchema,
|
|
873
|
-
syntaxKeyword: ColorValueSchema,
|
|
874
|
-
syntaxFunction: ColorValueSchema,
|
|
875
|
-
syntaxVariable: ColorValueSchema,
|
|
876
|
-
syntaxString: ColorValueSchema,
|
|
877
|
-
syntaxNumber: ColorValueSchema,
|
|
878
|
-
syntaxType: ColorValueSchema,
|
|
879
|
-
syntaxOperator: ColorValueSchema,
|
|
880
|
-
syntaxPunctuation: ColorValueSchema,
|
|
881
|
-
// Thinking Level Borders (6 colors)
|
|
882
|
-
thinkingOff: ColorValueSchema,
|
|
883
|
-
thinkingMinimal: ColorValueSchema,
|
|
884
|
-
thinkingLow: ColorValueSchema,
|
|
885
|
-
thinkingMedium: ColorValueSchema,
|
|
886
|
-
thinkingHigh: ColorValueSchema,
|
|
887
|
-
thinkingXhigh: ColorValueSchema,
|
|
888
|
-
// Bash Mode (1 color)
|
|
889
|
-
bashMode: ColorValueSchema,
|
|
890
|
-
// Python Mode (1 color)
|
|
891
|
-
pythonMode: ColorValueSchema,
|
|
892
|
-
// Footer Status Line
|
|
893
|
-
statusLineBg: ColorValueSchema,
|
|
894
|
-
statusLineSep: ColorValueSchema,
|
|
895
|
-
statusLineModel: ColorValueSchema,
|
|
896
|
-
statusLinePath: ColorValueSchema,
|
|
897
|
-
statusLineGitClean: ColorValueSchema,
|
|
898
|
-
statusLineGitDirty: ColorValueSchema,
|
|
899
|
-
statusLineContext: ColorValueSchema,
|
|
900
|
-
statusLineSpend: ColorValueSchema,
|
|
901
|
-
statusLineStaged: ColorValueSchema,
|
|
902
|
-
statusLineDirty: ColorValueSchema,
|
|
903
|
-
statusLineUntracked: ColorValueSchema,
|
|
904
|
-
statusLineOutput: ColorValueSchema,
|
|
905
|
-
statusLineCost: ColorValueSchema,
|
|
906
|
-
statusLineSubagents: ColorValueSchema,
|
|
907
|
-
}),
|
|
908
|
-
export: Type.Optional(
|
|
909
|
-
Type.Object({
|
|
910
|
-
pageBg: Type.Optional(ColorValueSchema),
|
|
911
|
-
cardBg: Type.Optional(ColorValueSchema),
|
|
912
|
-
infoBg: Type.Optional(ColorValueSchema),
|
|
913
|
-
}),
|
|
914
|
-
),
|
|
915
|
-
symbols: SymbolsSchema,
|
|
891
|
+
const symbolPresetSchema = z.enum(["unicode", "nerd", "ascii"]);
|
|
892
|
+
|
|
893
|
+
const themeJsonSchema = z.object({
|
|
894
|
+
$schema: z.string().optional(),
|
|
895
|
+
name: z.string(),
|
|
896
|
+
vars: z.record(z.string(), colorValueSchema).optional(),
|
|
897
|
+
colors: themeColorsSchema,
|
|
898
|
+
export: z
|
|
899
|
+
.object({
|
|
900
|
+
pageBg: colorValueSchema.optional(),
|
|
901
|
+
cardBg: colorValueSchema.optional(),
|
|
902
|
+
infoBg: colorValueSchema.optional(),
|
|
903
|
+
})
|
|
904
|
+
.optional(),
|
|
905
|
+
symbols: z
|
|
906
|
+
.object({
|
|
907
|
+
preset: symbolPresetSchema.optional(),
|
|
908
|
+
overrides: z.record(z.string(), z.string()).optional(),
|
|
909
|
+
})
|
|
910
|
+
.optional(),
|
|
916
911
|
});
|
|
917
912
|
|
|
918
|
-
type ThemeJson =
|
|
919
|
-
|
|
920
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- TypeBox CJS/ESM type mismatch
|
|
921
|
-
const validateThemeJson = TypeCompiler.Compile(ThemeJsonSchema as any);
|
|
913
|
+
type ThemeJson = z.infer<typeof themeJsonSchema>;
|
|
922
914
|
|
|
923
915
|
export type ThemeColor =
|
|
924
916
|
| "accent"
|
|
@@ -1638,18 +1630,20 @@ async function loadThemeJson(name: string): Promise<ThemeJson> {
|
|
|
1638
1630
|
} catch (error) {
|
|
1639
1631
|
throw new Error(`Failed to parse theme ${name}: ${error}`);
|
|
1640
1632
|
}
|
|
1641
|
-
|
|
1642
|
-
|
|
1633
|
+
const parsed = themeJsonSchema.safeParse(json);
|
|
1634
|
+
if (!parsed.success) {
|
|
1643
1635
|
const missingColors: string[] = [];
|
|
1644
1636
|
const otherErrors: string[] = [];
|
|
1645
1637
|
|
|
1646
|
-
for (const
|
|
1647
|
-
|
|
1648
|
-
const
|
|
1649
|
-
|
|
1650
|
-
|
|
1638
|
+
for (const issue of parsed.error.issues) {
|
|
1639
|
+
const parts = issue.path;
|
|
1640
|
+
const colorKey = parts.length === 2 && parts[0] === "colors" && typeof parts[1] === "string" ? parts[1] : null;
|
|
1641
|
+
|
|
1642
|
+
if (colorKey && issue.code === "invalid_type" && (issue as { received?: unknown }).received === undefined) {
|
|
1643
|
+
missingColors.push(colorKey);
|
|
1651
1644
|
} else {
|
|
1652
|
-
|
|
1645
|
+
const pathStr = parts.length === 0 ? "/" : `/${parts.map(String).join("/")}`;
|
|
1646
|
+
otherErrors.push(` - ${pathStr}: ${issue.message}`);
|
|
1653
1647
|
}
|
|
1654
1648
|
}
|
|
1655
1649
|
|
|
@@ -1666,7 +1660,7 @@ async function loadThemeJson(name: string): Promise<ThemeJson> {
|
|
|
1666
1660
|
|
|
1667
1661
|
throw new Error(errorMessage);
|
|
1668
1662
|
}
|
|
1669
|
-
return
|
|
1663
|
+
return parsed.data;
|
|
1670
1664
|
}
|
|
1671
1665
|
|
|
1672
1666
|
interface CreateThemeOptions {
|
package/src/modes/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { CompactionOutcome } from "@oh-my-pi/pi-agent-core/compaction";
|
|
2
3
|
import type { AssistantMessage, ImageContent, Message, UsageReport } from "@oh-my-pi/pi-ai";
|
|
3
4
|
import type { Component, Container, EditorTheme, Loader, Spacer, Text, TUI } from "@oh-my-pi/pi-tui";
|
|
4
5
|
import type { KeybindingsManager } from "../config/keybindings";
|
|
@@ -13,7 +14,6 @@ import type { CompactOptions } from "../extensibility/extensions/types";
|
|
|
13
14
|
import type { MCPManager } from "../mcp";
|
|
14
15
|
import type { PlanApprovalDetails } from "../plan-mode/approved-plan";
|
|
15
16
|
import type { AgentSession, AgentSessionEvent } from "../session/agent-session";
|
|
16
|
-
import type { CompactionOutcome } from "../session/compaction";
|
|
17
17
|
import type { HistoryStorage } from "../session/history-storage";
|
|
18
18
|
import type { SessionContext, SessionManager } from "../session/session-manager";
|
|
19
19
|
import type { LspStartupServerInfo } from "../tools";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import type { CompactionSettings } from "@oh-my-pi/pi-agent-core/compaction";
|
|
2
|
+
import { effectiveReserveTokens, estimateTokens, resolveThresholdTokens } from "@oh-my-pi/pi-agent-core/compaction";
|
|
1
3
|
import type { Model } from "@oh-my-pi/pi-ai";
|
|
2
4
|
import { countTokens } from "@oh-my-pi/pi-natives";
|
|
3
5
|
import { formatNumber } from "@oh-my-pi/pi-utils";
|
|
4
6
|
import type { Skill } from "../../extensibility/skills";
|
|
5
7
|
import type { AgentSession } from "../../session/agent-session";
|
|
6
|
-
import type { CompactionSettings } from "../../session/compaction";
|
|
7
|
-
import { effectiveReserveTokens, estimateTokens, resolveThresholdTokens } from "../../session/compaction";
|
|
8
8
|
import type { Tool } from "../../tools";
|
|
9
9
|
import type { theme as Theme } from "../theme/theme";
|
|
10
10
|
|
package/src/sdk.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
Agent,
|
|
3
3
|
type AgentEvent,
|
|
4
4
|
type AgentMessage,
|
|
5
|
+
type AgentTelemetryConfig,
|
|
5
6
|
type AgentTool,
|
|
6
7
|
INTENT_FIELD,
|
|
7
8
|
type ThinkingLevel,
|
|
@@ -244,6 +245,17 @@ export interface CreateAgentSessionOptions {
|
|
|
244
245
|
|
|
245
246
|
/** Whether UI is available (enables interactive tools like ask). Default: false */
|
|
246
247
|
hasUI?: boolean;
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Opt-in OpenTelemetry instrumentation forwarded to the underlying Agent.
|
|
251
|
+
* Passing `{}` enables the loop's GenAI-semantic-convention spans. See
|
|
252
|
+
* {@link AgentTelemetryConfig} for the full surface (hooks, content capture,
|
|
253
|
+
* cost estimator, agent identity).
|
|
254
|
+
*
|
|
255
|
+
* Safe to enable without an OTEL SDK registered in the host: the
|
|
256
|
+
* `@opentelemetry/api` package returns a no-op tracer in that case.
|
|
257
|
+
*/
|
|
258
|
+
telemetry?: AgentTelemetryConfig;
|
|
247
259
|
}
|
|
248
260
|
|
|
249
261
|
/** Result from createAgentSession */
|
|
@@ -920,18 +932,24 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
920
932
|
// it. On timeout we forward `undefined` to ToolSession; buildSystemPromptInternal
|
|
921
933
|
// will re-race the same promise through its own withDeadline path. Background
|
|
922
934
|
// work continues so caches still warm.
|
|
923
|
-
const raceWithDeadline = <T>(name: string, work: Promise<T>): Promise<T | undefined> =>
|
|
924
|
-
|
|
935
|
+
const raceWithDeadline = async <T>(name: string, work: Promise<T>): Promise<T | undefined> => {
|
|
936
|
+
let timedOut = false;
|
|
937
|
+
const result = await Promise.race([
|
|
925
938
|
work,
|
|
926
939
|
Bun.sleep(STARTUP_SCAN_DEADLINE_MS).then(() => {
|
|
927
|
-
|
|
928
|
-
name,
|
|
929
|
-
timeoutMs: STARTUP_SCAN_DEADLINE_MS,
|
|
930
|
-
cwd,
|
|
931
|
-
});
|
|
940
|
+
timedOut = true;
|
|
932
941
|
return undefined;
|
|
933
942
|
}),
|
|
934
943
|
]);
|
|
944
|
+
if (timedOut) {
|
|
945
|
+
logger.warn("Startup scan exceeded deadline; deferring to system prompt fallback", {
|
|
946
|
+
name,
|
|
947
|
+
timeoutMs: STARTUP_SCAN_DEADLINE_MS,
|
|
948
|
+
cwd,
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
return result;
|
|
952
|
+
};
|
|
935
953
|
const [contextFiles, resolvedWorkspaceTree] = await Promise.all([
|
|
936
954
|
contextFilesPromise,
|
|
937
955
|
raceWithDeadline("buildWorkspaceTree", workspaceTreePromise),
|
|
@@ -1093,6 +1111,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1093
1111
|
settings,
|
|
1094
1112
|
authStorage,
|
|
1095
1113
|
modelRegistry,
|
|
1114
|
+
getTelemetry: () => agent?.telemetry,
|
|
1096
1115
|
};
|
|
1097
1116
|
|
|
1098
1117
|
// Wire process-wide internal URL singletons owned by their real classes.
|
|
@@ -1746,6 +1765,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1746
1765
|
},
|
|
1747
1766
|
intentTracing: !!intentField,
|
|
1748
1767
|
getToolChoice: () => session?.nextToolChoice(),
|
|
1768
|
+
telemetry: options.telemetry,
|
|
1749
1769
|
});
|
|
1750
1770
|
|
|
1751
1771
|
cursorEventEmitter = event => agent.emitExternalEvent(event);
|
|
@@ -1754,11 +1774,14 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1754
1774
|
if (hasExistingSession) {
|
|
1755
1775
|
agent.replaceMessages(existingSession.messages);
|
|
1756
1776
|
} else {
|
|
1757
|
-
// Save initial model
|
|
1777
|
+
// Save initial model, thinking level, and service tier for new sessions so they can be restored on resume.
|
|
1758
1778
|
if (model) {
|
|
1759
1779
|
sessionManager.appendModelChange(`${model.provider}/${model.id}`);
|
|
1760
1780
|
}
|
|
1761
1781
|
sessionManager.appendThinkingLevelChange(thinkingLevel);
|
|
1782
|
+
if (initialServiceTier) {
|
|
1783
|
+
sessionManager.appendServiceTierChange(initialServiceTier);
|
|
1784
|
+
}
|
|
1762
1785
|
}
|
|
1763
1786
|
|
|
1764
1787
|
session = new AgentSession({
|