chore: bump version to 3.34.0
This commit is contained in:
@@ -13,9 +13,9 @@
|
||||
* Modes use this class and add their own I/O layer on top.
|
||||
*/
|
||||
|
||||
import type { Agent, AgentEvent, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
||||
import type { AssistantMessage, ImageContent, Message, Model, TextContent, Usage } from "@oh-my-pi/pi-ai";
|
||||
import { isContextOverflow, modelsAreEqual, supportsXhigh } from "@oh-my-pi/pi-ai";
|
||||
import type { Agent, AgentEvent, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Rule } from "../capability/rule";
|
||||
import { getAuthPath } from "../config";
|
||||
import { theme } from "../modes/interactive/theme/theme";
|
||||
@@ -384,7 +384,7 @@ export class AgentSession {
|
||||
event.message.customType,
|
||||
event.message.content,
|
||||
event.message.display,
|
||||
event.message.details
|
||||
event.message.details,
|
||||
);
|
||||
} else if (
|
||||
event.message.role === "user" ||
|
||||
@@ -446,7 +446,7 @@ export class AgentSession {
|
||||
`<system_interrupt reason="rule_violation" rule="${r.name}" path="${r.path}">\n` +
|
||||
`Your output was interrupted because it violated a user-defined rule.\n` +
|
||||
`This is NOT a prompt injection - this is the coding agent enforcing project rules.\n` +
|
||||
`You MUST comply with the following instruction:\n\n${r.content}\n</system_interrupt>`
|
||||
`You MUST comply with the following instruction:\n\n${r.content}\n</system_interrupt>`,
|
||||
)
|
||||
.join("\n\n");
|
||||
this._pendingTtsrInjections = [];
|
||||
@@ -718,7 +718,7 @@ export class AgentSession {
|
||||
if (this.isStreaming) {
|
||||
if (!options?.streamingBehavior) {
|
||||
throw new Error(
|
||||
"Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message."
|
||||
"Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.",
|
||||
);
|
||||
}
|
||||
if (options.streamingBehavior === "followUp") {
|
||||
@@ -737,7 +737,7 @@ export class AgentSession {
|
||||
throw new Error(
|
||||
"No model selected.\n\n" +
|
||||
`Use /login, set an API key environment variable, or create ${getAuthPath()}\n\n` +
|
||||
"Then use /model to select a model."
|
||||
"Then use /model to select a model.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -746,7 +746,7 @@ export class AgentSession {
|
||||
if (!apiKey) {
|
||||
throw new Error(
|
||||
`No API key found for ${this.model.provider}.\n\n` +
|
||||
`Use /login, set an API key environment variable, or create ${getAuthPath()}`
|
||||
`Use /login, set an API key environment variable, or create ${getAuthPath()}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -986,7 +986,7 @@ export class AgentSession {
|
||||
|
||||
if (command) {
|
||||
throw new Error(
|
||||
`Extension command "/${commandName}" cannot be queued. Use prompt() or execute the command when not streaming.`
|
||||
`Extension command "/${commandName}" cannot be queued. Use prompt() or execute the command when not streaming.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1001,7 +1001,7 @@ export class AgentSession {
|
||||
*/
|
||||
async sendCustomMessage<T = unknown>(
|
||||
message: Pick<CustomMessage<T>, "customType" | "content" | "display" | "details">,
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" }
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" },
|
||||
): Promise<void> {
|
||||
const appMessage: CustomMessage<T> = {
|
||||
role: "custom",
|
||||
@@ -1031,7 +1031,12 @@ export class AgentSession {
|
||||
}
|
||||
|
||||
this.agent.appendMessage(appMessage);
|
||||
this.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, message.details);
|
||||
this.sessionManager.appendCustomMessageEntry(
|
||||
message.customType,
|
||||
message.content,
|
||||
message.display,
|
||||
message.details,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1176,7 +1181,7 @@ export class AgentSession {
|
||||
*/
|
||||
async cycleRoleModels(
|
||||
roleOrder: string[],
|
||||
options?: { temporary?: boolean }
|
||||
options?: { temporary?: boolean },
|
||||
): Promise<RoleModelCycleResult | undefined> {
|
||||
const availableModels = this._modelRegistry.getAvailable();
|
||||
if (availableModels.length === 0) return undefined;
|
||||
@@ -1189,7 +1194,7 @@ export class AgentSession {
|
||||
for (const role of roleOrder) {
|
||||
const roleModelStr =
|
||||
role === "default"
|
||||
? this.settingsManager.getModelRole("default") ?? `${currentModel.provider}/${currentModel.id}`
|
||||
? (this.settingsManager.getModelRole("default") ?? `${currentModel.provider}/${currentModel.id}`)
|
||||
: this.settingsManager.getModelRole(role);
|
||||
if (!roleModelStr) continue;
|
||||
|
||||
@@ -1454,7 +1459,7 @@ export class AgentSession {
|
||||
this.model,
|
||||
apiKey,
|
||||
customInstructions,
|
||||
this._compactionAbortController.signal
|
||||
this._compactionAbortController.signal,
|
||||
);
|
||||
summary = result.summary;
|
||||
firstKeptEntryId = result.firstKeptEntryId;
|
||||
@@ -1627,7 +1632,7 @@ export class AgentSession {
|
||||
this.model,
|
||||
apiKey,
|
||||
undefined,
|
||||
this._autoCompactionAbortController.signal
|
||||
this._autoCompactionAbortController.signal,
|
||||
);
|
||||
summary = compactResult.summary;
|
||||
firstKeptEntryId = compactResult.firstKeptEntryId;
|
||||
@@ -1684,7 +1689,7 @@ export class AgentSession {
|
||||
throw new Error(
|
||||
`Context overflow: ${
|
||||
error instanceof Error ? error.message : "compaction failed"
|
||||
}. Your input may be too large for the context window.`
|
||||
}. Your input may be too large for the context window.`,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
@@ -1722,7 +1727,7 @@ export class AgentSession {
|
||||
const err = message.errorMessage;
|
||||
// Match: overloaded_error, rate limit, 429, 500, 502, 503, 504, service unavailable, connection error
|
||||
return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error/i.test(
|
||||
err
|
||||
err,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1876,7 +1881,7 @@ export class AgentSession {
|
||||
async executeBash(
|
||||
command: string,
|
||||
onChunk?: (chunk: string) => void,
|
||||
options?: { excludeFromContext?: boolean }
|
||||
options?: { excludeFromContext?: boolean },
|
||||
): Promise<BashResult> {
|
||||
this._bashAbortController = new AbortController();
|
||||
|
||||
@@ -2107,7 +2112,7 @@ export class AgentSession {
|
||||
*/
|
||||
async navigateTree(
|
||||
targetId: string,
|
||||
options: { summarize?: boolean; customInstructions?: string } = {}
|
||||
options: { summarize?: boolean; customInstructions?: string } = {},
|
||||
): Promise<{ editorText?: string; cancelled: boolean; aborted?: boolean; summaryEntry?: BranchSummaryEntry }> {
|
||||
const oldLeafId = this.sessionManager.getLeafId();
|
||||
|
||||
@@ -2130,7 +2135,7 @@ export class AgentSession {
|
||||
const { entries: entriesToSummarize, commonAncestorId } = collectEntriesForBranchSummary(
|
||||
this.sessionManager,
|
||||
oldLeafId,
|
||||
targetId
|
||||
targetId,
|
||||
);
|
||||
|
||||
// Prepare event data
|
||||
|
||||
@@ -44,7 +44,10 @@ export class AuthStorage {
|
||||
* @param authPath - Primary path for reading/writing auth.json
|
||||
* @param fallbackPaths - Additional paths to check when reading (legacy support)
|
||||
*/
|
||||
constructor(private authPath: string, private fallbackPaths: string[] = []) {}
|
||||
constructor(
|
||||
private authPath: string,
|
||||
private fallbackPaths: string[] = [],
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Set a runtime API key override (not persisted to disk).
|
||||
@@ -173,7 +176,7 @@ export class AuthStorage {
|
||||
onAuth: (info: { url: string; instructions?: string }) => void;
|
||||
onPrompt: (prompt: { message: string; placeholder?: string }) => Promise<string>;
|
||||
onProgress?: (message: string) => void;
|
||||
}
|
||||
},
|
||||
): Promise<void> {
|
||||
let credentials: OAuthCredentials;
|
||||
|
||||
@@ -181,7 +184,7 @@ export class AuthStorage {
|
||||
case "anthropic":
|
||||
credentials = await loginAnthropic(
|
||||
(url) => callbacks.onAuth({ url }),
|
||||
() => callbacks.onPrompt({ message: "Paste the authorization code:" })
|
||||
() => callbacks.onPrompt({ message: "Paste the authorization code:" }),
|
||||
);
|
||||
break;
|
||||
case "github-copilot":
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
* a summary of the branch being left so context isn't lost.
|
||||
*/
|
||||
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import { completeSimple } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import branchSummaryPrompt from "../../prompts/branch-summary.md" with { type: "text" };
|
||||
import branchSummaryPreamble from "../../prompts/branch-summary-preamble.md" with { type: "text" };
|
||||
import {
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
* and after compaction the session is reloaded.
|
||||
*/
|
||||
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { AssistantMessage, Model, Usage } from "@oh-my-pi/pi-ai";
|
||||
import { complete, completeSimple } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import compactionSummaryPrompt from "../../prompts/compaction-summary.md" with { type: "text" };
|
||||
import compactionTurnPrefixPrompt from "../../prompts/compaction-turn-prefix.md" with { type: "text" };
|
||||
import compactionUpdateSummaryPrompt from "../../prompts/compaction-update-summary.md" with { type: "text" };
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Shared utilities for compaction and branch summarization.
|
||||
*/
|
||||
|
||||
import type { Message } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Message } from "@oh-my-pi/pi-ai";
|
||||
import summarizationSystemPrompt from "../../prompts/summarization-system.md" with { type: "text" };
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* They can provide custom rendering for tool calls and results in the TUI.
|
||||
*/
|
||||
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import type { Component } from "@oh-my-pi/pi-tui";
|
||||
import type { Static, TSchema } from "@sinclair/typebox";
|
||||
import type { Theme } from "../../modes/interactive/theme/theme";
|
||||
@@ -140,7 +140,7 @@ export interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {
|
||||
params: Static<TParams>,
|
||||
onUpdate: AgentToolUpdateCallback<TDetails> | undefined,
|
||||
ctx: CustomToolContext,
|
||||
signal?: AbortSignal
|
||||
signal?: AbortSignal,
|
||||
): Promise<AgentToolResult<TDetails>>;
|
||||
|
||||
/** Called on session lifecycle events - use to reconstruct state or cleanup resources */
|
||||
@@ -154,7 +154,7 @@ export interface CustomTool<TParams extends TSchema = TSchema, TDetails = any> {
|
||||
|
||||
/** Factory function that creates a custom tool or array of tools */
|
||||
export type CustomToolFactory = (
|
||||
pi: CustomToolAPI
|
||||
pi: CustomToolAPI,
|
||||
) => CustomTool<any, any> | CustomTool<any, any>[] | Promise<CustomTool<any, any> | CustomTool<any, any>[]>;
|
||||
|
||||
/** Loaded custom tool with metadata and wrapped AgentTool */
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Extension runner - executes extensions and manages their lifecycle.
|
||||
*/
|
||||
|
||||
import type { ImageContent, Model } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { ImageContent, Model } from "@oh-my-pi/pi-ai";
|
||||
import type { KeyId } from "@oh-my-pi/pi-tui";
|
||||
import { theme } from "../../modes/interactive/theme/theme";
|
||||
import type { ModelRegistry } from "../model-registry";
|
||||
@@ -53,7 +53,7 @@ export type BranchHandler = (entryId: string) => Promise<{ cancelled: boolean }>
|
||||
|
||||
export type NavigateTreeHandler = (
|
||||
targetId: string,
|
||||
options?: { summarize?: boolean }
|
||||
options?: { summarize?: boolean },
|
||||
) => Promise<{ cancelled: boolean }>;
|
||||
|
||||
const noOpUIContext: ExtensionUIContext = {
|
||||
@@ -94,7 +94,7 @@ export class ExtensionRunner {
|
||||
extensions: LoadedExtension[],
|
||||
cwd: string,
|
||||
sessionManager: SessionManager,
|
||||
modelRegistry: ModelRegistry
|
||||
modelRegistry: ModelRegistry,
|
||||
) {
|
||||
this.extensions = extensions;
|
||||
this.uiContext = noOpUIContext;
|
||||
@@ -215,7 +215,7 @@ export class ExtensionRunner {
|
||||
|
||||
if (ExtensionRunner.RESERVED_SHORTCUTS.has(normalizedKey)) {
|
||||
console.warn(
|
||||
`Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.`
|
||||
`Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -223,7 +223,7 @@ export class ExtensionRunner {
|
||||
const existing = allShortcuts.get(normalizedKey);
|
||||
if (existing) {
|
||||
console.warn(
|
||||
`Extension shortcut conflict: '${key}' registered by both ${existing.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`
|
||||
`Extension shortcut conflict: '${key}' registered by both ${existing.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`,
|
||||
);
|
||||
}
|
||||
allShortcuts.set(normalizedKey, shortcut);
|
||||
@@ -309,7 +309,7 @@ export class ExtensionRunner {
|
||||
}
|
||||
|
||||
private isSessionBeforeEvent(
|
||||
type: string
|
||||
type: string,
|
||||
): type is "session_before_switch" | "session_before_branch" | "session_before_compact" | "session_before_tree" {
|
||||
return (
|
||||
type === "session_before_switch" ||
|
||||
@@ -320,7 +320,7 @@ export class ExtensionRunner {
|
||||
}
|
||||
|
||||
async emit(
|
||||
event: ExtensionEvent
|
||||
event: ExtensionEvent,
|
||||
): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined> {
|
||||
const ctx = this.createContext();
|
||||
let result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined;
|
||||
@@ -428,7 +428,7 @@ export class ExtensionRunner {
|
||||
|
||||
async emitBeforeAgentStart(
|
||||
prompt: string,
|
||||
images?: ImageContent[]
|
||||
images?: ImageContent[],
|
||||
): Promise<BeforeAgentStartCombinedResult | undefined> {
|
||||
const ctx = this.createContext();
|
||||
const messages: NonNullable<BeforeAgentStartEventResult["message"]>[] = [];
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
* - Interact with the user via UI primitives
|
||||
*/
|
||||
|
||||
import type { ImageContent, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
||||
import type { ImageContent, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
|
||||
import type { Component, KeyId, TUI } from "@oh-my-pi/pi-tui";
|
||||
import type { Static, TSchema } from "@sinclair/typebox";
|
||||
import type { Theme } from "../../modes/interactive/theme/theme";
|
||||
@@ -67,8 +67,8 @@ export interface ExtensionUIContext {
|
||||
factory: (
|
||||
tui: TUI,
|
||||
theme: Theme,
|
||||
done: (result: T) => void
|
||||
) => (Component & { dispose?(): void }) | Promise<Component & { dispose?(): void }>
|
||||
done: (result: T) => void,
|
||||
) => (Component & { dispose?(): void }) | Promise<Component & { dispose?(): void }>,
|
||||
): Promise<T>;
|
||||
|
||||
/** Set the text in the core input editor. */
|
||||
@@ -178,7 +178,7 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
|
||||
params: Static<TParams>,
|
||||
onUpdate: AgentToolUpdateCallback<TDetails> | undefined,
|
||||
ctx: ExtensionContext,
|
||||
signal?: AbortSignal
|
||||
signal?: AbortSignal,
|
||||
): Promise<AgentToolResult<TDetails>>;
|
||||
|
||||
/** Called on session lifecycle events - use to reconstruct state or cleanup resources */
|
||||
@@ -490,7 +490,7 @@ export interface MessageRenderOptions {
|
||||
export type MessageRenderer<T = unknown> = (
|
||||
message: CustomMessage<T>,
|
||||
options: MessageRenderOptions,
|
||||
theme: Theme
|
||||
theme: Theme,
|
||||
) => Component | undefined;
|
||||
|
||||
// ============================================================================
|
||||
@@ -535,17 +535,17 @@ export interface ExtensionAPI {
|
||||
on(event: "session_start", handler: ExtensionHandler<SessionStartEvent>): void;
|
||||
on(
|
||||
event: "session_before_switch",
|
||||
handler: ExtensionHandler<SessionBeforeSwitchEvent, SessionBeforeSwitchResult>
|
||||
handler: ExtensionHandler<SessionBeforeSwitchEvent, SessionBeforeSwitchResult>,
|
||||
): void;
|
||||
on(event: "session_switch", handler: ExtensionHandler<SessionSwitchEvent>): void;
|
||||
on(
|
||||
event: "session_before_branch",
|
||||
handler: ExtensionHandler<SessionBeforeBranchEvent, SessionBeforeBranchResult>
|
||||
handler: ExtensionHandler<SessionBeforeBranchEvent, SessionBeforeBranchResult>,
|
||||
): void;
|
||||
on(event: "session_branch", handler: ExtensionHandler<SessionBranchEvent>): void;
|
||||
on(
|
||||
event: "session_before_compact",
|
||||
handler: ExtensionHandler<SessionBeforeCompactEvent, SessionBeforeCompactResult>
|
||||
handler: ExtensionHandler<SessionBeforeCompactEvent, SessionBeforeCompactResult>,
|
||||
): void;
|
||||
on(event: "session_compact", handler: ExtensionHandler<SessionCompactEvent>): void;
|
||||
on(event: "session_shutdown", handler: ExtensionHandler<SessionShutdownEvent>): void;
|
||||
@@ -580,7 +580,7 @@ export interface ExtensionAPI {
|
||||
options: {
|
||||
description?: string;
|
||||
handler: (ctx: ExtensionContext) => Promise<void> | void;
|
||||
}
|
||||
},
|
||||
): void;
|
||||
|
||||
/** Register a CLI flag. */
|
||||
@@ -590,7 +590,7 @@ export interface ExtensionAPI {
|
||||
description?: string;
|
||||
type: "boolean" | "string";
|
||||
default?: boolean | string;
|
||||
}
|
||||
},
|
||||
): void;
|
||||
|
||||
/** Get the value of a registered CLI flag. */
|
||||
@@ -610,7 +610,7 @@ export interface ExtensionAPI {
|
||||
/** Send a custom message to the session. */
|
||||
sendMessage<T = unknown>(
|
||||
message: Pick<CustomMessage<T>, "customType" | "content" | "display" | "details">,
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" }
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" },
|
||||
): void;
|
||||
|
||||
/** Append a custom entry to the session for state persistence (not sent to LLM). */
|
||||
@@ -663,7 +663,7 @@ type HandlerFn = (...args: unknown[]) => Promise<unknown>;
|
||||
|
||||
export type SendMessageHandler = <T = unknown>(
|
||||
message: Pick<CustomMessage<T>, "customType" | "content" | "display" | "details">,
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" }
|
||||
options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" },
|
||||
) => void;
|
||||
|
||||
export type AppendEntryHandler = <T = unknown>(customType: string, data?: T) => void;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Tool wrappers for extensions.
|
||||
*/
|
||||
|
||||
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
||||
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
||||
import type { Theme } from "../../modes/interactive/theme/theme";
|
||||
import type { ExtensionRunner } from "./runner";
|
||||
import type { ExtensionContext, RegisteredTool, ToolCallEventResult, ToolResultEventResult } from "./types";
|
||||
@@ -26,7 +26,7 @@ export function wrapRegisteredTool(registeredTool: RegisteredTool, getContext: (
|
||||
definition.renderResult?.(
|
||||
result,
|
||||
{ expanded: options.expanded, isPartial: options.isPartial, spinnerFrame: options.spinnerFrame },
|
||||
theme as Theme
|
||||
theme as Theme,
|
||||
)
|
||||
: undefined,
|
||||
};
|
||||
@@ -37,7 +37,7 @@ export function wrapRegisteredTool(registeredTool: RegisteredTool, getContext: (
|
||||
*/
|
||||
export function wrapRegisteredTools(
|
||||
registeredTools: RegisteredTool[],
|
||||
getContext: () => ExtensionContext
|
||||
getContext: () => ExtensionContext,
|
||||
): AgentTool[] {
|
||||
return registeredTools.map((rt) => wrapRegisteredTool(rt, getContext));
|
||||
}
|
||||
@@ -55,7 +55,7 @@ export function wrapToolWithExtensions<T>(tool: AgentTool<any, T>, runner: Exten
|
||||
params: Record<string, unknown>,
|
||||
signal?: AbortSignal,
|
||||
onUpdate?: AgentToolUpdateCallback<T>,
|
||||
context?: AgentToolContext
|
||||
context?: AgentToolContext,
|
||||
) => {
|
||||
// Emit tool_call event - extensions can block execution
|
||||
if (runner.hasHandlers("tool_call")) {
|
||||
@@ -113,7 +113,8 @@ export function wrapToolWithExtensions<T>(tool: AgentTool<any, T>, runner: Exten
|
||||
if (resultResult.isError === true && !executionError) {
|
||||
// Extension marks a successful result as error
|
||||
const textBlocks = (modifiedContent ?? []).filter((c): c is TextContent => c.type === "text");
|
||||
const errorText = textBlocks.map((t) => t.text).join("\n") || "Tool result marked as error by extension";
|
||||
const errorText =
|
||||
textBlocks.map((t) => t.text).join("\n") || "Tool result marked as error by extension";
|
||||
throw new Error(errorText);
|
||||
}
|
||||
if (resultResult.isError === false && executionError) {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Hook runner - executes hooks and manages their lifecycle.
|
||||
*/
|
||||
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import { theme } from "../../modes/interactive/theme/theme";
|
||||
import type { ModelRegistry } from "../model-registry";
|
||||
import type { SessionManager } from "../session-manager";
|
||||
@@ -272,7 +272,7 @@ export class HookRunner {
|
||||
* Check if event type is a session "before_*" event that can be cancelled.
|
||||
*/
|
||||
private isSessionBeforeEvent(
|
||||
type: string
|
||||
type: string,
|
||||
): type is "session_before_switch" | "session_before_branch" | "session_before_compact" | "session_before_tree" {
|
||||
return (
|
||||
type === "session_before_switch" ||
|
||||
@@ -287,7 +287,7 @@ export class HookRunner {
|
||||
* Returns the result from session before_* / tool_result events (if any handler returns one).
|
||||
*/
|
||||
async emit(
|
||||
event: HookEvent
|
||||
event: HookEvent,
|
||||
): Promise<SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined> {
|
||||
const ctx = this.createContext();
|
||||
let result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined;
|
||||
@@ -400,7 +400,7 @@ export class HookRunner {
|
||||
*/
|
||||
async emitBeforeAgentStart(
|
||||
prompt: string,
|
||||
images?: import("@oh-my-pi/pi-ai").ImageContent[]
|
||||
images?: import("@oh-my-pi/pi-ai").ImageContent[],
|
||||
): Promise<BeforeAgentStartEventResult | undefined> {
|
||||
const ctx = this.createContext();
|
||||
let result: BeforeAgentStartEventResult | undefined;
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* and interact with the user via UI primitives.
|
||||
*/
|
||||
|
||||
import type { ImageContent, Message, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { ImageContent, Message, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
|
||||
import type { Component, TUI } from "@oh-my-pi/pi-tui";
|
||||
import type { Theme } from "../../modes/interactive/theme/theme";
|
||||
import type { CompactionPreparation, CompactionResult } from "../compaction/index";
|
||||
@@ -97,8 +97,8 @@ export interface HookUIContext {
|
||||
factory: (
|
||||
tui: TUI,
|
||||
theme: Theme,
|
||||
done: (result: T) => void
|
||||
) => (Component & { dispose?(): void }) | Promise<Component & { dispose?(): void }>
|
||||
done: (result: T) => void,
|
||||
) => (Component & { dispose?(): void }) | Promise<Component & { dispose?(): void }>,
|
||||
): Promise<T>;
|
||||
|
||||
/**
|
||||
@@ -632,7 +632,7 @@ export interface HookMessageRenderOptions {
|
||||
export type HookMessageRenderer<T = unknown> = (
|
||||
message: HookMessage<T>,
|
||||
options: HookMessageRenderOptions,
|
||||
theme: Theme
|
||||
theme: Theme,
|
||||
) => Component | undefined;
|
||||
|
||||
/**
|
||||
@@ -658,7 +658,7 @@ export interface HookAPI {
|
||||
on(event: "session_branch", handler: HookHandler<SessionBranchEvent>): void;
|
||||
on(
|
||||
event: "session_before_compact",
|
||||
handler: HookHandler<SessionBeforeCompactEvent, SessionBeforeCompactResult>
|
||||
handler: HookHandler<SessionBeforeCompactEvent, SessionBeforeCompactResult>,
|
||||
): void;
|
||||
on(event: "session_compact", handler: HookHandler<SessionCompactEvent>): void;
|
||||
on(event: "session_shutdown", handler: HookHandler<SessionShutdownEvent>): void;
|
||||
@@ -692,7 +692,7 @@ export interface HookAPI {
|
||||
*/
|
||||
sendMessage<T = unknown>(
|
||||
message: Pick<HookMessage<T>, "customType" | "content" | "display" | "details">,
|
||||
triggerTurn?: boolean
|
||||
triggerTurn?: boolean,
|
||||
): void;
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
* and provides a transformer to convert them to LLM-compatible messages.
|
||||
*/
|
||||
|
||||
import type { ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai";
|
||||
|
||||
export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
|
||||
|
||||
@@ -136,7 +136,7 @@ export function createBranchSummaryMessage(summary: string, fromId: string, time
|
||||
export function createCompactionSummaryMessage(
|
||||
summary: string,
|
||||
tokensBefore: number,
|
||||
timestamp: string
|
||||
timestamp: string,
|
||||
): CompactionSummaryMessage {
|
||||
return {
|
||||
role: "compactionSummary",
|
||||
@@ -152,7 +152,7 @@ export function createCustomMessage(
|
||||
content: string | (TextContent | ImageContent)[],
|
||||
display: boolean,
|
||||
details: unknown | undefined,
|
||||
timestamp: string
|
||||
timestamp: string,
|
||||
): CustomMessage {
|
||||
return {
|
||||
role: "custom",
|
||||
|
||||
@@ -39,7 +39,7 @@ const ModelDefinitionSchema = Type.Object({
|
||||
Type.Literal("anthropic-messages"),
|
||||
Type.Literal("google-generative-ai"),
|
||||
Type.Literal("google-vertex"),
|
||||
])
|
||||
]),
|
||||
),
|
||||
reasoning: Type.Boolean(),
|
||||
input: Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")])),
|
||||
@@ -66,7 +66,7 @@ const ProviderConfigSchema = Type.Object({
|
||||
Type.Literal("anthropic-messages"),
|
||||
Type.Literal("google-generative-ai"),
|
||||
Type.Literal("google-vertex"),
|
||||
])
|
||||
]),
|
||||
),
|
||||
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
||||
authHeader: Type.Optional(Type.Boolean()),
|
||||
@@ -126,7 +126,7 @@ export class ModelRegistry {
|
||||
constructor(
|
||||
readonly authStorage: AuthStorage,
|
||||
private modelsJsonPath: string | undefined = undefined,
|
||||
private fallbackPaths: string[] = []
|
||||
private fallbackPaths: string[] = [],
|
||||
) {
|
||||
// Set up fallback resolver for custom provider API keys
|
||||
this.authStorage.setFallbackResolver((provider) => {
|
||||
@@ -189,7 +189,9 @@ export class ModelRegistry {
|
||||
// Update github-copilot base URL based on OAuth credentials
|
||||
const copilotCred = this.authStorage.get("github-copilot");
|
||||
if (copilotCred?.type === "oauth") {
|
||||
const domain = copilotCred.enterpriseUrl ? normalizeDomain(copilotCred.enterpriseUrl) ?? undefined : undefined;
|
||||
const domain = copilotCred.enterpriseUrl
|
||||
? (normalizeDomain(copilotCred.enterpriseUrl) ?? undefined)
|
||||
: undefined;
|
||||
const baseUrl = getGitHubCopilotBaseUrl(copilotCred.access, domain);
|
||||
this.models = combined.map((m) => (m.provider === "github-copilot" ? { ...m, baseUrl } : m));
|
||||
} else {
|
||||
@@ -265,7 +267,7 @@ export class ModelRegistry {
|
||||
return emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\n\nFile: ${modelsJsonPath}`);
|
||||
}
|
||||
return emptyCustomModelsResult(
|
||||
`Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`
|
||||
`Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -279,7 +281,7 @@ export class ModelRegistry {
|
||||
// Override-only config: just needs baseUrl (to override built-in)
|
||||
if (!providerConfig.baseUrl) {
|
||||
throw new Error(
|
||||
`Provider ${providerName}: must specify either "baseUrl" (for override) or "models" (for replacement).`
|
||||
`Provider ${providerName}: must specify either "baseUrl" (for override) or "models" (for replacement).`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@@ -297,7 +299,7 @@ export class ModelRegistry {
|
||||
|
||||
if (!hasProviderApi && !hasModelApi) {
|
||||
throw new Error(
|
||||
`Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.`
|
||||
`Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -329,7 +331,9 @@ export class ModelRegistry {
|
||||
|
||||
// Merge headers: provider headers are base, model headers override
|
||||
let headers =
|
||||
providerConfig.headers || modelDef.headers ? { ...providerConfig.headers, ...modelDef.headers } : undefined;
|
||||
providerConfig.headers || modelDef.headers
|
||||
? { ...providerConfig.headers, ...modelDef.headers }
|
||||
: undefined;
|
||||
|
||||
// If authHeader is true, add Authorization header with resolved API key
|
||||
if (providerConfig.authHeader && providerConfig.apiKey) {
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
* Model resolution, scoping, and initial selection
|
||||
*/
|
||||
|
||||
import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my-pi/pi-ai";
|
||||
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
||||
import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my-pi/pi-ai";
|
||||
import chalk from "chalk";
|
||||
import { minimatch } from "minimatch";
|
||||
import { isValidThinkingLevel } from "../cli/args";
|
||||
@@ -25,6 +25,7 @@ export const defaultModelPerProvider: Record<KnownProvider, string> = {
|
||||
cerebras: "zai-glm-4.6",
|
||||
zai: "glm-4.6",
|
||||
mistral: "devstral-medium-latest",
|
||||
opencode: "claude-sonnet-4-5",
|
||||
};
|
||||
|
||||
export interface ScopedModel {
|
||||
@@ -79,7 +80,7 @@ function tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Mod
|
||||
const provider = modelPattern.substring(0, slashIndex);
|
||||
const modelId = modelPattern.substring(slashIndex + 1);
|
||||
const providerMatch = availableModels.find(
|
||||
(m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase()
|
||||
(m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(),
|
||||
);
|
||||
if (providerMatch) {
|
||||
return providerMatch;
|
||||
@@ -97,7 +98,7 @@ function tryMatchModel(modelPattern: string, availableModels: Model<Api>[]): Mod
|
||||
const matches = availableModels.filter(
|
||||
(m) =>
|
||||
m.id.toLowerCase().includes(modelPattern.toLowerCase()) ||
|
||||
m.name?.toLowerCase().includes(modelPattern.toLowerCase())
|
||||
m.name?.toLowerCase().includes(modelPattern.toLowerCase()),
|
||||
);
|
||||
|
||||
if (matches.length === 0) {
|
||||
@@ -351,7 +352,7 @@ export async function restoreModelFromSession(
|
||||
savedModelId: string,
|
||||
currentModel: Model<Api> | undefined,
|
||||
shouldPrintMessages: boolean,
|
||||
modelRegistry: ModelRegistry
|
||||
modelRegistry: ModelRegistry,
|
||||
): Promise<{ model: Model<Api> | undefined; fallbackMessage: string | undefined }> {
|
||||
const restoredModel = modelRegistry.find(savedProvider, savedModelId);
|
||||
|
||||
@@ -427,7 +428,7 @@ export async function restoreModelFromSession(
|
||||
*/
|
||||
export async function findSmolModel(
|
||||
modelRegistry: ModelRegistry,
|
||||
savedModel?: string
|
||||
savedModel?: string,
|
||||
): Promise<Model<Api> | undefined> {
|
||||
const availableModels = modelRegistry.getAvailable();
|
||||
if (availableModels.length === 0) return undefined;
|
||||
@@ -470,7 +471,7 @@ export async function findSmolModel(
|
||||
*/
|
||||
export async function findSlowModel(
|
||||
modelRegistry: ModelRegistry,
|
||||
savedModel?: string
|
||||
savedModel?: string,
|
||||
): Promise<Model<Api> | undefined> {
|
||||
const availableModels = modelRegistry.getAvailable();
|
||||
if (availableModels.length === 0) return undefined;
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
*/
|
||||
|
||||
import { join } from "node:path";
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import { Agent, type AgentTool, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Model } from "@oh-my-pi/pi-ai";
|
||||
import type { Component } from "@oh-my-pi/pi-tui";
|
||||
import chalk from "chalk";
|
||||
// Import discovery to register all providers on startup
|
||||
@@ -248,7 +248,7 @@ export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir(
|
||||
*/
|
||||
export async function discoverModels(
|
||||
authStorage: AuthStorage,
|
||||
agentDir: string = getDefaultAgentDir()
|
||||
agentDir: string = getDefaultAgentDir(),
|
||||
): Promise<ModelRegistry> {
|
||||
const primaryPath = join(agentDir, "models.json");
|
||||
// Get all models.json paths (user-level only), excluding the primary
|
||||
@@ -288,7 +288,7 @@ export function discoverSkills(cwd?: string, _agentDir?: string, settings?: Skil
|
||||
*/
|
||||
export function discoverContextFiles(
|
||||
cwd?: string,
|
||||
_agentDir?: string
|
||||
_agentDir?: string,
|
||||
): Array<{ path: string; content: string; depth?: number }> {
|
||||
return loadContextFilesInternal({
|
||||
cwd: cwd ?? process.cwd(),
|
||||
@@ -436,11 +436,11 @@ function customToolToDefinition(tool: CustomTool): ToolDefinition {
|
||||
const component = tool.renderResult?.(
|
||||
result,
|
||||
{ expanded: options.expanded, isPartial: options.isPartial, spinnerFrame: options.spinnerFrame },
|
||||
theme
|
||||
theme,
|
||||
);
|
||||
// Return empty component if undefined to match Component type requirement
|
||||
return component ?? ({ render: () => [] } as unknown as Component);
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
[TOOL_DEFINITION_MARKER]: true,
|
||||
};
|
||||
@@ -465,19 +465,19 @@ function createCustomToolsExtension(tools: CustomTool[]): ExtensionFactory {
|
||||
};
|
||||
|
||||
api.on("session_start", async (_event, ctx) =>
|
||||
runOnSession({ reason: "start", previousSessionFile: undefined }, ctx)
|
||||
runOnSession({ reason: "start", previousSessionFile: undefined }, ctx),
|
||||
);
|
||||
api.on("session_switch", async (event, ctx) =>
|
||||
runOnSession({ reason: "switch", previousSessionFile: event.previousSessionFile }, ctx)
|
||||
runOnSession({ reason: "switch", previousSessionFile: event.previousSessionFile }, ctx),
|
||||
);
|
||||
api.on("session_branch", async (event, ctx) =>
|
||||
runOnSession({ reason: "branch", previousSessionFile: event.previousSessionFile }, ctx)
|
||||
runOnSession({ reason: "branch", previousSessionFile: event.previousSessionFile }, ctx),
|
||||
);
|
||||
api.on("session_tree", async (_event, ctx) =>
|
||||
runOnSession({ reason: "tree", previousSessionFile: undefined }, ctx)
|
||||
runOnSession({ reason: "tree", previousSessionFile: undefined }, ctx),
|
||||
);
|
||||
api.on("session_shutdown", async (_event, ctx) =>
|
||||
runOnSession({ reason: "shutdown", previousSessionFile: undefined }, ctx)
|
||||
runOnSession({ reason: "shutdown", previousSessionFile: undefined }, ctx),
|
||||
);
|
||||
};
|
||||
}
|
||||
@@ -659,7 +659,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
if (options.hasUI && serverNames.length > 0) {
|
||||
process.stderr.write(
|
||||
chalk.gray(`Connecting to MCP servers: ${serverNames.join(", ")}...
|
||||
`)
|
||||
`),
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -728,7 +728,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
configuredPaths,
|
||||
cwd,
|
||||
eventBus,
|
||||
settingsManager.getDisabledExtensions()
|
||||
settingsManager.getDisabledExtensions(),
|
||||
);
|
||||
time("discoverAndLoadExtensions");
|
||||
for (const { path, error } of extensionsResult.errors) {
|
||||
@@ -905,7 +905,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
||||
transformContext: extensionRunner
|
||||
? async (messages) => {
|
||||
return extensionRunner.emitContext(messages);
|
||||
}
|
||||
}
|
||||
: undefined,
|
||||
steeringMode: settingsManager.getSteeringMode(),
|
||||
followUpMode: settingsManager.getFollowUpMode(),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { basename, join, resolve } from "node:path";
|
||||
import type { ImageContent, Message, TextContent, Usage } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
||||
import type { ImageContent, Message, TextContent, Usage } from "@oh-my-pi/pi-ai";
|
||||
import { nanoid } from "nanoid";
|
||||
import { getAgentDir as getDefaultAgentDir } from "../config";
|
||||
import { resizeImage } from "../utils/image-resize";
|
||||
@@ -304,7 +304,7 @@ function toError(value: unknown): Error {
|
||||
export function buildSessionContext(
|
||||
entries: SessionEntry[],
|
||||
leafId?: string | null,
|
||||
byId?: Map<string, SessionEntry>
|
||||
byId?: Map<string, SessionEntry>,
|
||||
): SessionContext {
|
||||
// Build uuid index if not available
|
||||
if (!byId) {
|
||||
@@ -382,7 +382,7 @@ export function buildSessionContext(
|
||||
messages.push(entry.message);
|
||||
} else if (entry.type === "custom_message") {
|
||||
messages.push(
|
||||
createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp)
|
||||
createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp),
|
||||
);
|
||||
} else if (entry.type === "branch_summary" && entry.summary) {
|
||||
messages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp));
|
||||
@@ -540,7 +540,7 @@ function getSortedSessions(sessionDir: string, storage: SessionStorage): RecentS
|
||||
/** Exported for testing */
|
||||
export function findMostRecentSession(
|
||||
sessionDir: string,
|
||||
storage: SessionStorage = new FileSessionStorage()
|
||||
storage: SessionStorage = new FileSessionStorage(),
|
||||
): string | null {
|
||||
const sessions = getSortedSessions(sessionDir, storage);
|
||||
return sessions[0]?.path || null;
|
||||
@@ -645,7 +645,7 @@ async function truncateForPersistence<T>(obj: T, key?: string): Promise<T> {
|
||||
const newItem = await truncateForPersistence(item, key);
|
||||
if (newItem !== item) changed = true;
|
||||
return newItem;
|
||||
})
|
||||
}),
|
||||
);
|
||||
return changed ? (result as T) : obj;
|
||||
}
|
||||
@@ -800,7 +800,7 @@ class NdjsonFileWriter {
|
||||
export function getRecentSessions(
|
||||
sessionDir: string,
|
||||
limit = 3,
|
||||
storage: SessionStorage = new FileSessionStorage()
|
||||
storage: SessionStorage = new FileSessionStorage(),
|
||||
): RecentSessionInfo[] {
|
||||
return getSortedSessions(sessionDir, storage).slice(0, limit);
|
||||
}
|
||||
@@ -1021,7 +1021,7 @@ export class SessionManager {
|
||||
async () => {
|
||||
await this._closePersistWriterInternal();
|
||||
},
|
||||
{ ignoreError: true }
|
||||
{ ignoreError: true },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1229,7 +1229,7 @@ export class SessionManager {
|
||||
firstKeptEntryId: string,
|
||||
tokensBefore: number,
|
||||
details?: T,
|
||||
fromExtension?: boolean
|
||||
fromExtension?: boolean,
|
||||
): string {
|
||||
const entry: CompactionEntry<T> = {
|
||||
type: "compaction",
|
||||
@@ -1272,7 +1272,7 @@ export class SessionManager {
|
||||
customType: string,
|
||||
content: string | (TextContent | ImageContent)[],
|
||||
display: boolean,
|
||||
details?: T
|
||||
details?: T,
|
||||
): string {
|
||||
const entry: CustomMessageEntry<T> = {
|
||||
type: "custom_message",
|
||||
@@ -1632,7 +1632,7 @@ export class SessionManager {
|
||||
static async open(
|
||||
path: string,
|
||||
sessionDir?: string,
|
||||
storage: SessionStorage = new FileSessionStorage()
|
||||
storage: SessionStorage = new FileSessionStorage(),
|
||||
): Promise<SessionManager> {
|
||||
// Extract cwd from session header if possible, otherwise use process.cwd()
|
||||
const entries = loadEntriesFromFile(path, storage);
|
||||
@@ -1653,7 +1653,7 @@ export class SessionManager {
|
||||
static async continueRecent(
|
||||
cwd: string,
|
||||
sessionDir?: string,
|
||||
storage: SessionStorage = new FileSessionStorage()
|
||||
storage: SessionStorage = new FileSessionStorage(),
|
||||
): Promise<SessionManager> {
|
||||
const dir = sessionDir ?? getDefaultSessionDir(cwd, storage);
|
||||
const mostRecent = findMostRecentSession(dir, storage);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
import * as fs from "node:fs";
|
||||
import * as path from "node:path";
|
||||
import type { TextContent } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
||||
import type { TextContent } from "@oh-my-pi/pi-ai";
|
||||
import type { Component } from "@oh-my-pi/pi-tui";
|
||||
import { Text } from "@oh-my-pi/pi-tui";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { homedir } from "node:os";
|
||||
import path from "node:path";
|
||||
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
||||
import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
|
||||
import type { Component } from "@oh-my-pi/pi-tui";
|
||||
import { Text } from "@oh-my-pi/pi-tui";
|
||||
import { Type } from "@sinclair/typebox";
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* - Session artifacts for debugging
|
||||
*/
|
||||
|
||||
import type { Usage } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Usage } from "@oh-my-pi/pi-ai";
|
||||
import type { Theme } from "../../../modes/interactive/theme/theme";
|
||||
import taskDescriptionTemplate from "../../../prompts/tools/task.md" with { type: "text" };
|
||||
import { formatDuration } from "../render-utils";
|
||||
|
||||
@@ -59,12 +59,12 @@ export const taskSchema = Type.Object({
|
||||
model: Type.Optional(
|
||||
Type.String({
|
||||
description: "Model override for all tasks (fuzzy matching, e.g. 'sonnet', 'opus')",
|
||||
})
|
||||
}),
|
||||
),
|
||||
output: Type.Optional(
|
||||
Type.Any({
|
||||
description: "JTD schema for structured subagent output (used by the complete tool)",
|
||||
})
|
||||
}),
|
||||
),
|
||||
tasks: Type.Array(taskItemSchema, {
|
||||
description: "Tasks to run in parallel",
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
* 5. Parent can send { type: "abort" } to request cancellation
|
||||
*/
|
||||
|
||||
import type { Api, Model } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentEvent, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
||||
import type { Api, Model } from "@oh-my-pi/pi-ai";
|
||||
import type { AgentSessionEvent } from "../../agent-session";
|
||||
import { parseModelPattern, parseModelString } from "../../model-resolver";
|
||||
import { createAgentSession, discoverAuthStorage, discoverModels } from "../../sdk";
|
||||
@@ -88,7 +88,7 @@ let pendingAbort = false;
|
||||
*/
|
||||
function resolveModelOverride(
|
||||
override: string | undefined,
|
||||
modelRegistry: { getAvailable: () => Model<Api>[]; find: (provider: string, id: string) => Model<Api> | undefined }
|
||||
modelRegistry: { getAvailable: () => Model<Api>[]; find: (provider: string, id: string) => Model<Api> | undefined },
|
||||
): { model?: Model<Api>; thinkingLevel?: ThinkingLevel } {
|
||||
if (!override) return {};
|
||||
|
||||
@@ -190,7 +190,7 @@ async function runTask(runState: RunState, payload: SubagentWorkerStartPayload):
|
||||
() => {
|
||||
void session.abort();
|
||||
},
|
||||
{ once: true, signal: sessionAbortController.signal }
|
||||
{ once: true, signal: sessionAbortController.signal },
|
||||
);
|
||||
|
||||
// Initialize extensions (equivalent to CLI's extension initialization)
|
||||
|
||||
Reference in New Issue
Block a user