Skip to content

feat: add QueryAgentTool for the query tool type#2569

Open
ks93 wants to merge 5 commits intofeat/agents/add-runtime-versionfrom
feat/add-query-agent-tool
Open

feat: add QueryAgentTool for the query tool type#2569
ks93 wants to merge 5 commits intofeat/agents/add-runtime-versionfrom
feat/add-query-agent-tool

Conversation

@ks93
Copy link
Copy Markdown
Contributor

@ks93 ks93 commented Apr 16, 2026

Note

Stacked on #2568 — merge that first.

Summary

  • Adds first-class SDK support for the "query" agent tool type, which was previously deserialized as UnknownAgentTool
  • New classes: QueryAgentTool, QueryAgentToolUpsert, QueryAgentToolConfiguration
  • Configuration uses a flat data_models list (reusing DataModelInfo) with transparent API wrapping in dump/_load

Test plan

  • Unit tests added and passing (26 tests)
  • Verify round-trip fidelity: load → dump produces identical JSON
  • Verify auto-discovery: _AGENT_TOOL_CLS_BY_TYPE contains "query": QueryAgentTool

API not yet public, see
image
image

providedAtRuntime is not yet public.

@ks93 ks93 requested review from a team as code owners April 16, 2026 05:20
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the QueryAgentTool, QueryAgentToolConfiguration, and QueryAgentToolUpsert classes to the Agents API, enabling flexible queries against data models. The changes include comprehensive documentation examples and unit tests for the new tool types. A review comment identifies a potential TypeError in the QueryAgentToolConfiguration._load method when handling null values for the dataModels key in API responses and provides a suggestion to improve the robustness of the parsing logic.

Comment thread cognite/client/data_classes/agents/agent_tools.py
@ks93 ks93 force-pushed the feat/add-query-agent-tool branch from 5085319 to dda47b6 Compare April 16, 2026 05:58
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.76%. Comparing base (7210c03) to head (1d606a2).

Additional details and impacted files
@@                         Coverage Diff                         @@
##           feat/agents/add-runtime-version    #2569      +/-   ##
===================================================================
+ Coverage                            92.72%   92.76%   +0.04%     
===================================================================
  Files                                  480      480              
  Lines                                48314    48369      +55     
===================================================================
+ Hits                                 44798    44871      +73     
+ Misses                                3516     3498      -18     
Files with missing lines Coverage Δ
cognite/client/_api/agents/agents.py 100.00% <ø> (ø)
cognite/client/_sync_api/agents/agents.py 100.00% <ø> (ø)
cognite/client/data_classes/agents/__init__.py 100.00% <ø> (ø)
cognite/client/data_classes/agents/agent_tools.py 98.66% <100.00%> (+0.33%) ⬆️
.../test_data_classes/test_agents/test_agent_tools.py 98.64% <100.00%> (+0.21%) ⬆️

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ks93 ks93 added the waiting-for-risk-review Waiting for a member of the risk review team to take an action label Apr 16, 2026
Comment thread cognite/client/_api/agents/agents.py Outdated
Comment thread cognite/client/data_classes/agents/agent_tools.py Outdated
def _load(cls, resource: dict[str, Any]) -> QueryAgentToolConfiguration:
# API always returns dataModels, but guard against null defensively:
dm_config = resource.get("dataModels") or {}
data_models = [DataModelInfo._load(dm) for dm in (dm_config.get("dataModels") or [])]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is the payload really ["dataModels"]["dataModels"]?

Copy link
Copy Markdown
Contributor Author

@ks93 ks93 Apr 16, 2026

Choose a reason for hiding this comment

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

Yes — it's a discriminated union in the API. The outer dataModels is an object with a type field ("manual" or "providedAtRuntime" (internal for now)), and when manual, it contains an inner dataModels array:

"configuration": {
    "dataModels": {
        "type": "manual",
        "dataModels": [
            {
                "space": "cdf_idm",
                "externalId": "CogniteProcessIndustries",
                "version": "v1",
                "viewExternalIds": ["CogniteAsset"]
            }
        ]
    },
    "instanceSpaces": {"type": "manual", "spaces": ["my_space"]}
}

Confirmed in cog-ai — see e.g. QueryToolConfigurationDTOQueryToolManualDataModelsDTOlist[QueryToolDataModelItemDTO].

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.

@haakonvt how would you shape this instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

😉

Comment on lines +231 to +232
def as_write(self) -> QueryAgentToolConfiguration:
return self
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The load method implies this is the response version, not the write version: "# API always returns dataModels, but guard against null defensively:"

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.

What do you mean?


@dataclass
class QueryAgentTool(AgentTool):
"""Agent tool for running flexible queries against data models.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you give me a link to the documentation for this tool? Would make it simpler to verify e.g. required fields and so on.

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.

Documentation? :hide:

It's not yet publicly documented. Adding screenshots of local docs in PR desc.

Comment thread cognite/client/data_classes/agents/agents.py
Comment thread tests/tests_unit/test_api/test_agents.py
Comment thread tests/tests_unit/test_data_classes/test_agents/test_agent_tools.py Outdated
ks93

This comment was marked as outdated.

@ks93 ks93 changed the base branch from master to feat/agents/add-runtime-version April 16, 2026 07:08
ks93 added 3 commits April 16, 2026 00:09
The cog-ai backend and Fusion frontend already support the "query" tool
type, but the Python SDK deserialized it as UnknownAgentTool. This adds
first-class support with QueryAgentTool, QueryAgentToolUpsert, and
QueryAgentToolConfiguration classes.
Remove maturity label from docstring examples and surface missing
dataModels key instead of silently defaulting to empty dict.
@ks93 ks93 force-pushed the feat/add-query-agent-tool branch from 9da3c4d to 6acddf4 Compare April 16, 2026 07:11
ks93 added 2 commits April 16, 2026 00:13
Covered automatically by tests/tests_unit/test_base.py.
Covered by automatic load/dump tests in test_base.py. Keep only
test_load_without_configuration for the None config edge case.
@ks93 ks93 requested a review from haakonvt April 16, 2026 07:34
@haakonvt haakonvt removed the waiting-for-risk-review Waiting for a member of the risk review team to take an action label Apr 16, 2026
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.

2 participants