Skip to content

feat: builtin tools redesign — factories + ctx + setTools push#58

Merged
uchouT merged 19 commits intomainfrom
feat/builtin-tools-redesign
Apr 27, 2026
Merged

feat: builtin tools redesign — factories + ctx + setTools push#58
uchouT merged 19 commits intomainfrom
feat/builtin-tools-redesign

Conversation

@uchouT
Copy link
Copy Markdown
Collaborator

@uchouT uchouT commented Apr 27, 2026

Summary

Redesign of how built-in tools (stello_create_session, activate_skill) are embedded, and a real bug fix: their descriptions never reached the LLM under the old auto-injection model.

The bug. Engine internally built a CompositeToolRuntime containing built-ins + user tools, but only exposed it via engine.executeTool / engine.getToolDefinitions. Session.send injected tools to the LLM from a list captured at loadSession time, and the engine never pushed its composite into the session. Net effect: in any production config the LLM never saw stello_create_session or activate_skill and so never called them.

The redesign. Built-in and user tools are now isomorphic ToolRegistryEntry objects. Users register exactly what they want exposed:

- tools: new ToolRegistryImpl()  // built-ins were auto-injected (broken)
+ tools: new ToolRegistryImpl([
+   createSessionTool(),         // opt-in
+   activateSkillTool(skills),   // opt-in
+ ])

All tool execute receives ctx: { agent, sessionId, toolCallId?, toolName }. The Engine pushes union(session.tools, capabilities.tools) to the session at construction and after every forkSession() via a new setTools mutator. The bug fix flows naturally from the new model — single source of truth for "what the LLM sees" is the registry.

Breaking changes

  • ToolRegistryEntry.execute now requires a ctx: ToolExecutionContext parameter
  • Removed: createBuiltinToolEntries, CompositeToolRuntime, engine/builtin-tools.ts, Engine.executeCreateSession
  • Removed re-export of createSessionTool from @stello-ai/session (legacy duplicate that bypassed Engine editing/profile/SplitGuard); the new createSessionTool from @stello-ai/core is the replacement
  • Session / MainSession / EngineRuntimeSession gained required tools getter + setTools mutator (additive but type-required — custom Session-shaped wrappers must forward both members)

Versions: @stello-ai/core 0.6.1 → 0.7.0, @stello-ai/session 0.5.1 → 0.6.0.

Test plan

  • pnpm -r test: 270 core / 127 session (6 env-gated skipped) / 15 devtools — all green
  • pnpm -r build: all packages compile
  • New regression test packages/core/src/__tests__/builtin-tools-llm-exposure.test.ts asserts LLM complete receives tool descriptions through the full chain (registry → engine push → session.setTools → session.send → llm.complete)
  • Demo demo/stello-agent-chat/chat-devtools.ts migrated to new factory API; wrapper objects forward setTools

uchouT added 19 commits April 26, 2026 22:13
- Add unionByName helper for merging tool lists by name (override wins)
- StelloEngineImpl.pushToolsToSession() builds session-compatible tool list
  from this.tools and unions with session.tools, then forwards to setTools
- Constructor pushes after this.tools is assigned (initial sync to session)
- forkSession captures child runtime from session.fork() and pushes to it
  (so newly forked sessions advertise engine-level tools to the LLM)
- Add unit tests for unionByName + integration tests for engine push behavior
- Update existing session stubs in agent / fork-compress / engine-factory
  tests to provide setTools (now required by EngineRuntimeSession contract)
Task 10 of builtin-tools redesign. The factory returns a
ToolRegistryEntry whose execute closure resolves agent.forkSession at
call time and reads agent.profiles dynamically for profile validation —
no external state captured, so the factory takes no parameters.

Framework adjustments:
- ForkProfileRegistry: add has(name) for cheap profile membership check
  (used by the new tool's runtime profile validation).
- core/index.ts: export createSessionTool from ./builtin-tools and
  remove the legacy re-export from @stello-ai/session (name collision;
  the session-package version is superseded by this factory).
…reateSessionTool

- Delete packages/core/src/engine/builtin-tools.ts (schema gen moved to factory)
- Delete createBuiltinToolEntries and CompositeToolRuntime (engine no longer composites)
- Delete packages/session/src/tools/create-session-tool.ts (bypassed Engine editing)
- Delete obsolete tests; un-skip and rewrite buildSessionToolList tests
- Drop activate_skill auto-injection skill-filter tests (no longer applicable)
…ssion

The Session and MainSession interfaces gained tools getter + setTools
mutator (required, not optional). The demo's local wrappers must forward
both members so the Engine's pushToolsToSession can update the underlying
real Session at runtime.

Fixes runtime error: 'session.setTools is not a function' in devtools demo.
- Replace 'as any' test stubs with 'as never' (no-explicit-any rule)
- Drop unused 'vi' / 'ForkProfileRegistryImpl' imports
- Drop unused '_ctx' param in activateSkillTool
CI runs strict tsc --noEmit; vitest/tsup were lenient and missed:
- builtin-tools-llm-exposure.test.ts: cast Session→SessionCompatible at
  adaptSessionToEngineRuntime boundary (Session.fork's context union
  excludes 'compress'; applyCompressContext resolves it before reaching
  session.fork, so the cast is runtime-safe).
- session-runtime.test.ts: add setTools stub to 4 SessionCompatible mocks.
- fork-compress.test.ts + default-engine-factory.test.ts: add agent stub
  to StelloEngineOptions / DefaultEngineFactoryOptions test fixtures.
@uchouT uchouT merged commit 7aac12e into main Apr 27, 2026
2 checks passed
@uchouT uchouT deleted the feat/builtin-tools-redesign branch April 28, 2026 19:10
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