RSI Phase 2 + redesign Phase 1 (JIT context, budget/scheduling, model routing) - #56
Conversation
Brings in PR #54's work (staleness enum, headless_claude model pinning/rate-limit handling/tool-use capture, the translation task type, and the design retrospective from real runs) that was still unmerged upstream. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces raw Read/Grep/Glob access to the full cached page file with a narrow context_fetch_cli tool (get-refs/get-neighbors/get-prior-sugyot) plus a compact page skeleton and worked examples inlined in the prompt. Auto-populates generation records' dependsOn from what was actually fetched, instead of always []. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the hardcoded MODEL constant with model_routing_config.json, read via model_routing.ts, so a future routing tuner can propose changes from logged outcomes instead of a hand-edited constant. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds budget_config.json (hand-edited enable/caps/pause per task type, ships disabled by default), status_cli.ts for call-count/cost visibility against those caps, and schedule_runner.ts as the bounded per-tick cron/launchd entrypoint that honors the config. Folds per-call cost/model logging into context_usage_log.jsonl (added a `model` field) instead of a separate spend ledger, since the two would otherwise track nearly identical data. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
7aaafed to
37ce45d
Compare
| const baseRef = onIndex === -1 ? ref : ref.slice(onIndex + 4); | ||
| let match: Book | undefined; | ||
| for (const book of books.allBooks) { | ||
| if (baseRef.startsWith(`${book.canonicalName} `) |
There was a problem hiding this comment.
Use books.parse() instead
There was a problem hiding this comment.
Done — parseRefLocation now calls books.parse() instead of the manual loop (same commit, b7630f0).
| */ | ||
| export function parseRefLocation(ref: string): RefLocation | undefined { | ||
| const onIndex = ref.lastIndexOf(" on "); | ||
| const baseRef = onIndex === -1 ? ref : ref.slice(onIndex + 4); |
There was a problem hiding this comment.
This looks brittle. "On" is not an api contract. Can we use the pages tree structure to deduce the base ref instead?
Otherwise, maybe the mapping should be precomputed somewhere
There was a problem hiding this comment.
Replaced the manual book-name loop + " on " split with a scan over successive token suffixes through books.parse() — no hardcoded string convention, just structural matching against the real book/alias registry. See parseRefLocation in b7630f0.
| // Falls back to this only if precomputed/rsi_state/model_routing.json has no entry for this task | ||
| // type. The routing tuner (Phase 4 — not built yet) is meant to propose changes to that file from | ||
| // logged outcomes; this constant is just the safety-net default, not the source of truth. | ||
| const DEFAULT_MODEL_CONFIG = {generateModel: "claude-sonnet-5", critiqueModel: "claude-sonnet-5"}; |
There was a problem hiding this comment.
Remove this - if no defaults are set an error should be thrown
There was a problem hiding this comment.
Removed DEFAULT_MODEL_CONFIG; getTaskModelConfig now throws if a task type has no entry in model_routing_config.json instead of falling back.
| const value = Number(args[index + 1]); | ||
| return Number.isFinite(value) ? value : fallback; | ||
| } | ||
|
|
There was a problem hiding this comment.
Is there a flags library to handle this?
There was a problem hiding this comment.
Switched to yargs (.command() per subcommand), matching rashi_tosafot_translation_cli.ts's pattern, instead of hand-rolled argv parsing.
| formatWorkedExamples(workedExamples), | ||
| "", | ||
| "This page's segments and commentary, for orientation (not full text):", | ||
| skeleton ? formatPageSkeleton(skeleton) : "(page not cached)", |
There was a problem hiding this comment.
Error if it's not cached
There was a problem hiding this comment.
generationPrompt now throws if the page isn't cached (or the book is unrecognized) instead of degrading to "(page not cached)" in the prompt text — a candidate can only exist if the page was cached at listing time, so this indicates a real inconsistency, not an expected case.
- parseRefLocation: replace the "on"-string heuristic and manual book-prefix loop with books.parse() over successive token suffixes — structural, not a hardcoded string convention. - getTaskModelConfig: throw when a task type has no config entry instead of silently falling back to a hardcoded default. - generationPrompt: throw if the page isn't cached instead of degrading to "(page not cached)" in the prompt text. - context_fetch_cli.ts: use yargs (consistent with the sibling CLI) instead of hand-rolled argv parsing. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
PR #55 was merged with only the plan doc (
RSIAgentRedesignPlan.md) before this branch'simplementation commits landed — this PR carries everything else that accumulated on the same
branch afterward:
rashi_tosafot_translation.ts,headless_claude.ts's model-pinning/rate-limit/cost-capture work, andRSIAgentDesignRetrospective.md— the real-run findings that motivated the redesign plan.context_fetch.ts/context_fetch_cli.tsreplace rawRead/Grep/Globaccess to the full cached page file with a narrow, ref-addressed, size-capped tool;
page_skeleton.tsgives the prompt a compact page structure instead of the raw 400KB+ JSON;worked examples are now inlined in the generation prompt.
dependsOnis now auto-populated from whatcontext_fetchactually served (extractRequestedRefs), not always[]— this is what letsa Tier 3 staleness hit cascade to dependent artifacts.
model_routing_config.json(read viamodel_routing.ts) replaces thehardcoded model constant.
budget_config.json(hand-edited, ships fully disabled) +schedule_runner.ts(bounded per-tick runner) +status_cli.ts(call-count/cost visibility)— a human-driven schedule rather than a blind cron or a dollar cap that may not mean anything
under subscription billing.
Not yet implemented: the in-page review UI (Phase 3) and the segmentation-boundary audit task
type (Phase 2) — see
RSIAgentRedesignPlan.mdfor phasing.Test plan
npx jest— all 85 suites / 823 tests passnpx tsc(project's pre-commit check) — cleannpx eslinton all changed files — no errors (only pre-existingno-consolewarnings onCLI scripts, matching existing convention)
context_fetch_cli.ts,status_cli.ts, andschedule_runner.tsviats-nodeagainst real local state
🤖 Generated with Claude Code