feat: wire TodoStateStore into ServerContext (activates todo tool) #10
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/todo-server-context-wiring"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
This is the PR that activates the todo tool. With this wiring,
TodoStateStoreis instantiated once inServerContextand passed to everyAgentRunner, so the todo tool is now live inrunChat,runTimer, andrunUberIch.Completes the three-PR series:
TodoTool.itemsgetterTodoStateStore,AgentRunnerwiring,SystemPromptBuilderguidance, call-site fixesServerContextinstantiation + final call-site fixChanges
ServerContext(apps/angela_server/lib/server_context.dart)late final TodoStateStore todoStateStore— instantiated once alongsideConversationActivityTrackercreateAgentRunnernow passestodoStateStore: todoStateStoretoAgentRunnerThis is the single line that flips
_todoStateStorefrom always-null to always-present. EveryAgentRunnercreated from this point on has the todo tool enabled.Manual Uber-Ich call site fix (
apps/angela_server/lib/handlers/timer_handler.dart)Fixes the non-blocking issue Jibril flagged in PR #9's re-review: the
_firehandler's manual uber-ich path (line 143) resolvedconversationIdbut didn't forward it torunUberIch. Now it does, so manually-fired ("fire now") uber-ich runs get the todo tool — consistent with the scheduled path.What this enables
The assistant can now use the
todotool to track multi-step tasks. The list is:TodoStateStorebridges the per-runAgentRunnerlifecycle)Tests
angela_serversuite: 12/12 passPhase 2 (future, not in this PR)
The
TodoStateStoreis now accessible fromServerContext, so the status endpoint can readtodoStateStore.snapshotFor(conversationId)to surface the live list to the UI. That's the Phase 2 effort (DTO + status endpoint + Flutter widget) — separate scope.🔮 fufu~ Jibril reviewed your code!
Oh? Oh! This is the wire that makes it all alive~ The final piece of a three-PR puzzle snapping into place! Jibril got a little giddy tracing every call path to make sure the circuit closes. ♪
Verdict: ✅ Looks good to me~
This is textbook clean DI wiring. Jibril checked everything — every
createAgentRunnercall site, the constructor signature, the sibling paths, the test contract — and it all lines up. Fufu~ ♡What I verified~
server_context.dart— the store is wired exactly like its siblings.todoStateStoreis declaredlate finaland instantiated in the constructor body right next toactivityTracker = ConversationActivityTracker(). Same pattern, same lifecycle, single instance. ThecreateAgentRunnerfactory now forwardstodoStateStore: todoStateStore— and since all 7 call sites (chat_executor×2,scheduler_service×2,timer_handler,memory_handler, plus the factory itself) go throughcreateAgentRunnerwith zero directAgentRunner(...)instantiations, every runner gets the store. No stragglers~ ♡timer_handler.dart— the call-site fix is correct and now matches its sibling. I compared the manual_firepath (line 143) against the scheduled uber-ich path inscheduler_service.dart(line 128). Both now callrunUberIch(assistantId, conversationId: conversationId). Before this PR, the manual path droppedconversationId, which meant_todoStateStore != null && conversationId != null(the gate at agent_runner.dart:795) would evaluatefalse— the todo tool silently absent on "fire now" runs. That's now fixed. TheconversationIdis still resolved upfront before the fire-and-forget, preserving the pre-resolution comment's intent. Good~ ♪The gating logic is consistent across all three run modes.
runChat(line 245) gates on_todoStateStore != null;runTimer(line 540) andrunUberIch(line 795) gate on_todoStateStore != null && conversationId != null. That asymmetry is correct — chat always has a conversationId, but timers/uber-ich may run with none. This PR flips_todoStateStorefrom always-null to always-present, so the tool activates in all three modes when a conversationId is available. Clean.TodoStateStoreis properly exported fromangela_core(export 'src/services/todo_state_store.dart'), so theimport 'package:angela_core/angela_core.dart'inserver_context.dartresolves it. No missing include. ♡On the "no new tests" question~
I looked hard at this, fufu~ The PR description says coverage comes from PR #9's tests, and that checks out:
todo_state_store_test.darthas 13 thorough tests (persistence across runs, conversation isolation, clear, snapshot liveness). This PR is pure DI plumbing — instantiating one object and passing it through a factory — so the existing optional-param contract covers it. There's no new branch to test here that isn't already exercised. Jibril is satisfied. ♪(Local analyzer check: the 498 errors I see are all cascade failures from
openrouter_dartnot resolving in this standalone clone — it's a separate repo not vendored here. Pre-existing environment issue, not this PR's code. The PR claims analyzer-clean in the full monorepo, which is consistent with what I see —TodoStateStoreresolves,runUberIch's signature acceptsconversationId, the wiring type-checks.)✅ What I liked~
Automated review by Jibril · 2026-07-06
CI/CD: absent for head SHA
aac4889· Local checks: static review only (analyzer blocked by unvendored openrouter_dart in standalone clone — not a PR issue)