@guuey/chat 0.5.0 → 0.6.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.
- package/dist/hitl.d.ts +58 -0
- package/dist/hitl.d.ts.map +1 -0
- package/dist/hitl.js +81 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/native/components.d.ts +18 -2
- package/dist/native/components.d.ts.map +1 -1
- package/dist/native/components.js +49 -0
- package/dist/native/transcript.d.ts +1 -1
- package/dist/native/transcript.d.ts.map +1 -1
- package/dist/native/transcript.js +2 -2
- package/dist/native.d.ts +1 -1
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +1 -1
- package/dist/plan.d.ts +15 -0
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +211 -13
- package/dist/policy.d.ts +4 -0
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +2 -0
- package/dist/react/components.d.ts +42 -5
- package/dist/react/components.d.ts.map +1 -1
- package/dist/react/components.js +51 -1
- package/dist/react/guuey-chat.d.ts +62 -4
- package/dist/react/guuey-chat.d.ts.map +1 -1
- package/dist/react/guuey-chat.js +73 -8
- package/dist/react/transcript.d.ts +1 -1
- package/dist/react/transcript.d.ts.map +1 -1
- package/dist/react/transcript.js +2 -2
- package/dist/react/use-transcript.d.ts +21 -2
- package/dist/react/use-transcript.d.ts.map +1 -1
- package/dist/react/use-transcript.js +57 -3
- package/dist/react.d.ts +2 -2
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +1 -1
- package/dist/strings.d.ts +13 -0
- package/dist/strings.d.ts.map +1 -1
- package/dist/strings.js +8 -0
- package/dist/types.d.ts +146 -7
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -5
- package/src/corpus/README.md +13 -1
- package/src/corpus/__snapshots__/corpus.test.ts.snap +304 -0
- package/src/corpus/drive.ts +3 -3
- package/src/corpus/fixtures.ts +220 -1
- package/src/hitl.ts +103 -0
- package/src/index.ts +15 -0
- package/src/native/components.tsx +136 -1
- package/src/native/transcript.tsx +4 -3
- package/src/native.tsx +1 -0
- package/src/plan.ts +233 -20
- package/src/policy.ts +4 -0
- package/src/react/components.tsx +171 -8
- package/src/react/guuey-chat.tsx +143 -9
- package/src/react/transcript.tsx +4 -3
- package/src/react/use-transcript.ts +83 -5
- package/src/react.tsx +3 -1
- package/src/strings.ts +25 -0
- package/src/types.ts +152 -6
- package/styles.css +21 -0
package/dist/plan.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { snapshotViewMount, toolResultViewMount, uiLocator } from "@guuey/mcp-apps-host";
|
|
2
|
+
import { grantModeDisplay } from "./hitl.js";
|
|
2
3
|
/** R5's giant threshold: above this byte count the state is `giant`. */
|
|
3
4
|
const GIANT_RESULT_BYTES = 16_384;
|
|
4
5
|
/** Approximate byte size of a JSON value — deterministic, allocation-bounded. */
|
|
@@ -28,6 +29,13 @@ function resolveExpanded(key, policyDefault, overrides) {
|
|
|
28
29
|
const override = overrides[key]?.expanded;
|
|
29
30
|
return override ?? policyDefault;
|
|
30
31
|
}
|
|
32
|
+
/** R16 notice text: the message's text blocks, joined (non-text blocks carry no notice prose). */
|
|
33
|
+
function noticeText(content) {
|
|
34
|
+
return content
|
|
35
|
+
.filter((b) => b.type === "text")
|
|
36
|
+
.map((b) => b.text)
|
|
37
|
+
.join("\n");
|
|
38
|
+
}
|
|
31
39
|
function foldAssistantSources(result, inFlight, aborted) {
|
|
32
40
|
// Real pod folds carry `tool-result` blocks in separate `role: "tool"`
|
|
33
41
|
// messages between assistant turns (the production ggui-render capture is
|
|
@@ -35,21 +43,49 @@ function foldAssistantSources(result, inFlight, aborted) {
|
|
|
35
43
|
// assistant-only filter orphans every call and drops every mount. A tool
|
|
36
44
|
// message's blocks belong to the PRECEDING assistant slot's walk, exactly
|
|
37
45
|
// the whole-fold message order the retired first-party renderers used.
|
|
46
|
+
//
|
|
47
|
+
// LIVE detection is turn-identity-based where the fold carries it: while
|
|
48
|
+
// a turn is in flight, an assistant message whose `turnId` maps to a turn
|
|
49
|
+
// record WITHOUT an `outcome` belongs to the open turn — settled earlier
|
|
50
|
+
// turns stay settled even mid-session (what makes the tail alignment
|
|
51
|
+
// below count them correctly). Nothing is live once the status is back to
|
|
52
|
+
// `ready`, whatever the records say (a fold that missed `turn.done` must
|
|
53
|
+
// not pin a settled turn open forever). Folds without turn identity (a
|
|
54
|
+
// hand-driven fold that never saw `turn.*` lifecycle) fall back to the
|
|
55
|
+
// last-source-is-live-iff-in-flight heuristic — the pre-refinement
|
|
56
|
+
// behaviour, kept so identity-less folds plan exactly as before.
|
|
57
|
+
const openTurns = new Set(result.turns.filter((t) => t.outcome === undefined).map((t) => t.turnId));
|
|
58
|
+
const hasTurnIdentity = result.messages.some((m) => m.role === "assistant" && m.turnId !== undefined);
|
|
38
59
|
const sources = [];
|
|
60
|
+
const notices = [];
|
|
39
61
|
for (const m of result.messages) {
|
|
40
62
|
if (m.role === "assistant") {
|
|
41
|
-
sources.push({
|
|
63
|
+
sources.push({
|
|
64
|
+
blocks: [...m.content],
|
|
65
|
+
live: inFlight && hasTurnIdentity && m.turnId !== undefined && openTurns.has(m.turnId),
|
|
66
|
+
stopped: false,
|
|
67
|
+
});
|
|
42
68
|
}
|
|
43
69
|
else if (m.role === "tool" && sources.length > 0) {
|
|
44
70
|
sources[sources.length - 1].blocks.push(...m.content);
|
|
45
71
|
}
|
|
72
|
+
else if (m.role === "notice") {
|
|
73
|
+
// R16 (spec draft.2): a session annotation — a PEER row, never folded
|
|
74
|
+
// into assistant content; it anchors after the source it followed.
|
|
75
|
+
notices.push({
|
|
76
|
+
text: noticeText(m.content),
|
|
77
|
+
source: m.noticeSource ?? null,
|
|
78
|
+
afterSourceIndex: sources.length - 1,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
46
81
|
}
|
|
47
82
|
const last = sources[sources.length - 1];
|
|
48
83
|
if (last) {
|
|
49
|
-
|
|
84
|
+
if (!hasTurnIdentity)
|
|
85
|
+
last.live = inFlight;
|
|
50
86
|
last.stopped = aborted;
|
|
51
87
|
}
|
|
52
|
-
return sources;
|
|
88
|
+
return { sources, notices };
|
|
53
89
|
}
|
|
54
90
|
function flatAssistantSources(inputs, inFlight) {
|
|
55
91
|
const settled = inputs.messages
|
|
@@ -521,11 +557,74 @@ export function planTranscript(inputs, policy, overrides = {}) {
|
|
|
521
557
|
}
|
|
522
558
|
const inFlight = inputs.status !== "ready";
|
|
523
559
|
const users = inputs.messages.filter((m) => m.role === "user");
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
560
|
+
// R16 — notice rows are session annotations anchored between turns: a
|
|
561
|
+
// flat notice renders after the conversation slot of the user turn it
|
|
562
|
+
// followed (usersSeen-1; -1 = before the conversation). They are PEER
|
|
563
|
+
// rows — excluded from both the user pairing and the assistant seam
|
|
564
|
+
// count, so the fold alignment below never sees them.
|
|
565
|
+
const notices = [];
|
|
566
|
+
if (policy.notice.show) {
|
|
567
|
+
let usersSeen = 0;
|
|
568
|
+
inputs.messages.forEach((m, i) => {
|
|
569
|
+
if (m.role === "user")
|
|
570
|
+
usersSeen += 1;
|
|
571
|
+
else if (m.role === "notice") {
|
|
572
|
+
notices.push({ key: `n${i}`, text: m.text, source: m.noticeSource ?? null, afterSlot: usersSeen - 1 });
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
// Turn-scoped fold composition (guuey#135 kit refinement): the fold owns
|
|
577
|
+
// the TRAILING assistant turns it actually covers — its settled sources
|
|
578
|
+
// replace that many trailing flat assistant entries; any EARLIER flat
|
|
579
|
+
// entries (a rehydrated/persisted prefix the session's Reducer never saw)
|
|
580
|
+
// keep rendering as flat text slots in front. When the fold spans the
|
|
581
|
+
// whole conversation (a pure-live session — the corpus's world), the kept
|
|
582
|
+
// prefix is empty and the plan is byte-identical to the old wholesale
|
|
583
|
+
// replace. Alignment is by COUNT (trailing flat entries ↔ settled fold
|
|
584
|
+
// sources): flat rows carry no turn identity, so a persisted CARD-ONLY
|
|
585
|
+
// turn inside the fold's span (an empty-text assistant row the assembler
|
|
586
|
+
// dropped) can offset the seam by one — a documented approximation, same
|
|
587
|
+
// class as the header's read-plane-seq note, resolved for the visible
|
|
588
|
+
// cards by the actionScope dedupe below.
|
|
589
|
+
let assistants;
|
|
590
|
+
if (inputs.result) {
|
|
591
|
+
const fold = foldAssistantSources(inputs.result, inFlight, inputs.aborted === true);
|
|
592
|
+
const foldSources = fold.sources;
|
|
593
|
+
const settledFoldCount = foldSources.filter((s) => !s.live).length;
|
|
594
|
+
const flatSettled = inputs.messages.filter((m) => m.role === "assistant");
|
|
595
|
+
const keep = Math.max(0, flatSettled.length - settledFoldCount);
|
|
596
|
+
assistants = [
|
|
597
|
+
...flatSettled.slice(0, keep).map((m) => ({
|
|
598
|
+
blocks: [{ type: "text", text: m.text }],
|
|
599
|
+
live: false,
|
|
600
|
+
stopped: false,
|
|
601
|
+
})),
|
|
602
|
+
...foldSources,
|
|
603
|
+
];
|
|
604
|
+
if (policy.notice.show) {
|
|
605
|
+
// Fold-borne notices anchor to the fold source they followed, which
|
|
606
|
+
// sits at global slot `keep + afterSourceIndex` after the seam.
|
|
607
|
+
fold.notices.forEach((n, i) => {
|
|
608
|
+
notices.push({ key: `nf${i}`, text: n.text, source: n.source, afterSlot: keep + n.afterSourceIndex });
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
else {
|
|
613
|
+
assistants = flatAssistantSources(inputs, inFlight);
|
|
614
|
+
}
|
|
527
615
|
const slots = Math.max(users.length, assistants.length);
|
|
528
616
|
const conversation = [];
|
|
617
|
+
const noticeItem = (n) => ({
|
|
618
|
+
kind: "notice",
|
|
619
|
+
key: n.key,
|
|
620
|
+
expanded: true,
|
|
621
|
+
text: n.text,
|
|
622
|
+
source: n.source,
|
|
623
|
+
sourceLabel: policy.debugDetail && n.source !== null ? n.source : null,
|
|
624
|
+
});
|
|
625
|
+
for (const n of notices)
|
|
626
|
+
if (n.afterSlot < 0)
|
|
627
|
+
conversation.push(noticeItem(n));
|
|
529
628
|
for (let slot = 0; slot < slots; slot++) {
|
|
530
629
|
const user = users[slot];
|
|
531
630
|
if (user) {
|
|
@@ -546,15 +645,37 @@ export function planTranscript(inputs, policy, overrides = {}) {
|
|
|
546
645
|
if (assistant) {
|
|
547
646
|
conversation.push(...planAssistantSource(assistant, slot, inputs, policy, overrides));
|
|
548
647
|
}
|
|
648
|
+
for (const n of notices)
|
|
649
|
+
if (n.afterSlot === slot)
|
|
650
|
+
conversation.push(noticeItem(n));
|
|
549
651
|
}
|
|
550
652
|
items.push(...groupTools(conversation, policy, overrides));
|
|
551
653
|
// R13 — persisted cards, seq order. (Position: after the settled
|
|
552
654
|
// conversation; true in-turn interleave needs read-plane seqs the flat
|
|
553
655
|
// surface lacks — the 3b assemblers own that refinement.)
|
|
656
|
+
//
|
|
657
|
+
// Dedupe against LIVE mounts by actionScope (the persisted `ui://`
|
|
658
|
+
// identity both sides carry): a session whose fold still holds a turn the
|
|
659
|
+
// read plane has ALSO persisted — the #192 adopted turn, a thread view's
|
|
660
|
+
// post-handoff refetch — would otherwise render the same card twice. The
|
|
661
|
+
// fold's view row owns it (richer phase state); the history snapshot
|
|
662
|
+
// renders only when no live mount claims its identity.
|
|
663
|
+
const liveViewScopes = new Set();
|
|
664
|
+
for (const item of items) {
|
|
665
|
+
if (item.kind === "view" && item.actionScope !== null)
|
|
666
|
+
liveViewScopes.add(item.actionScope);
|
|
667
|
+
}
|
|
554
668
|
const cards = [...(inputs.historyCards ?? [])].sort((a, b) => a.seq - b.seq);
|
|
555
669
|
for (const card of cards) {
|
|
556
670
|
const key = `card.${card.seq}`;
|
|
557
671
|
const mount = snapshotViewMount(card.cardSnapshot);
|
|
672
|
+
const scope = mount === undefined
|
|
673
|
+
? null
|
|
674
|
+
: mount.channel === "locator"
|
|
675
|
+
? mount.resourceUri
|
|
676
|
+
: mount.resource.uri;
|
|
677
|
+
if (scope !== null && liveViewScopes.has(scope))
|
|
678
|
+
continue; // live mount owns it
|
|
558
679
|
const view = {
|
|
559
680
|
kind: "view",
|
|
560
681
|
key,
|
|
@@ -565,18 +686,40 @@ export function planTranscript(inputs, policy, overrides = {}) {
|
|
|
565
686
|
label: null,
|
|
566
687
|
attribution: null,
|
|
567
688
|
toolTitle: null,
|
|
568
|
-
actionScope:
|
|
569
|
-
? null
|
|
570
|
-
: mount.channel === "locator"
|
|
571
|
-
? mount.resourceUri
|
|
572
|
-
: mount.resource.uri,
|
|
689
|
+
actionScope: scope,
|
|
573
690
|
};
|
|
574
691
|
view.label = viewLabel(view, policy);
|
|
575
692
|
items.push(view);
|
|
576
693
|
}
|
|
577
|
-
// R10 — prompts, in input order
|
|
694
|
+
// R10 — prompts, in input order (narrow on `kind`: the guuey-wire
|
|
695
|
+
// profile arm vs the AgJSON hitl arm, spec draft.2).
|
|
578
696
|
for (const prompt of inputs.prompts) {
|
|
579
697
|
const key = `p.${prompt.id}`;
|
|
698
|
+
if (prompt.kind === "hitl") {
|
|
699
|
+
const chosen = prompt.grantModeId !== undefined
|
|
700
|
+
? (prompt.ask.grantModes ?? []).find((m) => m.id === prompt.grantModeId)
|
|
701
|
+
: undefined;
|
|
702
|
+
items.push({
|
|
703
|
+
kind: "prompt",
|
|
704
|
+
key,
|
|
705
|
+
promptId: prompt.id,
|
|
706
|
+
// `cancelled` collapses to a dismissed record but stays expandable —
|
|
707
|
+
// guuey's re-askable ruling (silverprotocol#16); pending opens.
|
|
708
|
+
expanded: resolveExpanded(key, prompt.state === "pending", overrides),
|
|
709
|
+
promptKind: "hitl",
|
|
710
|
+
ask: prompt.ask,
|
|
711
|
+
message: prompt.ask.message ?? null,
|
|
712
|
+
askKind: prompt.ask.kind,
|
|
713
|
+
grantModes: prompt.ask.grantModes ?? [],
|
|
714
|
+
state: prompt.state,
|
|
715
|
+
chosenModeId: prompt.grantModeId ?? null,
|
|
716
|
+
chosenModeLabel: chosen !== undefined ? grantModeDisplay(chosen) : null,
|
|
717
|
+
raw: policy.prompt.rawPayload
|
|
718
|
+
? { askId: prompt.ask.askId, kind: prompt.ask.kind, state: prompt.state, grantModeId: prompt.grantModeId ?? null }
|
|
719
|
+
: null,
|
|
720
|
+
});
|
|
721
|
+
continue;
|
|
722
|
+
}
|
|
580
723
|
items.push({
|
|
581
724
|
kind: "prompt",
|
|
582
725
|
key,
|
|
@@ -621,9 +764,64 @@ export function planTranscript(inputs, policy, overrides = {}) {
|
|
|
621
764
|
verbatim: policy.error.verbatim ? `${code ?? "uncoded"}: ${inputs.error.message}` : null,
|
|
622
765
|
});
|
|
623
766
|
}
|
|
767
|
+
// guuey#204 "promote and reference": the ONE mount a host-owned stage
|
|
768
|
+
// shows (`inputs.promotedViewKey`) renders as a compact reference chip
|
|
769
|
+
// instead of a second live app instance. A key matching nothing (stale
|
|
770
|
+
// host state) or an expired mount promotes nothing — the honest no-op;
|
|
771
|
+
// the next render's key corrects it. The chip keeps the mount's key, so
|
|
772
|
+
// overrides and phase reports survive a swap back to the full mount.
|
|
773
|
+
const promoted = inputs.promotedViewKey;
|
|
774
|
+
const finalItems = promoted === undefined
|
|
775
|
+
? items
|
|
776
|
+
: items.map((item) => {
|
|
777
|
+
if (item.kind !== "view" || item.key !== promoted)
|
|
778
|
+
return item;
|
|
779
|
+
if (item.phase === "expired" || item.mount === null)
|
|
780
|
+
return item;
|
|
781
|
+
const title = item.toolTitle ?? policy.strings.viewRefFallbackTitle;
|
|
782
|
+
const ref = {
|
|
783
|
+
kind: "viewRef",
|
|
784
|
+
key: item.key,
|
|
785
|
+
expanded: false,
|
|
786
|
+
title,
|
|
787
|
+
label: policy.strings.viewPromoted(title),
|
|
788
|
+
};
|
|
789
|
+
return ref;
|
|
790
|
+
});
|
|
624
791
|
return {
|
|
625
|
-
items,
|
|
792
|
+
items: finalItems,
|
|
626
793
|
status: deriveStatus(inputs, policy),
|
|
627
794
|
recovery: inputs.adopted === true && policy.debugDetail ? policy.strings.recoveredFromHistory : null,
|
|
628
795
|
};
|
|
629
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* The plan key of the NEWEST mountable view — what a "most recent card"
|
|
799
|
+
* stage (the widget's CanvasPane) will show, derived in the same family
|
|
800
|
+
* the plan's own emission uses: live fold mounts (transcript order, last
|
|
801
|
+
* wins) outrank history cards (ascending `seq`). `undefined` when nothing
|
|
802
|
+
* narrows to a mountable resource. Hosts pass the key back as
|
|
803
|
+
* `TranscriptInputs.promotedViewKey`; `channel` lets a host decline to
|
|
804
|
+
* promote a bare locator when no reader is wired (the stage would show
|
|
805
|
+
* nothing, and a chip must never point at an empty canvas).
|
|
806
|
+
*/
|
|
807
|
+
export function newestViewKey(inputs) {
|
|
808
|
+
let newest;
|
|
809
|
+
const cards = [...(inputs.historyCards ?? [])].sort((a, b) => a.seq - b.seq);
|
|
810
|
+
for (const card of cards) {
|
|
811
|
+
const mount = snapshotViewMount(card.cardSnapshot);
|
|
812
|
+
if (mount === undefined)
|
|
813
|
+
continue;
|
|
814
|
+
newest = { key: `card.${card.seq}`, channel: mount.channel };
|
|
815
|
+
}
|
|
816
|
+
for (const message of inputs.result?.messages ?? []) {
|
|
817
|
+
for (const block of message.content) {
|
|
818
|
+
if (block.type !== "tool-result")
|
|
819
|
+
continue;
|
|
820
|
+
const mount = toolResultViewMount(block);
|
|
821
|
+
if (mount === undefined)
|
|
822
|
+
continue;
|
|
823
|
+
newest = { key: `view.${block.toolCallId}`, channel: mount.channel };
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
return newest;
|
|
827
|
+
}
|
package/dist/policy.d.ts
CHANGED
|
@@ -93,6 +93,10 @@ export interface TranscriptPolicy {
|
|
|
93
93
|
wakingMs: number;
|
|
94
94
|
longStartMs: number;
|
|
95
95
|
};
|
|
96
|
+
/** R16 (spec draft.2) — notice rows; provenance facet shows under debug. */
|
|
97
|
+
notice: {
|
|
98
|
+
show: boolean;
|
|
99
|
+
};
|
|
96
100
|
/** R14. */
|
|
97
101
|
compaction: {
|
|
98
102
|
show: boolean;
|
package/dist/policy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtF,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,OAAO,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU;IACV,WAAW,EAAE;QAAE,eAAe,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1C,+EAA+E;IAC/E,IAAI,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5B,UAAU;IACV,SAAS,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,iBAAiB,EAAE,OAAO,CAAA;KAAE,CAAC;IACzD,UAAU;IACV,IAAI,EAAE;QACJ,eAAe,EAAE,OAAO,CAAC;QACzB,WAAW,EAAE,OAAO,CAAC;QACrB,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;KAC7C,CAAC;IACF,iEAAiE;IACjE,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAA;KAAE,CAAC;IACzC,UAAU;IACV,UAAU,EAAE;QACV,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,OAAO,CAAC;QACrB,eAAe,EAAE,OAAO,CAAC;QACzB,+EAA+E;QAC/E,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,kEAAkE;IAClE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,UAAU;IACV,KAAK,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IACxD,UAAU;IACV,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IACxC,UAAU;IACV,SAAS,EAAE;QAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAC;IACvC,WAAW;IACX,MAAM,EAAE;QAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/D;;;;;;;;;;;OAWG;IACH,KAAK,EAAE;QACL,QAAQ,EAAE,OAAO,CAAC;QAClB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7C,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC;KAC1C,CAAC;IACF,oFAAoF;IACpF,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,WAAW;IACX,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,WAAW;IACX,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAEtF,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,OAAO,EAAE,WAAW,CAAC;IACrB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,UAAU;IACV,WAAW,EAAE;QAAE,eAAe,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1C,+EAA+E;IAC/E,IAAI,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IAC5B,UAAU;IACV,SAAS,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,iBAAiB,EAAE,OAAO,CAAA;KAAE,CAAC;IACzD,UAAU;IACV,IAAI,EAAE;QACJ,eAAe,EAAE,OAAO,CAAC;QACzB,WAAW,EAAE,OAAO,CAAC;QACrB,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;KAC7C,CAAC;IACF,iEAAiE;IACjE,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAA;KAAE,CAAC;IACzC,UAAU;IACV,UAAU,EAAE;QACV,MAAM,EAAE,MAAM,CAAC;QACf,WAAW,EAAE,OAAO,CAAC;QACrB,eAAe,EAAE,OAAO,CAAC;QACzB,+EAA+E;QAC/E,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,kEAAkE;IAClE,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5B,UAAU;IACV,KAAK,EAAE;QAAE,iBAAiB,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IACxD,UAAU;IACV,IAAI,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IACxC,UAAU;IACV,SAAS,EAAE;QAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAAA;KAAE,CAAC;IACvC,WAAW;IACX,MAAM,EAAE;QAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC;QAAC,UAAU,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/D;;;;;;;;;;;OAWG;IACH,KAAK,EAAE;QACL,QAAQ,EAAE,OAAO,CAAC;QAClB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;QAC7C,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,KAAK,CAAC;KAC1C,CAAC;IACF,oFAAoF;IACpF,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,4EAA4E;IAC5E,MAAM,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IAC1B,WAAW;IACX,UAAU,EAAE;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE,CAAC;IAC9B,WAAW;IACX,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AAoDD,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAElF;AAED,8EAA8E;AAC9E,wBAAgB,WAAW,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,gBAAgB,CAcnF"}
|
package/dist/policy.js
CHANGED
|
@@ -27,6 +27,7 @@ function withOverrides(base, overrides) {
|
|
|
27
27
|
prompt: { ...base.prompt, ...(overrides.prompt ?? {}) },
|
|
28
28
|
error: { ...base.error, ...(overrides.error ?? {}) },
|
|
29
29
|
status: { ...base.status, ...(overrides.status ?? {}) },
|
|
30
|
+
notice: { ...base.notice, ...(overrides.notice ?? {}) },
|
|
30
31
|
compaction: { ...base.compaction, ...(overrides.compaction ?? {}) },
|
|
31
32
|
unknown: { ...base.unknown, ...(overrides.unknown ?? {}) },
|
|
32
33
|
};
|
|
@@ -46,6 +47,7 @@ function calmBase() {
|
|
|
46
47
|
media: { inlineImageCapRem: 20, chipOnly: false },
|
|
47
48
|
code: { capRem: 16, wrap: false },
|
|
48
49
|
citations: { style: "chips" },
|
|
50
|
+
notice: { show: true },
|
|
49
51
|
prompt: { placement: "inline", rawPayload: false },
|
|
50
52
|
error: { verbatim: false, copyByCode: {}, verbatimCodes: [] },
|
|
51
53
|
status: { wakingMs: 2500, longStartMs: 15_000 },
|
|
@@ -22,7 +22,7 @@ import { type ComponentType, type ReactNode } from "react";
|
|
|
22
22
|
import { type GuueyViewProps } from "@guuey/mcp-apps-host/react";
|
|
23
23
|
import type { ResolvedViewMount, ViewHostPhase } from "@guuey/mcp-apps-host";
|
|
24
24
|
import type { ChatStrings } from "../strings.js";
|
|
25
|
-
import type { CitationsItem, CodeItem, CompactionItem, DataResultItem, DisplayItem, ErrorItem, HistoryBoundaryItem, ItemKey, MediaItem, PromptItem, ReasoningItem, StatusLineItem, ToolGroupItem, ToolItem, UnknownItem, UserMessageItem, TextItem, ViewMountItem } from "../types.js";
|
|
25
|
+
import type { CitationsItem, CodeItem, CompactionItem, DataResultItem, DisplayItem, ErrorItem, HistoryBoundaryItem, ItemKey, MediaItem, NoticeItem, PromptItem, ReasoningItem, StatusLineItem, ToolGroupItem, ToolItem, UnknownItem, UserMessageItem, TextItem, ViewMountItem, ViewRefItem } from "../types.js";
|
|
26
26
|
/** Everything a rendered item may need beyond itself. */
|
|
27
27
|
export interface TranscriptItemContext {
|
|
28
28
|
strings: ChatStrings;
|
|
@@ -30,17 +30,40 @@ export interface TranscriptItemContext {
|
|
|
30
30
|
onToggle: (key: ItemKey) => void;
|
|
31
31
|
/** R0 failed-send retry. */
|
|
32
32
|
onRetry?: (item: UserMessageItem) => void;
|
|
33
|
-
/**
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* R10 prompt actions — the host owns what accept/decline DO. A hitl card
|
|
35
|
+
* with declared grant modes reports the pick as `{ grantModeId }` (spec
|
|
36
|
+
* draft.2); plain accepts stay the `"accept"` string.
|
|
37
|
+
*/
|
|
38
|
+
onPromptAction?: (item: PromptItem, action: "accept" | "decline" | "dismiss" | {
|
|
39
|
+
grantModeId: string;
|
|
40
|
+
}) => void;
|
|
35
41
|
/** R11 action slots (sign-in / upgrade / retry affordances). */
|
|
36
42
|
onErrorAction?: (item: ErrorItem) => void;
|
|
37
43
|
/** R6: locator mounts resolved by `useTranscript` ("expired" = failed). */
|
|
38
44
|
resolvedMounts: ReadonlyMap<ItemKey, ResolvedViewMount | "expired">;
|
|
39
45
|
/** R6: live phase reports wired back into the next plan. */
|
|
40
46
|
onViewPhase: (key: ItemKey, phase: ViewHostPhase) => void;
|
|
41
|
-
/**
|
|
42
|
-
|
|
47
|
+
/**
|
|
48
|
+
* guuey#204: a promoted-view reference chip was activated — the host
|
|
49
|
+
* focuses/reveals its stage (canvas). Absent ⇒ the chip renders as a
|
|
50
|
+
* non-interactive label.
|
|
51
|
+
*/
|
|
52
|
+
onViewRef?: (item: ViewRefItem) => void;
|
|
53
|
+
/**
|
|
54
|
+
* R6 pass-through (sandbox overrides, the two-origin mount, relay hooks
|
|
55
|
+
* — policy-gated by the host). Static, or a FUNCTION of the mount being
|
|
56
|
+
* rendered: view configuration legitimately varies per mount — the
|
|
57
|
+
* relay-page URL picks a per-channel egress grant (`?channel=`), and a
|
|
58
|
+
* `tools/call` hook scopes to the item's persisted locator (guuey#158) —
|
|
59
|
+
* so the function form receives the item and its resolved mount and is
|
|
60
|
+
* called only when something actually mounts. Static keeps working
|
|
61
|
+
* unchanged.
|
|
62
|
+
*/
|
|
63
|
+
viewProps?: ViewSlotProps | ((item: ViewMountItem, mount: ResolvedViewMount) => ViewSlotProps);
|
|
43
64
|
}
|
|
65
|
+
/** The per-view slice of `GuueyViewProps` a transcript may configure. */
|
|
66
|
+
export type ViewSlotProps = Pick<GuueyViewProps, "hostCapabilities" | "hostInfo" | "hostContext" | "onCallTool" | "onReadResource" | "onSizeChanged" | "negotiationTimeoutMs" | "dangerouslyAddSandboxFlags" | "allow" | "sandboxPageUrl" | "autoResize">;
|
|
44
67
|
interface ItemProps<T> {
|
|
45
68
|
item: T;
|
|
46
69
|
ctx: TranscriptItemContext;
|
|
@@ -52,10 +75,22 @@ export declare function DefaultDataResult({ item, ctx }: ItemProps<DataResultIte
|
|
|
52
75
|
export declare function DefaultTool({ item, ctx }: ItemProps<ToolItem>): ReactNode;
|
|
53
76
|
export declare function DefaultToolGroup({ item, ctx }: ItemProps<ToolGroupItem>): ReactNode;
|
|
54
77
|
export declare function DefaultView({ item, ctx }: ItemProps<ViewMountItem>): ReactNode;
|
|
78
|
+
/**
|
|
79
|
+
* guuey#204: the "promote and reference" chip — stands in for the one
|
|
80
|
+
* mount the host's stage shows. A real button when the host wires
|
|
81
|
+
* `onViewRef` (keyboard-accessible for free); a plain label otherwise.
|
|
82
|
+
*/
|
|
83
|
+
export declare function DefaultViewRef({ item, ctx }: ItemProps<ViewRefItem>): ReactNode;
|
|
55
84
|
export declare function DefaultMedia({ item }: ItemProps<MediaItem>): ReactNode;
|
|
56
85
|
export declare function DefaultCode({ item, ctx }: ItemProps<CodeItem>): ReactNode;
|
|
57
86
|
export declare function DefaultCitations({ item, ctx }: ItemProps<CitationsItem>): ReactNode;
|
|
58
87
|
export declare function DefaultPrompt({ item, ctx }: ItemProps<PromptItem>): ReactNode;
|
|
88
|
+
/**
|
|
89
|
+
* A `role:"notice"` session annotation (spec draft.2) — a labeled,
|
|
90
|
+
* non-conversational row that must never read as agent-authored. Calm
|
|
91
|
+
* shows the quiet label; debug appends the provenance facet verbatim.
|
|
92
|
+
*/
|
|
93
|
+
export declare function DefaultNotice({ item, ctx }: ItemProps<NoticeItem>): ReactNode;
|
|
59
94
|
export declare function DefaultError({ item, ctx }: ItemProps<ErrorItem>): ReactNode;
|
|
60
95
|
export declare function DefaultHistoryBoundary({ item }: ItemProps<HistoryBoundaryItem>): ReactNode;
|
|
61
96
|
export declare function DefaultCompaction({ item }: ItemProps<CompactionItem>): ReactNode;
|
|
@@ -70,10 +105,12 @@ export interface TranscriptComponents {
|
|
|
70
105
|
toolGroup: ComponentType<ItemProps<ToolGroupItem>>;
|
|
71
106
|
dataResult: ComponentType<ItemProps<DataResultItem>>;
|
|
72
107
|
view: ComponentType<ItemProps<ViewMountItem>>;
|
|
108
|
+
viewRef: ComponentType<ItemProps<ViewRefItem>>;
|
|
73
109
|
media: ComponentType<ItemProps<MediaItem>>;
|
|
74
110
|
code: ComponentType<ItemProps<CodeItem>>;
|
|
75
111
|
citations: ComponentType<ItemProps<CitationsItem>>;
|
|
76
112
|
prompt: ComponentType<ItemProps<PromptItem>>;
|
|
113
|
+
notice: ComponentType<ItemProps<NoticeItem>>;
|
|
77
114
|
error: ComponentType<ItemProps<ErrorItem>>;
|
|
78
115
|
history: ComponentType<ItemProps<HistoryBoundaryItem>>;
|
|
79
116
|
compaction: ComponentType<ItemProps<CompactionItem>>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/react/components.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EACV,aAAa,EACb,QAAQ,EACR,cAAc,EACd,cAAc,EACd,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,OAAO,EACP,SAAS,EACT,UAAU,EACV,aAAa,EACb,cAAc,EACd,aAAa,EACb,QAAQ,EACR,WAAW,EACX,eAAe,EACf,QAAQ,EACR,aAAa,
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../../src/react/components.tsx"],"names":[],"mappings":"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"}
|
package/dist/react/components.js
CHANGED
|
@@ -98,7 +98,22 @@ export function DefaultView({ item, ctx }) {
|
|
|
98
98
|
// never blank.
|
|
99
99
|
return (_jsx("div", { className: "guuey-chat-view guuey-chat-view-negotiating guuey-chat-shimmer", children: _jsx("p", { role: "status", children: item.label ?? ctx.strings.viewNegotiating }) }));
|
|
100
100
|
}
|
|
101
|
-
|
|
101
|
+
// The function form resolves against the ACTUAL mount (per-channel relay
|
|
102
|
+
// URLs, per-locator action scoping); it runs only when something mounts.
|
|
103
|
+
const viewProps = typeof ctx.viewProps === "function" ? ctx.viewProps(item, mount) : (ctx.viewProps ?? {});
|
|
104
|
+
return (_jsxs("div", { className: "guuey-chat-view", children: [_jsx(GuueyView, { mount: mount, ...viewProps, onPhaseChange: (phase) => ctx.onViewPhase(item.key, phase) }), item.attribution !== null ? (_jsx("p", { className: "guuey-chat-attribution", children: item.attribution })) : null] }));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* guuey#204: the "promote and reference" chip — stands in for the one
|
|
108
|
+
* mount the host's stage shows. A real button when the host wires
|
|
109
|
+
* `onViewRef` (keyboard-accessible for free); a plain label otherwise.
|
|
110
|
+
*/
|
|
111
|
+
export function DefaultViewRef({ item, ctx }) {
|
|
112
|
+
if (ctx.onViewRef === undefined) {
|
|
113
|
+
return (_jsx("p", { className: "guuey-chat-view-ref", role: "note", children: item.label }));
|
|
114
|
+
}
|
|
115
|
+
const onViewRef = ctx.onViewRef;
|
|
116
|
+
return (_jsx("button", { type: "button", className: "guuey-chat-view-ref guuey-chat-view-ref-button", onClick: () => onViewRef(item), children: item.label }));
|
|
102
117
|
}
|
|
103
118
|
// ─── R7 ────────────────────────────────────────────────────────────────────
|
|
104
119
|
/** Inline images allow https URLs and image/* base64 data — nothing else. */
|
|
@@ -160,6 +175,22 @@ export function DefaultPrompt({ item, ctx }) {
|
|
|
160
175
|
}
|
|
161
176
|
wasPending.current = item.state === "pending";
|
|
162
177
|
}, [item.state]);
|
|
178
|
+
if (item.promptKind === "hitl") {
|
|
179
|
+
const s = ctx.strings;
|
|
180
|
+
// Settled records: resolved shows the CHOSEN MODE'S LABEL (ids are
|
|
181
|
+
// echo-only identity — asker-scoped semantics, spec §7); declined is
|
|
182
|
+
// the durable deny. `cancelled` is guuey's re-askable dismissal: it
|
|
183
|
+
// collapses to a record but stays answerable when expanded.
|
|
184
|
+
if (item.state === "resolved" || item.state === "declined") {
|
|
185
|
+
return (_jsx("p", { className: `guuey-chat-prompt-record guuey-chat-prompt-${item.state}`, children: item.state === "resolved"
|
|
186
|
+
? item.chosenModeLabel !== null
|
|
187
|
+
? s.promptAnsweredWith(item.chosenModeLabel)
|
|
188
|
+
: s.promptAccept
|
|
189
|
+
: s.promptDeclinedRecord }));
|
|
190
|
+
}
|
|
191
|
+
const answerable = item.state === "pending" || (item.state === "cancelled" && item.expanded);
|
|
192
|
+
return (_jsxs("div", { className: "guuey-chat-prompt", role: "group", children: [item.state === "cancelled" && (_jsx("button", { type: "button", className: "guuey-chat-prompt-record guuey-chat-prompt-cancelled", "aria-expanded": item.expanded, onClick: () => ctx.onToggle(item.key), children: s.promptDismissed })), answerable && (_jsxs(_Fragment, { children: [item.message !== null && _jsx("p", { className: "guuey-chat-prompt-ask", children: item.message }), _jsxs("div", { className: "guuey-chat-prompt-actions", children: [item.grantModes.length === 0 ? (_jsx("button", { ref: firstAction, type: "button", className: "guuey-chat-prompt-accept", onClick: () => ctx.onPromptAction?.(item, "accept"), children: s.promptAccept })) : (item.grantModes.map((mode, i) => (_jsx("button", { ref: i === 0 ? firstAction : undefined, type: "button", className: "guuey-chat-prompt-accept", title: mode.description, onClick: () => ctx.onPromptAction?.(item, { grantModeId: mode.id }), children: mode.label ?? mode.id }, mode.id)))), _jsx("button", { type: "button", onClick: () => ctx.onPromptAction?.(item, "decline"), children: s.promptDecline })] })] }))] }));
|
|
193
|
+
}
|
|
163
194
|
if (item.state !== "pending") {
|
|
164
195
|
return (_jsxs("p", { className: `guuey-chat-prompt-record guuey-chat-prompt-${item.state}`, children: [item.promptKind, ": ", item.state] }));
|
|
165
196
|
}
|
|
@@ -167,6 +198,15 @@ export function DefaultPrompt({ item, ctx }) {
|
|
|
167
198
|
? `${item.appId} requests ${item.requested} access`
|
|
168
199
|
: `Link your account to ${item.appId}` }), _jsxs("div", { className: "guuey-chat-prompt-actions", children: [_jsx("button", { ref: firstAction, type: "button", className: "guuey-chat-prompt-accept", onClick: () => ctx.onPromptAction?.(item, "accept"), children: "Allow" }), _jsx("button", { type: "button", onClick: () => ctx.onPromptAction?.(item, "decline"), children: "Decline" })] }), item.raw !== null ? (_jsx("pre", { className: "guuey-chat-prompt-raw", children: JSON.stringify(item.raw, null, 2) })) : null] }));
|
|
169
200
|
}
|
|
201
|
+
// ─── R16 ──────────────────────────────────────────────────────────────────
|
|
202
|
+
/**
|
|
203
|
+
* A `role:"notice"` session annotation (spec draft.2) — a labeled,
|
|
204
|
+
* non-conversational row that must never read as agent-authored. Calm
|
|
205
|
+
* shows the quiet label; debug appends the provenance facet verbatim.
|
|
206
|
+
*/
|
|
207
|
+
export function DefaultNotice({ item, ctx }) {
|
|
208
|
+
return (_jsxs("div", { className: "guuey-chat-notice", role: "note", children: [_jsxs("span", { className: "guuey-chat-notice-label", children: [ctx.strings.noticeLabel, item.sourceLabel !== null ? ` · ${item.sourceLabel}` : ""] }), item.text !== "" && _jsx("span", { className: "guuey-chat-notice-text", children: item.text })] }));
|
|
209
|
+
}
|
|
170
210
|
// ─── R11 ───────────────────────────────────────────────────────────────────
|
|
171
211
|
export function DefaultError({ item, ctx }) {
|
|
172
212
|
return (_jsxs("div", { className: `guuey-chat-error guuey-chat-error-${item.family}`, role: "alert", children: [_jsx("p", { children: item.copy }), ctx.onErrorAction !== undefined && (item.family === "transient" || item.family === "auth") ? (_jsx("button", { type: "button", className: "guuey-chat-error-action", onClick: () => ctx.onErrorAction?.(item), children: item.family === "auth" ? ctx.strings.errorAuth : ctx.strings.userRetry })) : null, item.verbatim !== null ? _jsx("pre", { className: "guuey-chat-error-verbatim", children: item.verbatim }) : null] }));
|
|
@@ -193,10 +233,12 @@ export const defaultTranscriptComponents = {
|
|
|
193
233
|
toolGroup: DefaultToolGroup,
|
|
194
234
|
dataResult: DefaultDataResult,
|
|
195
235
|
view: DefaultView,
|
|
236
|
+
viewRef: DefaultViewRef,
|
|
196
237
|
media: DefaultMedia,
|
|
197
238
|
code: DefaultCode,
|
|
198
239
|
citations: DefaultCitations,
|
|
199
240
|
prompt: DefaultPrompt,
|
|
241
|
+
notice: DefaultNotice,
|
|
200
242
|
error: DefaultError,
|
|
201
243
|
history: DefaultHistoryBoundary,
|
|
202
244
|
compaction: DefaultCompaction,
|
|
@@ -234,6 +276,10 @@ export function renderItem(item, components, ctx) {
|
|
|
234
276
|
const C = components.view;
|
|
235
277
|
return _jsx(C, { item: item, ctx: ctx }, item.key);
|
|
236
278
|
}
|
|
279
|
+
case "viewRef": {
|
|
280
|
+
const C = components.viewRef;
|
|
281
|
+
return _jsx(C, { item: item, ctx: ctx }, item.key);
|
|
282
|
+
}
|
|
237
283
|
case "media": {
|
|
238
284
|
const C = components.media;
|
|
239
285
|
return _jsx(C, { item: item, ctx: ctx }, item.key);
|
|
@@ -250,6 +296,10 @@ export function renderItem(item, components, ctx) {
|
|
|
250
296
|
const C = components.prompt;
|
|
251
297
|
return _jsx(C, { item: item, ctx: ctx }, item.key);
|
|
252
298
|
}
|
|
299
|
+
case "notice": {
|
|
300
|
+
const C = components.notice;
|
|
301
|
+
return _jsx(C, { item: item, ctx: ctx }, item.key);
|
|
302
|
+
}
|
|
253
303
|
case "error": {
|
|
254
304
|
const C = components.error;
|
|
255
305
|
return _jsx(C, { item: item, ctx: ctx }, item.key);
|
|
@@ -31,17 +31,59 @@
|
|
|
31
31
|
* adapter (e.g. `createWebAdapters({ apiBaseUrl, … })`) and a persisted
|
|
32
32
|
* threadId rehydrates on mount — text transcript + persisted cards, which
|
|
33
33
|
* mount through the same R6 path as live views. Nothing here to configure.
|
|
34
|
+
*
|
|
35
|
+
* ## The imperative seam (guuey#210)
|
|
36
|
+
*
|
|
37
|
+
* Suggested-prompt chips and other host-driven sends stay on the
|
|
38
|
+
* batteries-included path via {@link GuueyChatHandle} — a ref handle
|
|
39
|
+
* (`forwardRef`) and/or the `onReady` callback, ONE stable object for the
|
|
40
|
+
* component's whole life. `send` runs through exactly the Send button's
|
|
41
|
+
* gate (never bypasses it; the typed draft is left untouched — a chip send
|
|
42
|
+
* must not eat a half-typed message); `prefill` mirrors the widget's
|
|
43
|
+
* staged-composer semantics (append joins with a space, never clobbers).
|
|
44
|
+
* Web-only for now: the native tier ships `<NativeTranscript>` without a
|
|
45
|
+
* native GuueyChat, so there is no native surface to put a handle on yet.
|
|
34
46
|
*/
|
|
35
|
-
import { type CSSProperties
|
|
47
|
+
import { type CSSProperties } from "react";
|
|
36
48
|
import { type AgentInvokeAdapters } from "@guuey/agent-client";
|
|
49
|
+
import type { AgHitlAnswer, AgPausedAsk } from "@silverprotocol/core";
|
|
37
50
|
import type { UiResourceReader } from "@guuey/mcp-apps-host";
|
|
38
51
|
import { type TranscriptPolicy } from "../policy.js";
|
|
39
52
|
import { type ChatStrings } from "../strings.js";
|
|
40
53
|
import { type GuueyChatTheme } from "../theme.js";
|
|
41
|
-
import type { ErrorItem, PromptItem } from "../types.js";
|
|
54
|
+
import type { ChatDebugEvent, ErrorItem, PromptItem } from "../types.js";
|
|
42
55
|
import type { ThemeMode } from "./theme-css.js";
|
|
43
56
|
import { type TranscriptWindowing } from "./transcript.js";
|
|
44
57
|
import type { TranscriptComponents, TranscriptItemContext } from "./components.js";
|
|
58
|
+
/**
|
|
59
|
+
* The imperative seam (guuey#210): programmatic send/prefill/focus for
|
|
60
|
+
* hosts that stay on the batteries-included path (suggested-prompt chips
|
|
61
|
+
* being the filing use case). Reach it via `ref` or `onReady` — both
|
|
62
|
+
* deliver the SAME stable object, valid for the component's whole life.
|
|
63
|
+
*/
|
|
64
|
+
export interface GuueyChatHandle {
|
|
65
|
+
/**
|
|
66
|
+
* Send `text` through exactly the Send button's gate: returns `false`
|
|
67
|
+
* and does nothing when chat is unavailable (`endpointUrl === null`), a
|
|
68
|
+
* turn is in flight, or the text is blank — it NEVER bypasses the
|
|
69
|
+
* composer's rules. The typed draft is left untouched (a programmatic
|
|
70
|
+
* send must not eat a half-typed message). Failures surface the same
|
|
71
|
+
* way a composer send's do (the hook's `error` / R0 failed-send).
|
|
72
|
+
*/
|
|
73
|
+
send(text: string): boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Put `text` into the composer draft. `append: true` joins onto a
|
|
76
|
+
* non-empty draft with a single space (the widget's staged-composer
|
|
77
|
+
* semantic — never clobbers); default replaces. Focuses the input
|
|
78
|
+
* unless `focus: false`.
|
|
79
|
+
*/
|
|
80
|
+
prefill(text: string, opts?: {
|
|
81
|
+
focus?: boolean;
|
|
82
|
+
append?: boolean;
|
|
83
|
+
}): void;
|
|
84
|
+
/** Focus the composer input. */
|
|
85
|
+
focusComposer(): void;
|
|
86
|
+
}
|
|
45
87
|
export interface GuueyChatProps {
|
|
46
88
|
/** Pod base URL (with or without `/agent/invoke`). `null` disables chat. */
|
|
47
89
|
endpointUrl: string | null;
|
|
@@ -67,6 +109,8 @@ export interface GuueyChatProps {
|
|
|
67
109
|
window?: TranscriptWindowing | false;
|
|
68
110
|
/** R6 locator resolution (history cards). See `useTranscript`. */
|
|
69
111
|
reader?: UiResourceReader;
|
|
112
|
+
/** The debug sink (spec §5) — fires only under the debug policy. */
|
|
113
|
+
onDebugEvent?: (event: ChatDebugEvent) => void;
|
|
70
114
|
/** R6 pass-through (relay hook, sandbox page/flags, host context…). */
|
|
71
115
|
viewProps?: TranscriptItemContext["viewProps"];
|
|
72
116
|
/**
|
|
@@ -74,11 +118,25 @@ export interface GuueyChatProps {
|
|
|
74
118
|
* The transcript record moves regardless; without a handler the prompt
|
|
75
119
|
* card is record-only.
|
|
76
120
|
*/
|
|
77
|
-
onPromptAction?: (item: PromptItem, action: "accept" | "decline" | "dismiss"
|
|
121
|
+
onPromptAction?: (item: PromptItem, action: "accept" | "decline" | "dismiss" | {
|
|
122
|
+
grantModeId: string;
|
|
123
|
+
}) => void;
|
|
124
|
+
/**
|
|
125
|
+
* Receives the VALIDATED wire answer for an AgJSON HITL ask (spec
|
|
126
|
+
* draft.2) — the host owns delivering it (the kit has no answer
|
|
127
|
+
* transport). Fired after the transcript record moves.
|
|
128
|
+
*/
|
|
129
|
+
onHitlAnswer?: (answer: AgHitlAnswer, ask: AgPausedAsk) => void;
|
|
78
130
|
/** R11 action slot (sign-in / retry affordances). */
|
|
79
131
|
onErrorAction?: (item: ErrorItem) => void;
|
|
132
|
+
/**
|
|
133
|
+
* Callback route to the {@link GuueyChatHandle} for hosts that prefer
|
|
134
|
+
* wiring over refs. Fires ONCE per component instance, on mount, with
|
|
135
|
+
* the same stable handle the ref receives.
|
|
136
|
+
*/
|
|
137
|
+
onReady?: (handle: GuueyChatHandle) => void;
|
|
80
138
|
className?: string;
|
|
81
139
|
style?: CSSProperties;
|
|
82
140
|
}
|
|
83
|
-
export declare
|
|
141
|
+
export declare const GuueyChat: import("react").ForwardRefExoticComponent<GuueyChatProps & import("react").RefAttributes<GuueyChatHandle>>;
|
|
84
142
|
//# sourceMappingURL=guuey-chat.d.ts.map
|