Subagents & AI Tools
Relevant source files
The following files were used as context for generating this wiki page:
- apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunner.kt
- apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSynthesisExecutionRunner.kt
- apps/api/src/main/kotlin/com/briefy/api/application/briefing/SubagentRunnerConfiguration.kt
- apps/api/src/main/resources/application.yml
- apps/api/src/test/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunnerTest.kt
- apps/web/src/lib/api/types.ts
Subagents and AI Tools form the core research and synthesis engine of the Briefy platform. This system utilizes specialized AI personas (subagents) that perform targeted investigations based on internal evidence and external web data. These subagents operate within a structured execution loop, utilizing specific tools to discover, fetch, and curate information before a final synthesis phase consolidates their findings into a cohesive briefing.
The system is designed to handle complex research tasks by breaking them down into multi-persona operations. Each persona is assigned a specific task and provided with internal sources. If these sources are insufficient, subagents can autonomously decide to use AI-powered tools like web search or web fetch to gather additional evidence. Sources: apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunner.kt:25-50, apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSynthesisExecutionRunner.kt:11-25
Subagent Execution Architecture
The AiSubagentExecutionRunner manages the lifecycle of a single subagent's investigation. It implements a "Tool Loop" where an LLM analyzes existing evidence and determines if further external data is required.
The Tool Execution Loop
The execution follows a three-phase approach:
- Source Lookup: Initial evidence is built from internal sources provided in the
SubagentExecutionContext. - LLM Tool Loop: The LLM enters a cycle (up to a configured
maxToolCalls) where it can either produce a final analysis or request a tool call. - Final Curation: If the budget is exhausted or the LLM completes its task, the curated text is extracted from a specific
markdownoroutputblock.
The following diagram illustrates the iterative nature of the subagent tool loop:
The diagram shows the decision process of the subagent as it chooses between using tools and providing final curated content. Sources: apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunner.kt:41-85
Tool Definitions & Protocol
Subagents communicate tool requests using a specific JSON format wrapped in a tool markdown block.
| Tool Name | Purpose | Required Arguments |
|---|---|---|
web_search | Search the web for new information | query (String), maxResults (Int) |
web_fetch | Retrieve and read a specific web page | url (String) |
Sources: apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunner.kt:130-143, apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunner.kt:193-241
Synthesis Engine
Once all subagents have completed their tasks, the AiSynthesisExecutionRunner aggregates the individual curated outputs into a single briefing. This process ensures that conflicting information between different personas is identified and resolved explicitly.
Synthesis Process
- Reference Aggregation: It merges all web references collected by subagents, deduplicating them by URL.
- Structured Prompting: The engine builds a comprehensive prompt containing intent, original internal sources, successful persona outputs, and collected references.
- JSON Extraction: The synthesis LLM is required to return a structured JSON object containing the final markdown body, refined references, and "Conflict Highlights."
This sequence details the consolidation of multi-persona research into a final product. Sources: apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSynthesisExecutionRunner.kt:11-37
Data Models for Synthesis
The synthesis result includes specialized structures to track conflicts and evidence citations.
| Field | Type | Description |
|---|---|---|
markdownBody | String | The final curated briefing text in Markdown format. |
references | List | A collection of BriefingReferenceCandidate (URL, Title, Snippet). |
conflictHighlights | List | Objects containing claim, counterClaim, and confidence. |
Sources: apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSynthesisExecutionRunner.kt:46-60, apps/web/src/lib/api/types.ts:257-270
Configuration & Integration
The system supports multiple AI providers and flexible execution modes, configured primarily via application.yml.
System Configuration
| Path | Default | Description |
|---|---|---|
briefing.execution.mode | sequential | How subagents are executed (sequential or parallel). |
briefing.execution.ai.provider | google_genai | The default LLM provider for runners. |
briefing.execution.ai.model | gemini-2.5-flash | The default model for subagents and synthesis. |
briefing.execution.ai.max-tool-calls | 8 | Maximum number of tools a subagent can use. |
briefing.execution.max-attempts | 3 | Number of retries for transient failures. |
Sources: apps/api/src/main/resources/application.yml:193-210
Runner Factory
The SubagentRunnerConfiguration class acts as a factory, instantiating either AiSubagentExecutionRunner or a DeterministicSequentialSubagentExecutionRunner based on the environment configuration.
@Bean
fun subagentExecutionRunner(
executionConfig: ExecutionConfigProperties,
objectMapper: ObjectMapper,
aiAdapter: AiAdapter,
webSearchTool: WebSearchTool?,
webFetchTool: WebFetchTool?
): SubagentExecutionRunner {
return when (executionConfig.runner) {
ExecutionConfigProperties.RunnerType.AI -> AiSubagentExecutionRunner(...)
ExecutionConfigProperties.RunnerType.DETERMINISTIC -> DeterministicSequentialSubagentExecutionRunner(...)
}
}
Sources: apps/api/src/main/kotlin/com/briefy/api/application/briefing/SubagentRunnerConfiguration.kt:20-40
Error Handling & Reliability
Subagent execution is designed to be resilient to transient AI or network issues.
- Transient Failures: Errors like HTTP 429 (Rate Limited), timeouts, and network errors are marked as
retryable. - Budget Exhaustion: If a subagent hits the
maxToolCallslimit, the runner sends aBUDGET_EXHAUSTED_PROMPTto force the LLM to provide its final analysis based on available evidence. - Empty Outputs: If the LLM produces a blank analysis block, the runner returns
SubagentExecutionResult.EmptyOutputto avoid corrupting the synthesis phase. - Deterministic Fallback: In the synthesis phase, if the LLM fails to provide valid JSON, the system falls back to a deterministic markdown generator that simply concatenates persona outputs.
Sources: apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunner.kt:88-105, apps/api/src/main/kotlin/com/briefy/api/application/briefing/AiSynthesisExecutionRunner.kt:182-198, apps/api/src/test/kotlin/com/briefy/api/application/briefing/AiSubagentExecutionRunnerTest.kt:185-200
Summary
The "Subagents & AI Tools" module provides a sophisticated framework for autonomous AI research. By combining persona-based task execution, a structured tool protocol (web search/fetch), and a dedicated synthesis engine, it allows Briefy to generate high-depth briefings that are grounded in both internal and external evidence while explicitly managing informational conflicts.