@poodle64/librarian 2026.9.28 → 2026.10.0

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.
Files changed (46) hide show
  1. package/README.md +66 -116
  2. package/dist/attachments.d.ts +2 -2
  3. package/dist/attachments.js +3 -3
  4. package/dist/chat.svelte.d.ts +22 -23
  5. package/dist/chat.svelte.js +41 -64
  6. package/dist/citations.d.ts +7 -7
  7. package/dist/citations.js +6 -6
  8. package/dist/client.d.ts +16 -45
  9. package/dist/client.js +15 -23
  10. package/dist/components/activity-group/activity-group.svelte +1 -1
  11. package/dist/components/agent-transcript/agent-transcript.svelte +9 -110
  12. package/dist/components/agent-transcript/agent-transcript.svelte.d.ts +4 -16
  13. package/dist/components/answer-mark/answer-mark.svelte +2 -2
  14. package/dist/components/answer-mark/answer-mark.svelte.d.ts +2 -2
  15. package/dist/components/answer-share/answer-share.svelte +2 -2
  16. package/dist/components/answer-share/answer-share.svelte.d.ts +2 -2
  17. package/dist/components/artefact-card/artefact-card.svelte +2 -2
  18. package/dist/components/artefact-card/artefact-card.svelte.d.ts +2 -2
  19. package/dist/components/artefact-pane/artefact-pane.svelte +2 -2
  20. package/dist/components/artefact-pane/artefact-pane.svelte.d.ts +2 -2
  21. package/dist/components/composer/composer.svelte +39 -112
  22. package/dist/components/composer/composer.svelte.d.ts +18 -18
  23. package/dist/components/composer/index.d.ts +1 -2
  24. package/dist/components/conversation/conversation.svelte +7 -18
  25. package/dist/components/conversation/conversation.svelte.d.ts +7 -12
  26. package/dist/components/conversation-list/conversation-list.svelte +2 -2
  27. package/dist/components/conversation-list/conversation-list.svelte.d.ts +2 -2
  28. package/dist/components/document-pane/document-pane.svelte +2 -2
  29. package/dist/components/document-pane/document-pane.svelte.d.ts +2 -2
  30. package/dist/components/fair-use-notice/fair-use-notice.svelte +2 -2
  31. package/dist/components/fair-use-notice/fair-use-notice.svelte.d.ts +2 -2
  32. package/dist/components/scope-statement/scope-statement.svelte +5 -5
  33. package/dist/components/scope-statement/scope-statement.svelte.d.ts +2 -2
  34. package/dist/components/source-list/source-list.svelte +2 -2
  35. package/dist/components/source-list/source-list.svelte.d.ts +2 -2
  36. package/dist/components/working/working.svelte +2 -2
  37. package/dist/components/working/working.svelte.d.ts +2 -2
  38. package/dist/copy.d.ts +16 -24
  39. package/dist/copy.js +10 -16
  40. package/dist/session.svelte.d.ts +1 -1
  41. package/dist/session.svelte.js +6 -7
  42. package/dist/transcript.svelte.d.ts +18 -32
  43. package/dist/transcript.svelte.js +19 -40
  44. package/package.json +1 -5
  45. package/dist/history.svelte.d.ts +0 -37
  46. package/dist/history.svelte.js +0 -59
