@mariozechner/pi-coding-agent 0.27.7 → 0.27.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/core/sdk.d.ts +4 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +12 -8
- package/dist/core/sdk.js.map +1 -1
- package/docs/hooks-v2.md +314 -0
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.27.8] - 2025-12-24
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- **API key priority**: OAuth tokens now take priority over settings.json API keys. Previously, an API key in settings.json would trump OAuth, causing users logged in with a plan (unlimited tokens) to be billed via PAYG instead.
|
|
10
|
+
|
|
5
11
|
## [0.27.7] - 2025-12-24
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/dist/core/sdk.d.ts
CHANGED
|
@@ -155,7 +155,10 @@ export declare function discoverContextFiles(cwd?: string, agentDir?: string): A
|
|
|
155
155
|
export declare function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[];
|
|
156
156
|
/**
|
|
157
157
|
* Create the default API key resolver.
|
|
158
|
-
* Priority:
|
|
158
|
+
* Priority: OAuth > custom providers (models.json) > environment variables > settings.json apiKeys.
|
|
159
|
+
*
|
|
160
|
+
* OAuth takes priority so users logged in with a plan (e.g. unlimited tokens) aren't
|
|
161
|
+
* accidentally billed via a PAYG API key sitting in settings.json.
|
|
159
162
|
*/
|
|
160
163
|
export declare function defaultGetApiKey(settingsManager?: SettingsManager): (model: Model<any>) => Promise<string | undefined>;
|
|
161
164
|
export interface BuildSystemPromptOptions {
|
package/dist/core/sdk.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // With custom hooks\n * const session = await createAgentSession({\n * hooks: [\n * ...await discoverHooks(),\n * { factory: myHookFactory },\n * ],\n * });\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport { type Model, setOAuthStorage } from \"@mariozechner/pi-ai\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { discoverAndLoadCustomTools, type LoadedCustomTool } from \"./custom-tools/index.js\";\nimport type { CustomAgentTool } from \"./custom-tools/types.js\";\nimport { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from \"./hooks/index.js\";\nimport type { HookFactory } from \"./hooks/types.js\";\nimport { messageTransformer } from \"./messages.js\";\nimport {\n\tfindModel as findModelInternal,\n\tgetApiKeyForModel,\n\tgetAvailableModels,\n\tloadAndMergeModels,\n} from \"./model-config.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from \"./slash-commands.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport { time } from \"./timings.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** API key resolver. Default: defaultGetApiKey() */\n\tgetApiKey?: (model: Model<any>) => Promise<string | undefined>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools (replaces discovery). */\n\tcustomTools?: Array<{ path?: string; tool: CustomAgentTool }>;\n\t/** Additional custom tool paths to load (merged with discovery). */\n\tadditionalCustomToolPaths?: string[];\n\n\t/** Hooks (replaces discovery). */\n\thooks?: Array<{ path?: string; factory: HookFactory }>;\n\t/** Additional hook paths to load (merged with discovery). */\n\tadditionalHookPaths?: string[];\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Slash commands. Default: discovered from cwd/.pi/commands/ + agentDir/commands/ */\n\tslashCommands?: FileSlashCommand[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Custom tools result (for UI context setup in interactive mode) */\n\tcustomToolsResult: {\n\t\ttools: LoadedCustomTool[];\n\t\tsetUIContext: (uiContext: any, hasUI: boolean) => void;\n\t};\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type { CustomAgentTool } from \"./custom-tools/types.js\";\nexport type { HookAPI, HookFactory } from \"./hooks/types.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { FileSlashCommand } from \"./slash-commands.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Configure OAuth storage to use the specified agent directory.\n * Must be called before using OAuth-based authentication.\n */\nexport function configureOAuthStorage(agentDir: string = getDefaultAgentDir()): void {\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\n\tsetOAuthStorage({\n\t\tload: () => {\n\t\t\tif (!existsSync(oauthPath)) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\t} catch {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t},\n\t\tsave: (storage) => {\n\t\t\tconst dir = dirname(oauthPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t\t}\n\t\t\twriteFileSync(oauthPath, JSON.stringify(storage, null, 2), \"utf-8\");\n\t\t\tchmodSync(oauthPath, 0o600);\n\t\t},\n\t});\n}\n\n// Discovery Functions\n\n/**\n * Get all models (built-in + custom from models.json).\n */\nexport function discoverModels(agentDir: string = getDefaultAgentDir()): Model<any>[] {\n\tconst { models, error } = loadAndMergeModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Get models that have valid API keys available.\n */\nexport async function discoverAvailableModels(agentDir: string = getDefaultAgentDir()): Promise<Model<any>[]> {\n\tconst { models, error } = await getAvailableModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Find a model by provider and ID.\n * @returns The model, or null if not found\n */\nexport function findModel(\n\tprovider: string,\n\tmodelId: string,\n\tagentDir: string = getDefaultAgentDir(),\n): Model<any> | null {\n\tconst { model, error } = findModelInternal(provider, modelId, agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn model;\n}\n\n/**\n * Discover hooks from cwd and agentDir.\n */\nexport async function discoverHooks(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; factory: HookFactory }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t}\n\n\treturn hooks.map((h) => ({\n\t\tpath: h.path,\n\t\tfactory: createFactoryFromLoadedHook(h),\n\t}));\n}\n\n/**\n * Discover custom tools from cwd and agentDir.\n */\nexport async function discoverCustomTools(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; tool: CustomAgentTool }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t}\n\n\treturn tools.map((t) => ({\n\t\tpath: t.path,\n\t\ttool: t.tool,\n\t}));\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover slash commands from cwd and agentDir.\n */\nexport function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[] {\n\treturn loadSlashCommandsInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n/**\n * Create the default API key resolver.\n * Priority: settings.json apiKeys > custom providers (models.json) > OAuth > environment variables.\n */\nexport function defaultGetApiKey(\n\tsettingsManager?: SettingsManager,\n): (model: Model<any>) => Promise<string | undefined> {\n\treturn async (model: Model<any>) => {\n\t\t// Check settings.json apiKeys first\n\t\tif (settingsManager) {\n\t\t\tconst settingsKey = settingsManager.getApiKey(model.provider);\n\t\t\tif (settingsKey) {\n\t\t\t\treturn settingsKey;\n\t\t\t}\n\t\t}\n\t\t// Fall back to existing resolution (custom providers, OAuth, env vars)\n\t\treturn getApiKeyForModel(model);\n\t};\n}\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tqueueMode: manager.getQueueMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\thooks: manager.getHookPaths(),\n\t\thookTimeout: manager.getHookTimeout(),\n\t\tcustomTools: manager.getCustomToolPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Internal Helpers\n\n/**\n * Create a HookFactory from a LoadedHook.\n * This allows mixing discovered hooks with inline hooks.\n */\nfunction createFactoryFromLoadedHook(loaded: LoadedHook): HookFactory {\n\treturn (api) => {\n\t\tfor (const [eventType, handlers] of loaded.handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tapi.on(eventType as any, handler as any);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Convert hook definitions to LoadedHooks for the HookRunner.\n */\nfunction createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; factory: HookFactory }>): LoadedHook[] {\n\treturn definitions.map((def) => {\n\t\tconst handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();\n\t\tlet sendHandler: (text: string, attachments?: any[]) => void = () => {};\n\n\t\tconst api = {\n\t\t\ton: (event: string, handler: (...args: unknown[]) => Promise<unknown>) => {\n\t\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\t\tlist.push(handler);\n\t\t\t\thandlers.set(event, list);\n\t\t\t},\n\t\t\tsend: (text: string, attachments?: any[]) => {\n\t\t\t\tsendHandler(text, attachments);\n\t\t\t},\n\t\t};\n\n\t\tdef.factory(api as any);\n\n\t\treturn {\n\t\t\tpath: def.path ?? \"<inline>\",\n\t\t\tresolvedPath: def.path ?? \"<inline>\",\n\t\t\thandlers,\n\t\t\tsetSendHandler: (handler: (text: string, attachments?: any[]) => void) => {\n\t\t\t\tsendHandler = handler;\n\t\t\t},\n\t\t};\n\t});\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * const { session } = await createAgentSession({\n * model: findModel('anthropic', 'claude-sonnet-4-20250514'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\n\t// Configure OAuth storage for this agentDir\n\tconfigureOAuthStorage(agentDir);\n\ttime(\"configureOAuthStorage\");\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\ttime(\"settingsManager\");\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, agentDir);\n\ttime(\"sessionManager\");\n\n\t// Helper to check API key availability (settings first, then OAuth/env vars)\n\tconst hasApiKey = async (m: Model<any>): Promise<boolean> => {\n\t\tconst settingsKey = settingsManager.getApiKey(m.provider);\n\t\tif (settingsKey) return true;\n\t\treturn !!(await getApiKeyForModel(m));\n\t};\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\ttime(\"loadSession\");\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = findModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await hasApiKey(restoredModel))) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = findModel(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel && (await hasApiKey(settingsModel))) {\n\t\t\t\tmodel = settingsModel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available model with a valid API key\n\tif (!model) {\n\t\tconst allModels = discoverModels(agentDir);\n\t\tfor (const m of allModels) {\n\t\t\tif (await hasApiKey(m)) {\n\t\t\t\tmodel = m;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ttime(\"discoverAvailableModels\");\n\t\tif (model) {\n\t\t\tif (modelFallbackMessage) {\n\t\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t\t}\n\t\t} else {\n\t\t\t// No models available - set message so user knows to /login or configure keys\n\t\t\tmodelFallbackMessage = \"No models available. Use /login or set an API key environment variable.\";\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst getApiKey = options.getApiKey ?? defaultGetApiKey(settingsManager);\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\ttime(\"discoverSkills\");\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\ttime(\"discoverContextFiles\");\n\n\tconst builtInTools = options.tools ?? createCodingTools(cwd);\n\ttime(\"createCodingTools\");\n\n\tlet customToolsResult: { tools: LoadedCustomTool[]; setUIContext: (ctx: any, hasUI: boolean) => void };\n\tif (options.customTools !== undefined) {\n\t\t// Use provided custom tools\n\t\tconst loadedTools: LoadedCustomTool[] = options.customTools.map((ct) => ({\n\t\t\tpath: ct.path ?? \"<inline>\",\n\t\t\tresolvedPath: ct.path ?? \"<inline>\",\n\t\t\ttool: ct.tool,\n\t\t}));\n\t\tcustomToolsResult = {\n\t\t\ttools: loadedTools,\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover custom tools, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];\n\t\tconst result = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);\n\t\ttime(\"discoverAndLoadCustomTools\");\n\t\tfor (const { path, error } of result.errors) {\n\t\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t\t}\n\t\tcustomToolsResult = result;\n\t}\n\n\tlet hookRunner: HookRunner | null = null;\n\tif (options.hooks !== undefined) {\n\t\tif (options.hooks.length > 0) {\n\t\t\tconst loadedHooks = createLoadedHooksFromDefinitions(options.hooks);\n\t\t\thookRunner = new HookRunner(loadedHooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t} else {\n\t\t// Discover hooks, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];\n\t\tconst { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);\n\t\ttime(\"discoverAndLoadHooks\");\n\t\tfor (const { path, error } of errors) {\n\t\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t\t}\n\t\tif (hooks.length > 0) {\n\t\t\thookRunner = new HookRunner(hooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t}\n\n\tlet allToolsArray: Tool[] = [...builtInTools, ...customToolsResult.tools.map((lt) => lt.tool as unknown as Tool)];\n\ttime(\"combineTools\");\n\tif (hookRunner) {\n\t\tallToolsArray = wrapToolsWithHooks(allToolsArray, hookRunner) as Tool[];\n\t}\n\n\tlet systemPrompt: string;\n\tconst defaultPrompt = buildSystemPromptInternal({\n\t\tcwd,\n\t\tagentDir,\n\t\tskills,\n\t\tcontextFiles,\n\t});\n\ttime(\"buildSystemPrompt\");\n\n\tif (options.systemPrompt === undefined) {\n\t\tsystemPrompt = defaultPrompt;\n\t} else if (typeof options.systemPrompt === \"string\") {\n\t\tsystemPrompt = options.systemPrompt;\n\t} else {\n\t\tsystemPrompt = options.systemPrompt(defaultPrompt);\n\t}\n\n\tconst slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);\n\ttime(\"discoverSlashCommands\");\n\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: allToolsArray,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\t\t\t\tconst key = await getApiKey(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\ttime(\"createAgent\");\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tfileCommands: slashCommands,\n\t\thookRunner,\n\t\tcustomTools: customToolsResult.tools,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t\tresolveApiKey: getApiKey,\n\t});\n\ttime(\"createAgentSession\");\n\n\treturn {\n\t\tsession,\n\t\tcustomToolsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // With custom hooks\n * const session = await createAgentSession({\n * hooks: [\n * ...await discoverHooks(),\n * { factory: myHookFactory },\n * ],\n * });\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport { type Model, setOAuthStorage } from \"@mariozechner/pi-ai\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { discoverAndLoadCustomTools, type LoadedCustomTool } from \"./custom-tools/index.js\";\nimport type { CustomAgentTool } from \"./custom-tools/types.js\";\nimport { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from \"./hooks/index.js\";\nimport type { HookFactory } from \"./hooks/types.js\";\nimport { messageTransformer } from \"./messages.js\";\nimport {\n\tfindModel as findModelInternal,\n\tgetApiKeyForModel,\n\tgetAvailableModels,\n\tloadAndMergeModels,\n} from \"./model-config.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from \"./slash-commands.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport { time } from \"./timings.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** API key resolver. Default: defaultGetApiKey() */\n\tgetApiKey?: (model: Model<any>) => Promise<string | undefined>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools (replaces discovery). */\n\tcustomTools?: Array<{ path?: string; tool: CustomAgentTool }>;\n\t/** Additional custom tool paths to load (merged with discovery). */\n\tadditionalCustomToolPaths?: string[];\n\n\t/** Hooks (replaces discovery). */\n\thooks?: Array<{ path?: string; factory: HookFactory }>;\n\t/** Additional hook paths to load (merged with discovery). */\n\tadditionalHookPaths?: string[];\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Slash commands. Default: discovered from cwd/.pi/commands/ + agentDir/commands/ */\n\tslashCommands?: FileSlashCommand[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Custom tools result (for UI context setup in interactive mode) */\n\tcustomToolsResult: {\n\t\ttools: LoadedCustomTool[];\n\t\tsetUIContext: (uiContext: any, hasUI: boolean) => void;\n\t};\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type { CustomAgentTool } from \"./custom-tools/types.js\";\nexport type { HookAPI, HookFactory } from \"./hooks/types.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { FileSlashCommand } from \"./slash-commands.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Configure OAuth storage to use the specified agent directory.\n * Must be called before using OAuth-based authentication.\n */\nexport function configureOAuthStorage(agentDir: string = getDefaultAgentDir()): void {\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\n\tsetOAuthStorage({\n\t\tload: () => {\n\t\t\tif (!existsSync(oauthPath)) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\t} catch {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t},\n\t\tsave: (storage) => {\n\t\t\tconst dir = dirname(oauthPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t\t}\n\t\t\twriteFileSync(oauthPath, JSON.stringify(storage, null, 2), \"utf-8\");\n\t\t\tchmodSync(oauthPath, 0o600);\n\t\t},\n\t});\n}\n\n// Discovery Functions\n\n/**\n * Get all models (built-in + custom from models.json).\n */\nexport function discoverModels(agentDir: string = getDefaultAgentDir()): Model<any>[] {\n\tconst { models, error } = loadAndMergeModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Get models that have valid API keys available.\n */\nexport async function discoverAvailableModels(agentDir: string = getDefaultAgentDir()): Promise<Model<any>[]> {\n\tconst { models, error } = await getAvailableModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Find a model by provider and ID.\n * @returns The model, or null if not found\n */\nexport function findModel(\n\tprovider: string,\n\tmodelId: string,\n\tagentDir: string = getDefaultAgentDir(),\n): Model<any> | null {\n\tconst { model, error } = findModelInternal(provider, modelId, agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn model;\n}\n\n/**\n * Discover hooks from cwd and agentDir.\n */\nexport async function discoverHooks(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; factory: HookFactory }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t}\n\n\treturn hooks.map((h) => ({\n\t\tpath: h.path,\n\t\tfactory: createFactoryFromLoadedHook(h),\n\t}));\n}\n\n/**\n * Discover custom tools from cwd and agentDir.\n */\nexport async function discoverCustomTools(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; tool: CustomAgentTool }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t}\n\n\treturn tools.map((t) => ({\n\t\tpath: t.path,\n\t\ttool: t.tool,\n\t}));\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover slash commands from cwd and agentDir.\n */\nexport function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[] {\n\treturn loadSlashCommandsInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n/**\n * Create the default API key resolver.\n * Priority: OAuth > custom providers (models.json) > environment variables > settings.json apiKeys.\n *\n * OAuth takes priority so users logged in with a plan (e.g. unlimited tokens) aren't\n * accidentally billed via a PAYG API key sitting in settings.json.\n */\nexport function defaultGetApiKey(\n\tsettingsManager?: SettingsManager,\n): (model: Model<any>) => Promise<string | undefined> {\n\treturn async (model: Model<any>) => {\n\t\t// Check OAuth, custom providers, env vars first\n\t\tconst resolvedKey = await getApiKeyForModel(model);\n\t\tif (resolvedKey) {\n\t\t\treturn resolvedKey;\n\t\t}\n\t\t// Fall back to settings.json apiKeys\n\t\tif (settingsManager) {\n\t\t\treturn settingsManager.getApiKey(model.provider);\n\t\t}\n\t\treturn undefined;\n\t};\n}\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tqueueMode: manager.getQueueMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\thooks: manager.getHookPaths(),\n\t\thookTimeout: manager.getHookTimeout(),\n\t\tcustomTools: manager.getCustomToolPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Internal Helpers\n\n/**\n * Create a HookFactory from a LoadedHook.\n * This allows mixing discovered hooks with inline hooks.\n */\nfunction createFactoryFromLoadedHook(loaded: LoadedHook): HookFactory {\n\treturn (api) => {\n\t\tfor (const [eventType, handlers] of loaded.handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tapi.on(eventType as any, handler as any);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Convert hook definitions to LoadedHooks for the HookRunner.\n */\nfunction createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; factory: HookFactory }>): LoadedHook[] {\n\treturn definitions.map((def) => {\n\t\tconst handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();\n\t\tlet sendHandler: (text: string, attachments?: any[]) => void = () => {};\n\n\t\tconst api = {\n\t\t\ton: (event: string, handler: (...args: unknown[]) => Promise<unknown>) => {\n\t\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\t\tlist.push(handler);\n\t\t\t\thandlers.set(event, list);\n\t\t\t},\n\t\t\tsend: (text: string, attachments?: any[]) => {\n\t\t\t\tsendHandler(text, attachments);\n\t\t\t},\n\t\t};\n\n\t\tdef.factory(api as any);\n\n\t\treturn {\n\t\t\tpath: def.path ?? \"<inline>\",\n\t\t\tresolvedPath: def.path ?? \"<inline>\",\n\t\t\thandlers,\n\t\t\tsetSendHandler: (handler: (text: string, attachments?: any[]) => void) => {\n\t\t\t\tsendHandler = handler;\n\t\t\t},\n\t\t};\n\t});\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * const { session } = await createAgentSession({\n * model: findModel('anthropic', 'claude-sonnet-4-20250514'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\n\t// Configure OAuth storage for this agentDir\n\tconfigureOAuthStorage(agentDir);\n\ttime(\"configureOAuthStorage\");\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\ttime(\"settingsManager\");\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, agentDir);\n\ttime(\"sessionManager\");\n\n\t// Helper to check API key availability (settings first, then OAuth/env vars)\n\tconst hasApiKey = async (m: Model<any>): Promise<boolean> => {\n\t\tconst settingsKey = settingsManager.getApiKey(m.provider);\n\t\tif (settingsKey) return true;\n\t\treturn !!(await getApiKeyForModel(m));\n\t};\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\ttime(\"loadSession\");\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = findModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await hasApiKey(restoredModel))) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = findModel(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel && (await hasApiKey(settingsModel))) {\n\t\t\t\tmodel = settingsModel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available model with a valid API key\n\tif (!model) {\n\t\tconst allModels = discoverModels(agentDir);\n\t\tfor (const m of allModels) {\n\t\t\tif (await hasApiKey(m)) {\n\t\t\t\tmodel = m;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ttime(\"discoverAvailableModels\");\n\t\tif (model) {\n\t\t\tif (modelFallbackMessage) {\n\t\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t\t}\n\t\t} else {\n\t\t\t// No models available - set message so user knows to /login or configure keys\n\t\t\tmodelFallbackMessage = \"No models available. Use /login or set an API key environment variable.\";\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst getApiKey = options.getApiKey ?? defaultGetApiKey(settingsManager);\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\ttime(\"discoverSkills\");\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\ttime(\"discoverContextFiles\");\n\n\tconst builtInTools = options.tools ?? createCodingTools(cwd);\n\ttime(\"createCodingTools\");\n\n\tlet customToolsResult: { tools: LoadedCustomTool[]; setUIContext: (ctx: any, hasUI: boolean) => void };\n\tif (options.customTools !== undefined) {\n\t\t// Use provided custom tools\n\t\tconst loadedTools: LoadedCustomTool[] = options.customTools.map((ct) => ({\n\t\t\tpath: ct.path ?? \"<inline>\",\n\t\t\tresolvedPath: ct.path ?? \"<inline>\",\n\t\t\ttool: ct.tool,\n\t\t}));\n\t\tcustomToolsResult = {\n\t\t\ttools: loadedTools,\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover custom tools, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];\n\t\tconst result = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);\n\t\ttime(\"discoverAndLoadCustomTools\");\n\t\tfor (const { path, error } of result.errors) {\n\t\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t\t}\n\t\tcustomToolsResult = result;\n\t}\n\n\tlet hookRunner: HookRunner | null = null;\n\tif (options.hooks !== undefined) {\n\t\tif (options.hooks.length > 0) {\n\t\t\tconst loadedHooks = createLoadedHooksFromDefinitions(options.hooks);\n\t\t\thookRunner = new HookRunner(loadedHooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t} else {\n\t\t// Discover hooks, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];\n\t\tconst { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);\n\t\ttime(\"discoverAndLoadHooks\");\n\t\tfor (const { path, error } of errors) {\n\t\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t\t}\n\t\tif (hooks.length > 0) {\n\t\t\thookRunner = new HookRunner(hooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t}\n\n\tlet allToolsArray: Tool[] = [...builtInTools, ...customToolsResult.tools.map((lt) => lt.tool as unknown as Tool)];\n\ttime(\"combineTools\");\n\tif (hookRunner) {\n\t\tallToolsArray = wrapToolsWithHooks(allToolsArray, hookRunner) as Tool[];\n\t}\n\n\tlet systemPrompt: string;\n\tconst defaultPrompt = buildSystemPromptInternal({\n\t\tcwd,\n\t\tagentDir,\n\t\tskills,\n\t\tcontextFiles,\n\t});\n\ttime(\"buildSystemPrompt\");\n\n\tif (options.systemPrompt === undefined) {\n\t\tsystemPrompt = defaultPrompt;\n\t} else if (typeof options.systemPrompt === \"string\") {\n\t\tsystemPrompt = options.systemPrompt;\n\t} else {\n\t\tsystemPrompt = options.systemPrompt(defaultPrompt);\n\t}\n\n\tconst slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);\n\ttime(\"discoverSlashCommands\");\n\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: allToolsArray,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\t\t\t\tconst key = await getApiKey(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\ttime(\"createAgent\");\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tfileCommands: slashCommands,\n\t\thookRunner,\n\t\tcustomTools: customToolsResult.tools,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t\tresolveApiKey: getApiKey,\n\t});\n\ttime(\"createAgentSession\");\n\n\treturn {\n\t\tsession,\n\t\tcustomToolsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
package/dist/core/sdk.js
CHANGED
|
@@ -178,19 +178,23 @@ export function discoverSlashCommands(cwd, agentDir) {
|
|
|
178
178
|
// API Key Helpers
|
|
179
179
|
/**
|
|
180
180
|
* Create the default API key resolver.
|
|
181
|
-
* Priority:
|
|
181
|
+
* Priority: OAuth > custom providers (models.json) > environment variables > settings.json apiKeys.
|
|
182
|
+
*
|
|
183
|
+
* OAuth takes priority so users logged in with a plan (e.g. unlimited tokens) aren't
|
|
184
|
+
* accidentally billed via a PAYG API key sitting in settings.json.
|
|
182
185
|
*/
|
|
183
186
|
export function defaultGetApiKey(settingsManager) {
|
|
184
187
|
return async (model) => {
|
|
185
|
-
// Check
|
|
188
|
+
// Check OAuth, custom providers, env vars first
|
|
189
|
+
const resolvedKey = await getApiKeyForModel(model);
|
|
190
|
+
if (resolvedKey) {
|
|
191
|
+
return resolvedKey;
|
|
192
|
+
}
|
|
193
|
+
// Fall back to settings.json apiKeys
|
|
186
194
|
if (settingsManager) {
|
|
187
|
-
|
|
188
|
-
if (settingsKey) {
|
|
189
|
-
return settingsKey;
|
|
190
|
-
}
|
|
195
|
+
return settingsManager.getApiKey(model.provider);
|
|
191
196
|
}
|
|
192
|
-
|
|
193
|
-
return getApiKeyForModel(model);
|
|
197
|
+
return undefined;
|
|
194
198
|
};
|
|
195
199
|
}
|
|
196
200
|
/**
|
package/dist/core/sdk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // With custom hooks\n * const session = await createAgentSession({\n * hooks: [\n * ...await discoverHooks(),\n * { factory: myHookFactory },\n * ],\n * });\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport { type Model, setOAuthStorage } from \"@mariozechner/pi-ai\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { discoverAndLoadCustomTools, type LoadedCustomTool } from \"./custom-tools/index.js\";\nimport type { CustomAgentTool } from \"./custom-tools/types.js\";\nimport { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from \"./hooks/index.js\";\nimport type { HookFactory } from \"./hooks/types.js\";\nimport { messageTransformer } from \"./messages.js\";\nimport {\n\tfindModel as findModelInternal,\n\tgetApiKeyForModel,\n\tgetAvailableModels,\n\tloadAndMergeModels,\n} from \"./model-config.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from \"./slash-commands.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport { time } from \"./timings.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** API key resolver. Default: defaultGetApiKey() */\n\tgetApiKey?: (model: Model<any>) => Promise<string | undefined>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools (replaces discovery). */\n\tcustomTools?: Array<{ path?: string; tool: CustomAgentTool }>;\n\t/** Additional custom tool paths to load (merged with discovery). */\n\tadditionalCustomToolPaths?: string[];\n\n\t/** Hooks (replaces discovery). */\n\thooks?: Array<{ path?: string; factory: HookFactory }>;\n\t/** Additional hook paths to load (merged with discovery). */\n\tadditionalHookPaths?: string[];\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Slash commands. Default: discovered from cwd/.pi/commands/ + agentDir/commands/ */\n\tslashCommands?: FileSlashCommand[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Custom tools result (for UI context setup in interactive mode) */\n\tcustomToolsResult: {\n\t\ttools: LoadedCustomTool[];\n\t\tsetUIContext: (uiContext: any, hasUI: boolean) => void;\n\t};\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type { CustomAgentTool } from \"./custom-tools/types.js\";\nexport type { HookAPI, HookFactory } from \"./hooks/types.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { FileSlashCommand } from \"./slash-commands.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Configure OAuth storage to use the specified agent directory.\n * Must be called before using OAuth-based authentication.\n */\nexport function configureOAuthStorage(agentDir: string = getDefaultAgentDir()): void {\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\n\tsetOAuthStorage({\n\t\tload: () => {\n\t\t\tif (!existsSync(oauthPath)) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\t} catch {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t},\n\t\tsave: (storage) => {\n\t\t\tconst dir = dirname(oauthPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t\t}\n\t\t\twriteFileSync(oauthPath, JSON.stringify(storage, null, 2), \"utf-8\");\n\t\t\tchmodSync(oauthPath, 0o600);\n\t\t},\n\t});\n}\n\n// Discovery Functions\n\n/**\n * Get all models (built-in + custom from models.json).\n */\nexport function discoverModels(agentDir: string = getDefaultAgentDir()): Model<any>[] {\n\tconst { models, error } = loadAndMergeModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Get models that have valid API keys available.\n */\nexport async function discoverAvailableModels(agentDir: string = getDefaultAgentDir()): Promise<Model<any>[]> {\n\tconst { models, error } = await getAvailableModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Find a model by provider and ID.\n * @returns The model, or null if not found\n */\nexport function findModel(\n\tprovider: string,\n\tmodelId: string,\n\tagentDir: string = getDefaultAgentDir(),\n): Model<any> | null {\n\tconst { model, error } = findModelInternal(provider, modelId, agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn model;\n}\n\n/**\n * Discover hooks from cwd and agentDir.\n */\nexport async function discoverHooks(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; factory: HookFactory }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t}\n\n\treturn hooks.map((h) => ({\n\t\tpath: h.path,\n\t\tfactory: createFactoryFromLoadedHook(h),\n\t}));\n}\n\n/**\n * Discover custom tools from cwd and agentDir.\n */\nexport async function discoverCustomTools(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; tool: CustomAgentTool }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t}\n\n\treturn tools.map((t) => ({\n\t\tpath: t.path,\n\t\ttool: t.tool,\n\t}));\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover slash commands from cwd and agentDir.\n */\nexport function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[] {\n\treturn loadSlashCommandsInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n/**\n * Create the default API key resolver.\n * Priority: settings.json apiKeys > custom providers (models.json) > OAuth > environment variables.\n */\nexport function defaultGetApiKey(\n\tsettingsManager?: SettingsManager,\n): (model: Model<any>) => Promise<string | undefined> {\n\treturn async (model: Model<any>) => {\n\t\t// Check settings.json apiKeys first\n\t\tif (settingsManager) {\n\t\t\tconst settingsKey = settingsManager.getApiKey(model.provider);\n\t\t\tif (settingsKey) {\n\t\t\t\treturn settingsKey;\n\t\t\t}\n\t\t}\n\t\t// Fall back to existing resolution (custom providers, OAuth, env vars)\n\t\treturn getApiKeyForModel(model);\n\t};\n}\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tqueueMode: manager.getQueueMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\thooks: manager.getHookPaths(),\n\t\thookTimeout: manager.getHookTimeout(),\n\t\tcustomTools: manager.getCustomToolPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Internal Helpers\n\n/**\n * Create a HookFactory from a LoadedHook.\n * This allows mixing discovered hooks with inline hooks.\n */\nfunction createFactoryFromLoadedHook(loaded: LoadedHook): HookFactory {\n\treturn (api) => {\n\t\tfor (const [eventType, handlers] of loaded.handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tapi.on(eventType as any, handler as any);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Convert hook definitions to LoadedHooks for the HookRunner.\n */\nfunction createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; factory: HookFactory }>): LoadedHook[] {\n\treturn definitions.map((def) => {\n\t\tconst handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();\n\t\tlet sendHandler: (text: string, attachments?: any[]) => void = () => {};\n\n\t\tconst api = {\n\t\t\ton: (event: string, handler: (...args: unknown[]) => Promise<unknown>) => {\n\t\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\t\tlist.push(handler);\n\t\t\t\thandlers.set(event, list);\n\t\t\t},\n\t\t\tsend: (text: string, attachments?: any[]) => {\n\t\t\t\tsendHandler(text, attachments);\n\t\t\t},\n\t\t};\n\n\t\tdef.factory(api as any);\n\n\t\treturn {\n\t\t\tpath: def.path ?? \"<inline>\",\n\t\t\tresolvedPath: def.path ?? \"<inline>\",\n\t\t\thandlers,\n\t\t\tsetSendHandler: (handler: (text: string, attachments?: any[]) => void) => {\n\t\t\t\tsendHandler = handler;\n\t\t\t},\n\t\t};\n\t});\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * const { session } = await createAgentSession({\n * model: findModel('anthropic', 'claude-sonnet-4-20250514'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\n\t// Configure OAuth storage for this agentDir\n\tconfigureOAuthStorage(agentDir);\n\ttime(\"configureOAuthStorage\");\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\ttime(\"settingsManager\");\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, agentDir);\n\ttime(\"sessionManager\");\n\n\t// Helper to check API key availability (settings first, then OAuth/env vars)\n\tconst hasApiKey = async (m: Model<any>): Promise<boolean> => {\n\t\tconst settingsKey = settingsManager.getApiKey(m.provider);\n\t\tif (settingsKey) return true;\n\t\treturn !!(await getApiKeyForModel(m));\n\t};\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\ttime(\"loadSession\");\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = findModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await hasApiKey(restoredModel))) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = findModel(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel && (await hasApiKey(settingsModel))) {\n\t\t\t\tmodel = settingsModel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available model with a valid API key\n\tif (!model) {\n\t\tconst allModels = discoverModels(agentDir);\n\t\tfor (const m of allModels) {\n\t\t\tif (await hasApiKey(m)) {\n\t\t\t\tmodel = m;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ttime(\"discoverAvailableModels\");\n\t\tif (model) {\n\t\t\tif (modelFallbackMessage) {\n\t\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t\t}\n\t\t} else {\n\t\t\t// No models available - set message so user knows to /login or configure keys\n\t\t\tmodelFallbackMessage = \"No models available. Use /login or set an API key environment variable.\";\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst getApiKey = options.getApiKey ?? defaultGetApiKey(settingsManager);\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\ttime(\"discoverSkills\");\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\ttime(\"discoverContextFiles\");\n\n\tconst builtInTools = options.tools ?? createCodingTools(cwd);\n\ttime(\"createCodingTools\");\n\n\tlet customToolsResult: { tools: LoadedCustomTool[]; setUIContext: (ctx: any, hasUI: boolean) => void };\n\tif (options.customTools !== undefined) {\n\t\t// Use provided custom tools\n\t\tconst loadedTools: LoadedCustomTool[] = options.customTools.map((ct) => ({\n\t\t\tpath: ct.path ?? \"<inline>\",\n\t\t\tresolvedPath: ct.path ?? \"<inline>\",\n\t\t\ttool: ct.tool,\n\t\t}));\n\t\tcustomToolsResult = {\n\t\t\ttools: loadedTools,\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover custom tools, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];\n\t\tconst result = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);\n\t\ttime(\"discoverAndLoadCustomTools\");\n\t\tfor (const { path, error } of result.errors) {\n\t\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t\t}\n\t\tcustomToolsResult = result;\n\t}\n\n\tlet hookRunner: HookRunner | null = null;\n\tif (options.hooks !== undefined) {\n\t\tif (options.hooks.length > 0) {\n\t\t\tconst loadedHooks = createLoadedHooksFromDefinitions(options.hooks);\n\t\t\thookRunner = new HookRunner(loadedHooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t} else {\n\t\t// Discover hooks, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];\n\t\tconst { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);\n\t\ttime(\"discoverAndLoadHooks\");\n\t\tfor (const { path, error } of errors) {\n\t\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t\t}\n\t\tif (hooks.length > 0) {\n\t\t\thookRunner = new HookRunner(hooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t}\n\n\tlet allToolsArray: Tool[] = [...builtInTools, ...customToolsResult.tools.map((lt) => lt.tool as unknown as Tool)];\n\ttime(\"combineTools\");\n\tif (hookRunner) {\n\t\tallToolsArray = wrapToolsWithHooks(allToolsArray, hookRunner) as Tool[];\n\t}\n\n\tlet systemPrompt: string;\n\tconst defaultPrompt = buildSystemPromptInternal({\n\t\tcwd,\n\t\tagentDir,\n\t\tskills,\n\t\tcontextFiles,\n\t});\n\ttime(\"buildSystemPrompt\");\n\n\tif (options.systemPrompt === undefined) {\n\t\tsystemPrompt = defaultPrompt;\n\t} else if (typeof options.systemPrompt === \"string\") {\n\t\tsystemPrompt = options.systemPrompt;\n\t} else {\n\t\tsystemPrompt = options.systemPrompt(defaultPrompt);\n\t}\n\n\tconst slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);\n\ttime(\"discoverSlashCommands\");\n\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: allToolsArray,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\t\t\t\tconst key = await getApiKey(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\ttime(\"createAgent\");\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tfileCommands: slashCommands,\n\t\thookRunner,\n\t\tcustomTools: customToolsResult.tools,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t\tresolveApiKey: getApiKey,\n\t});\n\ttime(\"createAgentSession\");\n\n\treturn {\n\t\tsession,\n\t\tcustomToolsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // With custom hooks\n * const session = await createAgentSession({\n * hooks: [\n * ...await discoverHooks(),\n * { factory: myHookFactory },\n * ],\n * });\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport { type Model, setOAuthStorage } from \"@mariozechner/pi-ai\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { discoverAndLoadCustomTools, type LoadedCustomTool } from \"./custom-tools/index.js\";\nimport type { CustomAgentTool } from \"./custom-tools/types.js\";\nimport { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from \"./hooks/index.js\";\nimport type { HookFactory } from \"./hooks/types.js\";\nimport { messageTransformer } from \"./messages.js\";\nimport {\n\tfindModel as findModelInternal,\n\tgetApiKeyForModel,\n\tgetAvailableModels,\n\tloadAndMergeModels,\n} from \"./model-config.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from \"./slash-commands.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport { time } from \"./timings.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** API key resolver. Default: defaultGetApiKey() */\n\tgetApiKey?: (model: Model<any>) => Promise<string | undefined>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools (replaces discovery). */\n\tcustomTools?: Array<{ path?: string; tool: CustomAgentTool }>;\n\t/** Additional custom tool paths to load (merged with discovery). */\n\tadditionalCustomToolPaths?: string[];\n\n\t/** Hooks (replaces discovery). */\n\thooks?: Array<{ path?: string; factory: HookFactory }>;\n\t/** Additional hook paths to load (merged with discovery). */\n\tadditionalHookPaths?: string[];\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Slash commands. Default: discovered from cwd/.pi/commands/ + agentDir/commands/ */\n\tslashCommands?: FileSlashCommand[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Custom tools result (for UI context setup in interactive mode) */\n\tcustomToolsResult: {\n\t\ttools: LoadedCustomTool[];\n\t\tsetUIContext: (uiContext: any, hasUI: boolean) => void;\n\t};\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type { CustomAgentTool } from \"./custom-tools/types.js\";\nexport type { HookAPI, HookFactory } from \"./hooks/types.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { FileSlashCommand } from \"./slash-commands.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Configure OAuth storage to use the specified agent directory.\n * Must be called before using OAuth-based authentication.\n */\nexport function configureOAuthStorage(agentDir: string = getDefaultAgentDir()): void {\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\n\tsetOAuthStorage({\n\t\tload: () => {\n\t\t\tif (!existsSync(oauthPath)) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\t} catch {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t},\n\t\tsave: (storage) => {\n\t\t\tconst dir = dirname(oauthPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t\t}\n\t\t\twriteFileSync(oauthPath, JSON.stringify(storage, null, 2), \"utf-8\");\n\t\t\tchmodSync(oauthPath, 0o600);\n\t\t},\n\t});\n}\n\n// Discovery Functions\n\n/**\n * Get all models (built-in + custom from models.json).\n */\nexport function discoverModels(agentDir: string = getDefaultAgentDir()): Model<any>[] {\n\tconst { models, error } = loadAndMergeModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Get models that have valid API keys available.\n */\nexport async function discoverAvailableModels(agentDir: string = getDefaultAgentDir()): Promise<Model<any>[]> {\n\tconst { models, error } = await getAvailableModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Find a model by provider and ID.\n * @returns The model, or null if not found\n */\nexport function findModel(\n\tprovider: string,\n\tmodelId: string,\n\tagentDir: string = getDefaultAgentDir(),\n): Model<any> | null {\n\tconst { model, error } = findModelInternal(provider, modelId, agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn model;\n}\n\n/**\n * Discover hooks from cwd and agentDir.\n */\nexport async function discoverHooks(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; factory: HookFactory }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t}\n\n\treturn hooks.map((h) => ({\n\t\tpath: h.path,\n\t\tfactory: createFactoryFromLoadedHook(h),\n\t}));\n}\n\n/**\n * Discover custom tools from cwd and agentDir.\n */\nexport async function discoverCustomTools(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; tool: CustomAgentTool }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t}\n\n\treturn tools.map((t) => ({\n\t\tpath: t.path,\n\t\ttool: t.tool,\n\t}));\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover slash commands from cwd and agentDir.\n */\nexport function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[] {\n\treturn loadSlashCommandsInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n/**\n * Create the default API key resolver.\n * Priority: OAuth > custom providers (models.json) > environment variables > settings.json apiKeys.\n *\n * OAuth takes priority so users logged in with a plan (e.g. unlimited tokens) aren't\n * accidentally billed via a PAYG API key sitting in settings.json.\n */\nexport function defaultGetApiKey(\n\tsettingsManager?: SettingsManager,\n): (model: Model<any>) => Promise<string | undefined> {\n\treturn async (model: Model<any>) => {\n\t\t// Check OAuth, custom providers, env vars first\n\t\tconst resolvedKey = await getApiKeyForModel(model);\n\t\tif (resolvedKey) {\n\t\t\treturn resolvedKey;\n\t\t}\n\t\t// Fall back to settings.json apiKeys\n\t\tif (settingsManager) {\n\t\t\treturn settingsManager.getApiKey(model.provider);\n\t\t}\n\t\treturn undefined;\n\t};\n}\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tqueueMode: manager.getQueueMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\thooks: manager.getHookPaths(),\n\t\thookTimeout: manager.getHookTimeout(),\n\t\tcustomTools: manager.getCustomToolPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Internal Helpers\n\n/**\n * Create a HookFactory from a LoadedHook.\n * This allows mixing discovered hooks with inline hooks.\n */\nfunction createFactoryFromLoadedHook(loaded: LoadedHook): HookFactory {\n\treturn (api) => {\n\t\tfor (const [eventType, handlers] of loaded.handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tapi.on(eventType as any, handler as any);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Convert hook definitions to LoadedHooks for the HookRunner.\n */\nfunction createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; factory: HookFactory }>): LoadedHook[] {\n\treturn definitions.map((def) => {\n\t\tconst handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();\n\t\tlet sendHandler: (text: string, attachments?: any[]) => void = () => {};\n\n\t\tconst api = {\n\t\t\ton: (event: string, handler: (...args: unknown[]) => Promise<unknown>) => {\n\t\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\t\tlist.push(handler);\n\t\t\t\thandlers.set(event, list);\n\t\t\t},\n\t\t\tsend: (text: string, attachments?: any[]) => {\n\t\t\t\tsendHandler(text, attachments);\n\t\t\t},\n\t\t};\n\n\t\tdef.factory(api as any);\n\n\t\treturn {\n\t\t\tpath: def.path ?? \"<inline>\",\n\t\t\tresolvedPath: def.path ?? \"<inline>\",\n\t\t\thandlers,\n\t\t\tsetSendHandler: (handler: (text: string, attachments?: any[]) => void) => {\n\t\t\t\tsendHandler = handler;\n\t\t\t},\n\t\t};\n\t});\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * const { session } = await createAgentSession({\n * model: findModel('anthropic', 'claude-sonnet-4-20250514'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\n\t// Configure OAuth storage for this agentDir\n\tconfigureOAuthStorage(agentDir);\n\ttime(\"configureOAuthStorage\");\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\ttime(\"settingsManager\");\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, agentDir);\n\ttime(\"sessionManager\");\n\n\t// Helper to check API key availability (settings first, then OAuth/env vars)\n\tconst hasApiKey = async (m: Model<any>): Promise<boolean> => {\n\t\tconst settingsKey = settingsManager.getApiKey(m.provider);\n\t\tif (settingsKey) return true;\n\t\treturn !!(await getApiKeyForModel(m));\n\t};\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\ttime(\"loadSession\");\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = findModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await hasApiKey(restoredModel))) {\n\t\t\tmodel = restoredModel;\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = findModel(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel && (await hasApiKey(settingsModel))) {\n\t\t\t\tmodel = settingsModel;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available model with a valid API key\n\tif (!model) {\n\t\tconst allModels = discoverModels(agentDir);\n\t\tfor (const m of allModels) {\n\t\t\tif (await hasApiKey(m)) {\n\t\t\t\tmodel = m;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\ttime(\"discoverAvailableModels\");\n\t\tif (model) {\n\t\t\tif (modelFallbackMessage) {\n\t\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t\t}\n\t\t} else {\n\t\t\t// No models available - set message so user knows to /login or configure keys\n\t\t\tmodelFallbackMessage = \"No models available. Use /login or set an API key environment variable.\";\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst getApiKey = options.getApiKey ?? defaultGetApiKey(settingsManager);\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\ttime(\"discoverSkills\");\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\ttime(\"discoverContextFiles\");\n\n\tconst builtInTools = options.tools ?? createCodingTools(cwd);\n\ttime(\"createCodingTools\");\n\n\tlet customToolsResult: { tools: LoadedCustomTool[]; setUIContext: (ctx: any, hasUI: boolean) => void };\n\tif (options.customTools !== undefined) {\n\t\t// Use provided custom tools\n\t\tconst loadedTools: LoadedCustomTool[] = options.customTools.map((ct) => ({\n\t\t\tpath: ct.path ?? \"<inline>\",\n\t\t\tresolvedPath: ct.path ?? \"<inline>\",\n\t\t\ttool: ct.tool,\n\t\t}));\n\t\tcustomToolsResult = {\n\t\t\ttools: loadedTools,\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover custom tools, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];\n\t\tconst result = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);\n\t\ttime(\"discoverAndLoadCustomTools\");\n\t\tfor (const { path, error } of result.errors) {\n\t\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t\t}\n\t\tcustomToolsResult = result;\n\t}\n\n\tlet hookRunner: HookRunner | null = null;\n\tif (options.hooks !== undefined) {\n\t\tif (options.hooks.length > 0) {\n\t\t\tconst loadedHooks = createLoadedHooksFromDefinitions(options.hooks);\n\t\t\thookRunner = new HookRunner(loadedHooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t} else {\n\t\t// Discover hooks, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];\n\t\tconst { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);\n\t\ttime(\"discoverAndLoadHooks\");\n\t\tfor (const { path, error } of errors) {\n\t\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t\t}\n\t\tif (hooks.length > 0) {\n\t\t\thookRunner = new HookRunner(hooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t}\n\n\tlet allToolsArray: Tool[] = [...builtInTools, ...customToolsResult.tools.map((lt) => lt.tool as unknown as Tool)];\n\ttime(\"combineTools\");\n\tif (hookRunner) {\n\t\tallToolsArray = wrapToolsWithHooks(allToolsArray, hookRunner) as Tool[];\n\t}\n\n\tlet systemPrompt: string;\n\tconst defaultPrompt = buildSystemPromptInternal({\n\t\tcwd,\n\t\tagentDir,\n\t\tskills,\n\t\tcontextFiles,\n\t});\n\ttime(\"buildSystemPrompt\");\n\n\tif (options.systemPrompt === undefined) {\n\t\tsystemPrompt = defaultPrompt;\n\t} else if (typeof options.systemPrompt === \"string\") {\n\t\tsystemPrompt = options.systemPrompt;\n\t} else {\n\t\tsystemPrompt = options.systemPrompt(defaultPrompt);\n\t}\n\n\tconst slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);\n\ttime(\"discoverSlashCommands\");\n\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: allToolsArray,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\t\t\t\tconst key = await getApiKey(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\ttime(\"createAgent\");\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tfileCommands: slashCommands,\n\t\thookRunner,\n\t\tcustomTools: customToolsResult.tools,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t\tresolveApiKey: getApiKey,\n\t});\n\ttime(\"createAgentSession\");\n\n\treturn {\n\t\tsession,\n\t\tcustomToolsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
package/docs/hooks-v2.md
ADDED
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
# Hooks v2: Commands + Context Control
|
|
2
|
+
|
|
3
|
+
Extends hooks with slash commands and context manipulation primitives.
|
|
4
|
+
|
|
5
|
+
## Goals
|
|
6
|
+
|
|
7
|
+
1. Hooks can register slash commands (`/pop`, `/pr`, `/test`)
|
|
8
|
+
2. Hooks can save custom session entries
|
|
9
|
+
3. Hooks can transform context before it goes to LLM
|
|
10
|
+
4. All handlers get unified baseline access to state
|
|
11
|
+
|
|
12
|
+
Benchmark: `/pop` (session stacking) implementable entirely as a hook.
|
|
13
|
+
|
|
14
|
+
## API Extensions
|
|
15
|
+
|
|
16
|
+
### Commands
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
pi.command("pop", {
|
|
20
|
+
description: "Pop to previous turn",
|
|
21
|
+
handler: async (ctx) => {
|
|
22
|
+
// ctx has full access (see Unified Context below)
|
|
23
|
+
const selected = await ctx.ui.select("Pop to:", options);
|
|
24
|
+
// ...
|
|
25
|
+
return { status: "Done" }; // show status
|
|
26
|
+
return "prompt text"; // send to agent
|
|
27
|
+
return; // do nothing
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Custom Entries
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
// Save arbitrary entry to session
|
|
36
|
+
await ctx.saveEntry({
|
|
37
|
+
type: "stack_pop", // custom type, ignored by core
|
|
38
|
+
backToIndex: 5,
|
|
39
|
+
summary: "...",
|
|
40
|
+
timestamp: Date.now()
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Context Transform
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// Fires when building context for LLM
|
|
48
|
+
pi.on("context", (event, ctx) => {
|
|
49
|
+
// event.entries: all session entries (including custom types)
|
|
50
|
+
// event.messages: core-computed messages (after compaction)
|
|
51
|
+
|
|
52
|
+
// Return modified messages, or undefined to keep default
|
|
53
|
+
return { messages: transformed };
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Multiple `context` handlers chain: each receives previous handler's output.
|
|
58
|
+
|
|
59
|
+
### Rebuild Trigger
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// Force context rebuild (after saving entries)
|
|
63
|
+
await ctx.rebuildContext();
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Unified Context
|
|
67
|
+
|
|
68
|
+
All handlers receive:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
interface HookEventContext {
|
|
72
|
+
// Existing
|
|
73
|
+
exec(cmd: string, args: string[], opts?): Promise<ExecResult>;
|
|
74
|
+
ui: { select, confirm, input, notify };
|
|
75
|
+
hasUI: boolean;
|
|
76
|
+
cwd: string;
|
|
77
|
+
sessionFile: string | null;
|
|
78
|
+
|
|
79
|
+
// New: State (read-only)
|
|
80
|
+
model: Model<any> | null;
|
|
81
|
+
thinkingLevel: ThinkingLevel;
|
|
82
|
+
entries: readonly SessionEntry[];
|
|
83
|
+
messages: readonly AppMessage[];
|
|
84
|
+
|
|
85
|
+
// New: Utilities
|
|
86
|
+
findModel(provider: string, id: string): Model<any> | null;
|
|
87
|
+
availableModels(): Promise<Model<any>[]>;
|
|
88
|
+
resolveApiKey(model: Model<any>): Promise<string | undefined>;
|
|
89
|
+
|
|
90
|
+
// New: Mutation (commands only? or all?)
|
|
91
|
+
saveEntry(entry: { type: string; [k: string]: unknown }): Promise<void>;
|
|
92
|
+
rebuildContext(): Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Commands additionally get:
|
|
97
|
+
- `args: string[]`, `argsRaw: string`
|
|
98
|
+
- `setModel()`, `setThinkingLevel()` (state mutation)
|
|
99
|
+
|
|
100
|
+
## Benchmark: Stacking as Hook
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
export default function(pi: HookAPI) {
|
|
104
|
+
// Command: /pop
|
|
105
|
+
pi.command("pop", {
|
|
106
|
+
description: "Pop to previous turn, summarizing substack",
|
|
107
|
+
handler: async (ctx) => {
|
|
108
|
+
// 1. Build turn list from entries
|
|
109
|
+
const turns = ctx.entries
|
|
110
|
+
.map((e, i) => ({ e, i }))
|
|
111
|
+
.filter(({ e }) => e.type === "message" && e.message.role === "user")
|
|
112
|
+
.map(({ e, i }) => ({ index: i, text: e.message.content.slice(0, 50) }));
|
|
113
|
+
|
|
114
|
+
if (!turns.length) return { status: "No turns to pop" };
|
|
115
|
+
|
|
116
|
+
// 2. User selects
|
|
117
|
+
const selected = await ctx.ui.select("Pop to:", turns.map(t => t.text));
|
|
118
|
+
if (!selected) return;
|
|
119
|
+
const backTo = turns.find(t => t.text === selected)!.index;
|
|
120
|
+
|
|
121
|
+
// 3. Summarize entries from backTo to now
|
|
122
|
+
const toSummarize = ctx.entries.slice(backTo)
|
|
123
|
+
.filter(e => e.type === "message")
|
|
124
|
+
.map(e => e.message);
|
|
125
|
+
const summary = await generateSummary(toSummarize, ctx);
|
|
126
|
+
|
|
127
|
+
// 4. Save custom entry
|
|
128
|
+
await ctx.saveEntry({
|
|
129
|
+
type: "stack_pop",
|
|
130
|
+
backToIndex: backTo,
|
|
131
|
+
summary,
|
|
132
|
+
timestamp: Date.now()
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// 5. Rebuild
|
|
136
|
+
await ctx.rebuildContext();
|
|
137
|
+
return { status: "Popped stack" };
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Context transform: apply stack pops
|
|
142
|
+
pi.on("context", (event, ctx) => {
|
|
143
|
+
const pops = event.entries.filter(e => e.type === "stack_pop");
|
|
144
|
+
if (!pops.length) return; // use default
|
|
145
|
+
|
|
146
|
+
// Build exclusion set
|
|
147
|
+
const excluded = new Set<number>();
|
|
148
|
+
const summaryAt = new Map<number, string>();
|
|
149
|
+
|
|
150
|
+
for (const pop of pops) {
|
|
151
|
+
const popIdx = event.entries.indexOf(pop);
|
|
152
|
+
for (let i = pop.backToIndex; i <= popIdx; i++) excluded.add(i);
|
|
153
|
+
summaryAt.set(pop.backToIndex, pop.summary);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Build filtered messages
|
|
157
|
+
const messages: AppMessage[] = [];
|
|
158
|
+
for (let i = 0; i < event.entries.length; i++) {
|
|
159
|
+
if (excluded.has(i)) continue;
|
|
160
|
+
|
|
161
|
+
if (summaryAt.has(i)) {
|
|
162
|
+
messages.push({
|
|
163
|
+
role: "user",
|
|
164
|
+
content: `[Subtask completed]\n\n${summaryAt.get(i)}`,
|
|
165
|
+
timestamp: Date.now()
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const e = event.entries[i];
|
|
170
|
+
if (e.type === "message") messages.push(e.message);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return { messages };
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async function generateSummary(messages, ctx) {
|
|
178
|
+
const apiKey = await ctx.resolveApiKey(ctx.model);
|
|
179
|
+
// Call LLM for summary...
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Core Changes Required
|
|
184
|
+
|
|
185
|
+
### session-manager.ts
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// Allow saving arbitrary entries
|
|
189
|
+
saveEntry(entry: { type: string; [k: string]: unknown }): void {
|
|
190
|
+
if (!entry.type) throw new Error("Entry must have type");
|
|
191
|
+
this.inMemoryEntries.push(entry);
|
|
192
|
+
this._persist(entry);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// buildSessionContext ignores unknown types (existing behavior works)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### hooks/types.ts
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// New event
|
|
202
|
+
interface ContextEvent {
|
|
203
|
+
type: "context";
|
|
204
|
+
entries: readonly SessionEntry[];
|
|
205
|
+
messages: AppMessage[];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Extended base context (see Unified Context above)
|
|
209
|
+
|
|
210
|
+
// Command types
|
|
211
|
+
interface CommandOptions {
|
|
212
|
+
description?: string;
|
|
213
|
+
handler: (ctx: CommandContext) => Promise<CommandResult | void>;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
type CommandResult =
|
|
217
|
+
| string
|
|
218
|
+
| { prompt: string; attachments?: Attachment[] }
|
|
219
|
+
| { status: string };
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### hooks/loader.ts
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Track registered commands
|
|
226
|
+
interface LoadedHook {
|
|
227
|
+
path: string;
|
|
228
|
+
handlers: Map<string, Handler[]>;
|
|
229
|
+
commands: Map<string, CommandOptions>; // NEW
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// createHookAPI adds command() method
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### hooks/runner.ts
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
class HookRunner {
|
|
239
|
+
// State callbacks (set by AgentSession)
|
|
240
|
+
setStateCallbacks(cb: StateCallbacks): void;
|
|
241
|
+
|
|
242
|
+
// Command invocation
|
|
243
|
+
getCommands(): Map<string, CommandOptions>;
|
|
244
|
+
invokeCommand(name: string, argsRaw: string): Promise<CommandResult | void>;
|
|
245
|
+
|
|
246
|
+
// Context event with chaining
|
|
247
|
+
async emitContext(entries, messages): Promise<AppMessage[]> {
|
|
248
|
+
let result = messages;
|
|
249
|
+
for (const hook of this.hooks) {
|
|
250
|
+
const handlers = hook.handlers.get("context");
|
|
251
|
+
for (const h of handlers ?? []) {
|
|
252
|
+
const out = await h({ entries, messages: result }, this.createContext());
|
|
253
|
+
if (out?.messages) result = out.messages;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return result;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### agent-session.ts
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
// Expose saveEntry
|
|
265
|
+
async saveEntry(entry): Promise<void> {
|
|
266
|
+
this.sessionManager.saveEntry(entry);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Rebuild context
|
|
270
|
+
async rebuildContext(): Promise<void> {
|
|
271
|
+
const base = this.sessionManager.buildSessionContext();
|
|
272
|
+
const entries = this.sessionManager.getEntries();
|
|
273
|
+
const messages = await this._hookRunner.emitContext(entries, base.messages);
|
|
274
|
+
this.agent.replaceMessages(messages);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Fire context event during normal context building too
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### interactive-mode.ts
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
// In setupEditorSubmitHandler, check hook commands
|
|
284
|
+
const commands = this.session.hookRunner?.getCommands();
|
|
285
|
+
if (commands?.has(commandName)) {
|
|
286
|
+
const result = await this.session.invokeCommand(commandName, argsRaw);
|
|
287
|
+
// Handle result...
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Add hook commands to autocomplete
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Open Questions
|
|
295
|
+
|
|
296
|
+
1. **Mutation in all handlers or commands only?**
|
|
297
|
+
- `saveEntry`/`rebuildContext` in all handlers = more power, more footguns
|
|
298
|
+
- Commands only = safer, but limits hook creativity
|
|
299
|
+
- Recommendation: start with commands only
|
|
300
|
+
|
|
301
|
+
2. **Context event timing**
|
|
302
|
+
- Fire on every prompt? Or only when explicitly rebuilt?
|
|
303
|
+
- Need to fire on session load too
|
|
304
|
+
- Recommendation: fire whenever agent.replaceMessages is called
|
|
305
|
+
|
|
306
|
+
3. **Compaction interaction**
|
|
307
|
+
- Core compaction runs first, then `context` event
|
|
308
|
+
- Hooks can post-process compacted output
|
|
309
|
+
- Future: compaction itself could become a replaceable hook
|
|
310
|
+
|
|
311
|
+
4. **Multiple context handlers**
|
|
312
|
+
- Chain in load order (global → project)
|
|
313
|
+
- Each sees previous output
|
|
314
|
+
- No explicit priority system (KISS)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mariozechner/pi-coding-agent",
|
|
3
|
-
"version": "0.27.
|
|
3
|
+
"version": "0.27.8",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -39,9 +39,9 @@
|
|
|
39
39
|
"prepublishOnly": "npm run clean && npm run build"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@mariozechner/pi-agent-core": "^0.27.
|
|
43
|
-
"@mariozechner/pi-ai": "^0.27.
|
|
44
|
-
"@mariozechner/pi-tui": "^0.27.
|
|
42
|
+
"@mariozechner/pi-agent-core": "^0.27.8",
|
|
43
|
+
"@mariozechner/pi-ai": "^0.27.8",
|
|
44
|
+
"@mariozechner/pi-tui": "^0.27.8",
|
|
45
45
|
"chalk": "^5.5.0",
|
|
46
46
|
"cli-highlight": "^2.1.11",
|
|
47
47
|
"diff": "^8.0.2",
|