@agent-native/core 0.7.19 → 0.7.21
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/README.md +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +45 -2
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/agent/loop-settings.d.ts +37 -0
- package/dist/agent/loop-settings.d.ts.map +1 -0
- package/dist/agent/loop-settings.js +127 -0
- package/dist/agent/loop-settings.js.map +1 -0
- package/dist/agent/production-agent.d.ts +8 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +268 -29
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +76 -3
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +1 -1
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +65 -2
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +3 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +52 -10
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/agent/tool-search.d.ts +37 -0
- package/dist/agent/tool-search.d.ts.map +1 -0
- package/dist/agent/tool-search.js +201 -0
- package/dist/agent/tool-search.js.map +1 -0
- package/dist/agent/types.d.ts +8 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +44 -9
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/workspacify.d.ts +2 -0
- package/dist/cli/workspacify.d.ts.map +1 -1
- package/dist/cli/workspacify.js +34 -1
- package/dist/cli/workspacify.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +277 -18
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +1 -1
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +14 -6
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/NewWorkspaceAppFlow.d.ts +14 -0
- package/dist/client/NewWorkspaceAppFlow.d.ts.map +1 -0
- package/dist/client/NewWorkspaceAppFlow.js +198 -0
- package/dist/client/NewWorkspaceAppFlow.js.map +1 -0
- package/dist/client/PoweredByBadge.d.ts +10 -1
- package/dist/client/PoweredByBadge.d.ts.map +1 -1
- package/dist/client/PoweredByBadge.js +120 -8
- package/dist/client/PoweredByBadge.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts +3 -5
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +26 -19
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +15 -3
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/analytics.d.ts +1 -1
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +141 -1
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/builder-frame.d.ts +10 -0
- package/dist/client/builder-frame.d.ts.map +1 -0
- package/dist/client/builder-frame.js +94 -0
- package/dist/client/builder-frame.js.map +1 -0
- package/dist/client/composer/MentionPopover.d.ts.map +1 -1
- package/dist/client/composer/MentionPopover.js +5 -1
- package/dist/client/composer/MentionPopover.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +11 -6
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/error-format.d.ts +20 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +53 -5
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/index.d.ts +3 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/notifications/NotificationsBell.d.ts.map +1 -1
- package/dist/client/notifications/NotificationsBell.js +28 -1
- package/dist/client/notifications/NotificationsBell.js.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.d.ts.map +1 -1
- package/dist/client/onboarding/OnboardingPanel.js +88 -6
- package/dist/client/onboarding/OnboardingPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +145 -9
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +13 -0
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +50 -9
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +3 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +88 -7
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/tools/ToolsListPage.d.ts.map +1 -1
- package/dist/client/tools/ToolsListPage.js +16 -1
- package/dist/client/tools/ToolsListPage.js.map +1 -1
- package/dist/client/tools/ToolsSidebarSection.d.ts.map +1 -1
- package/dist/client/tools/ToolsSidebarSection.js +63 -8
- package/dist/client/tools/ToolsSidebarSection.js.map +1 -1
- package/dist/client/tools/tool-order.d.ts +7 -0
- package/dist/client/tools/tool-order.d.ts.map +1 -0
- package/dist/client/tools/tool-order.js +47 -0
- package/dist/client/tools/tool-order.js.map +1 -0
- package/dist/client/transcription/BuilderTranscriptionCta.d.ts.map +1 -1
- package/dist/client/transcription/BuilderTranscriptionCta.js +71 -6
- package/dist/client/transcription/BuilderTranscriptionCta.js.map +1 -1
- package/dist/client/use-send-to-agent-chat.d.ts.map +1 -1
- package/dist/client/use-send-to-agent-chat.js +11 -3
- package/dist/client/use-send-to-agent-chat.js.map +1 -1
- package/dist/client/useProductionAgent.d.ts.map +1 -1
- package/dist/client/useProductionAgent.js +1 -1
- package/dist/client/useProductionAgent.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +5 -1
- package/dist/db/client.js.map +1 -1
- package/dist/deploy/build.d.ts +1 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +4 -1
- package/dist/deploy/build.js.map +1 -1
- package/dist/oauth-tokens/index.d.ts +1 -1
- package/dist/oauth-tokens/index.d.ts.map +1 -1
- package/dist/oauth-tokens/index.js +1 -1
- package/dist/oauth-tokens/index.js.map +1 -1
- package/dist/oauth-tokens/store.d.ts.map +1 -1
- package/dist/oauth-tokens/store.js +6 -0
- package/dist/oauth-tokens/store.js.map +1 -1
- package/dist/observability/store.d.ts.map +1 -1
- package/dist/observability/store.js +19 -19
- package/dist/observability/store.js.map +1 -1
- package/dist/onboarding/default-steps.d.ts.map +1 -1
- package/dist/onboarding/default-steps.js +95 -61
- package/dist/onboarding/default-steps.js.map +1 -1
- package/dist/onboarding/plugin.d.ts.map +1 -1
- package/dist/onboarding/plugin.js +17 -8
- package/dist/onboarding/plugin.js.map +1 -1
- package/dist/org/migrations.js +2 -2
- package/dist/org/migrations.js.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +2 -3
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/scripts/db/exec.d.ts +2 -1
- package/dist/scripts/db/exec.d.ts.map +1 -1
- package/dist/scripts/db/exec.js +264 -61
- package/dist/scripts/db/exec.js.map +1 -1
- package/dist/scripts/db/schema.d.ts.map +1 -1
- package/dist/scripts/db/schema.js +16 -4
- package/dist/scripts/db/schema.js.map +1 -1
- package/dist/scripts/dev/index.d.ts.map +1 -1
- package/dist/scripts/dev/index.js +36 -11
- package/dist/scripts/dev/index.js.map +1 -1
- package/dist/scripts/manage-agent-loop-settings.d.ts +7 -0
- package/dist/scripts/manage-agent-loop-settings.d.ts.map +1 -0
- package/dist/scripts/manage-agent-loop-settings.js +63 -0
- package/dist/scripts/manage-agent-loop-settings.js.map +1 -0
- package/dist/scripts/runner.d.ts.map +1 -1
- package/dist/scripts/runner.js +11 -0
- package/dist/scripts/runner.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +60 -18
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/app-url.d.ts +5 -4
- package/dist/server/app-url.d.ts.map +1 -1
- package/dist/server/app-url.js +8 -4
- package/dist/server/app-url.js.map +1 -1
- package/dist/server/auth.d.ts +8 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +82 -29
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +16 -5
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/builder-browser.d.ts +12 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +36 -4
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +350 -53
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/credential-provider.d.ts +21 -3
- package/dist/server/credential-provider.d.ts.map +1 -1
- package/dist/server/credential-provider.js +51 -21
- package/dist/server/credential-provider.js.map +1 -1
- package/dist/server/google-oauth.d.ts +3 -0
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +27 -3
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/index.d.ts +4 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.js +2 -2
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/schema-prompt.d.ts.map +1 -1
- package/dist/server/schema-prompt.js +2 -1
- package/dist/server/schema-prompt.js.map +1 -1
- package/dist/server/security-headers.d.ts +3 -0
- package/dist/server/security-headers.d.ts.map +1 -1
- package/dist/server/security-headers.js +7 -1
- package/dist/server/security-headers.js.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +31 -6
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/templates/default/_gitignore +5 -1
- package/dist/templates/default/app/root.tsx +1 -0
- package/dist/templates/default/public/favicon.svg +3 -3
- package/dist/templates/default/public/icon-180.svg +3 -3
- package/dist/templates/default/public/icon-192.svg +3 -3
- package/dist/templates/default/public/icon-512.svg +3 -3
- package/dist/templates/workspace-core/AGENTS.md +23 -7
- package/dist/templates/workspace-core/package.json +2 -1
- package/dist/templates/workspace-core/src/credentials.ts +22 -11
- package/dist/templates/workspace-root/.env.example +7 -0
- package/dist/templates/workspace-root/README.md +6 -3
- package/dist/templates/workspace-root/_gitignore +3 -0
- package/dist/templates/workspace-root/package.json +3 -1
- package/dist/templates/workspace-root/scripts/workspace-dev.ts +375 -0
- package/dist/tools/actions.d.ts.map +1 -1
- package/dist/tools/actions.js +2 -0
- package/dist/tools/actions.js.map +1 -1
- package/dist/tools/html-shell.d.ts.map +1 -1
- package/dist/tools/html-shell.js +13 -1
- package/dist/tools/html-shell.js.map +1 -1
- package/dist/tools/store.d.ts.map +1 -1
- package/dist/tools/store.js +10 -10
- package/dist/tools/store.js.map +1 -1
- package/dist/tracking/providers.d.ts +1 -0
- package/dist/tracking/providers.d.ts.map +1 -1
- package/dist/tracking/providers.js +72 -0
- package/dist/tracking/providers.js.map +1 -1
- package/dist/vite/action-types-plugin.d.ts.map +1 -1
- package/dist/vite/action-types-plugin.js +106 -9
- package/dist/vite/action-types-plugin.js.map +1 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +62 -1
- package/dist/vite/client.js.map +1 -1
- package/docs/content/authentication.md +17 -13
- package/docs/content/deployment.md +11 -11
- package/docs/content/mcp-clients.md +2 -2
- package/docs/content/onboarding.md +32 -30
- package/docs/content/security.md +1 -1
- package/docs/content/tools.md +4 -0
- package/package.json +2 -2
- package/src/templates/default/_gitignore +5 -1
- package/src/templates/default/app/root.tsx +1 -0
- package/src/templates/default/public/favicon.svg +3 -3
- package/src/templates/default/public/icon-180.svg +3 -3
- package/src/templates/default/public/icon-192.svg +3 -3
- package/src/templates/default/public/icon-512.svg +3 -3
- package/src/templates/workspace-core/AGENTS.md +23 -7
- package/src/templates/workspace-core/package.json +2 -1
- package/src/templates/workspace-core/src/credentials.ts +22 -11
- package/src/templates/workspace-root/.env.example +7 -0
- package/src/templates/workspace-root/README.md +6 -3
- package/src/templates/workspace-root/_gitignore +3 -0
- package/src/templates/workspace-root/package.json +3 -1
- package/src/templates/workspace-root/scripts/workspace-dev.ts +375 -0
|
@@ -8,8 +8,10 @@ import { PROVIDER_TO_ENV } from "./engine/provider-env-vars.js";
|
|
|
8
8
|
import { readAppState } from "../application-state/script-helpers.js";
|
|
9
9
|
import { startRun, subscribeToRun, getActiveRunForThread, getActiveRunForThreadAsync, getRun, abortRun, } from "./run-manager.js";
|
|
10
10
|
import { readBody } from "../server/h3-helpers.js";
|
|
11
|
-
import { getRequestUserEmail } from "../server/request-context.js";
|
|
11
|
+
import { getRequestOrgId, getRequestUserEmail, } from "../server/request-context.js";
|
|
12
12
|
import { isMcpToolAllowedForRequest } from "../mcp-client/visibility.js";
|
|
13
|
+
import { createToolSearchEntry, TOOL_SEARCH_ACTION_NAME, } from "./tool-search.js";
|
|
14
|
+
import { getDefaultMaxIterations, normalizeMaxIterations, readAgentLoopSettings, } from "./loop-settings.js";
|
|
13
15
|
// Register built-in engines on first import
|
|
14
16
|
registerBuiltinEngines();
|
|
15
17
|
export { PROVIDER_TO_ENV };
|
|
@@ -129,7 +131,159 @@ export async function getOwnerActiveApiKey(ownerEmail) {
|
|
|
129
131
|
export async function getOwnerAnthropicApiKey(ownerEmail) {
|
|
130
132
|
return getOwnerApiKey("anthropic", ownerEmail);
|
|
131
133
|
}
|
|
132
|
-
const
|
|
134
|
+
export const PLAN_MODE_SYSTEM_PROMPT = `## Plan Mode Active
|
|
135
|
+
|
|
136
|
+
You are in Plan mode. This turn is for research, clarification, and a proposed approach only.
|
|
137
|
+
|
|
138
|
+
Hard rules:
|
|
139
|
+
- Use only read-only tools. Do not edit files, write resources, run shell commands, mutate SQL rows, navigate the UI, send notifications, create jobs, create tools, call external agents, or change external systems.
|
|
140
|
+
- If a needed detail is unclear, ask a concise clarifying question before proposing a plan.
|
|
141
|
+
- When ready, present a concrete plan with the files/tools you expect to touch, the intended changes, validation steps, and notable risks.
|
|
142
|
+
- Do not treat approval as implicit while Plan mode is still active. Tell the user to switch to Act mode with the mode selector, Shift+Tab, or /act before implementation.`;
|
|
143
|
+
const PLAN_MODE_BLOCKED_READONLY_TOOLS = new Set([
|
|
144
|
+
"refresh-screen",
|
|
145
|
+
"set-search-params",
|
|
146
|
+
"set-url-path",
|
|
147
|
+
]);
|
|
148
|
+
const PLAN_MODE_ALLOWED_ACTIONS = {
|
|
149
|
+
resources: ["list", "read"],
|
|
150
|
+
"chat-history": ["search"],
|
|
151
|
+
"agent-teams": ["status", "read-result", "list"],
|
|
152
|
+
"manage-jobs": ["list"],
|
|
153
|
+
"manage-automations": ["list-events", "list"],
|
|
154
|
+
"manage-notifications": ["list"],
|
|
155
|
+
"manage-progress": ["list"],
|
|
156
|
+
"manage-agent-engine": ["list"],
|
|
157
|
+
};
|
|
158
|
+
const PLAN_MODE_WEB_REQUEST_METHODS = new Set(["GET", "HEAD"]);
|
|
159
|
+
function getToolAction(name, args) {
|
|
160
|
+
const raw = args && typeof args === "object" && "action" in args
|
|
161
|
+
? args.action
|
|
162
|
+
: undefined;
|
|
163
|
+
if (raw == null && name === "chat-history")
|
|
164
|
+
return "search";
|
|
165
|
+
return String(raw ?? "").toLowerCase();
|
|
166
|
+
}
|
|
167
|
+
function getWebRequestMethod(args) {
|
|
168
|
+
const raw = args && typeof args === "object" && "method" in args
|
|
169
|
+
? args.method
|
|
170
|
+
: undefined;
|
|
171
|
+
return String(raw ?? "GET").toUpperCase();
|
|
172
|
+
}
|
|
173
|
+
function restrictActionEnum(parameters, allowedActions) {
|
|
174
|
+
if (!parameters)
|
|
175
|
+
return parameters;
|
|
176
|
+
const actionParam = parameters.properties.action;
|
|
177
|
+
if (!actionParam)
|
|
178
|
+
return parameters;
|
|
179
|
+
return {
|
|
180
|
+
...parameters,
|
|
181
|
+
properties: {
|
|
182
|
+
...parameters.properties,
|
|
183
|
+
action: {
|
|
184
|
+
...actionParam,
|
|
185
|
+
enum: [...allowedActions],
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
function restrictWebRequestMethods(parameters) {
|
|
191
|
+
if (!parameters)
|
|
192
|
+
return parameters;
|
|
193
|
+
const methodParam = parameters.properties.method;
|
|
194
|
+
if (!methodParam)
|
|
195
|
+
return parameters;
|
|
196
|
+
return {
|
|
197
|
+
...parameters,
|
|
198
|
+
properties: {
|
|
199
|
+
...parameters.properties,
|
|
200
|
+
method: {
|
|
201
|
+
...methodParam,
|
|
202
|
+
enum: [...PLAN_MODE_WEB_REQUEST_METHODS],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
function planModeBlockedMessage(toolName, reason) {
|
|
208
|
+
return (`Plan mode blocked \`${toolName}\`` +
|
|
209
|
+
(reason ? ` (${reason})` : "") +
|
|
210
|
+
". Switch to Act mode after the user approves the plan, then retry the action.");
|
|
211
|
+
}
|
|
212
|
+
export function isPlanModeToolCallAllowed(name, input, entry) {
|
|
213
|
+
if (PLAN_MODE_BLOCKED_READONLY_TOOLS.has(name))
|
|
214
|
+
return false;
|
|
215
|
+
if (name === "web-request") {
|
|
216
|
+
return PLAN_MODE_WEB_REQUEST_METHODS.has(getWebRequestMethod(input));
|
|
217
|
+
}
|
|
218
|
+
const allowedActions = PLAN_MODE_ALLOWED_ACTIONS[name];
|
|
219
|
+
if (allowedActions) {
|
|
220
|
+
return allowedActions.includes(getToolAction(name, input));
|
|
221
|
+
}
|
|
222
|
+
return entry.readOnly === true;
|
|
223
|
+
}
|
|
224
|
+
function createPlanModeGuardedAction(name, entry, allowedActions) {
|
|
225
|
+
return {
|
|
226
|
+
...entry,
|
|
227
|
+
readOnly: true,
|
|
228
|
+
tool: {
|
|
229
|
+
...entry.tool,
|
|
230
|
+
description: `${entry.tool.description}\n\nPlan mode: only these read-only actions are available: ` +
|
|
231
|
+
allowedActions.map((action) => `"${action}"`).join(", ") +
|
|
232
|
+
".",
|
|
233
|
+
parameters: restrictActionEnum(entry.tool.parameters, allowedActions),
|
|
234
|
+
},
|
|
235
|
+
run: async (args, context) => {
|
|
236
|
+
const action = getToolAction(name, args);
|
|
237
|
+
if (!allowedActions.includes(action)) {
|
|
238
|
+
return planModeBlockedMessage(name, `action="${action || "(missing)"}"`);
|
|
239
|
+
}
|
|
240
|
+
return entry.run(args, context);
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
function createPlanModeWebRequestAction(entry) {
|
|
245
|
+
return {
|
|
246
|
+
...entry,
|
|
247
|
+
readOnly: true,
|
|
248
|
+
tool: {
|
|
249
|
+
...entry.tool,
|
|
250
|
+
description: `${entry.tool.description}\n\nPlan mode: only GET and HEAD requests are allowed.`,
|
|
251
|
+
parameters: restrictWebRequestMethods(entry.tool.parameters),
|
|
252
|
+
},
|
|
253
|
+
run: async (args, context) => {
|
|
254
|
+
const method = getWebRequestMethod(args);
|
|
255
|
+
if (!PLAN_MODE_WEB_REQUEST_METHODS.has(method)) {
|
|
256
|
+
return planModeBlockedMessage("web-request", `method="${method}"`);
|
|
257
|
+
}
|
|
258
|
+
return entry.run(args, context);
|
|
259
|
+
},
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
export function createPlanModeActionRegistry(actions) {
|
|
263
|
+
const filtered = {};
|
|
264
|
+
for (const [name, entry] of Object.entries(actions)) {
|
|
265
|
+
if (name === TOOL_SEARCH_ACTION_NAME)
|
|
266
|
+
continue;
|
|
267
|
+
if (PLAN_MODE_BLOCKED_READONLY_TOOLS.has(name))
|
|
268
|
+
continue;
|
|
269
|
+
const allowedActions = PLAN_MODE_ALLOWED_ACTIONS[name];
|
|
270
|
+
if (allowedActions) {
|
|
271
|
+
filtered[name] = createPlanModeGuardedAction(name, entry, allowedActions);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (name === "web-request") {
|
|
275
|
+
filtered[name] = createPlanModeWebRequestAction(entry);
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (entry.readOnly === true) {
|
|
279
|
+
filtered[name] = entry;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (actions[TOOL_SEARCH_ACTION_NAME]) {
|
|
283
|
+
filtered[TOOL_SEARCH_ACTION_NAME] = createToolSearchEntry(() => filtered);
|
|
284
|
+
}
|
|
285
|
+
return filtered;
|
|
286
|
+
}
|
|
133
287
|
const MAX_RETRIES = 3;
|
|
134
288
|
const RETRY_BASE_DELAY_MS = 2000;
|
|
135
289
|
function generateRunId() {
|
|
@@ -157,11 +311,22 @@ function isRetryableError(err) {
|
|
|
157
311
|
if (!(err instanceof Error))
|
|
158
312
|
return false;
|
|
159
313
|
const msg = err.message.toLowerCase();
|
|
160
|
-
|
|
314
|
+
const code = err instanceof EngineError ? (err.errorCode ?? "").toLowerCase() : "";
|
|
315
|
+
return (code === "http_502" ||
|
|
316
|
+
code === "http_503" ||
|
|
317
|
+
code === "http_504" ||
|
|
318
|
+
code === "timeout" ||
|
|
319
|
+
msg.includes("overloaded") ||
|
|
161
320
|
msg.includes("rate_limit") ||
|
|
162
321
|
msg.includes("529") ||
|
|
322
|
+
msg.includes("502") ||
|
|
163
323
|
msg.includes("503") ||
|
|
164
|
-
msg.includes("
|
|
324
|
+
msg.includes("504") ||
|
|
325
|
+
msg.includes("too many requests") ||
|
|
326
|
+
msg.includes("timeout") ||
|
|
327
|
+
msg.includes("gateway timeout") ||
|
|
328
|
+
msg.includes("inactivity timeout") ||
|
|
329
|
+
msg.includes("too much time has passed without sending any data"));
|
|
165
330
|
}
|
|
166
331
|
/** Wait with exponential backoff, respecting abort signal */
|
|
167
332
|
function retryDelay(attempt, signal) {
|
|
@@ -268,14 +433,34 @@ function enrichMessage(message, references) {
|
|
|
268
433
|
* Convert ActionEntry registry to EngineTool array.
|
|
269
434
|
*/
|
|
270
435
|
export function actionsToEngineTools(actions) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
|
|
436
|
+
const tools = [];
|
|
437
|
+
for (const [name, entry] of Object.entries(actions)) {
|
|
438
|
+
const inputSchema = normalizeToolInputSchema(entry.tool.parameters);
|
|
439
|
+
if (!inputSchema) {
|
|
440
|
+
console.warn(`[agent] Skipping tool "${name}" because its input schema is not an object.`);
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
tools.push({
|
|
444
|
+
name,
|
|
445
|
+
description: entry.tool.description,
|
|
446
|
+
inputSchema,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
return tools;
|
|
450
|
+
}
|
|
451
|
+
function normalizeToolInputSchema(schema) {
|
|
452
|
+
if (!schema)
|
|
453
|
+
return { type: "object", properties: {} };
|
|
454
|
+
if (schema.type !== "object")
|
|
455
|
+
return null;
|
|
456
|
+
return {
|
|
457
|
+
...schema,
|
|
458
|
+
type: "object",
|
|
459
|
+
properties: schema.properties && typeof schema.properties === "object"
|
|
460
|
+
? schema.properties
|
|
461
|
+
: {},
|
|
462
|
+
required: Array.isArray(schema.required) ? schema.required : [],
|
|
463
|
+
};
|
|
279
464
|
}
|
|
280
465
|
/**
|
|
281
466
|
* The core agent loop — calls the engine iteratively until no more tool calls.
|
|
@@ -291,12 +476,13 @@ export async function runAgentLoop(opts) {
|
|
|
291
476
|
cacheWriteTokens: 0,
|
|
292
477
|
model,
|
|
293
478
|
};
|
|
479
|
+
const maxIterations = normalizeMaxIterations(opts.maxIterations, getDefaultMaxIterations());
|
|
294
480
|
let iterations = 0;
|
|
295
481
|
while (true) {
|
|
296
482
|
if (signal.aborted)
|
|
297
483
|
break;
|
|
298
|
-
if (++iterations >
|
|
299
|
-
send({ type: "loop_limit" });
|
|
484
|
+
if (++iterations > maxIterations) {
|
|
485
|
+
send({ type: "loop_limit", maxIterations });
|
|
300
486
|
break;
|
|
301
487
|
}
|
|
302
488
|
let assistantContent;
|
|
@@ -372,9 +558,7 @@ export async function runAgentLoop(opts) {
|
|
|
372
558
|
const toolCallParts = assistantContent.filter((p) => p.type === "tool-call");
|
|
373
559
|
if (toolCallParts.length === 0)
|
|
374
560
|
break;
|
|
375
|
-
|
|
376
|
-
// blocks in one turn. Running them concurrently saves wall-clock time.
|
|
377
|
-
const toolResultParts = await Promise.all(toolCallParts.map(async (toolCall) => {
|
|
561
|
+
const runToolCall = async (toolCall) => {
|
|
378
562
|
const actionEntry = actions[toolCall.name];
|
|
379
563
|
if (!actionEntry) {
|
|
380
564
|
const result = `Error: Unknown tool "${toolCall.name}"`;
|
|
@@ -397,6 +581,18 @@ export async function runAgentLoop(opts) {
|
|
|
397
581
|
tool: toolCall.name,
|
|
398
582
|
input: toolCall.input,
|
|
399
583
|
});
|
|
584
|
+
if (opts.executionMode === "plan" &&
|
|
585
|
+
!isPlanModeToolCallAllowed(toolCall.name, toolCall.input, actionEntry)) {
|
|
586
|
+
const result = planModeBlockedMessage(toolCall.name);
|
|
587
|
+
send({ type: "tool_done", tool: toolCall.name, result });
|
|
588
|
+
return {
|
|
589
|
+
type: "tool-result",
|
|
590
|
+
toolCallId: toolCall.id,
|
|
591
|
+
toolName: toolCall.name,
|
|
592
|
+
content: result,
|
|
593
|
+
isError: true,
|
|
594
|
+
};
|
|
595
|
+
}
|
|
400
596
|
const MAX_TOOL_RESULT_CHARS = 50_000;
|
|
401
597
|
const TOOL_TIMEOUT_MS = 60_000;
|
|
402
598
|
let result;
|
|
@@ -429,10 +625,14 @@ export async function runAgentLoop(opts) {
|
|
|
429
625
|
if (!isError && actionEntry.readOnly !== true) {
|
|
430
626
|
try {
|
|
431
627
|
const { recordChange } = await import("../server/poll.js");
|
|
628
|
+
const owner = opts.ownerEmail ?? getRequestUserEmail() ?? undefined;
|
|
629
|
+
const orgId = opts.orgId ?? getRequestOrgId() ?? undefined;
|
|
432
630
|
recordChange({
|
|
433
631
|
source: "action",
|
|
434
632
|
type: "change",
|
|
435
633
|
key: toolCall.name,
|
|
634
|
+
...(owner ? { owner } : {}),
|
|
635
|
+
...(orgId ? { orgId } : {}),
|
|
436
636
|
});
|
|
437
637
|
}
|
|
438
638
|
catch {
|
|
@@ -447,7 +647,24 @@ export async function runAgentLoop(opts) {
|
|
|
447
647
|
content: result,
|
|
448
648
|
...(isError ? { isError } : {}),
|
|
449
649
|
};
|
|
450
|
-
}
|
|
650
|
+
};
|
|
651
|
+
const hasMutatingToolCall = toolCallParts.some((toolCall) => {
|
|
652
|
+
const entry = actions[toolCall.name];
|
|
653
|
+
return entry && entry.readOnly !== true;
|
|
654
|
+
});
|
|
655
|
+
// Engines can emit several tool-call blocks in one turn. Keep read-only
|
|
656
|
+
// calls parallel for latency, but serialize any batch containing a mutating
|
|
657
|
+
// call so DB writes and UI refresh events preserve model order and do not
|
|
658
|
+
// interleave or partially race.
|
|
659
|
+
const toolResultParts = [];
|
|
660
|
+
if (hasMutatingToolCall) {
|
|
661
|
+
for (const toolCall of toolCallParts) {
|
|
662
|
+
toolResultParts.push(await runToolCall(toolCall));
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
else {
|
|
666
|
+
toolResultParts.push(...(await Promise.all(toolCallParts.map(runToolCall))));
|
|
667
|
+
}
|
|
451
668
|
messages.push({ role: "user", content: toolResultParts });
|
|
452
669
|
}
|
|
453
670
|
send({ type: "done" });
|
|
@@ -463,9 +680,9 @@ export function createProductionAgentHandler(options) {
|
|
|
463
680
|
// the settings UI) show up to the LLM without a process restart. MCP tools
|
|
464
681
|
// are also scope-filtered per request — a user-scope server added by Alice
|
|
465
682
|
// must not appear in Bob's tool list in a shared-process deployment.
|
|
466
|
-
const getEngineTools = () => {
|
|
683
|
+
const getEngineTools = (actions = resolvedActions) => {
|
|
467
684
|
const filtered = {};
|
|
468
|
-
for (const [name, entry] of Object.entries(
|
|
685
|
+
for (const [name, entry] of Object.entries(actions)) {
|
|
469
686
|
if (name.startsWith("mcp__") && !isMcpToolAllowedForRequest(name)) {
|
|
470
687
|
continue;
|
|
471
688
|
}
|
|
@@ -487,6 +704,7 @@ export function createProductionAgentHandler(options) {
|
|
|
487
704
|
return { error: "Invalid request body" };
|
|
488
705
|
}
|
|
489
706
|
const { message, history = [], references = [], threadId, attachments, model: requestModel, engine: requestEngine, } = body;
|
|
707
|
+
const requestMode = body.mode === "plan" ? "plan" : "act";
|
|
490
708
|
if (!message) {
|
|
491
709
|
setResponseStatus(event, 400);
|
|
492
710
|
return { error: "message is required" };
|
|
@@ -578,6 +796,10 @@ export function createProductionAgentHandler(options) {
|
|
|
578
796
|
// the DB or invokes an action; running them sequentially was the
|
|
579
797
|
// single biggest contributor to pre-LLM latency.
|
|
580
798
|
const enrichedMessage = enrichMessage(message, references);
|
|
799
|
+
const loopSettingsPromise = readAgentLoopSettings({
|
|
800
|
+
userEmail: ownerEmail ?? getRequestUserEmail() ?? null,
|
|
801
|
+
orgId: getRequestOrgId() ?? null,
|
|
802
|
+
}).catch(() => readAgentLoopSettings({}));
|
|
581
803
|
let systemPromptError = null;
|
|
582
804
|
const systemPromptPromise = (async () => {
|
|
583
805
|
try {
|
|
@@ -732,12 +954,13 @@ export function createProductionAgentHandler(options) {
|
|
|
732
954
|
}
|
|
733
955
|
return filesContext;
|
|
734
956
|
})();
|
|
735
|
-
const [systemPrompt, screenBlock, urlBlock, selectionBlock, filesContext] = await Promise.all([
|
|
957
|
+
const [systemPrompt, screenBlock, urlBlock, selectionBlock, filesContext, loopSettings,] = await Promise.all([
|
|
736
958
|
systemPromptPromise,
|
|
737
959
|
screenContextPromise,
|
|
738
960
|
urlContextPromise,
|
|
739
961
|
selectionContextPromise,
|
|
740
962
|
filesContextPromise,
|
|
963
|
+
loopSettingsPromise,
|
|
741
964
|
]);
|
|
742
965
|
if (systemPromptError) {
|
|
743
966
|
setResponseHeader(event, "Content-Type", "text/event-stream");
|
|
@@ -752,11 +975,21 @@ export function createProductionAgentHandler(options) {
|
|
|
752
975
|
});
|
|
753
976
|
}
|
|
754
977
|
const screenContext = screenBlock + urlBlock + selectionBlock;
|
|
978
|
+
const requestActions = requestMode === "plan"
|
|
979
|
+
? createPlanModeActionRegistry(resolvedActions)
|
|
980
|
+
: resolvedActions;
|
|
981
|
+
const requestTools = getEngineTools(requestActions);
|
|
982
|
+
const requestSystemPrompt = requestMode === "plan"
|
|
983
|
+
? `${systemPrompt}\n\n${PLAN_MODE_SYSTEM_PROMPT}`
|
|
984
|
+
: systemPrompt;
|
|
755
985
|
// Pre-compute agent references for A2A resolution inside the run
|
|
756
986
|
const agentRefs = references.filter((r) => r.type === "agent");
|
|
757
987
|
const customAgentRefs = references.filter((r) => r.type === "custom-agent");
|
|
988
|
+
const planModeAgentNote = requestMode === "plan" && agentRefs.length > 0
|
|
989
|
+
? "\n\n<plan-mode-note>Connected external agent mentions were not called because Plan mode is read-only. Mention that they can be called after the user switches to Act mode if the plan needs them.</plan-mode-note>"
|
|
990
|
+
: "";
|
|
758
991
|
const userContent = buildUserContentWithAttachments({
|
|
759
|
-
text: enrichedMessage + screenContext + filesContext,
|
|
992
|
+
text: enrichedMessage + screenContext + filesContext + planModeAgentNote,
|
|
760
993
|
attachments,
|
|
761
994
|
});
|
|
762
995
|
const messages = [
|
|
@@ -804,7 +1037,7 @@ export function createProductionAgentHandler(options) {
|
|
|
804
1037
|
if (!profile) {
|
|
805
1038
|
throw new Error("Profile not found");
|
|
806
1039
|
}
|
|
807
|
-
const profilePrompt = `${
|
|
1040
|
+
const profilePrompt = `${requestSystemPrompt}\n\n<custom-agent-profile name="${profile.name}" path="${profile.path}">\n` +
|
|
808
1041
|
(profile.description ? `${profile.description}\n\n` : "") +
|
|
809
1042
|
`${profile.instructions}\n</custom-agent-profile>`;
|
|
810
1043
|
let responseText = "";
|
|
@@ -812,7 +1045,7 @@ export function createProductionAgentHandler(options) {
|
|
|
812
1045
|
engine,
|
|
813
1046
|
model: profile.model ?? model,
|
|
814
1047
|
systemPrompt: profilePrompt,
|
|
815
|
-
tools:
|
|
1048
|
+
tools: requestTools,
|
|
816
1049
|
messages: [
|
|
817
1050
|
{
|
|
818
1051
|
role: "user",
|
|
@@ -821,7 +1054,7 @@ export function createProductionAgentHandler(options) {
|
|
|
821
1054
|
],
|
|
822
1055
|
},
|
|
823
1056
|
],
|
|
824
|
-
actions:
|
|
1057
|
+
actions: requestActions,
|
|
825
1058
|
send: (event) => {
|
|
826
1059
|
if (event.type === "text") {
|
|
827
1060
|
responseText += event.text;
|
|
@@ -834,6 +1067,8 @@ export function createProductionAgentHandler(options) {
|
|
|
834
1067
|
},
|
|
835
1068
|
signal,
|
|
836
1069
|
providerOptions: options.providerOptions,
|
|
1070
|
+
executionMode: requestMode,
|
|
1071
|
+
maxIterations: loopSettings.maxIterations,
|
|
837
1072
|
});
|
|
838
1073
|
// Attribute custom-agent sub-calls under their own label
|
|
839
1074
|
// so the Usage panel separates them from the main chat.
|
|
@@ -889,7 +1124,7 @@ export function createProductionAgentHandler(options) {
|
|
|
889
1124
|
}
|
|
890
1125
|
}
|
|
891
1126
|
// Resolve connected agent @-mentions via A2A calls.
|
|
892
|
-
if (agentRefs.length > 0) {
|
|
1127
|
+
if (agentRefs.length > 0 && requestMode !== "plan") {
|
|
893
1128
|
const { A2AClient, callAgent } = await import("../a2a/client.js");
|
|
894
1129
|
const results = await Promise.allSettled(agentRefs.map(async (ref) => {
|
|
895
1130
|
send({
|
|
@@ -1003,13 +1238,17 @@ export function createProductionAgentHandler(options) {
|
|
|
1003
1238
|
const agentLoopOpts = {
|
|
1004
1239
|
engine,
|
|
1005
1240
|
model: effectiveModel,
|
|
1006
|
-
systemPrompt,
|
|
1007
|
-
tools:
|
|
1241
|
+
systemPrompt: requestSystemPrompt,
|
|
1242
|
+
tools: requestTools,
|
|
1008
1243
|
messages,
|
|
1009
|
-
actions:
|
|
1244
|
+
actions: requestActions,
|
|
1010
1245
|
send,
|
|
1011
1246
|
signal,
|
|
1247
|
+
ownerEmail,
|
|
1248
|
+
orgId: getRequestOrgId() ?? null,
|
|
1012
1249
|
providerOptions: options.providerOptions,
|
|
1250
|
+
executionMode: requestMode,
|
|
1251
|
+
maxIterations: loopSettings.maxIterations,
|
|
1013
1252
|
};
|
|
1014
1253
|
let loopUsage;
|
|
1015
1254
|
let instrumented = false;
|