spine-framework-portal 0.2.25 → 0.2.27

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.
@@ -79,7 +79,11 @@ async function handleNewTicket(
79
79
  const agentMsg = await runAgent(threadRecord.id, message, ctx)
80
80
 
81
81
  const confidence = agentMsg?.data?.confidence ?? 0
82
- const escalated = agentMsg?.data?.escalated ?? false
82
+ // Derive escalated from confidence vs threshold — don't rely solely on the
83
+ // message data field, which may not be set if running an older framework build.
84
+ const { data: pcRow } = await adminDb.from('prompt_configs').select('confidence_threshold').eq('id', promptConfigId).single()
85
+ const threshold = pcRow?.confidence_threshold ?? 0.75
86
+ const escalated = agentMsg?.data?.escalated ?? (confidence < threshold)
83
87
 
84
88
  // 4. Backfill suggested title if agent produced one, and stamp confidence/status
85
89
  const suggestedTitle = agentMsg?.data?.suggested_title || message.slice(0, 80)
@@ -122,7 +126,9 @@ async function handleReply(
122
126
  const agentMsg = await runAgent(thread_id, message, ctx)
123
127
 
124
128
  const confidence = agentMsg?.data?.confidence ?? 0
125
- const escalated = agentMsg?.data?.escalated ?? false
129
+ const { data: pcRow2 } = await adminDb.from('prompt_configs').select('confidence_threshold').eq('id', _ids.promptConfigId).single()
130
+ const threshold2 = pcRow2?.confidence_threshold ?? 0.75
131
+ const escalated = agentMsg?.data?.escalated ?? (confidence < threshold2)
126
132
 
127
133
  if (escalated) {
128
134
  const { data: currentTicket } = await adminDb
@@ -177,18 +177,8 @@ export function useSubmitFeedback() {
177
177
  setLoading(true)
178
178
  setError(null)
179
179
  try {
180
- // Update message data with feedback
181
- await fetchJSON(`/.netlify/functions/admin-data?entity=messages&id=${messageId}`, {
182
- method: 'PATCH',
183
- body: JSON.stringify({
184
- data: {
185
- feedback,
186
- feedback_at: new Date().toISOString()
187
- }
188
- }),
189
- })
190
-
191
- // Best-effort: record feedback in the core ai-interactions log
180
+ // Route through ai-interactions which safely merges data fields and
181
+ // handles not_helpful → human_assigned escalation server-side.
192
182
  await fetchJSON('/.netlify/functions/ai-interactions', {
193
183
  method: 'POST',
194
184
  body: JSON.stringify({
@@ -197,21 +187,7 @@ export function useSubmitFeedback() {
197
187
  ticket_id: ticketId,
198
188
  feedback: feedback === 'up' ? 'helpful' : 'not_helpful',
199
189
  }),
200
- }).catch(() => null) // best-effort — don't fail the feedback submission if this fails
201
-
202
- // If thumbs down, escalate to human
203
- if (feedback === 'down') {
204
- await fetchJSON(`/.netlify/functions/admin-data?entity=items&id=${ticketId}`, {
205
- method: 'PATCH',
206
- body: JSON.stringify({
207
- data: {
208
- status: 'human_assigned',
209
- aim_escalation_reason: 'thumbs_down'
210
- }
211
- }),
212
- })
213
- }
214
-
190
+ })
215
191
  return { success: true }
216
192
  } catch (e: any) {
217
193
  setError(e.message)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework-portal",
3
- "version": "0.2.25",
3
+ "version": "0.2.27",
4
4
  "private": false,
5
5
  "description": "Customer Portal — self-service portal app for Spine Framework",
6
6
  "type": "module",
@@ -144,8 +144,8 @@ function TicketThread({ ticketId, ticketStatus, onStatusChange }: TicketThreadPr
144
144
  }
145
145
 
146
146
  return (
147
- <div className="flex flex-col h-full">
148
- <ScrollArea className="flex-1 p-4">
147
+ <div className="flex flex-col h-full overflow-hidden">
148
+ <ScrollArea className="flex-1 min-h-0 p-4">
149
149
  <div className="space-y-3">
150
150
  {/* AI State Indicator */}
151
151
  {aiState === 'analyzing' && (
@@ -246,7 +246,7 @@ function DraftTicketView({ onClose, onCreated }: { onClose: () => void; onCreate
246
246
  }
247
247
 
248
248
  return (
249
- <div className="flex flex-col h-full">
249
+ <div className="flex flex-col h-full overflow-hidden">
250
250
  {/* Header — mirrors existing ticket header style */}
251
251
  <div className="px-6 py-3 border-b border-border flex items-center justify-between shrink-0">
252
252
  <div>
@@ -257,7 +257,7 @@ function DraftTicketView({ onClose, onCreated }: { onClose: () => void; onCreate
257
257
  </div>
258
258
 
259
259
  {/* Thread area */}
260
- <ScrollArea className="flex-1 p-4">
260
+ <ScrollArea className="flex-1 min-h-0 p-4">
261
261
  <div className="space-y-3">
262
262
  {draftMessages.length === 0 && (
263
263
  <p className="text-sm text-muted-foreground italic text-center py-8">Describe your issue and our AI will respond immediately.</p>
@@ -353,14 +353,9 @@ export function TicketsPage() {
353
353
 
354
354
  const handleStatusChange = useCallback(async (newStatus: string) => {
355
355
  if (!selectedId) return
356
- await updateTicket(selectedId, {
357
- data: {
358
- status: newStatus,
359
- aim_escalation_at: new Date().toISOString()
360
- }
361
- })
356
+ await updateTicket(selectedId, { status: newStatus })
362
357
  refetch()
363
- }, [selectedId, selectedTicket, updateTicket, refetch])
358
+ }, [selectedId, updateTicket, refetch])
364
359
 
365
360
  return (
366
361
  <div className="flex flex-col h-full">