OpenHands / OpenHands/enterprise
[Bug]: get git repo identity reliably into Laminar traces
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 4
- Forks
- 2
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 101
Description
Goal
Laminar traces should reliably carry git repo/branch/commit identity for any conversation that ends up touching a repo — not just conversations where a repo was pre-selected at creation. Today they don't, for two compounding reasons below. Both need fixing to actually achieve this.
Problem 1: the metadata that IS collected gets silently discarded (mechanical bug)
In openhands/app_server/app_conversation/live_status_app_conversation_service.py, the observability_metadata dict built by _build_observability_context (added in OpenHands/OpenHands#14431) is immediately overwritten two lines later by a reassignment from _build_observability_metadata (added in OpenHands/OpenHands#15059) — at both conversation-request builders (the regular OpenHands path and the ACP path). Only observability_tags from the first call survives.
_build_start_conversation_request_for_user (~line 1801):
observability_metadata, observability_tags = self._build_observability_context(
conversation_id,
agent_kind='openhands',
selected_repository=selected_repository,
selected_branch=selected_branch,
git_provider=git_provider,
)
...
observability_metadata = await self._build_observability_metadata( # <-- clobbers the line above
remote_workspace,
project_dir,
selected_repository,
selected_branch,
git_provider,
)
create_kwargs: dict[str, Any] = {'agent': agent, 'user_id': laminar_user_id}
if observability_metadata:
create_kwargs['observability_metadata'] = observability_metadata
if observability_tags:
create_kwargs['observability_tags'] = observability_tags
The identical pattern repeats in _build_acp_start_conversation_request (~line 2057-2097) for the ACP path.
_build_observability_context's metadata dict (app, conversation_id, agent_kind, repo_name, selected_branch, git_provider) is computed and then thrown away — it never reaches create_kwargs['observability_metadata']. Only its tags return value (app:openhands, agent_kind:..., repo:..., branch:..., git_provider:...) makes it through. The observability_metadata actually sent to Laminar ends up exclusively _build_observability_metadata's output (repo, branch, git_provider, commit), missing app/conversation_id/agent_kind.
Problem 2: even fixed, metadata only exists for repo-preselected conversations
_build_observability_metadata's repo/branch/git_provider/commit are all derived from selected_repository/selected_branch — the structured field passed at conversation creation (repo-picker flow). For a conversation started from scratch where the agent clones a repo itself in response to a chat message (selected_repository: null at creation — confirmed the dominant real-world flow via production trace analysis on infra#1454), this metadata stays empty for the whole conversation, even after the agent has cloned and is actively working in a repo. Fixing Problem 1 alone does not close this gap — most real conversations would still show no git identity in Laminar.
Suggested fix
- Immediate: merge the two metadata dicts instead of one clobbering the other (e.g.
metadata = {**context_metadata, **resolved_metadata}, or fold_build_observability_context'sapp/conversation_id/agent_kindfields into_build_observability_metadataand drop the duplicate call), at both call sites. - To actually meet the goal: populate/update git identity for conversations where the repo shows up after conversation start. Laminar metadata is currently only set once, at trace/request creation. Two directions worth weighing:
- Reuse the live git-probe the workspace-archive endpoint already does (
software-agent-sdk#3932,GET /api/file/archive'sX-Archive-Repo-Remote/-Branch/-Head-Commitheaders) to backfill/update trace metadata at archive time (pause/delete) — the only point today that already does a live probe outside of pre-agent setup. - Or hook into the agent's action/event stream to detect the first
git clone/repo materialization and update trace metadata then — more general, more invasive.
- Reuse the live git-probe the workspace-archive endpoint already does (
Introduced by OpenHands/OpenHands#14431 landing on top of OpenHands/OpenHands#15059 (merged 2026-07-01 / 2026-07-09 respectively); Problem 1 didn't exist before either PR individually. Problem 2 predates both — OpenHands/OpenHands#15059 already had it, OpenHands/OpenHands#14431 didn't change it.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in openhands/app_server/app_conversation/live_status_app_conversation_service.py, reading _build_observability_context, _build_observability_metadata, _build_start_conversation_request_for_user, and _build_acp_start_conversation_request. Compare both request builders and inspect the GET /api/file/archive live git-probe headers. Done means Laminar retains the combined metadata and receives git identity for repositories discovered after conversation creation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- observability
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100