# matrx_ai.agent_runners — Module Overview


## IMPORTANT: Do not edit auto-generated sections.

> This document is partially auto-generated. Sections tagged `<!-- AUTO:id -->` are refreshed by the generator.
> Everything else is yours to edit freely and will never be overwritten.

<!-- AUTO:meta -->
## About This Document

This file is **partially auto-generated**. Sections wrapped in `<!-- AUTO:id -->` tags
are overwritten each time the generator runs. Everything else is yours to edit freely.

| Field | Value |
|-------|-------|
| Module | `matrx_ai/agent_runners` |
| Last generated | 2026-04-07 11:38 |
| Output file | `matrx_ai/agent_runners/MODULE_README.md` |
| Signature mode | `signatures` |

**To refresh auto-sections:**
```bash
python utils/code_context/generate_module_readme.py matrx_ai/agent_runners --mode signatures
```

**To add permanent notes:** Write anywhere outside the `<!-- AUTO:... -->` blocks.
<!-- /AUTO:meta -->

<!-- HUMAN-EDITABLE: This section is yours. Agents & Humans can edit this section freely — it will not be overwritten. -->

## Architecture

> **Fill this in.** Describe the execution flow and layer map for this module.
> See `utils/code_context/MODULE_README_SPEC.md` for the recommended format.
>
> Suggested structure:
>
> ### Layers
> | File | Role |
> |------|------|
> | `entry.py` | Public entry point — receives requests, returns results |
> | `engine.py` | Core dispatch logic |
> | `models.py` | Shared data types |
>
> ### Call Flow (happy path)
> ```
> entry_function() → engine.dispatch() → implementation()
> ```


<!-- AUTO:tree -->
## Directory Tree

> Auto-generated. 6 files across 2 directories.

```
matrx_ai/agent_runners/
├── MODULE_README.md
├── __init__.py
├── conversation_labeler.py
├── podcast_generator.py
├── research.py
├── tests/
# excluded: 1 .md
```
<!-- /AUTO:tree -->

<!-- AUTO:signatures -->
## API Signatures

> Auto-generated via `output_mode="signatures"`. ~5-10% token cost vs full source.
> For full source, open the individual files directly.

