Commit graph

855 commits

Author SHA1 Message Date
Kent Overstreet
31a41fa042 ActiveTools wrapper: replace SharedActiveTools Arc<Mutex<Vec>>
New ActiveTools struct with proper methods: push, remove, abort_all,
take_finished, take_foreground, iter, len. Lives directly on AgentState,
no separate Arc<Mutex> needed.

TUI reads active tools through agent.state.try_lock(). Turn loop uses
helpers instead of manual index iteration.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 16:45:56 -04:00
Kent Overstreet
9c9618d034 WIP: ActiveTools wrapper type, removing SharedActiveTools
New ActiveTools struct with proper methods: push, remove,
take_finished, take_foreground, iter, len. Turn loop uses
helpers instead of manual index iteration.

Removing SharedActiveTools (Arc<Mutex<Vec>>) — active tools
live directly in AgentState. A few UI callers still need
updating.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 16:41:14 -04:00
Kent Overstreet
14fd8c9b90 Clean up warnings: StreamToken pub, dead oneshot code, SkipIndex
Made StreamToken pub (was pub(crate), needed by context.rs).
Removed dead API_CLIENT, get_client, sampling/priority fields
from oneshot. Suppressed pre-existing SkipIndex warning in learn.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 16:35:57 -04:00
Kent Overstreet
2c401e24d6 Parser consumes stream directly, yields tool calls via channel
ResponseParser::run() spawns a task that reads StreamTokens, parses
into the AST (locking context per token), and sends PendingToolCalls
through a channel. Returns (tool_rx, JoinHandle<Result>) — the turn
loop dispatches tool calls and awaits the handle for error checking.

Token IDs from vLLM are accumulated alongside text and stored directly
on AST leaves — no local re-encoding on the response path.

The turn loop no longer matches on individual stream events. It just
reads tool calls and dispatches them.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 16:32:00 -04:00
Kent Overstreet
0b9813431a Agent/AgentState split complete — separate context and state locks
Agent is now Arc<Agent> (immutable config). ContextState and AgentState
have separate tokio::sync::Mutex locks. The parser locks only context,
tool dispatch locks only state. No contention between the two.

All callers migrated: mind/, user/, tools/, oneshot, dmn, learn.
28 tests pass, zero errors.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:47:21 -04:00
Kent Overstreet
1d61b091b0 WIP: Agent/AgentState — 36 errors remaining, all .lock() → .state.lock() or .context.lock()
Bulk replaced Arc<Mutex<Agent>> with Arc<Agent> across all files.
Fixed control.rs, memory.rs tool handlers. Fixed oneshot Backend.
Remaining errors are all agent.lock() → agent.state.lock() or
agent.context.lock() in mind/, user/, and a few in mod.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:40:36 -04:00
Kent Overstreet
e73135a8d0 WIP: Agent/AgentState split — core methods migrated
turn(), push_node(), assemble_prompt_tokens(), compact(),
restore_from_log(), load_startup_journal(), apply_tool_result()
all use separate context/state locks. ToolHandler signature
updated to Arc<Agent>.

Remaining: tool handlers, control.rs, memory.rs, digest.rs,
and all outer callers (mind, user, learn, oneshot, dmn).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:39:03 -04:00
Kent Overstreet
7fe4584ba0 WIP: Agent/AgentState split — struct defined, 80+ errors remaining
Split Agent into immutable Agent (behind Arc) and mutable AgentState
(behind its own Mutex). ContextState has its own Mutex on Agent.
Activities moved to AgentState. new() and fork() rewritten.

All callers need mechanical updates: agent.lock().await.field →
agent.state.lock().await.field or agent.context.lock().await.method.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:36:08 -04:00
Kent Overstreet
e587431f9a IT BUILDS: Full AST migration compiles — zero errors
All callers migrated from old context types to AstNode/ContextState.
Killed: Message, Role (api), ConversationEntry, ContextEntry,
ContextSection, working_stack, api/parsing.rs, api/types.rs,
api/openai.rs, context_old.rs.

Oneshot standalone path stubbed (needs completions API rewrite).
12 warnings remaining (dead code cleanup).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:29:52 -04:00
Kent Overstreet
d0d876e067 WIP: Fix mind/, dmn, UI layer — 35 errors remaining
mind/mod.rs and mind/dmn.rs fully migrated to AST types.
user/context.rs, user/widgets.rs, user/chat.rs partially migrated.
Killed working_stack tool, tokenize_conv_entry, context_old.rs.

