@poodle64/librarian 2026.10.3 → 2026.10.4
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 +10 -4
- package/dist/chat.svelte.d.ts +40 -0
- package/dist/chat.svelte.js +57 -3
- package/dist/client.d.ts +3 -0
- package/dist/client.js +4 -1
- package/dist/components/activity-group/activity-group.svelte +21 -108
- package/dist/components/activity-group/activity-group.svelte.d.ts +3 -1
- package/dist/components/agent-transcript/agent-transcript.svelte +164 -4
- package/dist/components/agent-transcript/agent-transcript.svelte.d.ts +18 -0
- package/dist/components/artefact-pane/artefact-pane.svelte +162 -18
- package/dist/components/artefact-pane/artefact-pane.svelte.d.ts +10 -1
- package/dist/components/conversation/conversation.svelte +74 -4
- package/dist/components/conversation/conversation.svelte.d.ts +15 -0
- package/dist/components/markdown/markdown.d.ts +11 -0
- package/dist/components/markdown/markdown.js +62 -2
- package/dist/components/markdown/markdown.svelte +22 -2
- package/dist/components/markdown/markdown.svelte.d.ts +4 -0
- package/dist/components/thinking-row/thinking-row.svelte +1 -0
- package/dist/components/thinking-row/thinking-row.svelte.d.ts +1 -0
- package/dist/components/tool-row/tool-row.svelte +40 -20
- package/dist/components/tool-row/tool-row.svelte.d.ts +2 -3
- package/dist/components/web-list/index.d.ts +2 -0
- package/dist/components/web-list/index.js +2 -0
- package/dist/components/web-list/web-list.svelte +84 -0
- package/dist/components/web-list/web-list.svelte.d.ts +9 -0
- package/dist/components/written-card/index.d.ts +2 -0
- package/dist/components/written-card/index.js +2 -0
- package/dist/components/written-card/written-card.svelte +130 -0
- package/dist/components/written-card/written-card.svelte.d.ts +15 -0
- package/dist/copy.d.ts +19 -0
- package/dist/copy.js +13 -0
- package/dist/transcript.svelte.d.ts +15 -34
- package/dist/transcript.svelte.js +52 -55
- package/dist/web-sources.d.ts +18 -0
- package/dist/web-sources.js +58 -0
- package/dist/written.d.ts +46 -0
- package/dist/written.js +41 -0
- package/package.json +5 -1
|
@@ -7,34 +7,40 @@
|
|
|
7
7
|
|
|
8
8
|
The row says what the persona DID, in a reader's own words — never the
|
|
9
9
|
tool's name or the raw command it ran: the host's `DescribeTool`, or the
|
|
10
|
-
package's own `describe()`. Expanding
|
|
11
|
-
|
|
10
|
+
package's own `describe()`. Expanding it shows what went in and what came
|
|
11
|
+
back, the way Claude Code's own panel does.
|
|
12
12
|
-->
|
|
13
13
|
<script lang="ts">
|
|
14
14
|
import ChevronRightIcon from '@lucide/svelte/icons/chevron-right';
|
|
15
15
|
import { describe, type ToolBlock, type ToolWords } from '../../transcript.svelte';
|
|
16
|
+
import { resolveCopy, type ChatCopy } from '../../copy';
|
|
16
17
|
|
|
17
18
|
interface Props {
|
|
18
19
|
block: ToolBlock;
|
|
19
20
|
running: boolean;
|
|
20
|
-
/** Identical consecutive steps folded into this row — five pages of one
|
|
21
|
-
* document is one act of reading to a human. */
|
|
22
|
-
repeats?: number;
|
|
23
21
|
/** The call in the persona's words. Absent takes the package's own. */
|
|
24
22
|
words?: ToolWords;
|
|
23
|
+
copy?: Partial<ChatCopy>;
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
let { block, running,
|
|
26
|
+
let { block, running, words, copy }: Props = $props();
|
|
28
27
|
let open = $state(false);
|
|
29
28
|
|
|
29
|
+
const label = $derived(resolveCopy(copy));
|
|
30
30
|
const settled = $derived(block.result !== undefined);
|
|
31
31
|
const said = $derived(words ?? describe(block));
|
|
32
32
|
const tone = $derived(block.isError ? 'error' : settled ? 'success' : 'info');
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
:
|
|
37
|
-
|
|
33
|
+
// Pretty while it parses; the raw text while it is still arriving.
|
|
34
|
+
const input = $derived.by(() => {
|
|
35
|
+
try {
|
|
36
|
+
const parsed: unknown = JSON.parse(block.rawInput);
|
|
37
|
+
return typeof parsed === 'object' && parsed !== null && Object.keys(parsed).length === 0
|
|
38
|
+
? ''
|
|
39
|
+
: JSON.stringify(parsed, null, 2);
|
|
40
|
+
} catch {
|
|
41
|
+
return block.rawInput;
|
|
42
|
+
}
|
|
43
|
+
});
|
|
38
44
|
</script>
|
|
39
45
|
|
|
40
46
|
<div class="ds-lib-tool">
|
|
@@ -42,23 +48,27 @@
|
|
|
42
48
|
type="button"
|
|
43
49
|
class="ds-lib-tool-row"
|
|
44
50
|
onclick={() => (open = !open)}
|
|
45
|
-
disabled={!settled}
|
|
46
51
|
aria-expanded={open}
|
|
47
52
|
>
|
|
48
53
|
<span class="ds-lib-tool-chevron" class:is-open={open}>
|
|
49
|
-
|
|
54
|
+
<ChevronRightIcon size={12} />
|
|
50
55
|
</span>
|
|
51
56
|
<span class="ds-lib-tool-dot" data-tone={tone} class:is-live={!settled && running}></span>
|
|
52
57
|
<span class="ds-lib-tool-said">
|
|
53
58
|
<span class="ds-lib-tool-verb">{said.verb}</span>
|
|
54
59
|
{#if said.object}<span class="ds-lib-tool-object">{said.object}</span>{/if}
|
|
55
|
-
{#if repeats > 1}<span>{again}</span>{/if}
|
|
56
60
|
</span>
|
|
61
|
+
{#if block.isError}<span class="ds-lib-tool-failed">{label.stepFailed}</span>{/if}
|
|
57
62
|
</button>
|
|
58
63
|
|
|
59
64
|
{#if open}
|
|
60
65
|
<div class="ds-lib-tool-body">
|
|
66
|
+
{#if input}
|
|
67
|
+
<p class="ds-lib-tool-label">{label.stepInput}</p>
|
|
68
|
+
<pre class="ds-lib-tool-result">{input}</pre>
|
|
69
|
+
{/if}
|
|
61
70
|
{#if block.result}
|
|
71
|
+
<p class="ds-lib-tool-label">{label.stepResult}</p>
|
|
62
72
|
<pre class="ds-lib-tool-result">{block.result}</pre>
|
|
63
73
|
{/if}
|
|
64
74
|
</div>
|
|
@@ -87,10 +97,6 @@
|
|
|
87
97
|
cursor: pointer;
|
|
88
98
|
}
|
|
89
99
|
|
|
90
|
-
.ds-lib-tool-row:disabled {
|
|
91
|
-
cursor: default;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
100
|
.ds-lib-tool-chevron {
|
|
95
101
|
display: flex;
|
|
96
102
|
width: 0.75rem;
|
|
@@ -150,8 +156,8 @@
|
|
|
150
156
|
}
|
|
151
157
|
|
|
152
158
|
.ds-lib-tool-result {
|
|
153
|
-
margin
|
|
154
|
-
max-height:
|
|
159
|
+
margin: 0.125rem 0 0;
|
|
160
|
+
max-height: 12rem;
|
|
155
161
|
overflow: auto;
|
|
156
162
|
color: var(--ds-color-muted-foreground);
|
|
157
163
|
font-family: var(--ds-font-code);
|
|
@@ -159,6 +165,20 @@
|
|
|
159
165
|
white-space: pre-wrap;
|
|
160
166
|
}
|
|
161
167
|
|
|
168
|
+
.ds-lib-tool-label {
|
|
169
|
+
margin: 0.25rem 0 0;
|
|
170
|
+
color: var(--ds-color-muted-foreground);
|
|
171
|
+
font-size: var(--ds-text-2xs);
|
|
172
|
+
letter-spacing: 0.05em;
|
|
173
|
+
text-transform: uppercase;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.ds-lib-tool-failed {
|
|
177
|
+
flex: none;
|
|
178
|
+
color: var(--ds-color-status-error);
|
|
179
|
+
font-size: var(--ds-text-2xs);
|
|
180
|
+
}
|
|
181
|
+
|
|
162
182
|
.ds-lib-tool-lines {
|
|
163
183
|
margin: 0;
|
|
164
184
|
padding-inline-start: 1.375rem;
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { type ToolBlock, type ToolWords } from '../../transcript.svelte';
|
|
2
|
+
import { type ChatCopy } from '../../copy';
|
|
2
3
|
interface Props {
|
|
3
4
|
block: ToolBlock;
|
|
4
5
|
running: boolean;
|
|
5
|
-
/** Identical consecutive steps folded into this row — five pages of one
|
|
6
|
-
* document is one act of reading to a human. */
|
|
7
|
-
repeats?: number;
|
|
8
6
|
/** The call in the persona's words. Absent takes the package's own. */
|
|
9
7
|
words?: ToolWords;
|
|
8
|
+
copy?: Partial<ChatCopy>;
|
|
10
9
|
}
|
|
11
10
|
declare const ToolRow: import("svelte").Component<Props, {}, "">;
|
|
12
11
|
type ToolRow = ReturnType<typeof ToolRow>;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The web pages an answer drew on, apart from the library's numbered sources.
|
|
3
|
+
Never numbered; each opens in a new tab.
|
|
4
|
+
-->
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import type { ChatCopy } from '../../copy';
|
|
7
|
+
import type { WebSource } from '../../web-sources';
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
sources: WebSource[];
|
|
11
|
+
words: ChatCopy;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { sources, words }: Props = $props();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<section class="ds-lib-web">
|
|
18
|
+
<h2 class="ds-lib-web-heading">{words.fromTheWeb}</h2>
|
|
19
|
+
<ul class="ds-lib-web-list">
|
|
20
|
+
{#each sources as source (source.url)}
|
|
21
|
+
<li>
|
|
22
|
+
<a class="ds-lib-web-link" href={source.url} target="_blank" rel="noopener noreferrer">
|
|
23
|
+
<span class="ds-lib-web-title">{source.title}</span>
|
|
24
|
+
<span class="ds-lib-web-host">{source.host}</span>
|
|
25
|
+
</a>
|
|
26
|
+
</li>
|
|
27
|
+
{/each}
|
|
28
|
+
</ul>
|
|
29
|
+
</section>
|
|
30
|
+
|
|
31
|
+
<style>
|
|
32
|
+
.ds-lib-web-heading {
|
|
33
|
+
margin: 0 0 0.375rem;
|
|
34
|
+
color: var(--ds-color-muted-foreground);
|
|
35
|
+
font-family: inherit;
|
|
36
|
+
font-size: var(--ds-text-2xs);
|
|
37
|
+
font-weight: 500;
|
|
38
|
+
letter-spacing: 0.05em;
|
|
39
|
+
text-transform: uppercase;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.ds-lib-web-list {
|
|
43
|
+
display: flex;
|
|
44
|
+
flex-direction: column;
|
|
45
|
+
gap: 0.125rem;
|
|
46
|
+
margin: 0;
|
|
47
|
+
border-top: 1px solid var(--ds-color-border);
|
|
48
|
+
padding: 0.375rem 0 0;
|
|
49
|
+
list-style: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.ds-lib-web-link {
|
|
53
|
+
display: flex;
|
|
54
|
+
align-items: baseline;
|
|
55
|
+
gap: 0.5rem;
|
|
56
|
+
border-radius: var(--ds-radius-md);
|
|
57
|
+
padding: 0.375rem 0.625rem;
|
|
58
|
+
color: inherit;
|
|
59
|
+
font-size: 0.875rem;
|
|
60
|
+
text-decoration: none;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-lib-web-link:hover {
|
|
64
|
+
background: var(--ds-color-surface-2);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.ds-lib-web-link:focus-visible {
|
|
68
|
+
outline: 2px solid var(--ds-color-ring);
|
|
69
|
+
outline-offset: 2px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.ds-lib-web-title {
|
|
73
|
+
min-width: 0;
|
|
74
|
+
color: var(--ds-color-foreground);
|
|
75
|
+
font-weight: 500;
|
|
76
|
+
overflow-wrap: anywhere;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.ds-lib-web-host {
|
|
80
|
+
flex: none;
|
|
81
|
+
color: var(--ds-color-muted-foreground);
|
|
82
|
+
font-size: var(--ds-text-2xs);
|
|
83
|
+
}
|
|
84
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ChatCopy } from '../../copy';
|
|
2
|
+
import type { WebSource } from '../../web-sources';
|
|
3
|
+
interface Props {
|
|
4
|
+
sources: WebSource[];
|
|
5
|
+
words: ChatCopy;
|
|
6
|
+
}
|
|
7
|
+
declare const WebList: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type WebList = ReturnType<typeof WebList>;
|
|
9
|
+
export default WebList;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
A document the persona wrote, as a card in the turn: its name and version,
|
|
3
|
+
Open (the reading column shows that version) and a download link for the
|
|
4
|
+
source and for each format the app renders it as.
|
|
5
|
+
-->
|
|
6
|
+
<script lang="ts">
|
|
7
|
+
import FileTextIcon from '@lucide/svelte/icons/file-text';
|
|
8
|
+
import { fill, resolveCopy, type ChatCopy } from '../../copy';
|
|
9
|
+
import { downloads, type Written, type WrittenUrl } from '../../written';
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
written: Written;
|
|
13
|
+
/** The column is showing this version now. */
|
|
14
|
+
open?: boolean;
|
|
15
|
+
/** Omit and the card lists and links but does not open. */
|
|
16
|
+
onopen?: () => void;
|
|
17
|
+
/** Omit and no download links render. */
|
|
18
|
+
url?: WrittenUrl;
|
|
19
|
+
copy?: Partial<ChatCopy>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let { written, open = false, onopen, url, copy }: Props = $props();
|
|
23
|
+
|
|
24
|
+
const words = $derived(resolveCopy(copy));
|
|
25
|
+
</script>
|
|
26
|
+
|
|
27
|
+
<div class="ds-lib-written" class:is-open={open}>
|
|
28
|
+
<span class="ds-lib-written-icon" aria-hidden="true"><FileTextIcon size={16} /></span>
|
|
29
|
+
<span class="ds-lib-written-text">
|
|
30
|
+
<span class="ds-lib-written-name">{written.name}</span>
|
|
31
|
+
<span class="ds-lib-written-version">{fill(words.writtenVersion, { n: written.version })}</span>
|
|
32
|
+
</span>
|
|
33
|
+
{#if onopen}
|
|
34
|
+
<button type="button" class="ds-lib-written-open" onclick={onopen}>
|
|
35
|
+
{open ? words.showingArtefact : words.openArtefact}
|
|
36
|
+
</button>
|
|
37
|
+
{/if}
|
|
38
|
+
{#if url}
|
|
39
|
+
<ul class="ds-lib-written-links" aria-label={words.download}>
|
|
40
|
+
{#each downloads(written, words) as link (link.format)}
|
|
41
|
+
<li><a href={url(written.name, written.version, link.format)}>{link.label}</a></li>
|
|
42
|
+
{/each}
|
|
43
|
+
</ul>
|
|
44
|
+
{/if}
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.ds-lib-written {
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-wrap: wrap;
|
|
51
|
+
align-items: center;
|
|
52
|
+
gap: 0.5rem 0.75rem;
|
|
53
|
+
border: 1px solid var(--ds-color-border);
|
|
54
|
+
border-radius: var(--ds-radius-lg);
|
|
55
|
+
background: var(--ds-color-surface-1);
|
|
56
|
+
padding: 0.625rem 0.75rem;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.ds-lib-written.is-open {
|
|
60
|
+
border-color: var(--ds-color-primary);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.ds-lib-written-icon {
|
|
64
|
+
display: flex;
|
|
65
|
+
width: 2rem;
|
|
66
|
+
height: 2rem;
|
|
67
|
+
flex: none;
|
|
68
|
+
align-items: center;
|
|
69
|
+
justify-content: center;
|
|
70
|
+
border: 1px solid var(--ds-color-border);
|
|
71
|
+
border-radius: var(--ds-radius-md);
|
|
72
|
+
color: var(--ds-color-muted-foreground);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.ds-lib-written-text {
|
|
76
|
+
display: flex;
|
|
77
|
+
min-width: 0;
|
|
78
|
+
flex: 1;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.ds-lib-written-name {
|
|
83
|
+
font-size: 0.875rem;
|
|
84
|
+
font-weight: 500;
|
|
85
|
+
line-height: 1.25rem;
|
|
86
|
+
overflow-wrap: anywhere;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.ds-lib-written-version {
|
|
90
|
+
color: var(--ds-color-muted-foreground);
|
|
91
|
+
font-size: var(--ds-text-2xs);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.ds-lib-written-open {
|
|
95
|
+
border: 1px solid var(--ds-color-border);
|
|
96
|
+
border-radius: var(--ds-radius-md);
|
|
97
|
+
background: none;
|
|
98
|
+
padding: 0.25rem 0.625rem;
|
|
99
|
+
color: inherit;
|
|
100
|
+
font: inherit;
|
|
101
|
+
font-size: 0.8125rem;
|
|
102
|
+
cursor: pointer;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.ds-lib-written-open:focus-visible,
|
|
106
|
+
.ds-lib-written-links a:focus-visible {
|
|
107
|
+
outline: 2px solid var(--ds-color-ring);
|
|
108
|
+
outline-offset: 2px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.ds-lib-written-links {
|
|
112
|
+
display: flex;
|
|
113
|
+
flex-basis: 100%;
|
|
114
|
+
flex-wrap: wrap;
|
|
115
|
+
gap: 0.75rem;
|
|
116
|
+
margin: 0;
|
|
117
|
+
padding: 0;
|
|
118
|
+
font-size: var(--ds-text-2xs);
|
|
119
|
+
list-style: none;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.ds-lib-written-links a {
|
|
123
|
+
color: var(--ds-color-muted-foreground);
|
|
124
|
+
text-decoration: underline;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.ds-lib-written-links a:hover {
|
|
128
|
+
color: var(--ds-color-foreground);
|
|
129
|
+
}
|
|
130
|
+
</style>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ChatCopy } from '../../copy';
|
|
2
|
+
import { type Written, type WrittenUrl } from '../../written';
|
|
3
|
+
interface Props {
|
|
4
|
+
written: Written;
|
|
5
|
+
/** The column is showing this version now. */
|
|
6
|
+
open?: boolean;
|
|
7
|
+
/** Omit and the card lists and links but does not open. */
|
|
8
|
+
onopen?: () => void;
|
|
9
|
+
/** Omit and no download links render. */
|
|
10
|
+
url?: WrittenUrl;
|
|
11
|
+
copy?: Partial<ChatCopy>;
|
|
12
|
+
}
|
|
13
|
+
declare const WrittenCard: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type WrittenCard = ReturnType<typeof WrittenCard>;
|
|
15
|
+
export default WrittenCard;
|
package/dist/copy.d.ts
CHANGED
|
@@ -69,6 +69,25 @@ export interface ChatCopy {
|
|
|
69
69
|
showingArtefact: string;
|
|
70
70
|
/** Beside the clock on an answer this page did not start. */
|
|
71
71
|
stillAnswering: string;
|
|
72
|
+
/** An expanded tool step: what went in, what came back, and a call that failed. */
|
|
73
|
+
stepInput: string;
|
|
74
|
+
stepResult: string;
|
|
75
|
+
stepFailed: string;
|
|
76
|
+
/** Editing a question already asked: the control, the send, and what the
|
|
77
|
+
* edit does not carry. */
|
|
78
|
+
editQuestion: string;
|
|
79
|
+
editSend: string;
|
|
80
|
+
editFilesNote: string;
|
|
81
|
+
/** Web pages an answer drew on, listed apart from its numbered sources. */
|
|
82
|
+
fromTheWeb: string;
|
|
83
|
+
/** A document the persona wrote: its version (`{n}`), the version switcher's
|
|
84
|
+
* name, and what each download is called. */
|
|
85
|
+
writtenVersion: string;
|
|
86
|
+
writtenVersions: string;
|
|
87
|
+
formatMarkdown: string;
|
|
88
|
+
formatHtml: string;
|
|
89
|
+
formatWord: string;
|
|
90
|
+
formatPdf: string;
|
|
72
91
|
/** The answer mark: the two verdicts, the optional note, and after. */
|
|
73
92
|
markHelpful: string;
|
|
74
93
|
markNotHelpful: string;
|
package/dist/copy.js
CHANGED
|
@@ -80,6 +80,19 @@ export function copyFor(name = DEFAULT_PERSONA) {
|
|
|
80
80
|
openArtefact: 'Open',
|
|
81
81
|
showingArtefact: 'Showing',
|
|
82
82
|
stillAnswering: `${who} is still answering`,
|
|
83
|
+
stepInput: 'Input',
|
|
84
|
+
stepResult: 'Result',
|
|
85
|
+
stepFailed: 'Failed',
|
|
86
|
+
editQuestion: 'Edit',
|
|
87
|
+
editSend: 'Send',
|
|
88
|
+
editFilesNote: 'Files attached to the original question are not sent again.',
|
|
89
|
+
fromTheWeb: 'From the web',
|
|
90
|
+
writtenVersion: 'Version {n}',
|
|
91
|
+
writtenVersions: 'Version',
|
|
92
|
+
formatMarkdown: 'Markdown',
|
|
93
|
+
formatHtml: 'HTML',
|
|
94
|
+
formatWord: 'Word',
|
|
95
|
+
formatPdf: 'PDF',
|
|
83
96
|
markHelpful: 'Helpful',
|
|
84
97
|
markNotHelpful: 'Not helpful',
|
|
85
98
|
markNote: 'Anything to add? (optional)',
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import type { AgentEvent } from './client';
|
|
10
10
|
import type { Citation } from './citations';
|
|
11
|
+
import type { Written } from './written';
|
|
11
12
|
export interface TextBlock {
|
|
12
13
|
kind: 'text';
|
|
13
14
|
index: number;
|
|
@@ -66,12 +67,6 @@ export interface ToolWords {
|
|
|
66
67
|
object: string;
|
|
67
68
|
/** One dimmed line under the row. */
|
|
68
69
|
detail?: string;
|
|
69
|
-
/** How the activity line counts the call, singular and plural:
|
|
70
|
-
* `['search', 'searches']` reads "2 searches". Absent is not counted. */
|
|
71
|
-
tally?: [one: string, many: string];
|
|
72
|
-
/** How the row counts a run of identical calls: `['page', 'pages']`
|
|
73
|
-
* reads "· 5 pages". Absent reads "× 5". */
|
|
74
|
-
repeat?: [one: string, many: string];
|
|
75
70
|
/** Something the call read that a reader can open, listed under the
|
|
76
71
|
* answer and handed back to the host's `oncite` when tapped. */
|
|
77
72
|
source?: {
|
|
@@ -120,6 +115,8 @@ export declare class Transcript {
|
|
|
120
115
|
outcome: Outcome | null;
|
|
121
116
|
/** Sources for the answer, from the app's `citations` frame. */
|
|
122
117
|
citations: Citation[];
|
|
118
|
+
/** The document versions the persona wrote, in order. */
|
|
119
|
+
written: Written[];
|
|
123
120
|
other: AgentEvent[];
|
|
124
121
|
reset(): void;
|
|
125
122
|
apply(event: AgentEvent): void;
|
|
@@ -129,6 +126,7 @@ export interface FoldTarget {
|
|
|
129
126
|
blocks: Block[];
|
|
130
127
|
outcome: Outcome | null;
|
|
131
128
|
citations?: Citation[];
|
|
129
|
+
written?: Written[];
|
|
132
130
|
}
|
|
133
131
|
/** Where one turn's fold keeps its place between events. */
|
|
134
132
|
export interface FoldState {
|
|
@@ -155,29 +153,18 @@ export declare function fold(into: FoldTarget, state: FoldState, event: AgentEve
|
|
|
155
153
|
/** A message's content blocks; a user frame may carry a bare string instead. */
|
|
156
154
|
export declare function contentOf(event: AgentEvent): Array<Record<string, unknown>>;
|
|
157
155
|
export interface ActivityStep {
|
|
158
|
-
/** The block this step stands for
|
|
156
|
+
/** The block this step stands for.
|
|
159
157
|
*
|
|
160
158
|
* A `text` block here is interstitial narration, not the answer — see
|
|
161
159
|
* `segment()`. */
|
|
162
160
|
block: Block;
|
|
163
|
-
/**
|
|
164
|
-
repeats: number;
|
|
165
|
-
/** A tool step in the persona's words, resolved once here so the row, the
|
|
166
|
-
* count and the collapse all agree. */
|
|
161
|
+
/** A tool step in the persona's words, resolved once here. */
|
|
167
162
|
words?: ToolWords;
|
|
168
163
|
}
|
|
169
|
-
/** One count on the activity line: "2 searches". */
|
|
170
|
-
export interface Tally {
|
|
171
|
-
one: string;
|
|
172
|
-
many: string;
|
|
173
|
-
count: number;
|
|
174
|
-
}
|
|
175
164
|
export interface ActivityGroup {
|
|
176
165
|
kind: 'activity';
|
|
177
166
|
index: number;
|
|
178
167
|
steps: ActivityStep[];
|
|
179
|
-
/** What the steps counted as, in the order each first appeared. */
|
|
180
|
-
tallies: Tally[];
|
|
181
168
|
}
|
|
182
169
|
export type Segment = ActivityGroup | TextBlock;
|
|
183
170
|
/** One question and the answer to it, as the transcript renders it.
|
|
@@ -196,6 +183,10 @@ export interface Turn {
|
|
|
196
183
|
blocks: Block[];
|
|
197
184
|
outcome: Outcome | null;
|
|
198
185
|
citations?: Citation[];
|
|
186
|
+
/** The names of the files attached to the question. */
|
|
187
|
+
files?: string[];
|
|
188
|
+
/** The document versions the persona wrote answering it, in order. */
|
|
189
|
+
written?: Written[];
|
|
199
190
|
/** Something this turn produced for the reader to open, carded under the
|
|
200
191
|
* answer once the turn settles. */
|
|
201
192
|
artefact?: Artefact;
|
|
@@ -223,15 +214,11 @@ export interface Artefact {
|
|
|
223
214
|
/**
|
|
224
215
|
* Fold a turn's flat block list into what a reader should actually see.
|
|
225
216
|
*
|
|
226
|
-
*
|
|
217
|
+
* Two problems this solves, reported off a real transcript:
|
|
227
218
|
*
|
|
228
|
-
* 1.
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
* 2. "Reading pspf guidelines 2026" appeared five times in a row — five pages
|
|
232
|
-
* of one document, which is one act of reading to a human. Consecutive
|
|
233
|
-
* steps with the same label collapse to one row carrying a count.
|
|
234
|
-
* 3. The persona's between-tool narration was rendering unfolded, as answer prose.
|
|
219
|
+
* 1. Contiguous activity becomes ONE group, so the answer's prose is never
|
|
220
|
+
* split by each step; every step stays its own collapsed row in it.
|
|
221
|
+
* 2. The persona's between-tool narration was rendering unfolded, as answer prose.
|
|
235
222
|
* The caller stream carries no `thinking` blocks at all — measured on
|
|
236
223
|
* production 11/09/2026 — so "Let me also check whether…" arrives as an
|
|
237
224
|
* ordinary `text` block, indistinguishable from the answer except by
|
|
@@ -239,7 +226,7 @@ export interface Artefact {
|
|
|
239
226
|
* narration; only the run of text after the LAST tool call is the answer.
|
|
240
227
|
* Narration folds into the activity group as a thinking-shaped step.
|
|
241
228
|
*
|
|
242
|
-
* That
|
|
229
|
+
* That second rule is provisional while a turn streams, and deliberately so: a
|
|
243
230
|
* text block that is currently last IS the answer as far as anything can know,
|
|
244
231
|
* and renders as prose. The tool call that arrives after it re-homes it into
|
|
245
232
|
* the group. Nothing here holds state to make that work — `segment` is pure
|
|
@@ -252,12 +239,6 @@ export interface Artefact {
|
|
|
252
239
|
* off the prose itself would be unexplainable the first time it misfired.
|
|
253
240
|
*/
|
|
254
241
|
export declare function segment(blocks: Block[], describeTool?: DescribeTool): Segment[];
|
|
255
|
-
/** One line describing a whole investigation, for the collapsed state.
|
|
256
|
-
*
|
|
257
|
-
* Counts of what the persona did are fine ("1 search · 2 documents read"); how
|
|
258
|
-
* it organises what it knows is not — no collection count, no corpus.
|
|
259
|
-
*/
|
|
260
|
-
export declare function summariseActivity(group: ActivityGroup): string;
|
|
261
242
|
/**
|
|
262
243
|
* What a settled answer took, as one quiet line: `56.3s`, then what it cost
|
|
263
244
|
* — only when the host can price it (`formatCost`) and the run actually
|