Skip to content

feat(intelligence): wire canonical runs to the SDK — hooks, recordTrace, effort compiler#287

Merged
drewstone merged 3 commits into
mainfrom
feat/intelligence-canonical-wiring
Jun 14, 2026
Merged

feat(intelligence): wire canonical runs to the SDK — hooks, recordTrace, effort compiler#287
drewstone merged 3 commits into
mainfrom
feat/intelligence-canonical-wiring

Conversation

@drewstone

Copy link
Copy Markdown
Contributor

Close the four small wiring gaps from the unification audit so a canonical runPersonified run observes and ships through the Intelligence SDK in one line. Reuse-first: no new primitive on either side.

The four gaps (file:line)

  1. runPersonified subscribes to the Supervisor streamRunPersonifiedOptions.hooks?: RuntimeHooks (src/runtime/personify/types.ts:245) forwarded into supervisorOpts.hooks (src/runtime/personify/persona.ts:152). The Supervisor already threads opts.hooks into the root Scope (supervisor.ts:130), which already emits agent.spawn/agent.child (scope.ts:~219,345). The load-bearing one-liner — no kernel change.

  2. recordTrace(events) emits loop topology, not a flat spanIntelligenceClient.recordTrace (src/intelligence/index.ts) builds a nested loop → round → iteration OTLP span tree via the existing buildLoopOtelSpans into one traceId. No second span builder.

  3. compileEffort makes EffortPolicy gate at runtimecompileEffort(EffortSettings) (src/intelligence/effort.ts) is a pure compiler to run-config overrides (withAnalyst / fanout / withLoops / intelligenceBudgetUsd). No if (effort) scattered into the supervise kernel.

  4. OFF/eco degrade, not throw — gated at the EffortPolicy layer: analysts:false ⇒ withAnalyst:false ⇒ the caller omits the analyst, so the dormant empty-findings path runs and the base agent still works. The product fail-closed ("don't construct the analyst") stays separate from the experiment fail-closed inside createScopeAnalyst ("hard abort"), which is untouched.

How each reused an existing primitive

  • Gap 1 → SupervisorOpts.hooks + the Scope agent.spawn/agent.child stream (already shipped).
  • Gap 2 → buildLoopOtelSpans (the shipped topology builder) + createOtelExporter.exportSpan.
  • Gap 3/4 → the existing EffortSettings shape; the compiler is pure data, the caller reads it once.

Tests (reused harnesses)

  • tests/loops/personify.test.ts: runPersonified({hooks}) forwards agent.spawn/agent.child to a mock hook (and stays silent with no hooks).
  • src/intelligence/intelligence.test.ts: recordTrace produces the loop/loop.round/loop.iteration tree under one traceId (asserting buildLoopOtelSpans, not a flat per-event builder); compileEffort maps off ⇒ no-analyst/fanout-1, eco ⇒ analyst-on/no-breadth, standard ⇒ analyst-on/breadth/loops.

npx tsc --noEmit + Biome clean; full pnpm test green (886 pass, 0 fail).

Note on base: branched from feat/analyst-steer-wire per the brief; targeting main because that branch's work is already merged there (#284). Merges cleanly into origin/main.

…peAnalyst

Thread an optional ScopeAnalyst<D> through ShapeContext / RunPersonifiedOptions
/ createShapeContext, and consult it at the two combinator steer gates
(loopUntil.until, widen.gate.decide) instead of the hardcoded empty findings
array. The analyst spawns into the SAME scope (createScopeAnalyst), so its
compute stays on the conserved budget pool — equal-k holds by construction.
Absent an analyst the gates keep the dormant [] default (no behavior change).

Add registryScopeAnalyst: a ScopeAnalyst backed by an AnalystRegistryLike that
merges N analyst kinds into one findings list and pipes them through the same
assertTraceDerivedFindings firewall createScopeAnalyst uses (single-sourced
selector≠judge). The ScopeAnalyzeInput→registry-inputs projection is
caller-supplied (buildInputs), not an invented bridge.
…ce, effort compiler

Close the four small wiring gaps so a canonical runPersonified run observes and
ships through the Intelligence SDK without a new primitive on either side.

1. runPersonified can subscribe to the Supervisor stream. Add `hooks?: RuntimeHooks`
   to RunPersonifiedOptions and forward it into supervisorOpts.hooks. The Supervisor
   already threads opts.hooks into the root Scope, which already emits agent.spawn /
   agent.child — this is the load-bearing one-liner, no kernel change.

2. recordTrace(events) on the IntelligenceClient builds a nested loop -> round ->
   iteration OTLP span tree via the EXISTING buildLoopOtelSpans into one traceId. No
   second span builder; the topology a viewer renders matches the kernel's.

3. compileEffort(EffortSettings) in intelligence/effort.ts is a pure compiler from the
   effort policy to run-config overrides (withAnalyst / fanout / withLoops /
   intelligenceBudgetUsd). No `if (effort)` leaks into the supervise kernel.

4. OFF/eco degrade by construction: at analysts:false the caller omits the analyst
   (withAnalyst:false) so the dormant empty-findings path runs and the base agent still
   works. The product fail-closed ("don't construct the analyst") stays separate from
   the experiment fail-closed inside createScopeAnalyst ("hard abort"), which is untouched.

Tests: runPersonified({hooks}) forwards agent.spawn/agent.child to a mock hook;
recordTrace produces the loop/round/iteration tree (asserting buildLoopOtelSpans, not a
flat builder) under one traceId; compileEffort maps off -> no-analyst/fanout-1,
standard -> analyst-on. Full suite green (886).
tangletools
tangletools previously approved these changes Jun 14, 2026

@tangletools tangletools left a comment

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.

✅ Auto-approved PR — 6b5e83ef

Blanket team auto-approval is enabled for this reviewer service.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.

tangletools · auto-approval · reason: blanket_auto_approve · 2026-06-14T01:03:34Z

# Conflicts:
#	src/runtime/personify/types.ts

@tangletools tangletools left a comment

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.

✅ Auto-approved PR — 9d2bc175

Blanket team auto-approval is enabled for this reviewer service.
The full PR reviewer audit still runs separately and will publish findings if it detects issues.

tangletools · auto-approval · reason: blanket_auto_approve · 2026-06-14T01:13:15Z

@drewstone drewstone merged commit 14eae44 into main Jun 14, 2026
1 check 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.

2 participants