Skip to content

feat: middleware hooks, context injection, mid-run messaging, tool profiles, todo lists#87

Open
Enreign wants to merge 29 commits intomainfrom
feature/open-swe-adoption
Open

feat: middleware hooks, context injection, mid-run messaging, tool profiles, todo lists#87
Enreign wants to merge 29 commits intomainfrom
feature/open-swe-adoption

Conversation

@Enreign
Copy link
Copy Markdown
Collaborator

@Enreign Enreign commented Mar 20, 2026

Summary

Five new capabilities added to Sparks:

  • Middleware Safety NetSparkMiddleware trait with before_model_call / after_spark_complete hooks; ActivityLogFlushMiddleware registered by default. Guarantees deterministic post-run cleanup regardless of LLM behavior.
  • Rich Context InjectionTicketProvider::fetch_full_context() fetches issue comments (and future PR diffs) for GitHub and Linear at intake time. Opt-in via inject_full_context = true in [ticket_intake].
  • Mid-Run Message Injection — Messages arriving on Slack/Teams/Telegram while a spark is running are queued and injected as user-role messages before the next LLM call instead of being dropped. Configurable cap via max_queued_messages.
  • Tool Curation Profiles — Named [tool_profiles] config section; ghost configs reference via profile = "name" eliminating tool list copy-paste. Validated at startup by the doctor command.
  • Per-Spark Todo Liststodo_write and todo_check tools for sparks to track tasks during execution. Observable via /session command on Slack and Telegram. Persisted to spark_todos SQLite table on session close.

Test Plan

  • 462 tests passing (up from 433 baseline), 0 failures
  • cargo clippy — zero new warnings
  • Spec compliance reviewed per-task (two-stage review: spec then quality)
  • Quality issues fixed: pub(crate) scoping on executor fields; floor_char_boundary for non-ASCII safety in TicketContext::format
  • Manual smoke test: enable inject_full_context = true and verify a GitHub ticket spawns with comments in context
  • Manual smoke test: send a message to a running spark via Slack and verify it appears in the next step

🤖 Generated with Claude Code

Enreign and others added 29 commits March 20, 2026 10:30
5 Open SWE patterns evaluated for Sparks: middleware safety net,
rich context injection, mid-run message injection, tool curation
profiles, and per-spark todo lists — ordered by impact × effort ROI
with module touchpoints and effort estimates per item.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Correct middleware hook sites to strategy/react.rs + strategy/code.rs
- Fix mid-run inject queue owner to Executor (keyed by session ID)
- Add CoreHandle::inject() to item 3 design decisions
- Rename tool_allowlist -> tools throughout item 4
- Add src/profiles.rs to item 4 touchpoints
- Fix src/strategy.rs -> src/strategy/mod.rs in item 2

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1. middleware-safety-net — SparkMiddleware trait + lifecycle hooks
2. rich-context-injection — full ticket context at spark invocation
3. mid-run-message-injection — queue messages during running sparks
4. tool-curation-profiles — named tool profiles in [tool_profiles]
5. per-spark-todo-lists — todo_write/todo_check tools with SQLite persistence

Each plan is TDD-ordered, bite-sized steps, exact file paths.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eware

Introduces the SparkMiddleware trait with before_model_call and
after_spark_complete lifecycle hooks, plus an ActivityLogFlushMiddleware
no-op placeholder, ensuring the safety net infrastructure is in place
for deterministic post-run guarantees.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…complete

Adds SharedMiddlewares field to Executor, wires invoke_after_spark_complete
into Executor::run() after the strategy loop completes (on both success and
failure paths), and updates manager.rs to pass vec![] at the call site.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire the before_model_call middleware hook into every LLM invocation
site across ReactStrategy and CodeStrategy (native + text-fallback paths,
EXPLORE and VERIFY phases), using docker.session_id() as the session
identifier.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ls in code.rs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ew; add MiddlewareConfig

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ethod

Introduces TicketContext struct with comments and diff_summary fields,
a format() method with progressive trimming to a char budget, and a
default fetch_full_context() on TicketProvider so existing impls need
no changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…g loop

Add inject_full_context and rich_context_char_cap fields to TicketIntakeConfig
with serde defaults (false / 4000). Thread both values through spawn_ticket_intake
and apply fetch_full_context + TicketContext::format in the per-ticket dispatch
loop, warning on errors rather than failing. Includes a config round-trip test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…field

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…n in doctor

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ister in ToolRegistry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add session_todos() to ExecutorInjectHandle, CoreHandle, and Manager.
Wire todo block into /session responses for both Slack (mrkdwn code block)
and Telegram (HTML <pre> block).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Before removing a session's TodoList on close_session(), serialize it to
JSON and emit a structured tracing::info! event (spark_todos persisted)
so the todo state is captured in the observer log for post-session analysis.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… in TicketContext

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@Enreign Enreign changed the title feat: Open SWE adoption — middleware, context injection, mid-run messaging, tool profiles, todo lists feat: middleware hooks, context injection, mid-run messaging, tool profiles, todo lists Mar 20, 2026
}
async fn execute(&self, _session: &crate::docker::DockerSession, params: &Value) -> Result<crate::tools::ToolResult> {
let session_key = crate::executor::Executor::current_activity_context()
.map(|c| c.session_key)

Check failure

Code scanning / CodeQL

Cleartext logging of sensitive information High

This operation writes
|...| ...
to a log file.
}
async fn execute(&self, _session: &crate::docker::DockerSession, params: &Value) -> Result<crate::tools::ToolResult> {
let session_key = crate::executor::Executor::current_activity_context()
.map(|c| c.session_key)

Check failure

Code scanning / CodeQL

Cleartext logging of sensitive information High

This operation writes
|...| ...
to a log file.
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