PluginProbe
Extendify / 3.1.3
Extendify v3.1.3
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Agent / api.js

api.js in Extendify 3.1.3, at src/Agent/api.js

146 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useChatStore } from '@agent/state/chat';
2 import { useGlobalStore } from '@agent/state/global';
3 import { tools } from '@agent/workflows/workflows';
4 import { AI_HOST } from '@constants';
5 import { useQuickEditStore } from '@quick-edit/state/store';
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 block = useQuickEditStore.getState().agentBlock;
35
36 const messages = useChatStore
37 .getState()
38 .getCurrentMessages({ includeTools: false });
39 const lastAssistantMessage = useChatStore
40 .getState()
41 .getLastAssistantMessage();
42
43 const response = await fetch(`${AI_HOST}/api/agent/find-agent`, {
44 method: 'POST',
45 headers: { 'Content-Type': 'application/json' },
46 signal: options?.signal,
47 body: JSON.stringify({
48 ...reqDataBasics,
49 workflows: filteredWorkflows,
50 previousWorkflow: {
51 workflowId: lastAssistantMessage?.details?.workflowId,
52 language: lastAssistantMessage?.details?.language,
53 lastMessage: lastAssistantMessage?.details?.content,
54 sessionId: lastAssistantMessage?.details?.sessionId,
55 },
56 context,
57 agentContext: window.extAgentData.agentContext,
58 wpAbilities: window.extAgentData.wpAbilities ?? [],
59 messages: messages.slice(-5),
60 hasBlock: Boolean(block), // todo: remove this
61 blockDetails: block,
62 ...options,
63 extra: extra(),
64 }),
65 });
66
67 if (!response.ok) {
68 digest({
69 error: {
70 name: response.statusText,
71 messages: response.statusMessage,
72 },
73 details: { source: 'agent', caller: 'pick-workflow' },
74 });
75 const error = new Error('Bad response from server');
76 error.response = response;
77 throw error;
78 }
79 return await response.json();
80 };
81
82 export const handleWorkflow = async ({ workflow, workflowData, options }) => {
83 const { getCurrentMessages, getMessagesFor } = useChatStore.getState();
84 const response = await fetch(`${AI_HOST}/api/agent/handle-workflow`, {
85 method: 'POST',
86 headers: { 'Content-Type': 'application/json' },
87 signal: options?.signal,
88 body: JSON.stringify({
89 ...reqDataBasics,
90 workflow,
91 workflowData,
92 messages: getCurrentMessages(),
93 previousMessages: getMessagesFor(workflow?.id),
94 context: window.extAgentData.context,
95 agentContext: window.extAgentData.agentContext,
96 wpAbilities: window.extAgentData.wpAbilities ?? [],
97 retry: options?.retry || false,
98 extra: extra(),
99 }),
100 });
101
102 if (!response.ok) throw new Error('Bad response from server');
103 return await response.json();
104 };
105
106 export const rateAnswer = ({ answerId, rating }) =>
107 fetch(`${AI_HOST}/api/agent/rate-workflow`, {
108 method: 'POST',
109 headers: { 'Content-Type': 'application/json' },
110 body: JSON.stringify({ answerId, rating }),
111 }).catch((error) =>
112 digest({
113 error: error,
114 details: { source: 'agent', caller: 'rateAnswer', answerId, rating },
115 }),
116 );
117
118 export const callTool = async ({ tool, inputs }) => {
119 if (tools[tool]) return await tools[tool](inputs);
120 // Ability tools are named after the ability and have no file; the generic
121 // runner executes them. Key the result to its slot so the loop sees it filled.
122 const isAbility = (window.extAgentData?.wpAbilities ?? []).some((category) =>
123 category.abilities?.some((ability) => ability.name === tool),
124 );
125 if (isAbility) {
126 return {
127 [tool]: await tools['execute-ability']({ ability: tool, input: inputs }),
128 };
129 }
130 throw new Error(`Tool ${tool} not found`);
131 };
132
133 export const recordAgentActivity = ({ action, sessionId, value = {} }) => {
134 return fetch(`${AI_HOST}/api/agent/activities`, {
135 keepalive: true,
136 method: 'POST',
137 headers: { 'Content-Type': 'application/json' },
138 body: JSON.stringify({
139 ...reqDataBasics,
140 action,
141 sessionId,
142 value,
143 }),
144 });
145 };
146