@marketrix.ai/widget 4.0.135 → 4.0.136
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/dist/src/components/views/ChatView.d.ts +5 -1
- package/dist/src/context/ChatContext.d.ts +23 -8
- package/dist/src/hooks/useWidget.d.ts +1 -1
- package/dist/src/sdk/contracts/entities.d.ts +18 -0
- package/dist/src/services/StorageService.d.ts +10 -1
- package/dist/src/services/StreamClient.d.ts +4 -1
- package/dist/widget.mjs +64 -64
- package/package.json +1 -1
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
* shell's toolbar button fills with a share toggle, and the composer textarea ref. `MODES` pairs the
|
|
7
7
|
* mode chips' display order with the tenant setting enabling each, so the composer offers only what
|
|
8
8
|
* the workspace turned on. `ChatView` owns the draft text; `handleSendMessage` posts the turn and
|
|
9
|
-
* `handleModeChange` announces a mode switch in the transcript before flipping state.
|
|
9
|
+
* `handleModeChange` announces a mode switch in the transcript before flipping state. A POST failure
|
|
10
|
+
* restores the composed text to the (now-cleared) composer — `messageDispatch`'s resolved `false` —
|
|
11
|
+
* unless the visitor already started typing a new message in the meantime, so a resend is one tap on
|
|
12
|
+
* Send rather than a retype, and the failed turn's own bubble (added optimistically, unconditionally)
|
|
13
|
+
* still shows what was said either way.
|
|
10
14
|
*
|
|
11
15
|
* The composer is locked both while a reply is outstanding and while a screen-access request is open,
|
|
12
16
|
* since a second turn queued behind an unanswered permission card has nowhere to land. `use_screenshare`
|
|
@@ -8,15 +8,30 @@
|
|
|
8
8
|
* defers updaters and loses the effects captured in them, so tool calls never execute. `messageDispatch`
|
|
9
9
|
* POSTs fire-and-forget: the reply arrives over SSE, so only a POST failure resolves the placeholder
|
|
10
10
|
* locally, and a stale-reply watchdog keyed on id AND part count re-arms on every progress line.
|
|
11
|
+
* `messageDispatch` resolves `false` on that same POST failure (`true` otherwise, including preview
|
|
12
|
+
* mode) so a caller holding the composed text — `ChatView`'s composer — can restore it instead of the
|
|
13
|
+
* visitor having to retype a message the widget already dropped from the input box.
|
|
11
14
|
*
|
|
12
15
|
* The stream effect subscribes to the `StreamClient` singleton: `handleMessage` does the bookkeeping the
|
|
13
|
-
* pure reducer cannot hold (`tool_call_id` dedupe in a bounded set, cleared on a terminal status
|
|
14
|
-
* each effect runs its browser tool, stamps progress,
|
|
15
|
-
*
|
|
16
|
-
* retriable blip settles when the reply lands on the
|
|
17
|
-
* which carries no task id. Every failure on the tool
|
|
18
|
-
* as the console: an undelivered `tool/response`
|
|
19
|
-
* the
|
|
16
|
+
* pure reducer cannot hold (`tool_call_id` dedupe in a bounded set, cleared on a terminal status; the
|
|
17
|
+
* mirror-shaped `respondedRequestIds` below), then each effect runs its browser tool, stamps progress,
|
|
18
|
+
* replies `tool/response` and only then fires `afterResponseAttempt`. `handleError` converts only a
|
|
19
|
+
* `StreamGaveUpError` into a transport failure, as a retriable blip settles when the reply lands on the
|
|
20
|
+
* reconnected stream. `stopTask` sends `chat/stop`, which carries no task id. Every failure on the tool
|
|
21
|
+
* and stop paths reaches `uiActions.setError` as well as the console: an undelivered `tool/response`
|
|
22
|
+
* leaves the agent waiting on a reply that never comes, so the run stalls with nothing on screen unless
|
|
23
|
+
* the visitor is told, and `do` mode may still be clicking.
|
|
24
|
+
*
|
|
25
|
+
* `respondedRequestIds` closes the other half of the reconnect-replay contract `StreamClient.ts`
|
|
26
|
+
* documents (the api replays a chat_id's whole turn history, not just the tail a client missed):
|
|
27
|
+
* `reduceText`'s own exact-repeat guard (`sseReducer.ts`) only catches an identical FINAL
|
|
28
|
+
* `chat/response` replayed after the answer already closed, because it only ever compares against the
|
|
29
|
+
* message's LAST part. A replayed `chat/delta` fails that same-string check (it's a partial fragment,
|
|
30
|
+
* not the full closed text) and would otherwise be appended as a brand-new, visibly duplicated text
|
|
31
|
+
* segment ahead of the closing response that then only overwrites the one it just added — leaving two
|
|
32
|
+
* copies of the same answer on screen. Scoped by `request_id`, not globally, so an unrelated later
|
|
33
|
+
* turn's genuinely new `chat/delta`/`chat/response` is untouched; marked closed only once, on the
|
|
34
|
+
* request's own terminal `chat/response`, since a delta is by definition still open.
|
|
20
35
|
*
|
|
21
36
|
* `lastStreamErrorRef`/`currentErrorRef` close the loop `handleError` alone leaves open: `StreamClient`
|
|
22
37
|
* calls `onError` on every failed dial, not only a terminal give-up, so the visitor sees "Stream
|
|
@@ -43,7 +58,7 @@ interface ChatActions {
|
|
|
43
58
|
removeMessage: (messageId: string) => void;
|
|
44
59
|
setMessages: (messages: ChatMessage[]) => void;
|
|
45
60
|
clearMessages: () => void;
|
|
46
|
-
messageDispatch: (content: string, mode?: InstructionType, skipUserMessage?: boolean) => Promise<
|
|
61
|
+
messageDispatch: (content: string, mode?: InstructionType, skipUserMessage?: boolean) => Promise<boolean>;
|
|
47
62
|
}
|
|
48
63
|
interface TaskActions {
|
|
49
64
|
resetTask: () => void;
|
|
@@ -21,7 +21,7 @@ export declare const useWidget: () => {
|
|
|
21
21
|
removeMessage: (messageId: string) => void;
|
|
22
22
|
setMessages: (messages: import("..").ChatMessage[]) => void;
|
|
23
23
|
clearMessages: () => void;
|
|
24
|
-
messageDispatch: (content: string, mode?: import("..").InstructionType, skipUserMessage?: boolean) => Promise<
|
|
24
|
+
messageDispatch: (content: string, mode?: import("..").InstructionType, skipUserMessage?: boolean) => Promise<boolean>;
|
|
25
25
|
resetTask: () => void;
|
|
26
26
|
stopTask: () => Promise<void>;
|
|
27
27
|
setActiveView: (view: import("../types").WidgetView) => void;
|
|
@@ -135,6 +135,12 @@ export declare const WorkspaceSummarySchema: z.ZodObject<{
|
|
|
135
135
|
notify_all_members_on_question: z.ZodBoolean;
|
|
136
136
|
}, z.core.$strip>;
|
|
137
137
|
export type WorkspaceSummary = z.infer<typeof WorkspaceSummarySchema>;
|
|
138
|
+
export declare const ApplicationSkillDistillationStatusSchema: z.ZodEnum<{
|
|
139
|
+
failed: "failed";
|
|
140
|
+
idle: "idle";
|
|
141
|
+
pending: "pending";
|
|
142
|
+
}>;
|
|
143
|
+
export type ApplicationSkillDistillationStatus = z.infer<typeof ApplicationSkillDistillationStatusSchema>;
|
|
138
144
|
export declare const ApplicationEntitySchema: z.ZodObject<{
|
|
139
145
|
id: z.ZodNumber;
|
|
140
146
|
created_at: z.ZodCoercedDate<unknown>;
|
|
@@ -150,6 +156,12 @@ export declare const ApplicationEntitySchema: z.ZodObject<{
|
|
|
150
156
|
username: z.ZodNullable<z.ZodString>;
|
|
151
157
|
password: z.ZodNullable<z.ZodString>;
|
|
152
158
|
allowed_domains: z.ZodArray<z.ZodString>;
|
|
159
|
+
skill_distillation_status: z.ZodEnum<{
|
|
160
|
+
failed: "failed";
|
|
161
|
+
idle: "idle";
|
|
162
|
+
pending: "pending";
|
|
163
|
+
}>;
|
|
164
|
+
skill_distillation_error: z.ZodNullable<z.ZodString>;
|
|
153
165
|
}, z.core.$strip>;
|
|
154
166
|
export type ApplicationData = z.infer<typeof ApplicationEntitySchema>;
|
|
155
167
|
/** Used for all API responses; password is write-only and never returned to clients. */
|
|
@@ -167,6 +179,12 @@ export declare const ApplicationReadSchema: z.ZodObject<{
|
|
|
167
179
|
workspace_id: z.ZodNumber;
|
|
168
180
|
username: z.ZodNullable<z.ZodString>;
|
|
169
181
|
allowed_domains: z.ZodArray<z.ZodString>;
|
|
182
|
+
skill_distillation_status: z.ZodEnum<{
|
|
183
|
+
failed: "failed";
|
|
184
|
+
idle: "idle";
|
|
185
|
+
pending: "pending";
|
|
186
|
+
}>;
|
|
187
|
+
skill_distillation_error: z.ZodNullable<z.ZodString>;
|
|
170
188
|
}, z.core.$strip>;
|
|
171
189
|
export type ApplicationReadData = z.infer<typeof ApplicationReadSchema>;
|
|
172
190
|
export declare const WidgetChipSchema: z.ZodObject<{
|
|
@@ -5,7 +5,12 @@
|
|
|
5
5
|
* browser-local key shares via `scopedKey`, so the chat-context, drag-position and resize keys all
|
|
6
6
|
* partition by tenant identically. `readLocal`/`writeLocal` are the only `localStorage` access in `src/`;
|
|
7
7
|
* a host page can deny storage outright (third-party cookies off, sandboxed iframe), so both degrade to
|
|
8
|
-
*
|
|
8
|
+
* memory and the widget keeps working unpersisted. `updateContext` calls `writeLocal` on every UI-state
|
|
9
|
+
* change (a drag, a resize, every chat message), so without `warnOnce` a denied host page would spam one
|
|
10
|
+
* console line per write for the visitor's whole session; a single warn on first denial says everything
|
|
11
|
+
* a customer's console needs. `warnOnce` is keyed by read vs. write since `readLocal` also fires once on
|
|
12
|
+
* its own (`loadContext` at module init, before any write) and both should still surface if a page
|
|
13
|
+
* somehow denies one and not the other.
|
|
9
14
|
*
|
|
10
15
|
* `loadContext` merges one parsed key over `DEFAULT_CONTEXT`, so an older widget version's payload reads
|
|
11
16
|
* as incomplete rather than corrupt, and discards anything past `CONTEXT_EXPIRY_MS` (7 days).
|
|
@@ -55,6 +60,10 @@ type MarketrixChatContext = Omit<ChatSnapshot, 'messages'> & {
|
|
|
55
60
|
};
|
|
56
61
|
export declare function tenantScope(config: MarketrixConfig): string;
|
|
57
62
|
export declare function scopedKey(name: string, config: MarketrixConfig): string;
|
|
63
|
+
/** Test-only: `warned` is module-level so a "denies storage, keeps working" proof isn't the last test in
|
|
64
|
+
* the file to touch a denied `Storage.prototype`, and a later test in the same `bun test` process (one
|
|
65
|
+
* process per file, not per test) would otherwise see zero warns instead of one. Never called from `src/`. */
|
|
66
|
+
export declare function resetStorageWarningsForTests(): void;
|
|
58
67
|
export declare function readLocal(key: string): string | null;
|
|
59
68
|
export declare function writeLocal(key: string, value: string): void;
|
|
60
69
|
declare class StorageService {
|
|
@@ -6,7 +6,10 @@
|
|
|
6
6
|
*
|
|
7
7
|
* `open` is the transport, `registered` is the chat: only the latter can carry a reply, so `isConnected` reads
|
|
8
8
|
* `registered` and nothing waits on `open`. Backoff counters reset only on `registered` — resetting at `open` would
|
|
9
|
-
* defeat the max-attempts cap if registration never lands and the stream flaps open→closed.
|
|
9
|
+
* defeat the max-attempts cap if registration never lands and the stream flaps open→closed. `scheduleReconnect`'s
|
|
10
|
+
* EQUAL JITTER (the doubling delay's own second half, chosen uniformly) keeps every dial within the documented
|
|
11
|
+
* schedule's bound while stopping every tab across every open customer page from redialing on the exact same
|
|
12
|
+
* clock tick after a shared outage — a thundering herd the deterministic schedule alone cannot prevent. Tabs share the
|
|
10
13
|
* localStorage chat id, so the server keys SSE by (chat_id, tab_id) and `tabId` stops tabs evicting each other's
|
|
11
14
|
* stream. Credentials are read at connect time, not captured at init, so a reconnect after `updateMarketrixConfig`
|
|
12
15
|
* dials with the current ones.
|