# DEVELOPER GUIDE for adk directory

## Quick Summary
The `adk` directory serves as the core integration layer between the Solace AI Connector framework and Google's Agent Development Kit (ADK). It provides the essential components for building, configuring, and running sophisticated AI agents within a Solace messaging environment.

The architecture is designed for modularity and extensibility. The `setup.py` module acts as the main configuration hub, using factory functions from `services.py` to initialize pluggable services (like `FilesystemArtifactService` for artifact storage) and loading tools (Python functions, MCP tools) via the `ADKToolWrapper`.

Once initialized, the `AppLlmAgent` (a custom agent class) is managed by the `runner.py` module, which handles the asynchronous task execution loop. The agent's behavior is dynamically augmented at runtime by a rich set of callbacks from `callbacks.py`. These callbacks inject dynamic instructions, manage large tool responses, log events to Solace, and handle advanced features like streaming artifact creation and auto-continuation of conversations. The `models/` subdirectory provides the concrete LLM clients, with `LiteLlm` offering broad compatibility with various model providers.

## Files and Subdirectories Overview
- **Direct files:**
  - `__init__.py`: Standard Python package initializer
  - `app_llm_agent.py`: Defines a custom `LlmAgent` subclass that holds a reference to its host component
  - `callbacks.py`: Provides a rich set of ADK callback functions for dynamic instructions, metadata injection, and Solace integration
  - `embed_resolving_mcp_toolset.py`: Custom MCPToolset that resolves embeds in tool parameters before calling MCP tools
  - `filesystem_artifact_service.py`: A local filesystem-based implementation of ADK's `BaseArtifactService`
  - `intelligent_mcp_callbacks.py`: Intelligent MCP callback functions for processing and saving MCP tool responses as typed artifacts
  - `invocation_monitor.py`: A utility for monitoring and logging agent invocations to YAML files for debugging
  - `mcp_content_processor.py`: Intelligent processing of MCP tool responses, converting raw content into appropriately typed artifacts
  - `runner.py`: Manages the asynchronous execution of ADK agent tasks, including cancellation support
  - `services.py`: Contains factory functions for initializing ADK services (session, artifact, memory) based on configuration
  - `setup.py`: Handles the high-level initialization of the ADK agent, tools, and runner
  - `stream_parser.py`: An internal utility for parsing fenced artifact blocks from an LLM's streaming response
  - `tool_wrapper.py`: A wrapper for Python functions to make them compatible with ADK, handling embed resolution and config injection
- **Subdirectories:**
  - `artifacts/`: Contains filesystem and S3-compatible artifact storage implementations
  - `models/`: Contains concrete `BaseLlm` implementations for interfacing with various LLM providers

## Developer API Reference

### Direct Files

#### app_llm_agent.py
**Purpose:** A custom `LlmAgent` subclass that includes a reference to its hosting component, allowing callbacks and tools to access host-level configurations and services.
**Import:** `from solace_agent_mesh.agent.adk.app_llm_agent import AppLlmAgent`

**Classes/Functions/Constants:**
- `AppLlmAgent(host_component: Any = None, **kwargs)`: A custom `LlmAgent` that can be linked to a host component. The `host_component` is set post-initialization and is excluded from serialization.

#### callbacks.py
**Purpose:** Provides a suite of ADK callback functions that hook into the agent's lifecycle to inject custom logic. These are typically not called directly but are assigned to the agent during setup.
**Import:** `from solace_agent_mesh.agent.adk import callbacks`

**Classes/Functions/Constants:**
- `inject_dynamic_instructions_callback(...)`: Injects instructions into the prompt based on host configuration, active tools, and peer agents
- `manage_large_mcp_tool_responses_callback(...)`: Intercepts large tool responses, saves them as artifacts, and returns a truncated summary to the LLM
- `after_tool_callback_inject_metadata(...)`: After a tool creates an artifact, this loads its metadata and injects it into the tool response
- `process_artifact_blocks_callback(...)`: Processes streaming text to identify and save fenced artifact blocks (e.g., `«««save_artifact:...»»»`)
- `auto_continue_on_max_tokens_callback(...)`: Automatically continues a conversation if the LLM response was interrupted due to token limits
- `notify_tool_invocation_start_callback(...)`: Sends a status update over Solace when a tool is about to be invoked
- `solace_llm_invocation_callback(...)`: Sends a status update over Solace when the agent calls the LLM
- `repair_history_callback(...)`: Proactively checks for and repairs dangling tool calls in conversation history

#### embed_resolving_mcp_toolset.py
**Purpose:** Custom MCPToolset that resolves embeds in tool parameters before calling MCP tools, enabling dynamic content injection.
**Import:** `from solace_agent_mesh.agent.adk.embed_resolving_mcp_toolset import EmbedResolvingMCPToolset, EmbedResolvingMCPTool`

