Files
openclaw/src/shared/session-types.ts
Peter Steinberger 8b66fc103d feat(ui): durable session board face and dashboards index (#114262)
* feat(ui): durable session board face and dashboards index

Board face lived only in client-side boardSessionViews, capped at 50 entries,
so the preference never followed the user to another device, evicted as
sessions accumulated, and could not be seen as a set.

Persist it as SessionEntry.boardFace, which rides the existing entry_json blob
and so needs no SQLite schema change or version bump. Expose it on the session
list row and add it to the sessions.patch write-scope allowlist alongside label,
pinned, and archived: setting your own view preference is user-level chat
organization, not policy. Unknown patch fields still fail closed to
operator.admin.

Generic navigation now reads the stored face, so the sidebar and session list
open a thread on the face you left it on. boardSessionViews keeps only
activeTabId and reopenDockByTab, which are genuinely per-device.

Add /dashboards listing threads whose preferred face is dashboard. Filtering
runs server-side in filterSessionEntries before pagination, because the client
holds only a capped page and a client-side filter would silently omit
dashboards.

* test(protocol): assert the pre-rename face param is rejected

The gateway-protocol validator test still passed the pre-rename 'face' key,
which the closed schema rejects. Use boardFace, and pin the old name as a
negative case so it cannot silently return.

* chore(protocol): regenerate Swift bindings and docs map for boardFace

Adding boardFace to the sessions schema changes two committed generated
artifacts: the Swift gateway models (pnpm protocol:gen:swift) and the docs map
(pnpm docs:map:gen), which now lists the dashboards index section.
2026-07-27 00:35:34 -04:00

80 lines
1.9 KiB
TypeScript

/** Agent identity fields returned by gateway session listing APIs. */
type GatewayAgentIdentity = {
name?: string;
theme?: string;
emoji?: string;
avatar?: string;
avatarUrl?: string;
};
/** Model summary returned for an agent/session row. */
type GatewayAgentModel = {
primary?: string;
fallbacks?: string[];
};
/** Runtime selection metadata for an agent row. */
export type GatewayAgentRuntime = {
id: string;
fallback?: "openclaw" | "none";
source:
| "env"
| "agent"
| "defaults"
| "model"
| "provider"
| "implicit"
| "session"
| "session-key";
};
/** Thinking-level option exposed to UI clients. */
export type GatewayThinkingLevelOption = {
id: string;
label: string;
};
export type GatewayAgentKind = "agent" | "system";
/** Per-session Control UI face preference carried by session list rows. */
export type SessionBoardFace = "chat" | "dashboard";
/** Common agent row shape used by session list responses. */
export type GatewayAgentRow = {
id: string;
kind?: GatewayAgentKind;
name?: string;
identity?: GatewayAgentIdentity;
workspace?: string;
workspaceGit?: boolean;
model?: GatewayAgentModel;
agentRuntime?: GatewayAgentRuntime;
thinkingLevels?: GatewayThinkingLevelOption[];
thinkingOptions?: string[];
thinkingDefault?: string;
};
/** Generic base for paged session-list responses. */
export type SessionsListResultBase<TDefaults, TRow> = {
ts: number;
path: string;
count: number;
totalCount?: number;
limitApplied?: number;
offset?: number;
nextOffset?: number | null;
hasMore?: boolean;
/** Complete creator facet for the filtered result, independent of pagination. */
creators?: Array<{ id: string; label?: string }>;
defaults: TDefaults;
sessions: TRow[];
};
/** Generic base for successful session patch responses. */
export type SessionsPatchResultBase<TEntry> = {
ok: true;
path: string;
key: string;
entry: TEntry;
};