@flamingo-stack/openframe-frontend-core 0.0.532-snapshot.20260811155109 → 0.0.532
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/chat-protocol/decode.d.ts +9 -1
- package/dist/chat-protocol/decode.d.ts.map +1 -1
- package/dist/chat-protocol/events.d.ts +0 -35
- package/dist/chat-protocol/events.d.ts.map +1 -1
- package/dist/chat-protocol/index.cjs +3 -72
- package/dist/chat-protocol/index.cjs.map +1 -1
- package/dist/chat-protocol/index.d.ts +0 -1
- package/dist/chat-protocol/index.d.ts.map +1 -1
- package/dist/chat-protocol/index.js +4 -67
- package/dist/chat-protocol/index.js.map +1 -1
- package/dist/chat-protocol/nats-decoder.d.ts +0 -41
- package/dist/chat-protocol/nats-decoder.d.ts.map +1 -1
- package/dist/{chunk-OLOKQQAP.cjs → chunk-2MBS3YEY.cjs} +5 -5
- package/dist/{chunk-OLOKQQAP.cjs.map → chunk-2MBS3YEY.cjs.map} +1 -1
- package/dist/{chunk-DFQLUK75.cjs → chunk-2QP67D2L.cjs} +3 -3
- package/dist/{chunk-DFQLUK75.cjs.map → chunk-2QP67D2L.cjs.map} +1 -1
- package/dist/{chunk-6SMLYZLH.js → chunk-3G7FDE5E.js} +4 -4
- package/dist/{chunk-J4BE4FIR.cjs → chunk-4GL2XJ5C.cjs} +4 -4
- package/dist/{chunk-J4BE4FIR.cjs.map → chunk-4GL2XJ5C.cjs.map} +1 -1
- package/dist/{chunk-LE3BJ5H2.js → chunk-5W3RCZIK.js} +2 -2
- package/dist/{chunk-MVGL5NNJ.js → chunk-65NR333L.js} +2 -2
- package/dist/{chunk-6W3ULZ4X.js → chunk-7SGBF2I2.js} +6 -6
- package/dist/{chunk-6YXN5RHW.js → chunk-ALXLWF75.js} +2 -2
- package/dist/{chunk-5U67WTAS.js → chunk-AZBS4PZG.js} +2 -2
- package/dist/{chunk-4QKXNWH5.js → chunk-ECR37JHH.js} +2 -2
- package/dist/{chunk-ENPGPZIB.cjs → chunk-ETF2QXXU.cjs} +61 -61
- package/dist/{chunk-ENPGPZIB.cjs.map → chunk-ETF2QXXU.cjs.map} +1 -1
- package/dist/{chunk-UPHN2VRZ.cjs → chunk-GVLA2BPW.cjs} +117 -259
- package/dist/chunk-GVLA2BPW.cjs.map +1 -0
- package/dist/{chunk-4ZRHVOEB.cjs → chunk-GWFC3NE5.cjs} +31 -31
- package/dist/{chunk-4ZRHVOEB.cjs.map → chunk-GWFC3NE5.cjs.map} +1 -1
- package/dist/{chunk-GNOK5J34.cjs → chunk-HJDCDOJM.cjs} +37 -37
- package/dist/{chunk-GNOK5J34.cjs.map → chunk-HJDCDOJM.cjs.map} +1 -1
- package/dist/{chunk-JDW2IL7A.cjs → chunk-HXHA3DCI.cjs} +11 -11
- package/dist/{chunk-JDW2IL7A.cjs.map → chunk-HXHA3DCI.cjs.map} +1 -1
- package/dist/{chunk-XN4JKIJY.js → chunk-IZOGFZ7N.js} +2 -2
- package/dist/{chunk-Z3NOI7X7.cjs → chunk-JZ5XDZYD.cjs} +26 -26
- package/dist/{chunk-Z3NOI7X7.cjs.map → chunk-JZ5XDZYD.cjs.map} +1 -1
- package/dist/{chunk-YLB6XXO6.js → chunk-KYQZBQYV.js} +2 -2
- package/dist/{chunk-RKITTO5V.cjs → chunk-L6EKEYF7.cjs} +14 -14
- package/dist/{chunk-RKITTO5V.cjs.map → chunk-L6EKEYF7.cjs.map} +1 -1
- package/dist/{chunk-NAV4FRNL.cjs → chunk-LYWSHNK4.cjs} +26 -26
- package/dist/{chunk-NAV4FRNL.cjs.map → chunk-LYWSHNK4.cjs.map} +1 -1
- package/dist/{chunk-46FKXLNE.js → chunk-OAEJWP7H.js} +2 -2
- package/dist/{chunk-2MYDGLJS.cjs → chunk-QEMI34VA.cjs} +87 -87
- package/dist/{chunk-2MYDGLJS.cjs.map → chunk-QEMI34VA.cjs.map} +1 -1
- package/dist/{chunk-QZ2NAPLF.cjs → chunk-QYNLVIGQ.cjs} +9 -9
- package/dist/{chunk-QZ2NAPLF.cjs.map → chunk-QYNLVIGQ.cjs.map} +1 -1
- package/dist/{chunk-KMB66NYX.cjs → chunk-TMZS63G2.cjs} +7 -7
- package/dist/{chunk-KMB66NYX.cjs.map → chunk-TMZS63G2.cjs.map} +1 -1
- package/dist/{chunk-2TUOBFPK.js → chunk-TQ7EPKKO.js} +2 -2
- package/dist/{chunk-U555TMPC.js → chunk-UP4RA54U.js} +5 -5
- package/dist/{chunk-LIUARTOZ.js → chunk-WINT757E.js} +64 -206
- package/dist/chunk-WINT757E.js.map +1 -0
- package/dist/{chunk-2XGHEJZK.js → chunk-XBYEPSNZ.js} +4 -4
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chat/embeddable-chat.d.ts +0 -13
- package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-sse-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -10
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +1 -9
- package/dist/components/chat/stream/chat-stream-reducer.d.ts +0 -9
- package/dist/components/chat/stream/chat-stream-reducer.d.ts.map +1 -1
- package/dist/components/chat/types/message.types.d.ts +0 -15
- package/dist/components/chat/types/message.types.d.ts.map +1 -1
- package/dist/components/chat/types/network.types.d.ts +0 -4
- package/dist/components/chat/types/network.types.d.ts.map +1 -1
- package/dist/components/chat/types/processing.types.d.ts +1 -7
- package/dist/components/chat/types/processing.types.d.ts.map +1 -1
- package/dist/components/chat/utils/index.d.ts +0 -1
- package/dist/components/chat/utils/index.d.ts.map +1 -1
- package/dist/components/chat/utils/message-segment-accumulator.d.ts +3 -25
- package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/help-center-pages/index.cjs +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +132 -140
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +11 -19
- package/dist/components/index.js.map +1 -1
- package/dist/components/meeting-scheduler/index.cjs +34 -34
- package/dist/components/meeting-scheduler/index.js +3 -3
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/index.cjs +2 -10
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +1 -9
- package/dist/index.cjs +2 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -9
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.js.map +1 -1
- package/package.json +1 -1
- package/src/chat-protocol/__tests__/__snapshots__/nats-decoder-golden.test.ts.snap +0 -70
- package/src/chat-protocol/__tests__/nats-decoder-golden.test.ts +1 -108
- package/src/chat-protocol/decode.ts +153 -7
- package/src/chat-protocol/events.ts +0 -40
- package/src/chat-protocol/index.ts +0 -3
- package/src/chat-protocol/nats-decoder.ts +3 -111
- package/src/components/chat/embeddable-chat.tsx +0 -18
- package/src/components/chat/hooks/use-sse-chat-adapter.ts +16 -7
- package/src/components/chat/stream/chat-stream-reducer.ts +3 -49
- package/src/components/chat/types/message.types.ts +0 -15
- package/src/components/chat/types/network.types.ts +0 -4
- package/src/components/chat/types/processing.types.ts +1 -12
- package/src/components/chat/utils/__tests__/process-historical-messages-approvals.test.ts +0 -92
- package/src/components/chat/utils/index.ts +0 -9
- package/src/components/chat/utils/message-segment-accumulator.ts +32 -62
- package/src/components/chat/utils/process-historical-messages.ts +6 -40
- package/dist/chat-protocol/confirm-tool.d.ts +0 -50
- package/dist/chat-protocol/confirm-tool.d.ts.map +0 -1
- package/dist/chat-protocol/leading-frames.d.ts +0 -38
- package/dist/chat-protocol/leading-frames.d.ts.map +0 -1
- package/dist/chunk-LIUARTOZ.js.map +0 -1
- package/dist/chunk-UPHN2VRZ.cjs.map +0 -1
- package/dist/components/chat/utils/approval-display.d.ts +0 -49
- package/dist/components/chat/utils/approval-display.d.ts.map +0 -1
- package/src/chat-protocol/confirm-tool.ts +0 -67
- package/src/chat-protocol/leading-frames.ts +0 -175
- package/src/components/chat/utils/approval-display.ts +0 -70
- /package/dist/{chunk-6SMLYZLH.js.map → chunk-3G7FDE5E.js.map} +0 -0
- /package/dist/{chunk-LE3BJ5H2.js.map → chunk-5W3RCZIK.js.map} +0 -0
- /package/dist/{chunk-MVGL5NNJ.js.map → chunk-65NR333L.js.map} +0 -0
- /package/dist/{chunk-6W3ULZ4X.js.map → chunk-7SGBF2I2.js.map} +0 -0
- /package/dist/{chunk-6YXN5RHW.js.map → chunk-ALXLWF75.js.map} +0 -0
- /package/dist/{chunk-5U67WTAS.js.map → chunk-AZBS4PZG.js.map} +0 -0
- /package/dist/{chunk-4QKXNWH5.js.map → chunk-ECR37JHH.js.map} +0 -0
- /package/dist/{chunk-XN4JKIJY.js.map → chunk-IZOGFZ7N.js.map} +0 -0
- /package/dist/{chunk-YLB6XXO6.js.map → chunk-KYQZBQYV.js.map} +0 -0
- /package/dist/{chunk-46FKXLNE.js.map → chunk-OAEJWP7H.js.map} +0 -0
- /package/dist/{chunk-2TUOBFPK.js.map → chunk-TQ7EPKKO.js.map} +0 -0
- /package/dist/{chunk-U555TMPC.js.map → chunk-UP4RA54U.js.map} +0 -0
- /package/dist/{chunk-2XGHEJZK.js.map → chunk-XBYEPSNZ.js.map} +0 -0
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WHERE an approval card renders — the one rule, read by every path that turns
|
|
3
|
-
* an approval into segments.
|
|
4
|
-
*
|
|
5
|
-
* There are three such paths and they must agree: the NATS kernel (live chunks),
|
|
6
|
-
* the SSE kernel, and the history replay that rebuilds a dialog after a reload.
|
|
7
|
-
* When the rule lived only in the live kernel, a Product Guide card rendered
|
|
8
|
-
* inline while streaming and then moved into the escalation treatment on the
|
|
9
|
-
* next page load — same card, two behaviors, and its buttons pointed at the
|
|
10
|
-
* wrong backend once it moved.
|
|
11
|
-
*
|
|
12
|
-
* The rule itself: a card is gated on approval TIER (`displayApprovalTypes`,
|
|
13
|
-
* the agent's own privilege model) UNLESS it came from the Product Guide, whose
|
|
14
|
-
* proposals are typed by TOOL and are resolved through the hub's confirm route.
|
|
15
|
-
* A hub proposal has no tier to gate on, so tier-gating one means escalating it
|
|
16
|
-
* to a human who has no way to act on it.
|
|
17
|
-
*/
|
|
18
|
-
import type { GuideOrigin } from '../../../chat-protocol/events';
|
|
19
|
-
import type { MessageSegment } from '../types/message.types';
|
|
20
|
-
/** Anything carrying the optional `origin` marker: a stream event, or the
|
|
21
|
-
* `data` of a rendered segment. */
|
|
22
|
-
interface OriginBearing {
|
|
23
|
-
origin?: GuideOrigin | string;
|
|
24
|
-
}
|
|
25
|
-
/** True when this approval was minted by the Product Guide (the hub) rather
|
|
26
|
-
* than by the agent's own tool-approval tiering. */
|
|
27
|
-
export declare function isGuideApproval(source: OriginBearing | null | undefined): boolean;
|
|
28
|
-
/** The marker to stamp onto a built segment, or undefined for agent approvals.
|
|
29
|
-
* Keeps `origin` out of segment data unless it means something. */
|
|
30
|
-
export declare function guideApprovalOrigin(source: OriginBearing | null | undefined): GuideOrigin | undefined;
|
|
31
|
-
/**
|
|
32
|
-
* Does this approval render inline in its turn (true), or take the consumer's
|
|
33
|
-
* escalation treatment (false)?
|
|
34
|
-
*
|
|
35
|
-
* `displayApprovalTypes` undefined means "no tier gate configured" and every
|
|
36
|
-
* agent approval displays — the pre-existing history-replay default, preserved
|
|
37
|
-
* here so both kernels can share one predicate.
|
|
38
|
-
*/
|
|
39
|
-
export declare function approvalDisplaysInline(source: OriginBearing | null | undefined, approvalType: string, displayApprovalTypes?: readonly string[]): boolean;
|
|
40
|
-
/**
|
|
41
|
-
* True for a rendered segment that holds a Product Guide card (single or batch).
|
|
42
|
-
*
|
|
43
|
-
* Consumers use it to keep such a card in the message flow, where the hub's own
|
|
44
|
-
* chat puts it, instead of lifting it into their sticky pending-approvals
|
|
45
|
-
* footer — and to route its buttons to the hub rather than to the agent.
|
|
46
|
-
*/
|
|
47
|
-
export declare function isGuideApprovalSegment(segment: MessageSegment): boolean;
|
|
48
|
-
export {};
|
|
49
|
-
//# sourceMappingURL=approval-display.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"approval-display.d.ts","sourceRoot":"","sources":["../../../../src/components/chat/utils/approval-display.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAEhE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5D;oCACoC;AACpC,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,WAAW,GAAG,MAAM,CAAA;CAC9B;AAED;qDACqD;AACrD,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEjF;AAED;oEACoE;AACpE,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,GACvC,WAAW,GAAG,SAAS,CAEzB;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,aAAa,GAAG,IAAI,GAAG,SAAS,EACxC,YAAY,EAAE,MAAM,EACpB,oBAAoB,CAAC,EAAE,SAAS,MAAM,EAAE,GACvC,OAAO,CAGT;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAGvE"}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The hub's confirm-tool contract — request shape and error envelope.
|
|
3
|
-
*
|
|
4
|
-
* Resolving a Product Guide proposal is a POST to `endpoints.approvalToolUrl`
|
|
5
|
-
* whose response is an ordinary guide stream (a `decision_resolved` frame, then
|
|
6
|
-
* the hub's auto-continuation). Two callers make that call today: the SSE chat
|
|
7
|
-
* adapter, and any host replaying the same route into a different transport's
|
|
8
|
-
* conversation (the product app resolves guide cards inside a NATS Mingo
|
|
9
|
-
* dialog). They MUST send byte-identical bodies — a proposal is single-use, so a
|
|
10
|
-
* caller that drifts on a field name does not degrade, it fails the write — and
|
|
11
|
-
* they must surface the same server copy, because the hub's errors are written
|
|
12
|
-
* for the end user ("This approval expired — ask again to get a fresh one").
|
|
13
|
-
*
|
|
14
|
-
* Hence both live here rather than at either call site.
|
|
15
|
-
*
|
|
16
|
-
* Server-safe: no React, no browser APIs.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/** What the user did with the card. */
|
|
20
|
-
export type ApprovalToolAction = 'approve' | 'reject'
|
|
21
|
-
|
|
22
|
-
/** Client-side shape of a confirm; `buildConfirmToolBody` renames it to the
|
|
23
|
-
* wire's own casing so no caller hand-writes `proposal_id`. */
|
|
24
|
-
export interface ConfirmToolRequest {
|
|
25
|
-
/** The hub-minted proposal id carried by the card. */
|
|
26
|
-
proposalId: string
|
|
27
|
-
action: ApprovalToolAction
|
|
28
|
-
/**
|
|
29
|
-
* The hub's conversation id, quoted back verbatim. The hub rejects a confirm
|
|
30
|
-
* without it: a proposal only means something inside the conversation that
|
|
31
|
-
* minted it.
|
|
32
|
-
*/
|
|
33
|
-
conversationId: string | null | undefined
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Build the confirm-tool request body. The ONE place that knows the wire
|
|
37
|
-
* spells the id `proposal_id` while everything else is camelCase. */
|
|
38
|
-
export function buildConfirmToolBody(request: ConfirmToolRequest): Record<string, unknown> {
|
|
39
|
-
return {
|
|
40
|
-
proposal_id: request.proposalId,
|
|
41
|
-
action: request.action,
|
|
42
|
-
conversationId: request.conversationId,
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Pull the user-facing copy out of a failed chat/confirm response.
|
|
48
|
-
*
|
|
49
|
-
* The route-base envelope is `{error, code}`; `error` is written for the end
|
|
50
|
-
* user, so it beats any status-code copy the client could invent. Returns null
|
|
51
|
-
* when the body is not that envelope (HTML error page, empty body, gateway
|
|
52
|
-
* response) — the caller then supplies its own generic line.
|
|
53
|
-
*
|
|
54
|
-
* Consumes the body: call it once, on a response you have already decided is a
|
|
55
|
-
* failure.
|
|
56
|
-
*/
|
|
57
|
-
export async function readServerErrorMessage(response: {
|
|
58
|
-
json: () => Promise<unknown>
|
|
59
|
-
}): Promise<string | null> {
|
|
60
|
-
try {
|
|
61
|
-
const body = (await response.json()) as { error?: unknown } | null
|
|
62
|
-
if (typeof body?.error === 'string' && body.error.length > 0) return body.error
|
|
63
|
-
} catch {
|
|
64
|
-
/* non-JSON error body — the caller falls through to its generic copy */
|
|
65
|
-
}
|
|
66
|
-
return null
|
|
67
|
-
}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Leading-frame → `ChatStreamEvent` table — the ONE mapping both transports read.
|
|
3
|
-
*
|
|
4
|
-
* The SSE decoder (`./decode.ts`) reaches it while walking the hub's byte
|
|
5
|
-
* framing. The NATS decoder (`./nats-decoder.ts`) reaches it for `GUIDE` chunks
|
|
6
|
-
* carrying a `payload`: the saas-ai-agent re-streams the Product Guide's hub
|
|
7
|
-
* frames VERBATIM into the Mingo chunk stream (`GuideStreamingService`), so the
|
|
8
|
-
* bytes a guide answer is made of are the same frames on both transports — only
|
|
9
|
-
* the envelope differs. Decoding them twice would drift the moment the hub adds
|
|
10
|
-
* a frame kind, which is why this table lives outside either decoder.
|
|
11
|
-
*
|
|
12
|
-
* The NATS side does NOT take every event this table can produce; see
|
|
13
|
-
* `guideFrameEvent` in `./nats-decoder.ts` for which ones cross over and why.
|
|
14
|
-
*
|
|
15
|
-
* Server-safe: no React, no browser APIs.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import type { ChatStreamEvent } from './events'
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Escape `<` so markdown renderers that pass HTML through (rehypeRaw)
|
|
22
|
-
* don't treat XML-like tokens in Claude's thinking output as elements.
|
|
23
|
-
* `<` → `<` preserves the visible character without breaking
|
|
24
|
-
* blockquote `>` markers. Per-character, so it distributes over
|
|
25
|
-
* concatenation: escape(a + b) === escape(a) + escape(b) — callers may
|
|
26
|
-
* apply it per-delta or on the accumulated string interchangeably.
|
|
27
|
-
*/
|
|
28
|
-
export function escapeThinkingTags(text: string): string {
|
|
29
|
-
return text.replace(/</g, '<')
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Map one parsed leading frame to normalized events, replicating the
|
|
34
|
-
* legacy parser's else-if chain ORDER and its exact truthiness/typeof
|
|
35
|
-
* gates. Frames that matched a branch but failed its inner validation
|
|
36
|
-
* (e.g. `routing` without a string `routedComplexity`) produce NO event,
|
|
37
|
-
* exactly like the legacy no-op.
|
|
38
|
-
*
|
|
39
|
-
* Every branch pushes AT MOST ONE event — `guideFrameEvent` relies on that
|
|
40
|
-
* to hand a single event back to `decodeNatsChunk`'s per-chunk contract.
|
|
41
|
-
*/
|
|
42
|
-
export function mapLeadingFrame(meta: any, out: ChatStreamEvent[]): void {
|
|
43
|
-
if (meta.status === 'thinking') {
|
|
44
|
-
out.push({ type: 'status', phase: 'thinking' })
|
|
45
|
-
} else if (meta.kind === 'thinking-delta' && typeof meta.text === 'string') {
|
|
46
|
-
// Wire is ALREADY delta — emit verbatim, append-only contract.
|
|
47
|
-
out.push({ type: 'thinking-delta', text: meta.text })
|
|
48
|
-
} else if (meta.kind === 'usage' && meta.stage === 'start') {
|
|
49
|
-
out.push({
|
|
50
|
-
type: 'usage',
|
|
51
|
-
stage: 'start',
|
|
52
|
-
input_tokens: meta.input_tokens,
|
|
53
|
-
cache_read_input_tokens: meta.cache_read_input_tokens,
|
|
54
|
-
cache_creation_input_tokens: meta.cache_creation_input_tokens,
|
|
55
|
-
})
|
|
56
|
-
} else if (meta.kind === 'decision_resolved' && typeof meta.action === 'string') {
|
|
57
|
-
const status = meta.action === 'rejected' ? 'rejected' : 'approved'
|
|
58
|
-
const toolName = typeof meta.tool_name === 'string' ? meta.tool_name : undefined
|
|
59
|
-
const result = meta.result ?? null
|
|
60
|
-
const card = meta.card ?? null
|
|
61
|
-
out.push({
|
|
62
|
-
type: 'approval-resolved',
|
|
63
|
-
status,
|
|
64
|
-
ok: meta.ok === true,
|
|
65
|
-
willAutoContinue: meta.willAutoContinue === true,
|
|
66
|
-
...(toolName ? { toolName } : {}),
|
|
67
|
-
...(result ? { result } : {}),
|
|
68
|
-
...(card?.marker ? { marker: card.marker } : {}),
|
|
69
|
-
...(card?.ref ? { cardRef: card.ref } : {}),
|
|
70
|
-
...(card?.type ? { cardType: card.type } : {}),
|
|
71
|
-
...(typeof meta.receiptText === 'string' ? { receiptText: meta.receiptText } : {}),
|
|
72
|
-
requestId: typeof meta.proposalId === 'string' ? meta.proposalId : undefined,
|
|
73
|
-
})
|
|
74
|
-
} else if (meta.kind === 'approval_batch' && meta.batchId && Array.isArray(meta.proposals)) {
|
|
75
|
-
// Server-grouped multi-proposal turn → ONE batch event carrying a
|
|
76
|
-
// tool-call row per proposal. `toolExecutionRequestId` is the row's
|
|
77
|
-
// PROPOSAL id (each row resolves through its own per-proposal
|
|
78
|
-
// confirm); the batch's `requestId` is the stable anchor the shell
|
|
79
|
-
// uses for status flips. Field rows ride as the row's expandable
|
|
80
|
-
// args so per-proposal detail stays reachable inside the batch.
|
|
81
|
-
const toolCalls = (meta.proposals as Array<Record<string, any>>)
|
|
82
|
-
.filter((p) => p && typeof p.proposalId === 'string')
|
|
83
|
-
.map((p) => {
|
|
84
|
-
const rawFields = Array.isArray(p.fields)
|
|
85
|
-
? (p.fields as Array<{ label?: string; value?: string }>).filter(
|
|
86
|
-
(f) => f && f.label && f.value,
|
|
87
|
-
)
|
|
88
|
-
: []
|
|
89
|
-
// Prefer human-readable identity labels for the row's
|
|
90
|
-
// disambiguator; opaque-id labels ("Task", "Ticket") only as
|
|
91
|
-
// the last-resort first field.
|
|
92
|
-
const detail =
|
|
93
|
-
rawFields.find((f) => /^(title|subject|name)$/i.test(String(f.label))) ??
|
|
94
|
-
rawFields[0]
|
|
95
|
-
const base =
|
|
96
|
-
typeof p.title === 'string' && p.title.length > 0 ? p.title : String(p.toolName ?? 'Tool call')
|
|
97
|
-
return {
|
|
98
|
-
toolExecutionRequestId: String(p.proposalId),
|
|
99
|
-
toolName: String(p.toolName ?? 'tool'),
|
|
100
|
-
toolTitle: detail ? `${base} — ${detail.value}` : base,
|
|
101
|
-
requiresApproval: true,
|
|
102
|
-
toolCallArguments:
|
|
103
|
-
rawFields.length > 0
|
|
104
|
-
? Object.fromEntries(rawFields.map((f) => [String(f.label), String(f.value)]))
|
|
105
|
-
: null,
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
if (toolCalls.length > 0) {
|
|
109
|
-
out.push({
|
|
110
|
-
type: 'approval-request',
|
|
111
|
-
requestId: String(meta.batchId),
|
|
112
|
-
approvalType: 'chat',
|
|
113
|
-
toolCalls,
|
|
114
|
-
status: 'pending',
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
} else if (meta.kind === 'approval_request' && meta.proposalId) {
|
|
118
|
-
const proposalId = String(meta.proposalId)
|
|
119
|
-
const toolName = String(meta.toolName ?? 'tool')
|
|
120
|
-
const headline =
|
|
121
|
-
typeof meta.title === 'string' && meta.title.length > 0 ? meta.title : toolName
|
|
122
|
-
const rawFields = Array.isArray(meta.fields)
|
|
123
|
-
? (meta.fields as Array<{ label?: string; value?: string }>)
|
|
124
|
-
: []
|
|
125
|
-
const fields: Array<{ label: string; value: string }> = []
|
|
126
|
-
for (const f of rawFields) {
|
|
127
|
-
if (!f || !f.label || !f.value) continue
|
|
128
|
-
fields.push({ label: f.label, value: f.value })
|
|
129
|
-
}
|
|
130
|
-
out.push({
|
|
131
|
-
type: 'approval-request',
|
|
132
|
-
requestId: proposalId,
|
|
133
|
-
approvalType: toolName,
|
|
134
|
-
command: headline,
|
|
135
|
-
fields,
|
|
136
|
-
status: 'pending',
|
|
137
|
-
})
|
|
138
|
-
} else if (meta.kind === 'text-leading' && typeof meta.text === 'string') {
|
|
139
|
-
out.push({ type: 'text-delta', text: meta.text, leading: true })
|
|
140
|
-
} else if (meta.kind === 'tool_error') {
|
|
141
|
-
const msg =
|
|
142
|
-
typeof meta.message === 'string' && meta.message.length > 0
|
|
143
|
-
? meta.message
|
|
144
|
-
: 'Could not complete the requested action right now.'
|
|
145
|
-
out.push({ type: 'error', title: msg })
|
|
146
|
-
} else if (meta.kind === 'routing') {
|
|
147
|
-
if (typeof meta.routedComplexity === 'string') {
|
|
148
|
-
out.push({
|
|
149
|
-
type: 'metadata',
|
|
150
|
-
routing: {
|
|
151
|
-
routedComplexity: meta.routedComplexity,
|
|
152
|
-
...(typeof meta.routedModel === 'string' ? { routedModel: meta.routedModel } : {}),
|
|
153
|
-
routedThinkingBudget:
|
|
154
|
-
typeof meta.routedThinkingBudget === 'number' ? meta.routedThinkingBudget : null,
|
|
155
|
-
},
|
|
156
|
-
})
|
|
157
|
-
}
|
|
158
|
-
} else {
|
|
159
|
-
// Catch-all metadata-ish frame. Raw values pass through UNVALIDATED
|
|
160
|
-
// (possibly undefined) so the consumer can replicate the legacy
|
|
161
|
-
// presence/truthiness gates exactly — including the `model`-presence
|
|
162
|
-
// trigger whose value is never stored.
|
|
163
|
-
out.push({
|
|
164
|
-
type: 'metadata',
|
|
165
|
-
sources: meta.sources,
|
|
166
|
-
refs: meta.refs,
|
|
167
|
-
provider: meta.provider,
|
|
168
|
-
modelLabel: meta.modelLabel,
|
|
169
|
-
modelName: meta.model,
|
|
170
|
-
contextWindowMaxTokens: meta.contextWindowMaxTokens,
|
|
171
|
-
scrollAnchor: meta.scrollAnchor,
|
|
172
|
-
conversationId: meta.conversationId,
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WHERE an approval card renders — the one rule, read by every path that turns
|
|
3
|
-
* an approval into segments.
|
|
4
|
-
*
|
|
5
|
-
* There are three such paths and they must agree: the NATS kernel (live chunks),
|
|
6
|
-
* the SSE kernel, and the history replay that rebuilds a dialog after a reload.
|
|
7
|
-
* When the rule lived only in the live kernel, a Product Guide card rendered
|
|
8
|
-
* inline while streaming and then moved into the escalation treatment on the
|
|
9
|
-
* next page load — same card, two behaviors, and its buttons pointed at the
|
|
10
|
-
* wrong backend once it moved.
|
|
11
|
-
*
|
|
12
|
-
* The rule itself: a card is gated on approval TIER (`displayApprovalTypes`,
|
|
13
|
-
* the agent's own privilege model) UNLESS it came from the Product Guide, whose
|
|
14
|
-
* proposals are typed by TOOL and are resolved through the hub's confirm route.
|
|
15
|
-
* A hub proposal has no tier to gate on, so tier-gating one means escalating it
|
|
16
|
-
* to a human who has no way to act on it.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import type { GuideOrigin } from '../../../chat-protocol/events'
|
|
20
|
-
import { GUIDE_ORIGIN, isGuideOrigin } from '../../../chat-protocol/events'
|
|
21
|
-
import type { MessageSegment } from '../types/message.types'
|
|
22
|
-
|
|
23
|
-
/** Anything carrying the optional `origin` marker: a stream event, or the
|
|
24
|
-
* `data` of a rendered segment. */
|
|
25
|
-
interface OriginBearing {
|
|
26
|
-
origin?: GuideOrigin | string
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** True when this approval was minted by the Product Guide (the hub) rather
|
|
30
|
-
* than by the agent's own tool-approval tiering. */
|
|
31
|
-
export function isGuideApproval(source: OriginBearing | null | undefined): boolean {
|
|
32
|
-
return isGuideOrigin(source)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** The marker to stamp onto a built segment, or undefined for agent approvals.
|
|
36
|
-
* Keeps `origin` out of segment data unless it means something. */
|
|
37
|
-
export function guideApprovalOrigin(
|
|
38
|
-
source: OriginBearing | null | undefined,
|
|
39
|
-
): GuideOrigin | undefined {
|
|
40
|
-
return isGuideApproval(source) ? GUIDE_ORIGIN : undefined
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Does this approval render inline in its turn (true), or take the consumer's
|
|
45
|
-
* escalation treatment (false)?
|
|
46
|
-
*
|
|
47
|
-
* `displayApprovalTypes` undefined means "no tier gate configured" and every
|
|
48
|
-
* agent approval displays — the pre-existing history-replay default, preserved
|
|
49
|
-
* here so both kernels can share one predicate.
|
|
50
|
-
*/
|
|
51
|
-
export function approvalDisplaysInline(
|
|
52
|
-
source: OriginBearing | null | undefined,
|
|
53
|
-
approvalType: string,
|
|
54
|
-
displayApprovalTypes?: readonly string[],
|
|
55
|
-
): boolean {
|
|
56
|
-
if (isGuideApproval(source)) return true
|
|
57
|
-
return !displayApprovalTypes || displayApprovalTypes.includes(approvalType)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* True for a rendered segment that holds a Product Guide card (single or batch).
|
|
62
|
-
*
|
|
63
|
-
* Consumers use it to keep such a card in the message flow, where the hub's own
|
|
64
|
-
* chat puts it, instead of lifting it into their sticky pending-approvals
|
|
65
|
-
* footer — and to route its buttons to the hub rather than to the agent.
|
|
66
|
-
*/
|
|
67
|
-
export function isGuideApprovalSegment(segment: MessageSegment): boolean {
|
|
68
|
-
if (segment.type !== 'approval_request' && segment.type !== 'approval_batch') return false
|
|
69
|
-
return isGuideApproval(segment.data)
|
|
70
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|