**Classes/Functions/Constants:**
- `EmbedResolvingMCPToolset(connection_params, tool_filter=None, auth_scheme=None, auth_credential=None, tool_config=None)`: Custom MCPToolset that creates EmbedResolvingMCPTool instances
- `EmbedResolvingMCPTool(original_mcp_tool, tool_config=None)`: Custom MCPTool that resolves embeds in parameters before calling the actual MCP tool

#### filesystem_artifact_service.py
**Purpose:** An implementation of `BaseArtifactService` that stores artifacts on the local filesystem, organized by scope, user, and session.
**Import:** `from solace_agent_mesh.agent.adk.filesystem_artifact_service import FilesystemArtifactService`

**Classes/Functions/Constants:**
- `FilesystemArtifactService(base_path: str)`: A service for managing artifacts on the local disk
  - `async save_artifact(...) -> int`: Saves an artifact and returns its version number
  - `async load_artifact(...) -> Optional[adk_types.Part]`: Loads a specific version of an artifact, or the latest if unspecified
  - `async list_artifact_keys(...) -> List[str]`: Lists the names of all artifacts for a given user/session
  - `async delete_artifact(...)`: Deletes an artifact and all its versions
  - `async list_versions(...) -> List[int]`: Lists all version numbers for a specific artifact

#### intelligent_mcp_callbacks.py
**Purpose:** Intelligent MCP callback functions that use intelligent content processing to save MCP tool responses as appropriately typed artifacts.
**Import:** `from solace_agent_mesh.agent.adk.intelligent_mcp_callbacks import save_mcp_response_as_artifact_intelligent, McpSaveResult, McpSaveStatus`

**Classes/Functions/Constants:**
- `save_mcp_response_as_artifact_intelligent(tool, tool_context, host_component, mcp_response_dict, original_tool_args) -> McpSaveResult`: Intelligently processes and saves MCP tool response content as typed artifacts
- `McpSaveStatus`: Enumeration for the status of an MCP save operation (SUCCESS, PARTIAL_SUCCESS, ERROR)
- `McpSaveResult`: The definitive result of an MCP response save operation with status, message, and artifact details

#### invocation_monitor.py
**Purpose:** A debugging utility that logs the entire lifecycle of an agent invocation, from the initial request to the final response, into a structured YAML file.
**Import:** `from solace_agent_mesh.agent.adk.invocation_monitor import InvocationMonitor`

**Classes/Functions/Constants:**
- `InvocationMonitor()`: A class that monitors and logs agent message flows
  - `log_message_event(direction: str, topic: str, payload: any, ...)`: Logs a single message event
  - `cleanup()`: Finalizes any active logging sessions

#### mcp_content_processor.py
**Purpose:** Intelligent processing of MCP tool responses, converting raw MCP content into appropriately typed and formatted artifacts based on the MCP specification content types.
**Import:** `from solace_agent_mesh.agent.adk.mcp_content_processor import MCPContentProcessor, MCPContentItem, MCPContentProcessorConfig`

**Classes/Functions/Constants:**
- `MCPContentProcessor(tool_name: str, tool_args: Dict[str, Any])`: Main processor for MCP tool response content
  - `process_mcp_response(mcp_response_dict) -> List[MCPContentItem]`: Process an MCP tool response and extract content items
- `MCPContentItem`: Represents a processed MCP content item with metadata
- `MCPContentProcessorConfig`: Configuration for MCP content processing

#### runner.py
**Purpose:** Provides the core asynchronous task execution logic for the ADK agent, including robust cancellation handling.
**Import:** `from solace_agent_mesh.agent.adk.runner import run_adk_async_task_thread_wrapper, TaskCancelledError`

**Classes/Functions/Constants:**
- `run_adk_async_task_thread_wrapper(component, adk_session, adk_content, ...)`: A high-level wrapper that runs an ADK task in a separate thread and handles all cleanup and error finalization
- `run_adk_async_task(component, task_context, adk_session, adk_content, run_config, a2a_context) -> bool`: Runs the ADK Runner asynchronously and processes intermediate events
- `TaskCancelledError(Exception)`: Custom exception raised when an agent task is cancelled externally

#### services.py
**Purpose:** Provides factory functions to initialize the various ADK services based on the agent's configuration file.
**Import:** `from solace_agent_mesh.agent.adk.services import initialize_session_service, initialize_artifact_service, initialize_memory_service, ScopedArtifactServiceWrapper`

**Classes/Functions/Constants:**
- `initialize_session_service(component) -> BaseSessionService`: Creates a session service (e.g., `InMemorySessionService`)
- `initialize_artifact_service(component) -> BaseArtifactService`: Creates an artifact service (e.g., `FilesystemArtifactService`, `GcsArtifactService`)
- `initialize_memory_service(component) -> BaseMemoryService`: Creates a memory service (e.g., `InMemoryMemoryService`)
- `ScopedArtifactServiceWrapper`: A wrapper that transparently applies configured scope to artifact operations