```
---
Filepath: matrx_ai/agent_runners/research.py  [python]

  class AgentResult(BaseModel):
      # fields: success: bool, output: str = '', usage: dict[str, Any] = dict(), usage_history: list[TokenUsage] = list(), metadata: dict[str, Any] = dict()
  async def scrape_research_condenser_agent_1(instructions: str, scraped_content: str, queries: str, search_results: str, ctx: ToolContext) -> AgentResult
  async def scrape_research_condenser_agent_2(instructions: str, scraped_content: str, queries: str, search_results: str, ctx: ToolContext) -> AgentResult


---
Filepath: matrx_ai/agent_runners/podcast_generator.py  [python]

  class PodcastType(StrEnum):
  class InputDataType(StrEnum):
  class PostPrepOption(StrEnum):
  class AudioStyle(StrEnum):
  class PodcastRequest(BaseModel):
      # fields: show_id: str, input_data_type: InputDataType, input_data: str = '', file_urls: list[str] = [], podcast_type: PodcastType, post_prep_option: PostPrepOption = PostPrepOption.NONE, number_of_speakers: int = 2, first_show_info_text: str | None = None, audio_style: AudioStyle | None = None, prep_user_message: str | None = None, extraction_unit: str | None = None, truncate_audio_for_testing: bool = False, max_images: int | None = None, max_videos: int | None = None
  class StageResult(BaseModel):
      # fields: stage: str, success: bool, output: str = '', metadata: dict[str, Any] = dict(), error: str | None = None
  class PodcastGenerationResult(BaseModel):
      # fields: show_id: str, success: bool, script: str = '', audio_url: str = '', title: str = '', description: str = '', image_urls: list[str] = list(), video_urls: list[str] = list(), stage_results: list[StageResult] = list(), error: str | None = None
  def _is_placeholder(agent_id: str) -> bool
  async def _run_agent(agent_id: str, variables: dict[str, Any], stage_name: str) -> StageResult
  async def _run_agent_with_user_input(agent_id: str, variables: dict[str, Any], user_input: list[dict[str, Any]], stage_name: str) -> StageResult
  def _build_extraction_user_input(request: PodcastRequest) -> list[dict[str, Any]]
  async def _prepare_content(request: PodcastRequest) -> StageResult
  async def _apply_post_prep(content: str, option: PostPrepOption) -> StageResult
  def _select_script_agent(podcast_type: PodcastType) -> str
  async def _create_script(request: PodcastRequest, prepared_content: str) -> StageResult
  def _select_audio_agent(podcast_type: PodcastType) -> str
  def _resolve_audio_style(request: PodcastRequest) -> str
  async def _create_audio(request: PodcastRequest, script: str) -> StageResult
  async def _generate_metadata(prepared_content: str) -> StageResult
  async def _save_media_async(content: bytes, mime_type: str) -> str | None
  async def _generate_image_openai(prompt: str, index: int) -> StageResult
  async def _generate_image_google(prompt: str, index: int) -> StageResult
  async def _generate_image_flux(prompt: str, index: int) -> StageResult
  def _effective_media_count(cap: int | None, maximum: int) -> int  # None→full, 0→skip, 1→one, clamped
  async def _generate_images(image_descriptions: list[str], target: int = _TARGET_IMAGE_COUNT) -> list[StageResult]
  async def _generate_video_google(prompt: str, index: int) -> StageResult
  async def _generate_video_together(prompt: str, index: int) -> StageResult
  async def _generate_videos(video_descriptions: list[str], target: int = _TARGET_VIDEO_COUNT) -> list[StageResult]
  def _extract_dialogue(script: str) -> str
  def _truncate_script_for_testing(script: str, speakers: int = 2) -> str  # one turn per DISTINCT host (keeps every configured speaker)
  async def _generate_show_intro(show_id: str, info_text: str) -> StageResult
  def _extract_json_block(text: str) -> str
  def _parse_metadata(result: StageResult) -> tuple[str, str, list[str], list[str]]
  async def generate_podcast(request: PodcastRequest) -> PodcastGenerationResult


---
Filepath: matrx_ai/agent_runners/__init__.py  [python]



---
Filepath: matrx_ai/agent_runners/conversation_labeler.py  [python]

  LABELER_MODEL = 'llama-3.1-8b-instant'
  LABELER_MAX_TOKENS = 650
  CONVERSATION_LABEL_SYSTEM_PROMPT = 'You specialize in analyzing chat conversations and extracting structured metadata for labeling.\n\nYour task is to gene ...
  RECENT_CONVERSATIONS_TEMPLATE = '### Recent Conversation Titles (AVOID duplicating these):\n{{recent_titles}}\n\nLook at the titles above. Your new labe ...
  NO_RECENT_CONVERSATIONS = '### Recent Conversation Titles:\nNo recent conversations found. Generate the most descriptive and unique label you can. ...
  AGENT_CONTEXT_TEMPLATE = "### Important Context — Agent-Initiated Conversation:\nThis conversation was started by an AI agent (not a free-form us ...
  NO_AGENT_CONTEXT = ''
  class ConversationLabelResult(BaseModel):
      # fields: label: str = '', description: str = '', keywords: list[str] = list()
  class LabelResult(BaseModel):
      # fields: success: bool, output: str, error: str = ''
  def _build_user_message_for_chat(conversation_content: str) -> str
  def _build_recent_section(recent_titles: str) -> str
  def _build_agent_section(agent_name: str, agent_description: str, user_variables: str, user_prompt: str) -> str
  def _build_system_prompt(recent_titles: str, agent_name: str, agent_description: str, user_variables: str, user_prompt: str) -> str
  def _trim_content(content: str, max_chars: int = 5000) -> str
  def _format_messages_for_labeling(messages: list[dict[str, Any]], max_total_chars: int = 5000) -> str
  async def _call_groq_direct(system_prompt: str, user_message: str) -> LabelResult
  async def label_chat_conversation(conversation_content: str, recent_titles: str) -> LabelResult
  async def label_agent_conversation(conversation_content: str, recent_titles: str, agent_name: str, agent_description: str, user_variables: str, user_prompt: str) -> LabelResult
```
<!-- /AUTO:signatures -->

<!-- AUTO:callers -->
## Upstream Callers

> Auto-discovered by scanning all project files that import from this module.
> Set `ENTRY_POINTS` in `generate_readme.py` to pin specific functions.

| Caller | Calls |
|--------|-------|
| `matrx_ai/agents/services/conversation_labeler.py` | `ConversationLabelResult()` |
| `matrx_ai/agents/services/conversation_labeler.py` | `label_agent_conversation()` |
| `matrx_ai/agents/services/conversation_labeler.py` | `label_chat_conversation()` |
| `matrx_ai/tools/implementations/web.py` | `scrape_research_condenser_agent_1()` |
<!-- /AUTO:callers -->

<!-- AUTO:dependencies -->
## Dependencies

**External packages:** dotenv, groq, httpx, matrx_utils, openai, pydantic, together
**Internal modules:** matrx_ai._ext, matrx_ai.agents, matrx_ai.config, matrx_ai.context, matrx_ai.media, matrx_ai.tools
<!-- /AUTO:dependencies -->

<!-- AUTO:config -->
## Generation Config

> Auto-managed. Contains the exact parameters used to generate this README.
> Used by parent modules to auto-refresh this file when it is stale.
> Do not edit manually — changes will be overwritten on the next run.

```json
{
  "subdirectory": "matrx_ai/agent_runners",
  "mode": "signatures",
  "scope": null,
  "project_noise": null,
  "include_call_graph": false,
  "entry_points": null,
  "call_graph_exclude": [
    "tests"
  ],
  "signatures_exclude": [
    "tests",
    "db",
    "local_data",
    "docs"
  ]
}
```
<!-- /AUTO:config -->
