@flamingo-stack/openframe-frontend-core 0.0.511 → 0.0.512-1640.4209.1
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/{chunk-IXCBVJRU.cjs → chunk-4GAVZKHG.cjs} +9 -9
- package/dist/{chunk-IXCBVJRU.cjs.map → chunk-4GAVZKHG.cjs.map} +1 -1
- package/dist/{chunk-RXFBW2EJ.cjs → chunk-534P3NJ3.cjs} +7 -7
- package/dist/{chunk-RXFBW2EJ.cjs.map → chunk-534P3NJ3.cjs.map} +1 -1
- package/dist/{chunk-X7AJ3J42.js → chunk-6ETOEANJ.js} +362 -215
- package/dist/chunk-6ETOEANJ.js.map +1 -0
- package/dist/{chunk-TNZOUHHN.js → chunk-6QPWXKUM.js} +4 -4
- package/dist/{chunk-ZSIEM7CL.js → chunk-76ZIKD4J.js} +2 -2
- package/dist/{chunk-NNWSGOUP.js → chunk-A7MD5U35.js} +2 -2
- package/dist/{chunk-LEWQRAZ4.cjs → chunk-CY7M2OSZ.cjs} +31 -31
- package/dist/{chunk-LEWQRAZ4.cjs.map → chunk-CY7M2OSZ.cjs.map} +1 -1
- package/dist/{chunk-OMN7A6RP.cjs → chunk-EEGK4TEH.cjs} +26 -26
- package/dist/{chunk-OMN7A6RP.cjs.map → chunk-EEGK4TEH.cjs.map} +1 -1
- package/dist/{chunk-IUZMWMVX.cjs → chunk-EJIOXYJ2.cjs} +61 -61
- package/dist/{chunk-IUZMWMVX.cjs.map → chunk-EJIOXYJ2.cjs.map} +1 -1
- package/dist/{chunk-PRMR6WKC.js → chunk-EQRNQWXA.js} +2 -2
- package/dist/{chunk-RU3SCECX.js → chunk-FBW47BZ7.js} +2 -2
- package/dist/{chunk-PXQQFRUD.cjs → chunk-FOTOJSBJ.cjs} +5 -5
- package/dist/{chunk-PXQQFRUD.cjs.map → chunk-FOTOJSBJ.cjs.map} +1 -1
- package/dist/{chunk-C4EUXZSA.cjs → chunk-GCPMAP2K.cjs} +3 -3
- package/dist/{chunk-C4EUXZSA.cjs.map → chunk-GCPMAP2K.cjs.map} +1 -1
- package/dist/{chunk-YGS7BLSN.js → chunk-HJSWBSMO.js} +2 -2
- package/dist/{chunk-LVAJK2U2.js → chunk-JIRDHSAM.js} +2 -2
- package/dist/{chunk-7YV67K3I.cjs → chunk-LJXROUP3.cjs} +87 -87
- package/dist/{chunk-7YV67K3I.cjs.map → chunk-LJXROUP3.cjs.map} +1 -1
- package/dist/{chunk-TYVHM67X.js → chunk-LTABGSW6.js} +5 -5
- package/dist/{chunk-NKA3O4L6.js → chunk-MO647IKL.js} +2 -2
- package/dist/{chunk-ZBQV7WH7.js → chunk-MPAISYAF.js} +2 -2
- package/dist/{chunk-U4WPFX5K.cjs → chunk-ONAGMSOD.cjs} +26 -26
- package/dist/{chunk-U4WPFX5K.cjs.map → chunk-ONAGMSOD.cjs.map} +1 -1
- package/dist/{chunk-TR7AMHGB.js → chunk-PE4CBJUE.js} +6 -6
- package/dist/{chunk-A5YZUV6B.cjs → chunk-PSYNV2VB.cjs} +11 -11
- package/dist/{chunk-A5YZUV6B.cjs.map → chunk-PSYNV2VB.cjs.map} +1 -1
- package/dist/{chunk-J4VB4EHW.js → chunk-U5F5PAWV.js} +4 -4
- package/dist/{chunk-GHXTF35X.cjs → chunk-VFFEZ66K.cjs} +353 -206
- package/dist/chunk-VFFEZ66K.cjs.map +1 -0
- package/dist/{chunk-JXMNLH7F.js → chunk-VQQBYAKR.js} +2 -2
- package/dist/{chunk-DPLXHG7H.cjs → chunk-XEBFFFDB.cjs} +37 -37
- package/dist/{chunk-DPLXHG7H.cjs.map → chunk-XEBFFFDB.cjs.map} +1 -1
- package/dist/{chunk-2CE725NN.cjs → chunk-Y3VWQEFO.cjs} +13 -13
- package/dist/{chunk-2CE725NN.cjs.map → chunk-Y3VWQEFO.cjs.map} +1 -1
- package/dist/{chunk-4SG55XVA.cjs → chunk-ZMC4WIBZ.cjs} +4 -4
- package/dist/{chunk-4SG55XVA.cjs.map → chunk-ZMC4WIBZ.cjs.map} +1 -1
- package/dist/components/case-studies/index.cjs +8 -8
- package/dist/components/case-studies/index.js +2 -2
- package/dist/components/chat/entity-cards/deleted-data-card.d.ts +27 -0
- package/dist/components/chat/entity-cards/deleted-data-card.d.ts.map +1 -0
- package/dist/components/chat/entity-cards/dispatch.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-chat.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +2 -2
- package/dist/components/chat/index.js +1 -1
- package/dist/components/contact/index.cjs +3 -3
- package/dist/components/contact/index.js +2 -2
- package/dist/components/docs/index.cjs +5 -5
- package/dist/components/docs/index.js +4 -4
- package/dist/components/embeds/index.cjs +3 -3
- package/dist/components/embeds/index.js +2 -2
- package/dist/components/faq/index.cjs +3 -3
- package/dist/components/faq/index.js +2 -2
- package/dist/components/features/index.cjs +2 -2
- package/dist/components/features/index.js +1 -1
- package/dist/components/help-center-pages/index.cjs +22 -22
- package/dist/components/help-center-pages/index.js +13 -13
- package/dist/components/index.cjs +132 -132
- package/dist/components/index.js +11 -11
- package/dist/components/meeting-scheduler/index.cjs +34 -34
- package/dist/components/meeting-scheduler/index.js +3 -3
- package/dist/components/navigation/index.cjs +2 -2
- package/dist/components/navigation/index.js +1 -1
- package/dist/components/onboarding-guides/index.cjs +5 -5
- package/dist/components/onboarding-guides/index.js +4 -4
- package/dist/components/related-content/index.cjs +3 -3
- package/dist/components/related-content/index.js +2 -2
- package/dist/components/tickets/index.cjs +6 -6
- package/dist/components/tickets/index.js +5 -5
- package/dist/components/ui/index.cjs +2 -2
- package/dist/components/ui/index.js +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/chat/entity-cards/deleted-data-card.tsx +61 -0
- package/src/components/chat/entity-cards/dispatch.tsx +17 -0
- package/src/components/chat/hooks/use-chat.ts +174 -15
- package/dist/chunk-GHXTF35X.cjs.map +0 -1
- package/dist/chunk-X7AJ3J42.js.map +0 -1
- /package/dist/{chunk-TNZOUHHN.js.map → chunk-6QPWXKUM.js.map} +0 -0
- /package/dist/{chunk-ZSIEM7CL.js.map → chunk-76ZIKD4J.js.map} +0 -0
- /package/dist/{chunk-NNWSGOUP.js.map → chunk-A7MD5U35.js.map} +0 -0
- /package/dist/{chunk-PRMR6WKC.js.map → chunk-EQRNQWXA.js.map} +0 -0
- /package/dist/{chunk-RU3SCECX.js.map → chunk-FBW47BZ7.js.map} +0 -0
- /package/dist/{chunk-YGS7BLSN.js.map → chunk-HJSWBSMO.js.map} +0 -0
- /package/dist/{chunk-LVAJK2U2.js.map → chunk-JIRDHSAM.js.map} +0 -0
- /package/dist/{chunk-TYVHM67X.js.map → chunk-LTABGSW6.js.map} +0 -0
- /package/dist/{chunk-NKA3O4L6.js.map → chunk-MO647IKL.js.map} +0 -0
- /package/dist/{chunk-ZBQV7WH7.js.map → chunk-MPAISYAF.js.map} +0 -0
- /package/dist/{chunk-TR7AMHGB.js.map → chunk-PE4CBJUE.js.map} +0 -0
- /package/dist/{chunk-J4VB4EHW.js.map → chunk-U5F5PAWV.js.map} +0 -0
- /package/dist/{chunk-JXMNLH7F.js.map → chunk-VQQBYAKR.js.map} +0 -0
|
@@ -11,8 +11,10 @@
|
|
|
11
11
|
import { useState, useCallback, useEffect, useRef } from 'react'
|
|
12
12
|
import { useSSE, type StreamFn, type StreamFnExtraOptions } from './use-sse'
|
|
13
13
|
import type {
|
|
14
|
+
ApprovalBatchSegment,
|
|
14
15
|
Message,
|
|
15
16
|
MessageSegment,
|
|
17
|
+
PendingToolCallData,
|
|
16
18
|
ToolExecutionData,
|
|
17
19
|
} from '../types/message.types'
|
|
18
20
|
import { buildChatRefKey } from '../types/chat.types'
|
|
@@ -256,12 +258,136 @@ export function useChat({
|
|
|
256
258
|
{ hidden: true },
|
|
257
259
|
)
|
|
258
260
|
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
261
|
+
// ── BATCH COALESCING ────────────────────────────────────
|
|
262
|
+
// One assistant turn can propose N tool calls (§2a batch
|
|
263
|
+
// operations — "delete both", "close all three"). N stacked
|
|
264
|
+
// cards force N Approve clicks; consecutive proposals in the
|
|
265
|
+
// SAME turn coalesce into ONE `approval_batch` (the bulk-
|
|
266
|
+
// approval component) whose single Approve/Reject resolves
|
|
267
|
+
// every proposal sequentially through the same per-proposal
|
|
268
|
+
// confirm endpoint. `decision_resolved` frames then tick the
|
|
269
|
+
// batch's per-row execution icons (see the handler below).
|
|
270
|
+
const toToolCall = (d: Record<string, any>): PendingToolCallData => {
|
|
271
|
+
const fields = Array.isArray(d?.fields)
|
|
272
|
+
? (d.fields as Array<{ label: string; value: string }>)
|
|
273
|
+
: []
|
|
274
|
+
const detailField =
|
|
275
|
+
fields.find((f) => /^(title|subject|task|name)$/i.test(f.label)) ?? fields[0]
|
|
276
|
+
const base = typeof d?.command === 'string' && d.command ? d.command : 'Tool call'
|
|
277
|
+
return {
|
|
278
|
+
toolExecutionRequestId: String(d?.requestId ?? ''),
|
|
279
|
+
toolName: String(d?.approvalType ?? 'tool'),
|
|
280
|
+
toolTitle: detailField ? `${base} — ${detailField.value}` : base,
|
|
281
|
+
requiresApproval: true,
|
|
282
|
+
// Field rows become the expandable args block so the
|
|
283
|
+
// per-proposal detail from the single-card view stays
|
|
284
|
+
// reachable inside the batch.
|
|
285
|
+
toolCallArguments:
|
|
286
|
+
fields.length > 0
|
|
287
|
+
? Object.fromEntries(fields.map((f) => [f.label, f.value]))
|
|
288
|
+
: null,
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// Anchor a batch by its FIRST proposal id (stable across row
|
|
292
|
+
// appends); handlers derive the id list from the rows so no
|
|
293
|
+
// side-channel state is needed.
|
|
294
|
+
const makeBatchHandlers = (anchorId: string) => {
|
|
295
|
+
const findBatch = (
|
|
296
|
+
segments: MessageSegment[],
|
|
297
|
+
): ApprovalBatchSegment | undefined =>
|
|
298
|
+
segments.find(
|
|
299
|
+
(s): s is ApprovalBatchSegment =>
|
|
300
|
+
s.type === 'approval_batch' && s.data.approvalRequestId === anchorId,
|
|
301
|
+
)
|
|
302
|
+
const setBatchStatus = (status: 'approved' | 'rejected') => {
|
|
303
|
+
setMessages((prev) => {
|
|
304
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
305
|
+
const m = prev[i]
|
|
306
|
+
if (m.role !== 'assistant' || !Array.isArray(m.content)) continue
|
|
307
|
+
const segments = m.content as MessageSegment[]
|
|
308
|
+
if (!findBatch(segments)) continue
|
|
309
|
+
const next = [...prev]
|
|
310
|
+
next[i] = {
|
|
311
|
+
...m,
|
|
312
|
+
content: segments.map((s) =>
|
|
313
|
+
s.type === 'approval_batch' && s.data.approvalRequestId === anchorId
|
|
314
|
+
? { ...s, status }
|
|
315
|
+
: s,
|
|
316
|
+
),
|
|
317
|
+
}
|
|
318
|
+
return next
|
|
319
|
+
}
|
|
320
|
+
return prev
|
|
321
|
+
})
|
|
322
|
+
}
|
|
323
|
+
const act = (action: 'approve' | 'reject') => async () => {
|
|
324
|
+
// Read the CURRENT row set from state (rows may have been
|
|
325
|
+
// appended after this handler was created).
|
|
326
|
+
let ids: string[] = []
|
|
327
|
+
setMessages((prev) => {
|
|
328
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
329
|
+
const m = prev[i]
|
|
330
|
+
if (m.role !== 'assistant' || !Array.isArray(m.content)) continue
|
|
331
|
+
const batch = findBatch(m.content as MessageSegment[])
|
|
332
|
+
if (batch) {
|
|
333
|
+
ids = batch.data.toolCalls.map((c) => c.toolExecutionRequestId)
|
|
334
|
+
break
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return prev
|
|
338
|
+
})
|
|
339
|
+
// Optimistic status flip so per-row execution loaders show
|
|
340
|
+
// while the sequential confirms run.
|
|
341
|
+
setBatchStatus(action === 'approve' ? 'approved' : 'rejected')
|
|
342
|
+
for (const id of ids) {
|
|
343
|
+
await sendMessage(
|
|
344
|
+
'',
|
|
345
|
+
{ approvalAction: { proposalId: id, action } },
|
|
346
|
+
{ hidden: true },
|
|
347
|
+
)
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return { onApprove: act('approve'), onReject: act('reject') }
|
|
351
|
+
}
|
|
352
|
+
const liveSegments = [...currentAssistantSegmentsRef.current]
|
|
353
|
+
const lastSeg = liveSegments[liveSegments.length - 1] as any
|
|
354
|
+
if (lastSeg && lastSeg.type === 'approval_batch' && (lastSeg.status ?? 'pending') === 'pending') {
|
|
355
|
+
// Third-or-later proposal of the turn — append a row.
|
|
356
|
+
liveSegments[liveSegments.length - 1] = {
|
|
357
|
+
...lastSeg,
|
|
358
|
+
data: {
|
|
359
|
+
...lastSeg.data,
|
|
360
|
+
toolCalls: [...lastSeg.data.toolCalls, toToolCall(seg.data)],
|
|
361
|
+
},
|
|
362
|
+
}
|
|
363
|
+
} else if (
|
|
364
|
+
lastSeg &&
|
|
365
|
+
lastSeg.type === 'approval_request' &&
|
|
366
|
+
(lastSeg.status ?? 'pending') === 'pending'
|
|
367
|
+
) {
|
|
368
|
+
// Second proposal of the turn — convert card + card → batch.
|
|
369
|
+
const anchorId = String(lastSeg.data?.requestId ?? proposalId)
|
|
370
|
+
liveSegments[liveSegments.length - 1] = {
|
|
371
|
+
type: 'approval_batch',
|
|
372
|
+
status: 'pending',
|
|
373
|
+
data: {
|
|
374
|
+
approvalRequestId: anchorId,
|
|
375
|
+
approvalType: 'chat',
|
|
376
|
+
toolCalls: [toToolCall(lastSeg.data), toToolCall(seg.data)],
|
|
377
|
+
executions: {},
|
|
378
|
+
},
|
|
379
|
+
...makeBatchHandlers(anchorId),
|
|
380
|
+
} as ApprovalBatchSegment
|
|
381
|
+
} else {
|
|
382
|
+
// Single proposal — the existing per-card flow.
|
|
383
|
+
liveSegments.push({
|
|
384
|
+
...seg,
|
|
385
|
+
onApprove: wrappedApprove,
|
|
386
|
+
onReject: wrappedReject,
|
|
387
|
+
})
|
|
388
|
+
}
|
|
389
|
+
currentAssistantSegmentsRef.current = liveSegments
|
|
390
|
+
updateLastAssistantMessage([...liveSegments])
|
|
265
391
|
} else if ((segment as any).type === 'decision_resolved') {
|
|
266
392
|
// Server-driven decision frame from /api/chat/agent/confirm-tool.
|
|
267
393
|
//
|
|
@@ -305,7 +431,12 @@ export function useChat({
|
|
|
305
431
|
willAutoContinue?: boolean
|
|
306
432
|
}
|
|
307
433
|
if (!decision.proposalId) continue
|
|
308
|
-
// Step 1 — flip the source card's status.
|
|
434
|
+
// Step 1 — flip the source card's status. Two shapes can host
|
|
435
|
+
// the proposal: a standalone `approval_request` card (status
|
|
436
|
+
// flip), or an `approval_batch` row (batch status was flipped
|
|
437
|
+
// optimistically at click time — here we tick the row's
|
|
438
|
+
// per-tool execution icon: check on approved, cross on a
|
|
439
|
+
// failed approve).
|
|
309
440
|
setMessages((prev) => {
|
|
310
441
|
for (let i = prev.length - 1; i >= 0; i--) {
|
|
311
442
|
const m = prev[i]
|
|
@@ -314,16 +445,44 @@ export function useChat({
|
|
|
314
445
|
const segments = m.content as MessageSegment[]
|
|
315
446
|
const hasMatch = segments.some(
|
|
316
447
|
(s) =>
|
|
317
|
-
(s as any).type === 'approval_request' &&
|
|
318
|
-
|
|
448
|
+
((s as any).type === 'approval_request' &&
|
|
449
|
+
(s as any).data?.requestId === decision.proposalId) ||
|
|
450
|
+
((s as any).type === 'approval_batch' &&
|
|
451
|
+
(s as any).data?.toolCalls?.some(
|
|
452
|
+
(c: any) => c?.toolExecutionRequestId === decision.proposalId,
|
|
453
|
+
)),
|
|
319
454
|
)
|
|
320
455
|
if (!hasMatch) continue
|
|
321
|
-
const flipped = segments.map((s) =>
|
|
322
|
-
(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
456
|
+
const flipped = segments.map((s) => {
|
|
457
|
+
if (
|
|
458
|
+
(s as any).type === 'approval_request' &&
|
|
459
|
+
(s as any).data?.requestId === decision.proposalId
|
|
460
|
+
) {
|
|
461
|
+
return { ...(s as any), status: decision.action } as MessageSegment
|
|
462
|
+
}
|
|
463
|
+
if (
|
|
464
|
+
(s as any).type === 'approval_batch' &&
|
|
465
|
+
(s as any).data?.toolCalls?.some(
|
|
466
|
+
(c: any) => c?.toolExecutionRequestId === decision.proposalId,
|
|
467
|
+
)
|
|
468
|
+
) {
|
|
469
|
+
const batch = s as any
|
|
470
|
+
return {
|
|
471
|
+
...batch,
|
|
472
|
+
data: {
|
|
473
|
+
...batch.data,
|
|
474
|
+
executions: {
|
|
475
|
+
...(batch.data.executions ?? {}),
|
|
476
|
+
[decision.proposalId as string]: {
|
|
477
|
+
status: 'done',
|
|
478
|
+
success: decision.action === 'approved' ? decision.ok : false,
|
|
479
|
+
},
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
} as MessageSegment
|
|
483
|
+
}
|
|
484
|
+
return s
|
|
485
|
+
})
|
|
327
486
|
const next = [...prev]
|
|
328
487
|
next[i] = { ...m, content: flipped }
|
|
329
488
|
return next
|