Remaining: learn.rs (22), oneshot.rs (5), subconscious.rs (3),
chat.rs (3), widgets.rs (1), context.rs (1).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:24:49 -04:00
Kent Overstreet
bf3e2a9b73 WIP: Rename context_new → context, delete old files, fix UI layer
Renamed context_new.rs to context.rs, deleted context_old.rs,
types.rs, openai.rs, parsing.rs. Updated all imports. Rewrote
user/context.rs and user/widgets.rs for new types. Stubbed
working_stack tool. Killed tokenize_conv_entry.

Remaining: mind/mod.rs, mind/dmn.rs, learn.rs, chat.rs,
subconscious.rs, oneshot.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:20:26 -04:00
Kent Overstreet
22146156d4 Collapse API layer: inline openai.rs, delete types.rs and parsing.rs
API is now two files: mod.rs (430 lines) and http.rs. Contains:
Usage, StreamToken, SamplingParams, ApiClient, stream_completions,
SseReader, send_and_check. Everything else is dead and gone.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:15:21 -04:00
Kent Overstreet
9bb626f18c Strip api/types.rs to just Usage
Killed Message, Role, ToolCall, FunctionCall, MessageContent,
ContentPart, ImageUrl — all dead. types.rs is now 8 lines.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:12:28 -04:00
Kent Overstreet
39e6ae350d Kill dead API types: ChatRequest, ChatCompletionChunk, Delta, streaming types
Removed all chat completions wire types that are no longer used:
ChatRequest, ReasoningConfig, ChatCompletionChunk, ChunkChoice,
Delta, FunctionCallDelta, ToolCallDelta, append_content, user_with_images.

Remaining types in api/types.rs are transitional (Message, ToolCall, etc.)
— they'll go away as outer callers migrate to AstNode.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:08:41 -04:00
Kent Overstreet
1e5cd0dd3f Kill dead API code: stream_events, parsing.rs, build_response_message, log_diagnostics
Deleted: api/parsing.rs entirely (parsing now in context_new.rs),
stream_events (chat completions path), collect_stream, build_response_message,
log_diagnostics, tools_to_json_str, start_stream, chat_completion_stream_temp.

API layer is now just: stream_completion (token IDs in/out), SseReader,
send_and_check, and types. Zero errors in api/.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:06:33 -04:00
Kent Overstreet
48db4a42cc WIP: Kill chat API path — StreamEvent, collect_stream, build_response_message
Removed start_stream, chat_completion_stream_temp, collect_stream,
StreamResult, build_response_message. All streaming goes through
stream_completion → StreamToken now. ConversationLog rewritten
for AstNode serialization.

Remaining: openai.rs stream_events, mind/, user/, oneshot, learn.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 15:01:42 -04:00
Kent Overstreet
a68377907a WIP: Agent core migrated to AST types
agent/mod.rs fully uses AstNode/ContextState/PendingToolCall.
Killed: push_message, push_entry, append_streaming, finalize_streaming,
streaming_index, assemble_api_messages, age_out_images, working_stack,
context_sections, entries. ConversationLog rewritten for AstNode.

Remaining: api dead code (chat path), mind/, user/, oneshot, learn.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 14:59:38 -04:00
Kent Overstreet
9c79d7a037 WIP: Wiring context_new into agent — turn loop, StreamToken, dead code removal
Work in progress. New turn loop uses ResponseParser + StreamToken.
Killed StreamEvent, append_streaming, finalize_streaming, streaming_index,
assemble_api_messages, working_stack. Many methods still reference old
types — fixing next.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 14:55:10 -04:00
Kent Overstreet
648356ae40 ResponseParser mutates AST directly, returns PendingToolCalls
The parser takes &mut ContextState on feed()/finish() and pushes
completed children (content, thinking, tool calls) directly into
the assistant branch. Only PendingToolCall handles are returned
to the caller for dispatch — the caller no longer manages AST
mutation.

Tests verify by reading back from ContextState after parsing.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 14:33:57 -04:00
Kent Overstreet
6139d43942 ResponseParser returns children incrementally, add push_child/PendingToolCall
feed() now returns all completed children (not just tool calls) so the
caller can push them into the AST as they arrive. finish() returns
remaining buffered children. The caller manages the assistant branch.

