mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-19 10:03:19 +00:00
feat(coding-agent): ResourceLoader, package management, and /reload command (#645)
- Add ResourceLoader interface and DefaultResourceLoader implementation - Add PackageManager for npm/git extension sources with install/remove/update - Add session.reload() and session.bindExtensions() APIs - Add /reload command in interactive mode - Add CLI flags: --skill, --theme, --prompt-template, --no-themes, --no-prompt-templates - Add pi install/remove/update commands for extension management - Refactor settings.json to use arrays for skills, prompts, themes - Remove legacy SkillsSettings source flags and filters - Update SDK examples and documentation for ResourceLoader pattern - Add theme registration and loadThemeFromPath for dynamic themes - Add getShellEnv to include bin dir in PATH for bash commands
This commit is contained in:
parent
866d21c252
commit
b846a4bfcf
51 changed files with 2724 additions and 1852 deletions
|
|
@ -5,11 +5,11 @@
|
|||
*/
|
||||
|
||||
import { getModel } from "@mariozechner/pi-ai";
|
||||
import { createAgentSession, discoverAuthStorage, discoverModels } from "@mariozechner/pi-coding-agent";
|
||||
import { AuthStorage, createAgentSession, ModelRegistry } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Set up auth storage and model registry
|
||||
const authStorage = discoverAuthStorage();
|
||||
const modelRegistry = discoverModels(authStorage);
|
||||
const authStorage = new AuthStorage();
|
||||
const modelRegistry = new ModelRegistry(authStorage);
|
||||
|
||||
// Option 1: Find a specific built-in model by provider/id
|
||||
const opus = getModel("anthropic", "claude-opus-4-5");
|
||||
|
|
|
|||
|
|
@ -4,12 +4,18 @@
|
|||
* Shows how to replace or modify the default system prompt.
|
||||
*/
|
||||
|
||||
import { createAgentSession, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
import { createAgentSession, DefaultResourceLoader, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Option 1: Replace prompt entirely
|
||||
const { session: session1 } = await createAgentSession({
|
||||
systemPrompt: `You are a helpful assistant that speaks like a pirate.
|
||||
const loader1 = new DefaultResourceLoader({
|
||||
systemPromptOverride: () => `You are a helpful assistant that speaks like a pirate.
|
||||
Always end responses with "Arrr!"`,
|
||||
appendSystemPromptOverride: () => [],
|
||||
});
|
||||
await loader1.reload();
|
||||
|
||||
const { session: session1 } = await createAgentSession({
|
||||
resourceLoader: loader1,
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
});
|
||||
|
||||
|
|
@ -23,13 +29,17 @@ console.log("=== Replace prompt ===");
|
|||
await session1.prompt("What is 2 + 2?");
|
||||
console.log("\n");
|
||||
|
||||
// Option 2: Modify default prompt (receives default, returns modified)
|
||||
const { session: session2 } = await createAgentSession({
|
||||
systemPrompt: (defaultPrompt) => `${defaultPrompt}
|
||||
// Option 2: Append instructions to the default prompt
|
||||
const loader2 = new DefaultResourceLoader({
|
||||
appendSystemPromptOverride: (base) => [
|
||||
...base,
|
||||
"## Additional Instructions\n- Always be concise\n- Use bullet points when listing things",
|
||||
],
|
||||
});
|
||||
await loader2.reload();
|
||||
|
||||
## Additional Instructions
|
||||
- Always be concise
|
||||
- Use bullet points when listing things`,
|
||||
const { session: session2 } = await createAgentSession({
|
||||
resourceLoader: loader2,
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -5,20 +5,7 @@
|
|||
* Discover, filter, merge, or replace them.
|
||||
*/
|
||||
|
||||
import { createAgentSession, discoverSkills, SessionManager, type Skill } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Discover all skills from cwd/.pi/skills, ~/.pi/agent/skills, etc.
|
||||
const { skills: allSkills, warnings } = discoverSkills();
|
||||
console.log(
|
||||
"Discovered skills:",
|
||||
allSkills.map((s) => s.name),
|
||||
);
|
||||
if (warnings.length > 0) {
|
||||
console.log("Warnings:", warnings);
|
||||
}
|
||||
|
||||
// Filter to specific skills
|
||||
const filteredSkills = allSkills.filter((s) => s.name.includes("browser") || s.name.includes("search"));
|
||||
import { createAgentSession, DefaultResourceLoader, SessionManager, type Skill } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Or define custom skills inline
|
||||
const customSkill: Skill = {
|
||||
|
|
@ -29,19 +16,30 @@ const customSkill: Skill = {
|
|||
source: "custom",
|
||||
};
|
||||
|
||||
// Use filtered + custom skills
|
||||
const loader = new DefaultResourceLoader({
|
||||
skillsOverride: (current) => {
|
||||
const filteredSkills = current.skills.filter((s) => s.name.includes("browser") || s.name.includes("search"));
|
||||
return {
|
||||
skills: [...filteredSkills, customSkill],
|
||||
diagnostics: current.diagnostics,
|
||||
};
|
||||
},
|
||||
});
|
||||
await loader.reload();
|
||||
|
||||
// Discover all skills from cwd/.pi/skills, ~/.pi/agent/skills, etc.
|
||||
const discovered = loader.getSkills();
|
||||
console.log(
|
||||
"Discovered skills:",
|
||||
discovered.skills.map((s) => s.name),
|
||||
);
|
||||
if (discovered.diagnostics.length > 0) {
|
||||
console.log("Warnings:", discovered.diagnostics);
|
||||
}
|
||||
|
||||
await createAgentSession({
|
||||
skills: [...filteredSkills, customSkill],
|
||||
resourceLoader: loader,
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
});
|
||||
|
||||
console.log(`Session created with ${filteredSkills.length + 1} skills`);
|
||||
|
||||
// To disable all skills:
|
||||
// skills: []
|
||||
|
||||
// To use discovery with filtering via settings:
|
||||
// discoverSkills(process.cwd(), undefined, {
|
||||
// ignoredSkills: ["browser-tools"], // glob patterns to exclude
|
||||
// includeSkills: ["brave-*"], // glob patterns to include (empty = all)
|
||||
// })
|
||||
console.log("Session created with filtered skills");
|
||||
|
|
|
|||
|
|
@ -13,16 +13,25 @@
|
|||
* export default function (pi: ExtensionAPI) { ... }
|
||||
*/
|
||||
|
||||
import { createAgentSession, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
import { createAgentSession, DefaultResourceLoader, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Extensions are discovered automatically from standard locations.
|
||||
// You can also add paths via:
|
||||
// 1. settings.json: { "extensions": ["./my-extension.ts"] }
|
||||
// 2. additionalExtensionPaths option (see below)
|
||||
// You can also add paths via settings.json or DefaultResourceLoader options.
|
||||
|
||||
// To add additional extension paths beyond discovery:
|
||||
const { session } = await createAgentSession({
|
||||
const resourceLoader = new DefaultResourceLoader({
|
||||
additionalExtensionPaths: ["./my-logging-extension.ts", "./my-safety-extension.ts"],
|
||||
extensionFactories: [
|
||||
(pi) => {
|
||||
pi.on("agent_start", () => {
|
||||
console.log("[Inline Extension] Agent starting");
|
||||
});
|
||||
},
|
||||
],
|
||||
});
|
||||
await resourceLoader.reload();
|
||||
|
||||
const { session } = await createAgentSession({
|
||||
resourceLoader,
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,33 +4,36 @@
|
|||
* Context files provide project-specific instructions loaded into the system prompt.
|
||||
*/
|
||||
|
||||
import { createAgentSession, discoverContextFiles, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
import { createAgentSession, DefaultResourceLoader, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Discover AGENTS.md files walking up from cwd
|
||||
const discovered = discoverContextFiles();
|
||||
console.log("Discovered context files:");
|
||||
for (const file of discovered) {
|
||||
console.log(` - ${file.path} (${file.content.length} chars)`);
|
||||
}
|
||||
|
||||
// Use custom context files
|
||||
await createAgentSession({
|
||||
contextFiles: [
|
||||
...discovered,
|
||||
{
|
||||
path: "/virtual/AGENTS.md",
|
||||
content: `# Project Guidelines
|
||||
const loader = new DefaultResourceLoader({
|
||||
agentsFilesOverride: (current) => ({
|
||||
agentsFiles: [
|
||||
...current.agentsFiles,
|
||||
{
|
||||
path: "/virtual/AGENTS.md",
|
||||
content: `# Project Guidelines
|
||||
|
||||
## Code Style
|
||||
- Use TypeScript strict mode
|
||||
- No any types
|
||||
- Prefer const over let`,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
await loader.reload();
|
||||
|
||||
// Discover AGENTS.md files walking up from cwd
|
||||
const discovered = loader.getAgentsFiles().agentsFiles;
|
||||
console.log("Discovered context files:");
|
||||
for (const file of discovered) {
|
||||
console.log(` - ${file.path} (${file.content.length} chars)`);
|
||||
}
|
||||
|
||||
await createAgentSession({
|
||||
resourceLoader: loader,
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
});
|
||||
|
||||
console.log(`Session created with ${discovered.length + 1} context files`);
|
||||
|
||||
// Disable context files:
|
||||
// contextFiles: []
|
||||
|
|
|
|||
|
|
@ -6,18 +6,11 @@
|
|||
|
||||
import {
|
||||
createAgentSession,
|
||||
discoverPromptTemplates,
|
||||
DefaultResourceLoader,
|
||||
type PromptTemplate,
|
||||
SessionManager,
|
||||
} from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Discover templates from cwd/.pi/prompts/ and ~/.pi/agent/prompts/
|
||||
const discovered = discoverPromptTemplates();
|
||||
console.log("Discovered prompt templates:");
|
||||
for (const template of discovered) {
|
||||
console.log(` /${template.name}: ${template.description}`);
|
||||
}
|
||||
|
||||
// Define custom templates
|
||||
const deployTemplate: PromptTemplate = {
|
||||
name: "deploy",
|
||||
|
|
@ -30,13 +23,24 @@ const deployTemplate: PromptTemplate = {
|
|||
3. Deploy: npm run deploy`,
|
||||
};
|
||||
|
||||
// Use discovered + custom templates
|
||||
const loader = new DefaultResourceLoader({
|
||||
promptsOverride: (current) => ({
|
||||
prompts: [...current.prompts, deployTemplate],
|
||||
diagnostics: current.diagnostics,
|
||||
}),
|
||||
});
|
||||
await loader.reload();
|
||||
|
||||
// Discover templates from cwd/.pi/prompts/ and ~/.pi/agent/prompts/
|
||||
const discovered = loader.getPrompts().prompts;
|
||||
console.log("Discovered prompt templates:");
|
||||
for (const template of discovered) {
|
||||
console.log(` /${template.name}: ${template.description}`);
|
||||
}
|
||||
|
||||
await createAgentSession({
|
||||
promptTemplates: [...discovered, deployTemplate],
|
||||
resourceLoader: loader,
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
});
|
||||
|
||||
console.log(`Session created with ${discovered.length + 1} prompt templates`);
|
||||
|
||||
// Disable prompt templates:
|
||||
// promptTemplates: []
|
||||
|
|
|
|||
|
|
@ -4,19 +4,12 @@
|
|||
* Configure API key resolution via AuthStorage and ModelRegistry.
|
||||
*/
|
||||
|
||||
import {
|
||||
AuthStorage,
|
||||
createAgentSession,
|
||||
discoverAuthStorage,
|
||||
discoverModels,
|
||||
ModelRegistry,
|
||||
SessionManager,
|
||||
} from "@mariozechner/pi-coding-agent";
|
||||
import { AuthStorage, createAgentSession, ModelRegistry, SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Default: discoverAuthStorage() uses ~/.pi/agent/auth.json
|
||||
// discoverModels() loads built-in + custom models from ~/.pi/agent/models.json
|
||||
const authStorage = discoverAuthStorage();
|
||||
const modelRegistry = discoverModels(authStorage);
|
||||
// Default: AuthStorage uses ~/.pi/agent/auth.json
|
||||
// ModelRegistry loads built-in + custom models from ~/.pi/agent/models.json
|
||||
const authStorage = new AuthStorage();
|
||||
const modelRegistry = new ModelRegistry(authStorage);
|
||||
|
||||
await createAgentSession({
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
|
|
|
|||
|
|
@ -4,11 +4,11 @@
|
|||
* Override settings using SettingsManager.
|
||||
*/
|
||||
|
||||
import { createAgentSession, loadSettings, SessionManager, SettingsManager } from "@mariozechner/pi-coding-agent";
|
||||
import { createAgentSession, SessionManager, SettingsManager } from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Load current settings (merged global + project)
|
||||
const settings = loadSettings();
|
||||
console.log("Current settings:", JSON.stringify(settings, null, 2));
|
||||
const settingsManagerFromDisk = SettingsManager.create();
|
||||
console.log("Current settings:", JSON.stringify(settingsManagerFromDisk.getGlobalSettings(), null, 2));
|
||||
|
||||
// Override specific settings
|
||||
const settingsManager = SettingsManager.create();
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ import {
|
|||
AuthStorage,
|
||||
createAgentSession,
|
||||
createBashTool,
|
||||
createExtensionRuntime,
|
||||
createReadTool,
|
||||
ModelRegistry,
|
||||
type ResourceLoader,
|
||||
SessionManager,
|
||||
SettingsManager,
|
||||
} from "@mariozechner/pi-coding-agent";
|
||||
|
|
@ -42,6 +44,18 @@ const settingsManager = SettingsManager.inMemory({
|
|||
// When using a custom cwd with explicit tools, use the factory functions
|
||||
const cwd = process.cwd();
|
||||
|
||||
const resourceLoader: ResourceLoader = {
|
||||
getExtensions: () => ({ extensions: [], errors: [], runtime: createExtensionRuntime() }),
|
||||
getSkills: () => ({ skills: [], diagnostics: [] }),
|
||||
getPrompts: () => ({ prompts: [], diagnostics: [] }),
|
||||
getThemes: () => ({ themes: [], diagnostics: [] }),
|
||||
getAgentsFiles: () => ({ agentsFiles: [] }),
|
||||
getSystemPrompt: () => `You are a minimal assistant.
|
||||
Available: read, bash. Be concise.`,
|
||||
getAppendSystemPrompt: () => [],
|
||||
reload: async () => {},
|
||||
};
|
||||
|
||||
const { session } = await createAgentSession({
|
||||
cwd,
|
||||
agentDir: "/tmp/my-agent",
|
||||
|
|
@ -49,15 +63,9 @@ const { session } = await createAgentSession({
|
|||
thinkingLevel: "off",
|
||||
authStorage,
|
||||
modelRegistry,
|
||||
systemPrompt: `You are a minimal assistant.
|
||||
Available: read, bash. Be concise.`,
|
||||
resourceLoader,
|
||||
// Use factory functions with the same cwd to ensure path resolution works correctly
|
||||
tools: [createReadTool(cwd), createBashTool(cwd)],
|
||||
// Pass empty array to disable extension discovery, or provide inline factories
|
||||
extensions: [],
|
||||
skills: [],
|
||||
contextFiles: [],
|
||||
promptTemplates: [],
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
settingsManager,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,24 +33,18 @@ import { getModel } from "@mariozechner/pi-ai";
|
|||
import {
|
||||
AuthStorage,
|
||||
createAgentSession,
|
||||
discoverAuthStorage,
|
||||
discoverModels,
|
||||
discoverSkills,
|
||||
discoverExtensions,
|
||||
discoverContextFiles,
|
||||
discoverPromptTemplates,
|
||||
loadSettings,
|
||||
buildSystemPrompt,
|
||||
DefaultResourceLoader,
|
||||
ModelRegistry,
|
||||
SessionManager,
|
||||
SettingsManager,
|
||||
codingTools,
|
||||
readOnlyTools,
|
||||
readTool, bashTool, editTool, writeTool,
|
||||
} from "@mariozechner/pi-coding-agent";
|
||||
|
||||
// Auth and models setup
|
||||
const authStorage = discoverAuthStorage();
|
||||
const modelRegistry = discoverModels(authStorage);
|
||||
const authStorage = new AuthStorage();
|
||||
const modelRegistry = new ModelRegistry(authStorage);
|
||||
|
||||
// Minimal
|
||||
const { session } = await createAgentSession({ authStorage, modelRegistry });
|
||||
|
|
@ -60,11 +54,11 @@ const model = getModel("anthropic", "claude-opus-4-5");
|
|||
const { session } = await createAgentSession({ model, thinkingLevel: "high", authStorage, modelRegistry });
|
||||
|
||||
// Modify prompt
|
||||
const { session } = await createAgentSession({
|
||||
systemPrompt: (defaultPrompt) => defaultPrompt + "\n\nBe concise.",
|
||||
authStorage,
|
||||
modelRegistry,
|
||||
const loader = new DefaultResourceLoader({
|
||||
systemPromptOverride: (base) => `${base}\n\nBe concise.`,
|
||||
});
|
||||
await loader.reload();
|
||||
const { session } = await createAgentSession({ resourceLoader: loader, authStorage, modelRegistry });
|
||||
|
||||
// Read-only
|
||||
const { session } = await createAgentSession({ tools: readOnlyTools, authStorage, modelRegistry });
|
||||
|
|
@ -81,18 +75,24 @@ const customAuth = new AuthStorage("/my/app/auth.json");
|
|||
customAuth.setRuntimeApiKey("anthropic", process.env.MY_KEY!);
|
||||
const customRegistry = new ModelRegistry(customAuth);
|
||||
|
||||
const resourceLoader = new DefaultResourceLoader({
|
||||
systemPromptOverride: () => "You are helpful.",
|
||||
extensionFactories: [myExtension],
|
||||
skillsOverride: () => ({ skills: [], diagnostics: [] }),
|
||||
agentsFilesOverride: () => ({ agentsFiles: [] }),
|
||||
promptsOverride: () => ({ prompts: [], diagnostics: [] }),
|
||||
});
|
||||
await resourceLoader.reload();
|
||||
|
||||
const { session } = await createAgentSession({
|
||||
model,
|
||||
authStorage: customAuth,
|
||||
modelRegistry: customRegistry,
|
||||
systemPrompt: "You are helpful.",
|
||||
resourceLoader,
|
||||
tools: [readTool, bashTool],
|
||||
customTools: [{ tool: myTool }],
|
||||
extensions: [{ factory: myExtension }],
|
||||
skills: [],
|
||||
contextFiles: [],
|
||||
promptTemplates: [],
|
||||
sessionManager: SessionManager.inMemory(),
|
||||
settingsManager: SettingsManager.inMemory(),
|
||||
});
|
||||
|
||||
// Run prompts
|
||||
|
|
@ -108,23 +108,17 @@ await session.prompt("Hello");
|
|||
|
||||
| Option | Default | Description |
|
||||
|--------|---------|-------------|
|
||||
| `authStorage` | `discoverAuthStorage()` | Credential storage |
|
||||
| `modelRegistry` | `discoverModels(authStorage)` | Model registry |
|
||||
| `authStorage` | `new AuthStorage()` | Credential storage |
|
||||
| `modelRegistry` | `new ModelRegistry(authStorage)` | Model registry |
|
||||
| `cwd` | `process.cwd()` | Working directory |
|
||||
| `agentDir` | `~/.pi/agent` | Config directory |
|
||||
| `model` | From settings/first available | Model to use |
|
||||
| `thinkingLevel` | From settings/"off" | off, low, medium, high |
|
||||
| `systemPrompt` | Discovered | String or `(default) => modified` |
|
||||
| `tools` | `codingTools` | Built-in tools |
|
||||
| `customTools` | Discovered | Replaces discovery |
|
||||
| `additionalCustomToolPaths` | `[]` | Merge with discovery |
|
||||
| `extensions` | Discovered | Replaces discovery |
|
||||
| `additionalExtensionPaths` | `[]` | Merge with discovery |
|
||||
| `skills` | Discovered | Skills for prompt |
|
||||
| `contextFiles` | Discovered | AGENTS.md files |
|
||||
| `promptTemplates` | Discovered | Prompt templates (slash commands) |
|
||||
| `customTools` | `[]` | Additional tool definitions |
|
||||
| `resourceLoader` | DefaultResourceLoader | Resource loader for extensions, skills, prompts, themes |
|
||||
| `sessionManager` | `SessionManager.create(cwd)` | Persistence |
|
||||
| `settingsManager` | From agentDir | Settings overrides |
|
||||
| `settingsManager` | `SettingsManager.create(cwd, agentDir)` | Settings overrides |
|
||||
|
||||
## Events
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue