213 lines
5.8 KiB
TypeScript
213 lines
5.8 KiB
TypeScript
/**
|
|
* pi SDK adapter boundary
|
|
* Zones: pi agent sdk boundary, shared adapters
|
|
* Owns direct pi SDK imports and exposes narrow bridge-facing helpers/types for the extension composition layer
|
|
*/
|
|
|
|
import type { AssistantMessageEvent } from "@earendil-works/pi-ai";
|
|
import {
|
|
type AgentEndEvent,
|
|
type AgentSettledEvent,
|
|
type AgentStartEvent,
|
|
type BeforeAgentStartEvent,
|
|
type ExtensionAPI,
|
|
type ExtensionCommandContext,
|
|
type ExtensionContext,
|
|
type InputEvent,
|
|
type SessionBeforeCompactEvent,
|
|
type SessionCompactEvent,
|
|
type SessionShutdownEvent,
|
|
type SessionStartEvent,
|
|
type SlashCommandInfo,
|
|
SettingsManager,
|
|
} from "@earendil-works/pi-coding-agent";
|
|
|
|
export type {
|
|
AgentEndEvent,
|
|
AgentSettledEvent,
|
|
AgentStartEvent,
|
|
AssistantMessageEvent,
|
|
BeforeAgentStartEvent,
|
|
ExtensionAPI,
|
|
ExtensionCommandContext,
|
|
ExtensionContext,
|
|
InputEvent,
|
|
SessionBeforeCompactEvent,
|
|
SessionCompactEvent,
|
|
SessionShutdownEvent,
|
|
SessionStartEvent,
|
|
SlashCommandInfo,
|
|
};
|
|
|
|
export interface ToolExecutionStartEvent {
|
|
type: "tool_execution_start";
|
|
toolCallId: string;
|
|
toolName: string;
|
|
args: unknown;
|
|
}
|
|
|
|
export interface ToolExecutionUpdateEvent {
|
|
type: "tool_execution_update";
|
|
toolCallId: string;
|
|
toolName: string;
|
|
args: unknown;
|
|
partialResult: unknown;
|
|
}
|
|
|
|
export interface ToolExecutionEndEvent {
|
|
type: "tool_execution_end";
|
|
toolCallId: string;
|
|
toolName: string;
|
|
result: unknown;
|
|
isError: boolean;
|
|
}
|
|
|
|
export interface PiSettingsManager {
|
|
reload: () => Promise<void>;
|
|
flush: () => Promise<void>;
|
|
getEnabledModels: () => string[] | undefined;
|
|
setEnabledModels: (patterns: string[] | undefined) => void;
|
|
}
|
|
|
|
export type PiSlashCommandInfo = SlashCommandInfo;
|
|
export type PiRunMode = "tui" | "rpc" | "json" | "print";
|
|
|
|
function isPiRunMode(value: unknown): value is PiRunMode {
|
|
return (
|
|
value === "tui" || value === "rpc" || value === "json" || value === "print"
|
|
);
|
|
}
|
|
|
|
export function getExtensionContextMode(ctx: unknown): PiRunMode | undefined {
|
|
const mode =
|
|
typeof ctx === "object" && ctx !== null
|
|
? (ctx as { mode?: unknown }).mode
|
|
: undefined;
|
|
return isPiRunMode(mode) ? mode : undefined;
|
|
}
|
|
|
|
export function isExtensionContextPassiveRunMode(ctx: unknown): boolean {
|
|
const mode = getExtensionContextMode(ctx);
|
|
return mode === "print" || mode === "json";
|
|
}
|
|
|
|
export function canStartPollingInExtensionContext(ctx: unknown): boolean {
|
|
return !isExtensionContextPassiveRunMode(ctx);
|
|
}
|
|
|
|
export interface PiTopStatusSegmentPorts {
|
|
setStatusSegment?: (
|
|
key: string,
|
|
text: string | undefined,
|
|
options: { placement: "after-cost" },
|
|
) => void;
|
|
}
|
|
|
|
export function setExtensionContextTopStatusSegment(
|
|
ctx: ExtensionContext,
|
|
key: string,
|
|
text: string,
|
|
): void {
|
|
const ui = ctx.ui as ExtensionContext["ui"] & PiTopStatusSegmentPorts;
|
|
ui.setStatusSegment?.(key, text, { placement: "after-cost" });
|
|
}
|
|
|
|
export function formatPollingStartBlockedByRunMode(ctx: unknown): string {
|
|
const mode = getExtensionContextMode(ctx);
|
|
return mode
|
|
? `Telegram polling is unavailable in Pi ${mode} mode. Use /telegram-connect from a long-lived Pi session.`
|
|
: "Telegram polling is unavailable in this Pi run mode.";
|
|
}
|
|
|
|
export function getSessionCompactionReason(
|
|
event: unknown,
|
|
): "manual" | "threshold" | "overflow" | "unknown" {
|
|
const reason =
|
|
event && typeof event === "object" && "reason" in event
|
|
? (event as { reason?: unknown }).reason
|
|
: undefined;
|
|
return reason === "manual" || reason === "threshold" || reason === "overflow"
|
|
? reason
|
|
: "unknown";
|
|
}
|
|
|
|
export type PiSendUserMessageOptions = NonNullable<
|
|
Parameters<ExtensionAPI["sendUserMessage"]>[1]
|
|
>;
|
|
|
|
export interface PiExtensionApiRuntimePorts {
|
|
sendUserMessage: ExtensionAPI["sendUserMessage"];
|
|
exec: ExtensionAPI["exec"];
|
|
getCommands: ExtensionAPI["getCommands"];
|
|
getThinkingLevel: ExtensionAPI["getThinkingLevel"];
|
|
setThinkingLevel: ExtensionAPI["setThinkingLevel"];
|
|
setModel: ExtensionAPI["setModel"];
|
|
}
|
|
|
|
export function createExtensionApiRuntimePorts(
|
|
api: Pick<
|
|
ExtensionAPI,
|
|
| "sendUserMessage"
|
|
| "exec"
|
|
| "getCommands"
|
|
| "getThinkingLevel"
|
|
| "setThinkingLevel"
|
|
| "setModel"
|
|
>,
|
|
): PiExtensionApiRuntimePorts {
|
|
return {
|
|
sendUserMessage: (content, options) =>
|
|
api.sendUserMessage(content, options),
|
|
exec: (command, args, options) => api.exec(command, args, options),
|
|
getCommands: () => api.getCommands(),
|
|
getThinkingLevel: () => api.getThinkingLevel(),
|
|
setThinkingLevel: (level) => api.setThinkingLevel(level),
|
|
setModel: (model) => api.setModel(model),
|
|
};
|
|
}
|
|
|
|
export function createSettingsManager(cwd: string): PiSettingsManager {
|
|
return SettingsManager.create(cwd);
|
|
}
|
|
|
|
export function createScopedModelPatternPersister(deps: {
|
|
createSettingsManager: (cwd: string) => PiSettingsManager;
|
|
clearCachedModelMenuInputs: () => void;
|
|
}): (patterns: string[], ctx: ExtensionContext) => Promise<void> {
|
|
return async (patterns, ctx) => {
|
|
const settingsManager = deps.createSettingsManager(ctx.cwd);
|
|
settingsManager.setEnabledModels(
|
|
patterns.length > 0 ? patterns : undefined,
|
|
);
|
|
await settingsManager.flush();
|
|
deps.clearCachedModelMenuInputs();
|
|
};
|
|
}
|
|
|
|
export function getExtensionContextModel(
|
|
ctx: ExtensionContext,
|
|
): ExtensionContext["model"] {
|
|
return ctx.model;
|
|
}
|
|
|
|
export function getExtensionContextCwd(ctx: ExtensionContext): string {
|
|
return ctx.cwd;
|
|
}
|
|
|
|
export function isExtensionContextIdle(ctx: ExtensionContext): boolean {
|
|
return ctx.isIdle();
|
|
}
|
|
|
|
export function hasExtensionContextPendingMessages(
|
|
ctx: ExtensionContext,
|
|
): boolean {
|
|
return ctx.hasPendingMessages();
|
|
}
|
|
|
|
export function compactExtensionContext(
|
|
ctx: ExtensionContext,
|
|
callbacks: Parameters<ExtensionContext["compact"]>[0],
|
|
): ReturnType<ExtensionContext["compact"]> {
|
|
return ctx.compact(callbacks);
|
|
}
|