@anchrd/intel-ui 0.15.0 → 0.16.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/package.json +3 -2
- package/src/agent/agent-log/agent-log.tsx +36 -6
- package/src/agent/agent-profile/agent-profile.tsx +8 -2
- package/src/data/agent-runtime/agent-runtime.ts +12 -0
- package/src/i18n/de.json +5 -1
- package/src/i18n/en.json +5 -1
- package/src/i18n/es.json +5 -1
- package/src/kind-icon.ts +12 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@anchrd/intel-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"typecheck": "tsc --noEmit"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@anchrd/intel-contract": "^0.
|
|
32
|
+
"@anchrd/intel-contract": "^0.10.0",
|
|
33
33
|
"@assistant-ui/react": "^0.15.4",
|
|
34
34
|
"@assistant-ui/react-ai-sdk": "^1.4.4",
|
|
35
35
|
"@blocknote/core": "^0.52.1",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"zod": "^4.4.3"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
+
"@testing-library/dom": "^10.4.1",
|
|
63
64
|
"@testing-library/react": "^16.3.2",
|
|
64
65
|
"@types/node": "^24.13.3",
|
|
65
66
|
"@types/react": "^19.2.17",
|
|
@@ -3,7 +3,6 @@ import { useQuery } from "@tanstack/react-query";
|
|
|
3
3
|
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
4
4
|
import { useState } from "react";
|
|
5
5
|
import {
|
|
6
|
-
costWindow,
|
|
7
6
|
formatCost,
|
|
8
7
|
formatTokens,
|
|
9
8
|
type RunCost,
|
|
@@ -23,9 +22,10 @@ import { useIntelRouterContext } from "@/router/router-context.ts";
|
|
|
23
22
|
* trimmed there. So this list is short by design and has no paging — the runtime answers at most a
|
|
24
23
|
* hundred runs and keeps no more.
|
|
25
24
|
*
|
|
26
|
-
* ⚠️ A run says what it did
|
|
27
|
-
*
|
|
28
|
-
*
|
|
25
|
+
* ⚠️ A run says what it did, when it failed what stopped it, and since #268 what it answered — but
|
|
26
|
+
* only for the runs nobody was watching (`schedule`, `manual`, `task`). A chat answer belongs to the
|
|
27
|
+
* person it was streamed to and a mail answer to the correspondent, and the runtime deliberately
|
|
28
|
+
* stores neither where this list could reach it.
|
|
29
29
|
*
|
|
30
30
|
* ⚠️ Since #251 it also says what each run consumed and what it cost — and the two come from
|
|
31
31
|
* DIFFERENT places on purpose. The tokens are the runtime's own record; the money is Cloudflare's
|
|
@@ -223,22 +223,52 @@ function RunRow({
|
|
|
223
223
|
) : null}
|
|
224
224
|
</span>
|
|
225
225
|
</button>
|
|
226
|
-
{open ? <RunDetail agentId={agentId}
|
|
226
|
+
{open ? <RunDetail agentId={agentId} run={run} /> : null}
|
|
227
227
|
</li>
|
|
228
228
|
);
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
+
/**
|
|
232
|
+
* What an unattended run produced, which is the only place a person can read it (#272).
|
|
233
|
+
*
|
|
234
|
+
* ⚠️ Rendered for `schedule`, `manual` and `task`, and for nothing else. A `chat` or `mail` run
|
|
235
|
+
* carries no answer by construction (#268), so an empty state under one of those would invent a
|
|
236
|
+
* loss: the answer was streamed into a window or posted to a correspondent and was never meant to
|
|
237
|
+
* come back here.
|
|
238
|
+
*
|
|
239
|
+
* ⚠️ Read from the run the row already holds, not from the detail fetch. `GET /runs` carries the
|
|
240
|
+
* whole record, and hanging the answer off the second request would hide it whenever the
|
|
241
|
+
* operational log — the smaller half of what this row is for — happens to be unreadable.
|
|
242
|
+
*/
|
|
243
|
+
function RunAnswer({ run, i18n }: { run: AgentRun; i18n: I18n }) {
|
|
244
|
+
if (run.trigger === "chat" || run.trigger === "mail") return null;
|
|
245
|
+
return (
|
|
246
|
+
<section aria-label={i18n.t("agent.runAnswer")} className="mb-3">
|
|
247
|
+
<h3 className="text-sm font-semibold">{i18n.t("agent.runAnswer")}</h3>
|
|
248
|
+
{run.answer ? (
|
|
249
|
+
// Whitespace preserved: a model answers in paragraphs and lists, and collapsing them turns
|
|
250
|
+
// a readable report into one block of prose.
|
|
251
|
+
<p className="mt-1 whitespace-pre-wrap text-sm">{run.answer}</p>
|
|
252
|
+
) : (
|
|
253
|
+
<p className="mt-1 text-sm text-muted-foreground">{i18n.t("agent.runAnswerEmpty")}</p>
|
|
254
|
+
)}
|
|
255
|
+
</section>
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
|
|
231
259
|
// The operational log of one run: what it tried, in order. Fetched only when a row is opened —
|
|
232
260
|
// every run carries its own entries and loading all of them would be the whole log for one screen.
|
|
233
|
-
function RunDetail({ agentId,
|
|
261
|
+
function RunDetail({ agentId, run }: { agentId: string; run: AgentRun }) {
|
|
234
262
|
const { data } = useIntelRouterContext();
|
|
235
263
|
const i18n = useI18n();
|
|
264
|
+
const runId = run.id;
|
|
236
265
|
const detail = useQuery({
|
|
237
266
|
queryKey: ["agent-run", agentId, runId],
|
|
238
267
|
queryFn: () => data.getAgentRun(agentId, runId),
|
|
239
268
|
});
|
|
240
269
|
return (
|
|
241
270
|
<div className="border-t px-4 py-3">
|
|
271
|
+
<RunAnswer run={run} i18n={i18n} />
|
|
242
272
|
{detail.isPending ? (
|
|
243
273
|
<p className="text-sm text-muted-foreground">{i18n.t("common.loading")}</p>
|
|
244
274
|
) : null}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
Copy,
|
|
18
18
|
FileText,
|
|
19
19
|
Folder,
|
|
20
|
+
KanbanSquare,
|
|
20
21
|
KeyRound,
|
|
21
22
|
MessageSquare,
|
|
22
23
|
Paperclip,
|
|
@@ -340,8 +341,12 @@ function defaultRoleFor(kind: PickerKind): AgentReferenceRole | null {
|
|
|
340
341
|
* changes what a document MEANS to an agent must look changeable.
|
|
341
342
|
*
|
|
342
343
|
* ⚠️ Since #255 a row can also be a single document or table, and the role select shows only the
|
|
343
|
-
* roles that kind can carry. `memory` and `semantic-context` stay folders — the agent
|
|
344
|
-
*
|
|
344
|
+
* roles that kind can carry. `memory` and `semantic-context` stay folders — the agent searches both
|
|
345
|
+
* and writes into one of them — so a document simply never offers them.
|
|
346
|
+
*
|
|
347
|
+
* ⚠️ Memory is searched too, since #259, and the hint beside this section says so in words (#269).
|
|
348
|
+
* The role name alone reads as a write-only notebook, and somebody who believes that files things
|
|
349
|
+
* there that come back at them out of every later search.
|
|
345
350
|
*/
|
|
346
351
|
function KnowledgeSection({
|
|
347
352
|
definition,
|
|
@@ -427,6 +432,7 @@ const KindIcon: Record<NodeKind, typeof Folder> = {
|
|
|
427
432
|
table: Table2,
|
|
428
433
|
attachment: Paperclip,
|
|
429
434
|
agent: Bot,
|
|
435
|
+
board: KanbanSquare,
|
|
430
436
|
};
|
|
431
437
|
|
|
432
438
|
/**
|
|
@@ -43,6 +43,18 @@ export const AgentRun = z.object({
|
|
|
43
43
|
finishedAt: z.string().nullable(),
|
|
44
44
|
steps: z.number(),
|
|
45
45
|
error: z.string().nullable(),
|
|
46
|
+
/**
|
|
47
|
+
* What the run answered, for the runs nobody was watching: `schedule`, `manual` and `task`.
|
|
48
|
+
*
|
|
49
|
+
* ⚠️ A `chat` or `mail` run carries none, and that is a runtime invariant rather than an accident
|
|
50
|
+
* (#268): that answer belongs to the person whose window it was streamed into or to the
|
|
51
|
+
* correspondent it was posted to. The log screen therefore claims nothing at all on those two
|
|
52
|
+
* triggers — an empty state there would read as "the answer went missing".
|
|
53
|
+
*
|
|
54
|
+
* ⚠️ `.nullish()` for the same reason as `usage` below: a runtime from before #268 sends no such
|
|
55
|
+
* field, and a required one would blank the whole Log tab over its absence.
|
|
56
|
+
*/
|
|
57
|
+
answer: z.string().nullish(),
|
|
46
58
|
// ⚠️ `.nullish()` on both, not `.nullable()`. The runtime is a separate deployment and may be a
|
|
47
59
|
// version BEHIND this page: a run list from a runtime without #250/#251 has no such field at all,
|
|
48
60
|
// and a required one would blank the whole Log tab over a missing number.
|
package/src/i18n/de.json
CHANGED
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"tree.kind.attachment": "Datei",
|
|
51
51
|
"tree.kind.table": "Tabelle",
|
|
52
52
|
"tree.kind.agent": "Agent",
|
|
53
|
+
"tree.kind.board": "Board",
|
|
53
54
|
"tree.kind.flow": "Flow",
|
|
54
55
|
"tree.move.action": "Verschieben nach …",
|
|
55
56
|
"tree.move.title": "{title} verschieben",
|
|
@@ -108,6 +109,7 @@
|
|
|
108
109
|
"node.kind.attachment": "Upload",
|
|
109
110
|
"node.kind.table": "Tabelle",
|
|
110
111
|
"node.kind.agent": "Agent",
|
|
112
|
+
"node.kind.board": "Board",
|
|
111
113
|
"node.kind.flow": "Flow",
|
|
112
114
|
"node.share": "Freigeben",
|
|
113
115
|
"node.shareAction": "Zugriff geben",
|
|
@@ -322,7 +324,7 @@
|
|
|
322
324
|
"agent.contactAdd": "Erreichbarkeit hinzufügen",
|
|
323
325
|
"agent.contactAddReason": "Eine Mail-Adresse gehört der Installation, nicht der Definition des Agenten — sie wird dort konfiguriert, wo die Laufzeit betrieben wird.",
|
|
324
326
|
"agent.knows": "Was er weiß",
|
|
325
|
-
"agent.knowsHint": "Was dieser Agent liest, und wofür jeder Eintrag zählt. Eine Systemnachricht weist ihn an — ein Ordner, ein Dokument oder eine Tabelle. Semantischer Kontext wird durchsucht und in das Gedächtnis wird zurückgeschrieben, deshalb sind beide Ordner.",
|
|
327
|
+
"agent.knowsHint": "Was dieser Agent liest, und wofür jeder Eintrag zählt. Eine Systemnachricht weist ihn an — ein Ordner, ein Dokument oder eine Tabelle. Semantischer Kontext wird durchsucht, und in das Gedächtnis wird zurückgeschrieben und es wird ebenso durchsucht, deshalb sind beide Ordner. Der Name verspricht weniger als die Rolle: Was der Agent sich im Gedächtnis notiert, kommt ihm bei jeder späteren Suche wieder entgegen.",
|
|
326
328
|
"agent.addReference": "Etwas zum Lesen hinzufügen",
|
|
327
329
|
"agent.removeReferenceOf": "{title} nicht mehr lesen",
|
|
328
330
|
"agent.pickEntry": "Was gelesen wird",
|
|
@@ -377,6 +379,8 @@
|
|
|
377
379
|
"agent.runFailed": "Dieser Lauf konnte nicht gelesen werden.",
|
|
378
380
|
"agent.runLog": "Was dieser Lauf getan hat",
|
|
379
381
|
"agent.runLogEmpty": "Dieser Lauf hat nichts aufgezeichnet.",
|
|
382
|
+
"agent.runAnswer": "Was dieser Lauf geantwortet hat",
|
|
383
|
+
"agent.runAnswerEmpty": "Dieser Lauf hat keine Antwort aufgezeichnet.",
|
|
380
384
|
"agent.steps": "{count} Schritte",
|
|
381
385
|
"agent.trigger.chat": "aus dem Chat",
|
|
382
386
|
"agent.trigger.schedule": "nach Zeitplan",
|
package/src/i18n/en.json
CHANGED
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"tree.kind.attachment": "File",
|
|
51
51
|
"tree.kind.table": "Table",
|
|
52
52
|
"tree.kind.agent": "Agent",
|
|
53
|
+
"tree.kind.board": "Board",
|
|
53
54
|
"tree.kind.flow": "Flow",
|
|
54
55
|
"tree.move.action": "Move to…",
|
|
55
56
|
"tree.move.title": "Move {title}",
|
|
@@ -108,6 +109,7 @@
|
|
|
108
109
|
"node.kind.attachment": "Upload",
|
|
109
110
|
"node.kind.table": "Table",
|
|
110
111
|
"node.kind.agent": "Agent",
|
|
112
|
+
"node.kind.board": "Board",
|
|
111
113
|
"node.kind.flow": "Flow",
|
|
112
114
|
"node.share": "Share",
|
|
113
115
|
"node.shareAction": "Grant access",
|
|
@@ -322,7 +324,7 @@
|
|
|
322
324
|
"agent.contactAdd": "Add contact",
|
|
323
325
|
"agent.contactAddReason": "A mail address belongs to the installation, not to the agent's definition, so it is configured where the runtime is deployed.",
|
|
324
326
|
"agent.knows": "What it knows",
|
|
325
|
-
"agent.knowsHint": "What this agent reads, and what each entry counts as. A system message instructs it — a folder, a document or a table. Semantic context is searched and memory is written back to, so both of those are folders.",
|
|
327
|
+
"agent.knowsHint": "What this agent reads, and what each entry counts as. A system message instructs it — a folder, a document or a table. Semantic context is searched, and memory is written back to and searched as well, so both of those are folders. The name promises less than the role does: what the agent notes down in memory comes back to it in every later search.",
|
|
326
328
|
"agent.addReference": "Add something to read",
|
|
327
329
|
"agent.removeReferenceOf": "Stop reading {title}",
|
|
328
330
|
"agent.pickEntry": "What to read",
|
|
@@ -377,6 +379,8 @@
|
|
|
377
379
|
"agent.runFailed": "This run could not be read.",
|
|
378
380
|
"agent.runLog": "What this run did",
|
|
379
381
|
"agent.runLogEmpty": "This run recorded nothing.",
|
|
382
|
+
"agent.runAnswer": "What this run answered",
|
|
383
|
+
"agent.runAnswerEmpty": "This run recorded no answer.",
|
|
380
384
|
"agent.steps": "{count} steps",
|
|
381
385
|
"agent.trigger.chat": "from the chat",
|
|
382
386
|
"agent.trigger.schedule": "on schedule",
|
package/src/i18n/es.json
CHANGED
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"tree.kind.attachment": "Archivo",
|
|
51
51
|
"tree.kind.table": "Tabla",
|
|
52
52
|
"tree.kind.agent": "Agente",
|
|
53
|
+
"tree.kind.board": "Tablero",
|
|
53
54
|
"tree.kind.flow": "Flujo",
|
|
54
55
|
"tree.move.action": "Mover a…",
|
|
55
56
|
"tree.move.title": "Mover {title}",
|
|
@@ -108,6 +109,7 @@
|
|
|
108
109
|
"node.kind.attachment": "Subida",
|
|
109
110
|
"node.kind.table": "Tabla",
|
|
110
111
|
"node.kind.agent": "Agente",
|
|
112
|
+
"node.kind.board": "Tablero",
|
|
111
113
|
"node.kind.flow": "Flujo",
|
|
112
114
|
"node.share": "Compartir",
|
|
113
115
|
"node.shareAction": "Conceder acceso",
|
|
@@ -322,7 +324,7 @@
|
|
|
322
324
|
"agent.contactAdd": "Añadir un contacto",
|
|
323
325
|
"agent.contactAddReason": "Una dirección de correo pertenece a la instalación, no a la definición del agente, así que se configura donde está desplegado el entorno de ejecución.",
|
|
324
326
|
"agent.knows": "Lo que sabe",
|
|
325
|
-
"agent.knowsHint": "Lo que lee este agente y para qué cuenta cada entrada. Un mensaje de sistema lo instruye — una carpeta, un documento o una tabla. El contexto semántico se busca y en la memoria se escribe de vuelta, por eso
|
|
327
|
+
"agent.knowsHint": "Lo que lee este agente y para qué cuenta cada entrada. Un mensaje de sistema lo instruye — una carpeta, un documento o una tabla. El contexto semántico se busca, y en la memoria se escribe de vuelta y también se busca, por eso ambas son carpetas. El nombre promete menos que el papel: lo que el agente anota en la memoria le vuelve en cada búsqueda posterior.",
|
|
326
328
|
"agent.addReference": "Añadir algo para leer",
|
|
327
329
|
"agent.removeReferenceOf": "Dejar de leer {title}",
|
|
328
330
|
"agent.pickEntry": "Qué se lee",
|
|
@@ -377,6 +379,8 @@
|
|
|
377
379
|
"agent.runFailed": "Esta ejecución no se ha podido leer.",
|
|
378
380
|
"agent.runLog": "Lo que ha hecho esta ejecución",
|
|
379
381
|
"agent.runLogEmpty": "Esta ejecución no ha registrado nada.",
|
|
382
|
+
"agent.runAnswer": "Lo que ha respondido esta ejecución",
|
|
383
|
+
"agent.runAnswerEmpty": "Esta ejecución no ha registrado ninguna respuesta.",
|
|
380
384
|
"agent.steps": "{count} pasos",
|
|
381
385
|
"agent.trigger.chat": "desde el chat",
|
|
382
386
|
"agent.trigger.schedule": "por horario",
|
package/src/kind-icon.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Bot,
|
|
3
|
+
FileText,
|
|
4
|
+
Folder,
|
|
5
|
+
KanbanSquare,
|
|
6
|
+
type LucideIcon,
|
|
7
|
+
Paperclip,
|
|
8
|
+
Table,
|
|
9
|
+
Workflow,
|
|
10
|
+
} from "lucide-react";
|
|
2
11
|
import type { TreeEntry } from "@/data/intel-data-provider/intel-data-provider.types.ts";
|
|
3
12
|
|
|
4
13
|
/**
|
|
@@ -18,5 +27,7 @@ export const kindIcons: Record<TreeEntry["kind"], LucideIcon> = {
|
|
|
18
27
|
// An agent is listed and named like any other row (#139), and since #143 opening one leads to
|
|
19
28
|
// its own screen. The sidebar's create menu draws this same icon rather than naming `Bot` again.
|
|
20
29
|
agent: Bot,
|
|
30
|
+
// A board is a row like any other (#285); the views that open one are anchrd/intel#286.
|
|
31
|
+
board: KanbanSquare,
|
|
21
32
|
flow: Workflow,
|
|
22
33
|
};
|