co-mono/packages/coding-agent
Mario Zechner c7a73d4f81 Add line limits and truncation to read tool
- Default limit of 2000 lines per read
- Maximum line length of 2000 characters (truncates longer lines)
- Add optional offset and limit parameters for pagination
- Show truncation notice with instruction to continue reading
- Plain text output (no line numbers)

Examples:
- `read path/to/file` - reads first 2000 lines
- `read path/to/file offset=2001` - continues from line 2001
- `read path/to/file limit=100` - reads only 100 lines

This prevents extremely large files from overwhelming context.
2025-11-12 16:53:05 +01:00
..
src Add line limits and truncation to read tool 2025-11-12 16:53:05 +01:00
test Add image support in tool results across all providers 2025-11-12 10:45:56 +01:00
package.json Add /export command to export sessions as self-contained HTML 2025-11-12 16:21:59 +01:00
README.md Add 'pi' command alias and fix getApiKey import 2025-11-12 14:31:25 +01:00
tsconfig.build.json Agent package + coding agent WIP, refactored web-ui prompts 2025-10-17 11:47:01 +02:00
vitest.config.ts Agent package + coding agent WIP, refactored web-ui prompts 2025-10-17 11:47:01 +02:00

@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

npm install @mariozechner/pi-coding-agent

Quick Start

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

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

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:

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

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:

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)
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

// 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:

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):

# 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:

OPENAI_API_KEY=sk-...
ANTHROPIC_API_KEY=sk-ant-...
# etc.

License

MIT

See Also