@agents24/chat-react 0.3.0 → 0.3.2
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 +5 -2
- package/dist/index.cjs +82 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +87 -12
- package/dist/index.js.map +1 -1
- package/dist/mcp-oauth.d.ts +2 -0
- package/dist/types.d.ts +10 -0
- package/dist/ui/hitl-presentation.d.ts +4 -0
- package/dist/ui/index.cjs +49 -48
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.ts +1 -0
- package/dist/ui/index.js +46 -48
- package/dist/ui/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -22,7 +22,8 @@ The package owns thread hydration, older-page pagination, stream/reattach state,
|
|
|
22
22
|
- `appendStableStreamingTurn(messages, userMessage, assistantMessage)`
|
|
23
23
|
- `upsertStableAssistantMessage(messages, input)`
|
|
24
24
|
- normalized chat message, part, transport, and storage types
|
|
25
|
-
- typed V2 `pendingHitl`, `isResolvingHitl`, and `resumeHitl(...)` controller state/actions in
|
|
25
|
+
- typed V2 `pendingHitl`, `isResolvingHitl`, and `resumeHitl(...)` controller state/actions in the current `0.3.x` contract
|
|
26
|
+
- strict HITL response-block parsing and `waitForMcpOauthComplete(...)` for validated host-owned OAuth popup completion
|
|
26
27
|
- `partsFromResponseBlocks(blocks, fallbackText)`
|
|
27
28
|
- `renderChatPart(part, message, renderOptions)`
|
|
28
29
|
- `@agents24/chat-react/ui` for shared shadcn-derived `Message`, `Bubble`, `Attachment`, `Marker`, `MessageResponse`, `AgentChatMessage`, `AgentChatComposer`, `McpConnectRequiredCard`, and Agents24 message/attachment adapters
|
|
@@ -32,7 +33,9 @@ The package owns thread hydration, older-page pagination, stream/reattach state,
|
|
|
32
33
|
|
|
33
34
|
Hosts can pass `onRuntimeEvent(event, context)` and `onThreadDetailLoaded(detail)` to layer product-specific runtime UI, trace panels, analytics, or metadata over the shared chat lifecycle without forking stream handling. That surface is enough for running-history badges and read-only live thread inspectors without a separate host-owned reattach state machine.
|
|
34
35
|
|
|
35
|
-
`ChatMessage.parts` is the only render model. Backend `response_blocks` are normalized into ordered parts such as `text`, `tool-get_meteo`, `ui-blocks`, `reasoning`, `hitl`, `error`, and `data`. The shared
|
|
36
|
+
`ChatMessage.parts` is the only render model. Backend `response_blocks` are normalized into ordered parts such as `text`, `tool-get_meteo`, `ui-blocks`, `reasoning`, `hitl`, `error`, and `data`. The shared HITL action strip renders a neutral, borderless pending state and a compact terminal outcome for Tool review, MCP authentication, User Approval, and app-data permission. Tool review exposes only **Allow once** and **Don't allow**; verbose risk metadata, argument details, Edit, and Respond are not part of the chat presentation. Tool UI is client-owned through `renderPart`, `toolRenderers`, and `fallbackToolRenderer`; the package does not infer English tool labels or group tool rows.
|
|
37
|
+
|
|
38
|
+
MCP OAuth remains a host side effect. `startMcpAuth(...)` returns both `authorization_url` and the authoritative `callback_origin`; hosts open the popup and pass both values to `waitForMcpOauthComplete(...)` before calling `resumeHitl(...)`. The utility verifies popup identity, callback origin, server identity, and connection UUID and owns timeout/close cleanup.
|
|
36
39
|
|
|
37
40
|
`useStreamingText` owns reusable visual pacing for active assistant text. It returns `displayedText`, `isAnimating`, `mode`, and `parseIncompleteMarkdown` so host renderers can pass those values into their markdown component without the package depending on any markdown/UI library. The package only chooses text timing, cache behavior, reduced-motion handling, and active text-part helpers.
|
|
38
41
|
|
package/dist/index.cjs
CHANGED
|
@@ -81,7 +81,8 @@ __export(index_exports, {
|
|
|
81
81
|
useMessageScroller: () => import_message_scroller2.useMessageScroller,
|
|
82
82
|
useMessageScrollerScrollable: () => import_message_scroller2.useMessageScrollerScrollable,
|
|
83
83
|
useMessageScrollerVisibility: () => import_message_scroller2.useMessageScrollerVisibility,
|
|
84
|
-
useStreamingText: () => useStreamingText
|
|
84
|
+
useStreamingText: () => useStreamingText,
|
|
85
|
+
waitForMcpOauthComplete: () => waitForMcpOauthComplete
|
|
85
86
|
});
|
|
86
87
|
module.exports = __toCommonJS(index_exports);
|
|
87
88
|
|
|
@@ -385,6 +386,22 @@ var assistantTextFromEvents = (events) => {
|
|
|
385
386
|
};
|
|
386
387
|
var asRecord = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
387
388
|
var optionalString = (value) => typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
389
|
+
var HITL_ACTIONS_BY_KIND = {
|
|
390
|
+
tool_review: ["approve", "reject"],
|
|
391
|
+
mcp_auth: ["connect", "skip"],
|
|
392
|
+
user_approval: ["approve", "reject"],
|
|
393
|
+
app_data_permission: ["approve", "reject"]
|
|
394
|
+
};
|
|
395
|
+
var HITL_STATUSES = ["pending", "resolved", "expired", "cancelled", "invalidated"];
|
|
396
|
+
function exactHitlActions(kind, value) {
|
|
397
|
+
if (!Array.isArray(value)) throw new Error("Invalid V2 HITL response block.");
|
|
398
|
+
const actions = value.map((item) => String(item));
|
|
399
|
+
const expected = HITL_ACTIONS_BY_KIND[kind];
|
|
400
|
+
if (actions.length !== expected.length || actions.some((action, index) => action !== expected[index])) {
|
|
401
|
+
throw new Error("Invalid V2 HITL response block.");
|
|
402
|
+
}
|
|
403
|
+
return actions;
|
|
404
|
+
}
|
|
388
405
|
var toolStateFromStatus = (status) => {
|
|
389
406
|
const normalized = String(status || "").trim().toLowerCase();
|
|
390
407
|
if (["failed", "error"].includes(normalized)) return "output-error";
|
|
@@ -491,17 +508,19 @@ var partsFromResponseBlocks = (blocks, fallbackText) => {
|
|
|
491
508
|
const interruptId = optionalString(block.interruptId) || optionalString(hitl.interrupt_id);
|
|
492
509
|
const hitlKind = optionalString(block.hitlKind) || optionalString(hitl.kind);
|
|
493
510
|
const status = optionalString(block.status) || optionalString(hitl.status) || "pending";
|
|
494
|
-
|
|
495
|
-
if (!interruptId || allowedActions.length === 0 || !["tool_review", "mcp_auth", "user_approval", "app_data_permission"].includes(String(hitlKind))) {
|
|
511
|
+
if (!interruptId || !["tool_review", "mcp_auth", "user_approval", "app_data_permission"].includes(String(hitlKind)) || !HITL_STATUSES.includes(status)) {
|
|
496
512
|
throw new Error("Invalid V2 HITL response block.");
|
|
497
513
|
}
|
|
514
|
+
const kind = hitlKind;
|
|
515
|
+
const allowedActions = exactHitlActions(kind, hitl.allowed_actions);
|
|
498
516
|
const resolution = asRecord(block.resolution);
|
|
517
|
+
const resolver = asRecord(resolution?.resolver);
|
|
499
518
|
parts.push({
|
|
500
519
|
id,
|
|
501
520
|
type: "hitl",
|
|
502
521
|
kind: "hitl",
|
|
503
522
|
interruptId,
|
|
504
|
-
hitlKind,
|
|
523
|
+
hitlKind: kind,
|
|
505
524
|
message: optionalString(hitl.message) || optionalString(block.text) || "Input is required to continue.",
|
|
506
525
|
allowedActions,
|
|
507
526
|
status,
|
|
@@ -511,7 +530,10 @@ var partsFromResponseBlocks = (blocks, fallbackText) => {
|
|
|
511
530
|
outcome: optionalString(resolution.outcome),
|
|
512
531
|
reason: optionalString(resolution.reason),
|
|
513
532
|
resolvedAt: optionalString(resolution.resolved_at),
|
|
514
|
-
resolver:
|
|
533
|
+
resolver: resolver ? {
|
|
534
|
+
principalType: optionalString(resolver.principal_type) || optionalString(resolver.principalType) || null,
|
|
535
|
+
principalId: optionalString(resolver.principal_id) || optionalString(resolver.principalId) || null
|
|
536
|
+
} : null
|
|
515
537
|
} : null,
|
|
516
538
|
raw: block
|
|
517
539
|
});
|
|
@@ -1961,6 +1983,59 @@ var LatestThreadScroller = {
|
|
|
1961
1983
|
Outline: LatestThreadScrollerOutline
|
|
1962
1984
|
};
|
|
1963
1985
|
|
|
1986
|
+
// src/mcp-oauth.ts
|
|
1987
|
+
var CONNECTION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
1988
|
+
function normalizedOrigin(value) {
|
|
1989
|
+
try {
|
|
1990
|
+
return new URL(value).origin;
|
|
1991
|
+
} catch {
|
|
1992
|
+
throw new Error("MCP authorization returned an invalid callback origin.");
|
|
1993
|
+
}
|
|
1994
|
+
}
|
|
1995
|
+
function waitForMcpOauthComplete({
|
|
1996
|
+
popup,
|
|
1997
|
+
callbackOrigin,
|
|
1998
|
+
serverId,
|
|
1999
|
+
timeoutMs = 12e4
|
|
2000
|
+
}) {
|
|
2001
|
+
if (!popup) return Promise.reject(new Error("Could not open the MCP authorization popup."));
|
|
2002
|
+
const expectedOrigin = normalizedOrigin(callbackOrigin);
|
|
2003
|
+
const expectedServerId = String(serverId || "").trim();
|
|
2004
|
+
if (!expectedServerId) return Promise.reject(new Error("MCP authorization is missing its server identity."));
|
|
2005
|
+
return new Promise((resolve, reject) => {
|
|
2006
|
+
let settled = false;
|
|
2007
|
+
const finish = (result) => {
|
|
2008
|
+
if (settled) return;
|
|
2009
|
+
settled = true;
|
|
2010
|
+
window.clearTimeout(timeout);
|
|
2011
|
+
window.clearInterval(closeTimer);
|
|
2012
|
+
window.removeEventListener("message", onMessage);
|
|
2013
|
+
if (result instanceof Error) reject(result);
|
|
2014
|
+
else resolve(result);
|
|
2015
|
+
};
|
|
2016
|
+
const onMessage = (event) => {
|
|
2017
|
+
if (event.source !== popup || event.origin !== expectedOrigin) return;
|
|
2018
|
+
const data = event.data;
|
|
2019
|
+
if (data?.type !== "mcp-oauth-complete" || data.server_id !== expectedServerId) return;
|
|
2020
|
+
if (!data.success) {
|
|
2021
|
+
finish(new Error("MCP authorization failed."));
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2024
|
+
const connectionId = String(data.connection_id || "").trim();
|
|
2025
|
+
if (!CONNECTION_ID_PATTERN.test(connectionId)) return;
|
|
2026
|
+
finish({ connectionId });
|
|
2027
|
+
};
|
|
2028
|
+
const timeout = window.setTimeout(
|
|
2029
|
+
() => finish(new Error("MCP authorization timed out.")),
|
|
2030
|
+
Math.max(1, timeoutMs)
|
|
2031
|
+
);
|
|
2032
|
+
const closeTimer = window.setInterval(() => {
|
|
2033
|
+
if (popup.closed) finish(new Error("MCP authorization window was closed before connecting."));
|
|
2034
|
+
}, 500);
|
|
2035
|
+
window.addEventListener("message", onMessage);
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
|
|
1964
2039
|
// src/renderers.tsx
|
|
1965
2040
|
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1966
2041
|
var DefaultToolPart = ({ part }) => {
|
|
@@ -2398,6 +2473,7 @@ var import_message_scroller2 = require("@shadcn/react/message-scroller");
|
|
|
2398
2473
|
useMessageScroller,
|
|
2399
2474
|
useMessageScrollerScrollable,
|
|
2400
2475
|
useMessageScrollerVisibility,
|
|
2401
|
-
useStreamingText
|
|
2476
|
+
useStreamingText,
|
|
2477
|
+
waitForMcpOauthComplete
|
|
2402
2478
|
});
|
|
2403
2479
|
//# sourceMappingURL=index.cjs.map
|