Skip to content

feat: emit session_ready & tools_resolve lifecycle events#113

Open
NovusEdge wants to merge 2 commits into
tintinweb:masterfrom
engrammic-ai:feat/session-ready-event-clean
Open

feat: emit session_ready & tools_resolve lifecycle events#113
NovusEdge wants to merge 2 commits into
tintinweb:masterfrom
engrammic-ai:feat/session-ready-event-clean

Conversation

@NovusEdge

@NovusEdge NovusEdge commented Jun 23, 2026

Copy link
Copy Markdown

Summary

Add two new lifecycle events that enable extensions to integrate properly with subagent sessions:

  1. subagents:session_ready - Fires when an agent's session is created and ready
  2. subagents:tools_resolve - Fires before session creation to allow tool injection

Motivation

Extensions like memory/context systems need to:

  1. Attach state to the subagent's session when it starts
  2. Inject additional tools (e.g., memory tools) into subagent sessions
  3. Access the session object to inject context or track activity
  4. Clean up when the agent completes

Currently, the existing events (subagents:started, subagents:completed) don't expose the session object or allow tool injection, making this impossible without relying on internal APIs.

Changes

  • Emit subagents:session_ready event in agent-manager.ts right after onSessionCreated fires
  • Emit subagents:tools_resolve event in agent-runner.ts before session creation
  • Add onToolsResolve callback option to SpawnOptions and RunOptions
  • Update README to document the new events

Event Payloads

session_ready

{
  id: string;            // agent ID
  type: string;          // subagent type (Explore, Plan, etc.)
  session: AgentSession; // the session object
  record: AgentRecord;   // full record for metadata
}

tools_resolve

{
  type: string;    // subagent type
  tools: any[];    // mutable array - push to inject tools
  agentId: string; // agent ID
}

Use Cases

Context propagation (session_ready)

pi.events.on("subagents:session_ready", ({ id, type, session, record }) => {
  const childHarness = parentHarness.fork({ mode: 'fork', tagPrefix: type });
  session.veilHarness = childHarness;
  trackForMerge(id, childHarness);
});

Tool injection (tools_resolve)

pi.events.on("subagents:tools_resolve", (event) => {
  const veilTools = parentHarness.getTools();
  event.tools.push(...veilTools);
});

Backward Compatibility

This is purely additive - existing code is unaffected. Extensions can opt-in to the new events.

Add a new lifecycle event that fires when an agent's session is created
and ready for use. This enables extensions that need to attach state to
subagent sessions (memory systems, context managers, telemetry) to do so
cleanly without relying on internal APIs.

Event payload:
- id: agent ID
- type: subagent type (Explore, Plan, etc.)
- session: the AgentSession object
- record: the full AgentRecord for metadata

Use case: Memory/context systems like Veil that fork parent context for
subagents and merge findings back on completion.
Allows extensions to inject additional tools into subagent sessions
before they are created. Two mechanisms:

1. SpawnOptions.onToolsResolve callback - per-spawn tool injection
2. subagents:tools_resolve event - global hook for all spawns

The event payload includes a mutable `tools` array that extensions
can modify to add their own tools (e.g., memory/context tools).

Use case: Veil injects veil_recall, veil_remember, etc. into subagents
so they can use the parent's context system.

Event fires after built-in tool filtering but before session creation.
@tintinweb

Copy link
Copy Markdown
Owner

I think I need to look a little deeper into this. for example the tools injection. question is if this should be done on subagent creating. also, do we want to all all connected extensions to mess with the subagents. session_ready might be easier to land. also we should probably just emit copies of the session/record. I want to be a bit careful on how low-level connected extensions can go. 🤔

@NovusEdge

NovusEdge commented Jul 1, 2026

Copy link
Copy Markdown
Author

Hmm fair point. I think I have a proposal in that case.

For session_ready, I can update it to emit frozen copies instead of live objects. That should be safe to land.

For tools_resolve, I do need something like it. veil needs to inject context tools into subagents so they share memory with the parent.

Buuut I do agree, the mutable array is too open. Some options that come to mind to fix this:

  1. Spawn-time opt-in + add-only: only fire if spawner passes allowToolInjection: true, and extensions can only add tools, not remove or shadow
  2. Split the PR, land session_ready first while we figure out the right shape for tool injection
  3. Something better you have in mind?

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