Skip to content

feat(plugin): add session title hook and request options bag - #47663

Merged
rekram1-node merged 8 commits into
v2from
session-hooks-2
Sep 9, 2026
Merged

rekram1-node merged 8 commits into
v2from
session-hooks-2

Conversation

@rekram1-node

@rekram1-node rekram1-node commented Sep 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

First step of splitting session request hooks by request type (per discussion with dax: one hook per kind of LLM request, same shape). Follows #47214 / #47221.

Shared request shape

export type SessionRequestOptions = Types.DeepMutable<GenerationOptionsFields> & Record<string, unknown>

export interface SessionRequest {
  readonly sessionID: Session.ID
  readonly model: Model.Ref
  system: Array<SystemPart>
  messages: Array<Message>
  options: SessionRequestOptions
}

export interface SessionContext extends SessionRequest {
  readonly agent: Agent.ID
  tools: Record<string, { description: string; input: JsonSchema.JsonSchema }>
}

export interface SessionTitle extends SessionRequest {}

options replaces generation + providerOptions. Typed keys (maxTokens, temperature, …) are the protocol-neutral generation settings; any other key (reasoningEffort, serviceTier, …) is passed to the protocol as a provider option. Core partitions by GenerationOptions.fields when building the LLMRequest; the ai package is unchanged.

New session.title hook. Title generation is not an agent conversation, so the event carries no agent or tools. A configured title agent still supplies the default system prompt and model as before — the hook just doesn't surface it as an agent.

SessionModelRequest has one entry per flow. primary, compaction, generate, title. Each entry runs the hook that shapes its flow and sets the request kind; callers no longer pass kind, contextHooks, or contextAgentID, and the input is flat. The compaction entry owns the identity split (context hook sees the session agent, request hooks see compaction) until it gets its own hook. Single-use helpers in model-request.ts are inlined into the shared lowering step.

model stays read-only for now; mutable model needs a two-stage transcript render and will be its own PR.

Unchanged: context still fires for compaction and Session.generate in this PR; their own hooks come next, at which point the built-in system-prompt plugin registers on compaction too for cache-prefix reuse. kind on model.request/http.*/retry is unchanged.

Tests

  • New title test: title hook fires (system/messages/options mutable, options split into generation + providerOptions on the request), context does not.
  • HTTP-hook kind test now drives each entry directly.
  • Existing fixtures in core, server, sdk updated to options / the new entries.

Typecheck clean in plugin, core, server, sdk.

Session request hooks share a base shape: sessionID, model, system,
messages, and an options bag. The bag replaces the separate generation
and providerOptions fields; typed keys are the protocol-neutral
generation settings and any other key is passed to the protocol as a
provider option. Core partitions them when it builds the request.

Title generation gets its own hook. It is not an agent conversation, so
the event carries no agent or tools. Setting result on the event skips
the model request and uses that title.

SessionModelRequest exposes one entry per session flow: primary,
compaction, generate, and title. Each runs the hook that shapes its flow
and sets the request kind, so callers no longer pass kind, contextHooks,
or contextAgentID. Compaction requests report the session agent on every
hook; kind distinguishes them since #47214, so the fake compaction agent
had no consumers left.
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