Skip to content
Back to skills

1498 Core Agents 4e8afd92

BSecurity

AI agent creation, execution, and delegation system

  • 9 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 11, 2026
ai-agentsgobashreactnode

Works with

  • cli

Security analysis

B75/100
  • criticalPipes output to a shell interpreter

Pro shows the line behind each finding and how to fix it

Scanned October 11, 2026

npx -y skills add tools-only/X-Skills --skill 1498-core-agents_4e8afd92 --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of 1498 Core Agents 4e8afd92?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for 1498 Core Agents 4e8afd92
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/tools-only-1498-core-agents-4e8afd92/badge)](https://www.skillsdirectory.com/skills/tools-only-1498-core-agents-4e8afd92)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

SKILL.md
---
title: Core Agent Orchestration
path: src/tunacode/core/agents
type: directory
depth: 1
description: AI agent creation, execution, and delegation system
exports: [process_request, RequestOrchestrator, AgentConfig, get_or_create_agent]
seams: [M, D]
---

# Core Agent Orchestration

## Purpose

Manages AI agent lifecycle using pydantic-ai framework, including agent creation, request processing, tool execution, and multi-agent delegation.

## Provider Architecture

At `agent_config.py`, the `_create_model_with_retry()` function creates providers:

| Model Type | Provider Class |
|------------|----------------|
| Anthropic models | `AnthropicProvider` |
| All other models | `OpenAIProvider` |

OpenAI-compatible providers attach `validate_openai_chat_completion_response` as an HTTP response hook to detect error payloads and missing required fields before pydantic-ai validation.

The same HTTP client, retry logic, and provider instances are used for all requests.

## Message Flow

```
User Message
     |
     v
process_request() [main.py]
     |
     v
RequestOrchestrator created [main.py]
     |
     v
get_or_create_agent() [agent_config.py]
     |   - Always uses full tool set
     |   - Applies max_tokens (if set)
     v
prune_old_tool_outputs() [main.py]
     |   - Backward scan messages
     |   - Protect recent outputs
     |   - Replace old with placeholder
     v
agent.iter() -> Provider HTTP Request
```

## Key Components

### Main Entry Point

**process_request()** in `main.py`
- Creates RequestOrchestrator with agent configuration
- **Prunes old tool outputs before iteration**
- Iterates through agent responses until completion
- Handles tool execution and result aggregation
- Tracks iteration counters during the run
- Emits lifecycle debug logs when `SessionState.debug_mode` is enabled

### Agent Components

#### agent_config.py

- **get_or_create_agent()** - Factory for cached Agent instances
- **_create_model_with_retry()** - Model initialization with fallback
- **load_system_prompt()** - Loads system prompt
- **load_tunacode_context()** - Loads guide file into system prompt (defaults to `AGENTS.md`)

#### openai_response_validation.py

- **validate_openai_chat_completion_response()** - HTTP response hook that detects error payloads and missing required fields before pydantic-ai validation.

#### node_processor.py
- **_process_node()** - Core response processing loop
- Extracts tool calls from structured and text responses
- Handles empty/truncated response edge cases
- Detects submit tool calls for completion

#### streaming.py
- **stream_model_request_node()** - Streams token deltas with debug instrumentation
- Short-circuits when `debug_mode` is False to minimize overhead
- Capped debug accumulators prevent memory growth:
  - `DEBUG_STREAM_EVENT_HISTORY_LIMIT` (200) - max stored events
  - `DEBUG_STREAM_RAW_STREAM_MAX_CHARS` (20,000) - max raw stream size
  - `DEBUG_STREAM_EVENT_LOG_LIMIT` (5) - events logged per stream

#### streaming_debug.py
- Debug helper functions for stream previews, event summaries, and raw stream capture
- Owns `DEBUG_STREAM_*` constants and truncation limits for debug instrumentation

#### tool_executor.py
- **execute_tools_parallel()** - Concurrent read-only tool execution
- Implements exponential backoff retry logic
- Batches tools for efficiency
- Emits lifecycle debug logs for tool execution phases when debug mode is enabled

#### tool_buffer.py
- **ToolBuffer** - Collects and batches read-only tool calls
- Separates read-only from write operations

### Delegation System

#### delegation_tools.py
- **create_research_codebase_tool()** - Creates research delegation tool
- Spawns specialized research_agent for codebase exploration
- Research agent uses read-only tools only

#### research_agent.py
- Specialized agent with focused system prompt
- Limited tool set (glob, grep, read_file, list_dir)
- Returns structured research summaries

### State Management

#### state_transition.py
- **AgentStateMachine** - Tracks processing states
- Valid transitions: USER_INPUT → ASSISTANT → TOOL_EXECUTION → RESPONSE
- Ensures proper state flow

#### iteration_manager.py (in main.py)
- **IterationManager** - Tracks iteration counters in session state

## Configuration

**AgentConfig** dataclass:
- **max_iterations** (default: 15) - Configured per-request iteration limit value

## Tool Categories

### Tool set

Full tool set with detailed descriptions:

| Category | Tools |
|----------|-------|
| Read-Only | glob, grep, list_dir, read_file, web_fetch |
| Write/Execute | bash, write_file, update_file |
| Completion | submit |
| Todo | todowrite, todoread, todoclear |
| Delegation | research_codebase |

## Message Types

Messages use pydantic-ai's standard types from `types/pydantic_ai.py`:

| Type | Purpose |
|------|---------|
| `ModelRequest` | Requests sent to model |
| `ModelResponse` | Responses from model |
| `ToolReturnPart` | Tool execution results |
| `SystemPromptPart` | System messages |
| `UserPromptPart` | User messages |
| `ToolCallPart` | Tool call requests |

**Message format is identical in both modes.** The only differences are:
- Content size (pruned more aggressively in local mode)
- System prompt content (shorter in local mode)
- Tool schemas (fewer in local mode)

Message history persistence happens after a run finishes or aborts.
`RequestOrchestrator` syncs `SessionState.conversation.messages` from
`agent_run.all_messages()` on normal completion, but **does not persist** on abort/cancel to prevent dangling tool calls.

When aborting (e.g., ESC pressed during tool execution):
- `agent_run` state is **not persisted** to avoid copying incomplete tool states
- Only cleanups already in `session.conversation.messages` are applied (dangling tool calls, empty responses, consecutive requests)
- This prevents 'Cannot provide a new user prompt when the message history contains unprocessed tool calls' errors

See `main.py:577-601` for the abort handling logic and `main.py:626-653` for the improved `_message_has_tool_calls` helper.

## Integration Points

| Component | File | Integration |
|-----------|------|-------------|
| State | `core/state.py` | Session state, message history |
| Limits | `utils/limits.py` | `get_max_tokens()` |
| Compaction | `core/compaction.py` | `prune_old_tool_outputs()` |
| Prompting | `core/prompting/` | System prompt composition |
| Tools | `tools/` | Tool function registry |
| Types | `types/` | AgentRun, ModelName, MessageHistory |

## Seams (M, D)

**Modification Points:**
- Add new agent types (e.g., code_review_agent)
- Customize iteration settings and ReAct snapshot cadence
- Extend tool categorization logic
- Add new delegation patterns

**Extension Points:**
- Implement custom agent factories
- Add specialized tool executors
- Create new state machine transitions

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…