gsd-pi 2.11.0 → 2.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/dist/cli.js +18 -1
  2. package/dist/onboarding.js +3 -0
  3. package/dist/resource-loader.d.ts +2 -0
  4. package/dist/resource-loader.js +36 -1
  5. package/dist/resources/extensions/bg-shell/index.ts +51 -7
  6. package/dist/resources/extensions/gsd/auto-worktree.ts +509 -0
  7. package/dist/resources/extensions/gsd/auto.ts +381 -13
  8. package/dist/resources/extensions/gsd/commands.ts +9 -3
  9. package/dist/resources/extensions/gsd/doctor.ts +254 -3
  10. package/dist/resources/extensions/gsd/git-self-heal.ts +198 -0
  11. package/dist/resources/extensions/gsd/git-service.ts +11 -0
  12. package/dist/resources/extensions/gsd/guided-flow.ts +81 -9
  13. package/dist/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  14. package/dist/resources/extensions/gsd/preferences.ts +209 -1
  15. package/dist/resources/extensions/gsd/prompt-loader.ts +28 -1
  16. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  17. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -3
  18. package/dist/resources/extensions/gsd/prompts/discuss.md +10 -8
  19. package/dist/resources/extensions/gsd/prompts/execute-task.md +4 -2
  20. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -1
  21. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -1
  22. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  23. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +3 -1
  24. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +4 -2
  25. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -1
  26. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +3 -1
  27. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +9 -12
  28. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -3
  29. package/dist/resources/extensions/gsd/prompts/queue.md +3 -1
  30. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  31. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  32. package/dist/resources/extensions/gsd/prompts/system.md +32 -29
  33. package/dist/resources/extensions/gsd/templates/context.md +1 -1
  34. package/dist/resources/extensions/gsd/templates/state.md +3 -3
  35. package/dist/resources/extensions/gsd/tests/auto-worktree-merge.test.ts +282 -0
  36. package/dist/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +259 -0
  37. package/dist/resources/extensions/gsd/tests/auto-worktree.test.ts +147 -0
  38. package/dist/resources/extensions/gsd/tests/doctor-git.test.ts +246 -0
  39. package/dist/resources/extensions/gsd/tests/doctor.test.ts +115 -1
  40. package/dist/resources/extensions/gsd/tests/git-self-heal.test.ts +234 -0
  41. package/dist/resources/extensions/gsd/tests/isolation-resolver.test.ts +107 -0
  42. package/dist/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  43. package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +88 -0
  44. package/dist/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  45. package/dist/resources/extensions/gsd/tests/regex-hardening.test.ts +12 -0
  46. package/dist/resources/extensions/gsd/tests/worktree-e2e.test.ts +315 -0
  47. package/dist/resources/extensions/gsd/types.ts +109 -0
  48. package/dist/resources/extensions/gsd/worktree-manager.ts +6 -4
  49. package/dist/resources/extensions/search-the-web/command-search-provider.ts +8 -4
  50. package/dist/resources/extensions/search-the-web/native-search.ts +15 -10
  51. package/dist/resources/extensions/search-the-web/provider.ts +19 -2
  52. package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +62 -0
  53. package/dist/resources/extensions/search-the-web/tool-llm-context.ts +62 -3
  54. package/dist/resources/extensions/search-the-web/tool-search.ts +62 -3
  55. package/dist/wizard.js +1 -0
  56. package/package.json +1 -1
  57. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  58. package/packages/pi-agent-core/dist/agent-loop.js +169 -55
  59. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  60. package/packages/pi-agent-core/dist/agent.d.ts +13 -1
  61. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  62. package/packages/pi-agent-core/dist/agent.js +16 -0
  63. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  64. package/packages/pi-agent-core/dist/types.d.ts +91 -1
  65. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  66. package/packages/pi-agent-core/dist/types.js.map +1 -1
  67. package/packages/pi-agent-core/src/agent-loop.ts +273 -63
  68. package/packages/pi-agent-core/src/agent.ts +24 -0
  69. package/packages/pi-agent-core/src/types.ts +98 -0
  70. package/packages/pi-ai/dist/env-api-keys.js +1 -0
  71. package/packages/pi-ai/dist/env-api-keys.js.map +1 -1
  72. package/packages/pi-ai/dist/models.generated.d.ts +314 -0
  73. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  74. package/packages/pi-ai/dist/models.generated.js +236 -0
  75. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  76. package/packages/pi-ai/dist/types.d.ts +1 -1
  77. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  78. package/packages/pi-ai/dist/types.js.map +1 -1
  79. package/packages/pi-ai/src/env-api-keys.ts +1 -0
  80. package/packages/pi-ai/src/models.generated.ts +236 -0
  81. package/packages/pi-ai/src/types.ts +2 -1
  82. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  83. package/packages/pi-coding-agent/dist/cli/args.js +2 -1
  84. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  85. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -0
  86. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  87. package/packages/pi-coding-agent/dist/core/agent-session.js +69 -8
  88. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  89. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +4 -1
  90. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  91. package/packages/pi-coding-agent/dist/core/extensions/runner.js +2 -1
  92. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  93. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +5 -0
  94. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  95. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  96. package/packages/pi-coding-agent/dist/core/model-resolver.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/core/model-resolver.js +1 -0
  98. package/packages/pi-coding-agent/dist/core/model-resolver.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/core/sdk.js +3 -3
  100. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  101. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  102. package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -0
  103. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  104. package/packages/pi-coding-agent/src/cli/args.ts +2 -1
  105. package/packages/pi-coding-agent/src/core/agent-session.ts +76 -7
  106. package/packages/pi-coding-agent/src/core/extensions/runner.ts +2 -1
  107. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -0
  108. package/packages/pi-coding-agent/src/core/model-resolver.ts +1 -0
  109. package/packages/pi-coding-agent/src/core/sdk.ts +3 -3
  110. package/packages/pi-coding-agent/src/core/system-prompt.ts +9 -0
  111. package/packages/pi-tui/dist/components/editor.d.ts +11 -0
  112. package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
  113. package/packages/pi-tui/dist/components/editor.js +64 -6
  114. package/packages/pi-tui/dist/components/editor.js.map +1 -1
  115. package/packages/pi-tui/src/components/editor.ts +71 -6
  116. package/src/resources/extensions/bg-shell/index.ts +51 -7
  117. package/src/resources/extensions/gsd/auto-worktree.ts +509 -0
  118. package/src/resources/extensions/gsd/auto.ts +381 -13
  119. package/src/resources/extensions/gsd/commands.ts +9 -3
  120. package/src/resources/extensions/gsd/doctor.ts +254 -3
  121. package/src/resources/extensions/gsd/git-self-heal.ts +198 -0
  122. package/src/resources/extensions/gsd/git-service.ts +11 -0
  123. package/src/resources/extensions/gsd/guided-flow.ts +81 -9
  124. package/src/resources/extensions/gsd/post-unit-hooks.ts +449 -0
  125. package/src/resources/extensions/gsd/preferences.ts +209 -1
  126. package/src/resources/extensions/gsd/prompt-loader.ts +28 -1
  127. package/src/resources/extensions/gsd/prompts/complete-milestone.md +1 -1
  128. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -3
  129. package/src/resources/extensions/gsd/prompts/discuss.md +10 -8
  130. package/src/resources/extensions/gsd/prompts/execute-task.md +4 -2
  131. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +3 -1
  132. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +3 -1
  133. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +3 -1
  134. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +3 -1
  135. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +4 -2
  136. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +3 -1
  137. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +3 -1
  138. package/src/resources/extensions/gsd/prompts/plan-milestone.md +9 -12
  139. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -3
  140. package/src/resources/extensions/gsd/prompts/queue.md +3 -1
  141. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  142. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  143. package/src/resources/extensions/gsd/prompts/system.md +32 -29
  144. package/src/resources/extensions/gsd/templates/context.md +1 -1
  145. package/src/resources/extensions/gsd/templates/state.md +3 -3
  146. package/src/resources/extensions/gsd/tests/auto-worktree-merge.test.ts +282 -0
  147. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +259 -0
  148. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +147 -0
  149. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +246 -0
  150. package/src/resources/extensions/gsd/tests/doctor.test.ts +115 -1
  151. package/src/resources/extensions/gsd/tests/git-self-heal.test.ts +234 -0
  152. package/src/resources/extensions/gsd/tests/isolation-resolver.test.ts +107 -0
  153. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +297 -0
  154. package/src/resources/extensions/gsd/tests/preferences-git.test.ts +88 -0
  155. package/src/resources/extensions/gsd/tests/preferences-hooks.test.ts +226 -0
  156. package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +12 -0
  157. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +315 -0
  158. package/src/resources/extensions/gsd/types.ts +109 -0
  159. package/src/resources/extensions/gsd/worktree-manager.ts +6 -4
  160. package/src/resources/extensions/search-the-web/command-search-provider.ts +8 -4
  161. package/src/resources/extensions/search-the-web/native-search.ts +15 -10
  162. package/src/resources/extensions/search-the-web/provider.ts +19 -2
  163. package/src/resources/extensions/search-the-web/tool-fetch-page.ts +62 -0
  164. package/src/resources/extensions/search-the-web/tool-llm-context.ts +62 -3
  165. package/src/resources/extensions/search-the-web/tool-search.ts +62 -3
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["import { join } from \"node:path\";\nimport { Agent, type AgentMessage, type ThinkingLevel } from \"@gsd/pi-agent-core\";\nimport type { Message, Model } from \"@gsd/pi-ai\";\nimport { getAgentDir, getDocsPath } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\nimport type { ExtensionRunner, LoadExtensionsResult, ToolDefinition } from \"./extensions/index.js\";\nimport { convertToLlm } from \"./messages.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { findInitialModel } from \"./model-resolver.js\";\nimport type { ResourceLoader } from \"./resource-loader.js\";\nimport { DefaultResourceLoader } from \"./resource-loader.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.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\ttype ToolName,\n\twriteTool,\n} from \"./tools/index.js\";\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/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: new ModelRegistry(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (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/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\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/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandLocation,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.js\";\nexport type { PromptTemplate } from \"./prompt-templates.js\";\nexport type { Skill } from \"./skills.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 * 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 * import { getModel } from '@gsd/pi-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\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 loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [readTool, bashTool],\n * resourceLoader: loader,\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\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? new ModelRegistry(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd);\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\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 = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await modelRegistry.getApiKey(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, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `No models available. Use /login or set an API key environment variable. See ${join(getDocsPath(), \"providers.md\")}. Then use /model to select a model.`;\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\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 = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst initialActiveToolNames: ToolName[] = options.tools\n\t\t? options.tools.map((t) => t.name).filter((n): n is ToolName => n in allTools)\n\t\t: defaultActiveToolNames;\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tonPayload: async (payload, _model) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload);\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getRetrySettings().maxDelayMs,\n\t\tgetApiKey: async (provider) => {\n\t\t\t// Use the provider argument from the in-flight request;\n\t\t\t// agent.state.model may already be switched mid-turn.\n\t\t\tconst resolvedProvider = provider || agent.state.model?.provider;\n\t\t\tif (!resolvedProvider) {\n\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t}\n\n\t\t\t// Retry key resolution with backoff to handle transient network failures\n\t\t\t// (e.g., OAuth token refresh failing due to brief connectivity loss).\n\t\t\tconst maxAttempts = 3;\n\t\t\tconst baseDelayMs = 2000;\n\t\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\t\tconst key = await modelRegistry.getApiKeyForProvider(resolvedProvider);\n\t\t\t\tif (key) return key;\n\n\t\t\t\t// On the last attempt, fall through to error handling below\n\t\t\t\tif (attempt >= maxAttempts) break;\n\n\t\t\t\t// Only retry if credentials exist (network issue) — no point retrying\n\t\t\t\t// when there are genuinely no credentials configured.\n\t\t\t\tconst hasAuth = modelRegistry.authStorage.hasAuth(resolvedProvider);\n\t\t\t\tconst model = agent.state.model;\n\t\t\t\tconst isOAuth = model && modelRegistry.isUsingOAuth(model);\n\t\t\t\tif (!hasAuth && !isOAuth) break;\n\n\t\t\t\t// Wait with exponential backoff before retrying\n\t\t\t\tawait new Promise(resolve => setTimeout(resolve, baseDelayMs * attempt));\n\t\t\t}\n\n\t\t\t// All retries exhausted — throw descriptive error\n\t\t\t// Check if credentials exist but are temporarily backed off\n\t\t\t// (e.g., after a 429 quota exhaustion). Provide a specific error\n\t\t\t// so the retry handler knows this is transient, not a permanent\n\t\t\t// auth failure.\n\t\t\tconst hasAuth = modelRegistry.authStorage.hasAuth(resolvedProvider);\n\t\t\tif (hasAuth) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`All credentials for \"${resolvedProvider}\" are temporarily backed off due to rate limiting. ` +\n\t\t\t\t\t\t`The request will be retried automatically when backoff expires.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst model = agent.state.model;\n\t\t\tconst isOAuth = model && modelRegistry.isUsingOAuth(model);\n\t\t\tif (isOAuth) {\n\t\t\t\t// If credentials exist but are all in a backoff window (quota / rate-limit),\n\t\t\t\t// surface a specific message instead of the misleading \"Authentication failed\".\n\t\t\t\tif (modelRegistry.authStorage.areAllCredentialsBackedOff(resolvedProvider)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Rate limit in effect for \"${resolvedProvider}\". ` +\n\t\t\t\t\t\t\t`Please wait before retrying or switch to a different model.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Authentication failed for \"${resolvedProvider}\". ` +\n\t\t\t\t\t\t`Credentials may have expired or network is unavailable. ` +\n\t\t\t\t\t\t`Run '/login ${resolvedProvider}' to re-authenticate.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`No API key found for \"${resolvedProvider}\". ` +\n\t\t\t\t\t`Set an API key environment variable or run '/login ${resolvedProvider}'.`,\n\t\t\t);\n\t\t},\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\textensionRunnerRef,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\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":["import { join } from \"node:path\";\nimport { Agent, type AgentMessage, type ThinkingLevel } from \"@gsd/pi-agent-core\";\nimport type { Message, Model } from \"@gsd/pi-ai\";\nimport { getAgentDir, getDocsPath } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { AuthStorage } from \"./auth-storage.js\";\nimport { DEFAULT_THINKING_LEVEL } from \"./defaults.js\";\nimport type { ExtensionRunner, LoadExtensionsResult, ToolDefinition } from \"./extensions/index.js\";\nimport { convertToLlm } from \"./messages.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { findInitialModel } from \"./model-resolver.js\";\nimport type { ResourceLoader } from \"./resource-loader.js\";\nimport { DefaultResourceLoader } from \"./resource-loader.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { SettingsManager } from \"./settings-manager.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\ttype ToolName,\n\twriteTool,\n} from \"./tools/index.js\";\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/** Auth storage for credentials. Default: AuthStorage.create(agentDir/auth.json) */\n\tauthStorage?: AuthStorage;\n\t/** Model registry. Default: new ModelRegistry(authStorage, agentDir/models.json) */\n\tmodelRegistry?: ModelRegistry;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'medium' (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/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools to register (in addition to built-in tools). */\n\tcustomTools?: ToolDefinition[];\n\n\t/** Resource loader. When omitted, DefaultResourceLoader is used. */\n\tresourceLoader?: ResourceLoader;\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/** Extensions result (for UI context setup in interactive mode) */\n\textensionsResult: LoadExtensionsResult;\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type {\n\tExtensionAPI,\n\tExtensionCommandContext,\n\tExtensionContext,\n\tExtensionFactory,\n\tSlashCommandInfo,\n\tSlashCommandLocation,\n\tSlashCommandSource,\n\tToolDefinition,\n} from \"./extensions/index.js\";\nexport type { PromptTemplate } from \"./prompt-templates.js\";\nexport type { Skill } from \"./skills.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 * 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 * import { getModel } from '@gsd/pi-ai';\n * const { session } = await createAgentSession({\n * model: getModel('anthropic', 'claude-opus-4-5'),\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 loader = new DefaultResourceLoader({\n * cwd: process.cwd(),\n * agentDir: getAgentDir(),\n * settingsManager: SettingsManager.create(),\n * });\n * await loader.reload();\n * const { session } = await createAgentSession({\n * model: myModel,\n * tools: [readTool, bashTool],\n * resourceLoader: loader,\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\tlet resourceLoader = options.resourceLoader;\n\n\t// Use provided or create AuthStorage and ModelRegistry\n\tconst authPath = options.agentDir ? join(agentDir, \"auth.json\") : undefined;\n\tconst modelsPath = options.agentDir ? join(agentDir, \"models.json\") : undefined;\n\tconst authStorage = options.authStorage ?? AuthStorage.create(authPath);\n\tconst modelRegistry = options.modelRegistry ?? new ModelRegistry(authStorage, modelsPath);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd);\n\n\tif (!resourceLoader) {\n\t\tresourceLoader = new DefaultResourceLoader({ cwd, agentDir, settingsManager });\n\t\tawait resourceLoader.reload();\n\t\ttime(\"resourceLoader.reload\");\n\t}\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.buildSessionContext();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\tconst hasThinkingEntry = sessionManager.getBranch().some((entry) => entry.type === \"thinking_level_change\");\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 = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel && (await modelRegistry.getApiKey(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, use findInitialModel (checks settings default, then provider defaults)\n\tif (!model) {\n\t\tconst result = await findInitialModel({\n\t\t\tscopedModels: [],\n\t\t\tisContinuing: hasExistingSession,\n\t\t\tdefaultProvider: settingsManager.getDefaultProvider(),\n\t\t\tdefaultModelId: settingsManager.getDefaultModel(),\n\t\t\tdefaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),\n\t\t\tmodelRegistry,\n\t\t});\n\t\tmodel = result.model;\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `No models available. Use /login or set an API key environment variable. See ${join(getDocsPath(), \"providers.md\")}. Then use /model to select a model.`;\n\t\t} else if (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\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 = hasThinkingEntry\n\t\t\t? (existingSession.thinkingLevel as ThinkingLevel)\n\t\t\t: (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model || !model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst defaultActiveToolNames: ToolName[] = [\"read\", \"bash\", \"edit\", \"write\", \"lsp\"];\n\tconst initialActiveToolNames: ToolName[] = options.tools\n\t\t? options.tools.map((t) => t.name).filter((n): n is ToolName => n in allTools)\n\t\t: defaultActiveToolNames;\n\n\tlet agent: Agent;\n\n\t// Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)\n\tconst convertToLlmWithBlockImages = (messages: AgentMessage[]): Message[] => {\n\t\tconst converted = convertToLlm(messages);\n\t\t// Check setting dynamically so mid-session changes take effect\n\t\tif (!settingsManager.getBlockImages()) {\n\t\t\treturn converted;\n\t\t}\n\t\t// Filter out ImageContent from all messages, replacing with text placeholder\n\t\treturn converted.map((msg) => {\n\t\t\tif (msg.role === \"user\" || msg.role === \"toolResult\") {\n\t\t\t\tconst content = msg.content;\n\t\t\t\tif (Array.isArray(content)) {\n\t\t\t\t\tconst hasImages = content.some((c) => c.type === \"image\");\n\t\t\t\t\tif (hasImages) {\n\t\t\t\t\t\tconst filteredContent = content\n\t\t\t\t\t\t\t.map((c) =>\n\t\t\t\t\t\t\t\tc.type === \"image\" ? { type: \"text\" as const, text: \"Image reading is disabled.\" } : c,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.filter(\n\t\t\t\t\t\t\t\t(c, i, arr) =>\n\t\t\t\t\t\t\t\t\t// Dedupe consecutive \"Image reading is disabled.\" texts\n\t\t\t\t\t\t\t\t\t!(\n\t\t\t\t\t\t\t\t\t\tc.type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\tc.text === \"Image reading is disabled.\" &&\n\t\t\t\t\t\t\t\t\t\ti > 0 &&\n\t\t\t\t\t\t\t\t\t\tarr[i - 1].type === \"text\" &&\n\t\t\t\t\t\t\t\t\t\t(arr[i - 1] as { type: \"text\"; text: string }).text === \"Image reading is disabled.\"\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\treturn { ...msg, content: filteredContent };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn msg;\n\t\t});\n\t};\n\n\tconst extensionRunnerRef: { current?: ExtensionRunner } = {};\n\n\tagent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt: \"\",\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: [],\n\t\t},\n\t\tconvertToLlm: convertToLlmWithBlockImages,\n\t\tonPayload: async (payload, currentModel) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner?.hasHandlers(\"before_provider_request\")) {\n\t\t\t\treturn payload;\n\t\t\t}\n\t\t\treturn runner.emitBeforeProviderRequest(payload, currentModel);\n\t\t},\n\t\tsessionId: sessionManager.getSessionId(),\n\t\ttransformContext: async (messages) => {\n\t\t\tconst runner = extensionRunnerRef.current;\n\t\t\tif (!runner) return messages;\n\t\t\treturn runner.emitContext(messages);\n\t\t},\n\t\tsteeringMode: settingsManager.getSteeringMode(),\n\t\tfollowUpMode: settingsManager.getFollowUpMode(),\n\t\ttransport: settingsManager.getTransport(),\n\t\tthinkingBudgets: settingsManager.getThinkingBudgets(),\n\t\tmaxRetryDelayMs: settingsManager.getRetrySettings().maxDelayMs,\n\t\tgetApiKey: async (provider) => {\n\t\t\t// Use the provider argument from the in-flight request;\n\t\t\t// agent.state.model may already be switched mid-turn.\n\t\t\tconst resolvedProvider = provider || agent.state.model?.provider;\n\t\t\tif (!resolvedProvider) {\n\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t}\n\n\t\t\t// Retry key resolution with backoff to handle transient network failures\n\t\t\t// (e.g., OAuth token refresh failing due to brief connectivity loss).\n\t\t\tconst maxAttempts = 3;\n\t\t\tconst baseDelayMs = 2000;\n\t\t\tfor (let attempt = 1; attempt <= maxAttempts; attempt++) {\n\t\t\t\tconst key = await modelRegistry.getApiKeyForProvider(resolvedProvider);\n\t\t\t\tif (key) return key;\n\n\t\t\t\t// On the last attempt, fall through to error handling below\n\t\t\t\tif (attempt >= maxAttempts) break;\n\n\t\t\t\t// Only retry if credentials exist (network issue) — no point retrying\n\t\t\t\t// when there are genuinely no credentials configured.\n\t\t\t\tconst hasAuth = modelRegistry.authStorage.hasAuth(resolvedProvider);\n\t\t\t\tconst model = agent.state.model;\n\t\t\t\tconst isOAuth = model && modelRegistry.isUsingOAuth(model);\n\t\t\t\tif (!hasAuth && !isOAuth) break;\n\n\t\t\t\t// Wait with exponential backoff before retrying\n\t\t\t\tawait new Promise(resolve => setTimeout(resolve, baseDelayMs * attempt));\n\t\t\t}\n\n\t\t\t// All retries exhausted — throw descriptive error\n\t\t\t// Check if credentials exist but are temporarily backed off\n\t\t\t// (e.g., after a 429 quota exhaustion). Provide a specific error\n\t\t\t// so the retry handler knows this is transient, not a permanent\n\t\t\t// auth failure.\n\t\t\tconst hasAuth = modelRegistry.authStorage.hasAuth(resolvedProvider);\n\t\t\tif (hasAuth) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`All credentials for \"${resolvedProvider}\" are temporarily backed off due to rate limiting. ` +\n\t\t\t\t\t\t`The request will be retried automatically when backoff expires.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst model = agent.state.model;\n\t\t\tconst isOAuth = model && modelRegistry.isUsingOAuth(model);\n\t\t\tif (isOAuth) {\n\t\t\t\t// If credentials exist but are all in a backoff window (quota / rate-limit),\n\t\t\t\t// surface a specific message instead of the misleading \"Authentication failed\".\n\t\t\t\tif (modelRegistry.authStorage.areAllCredentialsBackedOff(resolvedProvider)) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Rate limit in effect for \"${resolvedProvider}\". ` +\n\t\t\t\t\t\t\t`Please wait before retrying or switch to a different model.`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Authentication failed for \"${resolvedProvider}\". ` +\n\t\t\t\t\t\t`Credentials may have expired or network is unavailable. ` +\n\t\t\t\t\t\t`Run '/login ${resolvedProvider}' to re-authenticate.`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`No API key found for \"${resolvedProvider}\". ` +\n\t\t\t\t\t`Set an API key environment variable or run '/login ${resolvedProvider}'.`,\n\t\t\t);\n\t\t},\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t\tif (!hasThinkingEntry) {\n\t\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t\t}\n\t} else {\n\t\t// Save initial model and thinking level for new sessions so they can be restored on resume\n\t\tif (model) {\n\t\t\tsessionManager.appendModelChange(model.provider, model.id);\n\t\t}\n\t\tsessionManager.appendThinkingLevelChange(thinkingLevel);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tcwd,\n\t\tscopedModels: options.scopedModels,\n\t\tresourceLoader,\n\t\tcustomTools: options.customTools,\n\t\tmodelRegistry,\n\t\tinitialActiveToolNames,\n\t\textensionRunnerRef,\n\t});\n\tconst extensionsResult = resourceLoader.getExtensions();\n\n\treturn {\n\t\tsession,\n\t\textensionsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAahE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CAmLhF"}
1
+ {"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAyB,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAchE,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,yBAAyB;IACzB,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CA2LhF"}
@@ -12,6 +12,7 @@ const toolDescriptions = {
12
12
  grep: "Search file contents for patterns (respects .gitignore)",
13
13
  find: "Find files by glob pattern (respects .gitignore)",
14
14
  ls: "List directory contents",
15
+ lsp: "Code intelligence via Language Server Protocol (go-to-definition, references, diagnostics, hover, rename, symbols)",
15
16
  };
16
17
  /** Build the system prompt with tools, guidelines, and context */
17
18
  export function buildSystemPrompt(options = {}) {
@@ -86,6 +87,7 @@ export function buildSystemPrompt(options = {}) {
86
87
  const hasFind = tools.includes("find");
87
88
  const hasLs = tools.includes("ls");
88
89
  const hasRead = tools.includes("read");
90
+ const hasLsp = tools.includes("lsp");
89
91
  // File exploration guidelines
90
92
  if (hasBash && !hasGrep && !hasFind && !hasLs) {
91
93
  addGuideline("Use bash for file operations like ls, rg, find");
@@ -105,6 +107,10 @@ export function buildSystemPrompt(options = {}) {
105
107
  if (hasWrite) {
106
108
  addGuideline("Use write only for new files or complete rewrites");
107
109
  }
110
+ // LSP guideline
111
+ if (hasLsp) {
112
+ addGuideline("Use lsp for go-to-definition, find-references, hover, rename, and diagnostics when working in typed codebases. Prefer lsp over grep for semantic navigation (finding call sites, implementations, type info). Falls back gracefully if no language server is available for the file type.");
113
+ }
108
114
  // Output guideline (only when actually writing or executing)
109
115
  if (hasEdit || hasWrite) {
110
116
  addGuideline("When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did");
@@ -1 +1 @@
1
- {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<string, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n};\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = cwd ?? process.cwd();\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// Built-ins use toolDescriptions. Custom tools can provide one-line snippets.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst toolsList =\n\t\ttools.length > 0\n\t\t\t? tools\n\t\t\t\t\t.map((name) => {\n\t\t\t\t\t\tconst snippet = toolSnippets?.[name] ?? toolDescriptions[name] ?? name;\n\t\t\t\t\t\treturn `- ${name}: ${snippet}`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\")\n\t\t\t: \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\taddGuideline(\"Use read to examine files before editing. You must use this tool instead of cat or sed.\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\taddGuideline(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\taddGuideline(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// Output guideline (only when actually writing or executing)\n\tif (hasEdit || hasWrite) {\n\t\taddGuideline(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include these\n\taddGuideline(\"Be concise in your responses\");\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nPi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md)\n- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
1
+ {"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport { getDocsPath, getExamplesPath, getReadmePath } from \"../config.js\";\nimport { formatSkillsForPrompt, type Skill } from \"./skills.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<string, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n\tlsp: \"Code intelligence via Language Server Protocol (go-to-definition, references, diagnostics, hover, rename, symbols)\",\n};\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: string[];\n\t/** Optional one-line tool snippets keyed by tool name. */\n\ttoolSnippets?: Record<string, string>;\n\t/** Additional guideline bullets appended to the default system prompt guidelines. */\n\tpromptGuidelines?: string[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Pre-loaded context files. */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills. */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\ttoolSnippets,\n\t\tpromptGuidelines,\n\t\tappendSystemPrompt,\n\t\tcwd,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = cwd ?? process.cwd();\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = appendSystemPrompt ? `\\n\\n${appendSystemPrompt}` : \"\";\n\n\tconst contextFiles = providedContextFiles ?? [];\n\tconst skills = providedSkills ?? [];\n\n\tif (customPrompt) {\n\t\tlet prompt = customPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation and examples\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\tconst examplesPath = getExamplesPath();\n\n\t// Build tools list based on selected tools.\n\t// Built-ins use toolDescriptions. Custom tools can provide one-line snippets.\n\tconst tools = selectedTools || [\"read\", \"bash\", \"edit\", \"write\"];\n\tconst toolsList =\n\t\ttools.length > 0\n\t\t\t? tools\n\t\t\t\t\t.map((name) => {\n\t\t\t\t\t\tconst snippet = toolSnippets?.[name] ?? toolDescriptions[name] ?? name;\n\t\t\t\t\t\treturn `- ${name}: ${snippet}`;\n\t\t\t\t\t})\n\t\t\t\t\t.join(\"\\n\")\n\t\t\t: \"(none)\";\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\tconst guidelinesSet = new Set<string>();\n\tconst addGuideline = (guideline: string): void => {\n\t\tif (guidelinesSet.has(guideline)) {\n\t\t\treturn;\n\t\t}\n\t\tguidelinesSet.add(guideline);\n\t\tguidelinesList.push(guideline);\n\t};\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\tconst hasLsp = tools.includes(\"lsp\");\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\taddGuideline(\"Use bash for file operations like ls, rg, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\taddGuideline(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\taddGuideline(\"Use read to examine files before editing. You must use this tool instead of cat or sed.\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\taddGuideline(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\taddGuideline(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// LSP guideline\n\tif (hasLsp) {\n\t\taddGuideline(\n\t\t\t\"Use lsp for go-to-definition, find-references, hover, rename, and diagnostics when working in typed codebases. Prefer lsp over grep for semantic navigation (finding call sites, implementations, type info). Falls back gracefully if no language server is available for the file type.\",\n\t\t);\n\t}\n\n\t// Output guideline (only when actually writing or executing)\n\tif (hasEdit || hasWrite) {\n\t\taddGuideline(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\tfor (const guideline of promptGuidelines ?? []) {\n\t\tconst normalized = guideline.trim();\n\t\tif (normalized.length > 0) {\n\t\t\taddGuideline(normalized);\n\t\t}\n\t}\n\n\t// Always include these\n\taddGuideline(\"Be concise in your responses\");\n\taddGuideline(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nIn addition to the tools above, you may have access to other custom tools depending on the project.\n\nGuidelines:\n${guidelines}\n\nPi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- Examples: ${examplesPath} (extensions, custom tools, SDK)\n- When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md)\n- When working on pi topics, read the docs and examples, and follow .md cross-references before implementing\n- Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"Project-specific instructions and guidelines:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
@@ -207,7 +207,7 @@ ${chalk.bold("Options:")}
207
207
  Supports globs (anthropic/*, *sonnet*) and fuzzy matching
208
208
  --no-tools Disable all built-in tools
209
209
  --tools <tools> Comma-separated list of tools to enable (default: read,bash,edit,write)
210
- Available: read, bash, edit, write, grep, find, ls
210
+ Available: read, bash, edit, write, lsp, grep, find, ls
211
211
  --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
212
212
  --extension, -e <path> Load an extension file (can be used multiple times)
213
213
  --no-extensions, -ne Disable extension discovery (explicit -e paths still work)
@@ -290,6 +290,7 @@ ${chalk.bold("Environment Variables:")}
290
290
  AI_GATEWAY_API_KEY - Vercel AI Gateway API key
291
291
  ZAI_API_KEY - ZAI API key
292
292
  MISTRAL_API_KEY - Mistral API key
293
+ OLLAMA_API_KEY - Ollama Cloud API key
293
294
  MINIMAX_API_KEY - MiniMax API key
294
295
  OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key
295
296
  KIMI_API_KEY - Kimi For Coding API key
@@ -67,7 +67,6 @@ import {
67
67
  type TurnEndEvent,
68
68
  type TurnStartEvent,
69
69
  wrapRegisteredTools,
70
- wrapToolsWithExtensions,
71
70
  } from "./extensions/index.js";
72
71
  import type { BashExecutionMessage, CustomMessage } from "./messages.js";
73
72
  import { FallbackResolver } from "./fallback-resolver.js";
@@ -304,6 +303,11 @@ export class AgentSession {
304
303
  // (session persistence, extensions, auto-compaction, retry logic)
305
304
  this._unsubscribeAgent = this.agent.subscribe(this._handleAgentEvent);
306
305
 
306
+ // Install tool hooks that await the event queue before emitting extension events.
307
+ // This ensures extensions always see settled state (e.g., assistant message appended)
308
+ // even when tools execute in parallel.
309
+ this._installAgentToolHooks();
310
+
307
311
  this._buildRuntime({
308
312
  activeToolNames: this._initialActiveToolNames,
309
313
  includeAllExtensionTools: true,
@@ -477,6 +481,73 @@ export class AgentSession {
477
481
  }
478
482
  }
479
483
 
484
+ /**
485
+ * Install beforeToolCall/afterToolCall hooks on the Agent.
486
+ *
487
+ * These hooks await `_agentEventQueue` before emitting extension events,
488
+ * ensuring that all prior events (including `message_end` which appends
489
+ * the assistant message) have fully settled. This prevents a race condition
490
+ * in parallel tool execution where extension `tool_call` handlers could
491
+ * see stale agent state.
492
+ */
493
+ private _installAgentToolHooks(): void {
494
+ this.agent.setBeforeToolCall(async ({ toolCall, args }) => {
495
+ // Wait for all queued agent events to settle before emitting to extensions
496
+ await this._agentEventQueue;
497
+
498
+ if (!this._extensionRunner?.hasHandlers("tool_call")) return undefined;
499
+
500
+ try {
501
+ const callResult = await this._extensionRunner.emitToolCall({
502
+ type: "tool_call",
503
+ toolName: toolCall.name,
504
+ toolCallId: toolCall.id,
505
+ input: args as Record<string, unknown>,
506
+ });
507
+
508
+ if (callResult?.block) {
509
+ return {
510
+ block: true,
511
+ reason: callResult.reason || "Tool execution was blocked by an extension",
512
+ };
513
+ }
514
+ } catch (err) {
515
+ if (err instanceof Error) {
516
+ return { block: true, reason: err.message };
517
+ }
518
+ return { block: true, reason: `Extension failed, blocking execution: ${String(err)}` };
519
+ }
520
+
521
+ return undefined;
522
+ });
523
+
524
+ this.agent.setAfterToolCall(async ({ toolCall, args, result, isError }) => {
525
+ // Wait for all queued agent events to settle
526
+ await this._agentEventQueue;
527
+
528
+ if (!this._extensionRunner?.hasHandlers("tool_result")) return undefined;
529
+
530
+ const resultResult = await this._extensionRunner.emitToolResult({
531
+ type: "tool_result",
532
+ toolName: toolCall.name,
533
+ toolCallId: toolCall.id,
534
+ input: args as Record<string, unknown>,
535
+ content: result.content,
536
+ details: result.details,
537
+ isError,
538
+ });
539
+
540
+ if (resultResult) {
541
+ return {
542
+ content: resultResult.content ?? undefined,
543
+ details: resultResult.details ?? undefined,
544
+ };
545
+ }
546
+
547
+ return undefined;
548
+ });
549
+ }
550
+
480
551
  /** Extract text content from a message */
481
552
  private _getUserMessageText(message: Message): string {
482
553
  if (message.role !== "user") return "";
@@ -2181,12 +2252,10 @@ export class AgentSession {
2181
2252
  toolRegistry.set(tool.name, tool);
2182
2253
  }
2183
2254
 
2184
- if (this._extensionRunner) {
2185
- const wrappedAllTools = wrapToolsWithExtensions(Array.from(toolRegistry.values()), this._extensionRunner);
2186
- this._toolRegistry = new Map(wrappedAllTools.map((tool) => [tool.name, tool]));
2187
- } else {
2188
- this._toolRegistry = toolRegistry;
2189
- }
2255
+ // Tool interception (tool_call/tool_result extension events) is handled by
2256
+ // beforeToolCall/afterToolCall hooks installed in _installAgentToolHooks(),
2257
+ // which await _agentEventQueue for safe parallel execution.
2258
+ this._toolRegistry = toolRegistry;
2190
2259
 
2191
2260
  const nextActiveToolNames = options?.activeToolNames
2192
2261
  ? [...options.activeToolNames]
@@ -712,7 +712,7 @@ export class ExtensionRunner {
712
712
  return currentMessages;
713
713
  }
714
714
 
715
- async emitBeforeProviderRequest(payload: unknown): Promise<unknown> {
715
+ async emitBeforeProviderRequest(payload: unknown, model?: { provider: string; id: string }): Promise<unknown> {
716
716
  const ctx = this.createContext();
717
717
  let currentPayload = payload;
718
718
 
@@ -725,6 +725,7 @@ export class ExtensionRunner {
725
725
  const event: BeforeProviderRequestEvent = {
726
726
  type: "before_provider_request",
727
727
  payload: currentPayload,
728
+ model,
728
729
  };
729
730
  const handlerResult = await handler(event, ctx);
730
731
  if (handlerResult !== undefined) {
@@ -506,6 +506,8 @@ export interface ContextEvent {
506
506
  export interface BeforeProviderRequestEvent {
507
507
  type: "before_provider_request";
508
508
  payload: unknown;
509
+ /** The resolved model for this request (provider, id, etc.) */
510
+ model?: { provider: string; id: string };
509
511
  }
510
512
 
511
513
  /** Fired after user submits prompt but before agent loop. */
@@ -36,6 +36,7 @@ export const defaultModelPerProvider: Record<KnownProvider, string> = {
36
36
  "opencode-go": "kimi-k2.5",
37
37
  "kimi-coding": "kimi-k2-thinking",
38
38
  "alibaba-coding-plan": "qwen3.5-plus",
39
+ "ollama-cloud": "qwen3:32b",
39
40
  };
40
41
 
41
42
  export interface ScopedModel {
@@ -238,7 +238,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
238
238
  thinkingLevel = "off";
239
239
  }
240
240
 
241
- const defaultActiveToolNames: ToolName[] = ["read", "bash", "edit", "write"];
241
+ const defaultActiveToolNames: ToolName[] = ["read", "bash", "edit", "write", "lsp"];
242
242
  const initialActiveToolNames: ToolName[] = options.tools
243
243
  ? options.tools.map((t) => t.name).filter((n): n is ToolName => n in allTools)
244
244
  : defaultActiveToolNames;
@@ -292,12 +292,12 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
292
292
  tools: [],
293
293
  },
294
294
  convertToLlm: convertToLlmWithBlockImages,
295
- onPayload: async (payload, _model) => {
295
+ onPayload: async (payload, currentModel) => {
296
296
  const runner = extensionRunnerRef.current;
297
297
  if (!runner?.hasHandlers("before_provider_request")) {
298
298
  return payload;
299
299
  }
300
- return runner.emitBeforeProviderRequest(payload);
300
+ return runner.emitBeforeProviderRequest(payload, currentModel);
301
301
  },
302
302
  sessionId: sessionManager.getSessionId(),
303
303
  transformContext: async (messages) => {
@@ -14,6 +14,7 @@ const toolDescriptions: Record<string, string> = {
14
14
  grep: "Search file contents for patterns (respects .gitignore)",
15
15
  find: "Find files by glob pattern (respects .gitignore)",
16
16
  ls: "List directory contents",
17
+ lsp: "Code intelligence via Language Server Protocol (go-to-definition, references, diagnostics, hover, rename, symbols)",
17
18
  };
18
19
 
19
20
  export interface BuildSystemPromptOptions {
@@ -131,6 +132,7 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
131
132
  const hasFind = tools.includes("find");
132
133
  const hasLs = tools.includes("ls");
133
134
  const hasRead = tools.includes("read");
135
+ const hasLsp = tools.includes("lsp");
134
136
 
135
137
  // File exploration guidelines
136
138
  if (hasBash && !hasGrep && !hasFind && !hasLs) {
@@ -154,6 +156,13 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
154
156
  addGuideline("Use write only for new files or complete rewrites");
155
157
  }
156
158
 
159
+ // LSP guideline
160
+ if (hasLsp) {
161
+ addGuideline(
162
+ "Use lsp for go-to-definition, find-references, hover, rename, and diagnostics when working in typed codebases. Prefer lsp over grep for semantic navigation (finding call sites, implementations, type info). Falls back gracefully if no language server is available for the file type.",
163
+ );
164
+ }
165
+
157
166
  // Output guideline (only when actually writing or executing)
158
167
  if (hasEdit || hasWrite) {
159
168
  addGuideline(
@@ -43,6 +43,9 @@ export declare class Editor implements Component, Focusable {
43
43
  private autocompleteState;
44
44
  private autocompletePrefix;
45
45
  private autocompleteMaxVisible;
46
+ private autocompleteDebounceTimer;
47
+ private lastAutocompleteLookupPrefix;
48
+ private static readonly AUTOCOMPLETE_DEBOUNCE_MS;
46
49
  private pastes;
47
50
  private pasteCounter;
48
51
  private pasteBuffer;
@@ -110,6 +113,11 @@ export declare class Editor implements Component, Focusable {
110
113
  */
111
114
  private insertTextAtCursorInternal;
112
115
  private insertCharacter;
116
+ /**
117
+ * Debounced version of tryTriggerAutocomplete for @ file reference context.
118
+ * Prevents synchronous fuzzyFind calls from blocking the event loop on every keystroke.
119
+ */
120
+ private debouncedTriggerAutocomplete;
113
121
  private handlePaste;
114
122
  private addNewLine;
115
123
  private shouldSubmitOnBackslashEnter;
@@ -220,7 +228,10 @@ export declare class Editor implements Component, Focusable {
220
228
  private handleSlashCommandCompletion;
221
229
  private forceFileAutocomplete;
222
230
  private cancelAutocomplete;
231
+ private clearAutocompleteDebounce;
223
232
  isShowingAutocomplete(): boolean;
224
233
  private updateAutocomplete;
234
+ private debouncedUpdateAutocompleteSuggestions;
235
+ private applyAutocompleteSuggestions;
225
236
  }
226
237
  //# sourceMappingURL=editor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"editor.d.ts","sourceRoot":"","sources":["../../src/components/editor.ts"],"names":[],"mappings":"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"}
@@ -69,6 +69,7 @@ export function wordWrapLine(line, maxWidth) {
69
69
  return chunks;
70
70
  }
71
71
  export class Editor {
72
+ static { this.AUTOCOMPLETE_DEBOUNCE_MS = 150; }
72
73
  constructor(tui, theme, options = {}) {
73
74
  this.state = {
74
75
  lines: [""],
@@ -85,6 +86,10 @@ export class Editor {
85
86
  this.autocompleteState = null;
86
87
  this.autocompletePrefix = "";
87
88
  this.autocompleteMaxVisible = 5;
89
+ // Debounce for @ file autocomplete to prevent blocking the event loop
90
+ // with synchronous fuzzyFind calls on every keystroke
91
+ this.autocompleteDebounceTimer = null;
92
+ this.lastAutocompleteLookupPrefix = null;
88
93
  // Paste tracking for large pastes
89
94
  this.pastes = new Map();
90
95
  this.pasteCounter = 0;
@@ -796,9 +801,10 @@ export class Editor {
796
801
  if (this.isInSlashCommandContext(textBeforeCursor)) {
797
802
  this.tryTriggerAutocomplete();
798
803
  }
799
- // Check if we're in an @ file reference context
804
+ // Check if we're in an @ file reference context (debounce to avoid
805
+ // blocking the event loop with synchronous fuzzyFind on every keystroke)
800
806
  else if (textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
801
- this.tryTriggerAutocomplete();
807
+ this.debouncedTriggerAutocomplete();
802
808
  }
803
809
  }
804
810
  }
@@ -806,6 +812,21 @@ export class Editor {
806
812
  this.updateAutocomplete();
807
813
  }
808
814
  }
815
+ /**
816
+ * Debounced version of tryTriggerAutocomplete for @ file reference context.
817
+ * Prevents synchronous fuzzyFind calls from blocking the event loop on every keystroke.
818
+ */
819
+ debouncedTriggerAutocomplete() {
820
+ if (this.autocompleteDebounceTimer) {
821
+ clearTimeout(this.autocompleteDebounceTimer);
822
+ this.autocompleteDebounceTimer = null;
823
+ }
824
+ this.autocompleteDebounceTimer = setTimeout(() => {
825
+ this.autocompleteDebounceTimer = null;
826
+ this.tryTriggerAutocomplete();
827
+ this.tui.requestRender();
828
+ }, Editor.AUTOCOMPLETE_DEBOUNCE_MS);
829
+ }
809
830
  handlePaste(pastedText) {
810
831
  this.historyIndex = -1; // Exit history browsing mode
811
832
  this.lastAction = null;
@@ -936,9 +957,9 @@ export class Editor {
936
957
  if (this.isInSlashCommandContext(textBeforeCursor)) {
937
958
  this.tryTriggerAutocomplete();
938
959
  }
939
- // @ file reference context
960
+ // @ file reference context (debounced to avoid blocking event loop)
940
961
  else if (textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
941
- this.tryTriggerAutocomplete();
962
+ this.debouncedTriggerAutocomplete();
942
963
  }
943
964
  }
944
965
  }
@@ -1176,9 +1197,9 @@ export class Editor {
1176
1197
  if (this.isInSlashCommandContext(textBeforeCursor)) {
1177
1198
  this.tryTriggerAutocomplete();
1178
1199
  }
1179
- // @ file reference context
1200
+ // @ file reference context (debounced to avoid blocking event loop)
1180
1201
  else if (textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
1181
- this.tryTriggerAutocomplete();
1202
+ this.debouncedTriggerAutocomplete();
1182
1203
  }
1183
1204
  }
1184
1205
  }
@@ -1670,6 +1691,14 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
1670
1691
  this.autocompleteState = null;
1671
1692
  this.autocompleteList = undefined;
1672
1693
  this.autocompletePrefix = "";
1694
+ this.clearAutocompleteDebounce();
1695
+ }
1696
+ clearAutocompleteDebounce() {
1697
+ if (this.autocompleteDebounceTimer) {
1698
+ clearTimeout(this.autocompleteDebounceTimer);
1699
+ this.autocompleteDebounceTimer = null;
1700
+ }
1701
+ this.lastAutocompleteLookupPrefix = null;
1673
1702
  }
1674
1703
  isShowingAutocomplete() {
1675
1704
  return this.autocompleteState !== null;
@@ -1681,6 +1710,35 @@ https://github.com/EsotericSoftware/spine-runtimes/actions/runs/19536643416/job/
1681
1710
  this.forceFileAutocomplete();
1682
1711
  return;
1683
1712
  }
1713
+ // Check if we're in an @ file reference context — these trigger expensive
1714
+ // synchronous fuzzyFind calls that block the event loop. Debounce them so
1715
+ // rapid typing doesn't cascade into dozens of blocking searches.
1716
+ const currentLine = this.state.lines[this.state.cursorLine] || "";
1717
+ const textBeforeCursor = currentLine.slice(0, this.state.cursorCol);
1718
+ if (this.autocompletePrefix.startsWith("@") || textBeforeCursor.match(/(?:^|[\s])@[^\s]*$/)) {
1719
+ this.debouncedUpdateAutocompleteSuggestions();
1720
+ return;
1721
+ }
1722
+ this.applyAutocompleteSuggestions();
1723
+ }
1724
+ debouncedUpdateAutocompleteSuggestions() {
1725
+ // Clear any pending debounce
1726
+ if (this.autocompleteDebounceTimer) {
1727
+ clearTimeout(this.autocompleteDebounceTimer);
1728
+ this.autocompleteDebounceTimer = null;
1729
+ }
1730
+ this.autocompleteDebounceTimer = setTimeout(() => {
1731
+ this.autocompleteDebounceTimer = null;
1732
+ // Guard: autocomplete may have been cancelled during debounce wait
1733
+ if (!this.autocompleteState || !this.autocompleteProvider)
1734
+ return;
1735
+ this.applyAutocompleteSuggestions();
1736
+ this.tui.requestRender();
1737
+ }, Editor.AUTOCOMPLETE_DEBOUNCE_MS);
1738
+ }
1739
+ applyAutocompleteSuggestions() {
1740
+ if (!this.autocompleteProvider)
1741
+ return;
1684
1742
  const suggestions = this.autocompleteProvider.getSuggestions(this.state.lines, this.state.cursorLine, this.state.cursorCol);
1685
1743
  if (suggestions && suggestions.items.length > 0) {
1686
1744
  this.autocompletePrefix = suggestions.prefix;