Skip to content

feat: /app-info endpoint in rest server - #1404

Open
wojtas000 wants to merge 8 commits into
google:mainfrom
wojtas000:feat/app-info-endpoint
Open

feat: /app-info endpoint in rest server#1404
wojtas000 wants to merge 8 commits into
google:mainfrom
wojtas000:feat/app-info-endpoint

Conversation

@wojtas000

@wojtas000 wojtas000 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Problem

adk-go does not implement GET /apps/{app_name}/app-info. It is the last endpoint from the Agents CLI wire contract that Go is missing. Agents CLI needs it in agent evaluation: it is the call that tells the CLI what an
app contains (agents, instructions, tools) before an eval run.

Solution

We implement GET /apps/{app_name}/app-info returning an AppInfo: the app name, its root
agent, and a flat map of every agent reachable from that root with its
description, instruction, tools and child names. Nothing is executed - no
session, no model call.

Details worth knowing:

  • Every agent kind is included. Instruction and tools are read through the
    existing internal state seam (llminternal.Reveal) when present; agents that
    are not LLM agents report instruction: "" and tools: [], and their
    children are still walked.
  • Toolsets are resolved best effort, with a timeout, since an MCP toolset
    may do I/O. A toolset that fails is logged and skipped rather than failing the
    whole request.
  • Tools are reported as function declarations, matching adk-python: tools
    without a declaration (built-in Gemini tools such as Google Search, and
    request-shaping tools) are omitted.

Deliberate differences from adk-python

adk-python this PR
non-LLM root 400 "Root agent is not an LlmAgent"api_server.py#L1410-L1421 200, described
non-LLM sub-agents dropped, with their whole subtree — agent_info.py#L65-L69 (the isinstance guard wraps both the recursion and the name append) included
subAgents casing sub_agents (snake_case) — agent_info.py#L29-L34 subAgents, per the contract's "MUST strictly emit camelCase"
isComputerUse emitted — api_server.py#L636-L642 omitted — not in the contract, and Go has no computer-use toolset
language "python", hardcoded — api_server.py#L1415 "go"

Testing plan

  • go build -mod=readonly work
  • go test -race -mod=readonly -count=1 -shuffle=on work
  • golangci-lint run — 0 issues, both modules
  • go mod tidy -diff — clean, both modules

Also checked live against a server serving six apps (simple, tooled, nested,
toolset-backed, SequentialAgent-rooted, graph-Workflow-rooted) and diffed
field by field against adk-python's /app-info for the same apps. Every
remaining difference is one of the deliberate ones listed above.

Example response

GET /apps/travel_app/app-info for one root agent with two sub-agents:

{
  "name": "travel_app",
  "rootAgentName": "travel_concierge",
  "description": "Plans trips end to end.",
  "language": "go",
  "agents": {
    "travel_concierge": {
      "name": "travel_concierge",
      "description": "Plans trips end to end.",
      "instruction": "Delegate flight questions and hotel questions to your sub-agents.",
      "tools": [],
      "subAgents": ["flight_agent", "hotel_agent"]
    },
    "flight_agent": {
      "name": "flight_agent",
      "description": "Finds and books flights.",
      "instruction": "Search for flights matching the user's dates.",
      "tools": [
        {
          "functionDeclarations": [
            {
              "name": "search_flights",
              "description": "Finds flights between two airports.",
              "parametersJsonSchema": {
                "type": "object",
                "properties": {
                  "origin": {"type": "string"},
                  "destination": {"type": "string"}
                },
                "required": ["origin", "destination"],
                "additionalProperties": false
              }
            }
          ]
        }
      ]
    },
    "hotel_agent": {
      "name": "hotel_agent",
      "description": "Finds and books hotels.",
      "instruction": "Book a hotel for the requested city and dates.",
      "tools": [
        {
          "functionDeclarations": [
            {
              "name": "book_hotel",
              "description": "Books a hotel in a city for a number of nights.",
              "parametersJsonSchema": {
                "type": "object",
                "properties": {
                  "city": {"type": "string"},
                  "nights": {"type": "integer"}
                },
                "required": ["city", "nights"],
                "additionalProperties": false
              }
            }
          ]
        }
      ]
    }
  }
}

@wojtas000 wojtas000 changed the title feat: /app-info endpoint in adk rest server feat: /app-info endpoint in rest server Aug 26, 2026
@wojtas000
wojtas000 force-pushed the feat/app-info-endpoint branch from da6ce23 to f604cfe Compare August 26, 2026 12:30
@wojtas000
wojtas000 marked this pull request as ready for review August 26, 2026 12:56
tsTools, err := ts.Tools(toolsetCtx)
if err != nil {
log.Printf("app-info: agent %q: skipping toolset %q: %v", agentName, ts.Name(), err)
continue

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment for reviewer: is the continue behavior fine on error when loading tools from toolset? Another way would be to throw 500 on the HTTP response (even if only one toolset fails and the rest tools/toolsets succeed when loaded).

// toolsetResolveTimeout bounds the time spent resolving an agent's toolsets.
// Toolsets may reach out over the network (an MCP server, for example), and
// describing an app must not hang on one.
const toolsetResolveTimeout = 10 * time.Second

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Value of this constant was chosen arbitrarily. But 10 seconds for toolsetResolveTimeout means that the overall timeout could be 10s * N_Toolsets, where N_Toolsets is the number of toolsets in the whole agent tree. Mabye it should be shortened?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant