mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-21 15:01:26 +00:00
Add 'pi' command alias and fix getApiKey import
This commit is contained in:
parent
00d8286523
commit
bf1a7d8571
4 changed files with 284 additions and 8 deletions
|
|
@ -1966,8 +1966,8 @@ export const MODELS = {
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0.255,
|
input: 0.21,
|
||||||
output: 1.02,
|
output: 0.84,
|
||||||
cacheRead: 0,
|
cacheRead: 0,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
|
|
@ -2238,13 +2238,13 @@ export const MODELS = {
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0.44999999999999996,
|
input: 0.6,
|
||||||
output: 1.9,
|
output: 2.2,
|
||||||
cacheRead: 0,
|
cacheRead: 0,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 202752,
|
contextWindow: 204800,
|
||||||
maxTokens: 4096,
|
maxTokens: 131072,
|
||||||
} satisfies Model<"openai-completions">,
|
} satisfies Model<"openai-completions">,
|
||||||
"anthropic/claude-sonnet-4.5": {
|
"anthropic/claude-sonnet-4.5": {
|
||||||
id: "anthropic/claude-sonnet-4.5",
|
id: "anthropic/claude-sonnet-4.5",
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import type {
|
||||||
MessageParam,
|
MessageParam,
|
||||||
} from "@anthropic-ai/sdk/resources/messages.js";
|
} from "@anthropic-ai/sdk/resources/messages.js";
|
||||||
import { calculateCost } from "../models.js";
|
import { calculateCost } from "../models.js";
|
||||||
|
import { getApiKey } from "../stream.js";
|
||||||
import type {
|
import type {
|
||||||
Api,
|
Api,
|
||||||
AssistantMessage,
|
AssistantMessage,
|
||||||
|
|
@ -111,8 +112,8 @@ export const streamAnthropic: StreamFunction<"anthropic-messages"> = (
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const apiKey = options?.apiKey ?? getApiKey(model.provider);
|
const apiKey = options?.apiKey ?? getApiKey(model.provider) ?? "";
|
||||||
const { client, isOAuthToken } = createClient(model, apiKey);
|
const { client, isOAuthToken } = createClient(model, apiKey);
|
||||||
const params = buildParams(model, context, isOAuthToken, options);
|
const params = buildParams(model, context, isOAuthToken, options);
|
||||||
const anthropicStream = client.messages.stream({ ...params, stream: true }, { signal: options?.signal });
|
const anthropicStream = client.messages.stream({ ...params, stream: true }, { signal: options?.signal });
|
||||||
stream.push({ type: "start", partial: output });
|
stream.push({ type: "start", partial: output });
|
||||||
|
|
|
||||||
274
packages/coding-agent/README.md
Normal file
274
packages/coding-agent/README.md
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
# @mariozechner/pi-coding-agent
|
||||||
|
|
||||||
|
AI coding assistant with file system access, code execution, and precise editing tools. Built on pi-ai for tool-enabled LLM workflows.
|
||||||
|
|
||||||
|
**Note**: Designed for local development environments. Use with caution—tools can modify your filesystem.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install @mariozechner/pi-coding-agent
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { getModel, CodingAgent, read, bash, edit, write } from '@mariozechner/pi-coding-agent';
|
||||||
|
|
||||||
|
// Define tools for the agent
|
||||||
|
const tools = [
|
||||||
|
read({ description: 'Read file contents (text or images)' }),
|
||||||
|
bash({ description: 'Execute bash commands (ls, grep, etc.)' }),
|
||||||
|
edit({ description: 'Edit files by replacing exact text matches' }),
|
||||||
|
write({ description: 'Write or overwrite files, creates directories' })
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create coding agent with model
|
||||||
|
const agent = new CodingAgent({
|
||||||
|
model: getModel('openai', 'gpt-4o-mini'),
|
||||||
|
tools,
|
||||||
|
systemPrompt: 'You are an expert coding assistant. Use tools to read/edit files, run commands. Be precise and safe.'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Run agent with a task
|
||||||
|
const task = { role: 'user', content: 'Create a simple Express server in src/server.ts' };
|
||||||
|
|
||||||
|
const stream = agent.run(task);
|
||||||
|
|
||||||
|
for await (const event of stream) {
|
||||||
|
switch (event.type) {
|
||||||
|
case 'agent_start':
|
||||||
|
console.log('Agent started');
|
||||||
|
break;
|
||||||
|
case 'message_update':
|
||||||
|
if (event.message.role === 'assistant') {
|
||||||
|
console.log('Agent:', event.message.content.map(c => c.type === 'text' ? c.text : '[Tool Call]').join(''));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'tool_execution_start':
|
||||||
|
console.log(`Executing: ${event.toolName}(${JSON.stringify(event.args)})`);
|
||||||
|
break;
|
||||||
|
case 'tool_execution_end':
|
||||||
|
if (event.isError) {
|
||||||
|
console.error('Tool error:', event.result);
|
||||||
|
} else {
|
||||||
|
console.log('Tool result:', event.result.output);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'agent_end':
|
||||||
|
console.log('Task complete');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get final messages
|
||||||
|
const messages = await stream.result();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
The agent uses specialized tools for coding tasks. All tools are type-safe with TypeBox schemas and validated at runtime.
|
||||||
|
|
||||||
|
### File Reading
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { read } from '@mariozechner/pi-coding-agent';
|
||||||
|
|
||||||
|
const readTool = read({
|
||||||
|
description: 'Read file contents',
|
||||||
|
parameters: Type.Object({
|
||||||
|
path: Type.String({ description: 'File path (relative or absolute)' })
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// In agent context
|
||||||
|
const context = {
|
||||||
|
systemPrompt: 'You are a coding assistant.',
|
||||||
|
messages: [{ role: 'user', content: 'What\'s in package.json?' }],
|
||||||
|
tools: [readTool]
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bash Execution
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { bash } from '@mariozechner/pi-coding-agent';
|
||||||
|
|
||||||
|
const bashTool = bash({
|
||||||
|
description: 'Run bash commands',
|
||||||
|
parameters: Type.Object({
|
||||||
|
command: Type.String({ description: 'Bash command to execute' })
|
||||||
|
}),
|
||||||
|
timeout: 30000 // 30s default
|
||||||
|
});
|
||||||
|
|
||||||
|
// Example: List files
|
||||||
|
// Agent calls: bash({ command: 'ls -la' })
|
||||||
|
// Returns stdout/stderr
|
||||||
|
```
|
||||||
|
|
||||||
|
### Precise Editing
|
||||||
|
|
||||||
|
For surgical code changes without overwriting entire files:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { edit } from '@mariozechner/pi-coding-agent';
|
||||||
|
|
||||||
|
const editTool = edit({
|
||||||
|
description: 'Replace exact text in files',
|
||||||
|
parameters: Type.Object({
|
||||||
|
path: Type.String({ description: 'File path' }),
|
||||||
|
oldText: Type.String({ description: 'Exact text to find (including whitespace)' }),
|
||||||
|
newText: Type.String({ description: 'Replacement text' })
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Example: Update import in src/index.ts
|
||||||
|
// edit({ path: 'src/index.ts', oldText: 'import { foo }', newText: 'import { foo, bar }' })
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Writing
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { write } from '@mariozechner/pi-coding-agent';
|
||||||
|
|
||||||
|
const writeTool = write({
|
||||||
|
description: 'Write file content',
|
||||||
|
parameters: Type.Object({
|
||||||
|
path: Type.String({ description: 'File path' }),
|
||||||
|
content: Type.String({ description: 'File content' })
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
// Creates directories if needed, overwrites existing files
|
||||||
|
// write({ path: 'src/utils/helper.ts', content: 'export const helper = () => { ... };' })
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Tools
|
||||||
|
|
||||||
|
Extend with custom tools using the pi-ai AgentTool interface:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { Type, AgentTool } from '@mariozechner/pi-ai';
|
||||||
|
|
||||||
|
const gitTool: AgentTool<typeof Type.Object({ command: Type.String() })> = {
|
||||||
|
name: 'git',
|
||||||
|
description: 'Run git commands',
|
||||||
|
parameters: Type.Object({ command: Type.String() }),
|
||||||
|
execute: async (toolCallId, args) => {
|
||||||
|
const { stdout } = await exec(`git ${args.command}`);
|
||||||
|
return { output: stdout };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Agent Workflow
|
||||||
|
|
||||||
|
The coding agent runs in loops until completion:
|
||||||
|
|
||||||
|
1. **Task Input**: User provides coding task (e.g., "Implement user auth")
|
||||||
|
2. **Planning**: Agent may think/reason (if model supports)
|
||||||
|
3. **Tool Calls**: Agent reads files, runs commands, proposes edits
|
||||||
|
4. **Execution**: Tools run safely; results fed back to agent
|
||||||
|
5. **Iteration**: Agent reviews outputs, makes adjustments
|
||||||
|
6. **Completion**: Agent signals done or asks for clarification
|
||||||
|
|
||||||
|
### Streaming Events
|
||||||
|
|
||||||
|
Monitor progress with detailed events:
|
||||||
|
|
||||||
|
- `agent_start` / `agent_end`: Session boundaries
|
||||||
|
- `turn_start` / `turn_end`: LLM-tool cycles
|
||||||
|
- `message_update`: Streaming assistant responses and tool calls
|
||||||
|
- `tool_execution_start` / `tool_execution_end`: Tool runs with args/results
|
||||||
|
- `error`: Validation failures or execution errors
|
||||||
|
|
||||||
|
### Safety Features
|
||||||
|
|
||||||
|
- **Read-Only Mode**: Set `readOnly: true` to disable writes/edits
|
||||||
|
- **Path Validation**: Restrict to project directory (configurable)
|
||||||
|
- **Timeout**: 30s default for bash commands
|
||||||
|
- **Validation**: All tool args validated against schemas
|
||||||
|
- **Dry Run**: Log actions without executing (for review)
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
const agent = new CodingAgent({
|
||||||
|
model: getModel('openai', 'gpt-4o-mini'),
|
||||||
|
tools,
|
||||||
|
readOnly: process.env.NODE_ENV === 'production', // Disable writes in prod
|
||||||
|
allowedPaths: ['./src', './test'], // Restrict file access
|
||||||
|
dryRun: true // Log without executing
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example Tasks
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// Refactor code
|
||||||
|
agent.run({ role: 'user', content: 'Convert src/index.ts to use async/await instead of callbacks' });
|
||||||
|
|
||||||
|
// Debug
|
||||||
|
agent.run({ role: 'user', content: 'Fix the TypeScript error in test/utils.test.ts: "Cannot find name \'describe\'"' });
|
||||||
|
|
||||||
|
// New feature
|
||||||
|
agent.run({ role: 'user', content: 'Add a REST API endpoint to src/server.ts for /users with GET/POST' });
|
||||||
|
|
||||||
|
// Analyze
|
||||||
|
agent.run({ role: 'user', content: 'Review src/ and suggest performance improvements' });
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with pi-ai
|
||||||
|
|
||||||
|
Built on `@mariozechner/pi-ai`. Use existing Context/Agent APIs:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { CodingAgent, Context } from '@mariozechner/pi-coding-agent';
|
||||||
|
import { getModel } from '@mariozechner/pi-ai';
|
||||||
|
|
||||||
|
const context: Context = {
|
||||||
|
systemPrompt: 'Expert TypeScript developer.',
|
||||||
|
messages: [
|
||||||
|
{ role: 'user', content: 'Optimize this loop in src/data.ts' },
|
||||||
|
{ role: 'assistant', content: [{ type: 'text', text: 'First, let me read the file...' }] }
|
||||||
|
],
|
||||||
|
tools: [read({}), edit({})]
|
||||||
|
};
|
||||||
|
|
||||||
|
const agent = new CodingAgent({ model: getModel('anthropic', 'claude-3-5-sonnet-20240620'), tools: context.tools });
|
||||||
|
const continuation = await agent.continue(context); // Resume from existing context
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
Set up your working directory (current dir becomes project root):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone or navigate to your project
|
||||||
|
cd my-project
|
||||||
|
|
||||||
|
# Install and run agent
|
||||||
|
npm install @mariozechner/pi-coding-agent
|
||||||
|
node -e "
|
||||||
|
const { CodingAgent } = require('@mariozechner/pi-coding-agent');
|
||||||
|
const agent = new CodingAgent({ model: getModel('openai', 'gpt-4o-mini') });
|
||||||
|
await agent.run({ role: 'user', content: process.argv[1] }, { cwd: process.cwd() });
|
||||||
|
" "Implement fizzbuzz in src/index.ts"
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Keys
|
||||||
|
|
||||||
|
Uses pi-ai's key management:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
OPENAI_API_KEY=sk-...
|
||||||
|
ANTHROPIC_API_KEY=sk-ant-...
|
||||||
|
# etc.
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
||||||
|
## See Also
|
||||||
|
|
||||||
|
- [@mariozechner/pi-ai](https://www.npmjs.com/package/@mariozechner/pi-ai): Core LLM toolkit
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
"pi": "dist/cli.js",
|
||||||
"coding-agent": "dist/cli.js"
|
"coding-agent": "dist/cli.js"
|
||||||
},
|
},
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue