docs(setup): explain local lockfile needed by tox - #7318
Closed
iarjunganesh wants to merge 1 commit into
Closed
iarjunganesh wants to merge 1 commit into
iarjunganesh wants to merge 1 commit into
Conversation
uv.lock is ignored in this repository, so contributors need to run uv sync before the tox lock runner. State that sequence explicitly in the setup skill. Signed-off-by: Arjun Ganesh <iarjunganesh@gmail.com>
copybara-service Bot
pushed a commit
that referenced
this pull request
Sep 29, 2026
Merge #7318 PiperOrigin-RevId: 990578226
Collaborator
|
Thank you @iarjunganesh for your contribution! 🎉 Your changes have been successfully imported and merged via Copybara in commit 96319fc. Closing this PR as the changes are now in the main branch. |
caohy1988
added a commit
to caohy1988/adk-python
that referenced
this pull request
Sep 30, 2026
…ytics error_message (#14) * fix(plugins): record content_formatter failure class in BigQuery rows When BigQueryLoggerConfig.content_formatter raised, or returned a type the parser cannot store, BigQueryAgentAnalyticsPlugin wrote the [FORMATTER_FAILED] sentinel, logged a constant warning, and left the row's error_message NULL, so the developer had no signal about why. Set error_message to a fixed-shape description that names only a class, for example "content_formatter raised ImportError" or "content_formatter returned unsupported type tuple", and never the exception message, args, or traceback, which can embed the content the formatter was protecting. Because type(name, ...) can mint a class named after that content, a name is used only when code chose it: a static type compiled into C, or a class bound under that name in its imported module. Any other class is described by its nearest such ancestor, for example "content_formatter raised <subclass of ValueError>". An event that already carries an error_message, such as a TOOL_ERROR, keeps it first, followed by "; " and the formatter failure. Add BigQueryLoggerConfig.debug_content_formatter_errors (default False), which attaches the traceback to the local formatter-failure warning for debugging. The traceback is never written to BigQuery, and the docstring warns that the process's log handlers can forward it, and the content it embeds, elsewhere. The fail-closed contract is unchanged: the sentinel content, the constant log text by default, and the formatter_failed drop counter. Refs: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#485 (item A) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix: stamp Redis sessions with the event timestamp Merge google#7293 Fixes google#7292 PiperOrigin-RevId: 990023711 * fix(plugins): stop formatter diagnostics leaking names or dropping rows Review of the previous commit found three ways the new content_formatter diagnostics could still leak payload text or drop a row. This closes them. Trusted labels only. A class created at runtime can be named after the content a formatter was protecting and then bound into its module, so "the class is bound under its name in its module" proved nothing, and such a name reached error_message. error_message now names a class only by a label that no runtime data can have chosen: the compiled name of a static C type, or a fixed string for an allowlisted class matched by identity (LlmRequest, types.Content, types.Part, pydantic BaseModel, and google.api_core GoogleAPICallError). Every other class, including every Python-defined library exception and every class the developer defines, is described by its nearest trusted ancestor, for example "content_formatter raised <subclass of ValueError>". Trade-off: fewer exact names, for example json.JSONDecodeError now reads "<subclass of ValueError>" and a google.api_core NotFound "<subclass of GoogleAPICallError>"; debug_content_formatter_errors shows the exact class locally. No class code runs while diagnosing. Flags, name, and MRO are read through type's own descriptors, and allowlist matching compares identity, so a metaclass __getattribute__, __eq__, or __hash__ can no longer run inside the fail-closed boundary. Such a hook could raise asyncio.CancelledError, which escaped the boundary's `except Exception` and dropped the row. Classification now cannot raise at all, so it needs no BaseException handler, and a genuine KeyboardInterrupt or SystemExit delivered by a signal still propagates. The exact-class check on formatter results also compares identity now, for the same reason. Best-effort debug traceback. With debug_content_formatter_errors, the traceback is rendered to text once, inside the plugin, and appended to the warning; handlers never receive the live exception, whose own code could otherwise fail inside a stock StreamHandler and drop the row. A rendering failure falls back to a constant placeholder. KeyboardInterrupt and SystemExit still propagate, because a signal can deliver them at any bytecode; any other BaseException raised while rendering, CancelledError included, can only come from the exception being rendered, since rendering never awaits. The warning is emitted after the except block, so a failing handler's handleError cannot reach the formatter's exception through its exception chain. Tests pin each guard: registered payload-named classes and their subclasses, a renamed allowlisted class, metaclass hooks raising CancelledError, SystemExit, or RuntimeError on both failure paths, unrenderable tracebacks under a stock StreamHandler, interrupt propagation, and a failing log handler. Removing any guard fails at least one test. Refs: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#485 (item A) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(plugins): keep formatter diagnosis from ever dropping the row Review of the previous commit showed three more ways that diagnosing a content_formatter failure could escape and drop the row, even after the hook-by-hook fixes: - a rendering hook raising SystemExit or KeyboardInterrupt, which the previous policy re-raised as possibly genuine; - type's own descriptors raising TypeError once a meta-metaclass drops `type` from the failed class's metaclass MRO, which disproved "classification cannot raise"; - a log handler or filter raising while the warning is emitted, which also misattributed an unsupported result as "raised RuntimeError". Instead of patching one hook at a time, all of diagnosis (naming the failed class, rendering the debug traceback, and emitting the warning) now runs in _diagnose_formatter_failure, behind one boundary that contains whatever is raised, of any type, and falls back to a constant note. It runs only after the fail-closed state is settled: the formatter's try/except now only records the failure and writes the sentinel, and the failure is counted before diagnosis starts. Nothing diagnosis does can reach the row, the sentinel, the counter, or the callback's caller. BaseException is contained deliberately. An interrupt raised by a hook, handler, or filter cannot be told apart from one a signal handler delivered, and letting it through would let the content under redaction abort the agent run and lose the row. Diagnosis never awaits, so a real asyncio cancellation is never swallowed; a signal that lands inside the short window is absorbed, and the next is delivered normally. Interrupts raised by the formatter call itself still propagate, as before. Two inner guards remain where they keep the warning: labeling falls back to "<unknown class>" when type's descriptors raise, and rendering falls back to a placeholder. Diagnosis still runs after the except block, so a failing handler's handleError cannot print the formatter's exception. A result whose __class__ merely claims to be str is now reported as an unsupported result instead of "raised TypeError". Tests: a property test injects RuntimeError, CancelledError, KeyboardInterrupt, SystemExit, and another BaseException at each diagnostic step (labeling, rendering, a handler, a filter) on both paths and requires the sentinel row and its count. Also added: the meta-metaclass regression on both paths, rendering hooks raising interrupts, a stderr check that a failing handler never prints the formatter's exception, and a guard that interrupts from the formatter call still propagate. Removing the boundary or any guard fails a test. Refs: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#485 (item A) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(plugins): close remaining formatter paths that leak or drop rows Review of the previous commit found three more paths, each also present on main, by which a content_formatter failure could still leak payload text or lose the row: - The failure warning can be logged while the caller is handling an exception, as ADK is when it runs error callbacks. A log handler that fails prints the exception being handled through handleError, so a closed stream could print the caller's exception, or the formatter's when it re-raised that one, to stderr. - The result check used isinstance(formatted, (dict, list)), which falls back to the object's own __class__. A returned object could raise CancelledError, SystemExit, or KeyboardInterrupt there and lose the row, or raise an ordinary exception that was then reported as the formatter having raised. - A rejected coroutine was released unstarted, so Python warned "coroutine '<name>' was never awaited", and the formatter can set that name from the content. Everything after the formatter call now runs in _settle_formatter_outcome, behind the one boundary that already contained diagnosis: judging the result, closing a rejected coroutine or generator, naming the class, rendering the debug traceback, and logging. The result is judged only by its real type, through issubclass(type(x), ...) and identity, which runs none of its code. A str, dict, or list subclass is still accepted; an object whose __class__ merely claims to be one is now a counted formatter failure rather than an [UNSUPPORTED_OBJECT] row. A rejected coroutine or generator is closed before release, which for an unstarted one runs no code and emits no warning. The warning is emitted while a constant stand-in exception, raised from None, is being handled, so a failing handler prints only that. The formatter call itself still lets KeyboardInterrupt, SystemExit, and CancelledError propagate. Docs: the content_formatter docstring now says "raises an Exception", explains judging by real type, and notes that interrupts from the call propagate. The boundary's docstring states plainly that a genuine signal delivered while it runs, including while a handler blocks, is absorbed. The debug flag notes that a failing handler echoes the rendered traceback to stderr. Tests: a caller handling a payload exception with a closed handler (re-raised and distinct); results whose __class__ property or __getattribute__ raises each interrupt type or claims to be a dict; an async formatter and a payload-named coroutine, with warnings recorded; and two more steps in the injection property test, judging the result and closing a rejected generator. Removing any guard fails a test. Refs: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#485 (item A) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * fix(plugins): honor genuine interrupts and isolate all plugin logging Review of the previous commit found two remaining gaps, and two guards that no test pinned: - A KeyboardInterrupt or SystemExit delivered while a content_formatter failure was being described was absorbed. A real SIGINT, or a SIGTERM whose handler calls sys.exit while a log handler blocks on I/O, left the row written but the process running, unaware of the signal. - Only the formatter-failure warning ran while a stand-in exception was handled. Any other plugin warning, such as the parser's, could still have a failing handler print the exception the caller is handling, as ADK is when it runs error callbacks. Interrupts are now sorted by the code that raised them, because Python cannot tell a signal from a direct raise. The failed class's and the rejected result's own code runs only while the debug traceback is rendered and while a rejected generator is closed. Each of those steps has its own guard, and whatever it raises, interrupts included, is contained, so the content under redaction cannot end the agent run. Everywhere else in the boundary only plugin code and the application's log filters and handlers run, so a KeyboardInterrupt or SystemExit there came from a signal or from the application. _settle_formatter_outcome returns it as a new exception without text (a SystemExit keeps an int exit code), and _log_event raises it once the row has been handed to the writer. CancelledError stays contained: nothing in the boundary awaits, so it cannot be a real cancellation. The trade-off is that a signal landing while payload-controlled code runs is still absorbed. The module logger's handle() now runs every record's filters and handlers while a constant stand-in exception is handled, with its __context__ cleared. So no plugin log call can print the caller's exception through handleError, or through a handler that walks __context__ and ignores __suppress_context__. Records are unchanged: Logger._log resolves exc_info and the calling function before handle() runs. This replaces the stand-in around the formatter warning alone. The boundary's docstring now bounds its never-drop claim to failed or rejected results. An admitted str, dict, or list subclass goes on to the parser, whose boundary catches Exception only. Tests: - the injection property test expects an interrupt from any step but closing to be raised after the row, as a new exception, and checks that a rejected generator's cleanup never reaches the unraisable hook; - a real SIGINT and SIGTERM delivered while the warning is emitted; - a parse-failure warning with a closed handler, and with a handler that walks __context__, while the caller handles a payload exception; - the plugin's error logs keep their own exc_info; - supported results (None, a str subclass whose hooks raise, dict and list subclasses, and exact Content, Part, and LlmRequest) pass through unchanged. Removing any new guard fails a test. Refs: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#485 (item A) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * docs(plugins): note that closing a rejected coroutine is contained too The boundary's docstring said the rejected result's own code runs only while the debug traceback is rendered and while a rejected generator is closed. The same guard also covers closing a rejected coroutine, which runs the coroutine's own cleanup if it was started. Wording only. Refs: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#485 (item A) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> * feat: honor tool_thread_pool_config for sync tools outside live mode A synchronous function tool blocks the event loop while it runs, and RunConfig.tool_thread_pool_config, the setting that moves tools off the loop, only applied in live mode. With it set, run_async now runs a synchronous function tool's function on the tool thread pool when an LlmAgent calls the tool, while async tools and tools used directly as Workflow nodes stay on the event loop, and without it nothing changes. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 990376105 * fix: drop unpairable trailing FRs in rearrange Merge google#6752 Fixes google#6751 PiperOrigin-RevId: 990390762 * fix: replay a parallel tool call that never ran when a sibling answered When a resumed model turn had parallel calls and only some had a response, the resume decision treated one answer as covering the whole turn, so it continued to the model and the call that never ran was dropped. The decision now replays just the calls with no response, and only when the agent has written nothing since the call, so answered calls do not run a second time. Close google#7108 Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 990408003 * chore(scripts): detect added files through git only The new-file check read added files and commit messages from several version control systems. Contributors and CI use git through pre-commit, and jj's default colocated repositories already take the git path, so the rest only added code to maintain. Outside a git work tree the check now reports that it could not determine the added files. A `//`-prefixed .py path with no file behind it, the form Perforce depot paths take, is now refused. Co-authored-by: Xuan Yang <xygoogle@google.com> PiperOrigin-RevId: 990408500 * fix(tools): surface NodeTool failures to on_tool_error and return dict validation errors NodeTool swallowed every exception raised while running its node and returned a plain string, which the flow wrapped as {'result': '<string>'}. As a result: - on_tool_error callbacks (agent and plugin) never saw node failures, unlike every other BaseTool, and the original exception was lost behind the generic "Dynamic node <name> failed" wrapper. - Input validation errors reached the model as {'result': ...} instead of the {'error': ...} shape FunctionTool uses for argument validation errors. This change aligns NodeTool with FunctionTool: - Input schema validation errors return {'error': ...} with the same wording as FunctionTool, so the model can correct its arguments and retry. - When the node fails, the node's original exception is re-raised (chained from DynamicNodeFailError). The tool pipeline then runs on_tool_error callbacks with the real cause; if none handles it, the error propagates, as it does for FunctionTool. Node-level retry_config still applies first, inside run_node. Behavior change: an agent using a node as a tool without an on_tool_error callback now fails the run when the node fails, instead of passing an error string to the model. This matches FunctionTool. Co-authored-by: Shangjie Chen <deanchen@google.com> PiperOrigin-RevId: 990410996 * feat(mcp): add an opt-in modern-protocol connect path for MCP SDK 2.x ADK always brought a session up with `initialize()`, which pins the connection to the 2025 wire for its whole life even on SDK 2.x: the server issues an `Mcp-Session-Id` to route later requests back to one instance, and `clientInfo` is stated once rather than on each request. Setting `ADK_ENABLE_MCP_MODERN_PROTOCOL=1` probes `server/discover` first and falls back to the handshake on anything that is not a modern server, so a 2025-era server is unaffected. Off by default, and a no-op on SDK 1.x. Co-authored-by: Kathy Wu <wukathy@google.com> PiperOrigin-RevId: 990414661 * feat(workflow): propagate skip_summarization from node tools to tool response Propagate `ctx.actions.skip_summarization` from dynamically executed child nodes to the parent context in `run_node_internal`, and include `NodeTool` alongside `AgentTool` when attaching displayable tool output to `function_response` events with `skip_summarization=True`. This allows `@node` and `Workflow` tools to set `ctx.actions.skip_summarization = True` inside the node so their terminal output is emitted directly as the final user-visible text response without triggering a follow-up LLM summarization turn, while keeping `NodeTool` internal. Co-authored-by: Shangjie Chen <deanchen@google.com> PiperOrigin-RevId: 990434765 * fix(eval): skip content-less events when mapping Vertex multi-turn turns Invocations now keep the final event with its content removed so the efficiency metrics can read its token usage, and the Vertex multi-turn facade sent that event as an empty agent message in every turn. Skips intermediate events without content when mapping a turn. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 990461145 * fix: detect a dead MCP session whose transport sits behind a dispatcher MCP SDK 2.x moved the transport off the client session and behind a dispatcher, so ADK's liveness check read attributes that no longer exist and a pooled session whose server had died looked healthy forever, failing every later call. A session with no streams of its own is now checked through its dispatcher's closed flag, which restores the existing reconnect path on both SDK majors. Co-authored-by: George Weale <gweale@google.com> PiperOrigin-RevId: 990472674 * fix: only apply --avatar_config to live sessions requesting video The server-wide avatar configuration added to `adk web` and `adk api_server` was attached to every /run_live session, including the default audio-only ones. Avatars are rendered as video, so only set `RunConfig.avatar_config` when the client requests the VIDEO modality, and say so in the `--avatar_config` help text. Also adds a test for the unreadable avatar configuration file path. Co-authored-by: Liang Wu <wuliang@google.com> PiperOrigin-RevId: 990498163 * fix: follow redirects when downloading skills in GcpSkillRegistry Merge google#6824 PiperOrigin-RevId: 990507320 * test: cover api server auto create session Merge google#6786 PiperOrigin-RevId: 990538126 * feat: propagate grounding metadata from MCP _meta Merge google#7047 Fixes google#6081 PiperOrigin-RevId: 990543079 * docs: explain local lockfile needed by tox in adk-setup skill Merge google#7318 PiperOrigin-RevId: 990578226 * feat: let BigQuery tools run where CMEK is required Merge google#7232 Fixes google#3931 PiperOrigin-RevId: 990587308 * feat: add the model consult session context handover layer When a small executor model escalates a hard step to a larger advisor model, the advisor has to be told what has happened so far, or it answers a question it does not understand. This adds the layer that turns a session event log into contents the advisor can read: - tool calls and tool results are flattened into plain text, so a model that was never given those tool declarations can still follow them; - consecutive events from the same role are merged into one turn, which third-party advisor models require; - the transcript is held to a character budget by keeping the head and the tail, marking the omitted middle, and trimming the newest turn when it does not fit on its own, so one long turn cannot silently multiply the cost of a consult; - thoughts, media parts, per-part length and event count are each configurable, and the in-flight escalation call itself is skipped. The layer is not wired into a tool yet; that follows in a later change. Co-authored-by: Xuan Yang <xygoogle@google.com> PiperOrigin-RevId: 990610529 * feat(tools): invoke advisor models without tools for model_consult Invoke the advisor `BaseLlm` via `generate_content_async(req, stream=False)` with `config.tools = []` and `config.tool_config = None` so mid-task consultations return text guidance without entering a tool loop, while still emitting standard OpenTelemetry client duration and token usage metrics: - `resolve_advisor_llm` and `resolve_thinking_level` for model and thinking-level normalization - `call_advisor` with automatic fallback retry when `thinking_config` is rejected, `MAX_TOKENS` truncation and thought-exhaustion handling across `Gemini` and `LiteLlm`, and OpenTelemetry metric emission - `AdvisorResult`, `AdvisorUsage`, and `AdvisorError` Co-authored-by: Xuan Yang <xygoogle@google.com> PiperOrigin-RevId: 990613834 * feat(tools): add ModelConsultTool with turn and session budgets Add `ModelConsultTool`, an ADK tool that lets an executor `LlmAgent` consult a stronger advisor model mid-generation without relinquishing control of the conversation. Key capabilities: - Per-turn (`max_uses`) and session-wide (`session_max_uses`) consult budgets stored in session state (`temp:` and persistent state keys) with `has_remaining_budget` helper and per-session concurrency/delta coordination for parallel tool calls. - Automatic context handover via `build_advisor_contents` (with both `'events'` and `'transcript'` handover modes on `ModelConsultContextConfig`). - Forwards the executor's `static_instruction`, state-interpolated `canonical_instruction`, and non-self tool inventory (`canonical_tools`) to the advisor system instruction. - Graceful degradation on budget exhaustion (`status='limit_reached'`), missing question (`status='invalid_request'`), and advisor runtime or timeout errors (`status='error'`). - Top-level lazy export of `ModelConsultTool` from `google.adk.tools`. Co-authored-by: Xuan Yang <xygoogle@google.com> PiperOrigin-RevId: 990614577 * docs(tools): add ModelConsultTool developer guide and sample agent Adds the developer guide and runnable order-support refund policy sample for `ModelConsultTool`: - Adds the `ModelConsultTool` unit guide under `docs/guides/tools/model_consult/model_consult_tool/index.md` covering getting started, how mid-generation escalation works, `ModelConsultTool` and `ModelConsultContextConfig` options, custom context budgets, custom `BaseLlm` advisors, and limitations, and registers it in `docs/guides/README.md`. - Adds a runnable e-commerce order support sample under `contributing/samples/tools/model_consult/` demonstrating `get_order`, `get_customer_profile`, and `issue_refund` paired with `ModelConsultTool`. Co-authored-by: Xuan Yang <xygoogle@google.com> PiperOrigin-RevId: 990615455 * fix: isolate and clean up single_turn LlmAgent node_input events Merge google#7320 Fixes google#7227 PiperOrigin-RevId: 990632092 * refactor(tools): extract shared URL validation helpers into _url_validator.py Extract the SSRF and URL target validation helpers (`_parse_request_target`, `_is_blocked_hostname`, `_is_blocked_address`, `_embedded_ipv4`, `_resolve_direct_addresses`, and `_reject_blocked_proxied_hostname`) into `_url_validator.py`. Previously, `ComputerUseToolset._wrap_navigate_with_url_validation` lazily imported private helpers from `load_web_page` inside the wrapper function to avoid pulling `requests` into the computer-use import path. Moving the validation logic into `_url_validator.py` allows `load_web_page`, `ComputerUseToolset`, and other outbound HTTP tools to import the shared validation helpers directly at the module level without extra runtime dependencies. Test files that patched `load_web_page.socket` were updated after private helpers were pruned from the `load_web_page` namespace. Co-authored-by: Jason Zhang <jasoncz@google.com> PiperOrigin-RevId: 990692502 * fix(plugins): chain re-raised interrupts to nothing, look up handle per call Review of the previous commit found two small hardening gaps: - The KeyboardInterrupt or SystemExit set aside while a content_formatter failure was described is raised after the row with `from None`. That only sets __suppress_context__: Python still records the exception the caller is handling, such as the error ADK passes to an error callback, as its __context__, so code that walks __context__ could reach it and its text. It is now raised while a context-free stand-in is handled, so that stand-in is its only link. - The stand-in wrapper bound Logger.handle when the plugin was imported, so a later class-level patch of Logger.handle, as instrumentation and test fixtures apply, never saw this logger's records. The class's handle is now looked up on each call, still inside the stand-in. The content_formatter docstring also states the downstream effect plainly: the row's status is left as the event set it, usually 'OK', so a query that counts any non-NULL error_message as an error, such as the BigQuery Agent Analytics SDK's error predicate, counts a formatter failure as an error. Behavior is unchanged. Tests: the re-raised interrupt links to neither the caller's exception nor anything chained to it (KeyboardInterrupt and SystemExit), and a class-level patch of Logger.handle made after import sees the plugin's formatter warning, handled while the stand-in is. Both fail before this change. Refs: GoogleCloudPlatform/BigQuery-Agent-Analytics-SDK#485 (item A) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Co-authored-by: feiiiiii5 <feiiiiii5@users.noreply.github.com> Co-authored-by: George Weale <gweale@google.com> Co-authored-by: Aarav Mittal <137450929+a2105z@users.noreply.github.com> Co-authored-by: Xuan Yang <xygoogle@google.com> Co-authored-by: Shangjie Chen <deanchen@google.com> Co-authored-by: Kathy Wu <wukathy@google.com> Co-authored-by: Liang Wu <wuliang@google.com> Co-authored-by: Shinobu Aoki <aoki@codebee.jp> Co-authored-by: YASHcode-IIITV <yashrajsiwal@gmail.com> Co-authored-by: Chaitanya Laxman <chaitanyalaxman118@gmail.com> Co-authored-by: Arjun Ganesh <iarjunganesh@gmail.com> Co-authored-by: Vishal Bulbule <vishal.bulbule@techtrapture.com> Co-authored-by: Abhay Joshi <abhayjoshi@google.com> Co-authored-by: Jason Zhang <jasoncz@google.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to Issue or Description of Change
Problem: The setup skill says dependencies are pinned in
uv.lock, but thisrepository ignores that file. On a fresh checkout, the tox lock runner fails
with
Unable to find lockfile at uv.lockuntiluv synchas run.Solution: Explain that
uv synccreates a local lockfile and must run beforetox.Testing Plan
uv.lockis untracked and ignored by the repository.uv sync; after syncing, tox reachedthe pytest suite.
pre-commit run --files .agents/skills/adk-setup/SKILL.mdpassed.Checklist
CONTRIBUTING.mdand reviewed the change.