Repository navigation
Add annotateAgentManifest manual API to LLMObs SDK - #12318
gh-worker-dd-mergequeue-cf854d[bot] merged 7 commits into
Conversation
- Add AgentManifest immutable value class with Builder pattern in LLMObs.java - Add AgentTool immutable value class in LLMObs.java - Add AGENT_MANIFEST constant to LLMObsTags - Add annotateAgentManifest() default method to LLMObsSpan interface - Add comprehensive builder tests for AgentManifest and AgentTool Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Stores agent manifest fields (name, instructions, model, model_settings, tools) as an internal tag `_ml_obs_tag.agent_manifest`. Only applies to agent spans; warns and no-ops on other span kinds. Null manifest is silently ignored. Tools with null/empty names are skipped with a warning. A second call overwrites the previous manifest. Framework field "AgentObs SDK" is always added when any manifest fields are present. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add AGENT_MANIFEST_KEY byte constant, include the tag in TAGS_FOR_REMAPPING, and handle it in the meta serialization loop as a msgpack map. Add two tests: one verifying all manifest fields appear in meta, one verifying the tag does not leak into the tags list. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b5f56f11d6
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
ncybul
left a comment
There was a problem hiding this comment.
A couple minor suggestions but overall looks good to me! Would be nice to see a manual verification of setting the manifest via the SDK.
|
Hi! 👋 Thanks for your pull request! 🎉 To help us review it, please make sure to:
If you need help, please check our contributing guidelines. |
There was a problem hiding this comment.
More details
The default API method keeps compatibility. The implementation accepts manifests only for agent spans and writes them to meta.agent_manifest.
🤖 Datadog Autotest · Commit b5f56f1 · What is Autotest? · @DataDog review to ask questions · Any feedback? Reach out in #autotest
…test hardening - Change annotateAgentManifest to merge successive calls instead of overwriting: name/instructions/model use new-value-wins logic with fallbacks; model_settings shallow-merges; tools replace only when caller provides a non-empty list. - Change MANUAL_FRAMEWORK constant from "AgentObs SDK" to "manual". - Update all test assertions that expected "AgentObs SDK" to "manual". - Replace overwrite test with merge-semantics test; add model_settings merge test. - Tests for post-finish no-op and empty-tools-list were already present. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
sabrenner
left a comment
There was a problem hiding this comment.
one main comment a couple nits otherwise lgtm!
…domain/DDLLMObsSpan.java Co-authored-by: Sam Brenner <106700075+sabrenner@users.noreply.github.com>
…nce; update docstring Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
Build pipeline has failing jobs for 5fa0942: What to do next?
DetailsSince those jobs are not marked as being allowed to fail, the pipeline will most likely fail. |
|
/merge |
|
View all feedbacks in Devflow UI.
The expected merge time in
|
|
/merge |
|
View all feedbacks in Devflow UI.
PR already in the queue with status in_progress |
e149937
into
master
## Description
`LLMObs.annotate(agent=...)` and `annotation_context(agent=...)` accepted a mapping but only read `version`, so a manually declared agent rendered an empty manifest panel. This adds validated support for `name`, `instructions`, `model`, `model_settings` and `tools`. All of these already exist in `AgentManifest`, so there is no wire schema change.
```python
LLMObs.annotate(agent={
"version": "2.1.0",
"name": "travel_desk",
"instructions": "Book travel.",
"model": "gpt-4o",
"model_settings": {"temperature": 0.1, "max_tokens": 1024},
"tools": [{"name": "get_weather", "description": "Look up the weather.",
"parameters": {"city": {"type": "string", "required": True}}}],
})
```
Behavior:
- The manifest is emitted on agent spans only, under `_dd.agent_manifest`. `version` stays an `agent_version` tag. A version-only agent emits no manifest.
- `framework` is set to `"manual"` by the SDK.
- `name` defaults to the agent span's name; a declared `name` overrides it.
- An `annotation_context` declaration reaches every agent span in its block, as `agent_version` already does. `annotate(span=...)` declares whatever span it names.
- Each declaration is validated, then shallow-updates the manifest key by key, so repeated `annotate()` calls and nested `annotation_context` blocks compose. A value that is unset (`None`, `""`, `[]`, `{}`) or unreportable declares nothing rather than erasing an earlier declaration.
- Declared fields merge into an integration-built manifest instead of replacing it. The integration's `framework` is kept.
- Input is validated per field and bad values are dropped. `model_settings` is limited to `ALLOWED_MODEL_SETTINGS_KEYS`, so provider-specific keys such as `extra_headers` (which can carry secrets) are not reported. Tool `parameters` accept the documented `{param: {type, required}}` mapping or a JSON Schema object, flattened to the same shape the integrations emit, with `required` omitted when false.
- The builder never raises, so a malformed field cannot drop the span event.
Java equivalent: DataDog/dd-trace-java#12318.
## Testing
Unit tests in `tests/llmobs/test_integrations_utils.py` (builder validation, JSON Schema parameters) and `tests/llmobs/test_llmobs_service.py` (agent-only emission, outermost-span scoping, merge semantics including `model_settings`, unset values, name fallback, malformed input). `pydantic_ai`, `crewai` and `openai_agents` suites cover the integrations that share the manifest path.
Traces:
[baggage agent (nested manifest)](https://app.datadoghq.com/llm/traces?query=%40ml_app%3Amax-test%20%40event_type%3Aspan%20%40is_root_span%3Atrue&agg_m=count&agg_m_source=base&agg_t=count&fromUser=false&is_llm_session=false&refresh_mode=sliding&selectedTab=overview&sidepanelContextScopeKind=agent&sp=%5B%7B%22p%22%3A%7B%22eventId%22%3A%22AwAAAaDUVLWsIKRuAQAAABhBYURVVkxXc0FBQzJfOG5oNW1wNUFBQUEAAAAkZjFhMGQ0NTgtMjU0OC00YmViLWEyNDAtMzg1ZTliZGIxNTVhAADofg%22%7D%2C%22i%22%3A%22llm-obs-panel%22%7D%5D&spanId=18175047169571987787&start=1790265508007&end=1790269108007&paused=false)
[simple travel desk agent](https://app.datadoghq.com/llm/traces?query=%40ml_app%3Amax-test%20%40event_type%3Aspan%20%40is_root_span%3Atrue&agg_m=count&agg_m_source=base&agg_t=count&fromUser=false&is_llm_session=false&refresh_mode=sliding&selectedTab=overview&sidepanelContextScope=17920727384912341806&sidepanelContextScopeKind=agent&sp=%5B%7B%22p%22%3A%7B%22eventId%22%3A%22AwAAAaDUVLWsWXlvDQAAABhBYURVVkxXc0FBQnV2Y2kyN08xY0FBQUEAAAAkZjFhMGQ0NTgtMjU0OC00YmViLWEyNDAtMzg1ZTliZGIxNTVhAADofw%22%7D%2C%22i%22%3A%22llm-obs-panel%22%7D%5D&spanId=17920727384912341806&start=1790265508007&end=1790269108007&paused=false)
## Risks
Low. Additive to an existing argument; version-only usage is unchanged.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: mz1119 <max.zhang@datadoghq.com>
Summary
Adds
annotateAgentManifest(LLMObs.AgentManifest)to the Java LLMObs SDK, allowing users to manually declare an agent span's configuration (name, instructions, model, model_settings, tools). Mirrors the Python implementation (DataDog/dd-trace-py#19771) and follows theannotatePromptpattern from #12161.Changes
LLMObsTags.java— addsAGENT_MANIFEST = "agent_manifest"constantLLMObs.java— adds two public immutable builder classes:LLMObs.AgentTool— represents a single tool (name, optionaldescription, optionalparameters)LLMObs.AgentManifest— builder withname,instructions,model,model_settings,toolsLLMObsSpan.java— addsdefault void annotateAgentManifest(LLMObs.AgentManifest)(no-op default for backwards compat)NoOpLLMObsSpan.java— explicit@Overrideno-opDDLLMObsSpan.java— real implementation: validates span kind (agent only), builds manifest map, stores as_ml_obs_tag.agent_manifestLLMObsSpanMapper.java— addsagent_manifesttoTAGS_FOR_REMAPPING; serializes tometa.agent_manifestas a msgpack mapBehaviour
agentspan kind; other span kinds emit a log warning and no-opframeworkis set to"AgentObs SDK"automatically by the SDKnamedefaults to the span name if not providedmodel_settingskeys are forwarded as-is (no allowlist in this initial PR)Test plan
./gradlew :dd-trace-api:test --tests "datadog.trace.api.llmobs.LLMObsTest"— 27 tests pass (4 new)./gradlew :dd-java-agent:agent-llmobs:test --tests "datadog.trace.llmobs.domain.DDLLMObsSpanTest"— 39 tests pass (7 new)./gradlew :dd-trace-core:test --tests "datadog.trace.llmobs.writer.ddintake.LLMObsSpanMapperTest"— 18 tests pass (2 new)🤖 Generated with Claude Code