@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.
@@ -2924,210 +2924,110 @@ const OpenGenerativeUIToolRenderer = function OpenGenerativeUIToolRenderer(props
2924
2924
  };
2925
2925
 
2926
2926
  //#endregion
2927
- //#region src/v2/a2ui/A2UIMessageRenderer.tsx
2928
- /**
2929
- * The container key used to wrap A2UI operations for explicit detection.
2930
- * Must match A2UI_OPERATIONS_KEY in @ag-ui/a2ui-middleware and copilotkit.a2ui (Python).
2931
- */
2932
- const A2UI_OPERATIONS_KEY = "a2ui_operations";
2933
- let initialized = false;
2934
- function ensureInitialized() {
2935
- if (!initialized) {
2936
- initializeDefaultCatalog();
2937
- injectStyles();
2938
- initialized = true;
2939
- }
2940
- }
2941
- function createA2UIMessageRenderer(options) {
2942
- const { theme, catalog, loadingComponent } = options;
2943
- return {
2944
- activityType: "a2ui-surface",
2945
- content: z.any(),
2946
- render: ({ content, agent }) => {
2947
- ensureInitialized();
2948
- const [operations, setOperations] = useState([]);
2949
- const { copilotkit } = useCopilotKit();
2950
- const lastContentRef = useRef(null);
2951
- useEffect(() => {
2952
- if (content === lastContentRef.current) return;
2953
- lastContentRef.current = content;
2954
- const incoming = content?.[A2UI_OPERATIONS_KEY];
2955
- if (!content || !Array.isArray(incoming)) {
2956
- setOperations([]);
2957
- return;
2958
- }
2959
- setOperations(incoming);
2960
- }, [content]);
2961
- const groupedOperations = useMemo(() => {
2962
- const groups = /* @__PURE__ */ new Map();
2963
- for (const operation of operations) {
2964
- const surfaceId = getOperationSurfaceId(operation) ?? DEFAULT_SURFACE_ID;
2965
- if (!groups.has(surfaceId)) groups.set(surfaceId, []);
2966
- groups.get(surfaceId).push(operation);
2967
- }
2968
- return groups;
2969
- }, [operations]);
2970
- if (!groupedOperations.size) return /* @__PURE__ */ jsx(loadingComponent ?? DefaultA2UILoading, {});
2971
- return /* @__PURE__ */ jsx("div", {
2972
- className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
2973
- children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ jsx(ReactSurfaceHost, {
2974
- surfaceId,
2975
- operations: ops,
2976
- theme,
2977
- agent,
2978
- copilotkit,
2979
- catalog
2980
- }, surfaceId))
2981
- });
2982
- }
2983
- };
2984
- }
2927
+ //#region src/v2/a2ui/A2UIRecoveryStates.tsx
2985
2928
  /**
2986
- * Renders a single A2UI surface using the React renderer.
2987
- * Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
2929
+ * The pre-paint lifecycle fields the middleware stamps onto the `a2ui-surface`
2930
+ * activity content (alongside `a2ui_operations` on paint). `.passthrough()` keeps
2931
+ * `a2ui_operations` and any future fields intact.
2988
2932
  */