@@ -1,20 +1,25 @@
1
- import type { Depth } from '../../client';
2
- import { type LibrarianCopy } from '../../copy';
3
- export type Scope = 'document' | 'collection' | 'library';
1
+ import { type ChatCopy } from '../../copy';
2
+ /** A collection a person may read, as the app lists it: `name` is what a
3
+ * question is narrowed to, `summary` is what the picker shows. */
4
+ export interface CollectionChoice {
5
+ name: string;
6
+ summary: string;
7
+ }
4
8
  interface Props {
5
9
  value: string;
6
10
  running: boolean;
7
- /** What the next message is about. A surface with one scope — a
8
- * session over one document — passes none and offers no choice. */
9
- scope?: Scope;
11
+ /** The collections this person may read. The picker renders when there
12
+ * are two or more: with one, or none, there is nothing to choose. */
13
+ collections?: CollectionChoice[];
14
+ /** The collection the next question is narrowed to, by name; undefined
15
+ * asks across all of them. */
16
+ collection?: string;
10
17
  /** Files to send with the next question. Cleared by the caller on send. */
11
18
  files?: File[];
12
- /** Names for the two narrower scopes; absent means that scope is unavailable. */
13
- documentName?: string;
14
- collectionName?: string;
15
19
  /** Hides the paperclip for a host whose ask route takes no files. */
16
20
  attachments?: boolean;
17
- onscope?: (scope: Scope) => void;
21
+ /** The person picked a collection by name, or all of them (undefined). */
22
+ oncollection?: (collection: string | undefined) => void;
18
23
  onsubmit: () => void;
19
24
  onstop: () => void;
20
25
  /** Asks for a study artefact instead of an ordinary answer. Omit and no
@@ -25,21 +30,16 @@ interface Props {
25
30
  * both placeholders are composed from it. */
26
31
  name?: string;
27
32
  /** Overrides for the package's own words. */
28
- copy?: Partial<LibrarianCopy>;
33
+ copy?: Partial<ChatCopy>;
29
34
  /** The session reads a message sent while it works — a job whose
30
35
  * route writes it onto the running process — so the box stays open
31
36
  * and Send sits beside Stop. Words only: the paperclip still waits for
32
37
  * the run. Absent, a chat waits for its answer. */
33
38
  sendWhileRunning?: boolean;
34
- /** One quiet line in the box's footer, where a scope choice would
39
+ /** One quiet line in the box's footer, where the collection picker would
35
40
  * sit, in the host's words: what sending does here ("It carries on
36
41
  * from where it stopped."). */
37
42
  note?: string;
38
- /** Quick or Thorough for the next question, as a two-way switch with a
39
- * one-line hint. Bind it and pass it to `ask()`; omit it and nothing
40
- * renders. Once shown it is never disabled or hidden, and never names
41
- * the model behind it. */
42
- depth?: Depth;
43
43
  /** How many turns are in the conversation so far. Past `turnLimit`
44
44
  * (8 by default), a quiet banner appears above the box offering to
45
45
  * start over. Omit and no banner ever renders — a host that does not
@@ -51,6 +51,6 @@ interface Props {
51
51
  * action is worse than none. */
52
52
  onnewquestion?: () => void;
53
53
  }
54
- declare const Composer: import("svelte").Component<Props, {}, "value" | "depth" | "files">;
54
+ declare const Composer: import("svelte").Component<Props, {}, "value" | "files">;
55
55
  type Composer = ReturnType<typeof Composer>;
56
56
  export default Composer;
@@ -1,4 +1,3 @@
1
1
  export { default as Composer } from './composer.svelte';
2
2
  export { default } from './composer.svelte';
3
- export type { Scope } from './composer.svelte';
4
- export type { Depth } from '../../client';
3
+ export type { CollectionChoice } from './composer.svelte';
@@ -14,7 +14,7 @@
14
14
  import type { DescribeTool, Turn } from '../../transcript.svelte';
15
15
  import type { Verdict } from '../../chat.svelte';
16
16
  import type { Citation, LoadDocument } from '../../citations';
17
- import { DEFAULT_PERSONA, personaName, resolveCopy, type LibrarianCopy } from '../../copy';
17
+ import { DEFAULT_PERSONA, personaName, resolveCopy, type ChatCopy } from '../../copy';
18
18
  import { FollowScroll } from '../../follow-scroll.svelte';
