feat(ui,docs): the open tab lives in the conversation url, admin screenshots in the readme
This commit is contained in:
@@ -7,6 +7,8 @@ boundary - without an opinion about what the agent is for. A setup is one
|
||||
holds the primitives, [beaver-agent](https://git.kotikot.com/beaver/beaver-agent)
|
||||
is a full setup built on them.
|
||||
|
||||

|
||||
|
||||
## What it gives a setup
|
||||
|
||||
- **agents/** - what an agent is: a Claude agent with a prompt per
|
||||
@@ -32,7 +34,13 @@ is a full setup built on them.
|
||||
- **storage/** - SQLModel tables and the Postgres session store.
|
||||
|
||||
`config.py` defines `Gateway` and loads a setup; `app.py` builds the runtime
|
||||
from it; `cli.py` is the entrypoint. Every string the gateway puts in front of
|
||||
from it; `cli.py` is the entrypoint. The admin SPA in `ui/` is the browser
|
||||
window on all of it: conversations by day, the thread with the tree of tool
|
||||
calls, the context of the last turn, memory, jobs, usage, tokens and the audit.
|
||||
|
||||

|
||||
|
||||
 Every string the gateway puts in front of
|
||||
a model or a user has an English default and is overridable
|
||||
(`ConversationTexts`, `TelegramTexts`).
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 138 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 122 KiB |
@@ -18,6 +18,7 @@
|
||||
onOpen,
|
||||
showTitle = true,
|
||||
initialView = "chat",
|
||||
onViewChange,
|
||||
}: {
|
||||
client: ApiClient;
|
||||
id: string;
|
||||
@@ -27,6 +28,8 @@
|
||||
showTitle?: boolean;
|
||||
// "activity" beside a deep chat's own note: the file is the thread.
|
||||
initialView?: string;
|
||||
// The page keeps the open tab in the URL so it survives a reload.
|
||||
onViewChange?: (view: string) => void;
|
||||
} = $props();
|
||||
|
||||
const host = usePanelHost();
|
||||
@@ -50,6 +53,10 @@
|
||||
historyKey += 1;
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
onViewChange?.(view);
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
const { running } = feed.model;
|
||||
if (!running) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import { goto, replaceState } from "$app/navigation";
|
||||
import { base } from "$app/paths";
|
||||
import { page } from "$app/state";
|
||||
import ConversationView from "$lib/panel/conversation-view.svelte";
|
||||
@@ -7,6 +7,22 @@
|
||||
|
||||
const id = $derived(page.params.id ?? "");
|
||||
const href = (target: string) => `${base}/conversations/${target}`;
|
||||
|
||||
// ``?view=context`` opens that tab and stays in the address bar, so a
|
||||
// reload (or a restart) lands where the reader was. Thread is the default
|
||||
// and keeps the URL clean.
|
||||
const initialView = $derived(page.url.searchParams.get("view") ?? "chat");
|
||||
function remember(view: string) {
|
||||
const url = new URL(page.url);
|
||||
if (view === "chat") {
|
||||
url.searchParams.delete("view");
|
||||
} else {
|
||||
url.searchParams.set("view", view);
|
||||
}
|
||||
if (url.href !== page.url.href) {
|
||||
replaceState(url, page.state);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head><title>Conversation · Beaver</title></svelte:head>
|
||||
@@ -17,7 +33,9 @@
|
||||
client={session.client}
|
||||
{href}
|
||||
{id}
|
||||
{initialView}
|
||||
onOpen={(target) => goto(href(target))}
|
||||
onViewChange={remember}
|
||||
/>
|
||||
{/key}
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user