@oh-my-pi/pi-coding-agent 16.0.4 → 16.0.5
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 +41 -0
- package/dist/cli.js +341 -261
- package/dist/types/advisor/advise-tool.d.ts +9 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/bench-cli.d.ts +6 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/config/settings-schema.d.ts +91 -2
- package/dist/types/extensibility/extensions/runner.d.ts +5 -2
- package/dist/types/extensibility/extensions/types.d.ts +8 -7
- package/dist/types/extensibility/shared-events.d.ts +22 -1
- package/dist/types/main.d.ts +1 -0
- package/dist/types/modes/components/status-line/component.d.ts +1 -1
- package/dist/types/modes/components/status-line/context-thresholds.d.ts +0 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +1 -1
- package/dist/types/modes/utils/context-usage.d.ts +12 -0
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +20 -0
- package/dist/types/session/session-persistence.d.ts +4 -0
- package/dist/types/tools/read.d.ts +1 -0
- package/dist/types/tui/code-cell.d.ts +2 -0
- package/dist/types/utils/image-vision-fallback.d.ts +28 -0
- package/dist/types/web/search/providers/base.d.ts +1 -0
- package/dist/types/web/search/providers/gemini.d.ts +1 -0
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +59 -0
- package/src/advisor/advise-tool.ts +13 -0
- package/src/cli/args.ts +1 -0
- package/src/cli/bench-cli.ts +30 -7
- package/src/cli/flag-tables.ts +8 -0
- package/src/collab/host.ts +2 -2
- package/src/commands/launch.ts +3 -0
- package/src/config/settings-schema.ts +84 -2
- package/src/eval/py/runner.py +44 -0
- package/src/extensibility/extensions/runner.ts +20 -2
- package/src/extensibility/extensions/types.ts +16 -5
- package/src/extensibility/shared-events.ts +24 -0
- package/src/internal-urls/docs-index.generated.ts +7 -7
- package/src/main.ts +12 -5
- package/src/modes/components/branch-summary-message.ts +1 -0
- package/src/modes/components/collab-prompt-message.ts +9 -7
- package/src/modes/components/compaction-summary-message.ts +1 -0
- package/src/modes/components/custom-message.ts +1 -0
- package/src/modes/components/footer.ts +6 -5
- package/src/modes/components/hook-message.ts +1 -0
- package/src/modes/components/read-tool-group.ts +9 -3
- package/src/modes/components/skill-message.ts +1 -0
- package/src/modes/components/status-line/component.ts +131 -14
- package/src/modes/components/status-line/context-thresholds.ts +0 -1
- package/src/modes/components/todo-reminder.ts +1 -0
- package/src/modes/components/ttsr-notification.ts +1 -0
- package/src/modes/components/user-message.ts +6 -6
- package/src/modes/controllers/event-controller.ts +2 -7
- package/src/modes/controllers/selector-controller.ts +10 -3
- package/src/modes/interactive-mode.ts +4 -2
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/modes/utils/context-usage.ts +28 -15
- package/src/prompts/tools/image-attachment-describe-system.md +8 -0
- package/src/prompts/tools/image-attachment-describe.md +10 -0
- package/src/sdk.ts +14 -18
- package/src/session/agent-session.ts +564 -231
- package/src/session/session-loader.ts +19 -32
- package/src/session/session-persistence.ts +27 -11
- package/src/ssh/connection-manager.ts +3 -2
- package/src/task/executor.ts +1 -1
- package/src/tools/image-gen.ts +67 -25
- package/src/tools/read.ts +28 -6
- package/src/tui/code-cell.ts +44 -3
- package/src/utils/image-vision-fallback.ts +197 -0
- package/src/web/search/index.ts +12 -0
- package/src/web/search/providers/base.ts +1 -0
- package/src/web/search/providers/gemini.ts +56 -18
|
@@ -94,7 +94,7 @@ export function computeNonMessageTokens(session: AgentSession): number {
|
|
|
94
94
|
* the status-line fast path intentionally uses the equivalent collapsed total
|
|
95
95
|
* in `computeNonMessageTokens`.
|
|
96
96
|
*/
|
|
97
|
-
function computeNonMessageBreakdown(session: AgentSession): {
|
|
97
|
+
export function computeNonMessageBreakdown(session: AgentSession): {
|
|
98
98
|
skillsTokens: number;
|
|
99
99
|
toolsTokens: number;
|
|
100
100
|
systemContextTokens: number;
|
|
@@ -119,22 +119,37 @@ export function computeContextBreakdown(
|
|
|
119
119
|
const model = session.model;
|
|
120
120
|
const contextWindow = model?.contextWindow ?? 0;
|
|
121
121
|
|
|
122
|
+
const breakdown = typeof session.getContextBreakdown === "function" ? session.getContextBreakdown() : undefined;
|
|
123
|
+
|
|
122
124
|
let messagesTokens = 0;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
125
|
+
let skillsTokens = 0;
|
|
126
|
+
let toolsTokens = 0;
|
|
127
|
+
let systemContextTokens = 0;
|
|
128
|
+
let systemPromptTokens = 0;
|
|
129
|
+
let usedTokens = 0;
|
|
130
|
+
|
|
131
|
+
if (breakdown) {
|
|
132
|
+
messagesTokens = breakdown.messagesTokens;
|
|
133
|
+
skillsTokens = breakdown.skillsTokens;
|
|
134
|
+
toolsTokens = breakdown.systemToolsTokens;
|
|
135
|
+
systemContextTokens = breakdown.systemContextTokens;
|
|
136
|
+
systemPromptTokens = breakdown.systemPromptTokens;
|
|
137
|
+
usedTokens = breakdown.usedTokens;
|
|
138
|
+
} else {
|
|
139
|
+
const convo = session.messages;
|
|
140
|
+
if (convo) {
|
|
141
|
+
for (const message of convo) {
|
|
142
|
+
messagesTokens += estimateTokens(message);
|
|
143
|
+
}
|
|
127
144
|
}
|
|
145
|
+
const nonMessage = computeNonMessageBreakdown(session);
|
|
146
|
+
skillsTokens = nonMessage.skillsTokens;
|
|
147
|
+
toolsTokens = nonMessage.toolsTokens;
|
|
148
|
+
systemContextTokens = nonMessage.systemContextTokens;
|
|
149
|
+
systemPromptTokens = nonMessage.systemPromptTokens;
|
|
150
|
+
usedTokens = skillsTokens + toolsTokens + systemContextTokens + systemPromptTokens + messagesTokens;
|
|
128
151
|
}
|
|
129
152
|
|
|
130
|
-
// The rendered system prompt already contains the skill descriptions and the
|
|
131
|
-
// markdown tool descriptions. To present a non-overlapping breakdown:
|
|
132
|
-
// System prompt = total system prompt text - skills section (tool descriptions stay)
|
|
133
|
-
// Tools = JSON tool schema sent separately on the wire
|
|
134
|
-
// Skills = the skill list embedded in the system prompt
|
|
135
|
-
// Messages = conversation messages
|
|
136
|
-
const { skillsTokens, toolsTokens, systemContextTokens, systemPromptTokens } = computeNonMessageBreakdown(session);
|
|
137
|
-
|
|
138
153
|
const categories: CategoryInfo[] = [
|
|
139
154
|
{ id: "systemPrompt", label: "System prompt", tokens: systemPromptTokens, color: "accent", glyph: CELL_FILLED },
|
|
140
155
|
{ id: "systemTools", label: "System tools", tokens: toolsTokens, color: "warning", glyph: CELL_FILLED },
|
|
@@ -155,8 +170,6 @@ export function computeContextBreakdown(
|
|
|
155
170
|
},
|
|
156
171
|
];
|
|
157
172
|
|
|
158
|
-
const usedTokens = categories.reduce((sum, c) => sum + c.tokens, 0);
|
|
159
|
-
|
|
160
173
|
let autoCompactBufferTokens = 0;
|
|
161
174
|
if (contextWindow > 0) {
|
|
162
175
|
const compactionSettings = session.settings.getGroup("compaction") as CompactionSettings;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
You are an image-analysis assistant. The user attached an image to a model that cannot see images, so your description is injected into that model's context in place of the image. The downstream model relies entirely on your text — it never sees the pixels.
|
|
2
|
+
|
|
3
|
+
Core behavior:
|
|
4
|
+
- Be faithful and evidence-first: distinguish direct observations from inferences.
|
|
5
|
+
- Transcribe ALL visible text verbatim, preserving casing, punctuation, and layout order. Mark unreadable segments explicitly rather than guessing.
|
|
6
|
+
- NEVER fabricate occluded, blurry, or uncertain details — say what is uncertain.
|
|
7
|
+
- Be thorough but compact: prefer dense, information-rich prose over filler.
|
|
8
|
+
- Do not add meta commentary, preambles ("This image shows…"), or closing remarks. Output only the description.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Describe this image in enough detail that a model which cannot see it can reason about its content.
|
|
2
|
+
|
|
3
|
+
Cover, where present:
|
|
4
|
+
- The overall scene, subject, and what is happening.
|
|
5
|
+
- People, objects, and their relationships, positions, colors, and counts.
|
|
6
|
+
- All visible text, transcribed verbatim (OCR).
|
|
7
|
+
- UI/screenshot elements: labels, buttons, inputs, states, errors, highlighted or disabled controls.
|
|
8
|
+
- Diagrams, charts, tables: structure, axes, series, and the values they encode.
|
|
9
|
+
|
|
10
|
+
Flag anything ambiguous or unreadable. Output the description as plain prose only.
|
package/src/sdk.ts
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getOpenAICodexTransportDetails,
|
|
22
22
|
prewarmOpenAICodexResponses,
|
|
23
23
|
} from "@oh-my-pi/pi-ai/providers/openai-codex-responses";
|
|
24
|
+
import { FALLBACK_DIALECT, preferredDialect } from "@oh-my-pi/pi-catalog/identity";
|
|
24
25
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
25
26
|
import {
|
|
26
27
|
$env,
|
|
@@ -40,7 +41,6 @@ import { AutoLearnController, buildAutoLearnInstructions } from "./autolearn/con
|
|
|
40
41
|
import { loadCapability } from "./capability";
|
|
41
42
|
import { type Rule, ruleCapability, setActiveRules } from "./capability/rule";
|
|
42
43
|
import { bucketRules } from "./capability/rule-buckets";
|
|
43
|
-
import { createApiKeyResolver } from "./config/api-key-resolver";
|
|
44
44
|
import { shouldEnableAppendOnlyContext } from "./config/append-only-context-mode";
|
|
45
45
|
import { ModelRegistry } from "./config/model-registry";
|
|
46
46
|
import {
|
|
@@ -415,6 +415,8 @@ export interface CreateAgentSessionOptions {
|
|
|
415
415
|
providerSessionId?: string;
|
|
416
416
|
/** Optional provider-facing prompt cache key, distinct from request lineage. */
|
|
417
417
|
providerPromptCacheKey?: string;
|
|
418
|
+
/** Absolute wall-clock deadline in Unix epoch milliseconds. */
|
|
419
|
+
deadline?: number;
|
|
418
420
|
|
|
419
421
|
/** Custom tools to register (in addition to built-in tools). Accepts both CustomTool and ToolDefinition. */
|
|
420
422
|
customTools?: (CustomTool | ToolDefinition)[];
|
|
@@ -567,10 +569,15 @@ export type DialectFormat = "auto" | "native" | Dialect;
|
|
|
567
569
|
|
|
568
570
|
export function resolveDialect(
|
|
569
571
|
format: DialectFormat,
|
|
570
|
-
model: Pick<Model, "supportsTools"> | undefined,
|
|
572
|
+
model: (Pick<Model, "supportsTools"> & Partial<Pick<Model, "id">>) | undefined,
|
|
571
573
|
): Dialect | undefined {
|
|
572
574
|
if (format === "native") return undefined;
|
|
573
|
-
if (format === "auto")
|
|
575
|
+
if (format === "auto") {
|
|
576
|
+
if (model?.supportsTools !== false) return undefined;
|
|
577
|
+
if (!model.id) return "glm";
|
|
578
|
+
const preferred = preferredDialect(model.id);
|
|
579
|
+
return preferred === FALLBACK_DIALECT ? "glm" : preferred;
|
|
580
|
+
}
|
|
574
581
|
return format;
|
|
575
582
|
}
|
|
576
583
|
|
|
@@ -2458,6 +2465,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2458
2465
|
onResponse,
|
|
2459
2466
|
sessionId: providerSessionId,
|
|
2460
2467
|
promptCacheKey: options.providerPromptCacheKey,
|
|
2468
|
+
deadline: options.deadline,
|
|
2461
2469
|
transformContext,
|
|
2462
2470
|
transformProviderContext,
|
|
2463
2471
|
steeringMode: settings.get("steeringMode") ?? "one-at-a-time",
|
|
@@ -2475,28 +2483,16 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
2475
2483
|
kimiApiFormat: settings.get("providers.kimiApiFormat") ?? "anthropic",
|
|
2476
2484
|
preferWebsockets: preferOpenAICodexWebsockets,
|
|
2477
2485
|
getToolContext: tc => toolContextStore.getContext(tc),
|
|
2478
|
-
getApiKey:
|
|
2479
|
-
// Read agent.sessionId at call time so credential selection stays aligned
|
|
2480
|
-
// with metadataResolver after /new, fork, resume, or branch switches.
|
|
2481
|
-
// Retry steps (ctx carries an auth error) drive the central a/b/c
|
|
2482
|
-
// policy — force-refresh the same account, then rotate to a sibling —
|
|
2483
|
-
// and may legitimately yield no key when every account is exhausted.
|
|
2484
|
-
if (ctx?.error !== undefined) {
|
|
2485
|
-
return createApiKeyResolver(modelRegistry, provider, { sessionId: agent.sessionId })(ctx);
|
|
2486
|
-
}
|
|
2487
|
-
const key = await modelRegistry.getApiKeyForProvider(provider, agent.sessionId);
|
|
2488
|
-
if (!key) {
|
|
2489
|
-
throw new Error(`No API key found for provider "${provider}"`);
|
|
2490
|
-
}
|
|
2491
|
-
return key;
|
|
2492
|
-
},
|
|
2486
|
+
getApiKey: requestModel => modelRegistry.resolver(requestModel, agent.sessionId),
|
|
2493
2487
|
streamFn: (streamModel, context, streamOptions) => {
|
|
2494
2488
|
const openrouterRoutingPreset = settings.get("providers.openrouterVariant");
|
|
2495
2489
|
const openrouterVariant =
|
|
2496
2490
|
openrouterRoutingPreset && openrouterRoutingPreset !== "default" ? openrouterRoutingPreset : undefined;
|
|
2491
|
+
const antigravityEndpointMode = settings.get("providers.antigravityEndpoint");
|
|
2497
2492
|
return streamSimple(streamModel, context, {
|
|
2498
2493
|
...streamOptions,
|
|
2499
2494
|
openrouterVariant: streamOptions?.openrouterVariant ?? openrouterVariant,
|
|
2495
|
+
antigravityEndpointMode: streamOptions?.antigravityEndpointMode ?? antigravityEndpointMode,
|
|
2500
2496
|
});
|
|
2501
2497
|
},
|
|
2502
2498
|
cursorExecHandlers,
|