19
19
  import AgentTranscript, {
20
20
  type AgentTranscriptProps
@@ -37,8 +37,8 @@
37
37
  /** Who is speaking. A slug is fine — `penny` renders as "Penny" — and
38
38
  * every word this package says is composed from it: the working line,
39
39
  * the failure sentences, the scope label, the composer's placeholder
40
- * and the accessible name of the scroll region. Absent is the library's
41
- * own Milton, which is a default rather than a hardcoding. */
40
+ * and the accessible name of the scroll region. Absent is a neutral
41
+ * default, never one app's persona. */
42
42
  name?: string;
43
43
  /** The empty state's opening line. Absent takes the persona's own. */
44
44
  welcome?: string;
@@ -46,27 +46,22 @@
46
46
  examples?: string[];
47
47
  onexample?: (question: string) => void;
48
48
  /** What this surface answers from and what it does not hold, in the
49
- * host's own words. One statement per room, above the first turn,
49
+ * host's own words. One statement per persona, above the first turn,
50
50
  * folded once the conversation starts. */
51
51
  scope?: string;
52
52
  /** Re-asks the last question. Offered on the last answer only. */
53
53
  onregenerate?: () => void;
54
- /** Asks a follow-up the librarian suggested. Offered on the last answer
55
- * only; without it the suggestion chips do not render. */
56
- onsuggest?: (question: string) => void;
57
54
  /** Records a verdict on an answer. Offered on the last answer only, as
58
55
  * asking again is; without it no mark renders. */
59
56
  onmark?: (turn: Turn, verdict: Verdict) => Promise<boolean>;
60
57
  /** Shares an answer read-only, or stops sharing it (`Chat.share`).
61
58
  * Offered on every settled answer; without it nothing is shareable. */
62
59
  onshare?: (turn: Turn, share: boolean) => Promise<boolean>;
63
- /** The last question waits behind somebody else's (`Chat.waiting`). */
64
- waiting?: boolean;
65
60
  /** When the last answer began, epoch ms, where this page did not see it
66
61
  * start (`Chat.answering`): it reads as still being written. */
67
62
  answering?: number | null;
68
63
  /** Overrides for the package's own words. */
69
- copy?: Partial<LibrarianCopy>;
64
+ copy?: Partial<ChatCopy>;
70
65
  /** Enables the source pane. Without it, chips render but do not open. */
71
66
  loadDocument?: LoadDocument;
72
67
  /** Takes every citation tap instead, for a host that shows the source
@@ -83,8 +78,8 @@
83
78
  describeTool?: DescribeTool;
84
79
  /** Prices a turn's `outcome.costUsd` in the host's own currency and
85
80
  * words ("about A$0.34"), for the footer's cost line beside a turn's
86
- * `depth`. The package never converts currency itself; omitted, the
87
- * line shows depth and duration only. */
81
+ * duration. The package never converts currency itself; omitted, the
82
+ * line shows the duration only. */
88
83
  formatCost?: (usd: number) => string;
89
84
  collectionNames?: Set<string>;
90
85
  /** The composer, rendered INSIDE the transcript column so the source
@@ -112,10 +107,8 @@
112
107
  onexample,
113
108
  scope,
114
109
  onregenerate,
115
- onsuggest,
116
110
  onmark,
117
111
  onshare,
118
- waiting = false,
119
112
  answering = null,
120
113
  copy,
121
114
  loadDocument,
@@ -309,10 +302,8 @@
309
302
  blocks: turn.blocks,
310
303
  outcome: turn.outcome,
311
304
  running: running && last,
312
- waiting: waiting && last,
313
305
  answering: last ? (answering ?? undefined) : undefined,
314
306
  citations: turn.citations ?? [],
315
- suggestions: turn.suggestions ?? [],
316
307
  collectionNames,
317
308
  copy: words,
318
309
  name: who,
@@ -321,11 +312,9 @@
321
312
  artefactOpen: isShowing(turn),
322
313
  onopenartefact: opener(turn),
323
314
  describeTool,
324
- depth: turn.depth,
325
315
  formatCost,
326
316
  oncite: oncite || loadDocument ? cite : undefined,
327
317
  onregenerate: last && !running ? onregenerate : undefined,
328
- onsuggest: last && !running ? onsuggest : undefined,
329
318
  onmark:
330
319
  last && !running && onmark ? (verdict: Verdict) => onmark(turn, verdict) : undefined,
331
320
  shared: turn.shared,
@@ -2,7 +2,7 @@ import type { Snippet } from 'svelte';
2
2
  import type { DescribeTool, Turn } from '../../transcript.svelte';
3
3
  import type { Verdict } from '../../chat.svelte';
4
4
  import type { Citation, LoadDocument } from '../../citations';
5
- import { type LibrarianCopy } from '../../copy';
5
+ import { type ChatCopy } from '../../copy';
6
6
  import { type AgentTranscriptProps } from '../agent-transcript/agent-transcript.svelte';
7
7
  interface Props {
8
8
  turns: Turn[];
@@ -13,8 +13,8 @@ interface Props {
13
13
  /** Who is speaking. A slug is fine — `penny` renders as "Penny" — and
14
14
  * every word this package says is composed from it: the working line,
15
15
  * the failure sentences, the scope label, the composer's placeholder
16
- * and the accessible name of the scroll region. Absent is the library's
17
- * own Milton, which is a default rather than a hardcoding. */
16
+ * and the accessible name of the scroll region. Absent is a neutral
17
+ * default, never one app's persona. */
18
18
  name?: string;
19
19
  /** The empty state's opening line. Absent takes the persona's own. */
20
20
  welcome?: string;
@@ -22,27 +22,22 @@ interface Props {
22
22
  examples?: string[];
23
23
  onexample?: (question: string) => void;
24
24
  /** What this surface answers from and what it does not hold, in the
25
- * host's own words. One statement per room, above the first turn,
25
+ * host's own words. One statement per persona, above the first turn,
26
26
  * folded once the conversation starts. */
27
27
  scope?: string;
28
28
  /** Re-asks the last question. Offered on the last answer only. */
29
29
  onregenerate?: () => void;
30
- /** Asks a follow-up the librarian suggested. Offered on the last answer
31
- * only; without it the suggestion chips do not render. */
32
- onsuggest?: (question: string) => void;
33
30
  /** Records a verdict on an answer. Offered on the last answer only, as
34
31
  * asking again is; without it no mark renders. */
35
32
  onmark?: (turn: Turn, verdict: Verdict) => Promise<boolean>;
36
33
  /** Shares an answer read-only, or stops sharing it (`Chat.share`).
37
34
  * Offered on every settled answer; without it nothing is shareable. */
38
35
  onshare?: (turn: Turn, share: boolean) => Promise<boolean>;
39
- /** The last question waits behind somebody else's (`Chat.waiting`). */
40
- waiting?: boolean;
41
36
  /** When the last answer began, epoch ms, where this page did not see it
42
37
  * start (`Chat.answering`): it reads as still being written. */
43
38
  answering?: number | null;
44
39
  /** Overrides for the package's own words. */
45
- copy?: Partial<LibrarianCopy>;
40
+ copy?: Partial<ChatCopy>;
46
41
  /** Enables the source pane. Without it, chips render but do not open. */
47
42
  loadDocument?: LoadDocument;
48
43
  /** Takes every citation tap instead, for a host that shows the source
@@ -59,8 +54,8 @@ interface Props {
59
54
  describeTool?: DescribeTool;
60
55
  /** Prices a turn's `outcome.costUsd` in the host's own currency and
61
56
  * words ("about A$0.34"), for the footer's cost line beside a turn's
62
- * `depth`. The package never converts currency itself; omitted, the
63
- * line shows depth and duration only. */
57
+ * duration. The package never converts currency itself; omitted, the
58
+ * line shows the duration only. */
64
59
  formatCost?: (usd: number) => string;
65
60
  collectionNames?: Set<string>;
66
61
  /** The composer, rendered INSIDE the transcript column so the source
@@ -18,7 +18,7 @@
18
18
  import PlusIcon from '@lucide/svelte/icons/plus';
19
19
  import TrashIcon from '@lucide/svelte/icons/trash-2';
20
20
  import type { ConversationSummary } from '../../chat.svelte';
21
- import { DEFAULT_PERSONA, resolveCopy, type LibrarianCopy } from '../../copy';
21
+ import { DEFAULT_PERSONA, resolveCopy, type ChatCopy } from '../../copy';
22
22
 
23
23
  interface Props {
24
24
  /** Null while it is still being read. */
@@ -39,7 +39,7 @@
39
39
  ondelete?: (id: string) => Promise<boolean>;
40
40
  /** Who is answering, for the line on a conversation still being answered. */
41
41
  name?: string;
42
- copy?: Partial<LibrarianCopy>;
42
+ copy?: Partial<ChatCopy>;
43
43
  }
44
44
 
45
45
  let {
@@ -1,5 +1,5 @@
1
1
  import type { ConversationSummary } from '../../chat.svelte';
2
- import { type LibrarianCopy } from '../../copy';
2
+ import { type ChatCopy } from '../../copy';
3
3
  interface Props {
4
4
  /** Null while it is still being read. */
5
5
  conversations: ConversationSummary[] | null;
@@ -19,7 +19,7 @@ interface Props {
19
19
  ondelete?: (id: string) => Promise<boolean>;
20
20
  /** Who is answering, for the line on a conversation still being answered. */
21
21
  name?: string;
22
- copy?: Partial<LibrarianCopy>;
22
+ copy?: Partial<ChatCopy>;
23
23
  }
24
24
  declare const ConversationList: import("svelte").Component<Props, {}, "">;
25
25
  type ConversationList = ReturnType<typeof ConversationList>;
@@ -10,14 +10,14 @@
10
10
  <script lang="ts">
11
11
  import XIcon from '@lucide/svelte/icons/x';
12
12
  import { trustMark, type Citation, type LoadDocument, type LoadedDocument } from '../../citations';
13
- import { resolveCopy, type LibrarianCopy } from '../../copy';
13
+ import { resolveCopy, type ChatCopy } from '../../copy';
14
14
  import Markdown from '../markdown/markdown.svelte';
15
15
 
16
16
  interface Props {
17
17
  citation: Citation;
18
18
  loadDocument: LoadDocument;
19
19
  onclose: () => void;
20
- copy?: Partial<LibrarianCopy>;
20
+ copy?: Partial<ChatCopy>;
21
21
  }
22
22
 
23
23
  let { citation, loadDocument, onclose, copy }: Props = $props();
@@ -1,10 +1,10 @@
1
1
  import { type Citation, type LoadDocument } from '../../citations';
2
- import { type LibrarianCopy } from '../../copy';
2
+ import { type ChatCopy } from '../../copy';
3
3
  interface Props {
4
4
  citation: Citation;
5
5
  loadDocument: LoadDocument;
6
6
  onclose: () => void;
7
- copy?: Partial<LibrarianCopy>;
7
+ copy?: Partial<ChatCopy>;
8
8
  }
9
9
  declare const DocumentPane: import("svelte").Component<Props, {}, "">;
10
10
  type DocumentPane = ReturnType<typeof DocumentPane>;
@@ -14,13 +14,13 @@
14
14
  <script lang="ts">
15
15
  import InfoIcon from '@lucide/svelte/icons/info';
16
16
  import type { Quota } from '../../chat.svelte';
17
- import { fill, resolveCopy, type LibrarianCopy } from '../../copy';
17
+ import { fill, resolveCopy, type ChatCopy } from '../../copy';
18
18
 
19
19
  interface Props {
20
20
  quota: Quota | null;
21
21
  /** Where to ask about the limit. Absent takes the allowance's own. */
22
22
  supportHref?: string;
23
- copy?: Partial<LibrarianCopy>;
23
+ copy?: Partial<ChatCopy>;
24
24
  }
25
25
 
26
26
  let { quota, supportHref, copy }: Props = $props();
@@ -1,10 +1,10 @@
1
1
  import type { Quota } from '../../chat.svelte';
2
- import { type LibrarianCopy } from '../../copy';
2
+ import { type ChatCopy } from '../../copy';
3
3
  interface Props {
4
4
  quota: Quota | null;
5
5
  /** Where to ask about the limit. Absent takes the allowance's own. */
6
6
  supportHref?: string;
7
- copy?: Partial<LibrarianCopy>;
7
+ copy?: Partial<ChatCopy>;
8
8
  }
9
9
  declare const FairUseNotice: import("svelte").Component<Props, {}, "">;
10
10
  type FairUseNotice = ReturnType<typeof FairUseNotice>;
@@ -1,9 +1,9 @@
1
1
  <!--
2
- What this room answers from, and what it does not hold.
2
+ What a persona answers from, and what it does not hold.
3
3
 
4
- A colleague's first question about a room is not the one they type — it is
4
+ A colleague's first question about a persona is not the one they type — it is
5
5
  whether the answer they are about to read covers their case at all. Saying it
6
- once, in the room's own words, is cheaper than every answer hedging.
6
+ once, in the persona's own words, is cheaper than every answer hedging.
7
7
 
8
8
  It leads while there is nothing else on the surface, and folds to one line as
9
9
  soon as there is: a boundary a reader has already read is a banner in the way
@@ -15,14 +15,14 @@
15
15
  import { untrack } from 'svelte';
16
16
  import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
17
17
  import InfoIcon from '@lucide/svelte/icons/info';
18
- import { resolveCopy, type LibrarianCopy } from '../../copy';
18
+ import { resolveCopy, type ChatCopy } from '../../copy';
19
19
 
20
20
  interface Props {
21
21
  /** The statement itself, in the host's own words. */
22
22
  statement: string;
23
23
  /** Open on arrival. Goes false once the conversation has a first turn. */
24
24
  expanded?: boolean;
25
- copy?: Partial<LibrarianCopy>;
25
+ copy?: Partial<ChatCopy>;
26
26
  }
27
27
 
28
28
  let { statement, expanded = true, copy }: Props = $props();
@@ -1,10 +1,10 @@
1
- import { type LibrarianCopy } from '../../copy';
1
+ import { type ChatCopy } from '../../copy';
2
2
  interface Props {
3
3
  /** The statement itself, in the host's own words. */
4
4
  statement: string;
5
5
  /** Open on arrival. Goes false once the conversation has a first turn. */
6
6
  expanded?: boolean;
7
- copy?: Partial<LibrarianCopy>;
7
+ copy?: Partial<ChatCopy>;
8
8
  }
9
9
  declare const ScopeStatement: import("svelte").Component<Props, {}, "">;
10
10
  type ScopeStatement = ReturnType<typeof ScopeStatement>;
@@ -8,11 +8,11 @@
8
8
  -->
9
9
  <script lang="ts">
10
10
  import { trustMark, type Citation } from '../../citations';
11
- import type { LibrarianCopy } from '../../copy';
11
+ import type { ChatCopy } from '../../copy';
12
12
 
13
13
  interface Props {
14
14
  sources: Citation[];
15
- words: LibrarianCopy;
15
+ words: ChatCopy;
16
16
  /** Opens the document. Omit and the rows list but do not open. */
17
17
  oncite?: (citation: Citation) => void;
18
18
  /** `h2` in a transcript turn, `h3` under the artefact's own title. */
@@ -1,8 +1,8 @@
1
1
  import { type Citation } from '../../citations';
2
- import type { LibrarianCopy } from '../../copy';
2
+ import type { ChatCopy } from '../../copy';
3
3
  interface Props {
4
4
  sources: Citation[];
5
- words: LibrarianCopy;
5
+ words: ChatCopy;
6
6
  /** Opens the document. Omit and the rows list but do not open. */
7
7
  oncite?: (citation: Citation) => void;
8
8
  /** `h2` in a transcript turn, `h3` under the artefact's own title. */
@@ -12,7 +12,7 @@
12
12
  `copy`, which the host's `name` composed, so this component knows no persona.
13
13
  -->
14
14
  <script lang="ts">
15
- import { resolveCopy, type LibrarianCopy } from '../../copy';
15
+ import { resolveCopy, type ChatCopy } from '../../copy';
16
16
 
17
17
  interface Props {
18
18
  /** Shown instead of the cycling word once real work is identifiable. */
@@ -21,7 +21,7 @@
21
21
  * the clock counts from it rather than from the moment it appeared. */
22
22
  since?: number;
23
23
  /** The persona's words. Resolved from `name` upstream. */
24
- copy?: Partial<LibrarianCopy>;
24
+ copy?: Partial<ChatCopy>;
25
25
  }
26
26
 
27
27
  let { label, since, copy }: Props = $props();
@@ -1,4 +1,4 @@
1
- import { type LibrarianCopy } from '../../copy';
1
+ import { type ChatCopy } from '../../copy';
2
2
  interface Props {
3
3
  /** Shown instead of the cycling word once real work is identifiable. */
4
4
  label?: string;
@@ -6,7 +6,7 @@ interface Props {
6
6
  * the clock counts from it rather than from the moment it appeared. */
7
7
  since?: number;
8
8
  /** The persona's words. Resolved from `name` upstream. */
9
- copy?: Partial<LibrarianCopy>;
9
+ copy?: Partial<ChatCopy>;
10
10
  }
11
11
  declare const Working: import("svelte").Component<Props, {}, "">;
12
12
  type Working = ReturnType<typeof Working>;
package/dist/copy.d.ts CHANGED
@@ -3,24 +3,23 @@
3
3
  *
4
4
  * Here rather than inline in each component because these sentences are the
5
5
  * package's opinion about how an agent talks to a colleague, and an app that
6
- * needs a different register — a room whose boundary is worded by its own
6
+ * needs a different register — a persona whose boundary is worded by its own
7
7
  * subject-matter owner — must be able to change one string without forking a
8
8
  * component.
9
9
  *
10
10
  * NO STRING HERE NAMES A PERSONA. The name is an argument: a consuming app
11
11
  * says who is speaking once, and every sentence the package renders is built
12
- * from that. Milton is the library's own persona and therefore the default,
13
- * which is a different thing from being baked in — a package that hardcodes
14
- * one app's persona is a package that lies in every other app, and did:
15
- * Pebblestone's Penny introduced herself as Milton for a fortnight.
12
+ * from that. The default is a neutral name, never one app's persona: a
13
+ * package that hardcodes one app's persona is a package that lies in every
14
+ * other app.
16
15
  *
17
16
  * Every component takes `copy` as a PARTIAL and resolves it itself, so a host
18
17
  * overriding one line does not have to restate the others, and a component
19
18
  * used directly behaves the same as one reached through `Conversation`.
20
19
  */
21
- /** The library's own persona: the default wherever a consumer names none. */
22
- export declare const DEFAULT_PERSONA = "Milton";
23
- export interface LibrarianCopy {
20
+ /** The name used wherever a consumer names no persona. */
21
+ export declare const DEFAULT_PERSONA = "Assistant";
22
+ export interface ChatCopy {
24
23
  /** Prefixes the date on a verified source: "verified 23 Jun 2026". */
25
24
  verified: string;
26
25
  /** A source the catalogue has never confirmed against its publisher. */
@@ -35,8 +34,6 @@ export interface LibrarianCopy {
35
34
  noAnswer: string;
36
35
  /** Heading over the list of what an answer cited. */
37
36
  sources: string;
38
- /** Heading over the follow-up questions the persona offered. */
39
- suggestions: string;
40
37
  /** The collapsed scope statement's own label. */
41
38
  scope: string;
42
39
  /** The empty transcript's opening line. */
@@ -44,14 +41,11 @@ export interface LibrarianCopy {
44
41
  /** The composer's placeholder, idle and while an answer streams. */
45
42
  askPlaceholder: string;
46
43
  answeringPlaceholder: string;
47
- /** The depth switch: its group's accessible name, each side's label, and
48
- * the one-line hint beside it saying what the picked side is for. Never
49
- * which model sits behind it — that is never the colleague's concern. */
50
- depthGroupLabel: string;
51
- depthQuick: string;
52
- depthThorough: string;
53
- depthQuickHint: string;
54
- depthThoroughHint: string;
44
+ /** The composer's collection picker: its group's accessible name, and the
45
+ * choice that asks across everything the person may read. A collection is
46
+ * shown by its own summary, supplied by the app. */
47
+ collectionsLabel: string;
48
+ allCollections: string;
55
49
  /** Past a few turns, the quiet line above the composer that offers to
56
50
  * start over — a follow-up re-reads the whole conversation, so each one
57
51
  * costs more than the last. */
@@ -69,8 +63,6 @@ export interface LibrarianCopy {
69
63
  /** An artefact card's action, and the same action while it is open. */
70
64
  openArtefact: string;
71
65
  showingArtefact: string;
72
- /** Beside the clock while the question waits behind someone else's. */
73
- waiting: string;
74
66
  /** Beside the clock on an answer this page did not start. */
75
67
  stillAnswering: string;
76
68
  /** The answer mark: the two verdicts, the optional note, and after. */
@@ -127,12 +119,12 @@ export declare function personaName(name: string): string;
127
119
  * Deliberately free of pronouns: the persona is whoever the consuming app
128
120
  * says it is, and a sentence that guesses is wrong for half of them.
129
121
  */
130
- export declare function copyFor(name?: string): LibrarianCopy;
122
+ export declare function copyFor(name?: string): ChatCopy;
131
123
  /** A sentence with `{name}` places, filled. A place with no value stays as
132
124
  * written, so a host's override that drops one loses nothing else. */
133
125
  export declare function fill(template: string, values: Record<string, string | number>): string;
134
- /** The library's own words, for a host that names no persona. */
135
- export declare const DEFAULT_COPY: LibrarianCopy;
126
+ /** The package's own words, for a host that names no persona. */
127
+ export declare const DEFAULT_COPY: ChatCopy;
136
128
  /**
137
129
  * One persona's words with a host's overrides on top.
138
130
  *
@@ -141,4 +133,4 @@ export declare const DEFAULT_COPY: LibrarianCopy;
141
133
  * nothing at all — and that is exactly the shape a host produces by passing a
142
134
  * value it computed from state that has not loaded yet.
143
135
  */
144
- export declare function resolveCopy(overrides?: Partial<LibrarianCopy>, name?: string): LibrarianCopy;
136
+ export declare function resolveCopy(overrides?: Partial<ChatCopy>, name?: string): ChatCopy;
package/dist/copy.js CHANGED
@@ -3,23 +3,22 @@
3
3
  *
4
4
  * Here rather than inline in each component because these sentences are the
5
5
  * package's opinion about how an agent talks to a colleague, and an app that
6
- * needs a different register — a room whose boundary is worded by its own
6
+ * needs a different register — a persona whose boundary is worded by its own
7
7
  * subject-matter owner — must be able to change one string without forking a
8
8
  * component.
9
9
  *
10
10
  * NO STRING HERE NAMES A PERSONA. The name is an argument: a consuming app
11
11
  * says who is speaking once, and every sentence the package renders is built
12
- * from that. Milton is the library's own persona and therefore the default,
13
- * which is a different thing from being baked in — a package that hardcodes
14
- * one app's persona is a package that lies in every other app, and did:
15
- * Pebblestone's Penny introduced herself as Milton for a fortnight.
12
+ * from that. The default is a neutral name, never one app's persona: a
13
+ * package that hardcodes one app's persona is a package that lies in every
14
+ * other app.
16
15
  *
17
16
  * Every component takes `copy` as a PARTIAL and resolves it itself, so a host
18
17
  * overriding one line does not have to restate the others, and a component
19
18
  * used directly behaves the same as one reached through `Conversation`.
20
19
  */
21
- /** The library's own persona: the default wherever a consumer names none. */
22
- export const DEFAULT_PERSONA = 'Milton';
20
+ /** The name used wherever a consumer names no persona. */
21
+ export const DEFAULT_PERSONA = 'Assistant';
23
22
  /**
24
23
  * The display name for a persona a host identified by its slug.
25
24
  *
@@ -52,7 +51,7 @@ export function copyFor(name = DEFAULT_PERSONA) {
52
51
  notVerified: 'not verified',
53
52
  // Two sentences, both plain: what happened, and the likeliest reason. It
54
53
  // says nothing about collections, indexes or retrieval — a colleague
55
- // reading it has no model of any of those, and the room's own
54
+ // reading it has no model of any of those, and the persona's own
56
55
  // instruction forbids naming them either.
57
56
  notHeld: `${who} answered this one without a source. There may be no document here that covers it.`,
58
57
  // A run can end `is_error` carrying no message at all, and a turn that
@@ -61,16 +60,12 @@ export function copyFor(name = DEFAULT_PERSONA) {
61
60
  unreachable: `${who} can't be reached right now.`,
62
61
  noAnswer: 'Stopped before an answer came.',
63
62
  sources: 'Sources',
64
- suggestions: 'Ask next',
65
63
  scope: `What ${who} answers from`,
66
64
  welcome: `Ask ${who} a question.`,
67
65
  askPlaceholder: `Ask ${who}…`,
68
66
  answeringPlaceholder: `${who} is answering…`,
69
- depthGroupLabel: `How hard ${who} works`,
70
- depthQuick: 'Quick',
71
- depthThorough: 'Thorough',
72
- depthQuickHint: 'Fast, for looking something up',
73
- depthThoroughHint: 'Slower, reads more, for questions of interpretation',
67
+ collectionsLabel: `Where ${who} looks`,
68
+ allCollections: 'All your collections',
74
69
  longConversation: `This conversation is getting long. A new question keeps ${who} quick.`,
75
70
  working: [`${who} is looking`, `${who} is reading`],
76
71
  conversationLabel: `Conversation with ${who}`,
@@ -82,7 +77,6 @@ export function copyFor(name = DEFAULT_PERSONA) {
82
77
  documentUnavailable: "That document can't be opened right now.",
83
78
  openArtefact: 'Open',
84
79
  showingArtefact: 'Showing',
85
- waiting: `${who} is answering another question first`,
86
80
  stillAnswering: `${who} is still answering`,
87
81
  markHelpful: 'Helpful',
88
82
  markNotHelpful: 'Not helpful',
@@ -124,7 +118,7 @@ export function copyFor(name = DEFAULT_PERSONA) {
124
118
  export function fill(template, values) {
125
119
  return template.replace(/\{(\w+)\}/g, (place, key) => key in values ? String(values[key]) : place);
126
120
  }
127
- /** The library's own words, for a host that names no persona. */
121
+ /** The package's own words, for a host that names no persona. */
128
122
  export const DEFAULT_COPY = copyFor();
129
123
  /**
130
124
  * One persona's words with a host's overrides on top.
@@ -12,7 +12,7 @@
12
12
  * Every Claude Code event carries a `uuid`, and one already folded is
13
13
  * skipped: a watch route replays from the first event, so opening it again
14
14
  * after the session moves on folds only what is new. A frame the server adds
15
- * itself (an error, the library's citations) carries none, and is known by
15
+ * itself (an error, the citations) carries none, and is known by
16
16
  * the event it follows.
17
17
  */
18
18
  import type { AgentEvent } from './client';