2989
- function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog }) {
2990
- return /* @__PURE__ */ jsx("div", {
2991
- className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
2992
- children: /* @__PURE__ */ jsxs(A2UIProvider, {
2993
- onAction: useCallback(async (message) => {
2994
- if (!agent) return;
2995
- message.userAction;
2996
- try {
2997
- copilotkit.setProperties({
2998
- ...copilotkit.properties,
2999
- a2uiAction: message
3000
- });
3001
- await copilotkit.runAgent({ agent });
3002
- } finally {
3003
- if (copilotkit.properties) {
3004
- const { a2uiAction, ...rest } = copilotkit.properties;
3005
- copilotkit.setProperties(rest);
3006
- }
3007
- }
3008
- }, [agent, copilotkit]),
3009
- theme,
3010
- catalog,
3011
- children: [/* @__PURE__ */ jsx(SurfaceMessageProcessor, {
3012
- surfaceId,
3013
- operations
3014
- }), /* @__PURE__ */ jsx(A2UISurfaceOrError, { surfaceId })]
3015
- })
3016
- });
2933
+ const A2UILifecycleFields = {
2934
+ status: z.enum([
2935
+ "building",
2936
+ "retrying",
2937
+ "failed"
2938
+ ]).optional(),
2939
+ attempt: z.number().optional(),
2940
+ maxAttempts: z.number().optional(),
2941
+ progressTokens: z.number().optional(),
2942
+ error: z.string().optional(),
2943
+ errors: z.array(z.any()).optional(),
2944
+ attempts: z.array(z.any()).optional(),
2945
+ debugExposure: z.enum([
2946
+ "hidden",
2947
+ "collapsed",
2948
+ "verbose"
2949
+ ]).optional()
2950
+ };
2951
+ /** Server-stamped debugExposure wins; else the client option; else "collapsed". */
2952
+ function resolveDebugExposure(content, optionDebugExposure) {
2953
+ return content?.debugExposure ?? optionDebugExposure;
3017
2954
  }
3018
- /**
3019
- * Renders the A2UI surface, or an error message if processing failed.
3020
- * Must be a child of A2UIProvider to access the error state.
3021
- */
3022
- function A2UISurfaceOrError({ surfaceId }) {
3023
- const error = useA2UIError();
3024
- if (error) return /* @__PURE__ */ jsxs("div", {
3025
- className: "cpk:rounded-lg cpk:border cpk:border-red-200 cpk:bg-red-50 cpk:p-3 cpk:text-sm cpk:text-red-700",
3026
- children: ["A2UI render error: ", error]
3027
- });
3028
- return /* @__PURE__ */ jsx(A2UIRenderer, {
3029
- surfaceId,
3030
- className: "cpk:flex cpk:flex-1"
2955
+ /** building: the generic skeleton + optional live token count. */
2956
+ function A2UIBuildingState({ content }) {
2957
+ return /* @__PURE__ */ jsx(A2UIGeneratingSkeleton, {
2958
+ label: "Building interface",
2959
+ tokens: typeof content?.progressTokens === "number" ? content.progressTokens : void 0
3031
2960
  });
3032
2961
  }
3033
2962
  /**
3034
- * Processes A2UI operations into the provider's message processor.
3035
- * Must be a child of A2UIProvider to access the actions context.
2963
+ * retrying: stays the generic skeleton through fast/transient retries; only once
2964
+ * the retry is perceptible (after `showAfterMs`, or once `attempt` crosses
2965
+ * `showAfterAttempts`) does the sub-label reveal "Retrying generation… (N/M)".
3036
2966
  */
3037
- function SurfaceMessageProcessor({ surfaceId, operations }) {
3038
- const { processMessages, getSurface } = useA2UIActions();
3039
- const lastHashRef = useRef("");
2967
+ function A2UIRetryingState({ content, showAfterMs, showAfterAttempts, debugExposure }) {
2968
+ const attempt = typeof content?.attempt === "number" ? content.attempt : void 0;
2969
+ const maxAttempts = typeof content?.maxAttempts === "number" ? content.maxAttempts : void 0;
2970
+ const immediate = attempt !== void 0 && attempt >= showAfterAttempts;
2971
+ const [revealed, setRevealed] = useState(immediate);
3040
2972
  useEffect(() => {
3041
- const hash = JSON.stringify(operations);
3042
- if (hash === lastHashRef.current) return;
3043
- lastHashRef.current = hash;
3044
- processMessages(getSurface(surfaceId) ? operations.filter((op) => !op?.createSurface) : operations);
3045
- }, [
3046
- processMessages,
3047
- getSurface,
3048
- surfaceId,
3049
- operations
3050
- ]);
3051
- return null;
2973
+ if (immediate) {
2974
+ setRevealed(true);
2975
+ return;
2976
+ }
2977
+ const timer = setTimeout(() => setRevealed(true), showAfterMs);
2978
+ return () => clearTimeout(timer);
2979
+ }, [immediate, showAfterMs]);
2980
+ const tokens = typeof content?.progressTokens === "number" ? content.progressTokens : void 0;
2981
+ if (!revealed) return /* @__PURE__ */ jsx(A2UIGeneratingSkeleton, {
2982
+ label: "Building interface",
2983
+ tokens
2984
+ });
2985
+ const label = attempt !== void 0 && maxAttempts !== void 0 ? `Retrying generation… (${attempt}/${maxAttempts} attempts)` : "Retrying generation…";
2986
+ const errors = Array.isArray(content?.errors) ? content.errors : [];
2987
+ return /* @__PURE__ */ jsx(A2UIGeneratingSkeleton, {
2988
+ label,
2989
+ tokens,
2990
+ children: debugExposure !== "hidden" && errors.length > 0 && /* @__PURE__ */ jsx(A2UIDebugDetails, {
2991
+ label: "validation issues",
2992
+ open: debugExposure === "verbose",
2993
+ payload: {
2994
+ attempt: content?.attempt,
2995
+ errors
2996
+ }
2997
+ })
2998
+ });
3052
2999
  }
3053
- /**
3054
- * Default loading component shown while an A2UI surface is generating.
3055
- * Displays an animated shimmer skeleton.
3056
- */
3057
- function DefaultA2UILoading() {
3000
+ /** failed: a clean hard-failure card that replaces the skeleton in place. */
3001
+ function A2UIRecoveryFailure({ content, debugExposure }) {
3058
3002
  return /* @__PURE__ */ jsxs("div", {
3059
- 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",
3060
- style: { minHeight: 120 },
3003
+ className: "cpk:rounded-lg cpk:border cpk:border-amber-200 cpk:bg-amber-50 cpk:p-3 cpk:text-sm cpk:text-amber-800",
3061
3004
  children: [
3062
- /* @__PURE__ */ jsxs("div", {
3063
- className: "cpk:flex cpk:items-center cpk:gap-2",
3064
- children: [/* @__PURE__ */ jsx("div", {
3065
- className: "cpk:h-3 cpk:w-3 cpk:rounded-full cpk:bg-gray-200",
3066
- style: { animation: "cpk-a2ui-pulse 1.5s ease-in-out infinite" }
3067
- }), /* @__PURE__ */ jsx("span", {
3068
- className: "cpk:text-xs cpk:font-medium cpk:text-gray-400",
3069
- children: "Generating UI..."
3070
- })]
3005
+ /* @__PURE__ */ jsx("div", {
3006
+ className: "cpk:font-medium",
3007
+ children: "Couldn't generate the UI"
3071
3008
  }),
3072
3009
  /* @__PURE__ */ jsx("div", {
3073
- className: "cpk:flex cpk:flex-col cpk:gap-2",
3074
- children: [
3075
- .8,
3076
- .6,
3077
- .4
3078
- ].map((width, i) => /* @__PURE__ */ jsx("div", {
3079
- className: "cpk:h-3 cpk:rounded cpk:bg-gray-200/70",
3080
- style: {
3081
- width: `${width * 100}%`,
3082
- animation: `cpk-a2ui-pulse 1.5s ease-in-out ${i * .15}s infinite`
3083
- }
3084
- }, i))
3010
+ className: "cpk:mt-1 cpk:text-xs cpk:text-amber-700",
3011
+ children: "Something went wrong rendering this. You can keep chatting and try again."
3085
3012
  }),
3086
- /* @__PURE__ */ jsx("style", { children: `
3087
- @keyframes cpk-a2ui-pulse {
3088
- 0%, 100% { opacity: 0.4; }
3089
- 50% { opacity: 1; }
3090
- }
3091
- ` })
3013
+ debugExposure !== "hidden" && /* @__PURE__ */ jsx(A2UIDebugDetails, {
3014
+ label: "developer details",
3015
+ open: debugExposure === "verbose",
3016
+ payload: {
3017
+ error: content?.error,
3018
+ attempts: content?.attempts
3019
+ }
3020
+ })
3092
3021
  ]
3093
3022
  });
3094
3023
  }
3095
- function getOperationSurfaceId(operation) {
3096
- if (!operation || typeof operation !== "object") return null;
3097
- if (typeof operation.surfaceId === "string") return operation.surfaceId;
3098
- return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
3099
- }
3100
-
3101
- //#endregion
3102
- //#region src/v2/a2ui/A2UIToolCallRenderer.tsx
3103
- /**
3104
- * Tool name used by the dynamic A2UI generation secondary LLM.
3105
- * This renderer is auto-registered when A2UI is enabled.
3106
- */
3107
- const RENDER_A2UI_TOOL_NAME = "render_a2ui";
3108
3024
  /**
3109
- * Built-in progress indicator for dynamic A2UI generation.
3110
- * Shows a skeleton wireframe that progressively reveals as tokens stream in.
3111
- *
3112
- * Registered automatically when A2UI is enabled. Users can override by
3113
- * providing their own `useRenderTool({ name: "render_a2ui", ... })`.
3025
+ * Animated wireframe skeleton with a label, an optional live token count, and an
3026
+ * optional debug-detail slot below it. Pure CSS animation (no data dependency).
3027
+ * The `tokens` count drives a progressive reveal of skeleton rows.
3114
3028
  */
3115
- function A2UIProgressIndicator({ parameters }) {
3116
- const lastRef = useRef({
3117
- time: 0,
3118
- tokens: 0
3119
- });
3120
- const now = Date.now();
3121
- let { tokens } = lastRef.current;
3122
- if (now - lastRef.current.time > 200) {
3123
- const chars = JSON.stringify(parameters ?? {}).length;
3124
- tokens = Math.round(chars / 4);
3125
- lastRef.current = {
3126
- time: now,
3127
- tokens
3128
- };
3129
- }
3130
- const phase = tokens < 50 ? 0 : tokens < 200 ? 1 : tokens < 400 ? 2 : 3;
3029
+ function A2UIGeneratingSkeleton({ label, tokens, children }) {
3030
+ const phase = tokens == null ? 3 : tokens < 50 ? 0 : tokens < 200 ? 1 : tokens < 400 ? 2 : 3;
3131
3031
  return /* @__PURE__ */ jsxs("div", {
3132
3032
  style: {
3133
3033
  margin: "12px 0",
@@ -3335,8 +3235,8 @@ function A2UIProgressIndicator({ parameters }) {
3335
3235
  color: "#a1a1aa",
3336
3236
  letterSpacing: "0.025em"
3337
3237
  },
3338
- children: "Building interface"
3339
- }), tokens > 0 && /* @__PURE__ */ jsxs("span", {
3238
+ children: label
3239
+ }), typeof tokens === "number" && tokens > 0 && /* @__PURE__ */ jsxs("span", {
3340
3240
  style: {
3341
3241
  fontSize: 11,
3342
3242
  color: "#d4d4d8",
@@ -3349,6 +3249,7 @@ function A2UIProgressIndicator({ parameters }) {
3349
3249
  ]
3350
3250
  })]
3351
3251
  }),
3252
+ children,
3352
3253
  /* @__PURE__ */ jsx("style", { children: `
3353
3254
  @keyframes cpk-a2ui-fade {
3354
3255
  0%, 100% { opacity: 1; }
@@ -3362,6 +3263,20 @@ function A2UIProgressIndicator({ parameters }) {
3362
3263
  ]
3363
3264
  });
3364
3265
  }
3266
+ function A2UIDebugDetails({ label, open, payload }) {
3267
+ return /* @__PURE__ */ jsxs("details", {
3268
+ open,
3269
+ className: "cpk:mt-2 cpk:text-xs",
3270
+ children: [/* @__PURE__ */ jsx("summary", {
3271
+ className: "cpk:cursor-pointer cpk:text-gray-500",
3272
+ children: label
3273
+ }), /* @__PURE__ */ jsx("pre", {
3274
+ className: "cpk:mt-1 cpk:overflow-auto cpk:rounded cpk:bg-gray-100 cpk:p-2 cpk:text-gray-700",
3275
+ style: { fontSize: 11 },
3276
+ children: JSON.stringify(payload, null, 2)
3277
+ })]
3278
+ });
3279
+ }
3365
3280
  function Dot() {
3366
3281
  return /* @__PURE__ */ jsx("div", { style: {
3367
3282
  width: 7,
@@ -3397,13 +3312,242 @@ function Row({ children, show, delay = 0 }) {
3397
3312
  children
3398
3313
  });
3399
3314
  }
3315
+
3316
+ //#endregion
3317
+ //#region src/v2/a2ui/A2UIMessageRenderer.tsx
3318
+ /**
3319
+ * The container key used to wrap A2UI operations for explicit detection.
3320
+ * Must match A2UI_OPERATIONS_KEY in @ag-ui/a2ui-middleware and copilotkit.a2ui (Python).
3321
+ */
3322
+ const A2UI_OPERATIONS_KEY = "a2ui_operations";
3323
+ let initialized = false;
3324
+ function ensureInitialized() {
3325
+ if (!initialized) {
3326
+ initializeDefaultCatalog();
3327
+ injectStyles();
3328
+ initialized = true;
3329
+ }
3330
+ }
3331
+ /**
3332
+ * The `a2ui-surface` activity carries the WHOLE generative-UI lifecycle on one
3333
+ * stable messageId (OSS-162): pre-paint `status` ("building" | "retrying" |
3334
+ * "failed") with recovery detail, then `a2ui_operations` on paint. The states
3335
+ * swap in place, so the painted surface replaces the skeleton with no extra
3336
+ * coordination. `.passthrough()` preserves operations + any future fields.
3337
+ */
3338
+ const A2UISurfaceContentSchema = z.object({
3339
+ a2ui_operations: z.array(z.any()).optional(),
3340
+ ...A2UILifecycleFields
3341
+ }).passthrough();
3342
+ function createA2UIMessageRenderer(options) {
3343
+ const { theme, catalog, loadingComponent, recovery } = options;
3344
+ const showAfterMs = recovery?.showAfterMs ?? 2e3;
3345
+ const showAfterAttempts = recovery?.showAfterAttempts ?? 2;
3346
+ const optionDebugExposure = recovery?.debugExposure ?? "collapsed";
3347
+ return {
3348
+ activityType: "a2ui-surface",
3349
+ content: A2UISurfaceContentSchema,
3350
+ render: ({ content, agent }) => {
3351
+ ensureInitialized();
3352
+ const [operations, setOperations] = useState([]);
3353
+ const { copilotkit } = useCopilotKit();
3354
+ const lastContentRef = useRef(null);
3355
+ useEffect(() => {
3356
+ if (content === lastContentRef.current) return;
3357
+ lastContentRef.current = content;
3358
+ const incoming = content?.[A2UI_OPERATIONS_KEY];
3359
+ if (!content || !Array.isArray(incoming)) {
3360
+ setOperations([]);
3361
+ return;
3362
+ }
3363
+ setOperations(incoming);
3364
+ }, [content]);
3365
+ const groupedOperations = useMemo(() => {
3366
+ const groups = /* @__PURE__ */ new Map();
3367
+ for (const operation of operations) {
3368
+ const surfaceId = getOperationSurfaceId(operation) ?? DEFAULT_SURFACE_ID;
3369
+ if (!groups.has(surfaceId)) groups.set(surfaceId, []);
3370
+ groups.get(surfaceId).push(operation);
3371
+ }
3372
+ return groups;
3373
+ }, [operations]);
3374
+ const hasOps = groupedOperations.size > 0;
3375
+ const renderLifecycle = (c) => {
3376
+ const status = c?.status;
3377
+ const debugExposure = resolveDebugExposure(c, optionDebugExposure);
3378
+ if (status === "failed") return /* @__PURE__ */ jsx(A2UIRecoveryFailure, {
3379
+ content: c,
3380
+ debugExposure
3381
+ });
3382
+ if (status === "retrying") return /* @__PURE__ */ jsx(A2UIRetryingState, {
3383
+ content: c,
3384
+ showAfterMs,
3385
+ showAfterAttempts,
3386
+ debugExposure
3387
+ });
3388
+ if (loadingComponent) return /* @__PURE__ */ jsx(loadingComponent, {});
3389
+ return /* @__PURE__ */ jsx(A2UIBuildingState, { content: c });
3390
+ };
3391
+ const lastLoaderContentRef = useRef(null);
3392
+ if (!(Array.isArray(content?.[A2UI_OPERATIONS_KEY]) && content[A2UI_OPERATIONS_KEY].length > 0)) lastLoaderContentRef.current = content;
3393
+ const [surfaceReady, setSurfaceReady] = useState(false);
3394
+ const readyRef = useRef(false);
3395
+ const markSurfaceReady = useCallback(() => {
3396
+ if (readyRef.current) return;
3397
+ readyRef.current = true;
3398
+ requestAnimationFrame(() => setSurfaceReady(true));
3399
+ }, []);
3400
+ useEffect(() => {
3401
+ if (!hasOps) {
3402
+ setSurfaceReady(false);
3403
+ readyRef.current = false;
3404
+ return;
3405
+ }
3406
+ const t = setTimeout(() => setSurfaceReady(true), 8e3);
3407
+ return () => clearTimeout(t);
3408
+ }, [hasOps]);
3409
+ if (!hasOps) return renderLifecycle(content);
3410
+ const surfaces = /* @__PURE__ */ jsx("div", {
3411
+ className: "cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6",
3412
+ children: Array.from(groupedOperations.entries()).map(([surfaceId, ops]) => /* @__PURE__ */ jsx(ReactSurfaceHost, {
3413
+ surfaceId,
3414
+ operations: ops,
3415
+ theme,
3416
+ agent,
3417
+ copilotkit,
3418
+ catalog,
3419
+ onReady: markSurfaceReady
3420
+ }, surfaceId))
3421
+ });
3422
+ return /* @__PURE__ */ jsxs("div", {
3423
+ style: { position: "relative" },
3424
+ children: [/* @__PURE__ */ jsx("div", {
3425
+ "aria-hidden": !surfaceReady,
3426
+ style: surfaceReady ? void 0 : {
3427
+ position: "absolute",
3428
+ inset: 0,
3429
+ opacity: 0,
3430
+ pointerEvents: "none"
3431
+ },
3432
+ children: surfaces
3433
+ }), !surfaceReady && renderLifecycle(lastLoaderContentRef.current ?? content)]
3434
+ });
3435
+ }
3436
+ };
3437
+ }
3438
+ /**
3439
+ * Renders a single A2UI surface using the React renderer.
3440
+ * Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
3441
+ */
3442
+ function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onReady }) {
3443
+ return /* @__PURE__ */ jsx("div", {
3444
+ className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
3445
+ children: /* @__PURE__ */ jsxs(A2UIProvider, {
3446
+ onAction: useCallback(async (message) => {
3447
+ if (!agent) return;
3448
+ message.userAction;
3449
+ try {
3450
+ copilotkit.setProperties({
3451
+ ...copilotkit.properties,
3452
+ a2uiAction: message
3453
+ });
3454
+ await copilotkit.runAgent({ agent });
3455
+ } finally {
3456
+ if (copilotkit.properties) {
3457
+ const { a2uiAction, ...rest } = copilotkit.properties;
3458
+ copilotkit.setProperties(rest);
3459
+ }
3460
+ }
3461
+ }, [agent, copilotkit]),
3462
+ theme,
3463
+ catalog,
3464
+ children: [/* @__PURE__ */ jsx(SurfaceMessageProcessor, {
3465
+ surfaceId,
3466
+ operations,
3467
+ onReady
3468
+ }), /* @__PURE__ */ jsx(A2UISurfaceOrError, { surfaceId })]
3469
+ })
3470
+ });
3471
+ }
3400
3472
  /**
3401
- * Registers the built-in `render_a2ui` tool call renderer via the props-based
3402
- * `setRenderToolCalls` mechanism (not `useRenderTool`).
3473
+ * Renders the A2UI surface, or an error message if processing failed.
3474
+ * Must be a child of A2UIProvider to access the error state.
3475
+ */
3476
+ function A2UISurfaceOrError({ surfaceId }) {
3477
+ const error = useA2UIError();
3478
+ if (error) return /* @__PURE__ */ jsxs("div", {
3479
+ className: "cpk:rounded-lg cpk:border cpk:border-red-200 cpk:bg-red-50 cpk:p-3 cpk:text-sm cpk:text-red-700",
3480
+ children: ["A2UI render error: ", error]
3481
+ });
3482
+ return /* @__PURE__ */ jsx(A2UIRenderer, {
3483
+ surfaceId,
3484
+ className: "cpk:flex cpk:flex-1"
3485
+ });
3486
+ }
3487
+ /**
3488
+ * Processes A2UI operations into the provider's message processor.
3489
+ * Must be a child of A2UIProvider to access the actions context.
3490
+ */
3491
+ function SurfaceMessageProcessor({ surfaceId, operations, onReady }) {
3492
+ const { processMessages, getSurface } = useA2UIActions();
3493
+ const lastHashRef = useRef("");
3494
+ useEffect(() => {
3495
+ const hash = JSON.stringify(operations);
3496
+ if (hash === lastHashRef.current) return;
3497
+ lastHashRef.current = hash;
3498
+ processMessages(getSurface(surfaceId) ? operations.filter((op) => !op?.createSurface) : operations);
3499
+ if (onReady && surfaceHasRenderableContent(operations)) onReady();
3500
+ }, [
3501
+ processMessages,
3502
+ getSurface,
3503
+ surfaceId,
3504
+ operations,
3505
+ onReady
3506
+ ]);
3507
+ return null;
3508
+ }
3509
+ /**
3510
+ * Whether the surface's operations are enough to paint a visible card yet.
3511
+ * A data-bound surface references its data via `path` and renders nothing until
3512
+ * the data model has ≥1 value; a static surface (no path refs) paints from its
3513
+ * components alone. Used to time the loader→surface cross-over to actual content
3514
+ * arrival rather than a fixed delay. (OSS-162)
3515
+ */
3516
+ function surfaceHasRenderableContent(operations) {
3517
+ const componentOps = operations.filter((o) => o?.updateComponents);
3518
+ if (!componentOps.length) return false;
3519
+ if (!JSON.stringify(componentOps).includes("\"path\"")) return true;
3520
+ return operations.some((o) => {
3521
+ const v = o?.updateDataModel?.value;
3522
+ if (!v || typeof v !== "object") return false;
3523
+ return Object.values(v).some((x) => Array.isArray(x) ? x.length > 0 : x !== null && x !== void 0 && x !== "");
3524
+ });
3525
+ }
3526
+ function getOperationSurfaceId(operation) {
3527
+ if (!operation || typeof operation !== "object") return null;
3528
+ if (typeof operation.surfaceId === "string") return operation.surfaceId;
3529
+ return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
3530
+ }
3531
+
3532
+ //#endregion
3533
+ //#region src/v2/a2ui/A2UIToolCallRenderer.tsx
3534
+ /**
3535
+ * Tool name used by the dynamic A2UI generation secondary LLM.
3536
+ */
3537
+ const RENDER_A2UI_TOOL_NAME = "render_a2ui";
3538
+ /**
3539
+ * Registers a no-op renderer for the `render_a2ui` tool call so its raw streamed
3540
+ * args are never surfaced in the transcript.
3403
3541
  *
3404
- * This ensures user-registered `useRenderTool({ name: "render_a2ui", ... })`
3405
- * hooks automatically override the built-in, since the merge logic in
3406
- * react-core.ts gives hook-based entries priority over prop-based entries.
3542
+ * The generation skeleton / retry / failure UX is NO LONGER owned here (OSS-162):
3543
+ * the A2UI middleware drives the whole lifecycle on the `a2ui-surface` activity
3544
+ * (one stable messageId, building retrying failed → painted), rendered in
3545
+ * place by `createA2UIMessageRenderer`. Owning a skeleton per tool call caused a
3546
+ * duplicate skeleton on retries / multi-call generations and a skeleton that
3547
+ * lingered after the surface painted — both fixed by retiring it here.
3548
+ *
3549
+ * Users can still override with their own `useRenderTool({ name: "render_a2ui" })`
3550
+ * (hook-based entries take priority over this prop-based registration).
3407
3551
  */
3408
3552
  function A2UIBuiltInToolCallRenderer() {
3409
3553
  const { copilotkit } = useCopilotKit();
@@ -3411,15 +3555,7 @@ function A2UIBuiltInToolCallRenderer() {
3411
3555
  const renderer = defineToolCallRenderer({
3412
3556
  name: RENDER_A2UI_TOOL_NAME,
3413
3557
  args: z.any(),
3414
- render: ({ status, args: parameters }) => {
3415
- if (status === "complete") return /* @__PURE__ */ jsx(Fragment$1, {});
3416
- const params = parameters;
3417
- const items = params?.items;
3418
- if (Array.isArray(items) && items.length > 0) return /* @__PURE__ */ jsx(Fragment$1, {});
3419
- const components = params?.components;
3420
- if (Array.isArray(components) && components.length > 2) return /* @__PURE__ */ jsx(Fragment$1, {});
3421
- return /* @__PURE__ */ jsx(A2UIProgressIndicator, { parameters });
3422
- }
3558
+ render: () => /* @__PURE__ */ jsx(Fragment$1, {})
3423
3559
  });
3424
3560
  const existing = copilotkit._renderToolCalls ?? [];
3425
3561
  copilotkit.setRenderToolCalls([...existing.filter((rc) => rc.name !== RENDER_A2UI_TOOL_NAME), renderer]);
@@ -3556,7 +3692,8 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = EMPTY
3556
3692
  if (runtimeA2UIEnabled) renderers.unshift(createA2UIMessageRenderer({
3557
3693
  theme: a2ui?.theme ?? viewerTheme,
3558
3694
  catalog: a2ui?.catalog,
3559
- loadingComponent: a2ui?.loadingComponent
3695
+ loadingComponent: a2ui?.loadingComponent,
3696
+ recovery: a2ui?.recovery
3560
3697
  }));
3561
3698
  return renderers;
3562
3699
  }, [
@@ -10527,4 +10664,4 @@ function validateProps(props) {
10527
10664
 
10528
10665
  //#endregion
10529
10666
  export { useHumanInTheLoop as $, INTELLIGENCE_TURN_HEAD as A, CopilotChatToolCallsView as B, CopilotChatToggleButton as C, useCopilotChatConfiguration as Ct, CopilotChatView_default as D, CopilotChat as E, CopilotChatSuggestionPill as F, useLearnFromUserAction as G, useLearningContainers as H, CopilotChatReasoningMessage_default as I, useConfigureSuggestions as J, useThreads$1 as K, CopilotChatUserMessage_default as L, getIntelligenceTurnAnchors as M, IntelligenceIndicatorView as N, CopilotChatAttachmentQueue as O, CopilotChatSuggestionView as P, useAgent as Q, CopilotChatAttachmentRenderer as R, CopilotModalHeader as S, CopilotChatConfigurationProvider as St, DefaultOpenIcon as T, useAttachments as U, useLearningContainersInCurrentThread as V, useLearnFromUserActionInCurrentThread as W, useCapabilities as X, useSuggestions as Y, UseAgentUpdate as Z, WildcardToolCallRender as _, useCopilotKit as _t, ThreadsProvider as a, useAgentContext as at, CopilotPopupView as b, AudioRecorderError as bt, CoAgentStateRendersProvider as c, useSandboxFunctions as ct, shouldShowDevConsole as d, MCPAppsActivityType as dt, useComponent as et, useToast as f, CopilotKitInspector as ft, useCopilotContext as g, defineToolCallRenderer as gt, CopilotContext as h, useRenderTool as ht, ThreadsContext as i, CopilotKitProvider as it, IntelligenceIndicator as j, CopilotChatMessageView as k, useCoAgentStateRenders as l, MCPAppsActivityContentSchema as lt, useCopilotMessagesContext as m, useDefaultRenderTool as mt, defaultCopilotContextCategories as n, useRenderActivityMessage as nt, useThreads as o, createA2UIMessageRenderer as ot, CopilotMessagesContext as p, useRenderToolCall as pt, useInterrupt as q, CoAgentStateRenderBridge as r, useRenderCustomMessages as rt, CoAgentStateRendersContext as s, SandboxFunctionsContext as st, CopilotKit as t, useFrontendTool as tt, useAsyncCallback as u, MCPAppsActivityRenderer as ut, CopilotPopup as v, CopilotKitCoreReact as vt, DefaultCloseIcon as w, CopilotSidebarView as x, CopilotChatAudioRecorder as xt, CopilotSidebar as y, CopilotChatInput_default as yt, CopilotChatAssistantMessage_default as z };
10530
- //# sourceMappingURL=copilotkit-DoIlZQqa.mjs.map
10667
+ //# sourceMappingURL=copilotkit-DEGlMWM0.mjs.map