Repository navigation
Session extension: pass the prompt language to the context section and make it async #526
Copy link
Copy link
Closed
Copy link
Labels
app-shellenhancementNew feature or requestNew feature or requestsecurity-reviewTouches security-critical code: elevated reviewTouches security-critical code: elevated review
Milestone
Description
Goal
The session extension's context section can follow the session's prompt language and can read the extension's own (async) data store. Today the hook gets neither, so an edition that keeps per-server, per-group or per-tag data in its extension tables cannot build a language-correct context section without blocking or duplicating core logic.
Context
SessionExtension::context_section(&self, _scope: &ServerScope) -> Option<String>is synchronous and receives only the scope (crates/app-logic/src/session_extension.rs:32).- Its only caller,
append_extension_section(crates/app-logic/src/session_extension.rs:140, call at:149), already has the prompt language inparts.language(used for the heading viaextension_heading,:128,:156) but does not pass it on. append_extension_sectionis called from two async contexts:crates/app-shell/src/commands/connect.rs:500(session connect, inside an async fn that already awaitsextension_scope),crates/app-shell/src/commands/chat.rs:276(rebuilt on every user message, inside an async loop that already awaitsextension_scope).
- The language type is
PromptLanguage(crates/app-logic/src/system_prompt.rs:135:De,En,Other(ResponseLanguage)). - Extension-owned tables (Spec 0038, section 2a) are reached through an async database handle, so a synchronous hook can only read them by blocking the runtime or keeping a separate cache.
- Precedent for an async edition hook:
OutgoingTransform::prepare_outgoinguses#[async_trait](crates/core/src/outgoing.rs:84-93);async-traitis already a dependency ofapp-logic(crates/app-logic/Cargo.toml:27). - Governing docs: Spec 0038, section 2 "Sitzungs-Erweiterung" (
docs/specs/0038-repository-app-shell-ci.md:38-68), ADR 0136 (docs/adr/0136-session-extension-point.md).
Requirements
SessionExtension::context_sectionreceives the prompt language of the session as aPromptLanguageargument, the same valueappend_extension_sectionuses for the section heading.context_sectionbecomesasync(via#[async_trait]onSessionExtension, likeOutgoingTransform), so an extension can await reads from its own data store. Noblock_in_placeor other blocking bridge in the core.- The default implementation still returns
None. append_extension_sectionbecomesasync; both call sites (connect.rs:500,chat.rs:276) await it. The order stays: core paragraphs, then the extension heading, then the redacted and fenced section (redact, then fence; ADR 0034).known_secrets,server_removedandgroup_removedkeep their current signatures and behaviour.- Without a registered extension the system prompt and the redactor stay byte-identical to before.
Acceptance Criteria
-
context_sectionis an async trait method that takes&ServerScopeandPromptLanguageand returnsOption<String>; its default returnsNone. -
append_extension_sectionpassesparts.languagetocontext_section; a test extension that returns a different text per language yields the German text forPromptLanguage::Deand the English text forPromptLanguage::En(counter-proof: the test fails if the language is not forwarded). - A test extension whose
context_sectionawaits (e.g. atokio::syncread) works throughappend_extension_sectionwithout blocking the runtime. - The existing session_extension tests (fence after core text in both languages, empty/whitespace section adds nothing, no extension adds nothing, section is redacted before fencing) pass in their async form.
- Both call sites in
connect.rsandchat.rsawait the async section; behaviour for a session without an extension is unchanged. - Spec 0038 (section 2, "Sitzungs-Erweiterung") states that the context section receives the prompt language and may be answered asynchronously; ADR 0136 gets a short note on the async hook and the language argument.
- Relevant automated tests pass
Technical Notes
- Affected:
crates/app-logic/src/session_extension.rs(trait,append_extension_section, tests incl.TestExtensionat:248andRecordingExtension),crates/app-shell/src/commands/connect.rs,crates/app-shell/src/commands/chat.rs, and every otherimpl SessionExtensionin tests (crates/app-logic/src/mcp_lookup.rs:252,crates/app-logic/src/session.rs:1869); they only implementknown_secretsbut the trait gains#[async_trait], so check they still compile. - This changes an internal extension-point API; editions that implement
SessionExtensionhave to adapt theircontext_sectionto the new signature. - Security: the section remains untrusted content. Redact-then-fence, the
server_notefence, and settinguntrusted_content_ingestedmust stay exactly as today. Filter, risk classification and redaction rules are not touched. - No data model or migration change.
Spec impact: update 0038
Related Work
- Extension point: session context section and per-server known secrets for redaction #463 (introduced the session extension point)
- Outgoing transform: pass the server's group chain like the session extension #501 (group chain in the scope of the outgoing transform)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
app-shellenhancementNew feature or requestNew feature or requestsecurity-reviewTouches security-critical code: elevated reviewTouches security-critical code: elevated review
Type
Fields
Priority
P1 - High
Stage
Done
Role
None
Activity
smart-ssh-coder commentedon Oct 14, 2026
Implementation update
PR: #527
Implemented:
SessionExtension::context_sectionis async and takes&ServerScope+PromptLanguage;append_extension_sectionis async; connect.rs and chat.rs await it.Remaining / open:
Decisions:
smart-ssh-reviewer commentedon Oct 14, 2026
Review result
Approved — see review on #527.
Findings:
Recommended next step: merge
feat(app-logic): async session extension context section with prompt …