#### setup.py
**Purpose:** The main entry point for configuring and instantiating the ADK agent and its dependencies. These functions tie all the other modules together.
**Import:** `from solace_agent_mesh.agent.adk.setup import load_adk_tools, initialize_adk_agent, initialize_adk_runner`

**Classes/Functions/Constants:**
- `async load_adk_tools(component) -> Tuple[List[Union[BaseTool, Callable]], List[BuiltinTool]]`: Loads all configured tools, including Python functions, MCP tools, and built-ins, wrapping them with `ADKToolWrapper`
- `initialize_adk_agent(component, loaded_explicit_tools, enabled_builtin_tools) -> AppLlmAgent`: Creates an `AppLlmAgent` instance, assigns all the necessary callbacks from `callbacks.py`, and attaches the tools
- `initialize_adk_runner(component) -> Runner`: Initializes the ADK Runner with the agent and services

#### stream_parser.py
**Purpose:** A stateful stream parser for identifying and extracting fenced artifact blocks from an LLM's text stream.
**Import:** `from solace_agent_mesh.agent.adk.stream_parser import FencedBlockStreamParser, BlockStartedEvent, BlockCompletedEvent`

**Classes/Functions/Constants:**
- `FencedBlockStreamParser(progress_update_interval_bytes=4096)`: Processes a stream of text chunks to identify and extract fenced artifact blocks
  - `process_chunk(text_chunk: str) -> ParserResult`: Processes the next chunk of text from the stream
  - `finalize() -> ParserResult`: Call at the end of an LLM turn to handle any unterminated blocks
- `BlockStartedEvent`, `BlockCompletedEvent`, `BlockProgressedEvent`, `BlockInvalidatedEvent`: Events emitted by the parser

#### tool_wrapper.py
**Purpose:** A wrapper for Python functions to make them compatible with ADK, handling embed resolution and config injection.
**Import:** `from solace_agent_mesh.agent.adk.tool_wrapper import ADKToolWrapper`

**Classes/Functions/Constants:**
- `ADKToolWrapper(original_func, tool_config, tool_name, origin, raw_string_args=None)`: A consolidated wrapper for ADK tools that handles metadata preservation, embed resolution, config injection, and error handling

### Subdirectory APIs

#### artifacts/
**Purpose:** Contains filesystem and S3-compatible artifact storage implementations for managing artifacts with versioning, user namespacing, and session-based organization
**Key Exports:** `FilesystemArtifactService`, `S3ArtifactService` classes for local and cloud artifact storage
**Import Examples:**
```python
from solace_agent_mesh.agent.adk.artifacts.filesystem_artifact_service import FilesystemArtifactService
from solace_agent_mesh.agent.adk.artifacts.s3_artifact_service import S3ArtifactService
```

#### models/
**Purpose:** Contains concrete `BaseLlm` implementations for interfacing with various LLM providers
**Key Exports:** `LiteLlm` class for broad model provider compatibility
**Import Examples:**
```python
from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm
```

## Complete Usage Guide

### 1. Basic ADK Agent Setup

```python
from solace_agent_mesh.agent.adk.setup import load_adk_tools, initialize_adk_agent, initialize_adk_runner
from solace_agent_mesh.agent.adk.services import initialize_session_service, initialize_artifact_service, initialize_memory_service
from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm

# Initialize services
session_service = initialize_session_service(component)
artifact_service = initialize_artifact_service(component)
memory_service = initialize_memory_service(component)

# Load tools
loaded_tools, builtin_tools = await load_adk_tools(component)

# Initialize agent
agent = initialize_adk_agent(component, loaded_tools, builtin_tools)

# Initialize runner
runner = initialize_adk_runner(component)
```

### 2. Custom LLM Model Configuration

```python
from solace_agent_mesh.agent.adk.models.lite_llm import LiteLlm

# Configure LiteLlm for different providers
# OpenAI
llm = LiteLlm(
    model="gpt-4-turbo",
    temperature=0.7,
    max_completion_tokens=1000
)

# Anthropic
llm = LiteLlm(
    model="claude-3-sonnet-20240229",
    temperature=0.5
)

# Vertex AI
llm = LiteLlm(
    model="gemini-pro",
    temperature=0.3
)
```

### 3. Artifact Service Usage

```python
from solace_agent_mesh.agent.adk.artifacts.filesystem_artifact_service import FilesystemArtifactService
from solace_agent_mesh.agent.adk.artifacts.s3_artifact_service import S3ArtifactService
from google.genai import types as adk_types

# Initialize filesystem artifact service
artifact_service = FilesystemArtifactService(base_path="/tmp/artifacts")

# Or initialize S3 artifact service
artifact_service = S3ArtifactService(bucket_name="my-artifacts-bucket")

# Save an artifact
content = "Hello, world!"
artifact = adk_types.Part.from_text(content

# content_hash: bdaeea265906dddb9e33e2ae4476cd77b2db58d735ff6afbc222b7815736f601
