Skip to content

feat(utee): Phase 1 observability pass-through adapter layer#46

Merged
dgarson merged 3 commits intoobservability/mainfrom
sandy/utee-phase1-observability
Feb 22, 2026
Merged

feat(utee): Phase 1 observability pass-through adapter layer#46
dgarson merged 3 commits intoobservability/mainfrom
sandy/utee-phase1-observability

Conversation

@dgarson
Copy link
Owner

@dgarson dgarson commented Feb 22, 2026

Summary

Implements UTEE (Unified Tool Execution Envelope) Phase 1: observability pass-through adapter.

All 3 blocking issues from Tim's Phase 1 review have been resolved:

  • ✅ Runtime wrap-toggle bug — toggle wiring fixed; tools created while disabled pick up enable/disable correctly (test: should wrap tools created while disabled and pick up enable later)
  • ✅ Config-init wiring gap — initUteeFromConfig wired in server.impl.ts; updateUteeFromConfig wired in server-reload-handlers.ts
  • ✅ AsyncLocalStorage import robustness — ESM-safe lazy import with import() fallback pattern

What's in Phase 1 (strictly pass-through)

  • UTEE adapter wraps tool calls at dispatch layer — zero behavior change
  • Generates requestId and traceId per invocation
  • Emits structured logs: utee_tool_invocation, utee_tool_result
  • In-memory metrics: invocation count, error count, avg/max duration by tool
  • Feature flag default-off (uteeEnabled = false)
  • Hot-reload support (no gateway restart needed to toggle)
  • Runtime toggle: enableUtee() / disableUtee()

What is NOT in Phase 1

  • No retry/idempotency (Phase 3)
  • No capability negotiation (Phase 4)
  • No error classification changes (Phase 2)

Test Results

28/28 tests passing:

✓ src/agents/utee-adapter.test.ts (28 tests) 280ms

Critical tests:

  • should start disabled
  • should pass through when UTEE is disabled
  • should wrap tools created while disabled and pick up enable later ✅ (runtime toggle fix)
  • should add minimal overhead when enabled (<1ms per call)

Rollout Plan (from canary readiness doc)

Phase 1 canary: 5% of sessions / 48h
Rollback: set utee.enabled = false, hot-reloads without restart
Success criteria: P95 latency overhead <5ms, no error rate increase

Files Changed

  • src/agents/utee-adapter.ts (547 lines) — main adapter
  • src/agents/utee-init.ts (33 lines) — config initialization
  • src/agents/utee-adapter.test.ts (381 lines) — test suite
  • src/agents/pi-tool-definition-adapter.ts — tool wrapping integration
  • src/config/types.utee.ts — config types
  • src/config/zod-schema.utee.ts — config schema
  • src/gateway/server.impl.ts — startup wiring
  • src/gateway/server-reload-handlers.ts — hot-reload wiring
  • src/gateway/config-reload.ts — reload rule

Canary readiness doc: sandy/utee-phase1-canary-readiness.md

Spec: tim/memory/2026-02-21-utee-notes.md

Implements UTEE Phase 1 with the following scope:
- Observability pass-through adapter layer for tool execution
- Auto-generate/propagate requestId + traceId/spanId metadata
- Structured logs for tool invocations
- Basic metrics hooks/counters (invocation count, error count, duration)
- Feature flag to enable/disable Phase 1 path

Guardrails maintained:
- No behavior changes to existing tool result/error payloads
- No retry/idempotency/capability negotiation
- Minimal blast radius (additive only)
- Rollback switch works (utee.enabled config flag)

Files added:
- src/agents/utee-adapter.ts: Core UTEE adapter implementation
- src/agents/utee-init.ts: Config initialization
- src/agents/utee-adapter.test.ts: Unit tests (26 tests passing)
- src/config/types.utee.ts: UTEE config types
- src/config/zod-schema.utee.ts: UTEE zod schema

Files modified:
- src/agents/pi-tool-definition-adapter.ts: Integrate UTEE wrapper
- src/config/types.openclaw.ts: Add utee config property
- src/config/zod-schema.ts: Add UTEE schema import and field
Fixes from architectural review:

1. Feature-flag bug at tool wrapping site:
   - Changed pi-tool-definition-adapter.ts to always wrap tools with UTEE
   - Wrapper now checks isUteeEnabled() at invocation time, not definition time
   - This fixes runtime enable-after-start scenarios

2. Config init not wired into runtime:
   - Added initUteeFromConfig() call in gateway startup (server.impl.ts)
   - Added updateUteeFromConfig() call in config hot reload (server-reload-handlers.ts)
   - Added 'utee' prefix to config reload rules (kind: none, no restart needed)

3. AsyncLocalStorage loading unreliable in ESM:
   - Replaced dynamic require('async_hooks') with createRequire pattern
   - Uses node:module createRequire for synchronous loading in ESM
   - Maintains graceful fallback for non-Node environments

4. Phase-1 blast radius check:
   - Diff is minimal: 6 files, 83 insertions, 14 deletions
   - Added 2 new tests proving runtime toggle works correctly

Tests: 28 tests pass including 2 new runtime toggle tests
- Move createRequire import to top-level ESM imports
- Use node:async_hooks protocol for consistency
- Avoids undefined require in pure ESM environments
@dgarson
Copy link
Owner Author

dgarson commented Feb 22, 2026

Tim architecture review complete — sign-off granted for UTEE Phase 1.

✅ Blocking issues from prior review are resolved:

  1. Runtime wrap-toggle bug fixed (tools always wrapped; flag checked at invocation time)
  2. Config-init wiring fixed (initUteeFromConfig on startup + updateUteeFromConfig on reload)
  3. AsyncLocalStorage loading hardened for ESM (createRequire + node:async_hooks)

✅ Guardrails still hold:

  • default-off feature flag (utee.enabled)
  • pass-through result/error behavior unchanged
  • no retry/idempotency/capability features in this phase

✅ Local validation in /Users/openclaw/worktrees/review-pr46:

  • npx vitest run --config vitest.unit.config.ts src/agents/utee-adapter.test.ts
  • Result: 28/28 passing

From architecture perspective: ready for 5%/48h canary once CI is green.

@dgarson dgarson changed the base branch from main to observability/main February 22, 2026 05:50
dgarson added a commit that referenced this pull request Feb 22, 2026
…Editor (Piper)

AgentScheduler: 7 seed schedules, list+calendar toggle, master/detail, run now/edit/delete
TokenLedger: 10 ledger entries, cost by agent+model breakdown, 7-day bar chart
ThemeEditor (Piper): preset themes, live preview panel, CSS var export; fixed TS errors

Sprint total: 47 views
@dgarson dgarson merged commit cb229a6 into observability/main Feb 22, 2026
2 of 9 checks passed
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