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