Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/dev/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ changing a contract that other features depend on.
turn: the injection order of the bias appendix + the
context-recall / samskara / intuition `<think>` chain + the
per-turn metadata block, plus freshness, failure degradation,
and observability rules. The spec `chat-loop.ts` implements.
and observability rules. The spec `chat/loop.ts` implements.
- [Settings](./settings.md) — the settings modal +
`profiles.settings` JSONB + theme.
- [Help](./help.md) — in-app rendering of `docs/user/`.
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ the function-side wire shape:
`/stream` route with a thread + anchor-message context,
subscribes to the `thread:<id>:stream` Broadcast channel, and
yields the function-published event union. Used only by the
main user-facing chat (`chat-loop.ts`).
main user-facing chat (`chat/loop.ts`).
- `SupabaseService.complete(req)` - non-streaming one-shot,
routed through the venice/complete route. Used only by the one
intentional browser-side completion path left: the intuition
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/attachments.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ covers the attachment-specific pieces.
routes the multipart upload through the venice edge function's
`/text-parser` route; the function holds the shared key and relays
the response.
- `src/lib/chat-loop.ts` - `toVeniceMessage` accepts `visionSpec` +
- `src/lib/chat/loop.ts` - `toVeniceMessage` accepts `visionSpec` +
`imageUrls` (the pre-resolved signed URLs) and routes user rows through
`buildUserVeniceContent` when they carry attachments.
- `src/lib/extractedTextDrawer.svelte.ts` - rune-based singleton store
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/bias-profile.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ interval lower bound (not the mean) as the surfacing gate.
(passing `p_user_id`) so the sweep re-analyzes with the fresh
message. All three writes swallow their errors - bias never blocks
a turn.
- **`buildSystemPrompt()`** - in `src/lib/chat-prompt.ts`, builds the
- **`buildSystemPrompt()`** - in `src/lib/chat/system-prompt.ts`, builds the
baseline only. The browser ships a bias-free system prompt; the
server appends the bias block with the same blank-line separator
`buildSystemPrompt` uses between sections, so the wire bytes are
Expand Down
14 changes: 7 additions & 7 deletions docs/dev/chat.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

