Merge https://github.com/google/adk-python/pull/3700
### Description
This PR refactors the `adk_stale_agent` to address `429 RESOURCE_EXHAUSTED` errors encountered during workflow execution. The previous implementation was inefficient in fetching issue history (using pagination over the REST API) and lacked server-side filtering, causing excessive API calls and huge token consumption that breached Gemini API quotas.
The new implementation switches to a **GraphQL-first approach**, implements server-side filtering via the Search API, adds robust concurrency controls, and significantly improves code maintainability through modular refactoring.
### Root Cause of Failure
The previous workflow failed with the following error due to passing too much context to the LLM and processing too many irrelevant issues:
```text
google.genai.errors.ClientError: 429 RESOURCE_EXHAUSTED.
Quota exceeded for metric: generativelanguage.googleapis.com/generate_content_paid_tier_input_token_count
```
### Key Changes
#### 1. Optimization: REST → GraphQL (`agent.py`)
* **Old:** Fetched issue comments and timeline events using multiple paginated REST API calls (`/timeline`).
* **New:** Implemented `get_issue_state` using a single **GraphQL** query. This fetches comments, `userContentEdits`, and specific timeline events (Labels, Renames) in one network request.
* **Refactoring:** The complex analysis logic has been decomposed into focused helper functions (_fetch_graphql_data, _build_history_timeline, _replay_history_to_find_state) for better readability and testing.
* **Configurable:** Added GRAPHQL_COMMENT_LIMIT and GRAPHQL_TIMELINE_LIMIT settings to tune context depth
* **Impact:** Drastically reduces the data payload size and eliminates multiple API round-trips, significantly lowering the token count sent to the LLM.
#### 2. Optimization: Server-Side Filtering (`utils.py`)
* **Old:** Fetched *all* open issues via REST and filtered them in Python memory.
* **New:** Uses the GitHub Search API (`get_old_open_issue_numbers`) with `created:<DATE` syntax.
* **Impact:** Only fetches issue numbers that actually meet the age threshold, preventing the agent from wasting cycles and tokens on brand-new issues.
#### 3. Concurrency & Rate Limiting (`main.py` & `settings.py`)
* **Old:** Sequential execution loop.
* **New:** Implemented `asyncio.gather` with a configurable `CONCURRENCY_LIMIT` (set to 3).
* **New:** Added `urllib3` retry strategies (exponential backoff) in `utils.py` to handle GitHub API rate limits (HTTP 429) gracefully.
#### 4. Logic Improvements ("Ghost Edits")
* **New Feature:** The agent now detects "Ghost Edits" (where an author updates the issue description without posting a new comment).
* **Action:** If a silent edit is detected on a stale candidate, the agent now alerts maintainers instead of marking it stale, preventing false positives.
### File Comparison Summary
| File | Change |
| :--- | :--- |
| `main.py` | Switched from `InMemoryRunner` loop to `asyncio` chunked processing. Added execution timing and API usage logging. |
| `agent.py` | Replaced REST logic with GraphQL query. Added logic to handle silent body edits. Decomposed giant get_issue_state into helper functions with docstrings. Added _format_days helper. |
| `utils.py` | Added `HTTPAdapter` with Retries. Added `get_old_open_issue_numbers` using Search API. |
| `settings.py` | Removed `ISSUES_PER_RUN`; added configuration for CONCURRENCY_LIMIT, SLEEP_BETWEEN_CHUNKS, and GraphQL limits. |
| `PROMPT_INSTRUCTIONS.txt` | Simplified decision tree; removed date calculation responsibility from LLM. |
### Verification
The new logic minimizes token usage by offloading date calculations to Python and strictly limiting the context passed to the LLM to semantic intent analysis (e.g., "Is this a question?").
* **Metric Check:** The workflow now tracks API calls per issue to ensure we stay within limits.
* **Safety:** Silent edits by users now correctly reset the "Stale" timer.
* **Maintainability:** All complex logic is now isolated in typed helper functions with comprehensive docstrings.
Co-authored-by: Xuan Yang <xygoogle@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3700 from ryanaiagent:feat/improve-stale-agent 888064eff125ae74f7c3a9ad6c74f98de80243a2
PiperOrigin-RevId: 838885530
This calls the cloudapiregistry.googleapis.com API to get MCP tools from the project's registry, and adds them to ADK.
Co-authored-by: Kathy Wu <wukathy@google.com>
PiperOrigin-RevId: 837166909
Merge https://github.com/google/adk-python/pull/3572
**Please ensure you have read the [contribution guide](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) before creating a pull request.**
### Link to Issue or Description of Change
**1. Link to an existing issue (if applicable):**
N/A
**2. Or, if no issue exists, describe the change:**
**Problem:**
Docs fix
### Checklist
- [ ] I have read the [CONTRIBUTING.md](https://github.com/google/adk-python/blob/main/CONTRIBUTING.md) document.
- [ ] I have performed a self-review of my own code.
- [ ] I have commented my code, particularly in hard-to-understand areas.
- [ ] I have added tests that prove my fix is effective or that my feature works.
- [ ] New and existing unit tests pass locally with my changes.
- [ ] I have manually tested my changes end-to-end.
- [ ] Any dependent changes have been merged and published in downstream modules.
Co-authored-by: Hangfei Lin <hangfei@google.com>
COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/3572 from issacg:patch-1 b7c7ed46ff0fb018f4da1537535eff27c323daf5
PiperOrigin-RevId: 834864431
It also enables the ADK triaging agent to run periodically on planned but not triaged issues.
Co-authored-by: Xuan Yang <xygoogle@google.com>
PiperOrigin-RevId: 834489103
Updates type annotations to use built-in types like `list` and `dict`, and uses `| None` for optional types, along with adding `from __future__ import annotations`
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 832522395
This change:
* Deprecates the `save_live_audio` configuration option in `RunConfig`, introducing `save_live_blob` as its replacement. A warning is issued if `save_live_audio` is used.
* Updates `base_llm_flow.py` to use the new `save_live_blob` flag.
* Ensures that audio events generated by `audio_cache_manager.py` are properly appended to the session service.
* Adds a utility script `pcm_audio_player.py` for playing raw PCM audio files.
Input sample event: 14a5859f-6b6c-46ed-9f28-e5008793b1c6|live_bidi_streaming_multi_agent|user|1e867c7f-dbe1-4268-a7bc-7a9fa5fbd16c|e-7a28a060-29bf-4483-bc5c-17248698a897|1762916981.5932|{"content":{"parts":[{"file_data":{"file_uri":"artifact://live_bidi_streaming_multi_agent/user/1e867c7f-dbe1-4268-a7bc-7a9fa5fbd16c/_adk_live/adk_live_audio_storage_input_audio_1762916981593.pcm#0","mime_type":"audio/pcm"}}],"role":"user"},"invocation_id":"e-7a28a060-29bf-4483-bc5c-17248698a897","author":"user","actions":{"state_delta":{},"artifact_delta":{},"requested_auth_configs":{},"requested_tool_confirmations":{}},"id":"14a5859f-6b6c-46ed-9f28-e5008793b1c6","timestamp":1762916981.5932002}
output sample event:
506c9df4-e143-4ebc-90a5-2f5b2eb26754|live_bidi_streaming_multi_agent|user|1e867c7f-dbe1-4268-a7bc-7a9fa5fbd16c|e-7a28a060-29bf-4483-bc5c-17248698a897|1762916986.10579|{"content":{"parts":[{"file_data":{"file_uri":"artifact://live_bidi_streaming_multi_agent/user/1e867c7f-dbe1-4268-a7bc-7a9fa5fbd16c/_adk_live/adk_live_audio_storage_output_audio_1762916986105.pcm;rate=24000#0","mime_type":"audio/pcm;rate=24000"}}],"role":"model"},"invocation_id":"e-7a28a060-29bf-4483-bc5c-17248698a897","author":"model","actions":{"state_delta":{},"artifact_delta":{},"requested_auth_configs":{},"requested_tool_confirmations":{}},"id":"506c9df4-e143-4ebc-90a5-2f5b2eb26754","timestamp":1762916986.105794}
Co-authored-by: Hangfei Lin <hangfei@google.com>
PiperOrigin-RevId: 831512074
This change introduces a mechanism for users to register their own custom backend services for sessions, memory, and artifacts without modifying the ADK framework. This enhances the extensibility of ADK.
Two methods of registration are supported, both by placing a file in the parent directory of the agents.
**YAML Configuration (services.yaml or .yml)**
This is the recommended approach for simple services that can be instantiated with a constructor like MyService(uri="...", **kwargs).
Example services.yaml:
```
services:
- scheme: mysession
type: session
class: my_package.my_module.MyCustomSessionService
```
**Python Registration (services.py)**
For services requiring more complex initialization logic, users can define factory functions in a services.py file.
Example services.py
```
from google.adk.cli.service_registry import get_service_registry
from my_package.my_module import MyCustomSessionService
def my_session_factory(uri: str, **kwargs):
# custom initialization logic
return MyCustomSessionService(...)
get_service_registry().register_session_service("mysession", my_session_factory)
```
ADK will load services from services.yaml/.yml first, and then from services.py. If the same service scheme is defined in both, the registration in services.py will take precedence.
To use a registered service, specify its URI via the corresponding command-line flag, e.g., `--session_service_uri=mysession://....`
Co-authored-by: Shangjie Chen <deanchen@google.com>
PiperOrigin-RevId: 831211371
The agent's instructions are updated to guide it to guess a positive integer, starting from 50 and decreasing, using the `guess_number_tool` until the target is found. The maximum number of retries for the `CustomRetryPlugin` is increased from 6 to 10.
Co-authored-by: Hangfei Lin <hangfei@google.com>
PiperOrigin-RevId: 830984481
Enhanced `save_artifact` in `callback_context.py` to accept `custom_metadata` and added `get_artifact_version` to retrieve artifact details.
Introduced a new sample, `context_offloading_with_artifact`, demonstrating how to use ADK artifacts to offload large data from the LLM context. The sample includes:
- `QueryLargeDataTool`: Generates mock sales reports, saves them as artifacts with custom metadata, and injects the artifact content into the LLM request immediately after creation.
- `CustomLoadArtifactsTool`: Provides summaries of available artifacts to the LLM based on metadata and loads artifact content on demand when `load_artifacts` is called.
Co-authored-by: Hangfei Lin <hangfei@google.com>
PiperOrigin-RevId: 830592786
This trimmed schema includes only the fields relevant to agent shells, tool wiring, and common generation parameters, improving efficiency and focus.
The default model for the assistant has also been updated to "gemini-2.5-pro"
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 829513627
Add `_to_litellm_response_format` to convert ADK's `response_schema` types (Pydantic models, JSON schema dicts) into the format needed by LiteLLM for JSON object/schema constraints
Close#1967
Co-authored-by: George Weale <gweale@google.com>
PiperOrigin-RevId: 829037987