Added ContextState::push_child() for appending to an existing branch,
PendingToolCall for ephemeral dispatch handles, and len() for section
size queries.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 14:26:53 -04:00
Kent Overstreet
9fb9c2b2cb Add serde derives to AST types, enable chrono serde feature
Prep for wiring context_new.rs into the codebase: AstNode, NodeLeaf,
NodeBody, Role all derive Serialize/Deserialize for conversation log
persistence.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 14:17:40 -04:00
Kent Overstreet
bb80225942 Recursive render_into/token_ids_into, compose from cached children
render_into(&mut String) and token_ids_into(&mut Vec<u32>) recurse
the tree extending the output in place. Branches emit their wrapping
(im_start/role/im_end) and recurse into children — same structure in
both methods. token_ids() now composes from cached leaf tokens instead
of re-encoding the full rendered string.

Killed the AstEvent/AstIter iterator experiment — explicit recursion
is cleaner for a tree walk that isn't truly flattening.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 14:00:42 -04:00
Kent Overstreet
942144949d Add Ast trait for render/token_ids/tokens
Implemented by both AstNode and ContextState, so anything that
needs "give me the prompt" can take impl Ast.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 13:39:05 -04:00
Kent Overstreet
f1397b7783 Redesign context AST: typed NodeBody, Role as grammar roles, tests
Role is now just System/User/Assistant — maps 1:1 to the grammar.
Leaf types are NodeBody variants: Content, Thinking, ToolCall,
ToolResult, Memory, Dmn, Log. Each variant renders itself; no Role
needed on leaves. AstNode is Leaf(NodeLeaf) | Branch{role, children}.
ContextState holds four Vec<AstNode> sections directly.

Moved tool call XML parsing from api/parsing.rs into context_new.rs
so all grammar knowledge lives in one place.

Tokenizer encode() now returns empty vec when uninitialized instead
of panicking, so tests work without the tokenizer file.

26 tests: XML parsing, incremental streaming (char-by-char feeds
found and fixed a lookahead bug), rendering for all node types,
tokenizer round-trip verification.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 13:35:04 -04:00
Kent Overstreet
6730d136d4 ContextState + private AstNode fields: enforce token_ids invariant
AstNode fields are now private with read-only accessors. All mutation
goes through ContextState methods (push, set_message, set_score, del)
which guarantee token_ids stays in sync with text on every leaf.

Also fix ResponseParser to use AstNode::tool_call() constructor,
widen parsing module visibility to pub(crate).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 12:58:59 -04:00
Kent Overstreet
29dc339f54 WIP: Context AST design — AstNode with Leaf{text,token_ids}/Branch
New context_new.rs with the AST-based context window design:
- AstNode: role + NodeBody (Leaf with text+token_ids, or Branch with children)
- Tokens only on leaves, branches walk children
- render() produces UTF-8, tokenize produces token IDs, same path
- ResponseParser state machine for streaming assistant responses
- Role enum covers all node types including sections

Still needs: fix remaining pattern match issues, add ContextState wrapper,
wire into mod.rs, replace old context.rs.

Does not compile yet — this is a design checkpoint.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 12:46:44 -04:00
Kent Overstreet
64157d8fd7 Add assert in append_streaming to catch impossible Thinking entry
Debug assertion to help trace the remaining Thinking/Log panic.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 12:10:54 -04:00
Kent Overstreet
603d58e686 Fix Thinking/Log panics: skip entries with empty token_ids
Entries with empty token_ids (Thinking, Log) are not part of the
prompt and don't have messages. Skip them in streaming_index(),
route_entry(), and sync_from_agent() instead of calling .message()
which panics.

Using token_ids.is_empty() as the guard in streaming_index means
the check is tied to the data, not the type — any entry that
doesn't produce tokens is safely skipped.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 12:05:49 -04:00
Kent Overstreet
cb64cdf5fe Init tokenizer in consciousness binary main
The consciousness binary has its own main() separate from poc-memory.
Agent::new() creates ContextEntries which need the tokenizer, so it
must be initialized before Mind::new().

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 11:55:32 -04:00
Kent Overstreet
f458af6dec Add /v1/completions streaming path with raw token IDs
New stream_completions() in openai.rs sends prompt as token IDs to
the completions endpoint instead of JSON messages to chat/completions.
Handles <think> tags in the response (split into Reasoning events)
and stops on <|im_end|> token.

start_stream_completions() on ApiClient provides the same interface
as start_stream() but takes token IDs instead of Messages.

The turn loop in Agent::turn() uses completions when the tokenizer
is initialized, falling back to the chat API otherwise. This allows
gradual migration — consciousness uses completions (Qwen tokenizer),
Claude Code hook still uses chat API (Anthropic).

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 11:42:22 -04:00
Kent Overstreet
e9765799c4 Move tool definitions into ContextState as system entries
Tool definitions are now pushed as a ContextEntry in the system
section at Agent construction time, formatted in the Qwen chat
template style. They're tokenized, scored, and treated like any
other context entry.

