| 1 |
import { useChatStore } from '@agent/state/chat'; |
| 2 |
import { useGlobalStore } from '@agent/state/global'; |
| 3 |
import { useWorkflowStore } from '@agent/state/workflows'; |
| 4 |
import { tools } from '@agent/workflows/workflows'; |
| 5 |
import { AI_HOST } from '@constants'; |
| 6 |
import { digest } from '@shared/api/digest'; |
| 7 |
import { reqDataBasics } from '@shared/lib/data'; |
| 8 |
|
| 9 |
const extra = () => { |
| 10 |
const { x, y, width, height } = useGlobalStore.getState(); |
| 11 |
return { |
| 12 |
userAgent: window?.navigator?.userAgent, |
| 13 |
vendor: window?.navigator?.vendor || 'unknown', |
| 14 |
platform: |
| 15 |
window?.navigator?.userAgentData?.platform || |
| 16 |
window?.navigator?.platform || |
| 17 |
'unknown', |
| 18 |
mobile: window?.navigator?.userAgentData?.mobile, |
| 19 |
width: window.innerWidth, |
| 20 |
height: window.innerHeight, |
| 21 |
screenHeight: window.screen.height, |
| 22 |
screenWidth: window.screen.width, |
| 23 |
orientation: window.screen.orientation?.type, |
| 24 |
touchSupport: 'ontouchstart' in window || navigator.maxTouchPoints > 0, |
| 25 |
agentUI: { x, y, width, height }, |
| 26 |
}; |
| 27 |
}; |
| 28 |
|
| 29 |
export const pickWorkflow = async ({ workflows, options }) => { |
| 30 |
const { failedWorkflows, context } = window.extAgentData; |
| 31 |
const failed = failedWorkflows ?? new Set(); |
| 32 |
const filteredWorkflows = workflows.filter((wf) => !failed.has(wf.id)); |
| 33 |
|
| 34 |
const { workflowHistory: pastWorkflows, block } = useWorkflowStore.getState(); |
| 35 |
|
| 36 |
const messages = useChatStore.getState().getMessagesForAI(); |
| 37 |
const lastAssistantMessage = useChatStore |
| 38 |
.getState() |
| 39 |
.getLastAssistantMessage(); |
| 40 |
|
| 41 |
const response = await fetch(`${AI_HOST}/api/agent/find-agent`, { |
| 42 |
method: 'POST', |
| 43 |
headers: { 'Content-Type': 'application/json' }, |
| 44 |
signal: options?.signal, |
| 45 |
body: JSON.stringify({ |
| 46 |
...reqDataBasics, |
| 47 |
workflows: filteredWorkflows, |
| 48 |
previousAgentName: pastWorkflows.at(0)?.agentName, |
| 49 |
previousWorkflow: { |
| 50 |
lastMessage: lastAssistantMessage?.details?.content, |
| 51 |
sessionId: lastAssistantMessage?.details?.sessionId, |
| 52 |
...pastWorkflows?.at(0), |
| 53 |
}, |
| 54 |
context, |
| 55 |
agentContext: window.extAgentData.agentContext, |
| 56 |
messages: messages.slice(-5), |
| 57 |
hasBlock: Boolean(block), // todo: remove this |
| 58 |
blockDetails: block, |
| 59 |
...options, |
| 60 |
extra: extra(), |
| 61 |
}), |
| 62 |
}); |
| 63 |
|
| 64 |
if (!response.ok) { |
| 65 |
digest({ |
| 66 |
error: { |
| 67 |
name: response.statusText, |
| 68 |
messages: response.statusMessage, |
| 69 |
}, |
| 70 |
details: { source: 'agent', caller: 'pick-workflow' }, |
| 71 |
}); |
| 72 |
const error = new Error('Bad response from server'); |
| 73 |
error.response = response; |
| 74 |
throw error; |
| 75 |
} |
| 76 |
return await response.json(); |
| 77 |
}; |
| 78 |
|
| 79 |
export const handleWorkflow = async ({ workflow, workflowData, options }) => { |
| 80 |
const messages = useChatStore.getState().getMessagesForAI(); |
| 81 |
const response = await fetch(`${AI_HOST}/api/agent/handle-workflow`, { |
| 82 |
method: 'POST', |
| 83 |
headers: { 'Content-Type': 'application/json' }, |
| 84 |
signal: options?.signal, |
| 85 |
body: JSON.stringify({ |
| 86 |
...reqDataBasics, |
| 87 |
workflow, |
| 88 |
workflowData, |
| 89 |
messages: messages, |
| 90 |
context: window.extAgentData.context, |
| 91 |
agentContext: window.extAgentData.agentContext, |
| 92 |
retry: options?.retry || false, |
| 93 |
extra: extra(), |
| 94 |
}), |
| 95 |
}); |
| 96 |
|
| 97 |
if (!response.ok) throw new Error('Bad response from server'); |
| 98 |
return await response.json(); |
| 99 |
}; |
| 100 |
|
| 101 |
export const rateAnswer = ({ answerId, rating }) => |
| 102 |
fetch(`${AI_HOST}/api/agent/rate-workflow`, { |
| 103 |
method: 'POST', |
| 104 |
headers: { 'Content-Type': 'application/json' }, |
| 105 |
body: JSON.stringify({ answerId, rating }), |
| 106 |
}).catch((error) => |
| 107 |
digest({ |
| 108 |
error: error, |
| 109 |
details: { source: 'agent', caller: 'rateAnswer', answerId, rating }, |
| 110 |
}), |
| 111 |
); |
| 112 |
|
| 113 |
export const callTool = async ({ tool, inputs }) => { |
| 114 |
if (!tools[tool]) throw new Error(`Tool ${tool} not found`); |
| 115 |
return await tools[tool](inputs); |
| 116 |
}; |
| 117 |
|
| 118 |
export const recordAgentActivity = ({ action, sessionId, value = {} }) => { |
| 119 |
return fetch(`${AI_HOST}/api/agent/activities`, { |
| 120 |
keepalive: true, |
| 121 |
method: 'POST', |
| 122 |
headers: { 'Content-Type': 'application/json' }, |
| 123 |
body: JSON.stringify({ |
| 124 |
...reqDataBasics, |
| 125 |
action, |
| 126 |
sessionId, |
| 127 |
value, |
| 128 |
}), |
| 129 |
}); |
| 130 |
}; |
| 131 |
|