Commit Graph

8 Commits

Author SHA1 Message Date
kami a4f6cf0564 feat(context): role means message type, layer means pinning (#312/#313)
The system block is now for content that does not change during a run.
Anything the run mutates renders as a user message — both because a
mutating system prefix defeats prompt caching and because models
under-weight system-folded content against the trailing user turn.

PromptRenderer: role alone decides the message type; the old
`layer == L0 ||` clause is gone. That clause was silently overriding
role on four packs (InferenceSummarizer, SemanticReviewerImpl,
CapabilityGapReflectorImpl, Talkie session-naming) which are L0+USER
prompts — they were rendering as a system-only request with no user
turn at all.

Re-roled SYSTEM -> USER, all mutable within a run:
  recoveryTicket, remainingDelta, groundingFeedback, rejectionFeedback
  (trailing slot), plus verifiedBaseline, promotedConcept, claimedTask,
  clarificationAnswer, locked steeringNote, factSheet (inline, still
  L0-pinned).
Left SYSTEM (immutable): systemPrompt, operatingGuidance,
schemaInstruction, projectProfile, operatorProfile, agentInstructions,
successfulPlanShape.

Trailing-slot scarcity guard: repairMandateSourceTypes joined ALL
matches, so a recovery stage on a retry with an unmet delta would stack
three competing mandates. Now a precedence list emits exactly one
(recoveryTicket > retryFeedback > groundingFeedback > rejectionFeedback)
with remainingDelta appended as the completion signal.

ContextClassifier keys STATIC on layer alone — L0 means pinned/never
pruned regardless of role, so the re-roled L0 entries don't fall through
to FREEFORM and get token-pruned.

Also fixes a stale ContextFeedbackTest assertion (expected a CAS hash
the producer deliberately stopped emitting) and a stale initialIntent
doc comment claiming L0/SYSTEM where the code says L1/USER.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 21:10:26 +04:00
kami 3bf4dd7379 feat(context): purify leading SYSTEM, route context layers as USER turns (#290)
Move intent, repo map, docs catalog, decision journal and relevant-files
context entries to EntryRole.USER so they no longer fold into the single
leading SYSTEM block — that block stays pure policy/schema. Omit L3 repo-map
retrieval on repair retries (the transcript already carries the evidence).
Add "initialIntent" to REQUIRED_SOURCE_TYPES.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 18:35:29 +04:00
kami bc050f8e8a feat(context): render retry repair mandate as final user turn (#293)
buildRetryFeedbackEntry was L1/SYSTEM, so PromptRenderer folded it into the
leading system block — far from the assistant/tool transcript and weaker than
the original stage task. Flip it to USER role and give the renderer an explicit
trailing repair-mandate slot (a sourceType set, extensible for recovery later):
repair mandates are lifted out of the inline flow and emitted once as the final
message, after the tool evidence and the steering anchor. retryFeedback is
already in REQUIRED_SOURCE_TYPES so it stays unprunable. Golden renderer test
proves the final message is the repair USER mandate and leading system no longer
carries it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-20 18:20:59 +04:00
kami 3d5e05c1fb feat(context): reasoning-thread continuity, L3 doc filtering, and gate hardening
Threads reasoning_content across inference calls and journal renders, filters
markdown noise out of L3 repo-knowledge retrieval, adds PlanLinter H3 checks,
and tightens filesystem tool output/dir-listing behavior surfaced by prior
live QA (see project_readloop_campaign memory).
2026-07-10 11:13:43 +04:00
kami 047e2a4070 feat(context,infra): compression pipeline stages 4-5 — token pruning + relevance + ToMe
- build() is now suspend: pipeline runs all stages in fixed order, each gated by level
- TOKEN_PRUNE (level 3): TokenPruner interface + LLMLingua-2 sidecar (sidecars/llmlingua)
  + HttpTokenPruner adapter (fails open if sidecar down); prunes freeform, preserves
  protected spans, skips tier-0 turns when TIER_SPLIT on
- TOME_MERGE (level 8): ToMeMerger collapses near-duplicate freeform turns (Jaccard)
- Stage 5 selection: RelevanceScorer + EmbeddingRelevanceScorer (cosine over Embedder);
  query-conditioned reorder so least-relevant freeform drops first under budget
- [orchestration] compression_level + token_pruner_url config, wired in Main
- suspend ripple fixed across builder callers/stubs
2026-07-01 14:29:56 +04:00
kami 61be90070f feat(context): compression pipeline stage 1 — level policy + deterministic stages
Additive CompressionPolicy (levels 1-9), ProtectedSpanTagger (regex
load-bearing spans), FormatCompressor (json→dotted lines), ContextClassifier
(static/structured/freeform). Stage 1 (FORMAT_COMPRESS) wired into
DefaultContextPackBuilder behind the policy; structured entries only, lossless.
PromptRenderer repetition-anchoring of steering directives.
2026-07-01 13:53:19 +04:00
kami 07819ec82d fix(inference): fold non-L0 SYSTEM entries into the leading system message
Strict chat templates (Qwen3.5) reject any system message after index 0.
Recalled L3 memory, L2 stage summaries, and retrieval entries carry
EntryRole.SYSTEM and rendered as standalone mid-conversation system turns,
making llama-server 400 on every router turn once L3 recall returned hits.
2026-06-11 21:55:28 +04:00
kami 8fe3a504bb fix(context): preserve chronological turn order through pack assembly
Tool-calling loops were rendered as all-assistant-calls-then-all-tool-results
with the original task last, causing the model to re-issue the same tool call
indefinitely. Two stacked reorderings caused it:

- DefaultContextPackBuilder grouped entries by sourceType for per-type
  compression, discarding a,t,a,t interleaving.
- PromptRenderer forced L1 (the live user turn) to render last, pushing the
  task after the entire transcript.
- SessionOrchestrator's tool loop re-fed currentContext.layers.values.flatten()
  (grouped by layer) each round, compounding the scramble.

Add a chronological `ordinal` to ContextEntry, stamped by the builder from
input order and restored after grouping/compression (the compressor preserves
entry identity, so ordinals survive). PromptRenderer now orders non-system
messages by ordinal, with the old L1-last layer priority kept only as a
tiebreak so router chat (ordinal 0) is unchanged. The orchestrator keeps a
running ordered accumulator instead of reading back the grouped pack.

Adds builder + renderer ordering regression tests.
2026-06-03 22:22:52 +04:00