assemble_prompt_tokens() no longer takes a tools parameter —
tools are already in the context. This prepares for the switch
to /v1/completions where tools aren't a separate API field.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 11:36:33 -04:00
Kent Overstreet
67e3228c32 Kill tiktoken — all token counting now uses Qwen 3.5 tokenizer
Remove tiktoken-rs dependency, CoreBPE field on Agent, and the
msg_token_count() function. All tokenization now goes through the
global HuggingFace tokenizer in agent/tokenizer.rs.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 11:25:28 -04:00
Kent Overstreet
5e4067c04f Replace token counting with token generation via HuggingFace tokenizer
Add agent/tokenizer.rs with global Qwen 3.5 tokenizer that generates
actual token IDs including chat template wrapping. ContextEntry now
stores token_ids: Vec<u32> instead of tokens: usize — the count is
derived from the length.

ContextEntry::new() tokenizes automatically via the global tokenizer.
ContextSection::push_entry() takes a raw ConversationEntry and
tokenizes it. set_message() re-tokenizes without needing an external
tokenizer parameter.

Token IDs include the full chat template: <|im_start|>role\ncontent
<|im_end|>\n — so concatenating token_ids across entries produces a
ready-to-send prompt for vLLM's /v1/completions endpoint.

The old tiktoken CoreBPE is now unused on Agent (will be removed in
a followup). Token counts are now exact for Qwen 3.5 instead of the
~85-90% approximation from cl100k_base.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 11:20:03 -04:00
Kent Overstreet
70ee7abea5 Fix restore_from_log panic on Thinking entries, fix bail nullglob
restore_from_log called .message() on all entries including Thinking
entries, which panic. Filter them out alongside Log entries.

