@poodle64/librarian 2026.10.4 → 2026.10.6
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/README.md +8 -6
- package/dist/components/activity-group/activity-group.svelte +99 -17
- package/dist/components/activity-group/activity-group.svelte.d.ts +4 -1
- package/dist/components/agent-transcript/agent-transcript.svelte +82 -26
- package/dist/components/agent-transcript/agent-transcript.svelte.d.ts +4 -3
- package/dist/components/artefact-pane/artefact-pane.svelte +278 -78
- package/dist/components/conversation/conversation.svelte +6 -6
- package/dist/components/conversation/conversation.svelte.d.ts +4 -4
- package/dist/components/markdown/markdown.d.ts +27 -10
- package/dist/components/markdown/markdown.js +99 -22
- package/dist/components/markdown/markdown.svelte +122 -28
- package/dist/components/markdown/markdown.svelte.d.ts +12 -4
- package/dist/components/source-fold/index.d.ts +2 -0
- package/dist/components/source-fold/index.js +2 -0
- package/dist/components/source-fold/source-fold.svelte +225 -0
- package/dist/components/source-fold/source-fold.svelte.d.ts +17 -0
- package/dist/components/source-list/source-list.svelte +5 -3
- package/dist/components/source-list/source-list.svelte.d.ts +2 -0
- package/dist/components/thinking-row/thinking-row.svelte +37 -16
- package/dist/components/thinking-row/thinking-row.svelte.d.ts +2 -0
- package/dist/components/tool-row/tool-row.svelte +130 -38
- package/dist/components/visual-block/chart-draw.svelte +26 -0
- package/dist/components/visual-block/chart-draw.svelte.d.ts +7 -0
- package/dist/components/visual-block/chart.svelte +73 -0
- package/dist/components/visual-block/chart.svelte.d.ts +8 -0
- package/dist/components/visual-block/entity-card.svelte +94 -0
- package/dist/components/visual-block/entity-card.svelte.d.ts +7 -0
- package/dist/components/visual-block/timeline.svelte +99 -0
- package/dist/components/visual-block/timeline.svelte.d.ts +7 -0
- package/dist/components/visual-block/visual-block.svelte +53 -0
- package/dist/components/visual-block/visual-block.svelte.d.ts +13 -0
- package/dist/components/written-card/written-card.svelte +97 -49
- package/dist/components/written-card/written-card.svelte.d.ts +1 -1
- package/dist/copy.d.ts +54 -0
- package/dist/copy.js +44 -1
- package/dist/diff.d.ts +8 -0
- package/dist/diff.js +37 -0
- package/dist/steps.d.ts +28 -0
- package/dist/steps.js +168 -0
- package/dist/transcript.svelte.d.ts +4 -0
- package/dist/transcript.svelte.js +13 -2
- package/dist/visuals.d.ts +46 -0
- package/dist/visuals.js +84 -0
- package/dist/web-sources.d.ts +19 -3
- package/dist/web-sources.js +39 -7
- package/dist/written.d.ts +26 -1
- package/dist/written.js +42 -0
- package/package.json +8 -1
- package/dist/components/web-list/index.d.ts +0 -2
- package/dist/components/web-list/index.js +0 -2
- package/dist/components/web-list/web-list.svelte +0 -84
- package/dist/components/web-list/web-list.svelte.d.ts +0 -9
package/README.md
CHANGED
|
@@ -35,8 +35,9 @@ src/lib/
|
|
|
35
35
|
document-pane/ the cited document, open at the cited passage
|
|
36
36
|
artefact-card/ an artefact's card, in the host's words
|
|
37
37
|
artefact-pane/ an artefact that is its answer's prose, or one version of a written document, in the column
|
|
38
|
-
written-card/ a document the persona wrote: version, Open,
|
|
39
|
-
|
|
38
|
+
written-card/ a document the persona wrote: kind, pages, version, Open, and a download chip
|
|
39
|
+
source-fold/ what an answer drew on, folded: the library's numbered sources, then the web pages numbered on from them
|
|
40
|
+
visual-block/ a fenced block of a registered language: its renderer, Drawing… while it arrives, its code when invalid
|
|
40
41
|
composer/ the input box: attachments, one collection control, a note, send/stop
|
|
41
42
|
markdown/ sanitised, streaming-safe markdown + highlighting
|
|
42
43
|
activity-group/ what the persona did, one collapsed row per step
|
|
@@ -178,7 +179,7 @@ on it fires once and never again.
|
|
|
178
179
|
| Asking again | `onregenerate`: re-send the last question as a NEW turn; the package exposes the action and never re-asks by itself |
|
|
179
180
|
| Choosing a collection | `Composer`'s `collections` (`{ name, title?, description? }[]`, the ones the person may read) and `collection` (the chosen name; undefined is all of them), with `oncollection(name \| undefined)`. From two collections up it is ONE control naming the choice, opening a listbox (searchable from eight) where each shows by its title (the name made readable where there is none) over its description, never a retrieval summary |
|
|
180
181
|
| The empty state | `welcome` and up to three `examples`. With a composer, the opening and the composer sit together in the middle of the panel, the examples, the folded scope and `lead` under it; the first turn docks the composer at the foot |
|
|
181
|
-
| Conversation controls | `toolbar`: a snippet at the measure's trailing edge above the transcript, outside its scroll (the
|
|
182
|
+
| Conversation controls | `toolbar`: a snippet at the measure's trailing edge above the transcript, outside its scroll (the chat page's Past questions and New question) |
|
|
182
183
|
| What this surface covers | `scope`: one statement per persona, in the host's own words. Rendered above the first turn and folded to a line once the conversation starts |
|
|
183
184
|
| The words themselves | `copy`: a partial of `ChatCopy`. Every component resolves it itself, so overriding one line does not mean restating the rest |
|
|
184
185
|
| An answer its own way | `turn`: a snippet given each turn's `AgentTranscriptProps` in place of `AgentTranscript`. Render your own from the parts, or `AgentTranscript` inside your own to add to it |
|
|
@@ -401,9 +402,10 @@ end that way.
|
|
|
401
402
|
| An artefact | `turn.artefact = { title, summary }` cards under the prose once the turn settles; `isAnswer: true` is an artefact that IS the prose, and replaces it |
|
|
402
403
|
| Opening it | `onopenartefact(turn)` and `showing` (the turn id the host shows). Without a handler, an `isAnswer` artefact opens in `ArtefactPane` and any other offers no action |
|
|
403
404
|
| Editing a question | `Conversation`'s `onedit(position, text)` (`Chat.edit`) offers an edit control on each plain question while nothing is being answered; the turns from there on are dropped and the new question streams in at that position (`ask({ edit })`). Files are not sent again |
|
|
404
|
-
| Documents it wrote | `artefact` frames and a stored turn's `artefacts` become `turn.written
|
|
405
|
-
|
|
|
406
|
-
|
|
|
405
|
+
| Documents it wrote | `artefact` frames and a stored turn's `artefacts` (each with `title`, `kind`, `changes`, `pages`) become `turn.written`: the newest version of each is a card with Open and a download chip (Word where `formats` has it, else the source). The pane marks what a version changed since the one before: a "Changed since vN" line from `changes`, and a bar beside each changed block. `loadWritten(name, version)` and `writtenUrl(name, version, format)` (`Chat.loadArtefact` / `Chat.artefactUrl` over the transport) let the pane show a version: Markdown sanitised, HTML only in a `sandbox=""` frame |
|
|
406
|
+
| The turn's steps | One fold, "Read your attachment, searched the library and the web, and wrote a minute · 6 steps", composed from the steps (`stepsSummary`); it says what is happening now while the turn runs, and opens on one row per step (a search row counts what it found, a web search opens on the pages it found) |
|
|
407
|
+
| Web sources | Pages from the turn's supacrawl calls and the answer's Markdown links fold with the library's sources ("6 sources · 4 library · 2 web"), numbered on from the library's, and a link to one in the answer reads as that number's chip |
|
|
408
|
+
| Drawing a fence | `visuals` on `Conversation` is a registry keyed on a fence's language, `{ component, parse }` each; `defaultVisuals` (from `@poodle64/librarian/visuals`) draws `chart` (`{title, type: bar | line | area, x, y: [fields], data}` on LayerChart, in the app's `--chart-1`…`--chart-5` tokens, loaded when an answer carries one), `timeline` and `card`. An app passes `{ ...defaultVisuals, openui }`. A block whose closing fence has not arrived is "Drawing…", one that does not parse is its code |
|
|
407
409
|
| "Answered without a source" | `copy.notHeld: ''` for a persona that answers from no sources |
|
|
408
410
|
| Saying something mid-run | `Composer`'s `sendWhileRunning`: while the session works the box stays open and Send sits beside Stop. For a route that reads a message while the run works; a chat leaves it off and waits for its answer |
|
|
409
411
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
<!--
|
|
2
|
-
What the persona did before it answered,
|
|
3
|
-
order — the way Claude Code's own panel lists them.
|
|
2
|
+
What the persona did before it answered, folded behind one line.
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
The line is a sentence composed from the steps ("Read your attachment,
|
|
5
|
+
searched the library and the web, and wrote a minute · 6 steps"), and while
|
|
6
|
+
the turn runs it says what is happening now. It opens on one row per step,
|
|
7
|
+
in order, the way Claude Code's own panel lists them: each says what the step
|
|
8
|
+
did in a reader's words and opens on what went in and what came back.
|
|
8
9
|
|
|
9
10
|
The persona's between-tool commentary is a step in here as well. It reaches
|
|
10
11
|
the caller as an ordinary `text` block, not a `thinking` one, so `segment()`
|
|
@@ -12,8 +13,12 @@
|
|
|
12
13
|
as a ThinkingRow beside the tools, folded like the rest.
|
|
13
14
|
-->
|
|
14
15
|
<script lang="ts">
|
|
16
|
+
import ChevronDownIcon from '@lucide/svelte/icons/chevron-down';
|
|
17
|
+
import ChevronUpIcon from '@lucide/svelte/icons/chevron-up';
|
|
15
18
|
import type { ActivityGroup } from '../../transcript.svelte';
|
|
16
|
-
import type
|
|
19
|
+
import { resolveCopy, type ChatCopy } from '../../copy';
|
|
20
|
+
import { stepsNow, stepsSummary } from '../../steps';
|
|
21
|
+
import type { Written } from '../../written';
|
|
17
22
|
import ToolRow from '../tool-row/tool-row.svelte';
|
|
18
23
|
import ThinkingRow from '../thinking-row/thinking-row.svelte';
|
|
19
24
|
|
|
@@ -21,26 +26,103 @@
|
|
|
21
26
|
group: ActivityGroup;
|
|
22
27
|
/** True while this group is the live one. */
|
|
23
28
|
live: boolean;
|
|
29
|
+
/** The documents the turn wrote: a step that wrote one says its kind. */
|
|
30
|
+
written?: Written[];
|
|
24
31
|
copy?: Partial<ChatCopy>;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
let { group, live, copy }: Props = $props();
|
|
34
|
+
let { group, live, written = [], copy }: Props = $props();
|
|
35
|
+
let open = $state(false);
|
|
36
|
+
|
|
37
|
+
const words = $derived(resolveCopy(copy));
|
|
38
|
+
const summary = $derived(stepsSummary(group.steps, written, words));
|
|
39
|
+
const now = $derived(stepsNow(group.steps, written, words));
|
|
28
40
|
</script>
|
|
29
41
|
|
|
30
|
-
<div class="ds-lib-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
{
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
<div class="ds-lib-steps">
|
|
43
|
+
<button
|
|
44
|
+
type="button"
|
|
45
|
+
class="ds-lib-steps-head"
|
|
46
|
+
onclick={() => (open = !open)}
|
|
47
|
+
aria-expanded={open}
|
|
48
|
+
>
|
|
49
|
+
<span class="ds-lib-steps-line">
|
|
50
|
+
{#if live}
|
|
51
|
+
<span class="ds-lib-steps-now">{now}</span>
|
|
52
|
+
{:else}
|
|
53
|
+
{summary.sentence}<span class="ds-lib-steps-trail">{` · ${summary.trail}`}</span>
|
|
54
|
+
{/if}
|
|
55
|
+
</span>
|
|
56
|
+
<span class="ds-lib-steps-chevron" aria-hidden="true">
|
|
57
|
+
{#if open}<ChevronUpIcon size={15} />{:else}<ChevronDownIcon size={15} />{/if}
|
|
58
|
+
</span>
|
|
59
|
+
</button>
|
|
60
|
+
|
|
61
|
+
{#if open}
|
|
62
|
+
<div class="ds-lib-steps-rows">
|
|
63
|
+
{#each group.steps as step, i (step.block.index)}
|
|
64
|
+
{#if step.block.kind === 'tool'}
|
|
65
|
+
<ToolRow block={step.block} words={step.words} running={live} {copy} />
|
|
66
|
+
{:else}
|
|
67
|
+
<ThinkingRow block={step.block} active={live && i === group.steps.length - 1} {copy} />
|
|
68
|
+
{/if}
|
|
69
|
+
{/each}
|
|
70
|
+
</div>
|
|
71
|
+
{/if}
|
|
38
72
|
</div>
|
|
39
73
|
|
|
40
74
|
<style>
|
|
41
|
-
.ds-lib-
|
|
75
|
+
.ds-lib-steps-head {
|
|
76
|
+
display: flex;
|
|
77
|
+
width: 100%;
|
|
78
|
+
align-items: flex-start;
|
|
79
|
+
gap: 0.5rem;
|
|
80
|
+
border: 0;
|
|
81
|
+
background: none;
|
|
82
|
+
padding: 0.25rem 0;
|
|
83
|
+
color: var(--ds-color-muted-foreground);
|
|
84
|
+
font: inherit;
|
|
85
|
+
font-size: 0.875rem;
|
|
86
|
+
line-height: 1.375rem;
|
|
87
|
+
text-align: start;
|
|
88
|
+
cursor: pointer;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.ds-lib-steps-head:hover {
|
|
92
|
+
color: var(--ds-color-foreground);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.ds-lib-steps-head:focus-visible {
|
|
96
|
+
outline: 2px solid var(--ds-color-ring);
|
|
97
|
+
outline-offset: 2px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.ds-lib-steps-line {
|
|
101
|
+
flex: 1;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.ds-lib-steps-now {
|
|
105
|
+
color: var(--ds-color-foreground);
|
|
106
|
+
font-weight: 500;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.ds-lib-steps-trail {
|
|
110
|
+
font-size: var(--ds-text-2xs);
|
|
111
|
+
opacity: 0.8;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.ds-lib-steps-chevron {
|
|
115
|
+
display: flex;
|
|
116
|
+
flex: none;
|
|
117
|
+
padding-top: 0.25rem;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.ds-lib-steps-rows {
|
|
42
121
|
display: flex;
|
|
43
122
|
flex-direction: column;
|
|
44
|
-
gap: 0.
|
|
123
|
+
gap: 0.125rem;
|
|
124
|
+
margin-top: 0.25rem;
|
|
125
|
+
border-inline-start: 1px solid var(--ds-color-border);
|
|
126
|
+
padding-inline-start: 0.75rem;
|
|
45
127
|
}
|
|
46
128
|
</style>
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { ActivityGroup } from '../../transcript.svelte';
|
|
2
|
-
import type
|
|
2
|
+
import { type ChatCopy } from '../../copy';
|
|
3
|
+
import type { Written } from '../../written';
|
|
3
4
|
interface Props {
|
|
4
5
|
group: ActivityGroup;
|
|
5
6
|
/** True while this group is the live one. */
|
|
6
7
|
live: boolean;
|
|
8
|
+
/** The documents the turn wrote: a step that wrote one says its kind. */
|
|
9
|
+
written?: Written[];
|
|
7
10
|
copy?: Partial<ChatCopy>;
|
|
8
11
|
}
|
|
9
12
|
declare const ActivityGroup: import("svelte").Component<Props, {}, "">;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import CheckIcon from '@lucide/svelte/icons/check';
|
|
17
17
|
import CopyIcon from '@lucide/svelte/icons/copy';
|
|
18
18
|
import PencilIcon from '@lucide/svelte/icons/pencil';
|
|
19
|
-
import
|
|
19
|
+
import FileTextIcon from '@lucide/svelte/icons/file-text';
|
|
20
20
|
import RefreshCwIcon from '@lucide/svelte/icons/refresh-cw';
|
|
21
21
|
import {
|
|
22
22
|
outcomeLine,
|
|
@@ -35,9 +35,10 @@
|
|
|
35
35
|
splitSources,
|
|
36
36
|
type Citation
|
|
37
37
|
} from '../../citations';
|
|
38
|
-
import { DEFAULT_PERSONA, personaName, resolveCopy, type ChatCopy } from '../../copy';
|
|
39
|
-
import { webSources } from '../../web-sources';
|
|
40
|
-
import { writtenKey, type Written, type WrittenUrl } from '../../written';
|
|
38
|
+
import { DEFAULT_PERSONA, fill, personaName, resolveCopy, type ChatCopy } from '../../copy';
|
|
39
|
+
import { webKey, webSources } from '../../web-sources';
|
|
40
|
+
import { newestPerName, writtenKey, type Written, type WrittenUrl } from '../../written';
|
|
41
|
+
import type { Visual } from '../../visuals';
|
|
41
42
|
import type { Verdict } from '../../chat.svelte';
|
|
42
43
|
import AnswerMark from '../answer-mark/answer-mark.svelte';
|
|
43
44
|
import AnswerShare from '../answer-share/answer-share.svelte';
|
|
@@ -45,9 +46,7 @@
|
|
|
45
46
|
import ActivityGroup from '../activity-group/activity-group.svelte';
|
|
46
47
|
import ArtefactCard from '../artefact-card/artefact-card.svelte';
|
|
47
48
|
import Markdown from '../markdown/markdown.svelte';
|
|
48
|
-
import
|
|
49
|
-
import SourceList from '../source-list/source-list.svelte';
|
|
50
|
-
import WebList from '../web-list/web-list.svelte';
|
|
49
|
+
import SourceFold from '../source-fold/source-fold.svelte';
|
|
51
50
|
import WrittenCard from '../written-card/written-card.svelte';
|
|
52
51
|
|
|
53
52
|
/** Everything one turn renders from: what `Conversation` hands a host's
|
|
@@ -97,8 +96,9 @@
|
|
|
97
96
|
onopenwritten?: (written: Written) => void;
|
|
98
97
|
/** Where a version downloads. Omit and no download links render. */
|
|
99
98
|
writtenUrl?: WrittenUrl;
|
|
100
|
-
/**
|
|
101
|
-
|
|
99
|
+
/** Renderers by a fence's language: a block of one is drawn by its
|
|
100
|
+
* component in the answer. Absent, every fence is code. */
|
|
101
|
+
visuals?: Record<string, Visual>;
|
|
102
102
|
/** When an answer this page did not start began, epoch ms: it is still
|
|
103
103
|
* being written, and the clock counts from then. */
|
|
104
104
|
answering?: number;
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
showingWritten,
|
|
141
141
|
onopenwritten,
|
|
142
142
|
writtenUrl,
|
|
143
|
-
|
|
143
|
+
visuals,
|
|
144
144
|
answering,
|
|
145
145
|
onmark,
|
|
146
146
|
shared,
|
|
@@ -214,8 +214,31 @@
|
|
|
214
214
|
const hasAnswer = $derived(texts.length > 0);
|
|
215
215
|
|
|
216
216
|
// Pages the answer drew on, once it has settled: a link still being typed
|
|
217
|
-
// is not a source.
|
|
218
|
-
|
|
217
|
+
// is not a source. They are numbered on from the library's, and a link to
|
|
218
|
+
// one reads as the same chip.
|
|
219
|
+
const web = $derived.by(() => {
|
|
220
|
+
if (running) return [];
|
|
221
|
+
const from = Math.max(0, ...sources.map((c) => c.n));
|
|
222
|
+
return webSources(blocks, answer).map((page, i) => ({ ...page, n: from + i + 1 }));
|
|
223
|
+
});
|
|
224
|
+
const webNumbers = $derived(new Map(web.map((page) => [webKey(page.url), page.n])));
|
|
225
|
+
|
|
226
|
+
// Which day the pages were read: today only for a turn asked today.
|
|
227
|
+
const readWhen = $derived.by(() => {
|
|
228
|
+
if (at === undefined) return '';
|
|
229
|
+
const when = new Date(at);
|
|
230
|
+
if (new Date().toDateString() === when.toDateString()) return words.readToday;
|
|
231
|
+
return fill(words.readOn, {
|
|
232
|
+
date: when.toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric' })
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
const cards = $derived(newestPerName(written));
|
|
237
|
+
|
|
238
|
+
const fileType = (file: string): string => {
|
|
239
|
+
const ext = /\.([A-Za-z0-9]{1,5})$/.exec(file)?.[1];
|
|
240
|
+
return ext ? ext.toUpperCase() : '';
|
|
241
|
+
};
|
|
219
242
|
|
|
220
243
|
let editing = $state(false);
|
|
221
244
|
let edited = $state('');
|
|
@@ -329,14 +352,20 @@
|
|
|
329
352
|
</form>
|
|
330
353
|
{:else if asked}
|
|
331
354
|
<div class="ds-lib-ask">
|
|
332
|
-
<div class="ds-lib-bubble">{asked}</div>
|
|
333
355
|
{#if files.length > 0}
|
|
334
356
|
<ul class="ds-lib-ask-files">
|
|
335
357
|
{#each files as file, i (i)}
|
|
336
|
-
<li class="ds-lib-ask-file"
|
|
358
|
+
<li class="ds-lib-ask-file">
|
|
359
|
+
<span class="ds-lib-ask-file-icon" aria-hidden="true"><FileTextIcon size={16} /></span>
|
|
360
|
+
<span class="ds-lib-ask-file-text">
|
|
361
|
+
<span class="ds-lib-ask-file-name">{file}</span>
|
|
362
|
+
{#if fileType(file)}<span class="ds-lib-ask-file-type">{fileType(file)}</span>{/if}
|
|
363
|
+
</span>
|
|
364
|
+
</li>
|
|
337
365
|
{/each}
|
|
338
366
|
</ul>
|
|
339
367
|
{/if}
|
|
368
|
+
<div class="ds-lib-bubble">{asked}</div>
|
|
340
369
|
<div class="ds-lib-ask-meta">
|
|
341
370
|
{#if onedit && !running}
|
|
342
371
|
<button type="button" class="ds-lib-action" onclick={startEdit}>
|
|
@@ -370,7 +399,12 @@
|
|
|
370
399
|
|
|
371
400
|
{#each segments as seg (seg.index)}
|
|
372
401
|
{#if seg.kind === 'activity'}
|
|
373
|
-
<ActivityGroup
|
|
402
|
+
<ActivityGroup
|
|
403
|
+
group={seg}
|
|
404
|
+
live={running && seg.index === lastIndex}
|
|
405
|
+
{written}
|
|
406
|
+
copy={words}
|
|
407
|
+
/>
|
|
374
408
|
{:else if !isArtefact}
|
|
375
409
|
<Markdown
|
|
376
410
|
content={seg.index === lastTextIndex && split.citations.length > 0
|
|
@@ -378,8 +412,10 @@
|
|
|
378
412
|
: seg.text}
|
|
379
413
|
streaming={running && seg.index === lastIndex}
|
|
380
414
|
{collectionNames}
|
|
381
|
-
{
|
|
415
|
+
{visuals}
|
|
416
|
+
copy={words}
|
|
382
417
|
citationNumbers={numbers}
|
|
418
|
+
{webNumbers}
|
|
383
419
|
oncite={(n) => {
|
|
384
420
|
const found = sources.find((c) => c.n === n);
|
|
385
421
|
if (found) oncite?.(found);
|
|
@@ -392,7 +428,7 @@
|
|
|
392
428
|
<ArtefactCard {artefact} open={artefactOpen} onopen={onopenartefact} copy={words} />
|
|
393
429
|
{/if}
|
|
394
430
|
|
|
395
|
-
{#each
|
|
431
|
+
{#each cards as doc (writtenKey(doc))}
|
|
396
432
|
<WrittenCard
|
|
397
433
|
written={doc}
|
|
398
434
|
open={showingWritten === writtenKey(doc)}
|
|
@@ -402,12 +438,8 @@
|
|
|
402
438
|
/>
|
|
403
439
|
{/each}
|
|
404
440
|
|
|
405
|
-
{#if !isArtefact && sources.length > 0}
|
|
406
|
-
<
|
|
407
|
-
{/if}
|
|
408
|
-
|
|
409
|
-
{#if !isArtefact && web.length > 0}
|
|
410
|
-
<WebList sources={web} {words} />
|
|
441
|
+
{#if !isArtefact && (sources.length > 0 || web.length > 0)}
|
|
442
|
+
<SourceFold library={sources} {web} {words} {oncite} {readWhen} />
|
|
411
443
|
{/if}
|
|
412
444
|
|
|
413
445
|
<!-- An empty `notHeld` is a host whose persona answers from no sources,
|
|
@@ -519,13 +551,37 @@
|
|
|
519
551
|
|
|
520
552
|
.ds-lib-ask-file {
|
|
521
553
|
display: flex;
|
|
554
|
+
max-width: 100%;
|
|
522
555
|
align-items: center;
|
|
523
|
-
gap: 0.
|
|
556
|
+
gap: 0.625rem;
|
|
524
557
|
border: 1px solid var(--ds-color-border);
|
|
525
|
-
border-radius: var(--ds-radius-
|
|
526
|
-
padding: 0.
|
|
558
|
+
border-radius: var(--ds-radius-full);
|
|
559
|
+
padding: 0.375rem 0.875rem 0.375rem 0.5rem;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.ds-lib-ask-file-icon {
|
|
563
|
+
display: flex;
|
|
564
|
+
flex: none;
|
|
527
565
|
color: var(--ds-color-muted-foreground);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
.ds-lib-ask-file-text {
|
|
569
|
+
display: flex;
|
|
570
|
+
min-width: 0;
|
|
571
|
+
flex-direction: column;
|
|
528
572
|
font-size: var(--ds-text-2xs);
|
|
573
|
+
line-height: 1.25;
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
.ds-lib-ask-file-name {
|
|
577
|
+
color: var(--ds-color-foreground);
|
|
578
|
+
font-size: 0.8125rem;
|
|
579
|
+
font-weight: 600;
|
|
580
|
+
overflow-wrap: anywhere;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
.ds-lib-ask-file-type {
|
|
584
|
+
color: var(--ds-color-muted-foreground);
|
|
529
585
|
}
|
|
530
586
|
|
|
531
587
|
.ds-lib-edit {
|
|
@@ -2,8 +2,8 @@ import { type Artefact, type Block, type DescribeTool, type Outcome } from '../.
|
|
|
2
2
|
import { type Citation } from '../../citations';
|
|
3
3
|
import { type ChatCopy } from '../../copy';
|
|
4
4
|
import { type Written, type WrittenUrl } from '../../written';
|
|
5
|
+
import type { Visual } from '../../visuals';
|
|
5
6
|
import type { Verdict } from '../../chat.svelte';
|
|
6
|
-
import type { Fences } from '../markdown/markdown';
|
|
7
7
|
/** Everything one turn renders from: what `Conversation` hands a host's
|
|
8
8
|
* own `turn` snippet, so it can render this component or its own. */
|
|
9
9
|
export interface AgentTranscriptProps {
|
|
@@ -51,8 +51,9 @@ export interface AgentTranscriptProps {
|
|
|
51
51
|
onopenwritten?: (written: Written) => void;
|
|
52
52
|
/** Where a version downloads. Omit and no download links render. */
|
|
53
53
|
writtenUrl?: WrittenUrl;
|
|
54
|
-
/**
|
|
55
|
-
|
|
54
|
+
/** Renderers by a fence's language: a block of one is drawn by its
|
|
55
|
+
* component in the answer. Absent, every fence is code. */
|
|
56
|
+
visuals?: Record<string, Visual>;
|
|
56
57
|
/** When an answer this page did not start began, epoch ms: it is still
|
|
57
58
|
* being written, and the clock counts from then. */
|
|
58
59
|
answering?: number;
|