@djangocfg/widget-assistant 0.3.12 → 0.3.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/widget-assistant",
3
- "version": "0.3.12",
3
+ "version": "0.3.13",
4
4
  "description": "A site assistant on top of @djangocfg/widget-chat: the SSE wire and session layer, a persistent host, docked column, floating button and sheet, dictation, Help and 17 built-in locales",
5
5
  "keywords": [
6
6
  "chat",
@@ -44,19 +44,19 @@
44
44
  "test": "vitest run"
45
45
  },
46
46
  "dependencies": {
47
- "@djangocfg/widget-chat": "^0.1.28",
47
+ "@djangocfg/widget-chat": "^0.1.29",
48
48
  "zustand": "^5.0.16"
49
49
  },
50
50
  "peerDependencies": {
51
- "@djangocfg/i18n": "^2.1.627",
52
- "@djangocfg/ui-core": "^2.1.627",
51
+ "@djangocfg/i18n": "^2.1.628",
52
+ "@djangocfg/ui-core": "^2.1.628",
53
53
  "lucide-react": "^1.68.0",
54
54
  "react": "^19.0.0"
55
55
  },
56
56
  "devDependencies": {
57
- "@djangocfg/i18n": "^2.1.627",
58
- "@djangocfg/typescript-config": "^2.1.627",
59
- "@djangocfg/ui-core": "^2.1.627",
57
+ "@djangocfg/i18n": "^2.1.628",
58
+ "@djangocfg/typescript-config": "^2.1.628",
59
+ "@djangocfg/ui-core": "^2.1.628",
60
60
  "@storybook/react-vite": "^10.6.5",
61
61
  "@types/node": "^25.9.5",
62
62
  "@types/react": "19.3.0",
@@ -41,7 +41,7 @@ export interface ChatCallResult<T> {
41
41
  /** The three plain calls of the kit's thread routes, as the host maps them from its generated client (`Chat.chatThreadsList`, ...). The stream is not among them: no schema describes it. */
42
42
  export interface ChatThreadCalls {
43
43
  list: (options: { signal?: AbortSignal }) => Promise<ChatCallResult<readonly ChatThreadListItemShape[]>>;
44
- create: (options: { body?: { kind?: string } }) => Promise<ChatCallResult<ChatThreadShape>>;
44
+ create: (options: { body?: { kind?: string; context?: Record<string, unknown> } }) => Promise<ChatCallResult<ChatThreadShape>>;
45
45
  retrieve: (options: { path: { thread_id: string }; signal?: AbortSignal }) => Promise<ChatCallResult<ChatThreadDetailShape>>;
46
46
  }
47
47
 
@@ -67,7 +67,7 @@ export function storedThreadOf(row: ChatThreadShape & Partial<Pick<ChatThreadLis
67
67
  }
68
68
 
69
69
  export interface ChatTransportConfig
70
- extends Pick<TransportConfig, 'getToken' | 'headers' | 'idleMs' | 'streamFetch'> {
70
+ extends Pick<TransportConfig, 'getToken' | 'headers' | 'idleMs' | 'streamFetch' | 'buildBody'> {
71
71
  /** The thread calls of the generated client. */
72
72
  client: ChatThreadCalls;
73
73
  /** API origin, no trailing slash (the stream is called directly, never through a rewrite). */
@@ -78,6 +78,13 @@ export interface ChatTransportConfig
78
78
  trailingSlash?: boolean;
79
79
  /** The chat kind "New chat" asks for; omit where the server named a default kind. */
80
80
  kind?: string;
81
+ /**
82
+ * Context sent on "New chat" as the create body's `context` (a document id, the page locale), read per call. Return `undefined` for none.
83
+ * Without it a host wraps `client.create` to add it.
84
+ */
85
+ getCreateContext?: () => Record<string, unknown> | undefined;
86
+ /** List only threads that hold at least one message (`message_count > 0`), so an empty "New chat" never fills the menu. Default `false`. */
87
+ hideEmpty?: boolean;
81
88
  }
82
89
 
83
90
  export interface ChatConnection {
@@ -93,18 +100,21 @@ export interface ChatConnection {
93
100
  * The host adds renderers, words, auth (`getToken` / `streamFetch`) and the mount point; nothing else.
94
101
  */
95
102
  export function createChatTransport(config: ChatTransportConfig): ChatConnection {
96
- const { client, baseUrl, mount, kind, trailingSlash = true } = config;
103
+ const { client, baseUrl, mount, kind, trailingSlash = true, getCreateContext, hideEmpty = false } = config;
97
104
  const tail = trailingSlash ? '/' : '';
98
105
  const streamUrl = ({ threadId }: SendInput) => `${mount}/threads/${encodeURIComponent(threadId ?? '')}/messages${tail}`;
99
- const transport = createTransport({ baseUrl, streamUrl, getToken: config.getToken, headers: config.headers, idleMs: config.idleMs, streamFetch: config.streamFetch });
106
+ const transport = createTransport({ baseUrl, streamUrl, getToken: config.getToken, buildBody: config.buildBody, headers: config.headers, idleMs: config.idleMs, streamFetch: config.streamFetch });
100
107
  const api: ThreadApi = {
101
108
  async list(signal) {
102
109
  const res = await client.list({ signal });
103
110
  if (res.error || !res.data) throw new Error('chat threads');
104
- return res.data.map(storedThreadOf);
111
+ const rows = hideEmpty ? res.data.filter((row) => row.message_count > 0) : res.data;
112
+ return rows.map(storedThreadOf);
105
113
  },
106
114
  async create() {
107
- const res = await client.create(kind ? { body: { kind } } : {});
115
+ const context = getCreateContext?.();
116
+ const body = { ...(kind ? { kind } : {}), ...(context ? { context } : {}) };
117
+ const res = await client.create(Object.keys(body).length ? { body } : {});
108
118
  if (res.error || !res.data) throw new Error('chat create');
109
119
  return storedThreadOf(res.data);
110
120
  },