Also fix bail-no-competing.sh: without nullglob, when no pid-* files
exist the glob stays literal and always triggers a false bail.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 10:39:07 -04:00
Kent Overstreet
06176201da Fix bail script: pass own pid file so it can exclude itself
The bail-no-competing.sh script expects $1 to be the path to the
current agent's pid file so it can skip it when checking for
competing processes. But the runner wasn't passing any arguments,
so $1 was empty and the script treated every pid file (including
the agent's own) as a competing process — bailing every time.

This caused surface-observe to always bail at step 2, preventing
all memory graph maintenance (organize, observe phases) from
running.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 09:35:52 -04:00
Kent Overstreet
6ce3f78e0a Fix stale pid reaper: check /proc/pid/cmdline to detect PID reuse
The reaper checks if agent PIDs are alive via kill(pid, 0), but if
the PID was reused by an unrelated process, the check succeeds and
the stale pid file blocks the agent from re-launching indefinitely.

Fix: read /proc/pid/cmdline and verify the process is actually a
claude/poc-memory process. If not, remove the pid file.

This caused memory surfacing to stop working for the entire April 7
session — a dead surface-observe process's PID was reused, blocking
all subsequent surfacing attempts with "already running".

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-08 09:18:21 -04:00
Kent Overstreet
7ecc50d2e4 Capture reasoning/thinking from API stream into Thinking entries
StreamResult now includes accumulated reasoning text. After each
stream completes, if reasoning was produced, a Thinking entry is
pushed to the conversation before the response message.

Reasoning content is visible in the context tree UI but not sent
back to the API and doesn't count against the token budget.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 22:49:35 -04:00
Kent Overstreet
e0ee441aec Add ConversationEntry::Thinking — 0 tokens, not sent to API
Thinking/reasoning content is now a first-class entry type:
- Serialized as {"thinking": "..."} in conversation log
- 0 tokens for budgeting (doesn't count against context window)
- Filtered from assemble_api_messages (not sent back to model)
- Displayed in UI with "thinking: ..." label and expandable content

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 22:46:06 -04:00
Kent Overstreet
7c5fddcb19 Fix input blocked during scoring: release agent lock before disk write
The scoring callback was holding the agent lock while doing a
synchronous file write (save_memory_scores). This blocked the event
loop from acquiring the lock to process user input.

Fix: collect the scores snapshot while holding the lock, drop the
lock, then write to disk.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 22:32:10 -04:00
Kent Overstreet
1be16b9f7b Move memory scores to status column for consistent alignment
Individual memory nodes now show their score in the status column
after the token count, not embedded in the name. Unscored memories
have an empty status column.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 22:28:14 -04:00
Kent Overstreet
c7c69a8f06 Add status column to context tree with tab-stop alignment
SectionView gains a status field for extra info displayed after the
token count column. Memory nodes section shows "N scored, M unscored"
in the status column instead of burying it in the title.

Renderer uses fixed-width columns (40 name, 16 tokens, status) for
consistent alignment across sections.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 22:13:27 -04:00
Kent Overstreet
07b400c95c Restore context tree display with SectionView UI type
Introduced SectionView {name, tokens, content, children} as a
UI-only tree node, separate from the data ContextSection. The widget
SectionTree renders SectionView with the old recursive expand/collapse
behavior — children for sub-sections, content for text expansion.

section_to_view() converts data sections to UI views, using
ConversationEntry::label() for names and content_text() for
expandable content.

read_context_views() builds the same tree the old context_state_summary
did: System, Identity, Journal, Memory nodes (scored/unscored counts,
expandable to show content), Conversation entries.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 22:06:10 -04:00
Kent Overstreet
613704720b Score memories in first 60% of conversation by tokens
Use cumulative token position instead of entry index for the scoring
cutoff. This reflects actual context usage — a few large entries
near the end won't skew the boundary.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-07 21:43:59 -04:00
Kent Overstreet
fd58386951 Incremental memory scoring with per-score persistence
score_memories_incremental now takes an async callback that fires
after each memory is scored. The callback:
- Writes the score to the conversation entry via set_score()
- Persists to memory-scores.json immediately
- Notifies the UI so the context screen updates live

Scoring no longer batches — each score is visible and persisted
as it completes. Does not touch the memory store.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 21:34:14 -04:00
Kent Overstreet
e213644514 Fix: only evict scored memories, not unscored
lowest_scored_memory() now skips memories with score=None. Unscored
memories haven't been evaluated — dropping them before scored
low-value ones loses potentially important context.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 21:06:45 -04:00
Kent Overstreet
a20f3e3642 Restore entry labels in context tree: role, tool calls, memory keys
ConversationEntry::label() provides descriptive labels matching the
old entry_sections format:
- "Kent: what about..." / "Aria: [tool_call: memory_search, ...]"
- "mem: [memory: key-name score:0.73]"
- "dmn: [heartbeat]" / "system: [system prompt]"

Uses config names (assistant_name, user_name) not generic "asst"/"user".
Widget renderer uses label() instead of raw content preview.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 21:04:41 -04:00
Kent Overstreet
5523752a15 Memory nodes section in F2 context screen with scoring visibility
Build a synthetic "Memory nodes (N scored, M unscored)" section in
the context screen by extracting Memory entries from the conversation
section. Each node shows its key and score. Inserted before the
conversation section so scores are visible at a glance.

This makes it easy to see whether scoring is keeping up — if unscored
count is high relative to scored, scoring needs to run more often.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 21:03:05 -04:00
Kent Overstreet
b892cae2be Simplify trim_entries, kill ContextBudget
trim_entries is now a simple loop:
1. Drop duplicate memories and DMN entries
2. While over budget: if memories > 50% of entry tokens, drop
   lowest-scored memory; otherwise drop oldest conversation entry
3. Snap to user message boundary

ContextBudget is gone — sections already have cached token totals:
- total_tokens() on ContextState replaces budget.total()
- format_budget() on ContextState replaces budget.format()
- trim() takes fixed_tokens: usize (system + identity + journal)

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
2026-04-07 20:58:06 -04:00
Kent Overstreet
62996e27d7 WIP: ContextEntry/ContextSection data structures for incremental token counting
New types — not yet wired to callers:

- ContextEntry: wraps ConversationEntry with cached token count and
  timestamp
- ContextSection: named group of entries with cached token total.
  Private entries/tokens, read via entries()/tokens().
  Mutation via push(entry), set(index, entry), del(index).
- ContextState: system/identity/journal/conversation sections + working_stack
- ConversationEntry::System variant for system prompt entries

Token counting happens once at push time. Sections maintain their
totals incrementally via push/set/del. No more recomputing from
scratch on every budget check.

Does not compile — callers need updating.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 20:48:08 -04:00
Kent Overstreet
776ac527f1 trim_entries: take ContextBudget instead of recomputing
compact() already computes context_budget() — pass it to trim_entries
so it has access to all budget components without recomputing them.

Co-Authored-By: Proof of Concept <poc@bcachefs.org>
2026-04-07 19:43:39 -04:00