The main user-facing surface plus the browser-side orchestration
that drives a single turn. `Chat.svelte` renders the drawer,
composer, and message list; `chat-loop.ts` builds the per-turn
composer, and message list; `chat/loop.ts` builds the per-turn
priming chain and the system-prompt preamble, then issues one
`venice.streamChat` call that routes through the venice edge
function's `/stream` route. The function owns the streaming round
Expand All @@ -19,7 +19,7 @@ A chat turn goes:
2. `Chat.svelte` resolves the effective model profile (per-thread
pin -> default profile), builds the history in OpenAI shape, and
calls `runChatLoop`.
3. `chat-loop.ts` runs the per-turn priming layers (samskara
3. `chat/loop.ts` runs the per-turn priming layers (samskara
fire-and-compound, intuition, context recall), stitches their
synthetic `<think>` blocks into the history, assembles the
three-layer system-prompt preamble (baseline, user-configured,
Expand All @@ -31,7 +31,7 @@ A chat turn goes:
round via the `commit_assistant_message` RPC, and broadcasts
typed events on `thread:<id>:stream` so the browser's UI stays
live.
5. `chat-loop.ts` consumes those events and routes them to the
5. `chat/loop.ts` consumes those events and routes them to the
UI handler surface (streaming bubble, reasoning panel, tool
timings, rate-limit indicator, slop-notice cards). At the END
event it captures the persisted assistant row id + terminal
Expand All @@ -50,7 +50,7 @@ A chat turn goes:
- `src/screens/Chat.svelte` - the screen itself. Drawer,
composer, message list, thread lifecycle, plus the call sites
for every other feature that hooks into chat.
- `src/lib/chat-loop.ts` - `runChatLoop`, `toVeniceMessage`, and
- `src/lib/chat/loop.ts` - `runChatLoop`, `toVeniceMessage`, and
the per-turn priming + event-routing orchestration. Issues one
`venice.streamChat` call per turn; the function-side round
chain takes over from there. Split from the screen so the
Expand Down Expand Up @@ -372,7 +372,7 @@ A chat turn goes:
- **System prompts are re-assembled every round, browser-side.**
The baseline tool-framing system message is NOT persisted - it's
built from the tool registry at request-time by
`buildSystemPrompt` in `chat-loop.ts`. User-configured prompts
`buildSystemPrompt` in `chat/loop.ts`. User-configured prompts
from Settings ride AFTER the baseline so a custom "you are a
pirate" prompt still wins on voice while the tool framing stays
in force. If you add a new tool, the model learns about it on
Expand Down Expand Up @@ -539,7 +539,7 @@ A chat turn goes:
the initial SUBSCRIBED, and a later `CHANNEL_ERROR` / `TIMED_OUT` /
`CLOSED` that this tab did not initiate flips `disconnected` and closes
the drain, which then throws `StreamDisconnectedError`. That propagates
through `chat-loop.ts` to `runExchange`'s catch, which releases the
through `chat/loop.ts` to `runExchange`'s catch, which releases the
slot and calls `reconnectInflightTurn` - the exact poll-the-row path
above, seeded with the partial the dropped stream had buffered. So a
mid-turn drop degrades gracefully to the reconnect poll instead of
Expand Down Expand Up @@ -569,7 +569,7 @@ A chat turn goes:
turn ends - the persisted DB row is the ONLY thing that can show the
partial afterward. The drain in `venice.ts` no longer `close()`s on
the `error` broadcast event (END is the sole terminal), and
`consumeStreamEvents` (`chat-loop.ts`) stashes the terminal error
`consumeStreamEvents` (`chat/loop.ts`) stashes the terminal error
instead of throwing immediately, throwing only AFTER the post-loop
`onAssistantPersisted` hydration has handed the persisted partial to
its card. Without the deferral the throw races ahead of hydration and
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/exchange.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ deterministic.

## Interactions

- **Chat loop (`src/lib/chat-loop.ts`)** — owns the actual
- **Chat loop (`src/lib/chat/loop.ts`)** — owns the actual
streaming + tool execution. The exchange module is the screen's
state container; the chat loop is the producer. Every
`handlers.X` callback in the `runChatLoop` call writes through
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/library.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ Tools:

Prompt:

- `src/lib/chat-prompt.ts` - `LIBRARY_BLOCK`, after `WIKI_BLOCK`.
- `src/lib/chat/system-prompt.ts` - `LIBRARY_BLOCK`, after `WIKI_BLOCK`.

UI:

Expand Down
2 changes: 1 addition & 1 deletion docs/dev/logging.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ Pick a short, stable source tag. Existing tags:
feature groups under a single drawer filter, same pattern as
`bias`
- `chat-loop` - the browser-side turn orchestrator
(`src/lib/chat-loop.ts`). Notably carries `venice request wire` at
(`src/lib/chat/loop.ts`). Notably carries `venice request wire` at
debug: the full `requestMessages` array sent for the turn's opening
round, priming `<think>` chain included. Round-1 wire only (later
tool rounds run edge-side under `stream`). Drop to `Debug+` when a
Expand Down
10 changes: 5 additions & 5 deletions docs/dev/prompt-augmentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ augmentation layer**. This doc is that layer's contract: who may inject
what, in what order, when it counts as fresh, how it degrades on
failure, and where it is observable. The code that enforces the
contract lives in two places: the browser assembles the baseline system
prompt + conversation + metadata in `src/lib/chat-loop.ts`
prompt + conversation + metadata in `src/lib/chat/loop.ts`
(`runChatLoop` -> `requestMessages`), and the server's priming stage
(`supabase/functions/venice/priming.ts` `runServerPriming`, the opening
stage of `getStreamingResponse`) appends the bias appendix and splices
Expand Down Expand Up @@ -40,7 +40,7 @@ Two distinct injection surfaces:
- **The baseline system prompt (row 1)** carries the slowly-changing,
always-on context: the tool catalog and the bias-profile appendix.
The tool catalog is assembled by `buildSystemPrompt()` in
`src/lib/chat-prompt.ts` (browser); the bias-profile appendix is
`src/lib/chat/system-prompt.ts` (browser); the bias-profile appendix is
rendered and appended server-side by `applyBiasPriming`
(`supabase/functions/venice/priming.ts`) before the first round,
joined with the same blank-line separator so the wire bytes match.
Expand All @@ -66,7 +66,7 @@ Two distinct injection surfaces:
| Samskara fire | `<think>` (row 6) | `fireSamskaras` (`venice/priming/samskara.ts`) | computed per turn | raced against `SAMSKARA_PRIMING_TIMEOUT_MS` |
| Intuition | `<think>` (row 7) | `runIntuitionPipeline` (`venice/priming/intuition.ts`) | `threads.intuition_payload` | `isPayloadFreshForInjection` (STALE_FUSE_MS) |
| Tool catalog | system (row 1) | `buildSystemPrompt` / `buildToolList` (`src/lib/tools`) | n/a (derived from enabled toolboxes) | per-turn snapshot of `toolboxes_enabled` |
| Metadata block | system (row 8) | `buildMetadataSystemMessage` (`src/lib/chat-loop`) | n/a | rebuilt every turn |
| Metadata block | system (row 8) | `buildMetadataSystemMessage` (`src/lib/chat/prompt-assembly`) | n/a | rebuilt every turn |

## Ordering

Expand Down Expand Up @@ -160,7 +160,7 @@ browser surface is unchanged:
round-tripped to the drawer via the edge-log Broadcast relay.
**The assembled prompt is NOT surfaced in any drawer wire dump.** The
browser logs its own *pre-priming* view of the request under source
`chat` ("venice request wire", in `chat-loop.ts`) before it POSTs;
`chat` ("venice request wire", in `chat/loop.ts`) before it POSTs;
the server then appends the bias + intent appendices and splices the
`<think>` chain server-side, so those additions never appear in that
dump. The server-side `stream` source carries only operational lines
Expand All @@ -184,7 +184,7 @@ browser surface is unchanged:
- [`tools.md`](./tools.md) - the tool catalog + toolbox-state halves of
the system prompt.
- The baseline prompt + catalog are browser-side
(`src/lib/chat-prompt.ts`); the bias appendix + `<think>`-chain
(`src/lib/chat/system-prompt.ts`); the bias appendix + `<think>`-chain
assembly + ordering are server-side
(`supabase/functions/venice/priming.ts`), with the trigger evaluator
mirrored in `_shared/priming-triggers.ts`.
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/second-thoughts.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ and fires the RPC best-effort for persistence across reload / device.
merge that lands the verdict's realtime echo.
- `src/lib/chat/prompt-assembly.ts` - `toVeniceMessage`'s acted-doubt
`<think>` projection.
- `src/lib/chat/types.ts` / `src/lib/chat-loop.ts` / `src/lib/venice.ts`
- `src/lib/chat/types.ts` / `src/lib/chat/loop.ts` / `src/lib/venice.ts`
- the `skipPriming` plumbing.
- `src/lib/supabase.ts` - `markSecondThoughtsActed`.

Expand Down
10 changes: 5 additions & 5 deletions docs/dev/tools.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ The catalog and the dispatch live on opposite sides of the wire:

- **The browser owns the catalog.** `buildToolList` composes the
wire `tools` array from the thread's enabled toolboxes, and
`src/lib/chat-prompt.ts` renders the same registry into the
`src/lib/chat/system-prompt.ts` renders the same registry into the
system-prompt catalog. Every browser `ToolDef` is a
`serverSideTool(schema)` - catalog metadata plus an `execute()`
that throws. Nothing dispatches tools in the browser.
Expand Down Expand Up @@ -205,7 +205,7 @@ Browser catalog (`src/lib/tools/`):

Adjacent browser modules:

- `src/lib/chat-prompt.ts` - `buildSystemPrompt` renders the
- `src/lib/chat/system-prompt.ts` - `buildSystemPrompt` renders the
registry into the system-prompt catalog; `buildToolboxStateBlock`
renders the volatile `(on)`/`(off)` state.
- `src/lib/ask-user.ts` - the ask_user suspend/resume envelope
Expand Down Expand Up @@ -252,7 +252,7 @@ Edge dispatch (`supabase/functions/venice/`):

## Entry points

- **Chat loop** - `chat-loop.ts` calls
- **Chat loop** - `chat/loop.ts` calls
`buildToolList(thread.toolboxes_enabled)` to ship the wire
`tools` array, then observes the streamed `tool_call_request` /
`tool_call_response` events. The edge function is
Expand All @@ -266,7 +266,7 @@ Edge dispatch (`supabase/functions/venice/`):
Triggers and per-agent stories live with the owning features
(`./memory.md`, `./wiki.md`).
- **System prompt assembly** - `buildSystemPrompt({ biasProfile })`
in `src/lib/chat-prompt.ts` composes the baseline system message.
in `src/lib/chat/system-prompt.ts` composes the baseline system message.
The catalog section lists always-on tools first, then each gated
toolbox and its tools. The catalog is state-free: it lists what
toolboxes exist, not which are enabled, so the baseline stays
Expand Down Expand Up @@ -366,7 +366,7 @@ Edge dispatch (`supabase/functions/venice/`):
(first-seen wins). Callers should never construct this array
by hand.
- `buildSystemPrompt(opts?)` / `buildToolboxStateBlock(enabled)` -
live in `src/lib/chat-prompt.ts`, importing the registry from
live in `src/lib/chat/system-prompt.ts`, importing the registry from
here. The baseline is state-free; the state block renders the
gated toolboxes as `(on)`/`(off)` lines and rides the per-turn
metadata message. Unknown names in `enabled` are ignored;
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/wiki.md
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ Main-thread plumbing:
`profiles.settings.displayTimezone` server-side.
- `src/lib/routing.svelte.ts` - extends `DrawerTab` with `'wiki'`
and `Route` with `wiki_article_id`.
- `src/lib/chat-prompt.ts` - `WIKI_BLOCK` after `JOURNAL_BLOCK` in
- `src/lib/chat/system-prompt.ts` - `WIKI_BLOCK` after `JOURNAL_BLOCK` in
the section list.

UI:
Expand Down
2 changes: 1 addition & 1 deletion docs/qa/use-cases/chat-cutoff-retry.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ cut-off reply's partial is preserved as a card, not dropped"):
write even when only reasoning streamed (`ensureAssistantRow`
normally fires on first `response_text`). Browser side, `venice.ts`
keeps the drain open past the `error` broadcast so the terminal END
carries the row id, and `consumeStreamEvents` (`chat-loop.ts`)
carries the row id, and `consumeStreamEvents` (`chat/loop.ts`)
hydrates that row before throwing.
2. **Retry replaces.** `retryIncompleteTurn` + the classification
predicates in `src/lib/ui/incomplete-turn.ts` (`isReasoningOnlyStall`,
Expand Down
4 changes: 2 additions & 2 deletions docs/qa/use-cases/intent-injection-toggle.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ drawer source ([dev: logging](../../dev/logging.md)).
The "# Working intentions" block is spliced into the row-0 system
message INSIDE the edge function (`applyIntentPriming`), AFTER the
browser has already POSTed and logged its own pre-priming view of
the wire (`chat-loop.ts` "venice request wire", source `chat`). The
the wire (`chat/loop.ts` "venice request wire", source `chat`). The
server-side `stream` logger carries only operational lines
(round/historyLen/terminal kind), never the assembled prompt
content. So there is NO drawer-surfaced dump of the row-0 system
Expand Down Expand Up @@ -125,4 +125,4 @@ update threads set intent_active_at_turn = '{}' where user_id = '$UID';
| Date | Env | Commit | Result | Notes |
| ---- | --- | ------ | ------ | ----- |
| 2026-06-24 | — | (this commit) | not run | Authored alongside the feature; first execution pending a live stack (cloud authoring env has none). The sequencing (intent block after bias on row 0) is also pinned by a Deno orchestration test; this case proves the end-to-end wire + the toggle gate + the snapshot, which unit tests cannot reach. |
| 2026-06-24 | local (dev-start) | f05168c | pass | First execution, driven by calling the real `applyIntentPriming` against the local Postgres (the orchestrator/Venice/Realtime path is unnecessary - priming is what mutates row-0 + writes the snapshot). Gate held: toggle off -> no block injected, `intent_active_at_turn` stayed `{}`. Toggle on -> block injected into row-0 with the dispositional-leans framing + user-instructions-first precedence note + both statements as bullets; snapshot held exactly the 2 active intent ids (cross-checked). With a bias block pre-seeded on row-0, the intent block landed AFTER it (precedence "guidance above" resolves). Cap arithmetic is pure + unit-covered (`intent-format.test.ts`). Rewrote the verification this run: dropped the non-executable "read the block in the `stream` wire" step (the block is spliced server-side after the browser logs its pre-priming wire, and the `stream` logger carries only operational lines - confirmed against `chat-loop.ts` + `getStreamingResponse.ts`); the faithful signal is the `intent_active_at_turn` snapshot. Root inaccuracy lives in `prompt-augmentation.md`'s Observability claim (tracked separately). |
| 2026-06-24 | local (dev-start) | f05168c | pass | First execution, driven by calling the real `applyIntentPriming` against the local Postgres (the orchestrator/Venice/Realtime path is unnecessary - priming is what mutates row-0 + writes the snapshot). Gate held: toggle off -> no block injected, `intent_active_at_turn` stayed `{}`. Toggle on -> block injected into row-0 with the dispositional-leans framing + user-instructions-first precedence note + both statements as bullets; snapshot held exactly the 2 active intent ids (cross-checked). With a bias block pre-seeded on row-0, the intent block landed AFTER it (precedence "guidance above" resolves). Cap arithmetic is pure + unit-covered (`intent-format.test.ts`). Rewrote the verification this run: dropped the non-executable "read the block in the `stream` wire" step (the block is spliced server-side after the browser logs its pre-priming wire, and the `stream` logger carries only operational lines - confirmed against `chat/loop.ts` + `getStreamingResponse.ts`); the faithful signal is the `intent_active_at_turn` snapshot. Root inaccuracy lives in `prompt-augmentation.md`'s Observability claim (tracked separately). |
11 changes: 6 additions & 5 deletions src/components/SamskaraHealthPanel.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
* One Refresh reloads BOTH - the summary and every health read - so
* the page is a single coherent snapshot, not two stale halves.
*
* Composition only: every severity classification, relative-time
* format, and count-to-label transform is delegated to
* `$lib/ui/samskara-browse`.
* Composition only: the severity classification, regen status, and
* count-to-label transforms are delegated to
* `$lib/ui/samskara-health`; the relative-time format comes from
* `$lib/ui/samskara-browse`, shared with the detail pane.
*/
import { onMount } from 'svelte';
import { app } from '$lib/state.svelte';
Expand All @@ -28,13 +29,13 @@
compoundRegenStatus,
worstSeverity,
healthHeadline,
relativeTime,
verdictBreakdown,
tier2CandidateLabel,
samskaraCountPhrase,
HEALTH_THRESHOLDS,
type Severity,
} from '$lib/ui/samskara-browse';
} from '$lib/ui/samskara-health';
import { relativeTime } from '$lib/ui/samskara-browse';
import type { SamskaraHealthSnapshot, SamskaraRates } from '$lib/supabase';

let loading = $state(true);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/app-state/root.svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ interface AppState {
* per-turn system-prompt appendix asking the model to use light
* Markdown emphasis for semantic save-points (bold terms, italic
* phrases). Opt-in; seeded from Supabase on unlock. See
* chat-loop.ts for the exact blurb.
* chat/loop.ts for the exact blurb.
*/
emphasisMarkdown: boolean;
/**
Expand Down
Loading