@poodle64/librarian 2026.9.13 → 2026.9.14
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/components/agent-transcript/agent-transcript.svelte +8 -2
- package/dist/components/composer/composer.svelte +5 -2
- package/dist/components/composer/composer.svelte.d.ts +2 -0
- package/dist/components/conversation/conversation.svelte +21 -6
- package/dist/components/conversation/conversation.svelte.d.ts +3 -0
- package/dist/copy.d.ts +3 -0
- package/dist/copy.js +1 -0
- package/package.json +1 -1
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
trustMark,
|
|
26
26
|
type Citation
|
|
27
27
|
} from '../../citations';
|
|
28
|
-
import { resolveCopy, type LibrarianCopy } from '../../copy';
|
|
28
|
+
import { DEFAULT_COPY, resolveCopy, type LibrarianCopy } from '../../copy';
|
|
29
29
|
import Working from '../working/working.svelte';
|
|
30
30
|
import ActivityGroup from '../activity-group/activity-group.svelte';
|
|
31
31
|
import ArtefactCard from '../artefact-card/artefact-card.svelte';
|
|
@@ -133,9 +133,15 @@
|
|
|
133
133
|
* a duration badge, and — worse — the "he holds nothing on this" line,
|
|
134
134
|
* which is a claim about the shelf made off a run that never finished
|
|
135
135
|
* looking.
|
|
136
|
+
*
|
|
137
|
+
* `error` still carries `DEFAULT_COPY.unreachable` verbatim from `client.ts`
|
|
138
|
+
* — the stream layer has no `name` to compose with — so that exact default
|
|
139
|
+
* is swapped for `words.unreachable`, which `Conversation`'s `name` prop
|
|
140
|
+
* (or a host's own `copy` override) already resolved.
|
|
136
141
|
*/
|
|
137
142
|
const failure = $derived(
|
|
138
|
-
outcome?.error
|
|
143
|
+
(outcome?.error === DEFAULT_COPY.unreachable ? words.unreachable : outcome?.error) ??
|
|
144
|
+
(outcome?.isError ? words.answerFailed : null)
|
|
139
145
|
);
|
|
140
146
|
|
|
141
147
|
// A failed turn settles too, and "Ask again" is the one thing a reader wants
|
|
@@ -44,6 +44,8 @@
|
|
|
44
44
|
* control renders — studying is a mode of asking, never a tab, so a
|
|
45
45
|
* host with nothing to build offers none rather than a disabled one. */
|
|
46
46
|
onbriefing?: () => void;
|
|
47
|
+
/** The persona's display name; the placeholder in both states takes it. */
|
|
48
|
+
name?: string;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
let {
|
|
@@ -57,7 +59,8 @@
|
|
|
57
59
|
onscope,
|
|
58
60
|
onsubmit,
|
|
59
61
|
onstop,
|
|
60
|
-
onbriefing
|
|
62
|
+
onbriefing,
|
|
63
|
+
name = 'Milton'
|
|
61
64
|
}: Props = $props();
|
|
62
65
|
|
|
63
66
|
// What Milton is being asked about — this document, this collection, or
|
|
@@ -214,7 +217,7 @@
|
|
|
214
217
|
onkeydown={keydown}
|
|
215
218
|
rows="1"
|
|
216
219
|
disabled={running}
|
|
217
|
-
placeholder={running ?
|
|
220
|
+
placeholder={running ? `${name} is answering…` : `Ask ${name}…`}
|
|
218
221
|
class="text-foreground placeholder:text-muted-foreground w-full resize-none bg-transparent px-4 pt-3 pb-2 text-base outline-none disabled:opacity-60"
|
|
219
222
|
></textarea>
|
|
220
223
|
|
|
@@ -17,6 +17,8 @@ interface Props {
|
|
|
17
17
|
* control renders — studying is a mode of asking, never a tab, so a
|
|
18
18
|
* host with nothing to build offers none rather than a disabled one. */
|
|
19
19
|
onbriefing?: () => void;
|
|
20
|
+
/** The persona's display name; the placeholder in both states takes it. */
|
|
21
|
+
name?: string;
|
|
20
22
|
}
|
|
21
23
|
declare const Composer: import("svelte").Component<Props, {}, "value" | "files">;
|
|
22
24
|
type Composer = ReturnType<typeof Composer>;
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
/** `Transcript.version` — bumped per event. Text grows in place, so a
|
|
32
32
|
* count of turns is not enough to keep the scroll following. */
|
|
33
33
|
version?: number;
|
|
34
|
+
/** The persona's display name. The aria-label, the `welcome` default and
|
|
35
|
+
* the unreachable alert all take it. */
|
|
36
|
+
name?: string;
|
|
34
37
|
welcome?: string;
|
|
35
38
|
/** Up to three, shown in the empty state as tappable pills. */
|
|
36
39
|
examples?: string[];
|
|
@@ -59,7 +62,8 @@
|
|
|
59
62
|
turns,
|
|
60
63
|
running,
|
|
61
64
|
version = 0,
|
|
62
|
-
|
|
65
|
+
name = 'Milton',
|
|
66
|
+
welcome = `Ask ${name} a question about the library.`,
|
|
63
67
|
examples = [],
|
|
64
68
|
onexample,
|
|
65
69
|
scope,
|
|
@@ -73,6 +77,12 @@
|
|
|
73
77
|
|
|
74
78
|
const words = $derived(resolveCopy(copy));
|
|
75
79
|
|
|
80
|
+
// A host's own `copy.unreachable` still wins: it comes last in the spread.
|
|
81
|
+
const effectiveCopy = $derived<Partial<LibrarianCopy>>({
|
|
82
|
+
unreachable: `${name} can't be reached right now.`,
|
|
83
|
+
...copy
|
|
84
|
+
});
|
|
85
|
+
|
|
76
86
|
let viewport = $state<HTMLElement | null>(null);
|
|
77
87
|
let column = $state<Column>(null);
|
|
78
88
|
const follow = new FollowScroll();
|
|
@@ -160,7 +170,7 @@
|
|
|
160
170
|
role="log"
|
|
161
171
|
aria-live="polite"
|
|
162
172
|
aria-busy={running}
|
|
163
|
-
aria-label="Conversation with
|
|
173
|
+
aria-label="Conversation with {name}"
|
|
164
174
|
class="min-h-0 flex-1 overflow-y-auto overscroll-contain"
|
|
165
175
|
>
|
|
166
176
|
<div class="mx-auto flex w-full max-w-[46rem] flex-col gap-8 px-4 py-6">
|
|
@@ -190,7 +200,7 @@
|
|
|
190
200
|
sit at the top of the same column so a reader meets them in
|
|
191
201
|
the same order whether or not they have asked anything yet. -->
|
|
192
202
|
{#if scope}
|
|
193
|
-
<ScopeStatement statement={scope} expanded={turns.length === 0} {
|
|
203
|
+
<ScopeStatement statement={scope} expanded={turns.length === 0} copy={effectiveCopy} />
|
|
194
204
|
{/if}
|
|
195
205
|
|
|
196
206
|
{#each turns as turn, index (turn.id)}
|
|
@@ -202,7 +212,7 @@
|
|
|
202
212
|
citations={turn.citations ?? []}
|
|
203
213
|
suggestions={turn.suggestions ?? []}
|
|
204
214
|
{collectionNames}
|
|
205
|
-
{
|
|
215
|
+
copy={effectiveCopy}
|
|
206
216
|
kind={turn.kind}
|
|
207
217
|
title={turn.title}
|
|
208
218
|
onopenartefact={() => openArtefact(turn)}
|
|
@@ -235,11 +245,16 @@
|
|
|
235
245
|
</div>
|
|
236
246
|
|
|
237
247
|
{#if column?.kind === 'document' && loadDocument}
|
|
238
|
-
<DocumentPane
|
|
248
|
+
<DocumentPane
|
|
249
|
+
citation={column.citation}
|
|
250
|
+
{loadDocument}
|
|
251
|
+
copy={effectiveCopy}
|
|
252
|
+
onclose={() => (column = null)}
|
|
253
|
+
/>
|
|
239
254
|
{:else if column?.kind === 'artefact'}
|
|
240
255
|
<ArtefactPane
|
|
241
256
|
turn={column.turn}
|
|
242
|
-
{
|
|
257
|
+
copy={effectiveCopy}
|
|
243
258
|
onclose={() => (column = null)}
|
|
244
259
|
oncite={(citation) => cite(citation)}
|
|
245
260
|
/>
|
|
@@ -8,6 +8,9 @@ interface Props {
|
|
|
8
8
|
/** `Transcript.version` — bumped per event. Text grows in place, so a
|
|
9
9
|
* count of turns is not enough to keep the scroll following. */
|
|
10
10
|
version?: number;
|
|
11
|
+
/** The persona's display name. The aria-label, the `welcome` default and
|
|
12
|
+
* the unreachable alert all take it. */
|
|
13
|
+
name?: string;
|
|
11
14
|
welcome?: string;
|
|
12
15
|
/** Up to three, shown in the empty state as tappable pills. */
|
|
13
16
|
examples?: string[];
|
package/dist/copy.d.ts
CHANGED
|
@@ -21,6 +21,9 @@ export interface LibrarianCopy {
|
|
|
21
21
|
notHeld: string;
|
|
22
22
|
/** Shown when the run itself ended in error and said nothing about why. */
|
|
23
23
|
answerFailed: string;
|
|
24
|
+
/** Shown when the stream never opened at all. `Conversation`'s `name`
|
|
25
|
+
* prop composes this default; a host overriding `copy` directly wins. */
|
|
26
|
+
unreachable: string;
|
|
24
27
|
/** Heading over the list of what an answer cited. */
|
|
25
28
|
sources: string;
|
|
26
29
|
/** Heading over the follow-up questions the librarian offered. */
|
package/dist/copy.js
CHANGED
|
@@ -23,6 +23,7 @@ export const DEFAULT_COPY = {
|
|
|
23
23
|
// A run can end `is_error` carrying no message at all, and a turn that
|
|
24
24
|
// simply stops is the one thing a reader must not have to guess about.
|
|
25
25
|
answerFailed: 'Milton stopped before he finished this one.',
|
|
26
|
+
unreachable: "Milton can't be reached right now.",
|
|
26
27
|
sources: 'Sources',
|
|
27
28
|
suggestions: 'Ask next',
|
|
28
29
|
scope: 'What Milton answers from',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poodle64/librarian",
|
|
3
|
-
"version": "2026.9.
|
|
3
|
+
"version": "2026.9.14",
|
|
4
4
|
"description": "Milton's conversation surface as a consumable Svelte 5 package: the stream client, transcript state and chat components (transcript, composer, markdown) every household app renders instead of rebuilding.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|