fix: migrate subagent tracing hook - #142
Conversation
Use the non-deprecated subagent_spawned lifecycle hook to create Opik subagent spans, preserving the metadata formerly captured during the legacy subagent_spawning hook. Co-Authored-By: Forge <noreply@openclaw.local>
| input: { | ||
| childSessionKey, | ||
| agentId: eventObj.agentId, | ||
| label: eventObj.label, | ||
| mode: eventObj.mode, | ||
| requester: eventObj.requester, | ||
| threadRequested: eventObj.threadRequested, | ||
| }, | ||
| metadata: { | ||
| status: "spawned", | ||
| requesterSessionKey, | ||
| childSessionKey, |
There was a problem hiding this comment.
delivery-target span reused as lifecycle
If childSessionKey was already used by subagent_delivery_target, subagent_spawned only updates the existing span's input and metadata, so it can stay recorded as subagent:delivery-target instead of the intended subagent:<agentId> lifecycle span — should we recreate or rename it here?
Want Baz to fix this for you? Activate Fixer
Other fix methods
Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
`src/service/hooks/subagent.ts` around lines 63-79 inside the
`deps.api.on("subagent_spawned", ...)` handler, the code reuses an existing span if one
exists (from earlier hooks like `subagent_delivery_target`) and only calls
`deps.safeSpanUpdate` for metadata, never recreating/renaming the span to the intended
`subagent:<agentId>` lifecycle semantics. Refactor this logic so that when
`subagent_spawned` fires and the current stored span was created for a different stage
(e.g., name/status mismatch), you end the old span (via the existing `deps.safeSpanEnd`
pattern if available), create a new span with `name: subagent:${agentId}` and the
intended `input` fields (childSessionKey, label, mode, requester, threadRequested),
replace `host.active.subagentSpans` and the remembered host association with the new
span, and then apply the `safeSpanUpdate` enrichment. Ensure the map always points at
the correct “spawned” span for that `childSessionKey` after this handler runs.
| import type { | ||
| OpenClawConfig, | ||
| OpenClawPluginApi, | ||
| OpenClawPluginDefinition, | ||
| } from "openclaw/plugin-sdk/plugin-entry"; | ||
| import { definePluginEntry, emptyPluginConfigSchema } from "openclaw/plugin-sdk/plugin-entry"; |
There was a problem hiding this comment.
The openclaw/plugin-sdk/plugin-entry and diagnostic-runtime imports in src/service.ts use APIs unavailable in the minimum >=2026.3.2, while only openclaw/plugin-sdk has local declarations, so a clean checkout without the optional openclaw peer fails tsc/npm run build and the plugin cannot load or opik configure cannot save configuration. Should we declare those subpaths locally, retain compatibility fallbacks, or raise the minimum/peer gateway version?
Want Baz to fix this for you? Activate Fixer
Other fix methods
Prompt for AI Agents
Before applying, verify this suggestion against the current code. In `index.ts` around
lines 1-6 (and 29-35), reconcile the OpenClaw SDK imports and `register` configuration
logic with the declared `>=2026.3.2` / `minGatewayVersion` support: the `plugin-entry`
APIs (`OpenClawPluginDefinition`, `definePluginEntry`, `current()`,
`mutateConfigFile()`) and the `diagnostic-runtime` import used in `src/service.ts`
(`DiagnosticEventPayload`) are not available on that runtime and are not resolvable via
local type declarations. Either add ambient declarations for the
`openclaw/plugin-sdk/plugin-entry` and `openclaw/plugin-sdk/diagnostic-runtime` subpaths
(or make the external peer SDK declarations an explicit build prerequisite, since Vitest
aliases only affect tests) so a clean `npm run build` succeeds, and provide
compatibility fallbacks using older load/write configuration APIs; if backward
compatibility isn't feasible, raise the peer and minimum gateway version requirements in
the package manifest to the first release providing all of these APIs.
| return proto === Object.prototype || proto === null; | ||
| } | ||
|
|
||
| export function sanitizeValueForOpik<T>(value: T): T; |
There was a problem hiding this comment.
Sanitizer returns invalid narrow types
The new sanitizeValueForOpik<T>(value: T): T overload claims identity even though sanitization rewrites nested strings and reconstructs arrays/plain objects, so a const value: "media:/tmp/x.png" result can be "media:<image-ref>" while callers still use it as the original literal — should we return a widened sanitized type or remove the identity overload?
Want Baz to fix this for you? Activate Fixer
Other fix methods
Prompt for AI Agents
Before applying, verify this suggestion against the current code. In
src/service/payload-sanitizer.ts around line 30, fix the `sanitizeValueForOpik` overload
because it promises the original type even though the implementation rewrites strings
and reconstructs nested arrays and plain objects. Remove the identity overload or
replace it with a sound widened/recursive sanitized return type, then update affected
call sites and tests so redacted string literals and precisely shaped or readonly
payloads are not treated as unchanged.
User description
Summary
api.on("subagent_spawning", ...)registration from the Opik OpenClaw plugin.subagent_spawnedhook instead, preserving label/requester/thread metadata.Risk: Medium — runtime observability hook behavior changes, but scope is limited to the Opik plugin subagent span lifecycle and covered by focused/full plugin tests.
Test plan
npm run test -- src/service.test.tsnpm run lintnpm run buildnpm run testnpm run smokenpm run typechecknpm run pack:checkGate and validation evidence
decision=proceed, artifact/tmp/forge-loop/2026-07-26T1000Z-dev-sprint/pre-pr-gate-opik-openclaw.jsonCo-Authored-By: Forge noreply@openclaw.local
Generated description
Below is a concise technical summary of the changes proposed in this PR:
graph LR plugin_("plugin"):::modified registerOpikCli_("registerOpikCli"):::modified OPENCLAW_CONFIG_index_ts_("OPENCLAW_CONFIG (index.ts)"):::modified runOpikConfigure_("runOpikConfigure"):::modified showOpikStatus_("showOpikStatus"):::modified OPENCLAW_CONFIG_src_configure_ts_("OPENCLAW_CONFIG (src/configure.ts)"):::modified registerHooks_("registerHooks"):::modified OPENCLAW_API_src_service_ts_("OPENCLAW_API (src/service.ts)"):::modified registerSubagentHooks_("registerSubagentHooks"):::modified OPENCLAW_API_src_service_hooks_subagent_ts_("OPENCLAW_API (src/service/hooks/subagent.ts)"):::modified OPIK_("OPIK"):::modified plugin_ -- "Passes current config and mutation callback instead of file I/O." --> registerOpikCli_ plugin_ -- "Reads current config and mutates via runtime API; restart required." --> OPENCLAW_CONFIG_index_ts_ registerOpikCli_ -- "Supplies currentConfig and mutateConfig callbacks for configuration updates." --> runOpikConfigure_ registerOpikCli_ -- "Status reads configuration through currentConfig instead of loadConfig." --> showOpikStatus_ runOpikConfigure_ -- "Uses current snapshot and mutation callback to update Opik settings." --> OPENCLAW_CONFIG_src_configure_ts_ showOpikStatus_ -- "Reads current OpenClaw configuration via currentConfig for status display." --> OPENCLAW_CONFIG_src_configure_ts_ registerHooks_ -- "Sanitizes any event.message value, returning it only when transformed." --> OPENCLAW_API_src_service_ts_ registerSubagentHooks_ -- "Handles spawned events, capturing label, requester, thread, and run metadata." --> OPENCLAW_API_src_service_hooks_subagent_ts_ registerSubagentHooks_ -- "Creates spawned-status spans with richer request and session/run metadata." --> OPIK_ classDef added stroke:#15AA7A classDef removed stroke:#CD5270 classDef modified stroke:#EDAC4C linkStyle default stroke:#CBD5E1,font-size:13pxMigrate Opik subagent tracing from the deprecated
subagent_spawninghook tosubagent_spawned, preserving lifecycle metadata and span enrichment. UpdateOpenClawPluginApi, configuration commands, tests, documentation, and SDK entry-point integrations for the supported plugin APIs.plugin-entryanddiagnostic-runtimeSDK surfaces, and migrate CLI configuration from whole-file writes tocurrentConfigplusmutateConfigFile.Modified files (11)
Latest Contributors(0)
subagent_spawned, retaining requester, label, thread, and run metadata while updating focused tests and event documentation.Modified files (4)
Latest Contributors(0)