mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 19:05:11 +00:00
Add --mode flag for CLI output control (text/json/rpc)
- text mode: only outputs final assistant message text (default) - json mode: streams all events as JSON (same as session manager writes) - rpc mode: JSON output + listens for JSON input on stdin for headless operation - Suppress informational messages in json/rpc modes
This commit is contained in:
parent
c75f53f6f2
commit
68092ccf01
8 changed files with 800 additions and 286 deletions
|
|
@ -1,268 +1,199 @@
|
|||
# @mariozechner/pi-coding-agent
|
||||
# @mariozechner/coding-agent
|
||||
|
||||
AI coding assistant with file system access, code execution, and precise editing tools. Built on pi-ai for tool-enabled LLM workflows.
|
||||
Interactive CLI coding assistant powered by multiple LLM providers. Chat with AI models that can read files, execute commands, and make precise edits to your codebase.
|
||||
|
||||
**Note**: Designed for local development environments. Use with caution—tools can modify your filesystem.
|
||||
**Note**: This tool can modify your filesystem. Use with caution in production environments.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @mariozechner/pi-coding-agent
|
||||
npm install -g @mariozechner/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
|
||||
# Set your API key (see API Keys section)
|
||||
export ANTHROPIC_API_KEY=sk-ant-...
|
||||
|
||||
# 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"
|
||||
# Start the interactive CLI
|
||||
pi
|
||||
|
||||
# Or use the full command name
|
||||
coding-agent
|
||||
```
|
||||
|
||||
Once in the CLI, you can chat with the AI:
|
||||
|
||||
```
|
||||
You: Create a simple Express server in src/server.ts
|
||||
```
|
||||
|
||||
The agent will use its tools to read, write, and edit files as needed.
|
||||
|
||||
## API Keys
|
||||
|
||||
Uses pi-ai's key management:
|
||||
The CLI supports multiple LLM providers. Set the appropriate environment variable for your chosen provider:
|
||||
|
||||
```bash
|
||||
OPENAI_API_KEY=sk-...
|
||||
ANTHROPIC_API_KEY=sk-ant-...
|
||||
# etc.
|
||||
# Anthropic (Claude)
|
||||
export ANTHROPIC_API_KEY=sk-ant-...
|
||||
# Or use OAuth token (retrieved via: claude setup-token)
|
||||
export ANTHROPIC_OAUTH_TOKEN=...
|
||||
|
||||
# OpenAI (GPT)
|
||||
export OPENAI_API_KEY=sk-...
|
||||
|
||||
# Google (Gemini)
|
||||
export GEMINI_API_KEY=...
|
||||
|
||||
# Groq
|
||||
export GROQ_API_KEY=gsk_...
|
||||
|
||||
# Cerebras
|
||||
export CEREBRAS_API_KEY=csk-...
|
||||
|
||||
# xAI (Grok)
|
||||
export XAI_API_KEY=xai-...
|
||||
|
||||
# OpenRouter
|
||||
export OPENROUTER_API_KEY=sk-or-...
|
||||
|
||||
# ZAI
|
||||
export ZAI_API_KEY=...
|
||||
```
|
||||
|
||||
If no API key is set, the CLI will prompt you to configure one on first run.
|
||||
|
||||
## Slash Commands
|
||||
|
||||
The CLI supports several commands to control its behavior:
|
||||
|
||||
### /model
|
||||
|
||||
Switch models mid-session. Opens an interactive selector where you can type to search (by provider or model name), use arrow keys to navigate, Enter to select, or Escape to cancel.
|
||||
|
||||
### /thinking
|
||||
|
||||
Adjust thinking/reasoning level for supported models (Claude Sonnet 4, GPT-5, Gemini 2.5). Opens an interactive selector where you can use arrow keys to navigate, Enter to select, or Escape to cancel.
|
||||
|
||||
### /export [filename]
|
||||
|
||||
Export the current session to a self-contained HTML file:
|
||||
|
||||
```
|
||||
/export # Auto-generates filename
|
||||
/export my-session.html # Custom filename
|
||||
```
|
||||
|
||||
The HTML file includes the full conversation with syntax highlighting and is viewable in any browser.
|
||||
|
||||
## Image Support
|
||||
|
||||
Send images to vision-capable models by providing file paths:
|
||||
|
||||
```
|
||||
You: What is in this screenshot? /path/to/image.png
|
||||
```
|
||||
|
||||
Supported formats: `.jpg`, `.jpeg`, `.png`, `.gif`, `.webp`, `.bmp`, `.svg`
|
||||
|
||||
The image will be automatically encoded and sent with your message. Vision-capable models include:
|
||||
- GPT-4o, GPT-4o-mini (OpenAI)
|
||||
- Claude 3.5 Sonnet, Claude 3.5 Haiku (Anthropic)
|
||||
- Gemini 2.5 Flash, Gemini 2.5 Pro (Google)
|
||||
|
||||
## Available Tools
|
||||
|
||||
The agent has access to four core tools for working with your codebase:
|
||||
|
||||
### read
|
||||
|
||||
Read file contents. Supports text files and images (jpg, png, gif, webp, bmp, svg). Images are sent as attachments. For text files, defaults to first 2000 lines. Use offset/limit parameters for large files. Lines longer than 2000 characters are truncated.
|
||||
|
||||
### write
|
||||
|
||||
Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.
|
||||
|
||||
### edit
|
||||
|
||||
Edit a file by replacing exact text. The oldText must match exactly (including whitespace). Use this for precise, surgical edits. Returns an error if the text appears multiple times or isn't found.
|
||||
|
||||
### bash
|
||||
|
||||
Execute a bash command in the current working directory. Returns stdout and stderr. Commands run with a 30 second timeout.
|
||||
|
||||
## Session Management
|
||||
|
||||
Sessions are automatically saved in `~/.pi/agent/sessions/` organized by working directory. Each session is stored as a JSONL file with a unique timestamp-based ID.
|
||||
|
||||
To continue the most recent session:
|
||||
|
||||
```bash
|
||||
pi --continue
|
||||
# or
|
||||
pi -c
|
||||
```
|
||||
|
||||
To browse and select from past sessions:
|
||||
|
||||
```bash
|
||||
pi --resume
|
||||
# or
|
||||
pi -r
|
||||
```
|
||||
|
||||
This opens an interactive session selector where you can:
|
||||
- Type to search through session messages
|
||||
- Use arrow keys to navigate the list
|
||||
- Press Enter to resume a session
|
||||
- Press Escape to cancel
|
||||
|
||||
Sessions include all conversation messages, tool calls and results, model switches, and thinking level changes.
|
||||
|
||||
## CLI Options
|
||||
|
||||
```bash
|
||||
pi [options] [messages...]
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
**--provider <name>**
|
||||
Provider name. Available: `anthropic`, `openai`, `google`, `xai`, `groq`, `cerebras`, `openrouter`, `zai`. Default: `anthropic`
|
||||
|
||||
**--model <id>**
|
||||
Model ID. Default: `claude-sonnet-4-5`
|
||||
|
||||
**--api-key <key>**
|
||||
API key (overrides environment variables)
|
||||
|
||||
**--system-prompt <text>**
|
||||
Custom system prompt (overrides default coding assistant prompt)
|
||||
|
||||
**--continue, -c**
|
||||
Continue the most recent session
|
||||
|
||||
**--resume, -r**
|
||||
Select a session to resume (opens interactive selector)
|
||||
|
||||
**--help, -h**
|
||||
Show help message
|
||||
|
||||
### Examples
|
||||
|
||||
```bash
|
||||
# Start interactive mode
|
||||
pi
|
||||
|
||||
# Single message mode
|
||||
pi "List all .ts files in src/"
|
||||
|
||||
# Continue previous session
|
||||
pi -c "What did we discuss?"
|
||||
|
||||
# Use different model
|
||||
pi --provider openai --model gpt-4o "Help me refactor this code"
|
||||
```
|
||||
|
||||
## License
|
||||
|
|
@ -271,4 +202,5 @@ MIT
|
|||
|
||||
## See Also
|
||||
|
||||
- [@mariozechner/pi-ai](https://www.npmjs.com/package/@mariozechner/pi-ai): Core LLM toolkit
|
||||
- [@mariozechner/pi-ai](https://www.npmjs.com/package/@mariozechner/pi-ai): Core LLM toolkit with multi-provider support
|
||||
- [@mariozechner/pi-agent](https://www.npmjs.com/package/@mariozechner/pi-agent): Agent framework with tool execution
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue