@runtypelabs/persona 4.25.0 → 4.26.1
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/animations/glyph-cycle.d.cts +1 -1
- package/dist/animations/glyph-cycle.d.ts +1 -1
- package/dist/animations/{types-Db61aI9J.d.cts → types-BwKTZhg9.d.cts} +14 -0
- package/dist/animations/{types-Db61aI9J.d.ts → types-BwKTZhg9.d.ts} +14 -0
- package/dist/animations/wipe.d.cts +1 -1
- package/dist/animations/wipe.d.ts +1 -1
- package/dist/animations-extra.d.cts +14 -0
- package/dist/animations-extra.d.ts +14 -0
- package/dist/approval-ui-QAKWNFNM.js +1 -0
- package/dist/approval-ui.cjs +2 -2
- package/dist/approval-ui.d.cts +186 -8
- package/dist/approval-ui.d.ts +186 -8
- package/dist/approval-ui.js +2 -2
- package/dist/{artifacts-ui-IGB5YKLO.js → artifacts-ui-NJGMM27I.js} +1 -1
- package/dist/artifacts-ui.cjs +4 -4
- package/dist/artifacts-ui.d.cts +186 -8
- package/dist/artifacts-ui.d.ts +186 -8
- package/dist/artifacts-ui.js +5 -5
- package/dist/chunk-2ANTRKTV.js +1 -0
- package/dist/chunk-4HPTPUC6.js +1 -0
- package/dist/chunk-6V3MNEKB.js +1 -0
- package/dist/chunk-GKPCIQPB.js +1 -0
- package/dist/chunk-HGUCGM3K.js +9 -0
- package/dist/chunk-IO5VVUKP.js +3 -0
- package/dist/chunk-J4J3Y2P2.js +1 -0
- package/dist/chunk-K6HKIP5K.js +1 -0
- package/dist/chunk-K7NA7G7J.js +1 -0
- package/dist/chunk-MXUTS3LB.js +1 -0
- package/dist/chunk-PDPVORUF.js +1 -0
- package/dist/chunk-QRKGQPU7.js +1 -0
- package/dist/chunk-S6PBWE75.js +1 -0
- package/dist/chunk-T7QM7YMF.js +1 -0
- package/dist/chunk-TR2H475E.js +1 -0
- package/dist/chunk-UPO4GUFC.js +1 -0
- package/dist/chunk-ZC66NAIR.js +1 -0
- package/dist/client-history-GOZWBDA5.js +1 -0
- package/dist/client-history.js +1 -0
- package/dist/client-stream-42FOI3EC.js +4 -0
- package/dist/client-stream.js +5 -0
- package/dist/codegen.cjs +1 -1
- package/dist/codegen.js +1 -1
- package/dist/context-mentions-E7HJYWO6.js +161 -0
- package/dist/{context-mentions-inline-I2RDEBAK.js → context-mentions-inline-QVESLW55.js} +1 -1
- package/dist/context-mentions.cjs +7 -7
- package/dist/context-mentions.d.cts +186 -8
- package/dist/context-mentions.d.ts +186 -8
- package/dist/context-mentions.js +8 -8
- package/dist/event-stream-view-FOIJHFQO.js +1 -0
- package/dist/event-stream-view.cjs +1 -1
- package/dist/event-stream-view.d.cts +189 -31
- package/dist/event-stream-view.d.ts +189 -31
- package/dist/event-stream-view.js +1 -1
- package/dist/forms-ui.d.cts +227 -667
- package/dist/forms-ui.d.ts +227 -667
- package/dist/history-shell-QDQ44PSE.js +3 -0
- package/dist/history-shell.js +3 -0
- package/dist/{history-view-BD6OXLNA.js → history-view-NCFBI5GR.js} +2 -2
- package/dist/history-view.cjs +2 -2
- package/dist/history-view.d.cts +35 -1
- package/dist/history-view.d.ts +35 -1
- package/dist/history-view.js +2 -2
- package/dist/index.cjs +80 -74
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +233 -738
- package/dist/index.d.ts +233 -738
- package/dist/index.global.js +3 -215
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +81 -75
- package/dist/index.js.map +1 -1
- package/dist/install.global.js +1 -1
- package/dist/install.global.js.map +1 -1
- package/dist/launcher.global.js +3 -67
- package/dist/launcher.global.js.map +1 -1
- package/dist/markdown-parsers.js +22 -22
- package/dist/runtype-tts-entry-NFBVWR7N.js +1 -0
- package/dist/runtype-tts.js +1 -1
- package/dist/session-actions-ISSKSI66.js +1 -0
- package/dist/session-actions.js +1 -0
- package/dist/session-reconnect.d.cts +186 -8
- package/dist/session-reconnect.d.ts +186 -8
- package/dist/smart-dom-reader.cjs +13 -13
- package/dist/smart-dom-reader.d.cts +186 -8
- package/dist/smart-dom-reader.d.ts +186 -8
- package/dist/smart-dom-reader.js +11 -11
- package/dist/theme-editor-preview.cjs +116 -98
- package/dist/theme-editor-preview.d.cts +188 -8
- package/dist/theme-editor-preview.d.ts +188 -8
- package/dist/theme-editor-preview.js +49 -54
- package/dist/theme-editor.cjs +2 -2
- package/dist/theme-editor.d.cts +187 -23
- package/dist/theme-editor.d.ts +187 -23
- package/dist/theme-editor.js +2 -2
- package/dist/theme-reference.d.cts +14 -0
- package/dist/theme-reference.d.ts +14 -0
- package/dist/ui-extras-entry-WAYFKVNW.js +3 -0
- package/dist/ui-extras.js +72 -0
- package/dist/voice-runtime-XLU6YK2N.js +17 -0
- package/dist/voice-runtime.cjs +17 -1
- package/dist/voice-runtime.d.cts +11656 -232
- package/dist/voice-runtime.d.ts +11656 -232
- package/dist/voice-runtime.js +17 -1
- package/dist/voice-worklet-player.cjs +19 -4
- package/dist/voice-worklet-player.d.cts +9 -10
- package/dist/voice-worklet-player.d.ts +9 -10
- package/dist/voice-worklet-player.js +19 -4
- package/dist/webmcp-polyfill.js +1 -1
- package/dist/webmcp-runtime-V6ZWW3PI.js +6 -0
- package/dist/webmcp-runtime.cjs +2 -2
- package/dist/webmcp-runtime.d.cts +1 -33
- package/dist/webmcp-runtime.d.ts +1 -33
- package/dist/webmcp-runtime.js +2 -2
- package/dist/widget.css +1 -1
- package/package.json +11 -5
- package/src/approval-paused-tool-settle.test.ts +325 -0
- package/src/client-approve.test.ts +311 -0
- package/src/client-history-eager.ts +9 -0
- package/src/client-history-loader.ts +23 -0
- package/src/client-history.ts +579 -0
- package/src/client-resume.ts +177 -0
- package/src/client-stream-eager.ts +12 -0
- package/src/client-stream-loader.ts +25 -0
- package/src/client-stream.ts +1880 -0
- package/src/client.test.ts +31 -1
- package/src/client.ts +293 -2607
- package/src/components/approval-actions.test.ts +27 -0
- package/src/components/approval-actions.ts +27 -3
- package/src/components/message-bubble.test.ts +19 -0
- package/src/components/message-bubble.ts +2 -0
- package/src/components/registry.ts +6 -6
- package/src/components/tool-bubble.test.ts +9 -0
- package/src/components/tool-bubble.ts +1 -0
- package/src/history-shell-bundle.test.ts +54 -0
- package/src/history-shell-eager.ts +12 -0
- package/src/history-shell-loader.ts +27 -0
- package/src/history-shell.ts +2362 -0
- package/src/history-view-loader.ts +2 -0
- package/src/history-view.ts +3 -0
- package/src/index-core.ts +6 -0
- package/src/index-global.ts +90 -248
- package/src/index.ts +13 -0
- package/src/install.ts +6 -4
- package/src/internal/runtype-history-provider.test.ts +1 -0
- package/src/internal/runtype-history-provider.ts +28 -13
- package/src/plugins/registry.ts +8 -8
- package/src/session-actions-chunk.test.ts +55 -0
- package/src/session-actions-eager.ts +11 -0
- package/src/session-actions-loader.ts +37 -0
- package/src/session-actions.ts +909 -0
- package/src/session-history.test.ts +3 -1
- package/src/session.ts +895 -1538
- package/src/session.voice.test.ts +1171 -5
- package/src/styles/widget.css +58 -0
- package/src/theme-editor/state.ts +91 -91
- package/src/types.ts +204 -5
- package/src/ui-ask-user-sheet.ts +382 -0
- package/src/ui-extras-eager.ts +10 -0
- package/src/ui-extras-entry.ts +9 -0
- package/src/ui-extras-loader.ts +26 -0
- package/src/ui.artifact-rail-resize.test.ts +2 -1
- package/src/ui.ask-user-chunk.test.ts +93 -0
- package/src/ui.history-chunk.test.ts +2 -1
- package/src/ui.history-config-provider.test.ts +2 -1
- package/src/ui.history-confirm-fallback.test.ts +142 -0
- package/src/ui.history-controller.test.ts +2 -1
- package/src/ui.history-lifecycle.test.ts +2 -1
- package/src/ui.history-render-hooks.test.ts +2 -1
- package/src/ui.history-shell.test.ts +2 -1
- package/src/ui.rail-overlay.test.ts +2 -1
- package/src/ui.rail-resize.test.ts +2 -1
- package/src/ui.rail-trigger-pending.test.ts +2 -1
- package/src/ui.ts +340 -2770
- package/src/utils/attachment-manager.ts +67 -67
- package/src/utils/constants.ts +3 -0
- package/src/utils/context-mention-controller.ts +323 -323
- package/src/utils/context-mention-manager.ts +40 -40
- package/src/utils/context-mention-orchestrator.ts +28 -0
- package/src/utils/event-stream-buffer.ts +50 -50
- package/src/utils/event-stream-store.ts +43 -43
- package/src/utils/throughput-tracker.ts +34 -34
- package/src/utils/virtual-scroller.ts +67 -67
- package/src/utils/visitor-store.test.ts +50 -0
- package/src/utils/visitor-store.ts +23 -5
- package/src/voice/__fixtures__/voice-wire/README.md +1 -0
- package/src/voice/__fixtures__/voice-wire/client/cancel.json +3 -0
- package/src/voice/__fixtures__/voice-wire/client/context.json +4 -0
- package/src/voice/__fixtures__/voice-wire/client/delegation_result.json +6 -0
- package/src/voice/__fixtures__/voice-wire/client/delegation_update.json +6 -0
- package/src/voice/__fixtures__/voice-wire/client/ping.json +3 -0
- package/src/voice/__fixtures__/voice-wire/client/playback_progress.json +5 -0
- package/src/voice/__fixtures__/voice-wire/client/start.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/artifact.json +11 -0
- package/src/voice/__fixtures__/voice-wire/server/attached.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/audio_clear.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/audio_end.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_cancelled.json +5 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_completed.json +8 -0
- package/src/voice/__fixtures__/voice-wire/server/delegation_started.json +15 -0
- package/src/voice/__fixtures__/voice-wire/server/error.json +6 -0
- package/src/voice/__fixtures__/voice-wire/server/metrics.json +10 -0
- package/src/voice/__fixtures__/voice-wire/server/pong.json +3 -0
- package/src/voice/__fixtures__/voice-wire/server/session_config.json +16 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_final.json +7 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_interim.json +4 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_partial.json +6 -0
- package/src/voice/__fixtures__/voice-wire/server/transcript_update.json +10 -0
- package/src/voice/__fixtures__/voice-wire/server/warning.json +5 -0
- package/src/voice/audio-playback-manager.test.ts +57 -0
- package/src/voice/audio-playback-manager.ts +120 -98
- package/src/voice/browser-voice-provider.ts +37 -37
- package/src/voice/fallback-speech-engine.ts +22 -16
- package/src/voice/keyed-voice-transcript.ts +314 -0
- package/src/voice/mic-state-styles.ts +182 -0
- package/src/voice/read-aloud-controller.ts +46 -44
- package/src/voice/runtype-speech-engine.ts +35 -33
- package/src/voice/runtype-voice-provider.ts +680 -189
- package/src/voice/session-voice-wiring.ts +266 -0
- package/src/voice/voice-delegation.test.ts +71 -0
- package/src/voice/voice-delegation.ts +364 -0
- package/src/voice/voice-turn-tracker.ts +6 -6
- package/src/voice/voice.test.ts +1060 -8
- package/src/voice/worklet-playback-engine.test.ts +81 -0
- package/src/voice/worklet-playback-engine.ts +21 -3
- package/src/voice-runtime-loader.ts +4 -1
- package/src/voice-runtime.ts +7 -0
- package/src/webmcp-runtime-entry.ts +41 -39
- package/dist/approval-ui-3NMYNXBD.js +0 -1
- package/dist/chunk-5EIIHQLQ.js +0 -1
- package/dist/chunk-7CO4T5KB.js +0 -1
- package/dist/chunk-EFJBUH5F.js +0 -1
- package/dist/chunk-R2TMIMDI.js +0 -3
- package/dist/chunk-UTVLOTWB.js +0 -9
- package/dist/context-mentions-45MODWOY.js +0 -161
- package/dist/event-stream-view-GL3ADRY2.js +0 -1
- package/dist/runtype-tts-entry-UJAEF7NZ.js +0 -1
- package/dist/voice-runtime-7DA7MJH4.js +0 -1
- package/dist/webmcp-runtime-JI7T4QYF.js +0 -6
|
@@ -95,16 +95,16 @@ const mentionKey = (sourceId: string, itemId: string) => `${sourceId}\u0000${ite
|
|
|
95
95
|
* that's the controller's job.
|
|
96
96
|
*/
|
|
97
97
|
export class ContextMentionManager {
|
|
98
|
-
|
|
98
|
+
readonly #opts: ContextMentionManagerOptions;
|
|
99
99
|
private readonly mentions: PendingMention[] = [];
|
|
100
100
|
|
|
101
101
|
constructor(opts: ContextMentionManagerOptions) {
|
|
102
|
-
this
|
|
103
|
-
this
|
|
102
|
+
this.#opts = opts;
|
|
103
|
+
this.#updateRowVisibility();
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
return this
|
|
106
|
+
get #maxMentions(): number {
|
|
107
|
+
return this.#opts.mentionConfig.maxMentions ?? 8;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
hasMentions(): boolean {
|
|
@@ -123,9 +123,9 @@ export class ContextMentionManager {
|
|
|
123
123
|
): boolean {
|
|
124
124
|
const key = mentionKey(source.id, item.id);
|
|
125
125
|
if (this.mentions.some((m) => m.key === key)) {
|
|
126
|
-
return this
|
|
126
|
+
return this.#reject(source, item, "duplicate");
|
|
127
127
|
}
|
|
128
|
-
if (this.atLimit()) return this
|
|
128
|
+
if (this.atLimit()) return this.#reject(source, item, "limit");
|
|
129
129
|
|
|
130
130
|
const ref = refFromItem(source, item);
|
|
131
131
|
const pending: PendingMention = {
|
|
@@ -138,7 +138,7 @@ export class ContextMentionManager {
|
|
|
138
138
|
};
|
|
139
139
|
pending.chip = createMentionChip({
|
|
140
140
|
ref,
|
|
141
|
-
config: this
|
|
141
|
+
config: this.#opts.mentionConfig,
|
|
142
142
|
onRemove: () => this.remove(key),
|
|
143
143
|
});
|
|
144
144
|
// Mention chips are always new when appended (a rebuild clears them with
|
|
@@ -149,17 +149,17 @@ export class ContextMentionManager {
|
|
|
149
149
|
() => pending.chip?.el.removeAttribute("data-persona-chip-enter"),
|
|
150
150
|
{ once: true }
|
|
151
151
|
);
|
|
152
|
-
this
|
|
152
|
+
this.#opts.contextRow.appendChild(pending.chip.el);
|
|
153
153
|
// startPending pushes into this.mentions, which updateRowVisibility reads —
|
|
154
154
|
// reversed order left the row hidden until the second chip.
|
|
155
|
-
this
|
|
156
|
-
this
|
|
155
|
+
this.#startPending(pending);
|
|
156
|
+
this.#updateRowVisibility();
|
|
157
157
|
return true;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
/** True when the mention limit is already reached (inline pre-insert gate). */
|
|
161
161
|
atLimit(): boolean {
|
|
162
|
-
return this.mentions.length >= this
|
|
162
|
+
return this.mentions.length >= this.#maxMentions;
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
/**
|
|
@@ -177,7 +177,7 @@ export class ContextMentionManager {
|
|
|
177
177
|
source: AgentWidgetContextMentionSource,
|
|
178
178
|
item: AgentWidgetContextMentionItem
|
|
179
179
|
): boolean {
|
|
180
|
-
if (this.atLimit()) return this
|
|
180
|
+
if (this.atLimit()) return this.#reject(source, item, "limit");
|
|
181
181
|
return true;
|
|
182
182
|
}
|
|
183
183
|
|
|
@@ -204,17 +204,17 @@ export class ContextMentionManager {
|
|
|
204
204
|
args,
|
|
205
205
|
reportStatus,
|
|
206
206
|
};
|
|
207
|
-
this
|
|
207
|
+
this.#startPending(pending);
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
/** Fire the rejection hooks for a blocked mention and return false (add's sentinel). */
|
|
211
|
-
|
|
211
|
+
#reject(
|
|
212
212
|
source: AgentWidgetContextMentionSource,
|
|
213
213
|
item: AgentWidgetContextMentionItem,
|
|
214
214
|
reason: "duplicate" | "limit"
|
|
215
215
|
): false {
|
|
216
|
-
this
|
|
217
|
-
this
|
|
216
|
+
this.#opts.mentionConfig.onMentionRejected?.(item, reason);
|
|
217
|
+
this.#opts.emit?.("rejected", { sourceId: source.id, itemId: item.id, reason });
|
|
218
218
|
return false;
|
|
219
219
|
}
|
|
220
220
|
|
|
@@ -224,39 +224,39 @@ export class ContextMentionManager {
|
|
|
224
224
|
* else starts the select-time resolve, keeping the promise so `finalize()`
|
|
225
225
|
* awaits this exact resolve rather than firing a second one.
|
|
226
226
|
*/
|
|
227
|
-
|
|
227
|
+
#startPending(pending: PendingMention): void {
|
|
228
228
|
this.mentions.push(pending);
|
|
229
229
|
if (pending.source.resolveOn === "submit") {
|
|
230
230
|
pending.status = "ready";
|
|
231
231
|
pending.chip?.setStatus("ready");
|
|
232
232
|
pending.reportStatus?.("resolved");
|
|
233
233
|
} else {
|
|
234
|
-
pending.resolvePromise = this
|
|
234
|
+
pending.resolvePromise = this.#resolvePending(pending);
|
|
235
235
|
}
|
|
236
|
-
this
|
|
236
|
+
this.#opts.announce(`Added ${pending.ref.label} to context`);
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
|
|
239
|
+
#buildResolveContext(
|
|
240
240
|
signal: AbortSignal,
|
|
241
241
|
args: string,
|
|
242
|
-
composerText = this
|
|
242
|
+
composerText = this.#opts.getComposerText()
|
|
243
243
|
) {
|
|
244
244
|
return {
|
|
245
|
-
messages: this
|
|
246
|
-
config: this
|
|
245
|
+
messages: this.#opts.getMessages(),
|
|
246
|
+
config: this.#opts.getConfig(),
|
|
247
247
|
composerText,
|
|
248
248
|
args,
|
|
249
249
|
signal,
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
|
|
253
|
+
async #resolvePending(pending: PendingMention): Promise<void> {
|
|
254
254
|
const abort = new AbortController();
|
|
255
255
|
pending.abort = abort;
|
|
256
256
|
try {
|
|
257
257
|
const payload = await pending.source.resolve(
|
|
258
258
|
pending.item,
|
|
259
|
-
this
|
|
259
|
+
this.#buildResolveContext(abort.signal, pending.args)
|
|
260
260
|
);
|
|
261
261
|
if (abort.signal.aborted) return;
|
|
262
262
|
pending.payload = payload;
|
|
@@ -272,11 +272,11 @@ export class ContextMentionManager {
|
|
|
272
272
|
pending.reportStatus?.("error");
|
|
273
273
|
// Speak the failure through the ASSERTIVE region — the visual error state
|
|
274
274
|
// (chip/token color) is otherwise silent for screen-reader users.
|
|
275
|
-
(this
|
|
275
|
+
(this.#opts.announceError ?? this.#opts.announce)(
|
|
276
276
|
`Couldn't attach ${pending.ref.label} to context`
|
|
277
277
|
);
|
|
278
|
-
this
|
|
279
|
-
this
|
|
278
|
+
this.#opts.mentionConfig.onMentionResolveError?.(pending.item, error);
|
|
279
|
+
this.#opts.emit?.("resolve-error", {
|
|
280
280
|
sourceId: pending.source.id,
|
|
281
281
|
itemId: pending.item.id,
|
|
282
282
|
});
|
|
@@ -289,8 +289,8 @@ export class ContextMentionManager {
|
|
|
289
289
|
const [pending] = this.mentions.splice(index, 1);
|
|
290
290
|
pending.abort?.abort();
|
|
291
291
|
pending.chip?.el.remove();
|
|
292
|
-
this
|
|
293
|
-
this
|
|
292
|
+
this.#updateRowVisibility();
|
|
293
|
+
this.#opts.announce(`Removed ${pending.ref.label} from context`);
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
/** Currently tracked refs, in order. Read-only: does not detach anything. */
|
|
@@ -312,7 +312,7 @@ export class ContextMentionManager {
|
|
|
312
312
|
m.chip?.el.remove();
|
|
313
313
|
}
|
|
314
314
|
this.mentions.length = 0;
|
|
315
|
-
this
|
|
315
|
+
this.#updateRowVisibility();
|
|
316
316
|
}
|
|
317
317
|
|
|
318
318
|
/**
|
|
@@ -330,12 +330,12 @@ export class ContextMentionManager {
|
|
|
330
330
|
collectForSubmit(): { refs: AgentWidgetContextMentionRef[]; finalize: () => Promise<MentionSubmitBundle> } {
|
|
331
331
|
const snapshot = [...this.mentions];
|
|
332
332
|
const refs = snapshot.map((m) => m.ref);
|
|
333
|
-
const composerText = this
|
|
333
|
+
const composerText = this.#opts.getComposerText();
|
|
334
334
|
|
|
335
335
|
// Detach: empty the composer chip row without aborting resolves.
|
|
336
336
|
for (const m of snapshot) m.chip?.el.remove();
|
|
337
337
|
this.mentions.length = 0;
|
|
338
|
-
this
|
|
338
|
+
this.#updateRowVisibility();
|
|
339
339
|
|
|
340
340
|
const finalize = async (): Promise<MentionSubmitBundle> => {
|
|
341
341
|
// Resolve every mention concurrently: submit-deferred sources resolve now;
|
|
@@ -346,7 +346,7 @@ export class ContextMentionManager {
|
|
|
346
346
|
if (m.source.resolveOn === "submit") {
|
|
347
347
|
return await m.source.resolve(
|
|
348
348
|
m.item,
|
|
349
|
-
this
|
|
349
|
+
this.#buildResolveContext(new AbortController().signal, m.args, composerText)
|
|
350
350
|
);
|
|
351
351
|
}
|
|
352
352
|
if (m.resolvePromise) await m.resolvePromise;
|
|
@@ -355,13 +355,13 @@ export class ContextMentionManager {
|
|
|
355
355
|
// A throwing host `onMentionResolveError` must not reject the whole
|
|
356
356
|
// bundle — guard the callback so one bad item just drops.
|
|
357
357
|
try {
|
|
358
|
-
this
|
|
358
|
+
this.#opts.mentionConfig.onMentionResolveError?.(m.item, error);
|
|
359
359
|
} catch (cbError) {
|
|
360
360
|
if (typeof console !== "undefined") {
|
|
361
361
|
console.warn("[Persona] onMentionResolveError callback threw", cbError);
|
|
362
362
|
}
|
|
363
363
|
}
|
|
364
|
-
this
|
|
364
|
+
this.#opts.emit?.("resolve-error", {
|
|
365
365
|
sourceId: m.source.id,
|
|
366
366
|
itemId: m.item.id,
|
|
367
367
|
});
|
|
@@ -398,7 +398,7 @@ export class ContextMentionManager {
|
|
|
398
398
|
formatMentionBlock(
|
|
399
399
|
{ label: m.ref.label, text: payload.llmAppend, ref: m.ref, item: m.item },
|
|
400
400
|
blocks.length,
|
|
401
|
-
this
|
|
401
|
+
this.#opts.mentionConfig.llmFormat
|
|
402
402
|
)
|
|
403
403
|
);
|
|
404
404
|
} catch (error) {
|
|
@@ -425,7 +425,7 @@ export class ContextMentionManager {
|
|
|
425
425
|
* The row is shared with the composer's mode chips, so visibility follows the
|
|
426
426
|
* row's children, never this manager's mention count.
|
|
427
427
|
*/
|
|
428
|
-
|
|
429
|
-
syncComposerChipRow(this
|
|
428
|
+
#updateRowVisibility(): void {
|
|
429
|
+
syncComposerChipRow(this.#opts.contextRow);
|
|
430
430
|
}
|
|
431
431
|
}
|
|
@@ -76,6 +76,22 @@ export interface ContextMentionOrchestrator {
|
|
|
76
76
|
destroy: () => void;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
export type ContextMentionOrchestratorDeps = {
|
|
80
|
+
loadContextMentions: typeof loadContextMentions;
|
|
81
|
+
loadContextMentionsInline: typeof loadContextMentionsInline;
|
|
82
|
+
renderLucideIcon: typeof renderLucideIcon;
|
|
83
|
+
createMentionButton: typeof createMentionButton;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Call through the live module bindings (not captured references) so spies
|
|
87
|
+
// and late re-registration keep working.
|
|
88
|
+
const defaultDeps: ContextMentionOrchestratorDeps = {
|
|
89
|
+
loadContextMentions: () => loadContextMentions(),
|
|
90
|
+
loadContextMentionsInline: () => loadContextMentionsInline(),
|
|
91
|
+
renderLucideIcon: (...args) => renderLucideIcon(...args),
|
|
92
|
+
createMentionButton: (...args) => createMentionButton(...args),
|
|
93
|
+
};
|
|
94
|
+
|
|
79
95
|
export function createContextMentionOrchestrator(opts: {
|
|
80
96
|
config: AgentWidgetConfig;
|
|
81
97
|
textarea: HTMLTextAreaElement;
|
|
@@ -94,7 +110,19 @@ export function createContextMentionOrchestrator(opts: {
|
|
|
94
110
|
* Omit and the orchestrator creates a standalone row the caller must place.
|
|
95
111
|
*/
|
|
96
112
|
chipRow?: HTMLElement;
|
|
113
|
+
/**
|
|
114
|
+
* Stateful collaborators (chunk loaders, icon registry, tooltip-backed
|
|
115
|
+
* button). The IIFE/CDN build loads this module in the lazy `ui-extras`
|
|
116
|
+
* chunk and passes core's instances so the chunk never uses its own copies.
|
|
117
|
+
*/
|
|
118
|
+
deps?: ContextMentionOrchestratorDeps;
|
|
97
119
|
}): ContextMentionOrchestrator | null {
|
|
120
|
+
const {
|
|
121
|
+
loadContextMentions,
|
|
122
|
+
loadContextMentionsInline,
|
|
123
|
+
renderLucideIcon,
|
|
124
|
+
createMentionButton,
|
|
125
|
+
} = opts.deps ?? defaultDeps;
|
|
98
126
|
const mentionConfig = opts.config.contextMentions;
|
|
99
127
|
if (!mentionConfig?.enabled) return null;
|
|
100
128
|
|
|
@@ -2,70 +2,70 @@ import type { SSEEventRecord } from "../types";
|
|
|
2
2
|
import type { EventStreamStore } from "./event-stream-store";
|
|
3
3
|
|
|
4
4
|
export class EventStreamBuffer {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
#buffer: SSEEventRecord[];
|
|
6
|
+
#head = 0;
|
|
7
|
+
#count = 0;
|
|
8
|
+
#totalCaptured = 0;
|
|
9
|
+
#eventTypesSet = new Set<string>();
|
|
10
|
+
readonly #maxSize: number;
|
|
11
|
+
readonly #store: EventStreamStore | null;
|
|
12
12
|
|
|
13
13
|
constructor(maxSize = 2000, store: EventStreamStore | null = null) {
|
|
14
|
-
this
|
|
15
|
-
this
|
|
16
|
-
this
|
|
14
|
+
this.#maxSize = maxSize;
|
|
15
|
+
this.#buffer = new Array(maxSize);
|
|
16
|
+
this.#store = store;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
push(event: SSEEventRecord): void {
|
|
20
|
-
this
|
|
21
|
-
this
|
|
22
|
-
if (this
|
|
23
|
-
this
|
|
20
|
+
this.#buffer[this.#head] = event;
|
|
21
|
+
this.#head = (this.#head + 1) % this.#maxSize;
|
|
22
|
+
if (this.#count < this.#maxSize) {
|
|
23
|
+
this.#count++;
|
|
24
24
|
}
|
|
25
|
-
this
|
|
26
|
-
this
|
|
27
|
-
this
|
|
25
|
+
this.#totalCaptured++;
|
|
26
|
+
this.#eventTypesSet.add(event.type);
|
|
27
|
+
this.#store?.put(event);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
getAll(): SSEEventRecord[] {
|
|
31
|
-
if (this
|
|
32
|
-
if (this
|
|
33
|
-
return this
|
|
31
|
+
if (this.#count === 0) return [];
|
|
32
|
+
if (this.#count < this.#maxSize) {
|
|
33
|
+
return this.#buffer.slice(0, this.#count);
|
|
34
34
|
}
|
|
35
35
|
// Buffer is full, items wrap around
|
|
36
36
|
return [
|
|
37
|
-
...this
|
|
38
|
-
...this
|
|
37
|
+
...this.#buffer.slice(this.#head, this.#maxSize),
|
|
38
|
+
...this.#buffer.slice(0, this.#head)
|
|
39
39
|
];
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
async restore(): Promise<number> {
|
|
43
|
-
if (!this
|
|
44
|
-
const events = await this
|
|
43
|
+
if (!this.#store) return 0;
|
|
44
|
+
const events = await this.#store.getAll();
|
|
45
45
|
if (events.length === 0) return 0;
|
|
46
46
|
|
|
47
47
|
// Take the most recent maxSize events (store returns sorted by timestamp)
|
|
48
|
-
const toLoad = events.length > this
|
|
49
|
-
? events.slice(events.length - this
|
|
48
|
+
const toLoad = events.length > this.#maxSize
|
|
49
|
+
? events.slice(events.length - this.#maxSize)
|
|
50
50
|
: events;
|
|
51
51
|
|
|
52
52
|
// Populate the ring buffer without writing back to the store
|
|
53
53
|
for (const event of toLoad) {
|
|
54
|
-
this
|
|
55
|
-
this
|
|
56
|
-
if (this
|
|
57
|
-
this
|
|
54
|
+
this.#buffer[this.#head] = event;
|
|
55
|
+
this.#head = (this.#head + 1) % this.#maxSize;
|
|
56
|
+
if (this.#count < this.#maxSize) {
|
|
57
|
+
this.#count++;
|
|
58
58
|
}
|
|
59
|
-
this
|
|
59
|
+
this.#eventTypesSet.add(event.type);
|
|
60
60
|
}
|
|
61
|
-
this
|
|
61
|
+
this.#totalCaptured = events.length;
|
|
62
62
|
|
|
63
63
|
return toLoad.length;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
getAllFromStore(): Promise<SSEEventRecord[]> {
|
|
67
|
-
if (this
|
|
68
|
-
return this
|
|
67
|
+
if (this.#store) {
|
|
68
|
+
return this.#store.getAll();
|
|
69
69
|
}
|
|
70
70
|
return Promise.resolve(this.getAll());
|
|
71
71
|
}
|
|
@@ -77,36 +77,36 @@ export class EventStreamBuffer {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
getSize(): number {
|
|
80
|
-
return this
|
|
80
|
+
return this.#count;
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
getTotalCaptured(): number {
|
|
84
|
-
return this
|
|
84
|
+
return this.#totalCaptured;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
getEvictedCount(): number {
|
|
88
|
-
return this
|
|
88
|
+
return this.#totalCaptured - this.#count;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
clear(): void {
|
|
92
|
-
this
|
|
93
|
-
this
|
|
94
|
-
this
|
|
95
|
-
this
|
|
96
|
-
this
|
|
97
|
-
this
|
|
92
|
+
this.#buffer = new Array(this.#maxSize);
|
|
93
|
+
this.#head = 0;
|
|
94
|
+
this.#count = 0;
|
|
95
|
+
this.#totalCaptured = 0;
|
|
96
|
+
this.#eventTypesSet.clear();
|
|
97
|
+
this.#store?.clear();
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
destroy(): void {
|
|
101
|
-
this
|
|
102
|
-
this
|
|
103
|
-
this
|
|
104
|
-
this
|
|
105
|
-
this
|
|
106
|
-
this
|
|
101
|
+
this.#buffer = [];
|
|
102
|
+
this.#head = 0;
|
|
103
|
+
this.#count = 0;
|
|
104
|
+
this.#totalCaptured = 0;
|
|
105
|
+
this.#eventTypesSet.clear();
|
|
106
|
+
this.#store?.destroy();
|
|
107
107
|
}
|
|
108
108
|
|
|
109
109
|
getEventTypes(): string[] {
|
|
110
|
-
return Array.from(this
|
|
110
|
+
return Array.from(this.#eventTypesSet);
|
|
111
111
|
}
|
|
112
112
|
}
|
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import type { SSEEventRecord } from "../types";
|
|
2
2
|
|
|
3
3
|
export class EventStreamStore {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
#db: IDBDatabase | null = null;
|
|
5
|
+
#pendingWrites: SSEEventRecord[] = [];
|
|
6
|
+
#flushScheduled = false;
|
|
7
|
+
#isDestroyed = false;
|
|
8
|
+
readonly #dbName: string;
|
|
9
|
+
readonly #storeName: string;
|
|
10
10
|
|
|
11
11
|
constructor(dbName = "persona-event-stream", storeName = "events") {
|
|
12
|
-
this
|
|
13
|
-
this
|
|
12
|
+
this.#dbName = dbName;
|
|
13
|
+
this.#storeName = storeName;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
open(): Promise<void> {
|
|
17
17
|
return new Promise((resolve, reject) => {
|
|
18
18
|
try {
|
|
19
|
-
const request = indexedDB.open(this
|
|
19
|
+
const request = indexedDB.open(this.#dbName, 1);
|
|
20
20
|
|
|
21
21
|
request.onupgradeneeded = () => {
|
|
22
22
|
const db = request.result;
|
|
23
|
-
if (!db.objectStoreNames.contains(this
|
|
24
|
-
const store = db.createObjectStore(this
|
|
23
|
+
if (!db.objectStoreNames.contains(this.#storeName)) {
|
|
24
|
+
const store = db.createObjectStore(this.#storeName, { keyPath: "id" });
|
|
25
25
|
store.createIndex("timestamp", "timestamp", { unique: false });
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
request.onsuccess = () => {
|
|
30
|
-
this
|
|
30
|
+
this.#db = request.result;
|
|
31
31
|
resolve();
|
|
32
32
|
};
|
|
33
33
|
|
|
@@ -41,19 +41,19 @@ export class EventStreamStore {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
put(event: SSEEventRecord): void {
|
|
44
|
-
if (!this
|
|
45
|
-
this
|
|
46
|
-
if (!this
|
|
47
|
-
this
|
|
48
|
-
queueMicrotask(() => this
|
|
44
|
+
if (!this.#db || this.#isDestroyed) return;
|
|
45
|
+
this.#pendingWrites.push(event);
|
|
46
|
+
if (!this.#flushScheduled) {
|
|
47
|
+
this.#flushScheduled = true;
|
|
48
|
+
queueMicrotask(() => this.#flushWrites());
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
putBatch(events: SSEEventRecord[]): void {
|
|
53
|
-
if (!this
|
|
53
|
+
if (!this.#db || this.#isDestroyed || events.length === 0) return;
|
|
54
54
|
try {
|
|
55
|
-
const tx = this
|
|
56
|
-
const store = tx.objectStore(this
|
|
55
|
+
const tx = this.#db.transaction(this.#storeName, "readwrite");
|
|
56
|
+
const store = tx.objectStore(this.#storeName);
|
|
57
57
|
for (const event of events) {
|
|
58
58
|
store.put(event);
|
|
59
59
|
}
|
|
@@ -64,13 +64,13 @@ export class EventStreamStore {
|
|
|
64
64
|
|
|
65
65
|
getAll(): Promise<SSEEventRecord[]> {
|
|
66
66
|
return new Promise((resolve, reject) => {
|
|
67
|
-
if (!this
|
|
67
|
+
if (!this.#db) {
|
|
68
68
|
resolve([]);
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
try {
|
|
72
|
-
const tx = this
|
|
73
|
-
const store = tx.objectStore(this
|
|
72
|
+
const tx = this.#db.transaction(this.#storeName, "readonly");
|
|
73
|
+
const store = tx.objectStore(this.#storeName);
|
|
74
74
|
const index = store.index("timestamp");
|
|
75
75
|
const request = index.getAll();
|
|
76
76
|
|
|
@@ -89,13 +89,13 @@ export class EventStreamStore {
|
|
|
89
89
|
|
|
90
90
|
getCount(): Promise<number> {
|
|
91
91
|
return new Promise((resolve, reject) => {
|
|
92
|
-
if (!this
|
|
92
|
+
if (!this.#db) {
|
|
93
93
|
resolve(0);
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
96
|
try {
|
|
97
|
-
const tx = this
|
|
98
|
-
const store = tx.objectStore(this
|
|
97
|
+
const tx = this.#db.transaction(this.#storeName, "readonly");
|
|
98
|
+
const store = tx.objectStore(this.#storeName);
|
|
99
99
|
const request = store.count();
|
|
100
100
|
|
|
101
101
|
request.onsuccess = () => {
|
|
@@ -113,14 +113,14 @@ export class EventStreamStore {
|
|
|
113
113
|
|
|
114
114
|
clear(): Promise<void> {
|
|
115
115
|
return new Promise((resolve, reject) => {
|
|
116
|
-
if (!this
|
|
116
|
+
if (!this.#db) {
|
|
117
117
|
resolve();
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
|
-
this
|
|
120
|
+
this.#pendingWrites = [];
|
|
121
121
|
try {
|
|
122
|
-
const tx = this
|
|
123
|
-
const store = tx.objectStore(this
|
|
122
|
+
const tx = this.#db.transaction(this.#storeName, "readwrite");
|
|
123
|
+
const store = tx.objectStore(this.#storeName);
|
|
124
124
|
const request = store.clear();
|
|
125
125
|
|
|
126
126
|
request.onsuccess = () => {
|
|
@@ -137,19 +137,19 @@ export class EventStreamStore {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
close(): void {
|
|
140
|
-
if (this
|
|
141
|
-
this
|
|
142
|
-
this
|
|
140
|
+
if (this.#db) {
|
|
141
|
+
this.#db.close();
|
|
142
|
+
this.#db = null;
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
destroy(): Promise<void> {
|
|
147
|
-
this
|
|
148
|
-
this
|
|
147
|
+
this.#isDestroyed = true;
|
|
148
|
+
this.#pendingWrites = [];
|
|
149
149
|
this.close();
|
|
150
150
|
return new Promise((resolve, reject) => {
|
|
151
151
|
try {
|
|
152
|
-
const request = indexedDB.deleteDatabase(this
|
|
152
|
+
const request = indexedDB.deleteDatabase(this.#dbName);
|
|
153
153
|
|
|
154
154
|
request.onsuccess = () => {
|
|
155
155
|
resolve();
|
|
@@ -164,14 +164,14 @@ export class EventStreamStore {
|
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
166
|
|
|
167
|
-
|
|
168
|
-
this
|
|
169
|
-
if (!this
|
|
170
|
-
const toWrite = this
|
|
171
|
-
this
|
|
167
|
+
#flushWrites(): void {
|
|
168
|
+
this.#flushScheduled = false;
|
|
169
|
+
if (!this.#db || this.#isDestroyed || this.#pendingWrites.length === 0) return;
|
|
170
|
+
const toWrite = this.#pendingWrites;
|
|
171
|
+
this.#pendingWrites = [];
|
|
172
172
|
try {
|
|
173
|
-
const tx = this
|
|
174
|
-
const store = tx.objectStore(this
|
|
173
|
+
const tx = this.#db.transaction(this.#storeName, "readwrite");
|
|
174
|
+
const store = tx.objectStore(this.#storeName);
|
|
175
175
|
for (const event of toWrite) {
|
|
176
176
|
store.put(event);
|
|
177
177
|
}
|