@copilotkit/react-core 1.59.4 → 1.59.5
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/{copilotkit-LdQ8w20l.cjs → copilotkit-CFfEVdV4.cjs} +340 -203
- package/dist/copilotkit-CFfEVdV4.cjs.map +1 -0
- package/dist/{copilotkit-CtqalfG8.d.cts → copilotkit-Ctvinul7.d.cts} +40 -3
- package/dist/copilotkit-Ctvinul7.d.cts.map +1 -0
- package/dist/{copilotkit-DoIlZQqa.mjs → copilotkit-DEGlMWM0.mjs} +340 -203
- package/dist/copilotkit-DEGlMWM0.mjs.map +1 -0
- package/dist/{copilotkit-D42EuTt0.d.mts → copilotkit-DqDT5RLa.d.mts} +40 -3
- package/dist/copilotkit-DqDT5RLa.d.mts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +339 -202
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +1 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +1 -1
- package/dist/v2/index.umd.js +339 -202
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/dist/copilotkit-CtqalfG8.d.cts.map +0 -1
- package/dist/copilotkit-D42EuTt0.d.mts.map +0 -1
- package/dist/copilotkit-DoIlZQqa.mjs.map +0 -1
- package/dist/copilotkit-LdQ8w20l.cjs.map +0 -1
package/dist/v2/index.umd.js
CHANGED
|
@@ -2940,210 +2940,110 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2940
2940
|
};
|
|
2941
2941
|
|
|
2942
2942
|
//#endregion
|
|
2943
|
-
//#region src/v2/a2ui/
|
|
2943
|
+
//#region src/v2/a2ui/A2UIRecoveryStates.tsx
|
|
2944
2944
|
/**
|
|
2945
|
-
* The
|
|
2946
|
-
*
|
|
2947
|
-
|
|
2948
|
-
const A2UI_OPERATIONS_KEY = "a2ui_operations";
|
|
2949
|
-
let initialized = false;
|
|
2950
|
-
function ensureInitialized() {
|
|
2951
|
-
if (!initialized) {
|
|
2952
|
-
(0, _copilotkit_a2ui_renderer.initializeDefaultCatalog)();
|
|
2953
|
-
(0, _copilotkit_a2ui_renderer.injectStyles)();
|
|
2954
|
-
initialized = true;
|
|
2955
|
-
}
|
|
2956
|
-
}
|
|
2957
|
-
function createA2UIMessageRenderer(options) {
|
|
2958
|
-
const { theme, catalog, loadingComponent } = options;
|
|
2959
|
-
return {
|
|
2960
|
-
activityType: "a2ui-surface",
|
|
2961
|
-
content: zod.z.any(),
|
|
2962
|
-
render: ({ content, agent }) => {
|
|
2963
|
-
ensureInitialized();
|
|
2964
|
-
const [operations, setOperations] = (0, react.useState)([]);
|
|
2965
|
-
const { copilotkit } = useCopilotKit();
|
|
2966
|
-
const lastContentRef = (0, react.useRef)(null);
|
|
2967
|
-
(0, react.useEffect)(() => {
|
|
2968
|
-
if (content === lastContentRef.current) return;
|
|
2969
|
-
lastContentRef.current = content;
|
|
2970
|
-
const incoming = content?.[A2UI_OPERATIONS_KEY];
|
|
2971
|
-
if (!content || !Array.isArray(incoming)) {
|
|
2972
|
-
setOperations([]);
|
|
2973
|
-
return;
|
|
2974
|
-
}
|
|
2975
|
-
setOperations(incoming);
|
|
2976
|
-
}, [content]);
|
|
2977
|
-
const groupedOperations = (0, react.useMemo)(() => {
|
|
2978
|
-
const groups = /* @__PURE__ */ new Map();
|
|
2979
|
-
for (const operation of operations) {
|
|
2980
|
-
const surfaceId = getOperationSurfaceId(operation) ?? _copilotkit_a2ui_renderer.DEFAULT_SURFACE_ID;
|
|
2981
|
-
if (!groups.has(surfaceId)) groups.set(surfaceId, []);
|
|
2982
|
-
groups.get(surfaceId).push(operation);
|
|
2983
|
-
}
|
|
2984
|
-
return groups;
|
|
2985
|
-
}, [operations]);
|
|
2986
|
-
if (!groupedOperations.size) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(loadingComponent ?? DefaultA2UILoading, {});
|
|
2987
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2988
|
-
className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
|
|
2989
|
-
children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReactSurfaceHost, {
|
|
2990
|
-
surfaceId,
|
|
2991
|
-
operations: ops,
|
|
2992
|
-
theme,
|
|
2993
|
-
agent,
|
|
2994
|
-
copilotkit,
|
|
2995
|
-
catalog
|
|
2996
|
-
}, surfaceId))
|
|
2997
|
-
});
|
|
2998
|
-
}
|
|
2999
|
-
};
|
|
3000
|
-
}
|
|
3001
|
-
/**
|
|
3002
|
-
* Renders a single A2UI surface using the React renderer.
|
|
3003
|
-
* Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
|
|
2945
|
+
* The pre-paint lifecycle fields the middleware stamps onto the `a2ui-surface`
|
|
2946
|
+
* activity content (alongside `a2ui_operations` on paint). `.passthrough()` keeps
|
|
2947
|
+
* `a2ui_operations` and any future fields intact.
|
|
3004
2948
|
*/
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
catalog,
|
|
3027
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
|
|
3028
|
-
surfaceId,
|
|
3029
|
-
operations
|
|
3030
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UISurfaceOrError, { surfaceId })]
|
|
3031
|
-
})
|
|
3032
|
-
});
|
|
2949
|
+
const A2UILifecycleFields = {
|
|
2950
|
+
status: zod.z.enum([
|
|
2951
|
+
"building",
|
|
2952
|
+
"retrying",
|
|
2953
|
+
"failed"
|
|
2954
|
+
]).optional(),
|
|
2955
|
+
attempt: zod.z.number().optional(),
|
|
2956
|
+
maxAttempts: zod.z.number().optional(),
|
|
2957
|
+
progressTokens: zod.z.number().optional(),
|
|
2958
|
+
error: zod.z.string().optional(),
|
|
2959
|
+
errors: zod.z.array(zod.z.any()).optional(),
|
|
2960
|
+
attempts: zod.z.array(zod.z.any()).optional(),
|
|
2961
|
+
debugExposure: zod.z.enum([
|
|
2962
|
+
"hidden",
|
|
2963
|
+
"collapsed",
|
|
2964
|
+
"verbose"
|
|
2965
|
+
]).optional()
|
|
2966
|
+
};
|
|
2967
|
+
/** Server-stamped debugExposure wins; else the client option; else "collapsed". */
|
|
2968
|
+
function resolveDebugExposure(content, optionDebugExposure) {
|
|
2969
|
+
return content?.debugExposure ?? optionDebugExposure;
|
|
3033
2970
|
}
|
|
3034
|
-
/**
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
const error = (0, _copilotkit_a2ui_renderer.useA2UIError)();
|
|
3040
|
-
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3041
|
-
className: "cpk:rounded-lg cpk:border cpk:border-red-200 cpk:bg-red-50 cpk:p-3 cpk:text-sm cpk:text-red-700",
|
|
3042
|
-
children: ["A2UI render error: ", error]
|
|
3043
|
-
});
|
|
3044
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_copilotkit_a2ui_renderer.A2UIRenderer, {
|
|
3045
|
-
surfaceId,
|
|
3046
|
-
className: "cpk:flex cpk:flex-1"
|
|
2971
|
+
/** building: the generic skeleton + optional live token count. */
|
|
2972
|
+
function A2UIBuildingState({ content }) {
|
|
2973
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIGeneratingSkeleton, {
|
|
2974
|
+
label: "Building interface",
|
|
2975
|
+
tokens: typeof content?.progressTokens === "number" ? content.progressTokens : void 0
|
|
3047
2976
|
});
|
|
3048
2977
|
}
|
|
3049
2978
|
/**
|
|
3050
|
-
*
|
|
3051
|
-
*
|
|
2979
|
+
* retrying: stays the generic skeleton through fast/transient retries; only once
|
|
2980
|
+
* the retry is perceptible (after `showAfterMs`, or once `attempt` crosses
|
|
2981
|
+
* `showAfterAttempts`) does the sub-label reveal "Retrying generation… (N/M)".
|
|
3052
2982
|
*/
|
|
3053
|
-
function
|
|
3054
|
-
const
|
|
3055
|
-
const
|
|
2983
|
+
function A2UIRetryingState({ content, showAfterMs, showAfterAttempts, debugExposure }) {
|
|
2984
|
+
const attempt = typeof content?.attempt === "number" ? content.attempt : void 0;
|
|
2985
|
+
const maxAttempts = typeof content?.maxAttempts === "number" ? content.maxAttempts : void 0;
|
|
2986
|
+
const immediate = attempt !== void 0 && attempt >= showAfterAttempts;
|
|
2987
|
+
const [revealed, setRevealed] = (0, react.useState)(immediate);
|
|
3056
2988
|
(0, react.useEffect)(() => {
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
2989
|
+
if (immediate) {
|
|
2990
|
+
setRevealed(true);
|
|
2991
|
+
return;
|
|
2992
|
+
}
|
|
2993
|
+
const timer = setTimeout(() => setRevealed(true), showAfterMs);
|
|
2994
|
+
return () => clearTimeout(timer);
|
|
2995
|
+
}, [immediate, showAfterMs]);
|
|
2996
|
+
const tokens = typeof content?.progressTokens === "number" ? content.progressTokens : void 0;
|
|
2997
|
+
if (!revealed) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIGeneratingSkeleton, {
|
|
2998
|
+
label: "Building interface",
|
|
2999
|
+
tokens
|
|
3000
|
+
});
|
|
3001
|
+
const label = attempt !== void 0 && maxAttempts !== void 0 ? `Retrying generation… (${attempt}/${maxAttempts} attempts)` : "Retrying generation…";
|
|
3002
|
+
const errors = Array.isArray(content?.errors) ? content.errors : [];
|
|
3003
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIGeneratingSkeleton, {
|
|
3004
|
+
label,
|
|
3005
|
+
tokens,
|
|
3006
|
+
children: debugExposure !== "hidden" && errors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIDebugDetails, {
|
|
3007
|
+
label: "validation issues",
|
|
3008
|
+
open: debugExposure === "verbose",
|
|
3009
|
+
payload: {
|
|
3010
|
+
attempt: content?.attempt,
|
|
3011
|
+
errors
|
|
3012
|
+
}
|
|
3013
|
+
})
|
|
3014
|
+
});
|
|
3068
3015
|
}
|
|
3069
|
-
/**
|
|
3070
|
-
|
|
3071
|
-
* Displays an animated shimmer skeleton.
|
|
3072
|
-
*/
|
|
3073
|
-
function DefaultA2UILoading() {
|
|
3016
|
+
/** failed: a clean hard-failure card that replaces the skeleton in place. */
|
|
3017
|
+
function A2UIRecoveryFailure({ content, debugExposure }) {
|
|
3074
3018
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3075
|
-
className: "cpk:
|
|
3076
|
-
style: { minHeight: 120 },
|
|
3019
|
+
className: "cpk:rounded-lg cpk:border cpk:border-amber-200 cpk:bg-amber-50 cpk:p-3 cpk:text-sm cpk:text-amber-800",
|
|
3077
3020
|
children: [
|
|
3078
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3079
|
-
className: "cpk:
|
|
3080
|
-
children:
|
|
3081
|
-
className: "cpk:h-3 cpk:w-3 cpk:rounded-full cpk:bg-gray-200",
|
|
3082
|
-
style: { animation: "cpk-a2ui-pulse 1.5s ease-in-out infinite" }
|
|
3083
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3084
|
-
className: "cpk:text-xs cpk:font-medium cpk:text-gray-400",
|
|
3085
|
-
children: "Generating UI..."
|
|
3086
|
-
})]
|
|
3021
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3022
|
+
className: "cpk:font-medium",
|
|
3023
|
+
children: "Couldn't generate the UI"
|
|
3087
3024
|
}),
|
|
3088
3025
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3089
|
-
className: "cpk:
|
|
3090
|
-
children:
|
|
3091
|
-
.8,
|
|
3092
|
-
.6,
|
|
3093
|
-
.4
|
|
3094
|
-
].map((width, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3095
|
-
className: "cpk:h-3 cpk:rounded cpk:bg-gray-200/70",
|
|
3096
|
-
style: {
|
|
3097
|
-
width: `${width * 100}%`,
|
|
3098
|
-
animation: `cpk-a2ui-pulse 1.5s ease-in-out ${i * .15}s infinite`
|
|
3099
|
-
}
|
|
3100
|
-
}, i))
|
|
3026
|
+
className: "cpk:mt-1 cpk:text-xs cpk:text-amber-700",
|
|
3027
|
+
children: "Something went wrong rendering this. You can keep chatting and try again."
|
|
3101
3028
|
}),
|
|
3102
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3029
|
+
debugExposure !== "hidden" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIDebugDetails, {
|
|
3030
|
+
label: "developer details",
|
|
3031
|
+
open: debugExposure === "verbose",
|
|
3032
|
+
payload: {
|
|
3033
|
+
error: content?.error,
|
|
3034
|
+
attempts: content?.attempts
|
|
3035
|
+
}
|
|
3036
|
+
})
|
|
3108
3037
|
]
|
|
3109
3038
|
});
|
|
3110
3039
|
}
|
|
3111
|
-
function getOperationSurfaceId(operation) {
|
|
3112
|
-
if (!operation || typeof operation !== "object") return null;
|
|
3113
|
-
if (typeof operation.surfaceId === "string") return operation.surfaceId;
|
|
3114
|
-
return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
|
|
3115
|
-
}
|
|
3116
|
-
|
|
3117
|
-
//#endregion
|
|
3118
|
-
//#region src/v2/a2ui/A2UIToolCallRenderer.tsx
|
|
3119
|
-
/**
|
|
3120
|
-
* Tool name used by the dynamic A2UI generation secondary LLM.
|
|
3121
|
-
* This renderer is auto-registered when A2UI is enabled.
|
|
3122
|
-
*/
|
|
3123
|
-
const RENDER_A2UI_TOOL_NAME = "render_a2ui";
|
|
3124
3040
|
/**
|
|
3125
|
-
*
|
|
3126
|
-
*
|
|
3127
|
-
*
|
|
3128
|
-
* Registered automatically when A2UI is enabled. Users can override by
|
|
3129
|
-
* providing their own `useRenderTool({ name: "render_a2ui", ... })`.
|
|
3041
|
+
* Animated wireframe skeleton with a label, an optional live token count, and an
|
|
3042
|
+
* optional debug-detail slot below it. Pure CSS animation (no data dependency).
|
|
3043
|
+
* The `tokens` count drives a progressive reveal of skeleton rows.
|
|
3130
3044
|
*/
|
|
3131
|
-
function
|
|
3132
|
-
const
|
|
3133
|
-
time: 0,
|
|
3134
|
-
tokens: 0
|
|
3135
|
-
});
|
|
3136
|
-
const now = Date.now();
|
|
3137
|
-
let { tokens } = lastRef.current;
|
|
3138
|
-
if (now - lastRef.current.time > 200) {
|
|
3139
|
-
const chars = JSON.stringify(parameters ?? {}).length;
|
|
3140
|
-
tokens = Math.round(chars / 4);
|
|
3141
|
-
lastRef.current = {
|
|
3142
|
-
time: now,
|
|
3143
|
-
tokens
|
|
3144
|
-
};
|
|
3145
|
-
}
|
|
3146
|
-
const phase = tokens < 50 ? 0 : tokens < 200 ? 1 : tokens < 400 ? 2 : 3;
|
|
3045
|
+
function A2UIGeneratingSkeleton({ label, tokens, children }) {
|
|
3046
|
+
const phase = tokens == null ? 3 : tokens < 50 ? 0 : tokens < 200 ? 1 : tokens < 400 ? 2 : 3;
|
|
3147
3047
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3148
3048
|
style: {
|
|
3149
3049
|
margin: "12px 0",
|
|
@@ -3351,8 +3251,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3351
3251
|
color: "#a1a1aa",
|
|
3352
3252
|
letterSpacing: "0.025em"
|
|
3353
3253
|
},
|
|
3354
|
-
children:
|
|
3355
|
-
}), tokens > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3254
|
+
children: label
|
|
3255
|
+
}), typeof tokens === "number" && tokens > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3356
3256
|
style: {
|
|
3357
3257
|
fontSize: 11,
|
|
3358
3258
|
color: "#d4d4d8",
|
|
@@ -3365,6 +3265,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3365
3265
|
]
|
|
3366
3266
|
})]
|
|
3367
3267
|
}),
|
|
3268
|
+
children,
|
|
3368
3269
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: `
|
|
3369
3270
|
@keyframes cpk-a2ui-fade {
|
|
3370
3271
|
0%, 100% { opacity: 1; }
|
|
@@ -3378,6 +3279,20 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3378
3279
|
]
|
|
3379
3280
|
});
|
|
3380
3281
|
}
|
|
3282
|
+
function A2UIDebugDetails({ label, open, payload }) {
|
|
3283
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
3284
|
+
open,
|
|
3285
|
+
className: "cpk:mt-2 cpk:text-xs",
|
|
3286
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("summary", {
|
|
3287
|
+
className: "cpk:cursor-pointer cpk:text-gray-500",
|
|
3288
|
+
children: label
|
|
3289
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
3290
|
+
className: "cpk:mt-1 cpk:overflow-auto cpk:rounded cpk:bg-gray-100 cpk:p-2 cpk:text-gray-700",
|
|
3291
|
+
style: { fontSize: 11 },
|
|
3292
|
+
children: JSON.stringify(payload, null, 2)
|
|
3293
|
+
})]
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3381
3296
|
function Dot() {
|
|
3382
3297
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { style: {
|
|
3383
3298
|
width: 7,
|
|
@@ -3413,13 +3328,242 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3413
3328
|
children
|
|
3414
3329
|
});
|
|
3415
3330
|
}
|
|
3331
|
+
|
|
3332
|
+
//#endregion
|
|
3333
|
+
//#region src/v2/a2ui/A2UIMessageRenderer.tsx
|
|
3334
|
+
/**
|
|
3335
|
+
* The container key used to wrap A2UI operations for explicit detection.
|
|
3336
|
+
* Must match A2UI_OPERATIONS_KEY in @ag-ui/a2ui-middleware and copilotkit.a2ui (Python).
|
|
3337
|
+
*/
|
|
3338
|
+
const A2UI_OPERATIONS_KEY = "a2ui_operations";
|
|
3339
|
+
let initialized = false;
|
|
3340
|
+
function ensureInitialized() {
|
|
3341
|
+
if (!initialized) {
|
|
3342
|
+
(0, _copilotkit_a2ui_renderer.initializeDefaultCatalog)();
|
|
3343
|
+
(0, _copilotkit_a2ui_renderer.injectStyles)();
|
|
3344
|
+
initialized = true;
|
|
3345
|
+
}
|
|
3346
|
+
}
|
|
3347
|
+
/**
|
|
3348
|
+
* The `a2ui-surface` activity carries the WHOLE generative-UI lifecycle on one
|
|
3349
|
+
* stable messageId (OSS-162): pre-paint `status` ("building" | "retrying" |
|
|
3350
|
+
* "failed") with recovery detail, then `a2ui_operations` on paint. The states
|
|
3351
|
+
* swap in place, so the painted surface replaces the skeleton with no extra
|
|
3352
|
+
* coordination. `.passthrough()` preserves operations + any future fields.
|
|
3353
|
+
*/
|
|
3354
|
+
const A2UISurfaceContentSchema = zod.z.object({
|
|
3355
|
+
a2ui_operations: zod.z.array(zod.z.any()).optional(),
|
|
3356
|
+
...A2UILifecycleFields
|
|
3357
|
+
}).passthrough();
|
|
3358
|
+
function createA2UIMessageRenderer(options) {
|
|
3359
|
+
const { theme, catalog, loadingComponent, recovery } = options;
|
|
3360
|
+
const showAfterMs = recovery?.showAfterMs ?? 2e3;
|
|
3361
|
+
const showAfterAttempts = recovery?.showAfterAttempts ?? 2;
|
|
3362
|
+
const optionDebugExposure = recovery?.debugExposure ?? "collapsed";
|
|
3363
|
+
return {
|
|
3364
|
+
activityType: "a2ui-surface",
|
|
3365
|
+
content: A2UISurfaceContentSchema,
|
|
3366
|
+
render: ({ content, agent }) => {
|
|
3367
|
+
ensureInitialized();
|
|
3368
|
+
const [operations, setOperations] = (0, react.useState)([]);
|
|
3369
|
+
const { copilotkit } = useCopilotKit();
|
|
3370
|
+
const lastContentRef = (0, react.useRef)(null);
|
|
3371
|
+
(0, react.useEffect)(() => {
|
|
3372
|
+
if (content === lastContentRef.current) return;
|
|
3373
|
+
lastContentRef.current = content;
|
|
3374
|
+
const incoming = content?.[A2UI_OPERATIONS_KEY];
|
|
3375
|
+
if (!content || !Array.isArray(incoming)) {
|
|
3376
|
+
setOperations([]);
|
|
3377
|
+
return;
|
|
3378
|
+
}
|
|
3379
|
+
setOperations(incoming);
|
|
3380
|
+
}, [content]);
|
|
3381
|
+
const groupedOperations = (0, react.useMemo)(() => {
|
|
3382
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3383
|
+
for (const operation of operations) {
|
|
3384
|
+
const surfaceId = getOperationSurfaceId(operation) ?? _copilotkit_a2ui_renderer.DEFAULT_SURFACE_ID;
|
|
3385
|
+
if (!groups.has(surfaceId)) groups.set(surfaceId, []);
|
|
3386
|
+
groups.get(surfaceId).push(operation);
|
|
3387
|
+
}
|
|
3388
|
+
return groups;
|
|
3389
|
+
}, [operations]);
|
|
3390
|
+
const hasOps = groupedOperations.size > 0;
|
|
3391
|
+
const renderLifecycle = (c) => {
|
|
3392
|
+
const status = c?.status;
|
|
3393
|
+
const debugExposure = resolveDebugExposure(c, optionDebugExposure);
|
|
3394
|
+
if (status === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIRecoveryFailure, {
|
|
3395
|
+
content: c,
|
|
3396
|
+
debugExposure
|
|
3397
|
+
});
|
|
3398
|
+
if (status === "retrying") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIRetryingState, {
|
|
3399
|
+
content: c,
|
|
3400
|
+
showAfterMs,
|
|
3401
|
+
showAfterAttempts,
|
|
3402
|
+
debugExposure
|
|
3403
|
+
});
|
|
3404
|
+
if (loadingComponent) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(loadingComponent, {});
|
|
3405
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuildingState, { content: c });
|
|
3406
|
+
};
|
|
3407
|
+
const lastLoaderContentRef = (0, react.useRef)(null);
|
|
3408
|
+
if (!(Array.isArray(content?.[A2UI_OPERATIONS_KEY]) && content[A2UI_OPERATIONS_KEY].length > 0)) lastLoaderContentRef.current = content;
|
|
3409
|
+
const [surfaceReady, setSurfaceReady] = (0, react.useState)(false);
|
|
3410
|
+
const readyRef = (0, react.useRef)(false);
|
|
3411
|
+
const markSurfaceReady = (0, react.useCallback)(() => {
|
|
3412
|
+
if (readyRef.current) return;
|
|
3413
|
+
readyRef.current = true;
|
|
3414
|
+
requestAnimationFrame(() => setSurfaceReady(true));
|
|
3415
|
+
}, []);
|
|
3416
|
+
(0, react.useEffect)(() => {
|
|
3417
|
+
if (!hasOps) {
|
|
3418
|
+
setSurfaceReady(false);
|
|
3419
|
+
readyRef.current = false;
|
|
3420
|
+
return;
|
|
3421
|
+
}
|
|
3422
|
+
const t = setTimeout(() => setSurfaceReady(true), 8e3);
|
|
3423
|
+
return () => clearTimeout(t);
|
|
3424
|
+
}, [hasOps]);
|
|
3425
|
+
if (!hasOps) return renderLifecycle(content);
|
|
3426
|
+
const surfaces = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3427
|
+
className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
|
|
3428
|
+
children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReactSurfaceHost, {
|
|
3429
|
+
surfaceId,
|
|
3430
|
+
operations: ops,
|
|
3431
|
+
theme,
|
|
3432
|
+
agent,
|
|
3433
|
+
copilotkit,
|
|
3434
|
+
catalog,
|
|
3435
|
+
onReady: markSurfaceReady
|
|
3436
|
+
}, surfaceId))
|
|
3437
|
+
});
|
|
3438
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3439
|
+
style: { position: "relative" },
|
|
3440
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3441
|
+
"aria-hidden": !surfaceReady,
|
|
3442
|
+
style: surfaceReady ? void 0 : {
|
|
3443
|
+
position: "absolute",
|
|
3444
|
+
inset: 0,
|
|
3445
|
+
opacity: 0,
|
|
3446
|
+
pointerEvents: "none"
|
|
3447
|
+
},
|
|
3448
|
+
children: surfaces
|
|
3449
|
+
}), !surfaceReady && renderLifecycle(lastLoaderContentRef.current ?? content)]
|
|
3450
|
+
});
|
|
3451
|
+
}
|
|
3452
|
+
};
|
|
3453
|
+
}
|
|
3454
|
+
/**
|
|
3455
|
+
* Renders a single A2UI surface using the React renderer.
|
|
3456
|
+
* Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
|
|
3457
|
+
*/
|
|
3458
|
+
function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onReady }) {
|
|
3459
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3460
|
+
className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
|
|
3461
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
|
|
3462
|
+
onAction: (0, react.useCallback)(async (message) => {
|
|
3463
|
+
if (!agent) return;
|
|
3464
|
+
message.userAction;
|
|
3465
|
+
try {
|
|
3466
|
+
copilotkit.setProperties({
|
|
3467
|
+
...copilotkit.properties,
|
|
3468
|
+
a2uiAction: message
|
|
3469
|
+
});
|
|
3470
|
+
await copilotkit.runAgent({ agent });
|
|
3471
|
+
} finally {
|
|
3472
|
+
if (copilotkit.properties) {
|
|
3473
|
+
const { a2uiAction, ...rest } = copilotkit.properties;
|
|
3474
|
+
copilotkit.setProperties(rest);
|
|
3475
|
+
}
|
|
3476
|
+
}
|
|
3477
|
+
}, [agent, copilotkit]),
|
|
3478
|
+
theme,
|
|
3479
|
+
catalog,
|
|
3480
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
|
|
3481
|
+
surfaceId,
|
|
3482
|
+
operations,
|
|
3483
|
+
onReady
|
|
3484
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UISurfaceOrError, { surfaceId })]
|
|
3485
|
+
})
|
|
3486
|
+
});
|
|
3487
|
+
}
|
|
3416
3488
|
/**
|
|
3417
|
-
*
|
|
3418
|
-
*
|
|
3489
|
+
* Renders the A2UI surface, or an error message if processing failed.
|
|
3490
|
+
* Must be a child of A2UIProvider to access the error state.
|
|
3491
|
+
*/
|
|
3492
|
+
function A2UISurfaceOrError({ surfaceId }) {
|
|
3493
|
+
const error = (0, _copilotkit_a2ui_renderer.useA2UIError)();
|
|
3494
|
+
if (error) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3495
|
+
className: "cpk:rounded-lg cpk:border cpk:border-red-200 cpk:bg-red-50 cpk:p-3 cpk:text-sm cpk:text-red-700",
|
|
3496
|
+
children: ["A2UI render error: ", error]
|
|
3497
|
+
});
|
|
3498
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_copilotkit_a2ui_renderer.A2UIRenderer, {
|
|
3499
|
+
surfaceId,
|
|
3500
|
+
className: "cpk:flex cpk:flex-1"
|
|
3501
|
+
});
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Processes A2UI operations into the provider's message processor.
|
|
3505
|
+
* Must be a child of A2UIProvider to access the actions context.
|
|
3506
|
+
*/
|
|
3507
|
+
function SurfaceMessageProcessor({ surfaceId, operations, onReady }) {
|
|
3508
|
+
const { processMessages, getSurface } = (0, _copilotkit_a2ui_renderer.useA2UIActions)();
|
|
3509
|
+
const lastHashRef = (0, react.useRef)("");
|
|
3510
|
+
(0, react.useEffect)(() => {
|
|
3511
|
+
const hash = JSON.stringify(operations);
|
|
3512
|
+
if (hash === lastHashRef.current) return;
|
|
3513
|
+
lastHashRef.current = hash;
|
|
3514
|
+
processMessages(getSurface(surfaceId) ? operations.filter((op) => !op?.createSurface) : operations);
|
|
3515
|
+
if (onReady && surfaceHasRenderableContent(operations)) onReady();
|
|
3516
|
+
}, [
|
|
3517
|
+
processMessages,
|
|
3518
|
+
getSurface,
|
|
3519
|
+
surfaceId,
|
|
3520
|
+
operations,
|
|
3521
|
+
onReady
|
|
3522
|
+
]);
|
|
3523
|
+
return null;
|
|
3524
|
+
}
|
|
3525
|
+
/**
|
|
3526
|
+
* Whether the surface's operations are enough to paint a visible card yet.
|
|
3527
|
+
* A data-bound surface references its data via `path` and renders nothing until
|
|
3528
|
+
* the data model has ≥1 value; a static surface (no path refs) paints from its
|
|
3529
|
+
* components alone. Used to time the loader→surface cross-over to actual content
|
|
3530
|
+
* arrival rather than a fixed delay. (OSS-162)
|
|
3531
|
+
*/
|
|
3532
|
+
function surfaceHasRenderableContent(operations) {
|
|
3533
|
+
const componentOps = operations.filter((o) => o?.updateComponents);
|
|
3534
|
+
if (!componentOps.length) return false;
|
|
3535
|
+
if (!JSON.stringify(componentOps).includes("\"path\"")) return true;
|
|
3536
|
+
return operations.some((o) => {
|
|
3537
|
+
const v = o?.updateDataModel?.value;
|
|
3538
|
+
if (!v || typeof v !== "object") return false;
|
|
3539
|
+
return Object.values(v).some((x) => Array.isArray(x) ? x.length > 0 : x !== null && x !== void 0 && x !== "");
|
|
3540
|
+
});
|
|
3541
|
+
}
|
|
3542
|
+
function getOperationSurfaceId(operation) {
|
|
3543
|
+
if (!operation || typeof operation !== "object") return null;
|
|
3544
|
+
if (typeof operation.surfaceId === "string") return operation.surfaceId;
|
|
3545
|
+
return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
//#endregion
|
|
3549
|
+
//#region src/v2/a2ui/A2UIToolCallRenderer.tsx
|
|
3550
|
+
/**
|
|
3551
|
+
* Tool name used by the dynamic A2UI generation secondary LLM.
|
|
3552
|
+
*/
|
|
3553
|
+
const RENDER_A2UI_TOOL_NAME = "render_a2ui";
|
|
3554
|
+
/**
|
|
3555
|
+
* Registers a no-op renderer for the `render_a2ui` tool call so its raw streamed
|
|
3556
|
+
* args are never surfaced in the transcript.
|
|
3419
3557
|
*
|
|
3420
|
-
*
|
|
3421
|
-
*
|
|
3422
|
-
*
|
|
3558
|
+
* The generation skeleton / retry / failure UX is NO LONGER owned here (OSS-162):
|
|
3559
|
+
* the A2UI middleware drives the whole lifecycle on the `a2ui-surface` activity
|
|
3560
|
+
* (one stable messageId, building → retrying → failed → painted), rendered in
|
|
3561
|
+
* place by `createA2UIMessageRenderer`. Owning a skeleton per tool call caused a
|
|
3562
|
+
* duplicate skeleton on retries / multi-call generations and a skeleton that
|
|
3563
|
+
* lingered after the surface painted — both fixed by retiring it here.
|
|
3564
|
+
*
|
|
3565
|
+
* Users can still override with their own `useRenderTool({ name: "render_a2ui" })`
|
|
3566
|
+
* (hook-based entries take priority over this prop-based registration).
|
|
3423
3567
|
*/
|
|
3424
3568
|
function A2UIBuiltInToolCallRenderer() {
|
|
3425
3569
|
const { copilotkit } = useCopilotKit();
|
|
@@ -3427,15 +3571,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3427
3571
|
const renderer = defineToolCallRenderer({
|
|
3428
3572
|
name: RENDER_A2UI_TOOL_NAME,
|
|
3429
3573
|
args: zod.z.any(),
|
|
3430
|
-
render: (
|
|
3431
|
-
if (status === "complete") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
|
|
3432
|
-
const params = parameters;
|
|
3433
|
-
const items = params?.items;
|
|
3434
|
-
if (Array.isArray(items) && items.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
|
|
3435
|
-
const components = params?.components;
|
|
3436
|
-
if (Array.isArray(components) && components.length > 2) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {});
|
|
3437
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIProgressIndicator, { parameters });
|
|
3438
|
-
}
|
|
3574
|
+
render: () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, {})
|
|
3439
3575
|
});
|
|
3440
3576
|
const existing = copilotkit._renderToolCalls ?? [];
|
|
3441
3577
|
copilotkit.setRenderToolCalls([...existing.filter((rc) => rc.name !== RENDER_A2UI_TOOL_NAME), renderer]);
|
|
@@ -3572,7 +3708,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3572
3708
|
if (runtimeA2UIEnabled) renderers.unshift(createA2UIMessageRenderer({
|
|
3573
3709
|
theme: a2ui?.theme ?? _copilotkit_a2ui_renderer.viewerTheme,
|
|
3574
3710
|
catalog: a2ui?.catalog,
|
|
3575
|
-
loadingComponent: a2ui?.loadingComponent
|
|
3711
|
+
loadingComponent: a2ui?.loadingComponent,
|
|
3712
|
+
recovery: a2ui?.recovery
|
|
3576
3713
|
}));
|
|
3577
3714
|
return renderers;
|
|
3578
3715
|
}, [
|