@agent-native/core 0.200.0-nightly-20261002153252 → 0.200.0
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/agent/production-agent.d.ts +5 -1
- package/dist/agent/production-agent.js +36 -1
- package/dist/cli/design-connect.d.ts +1 -0
- package/dist/cli/design-connect.js +147 -7
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/file-upload/builder.js +20 -2
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/mcp-client/app-api.d.ts +11 -1
- package/dist/mcp-client/app-api.js +17 -3
- package/dist/mcp-client/index.d.ts +1 -1
- package/dist/mcp-client/manager.d.ts +3 -1
- package/dist/mcp-client/manager.js +4 -0
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +1 -1
- package/dist/server/agent-chat/run-code-tools.d.ts +7 -0
- package/dist/server/agent-chat/run-code-tools.js +7 -0
- package/dist/server/agent-chat-plugin.d.ts +5 -1
- package/dist/server/agent-chat-plugin.js +18 -12
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/triggers/actions/manage-automation.d.ts +2 -2
- package/package.json +5 -9
|
@@ -10,6 +10,7 @@ import { type BuilderGatewayAuth } from "../server/credential-provider.js";
|
|
|
10
10
|
import { fireInternalDispatch } from "../server/self-dispatch.js";
|
|
11
11
|
import { type RefusedTurnRetryContext } from "../shared/agent-chat-run-not-started.js";
|
|
12
12
|
import { type ReasoningEffort } from "../shared/reasoning-effort.js";
|
|
13
|
+
import type { TrackingMeta } from "../tracking/registry.js";
|
|
13
14
|
import { type ResolveEngineConfig } from "./engine/index.js";
|
|
14
15
|
import { PROVIDER_TO_ENV } from "./engine/provider-env-vars.js";
|
|
15
16
|
import type { AgentEngine, EngineTool, EngineMessage, EngineContentPart } from "./engine/types.js";
|
|
@@ -232,6 +233,9 @@ export declare function filterActionsByAllowedNames(actions: Record<string, Acti
|
|
|
232
233
|
export declare const PLAN_MODE_SYSTEM_PROMPT = "## Plan Mode Active\n\nYou are in Plan mode. This turn is for research, clarification, and a proposed approach only.\n\nHard rules:\n- Use only read-only tools. Do not edit files, write resources, run mutating bash commands, mutate SQL rows, navigate the UI, send notifications, create jobs, create tools, send messages or tasks to external agents, or change external systems.\n- If a needed detail is unclear, ask a concise clarifying question before proposing a plan.\n- When ready, present a concrete plan with the files/tools you expect to touch, the intended changes, validation steps, and notable risks.\n- Do not treat approval as implicit while Plan mode is still active. Tell the user to switch to Act mode with the mode selector or /act before implementation.";
|
|
233
234
|
export declare function isPlanModeToolCallAllowed(name: string, input: unknown, entry: ActionEntry): boolean;
|
|
234
235
|
export declare function createPlanModeActionRegistry(actions: Record<string, ActionEntry>): Record<string, ActionEntry>;
|
|
236
|
+
type AgentRunTrackingSource = Pick<TrackingMeta, "userId" | "authUserId" | "anonymousId" | "sessionId"> & {
|
|
237
|
+
isSyntheticTraffic?: boolean;
|
|
238
|
+
};
|
|
235
239
|
export interface ProductionAgentOptions {
|
|
236
240
|
actions?: Record<string, ActionEntry>;
|
|
237
241
|
/** @deprecated Use `actions` instead */
|
|
@@ -252,7 +256,7 @@ export interface ProductionAgentOptions {
|
|
|
252
256
|
hostedHarnessConfig?: AgentNativeHarnessSetting;
|
|
253
257
|
reasoningEffort?: ReasoningEffort;
|
|
254
258
|
providerOptions?: EngineMessage extends never ? never : any;
|
|
255
|
-
onRunComplete?: (run: ActiveRun, threadId: string | undefined) => void;
|
|
259
|
+
onRunComplete?: (run: ActiveRun, threadId: string | undefined, trackingSource?: AgentRunTrackingSource) => void;
|
|
256
260
|
onRunPrepared?: (details: {
|
|
257
261
|
runId: string;
|
|
258
262
|
turnId: string;
|
|
@@ -958,6 +958,35 @@ export async function resolveAgentOwnerEmail(options, event) {
|
|
|
958
958
|
}
|
|
959
959
|
return ownerEmail ?? getRequestUserEmail() ?? null;
|
|
960
960
|
}
|
|
961
|
+
function snapshotAgentRunTrackingSource() {
|
|
962
|
+
const requestContext = getRequestContext();
|
|
963
|
+
if (!requestContext)
|
|
964
|
+
return undefined;
|
|
965
|
+
const source = requestContext.agentRunAnonymous
|
|
966
|
+
? {
|
|
967
|
+
...(requestContext.userEmail
|
|
968
|
+
? { anonymousId: requestContext.userEmail }
|
|
969
|
+
: {}),
|
|
970
|
+
...(requestContext.browserSessionId
|
|
971
|
+
? { sessionId: requestContext.browserSessionId }
|
|
972
|
+
: {}),
|
|
973
|
+
}
|
|
974
|
+
: {
|
|
975
|
+
...(requestContext.userEmail
|
|
976
|
+
? { userId: requestContext.userEmail }
|
|
977
|
+
: {}),
|
|
978
|
+
...(requestContext.authUserId
|
|
979
|
+
? { authUserId: requestContext.authUserId }
|
|
980
|
+
: {}),
|
|
981
|
+
...(requestContext.browserSessionId
|
|
982
|
+
? { sessionId: requestContext.browserSessionId }
|
|
983
|
+
: {}),
|
|
984
|
+
};
|
|
985
|
+
const isSyntheticTraffic = requestContext.isSyntheticTraffic === true;
|
|
986
|
+
return Object.keys(source).length > 0 || isSyntheticTraffic
|
|
987
|
+
? { ...source, ...(isSyntheticTraffic ? { isSyntheticTraffic: true } : {}) }
|
|
988
|
+
: undefined;
|
|
989
|
+
}
|
|
961
990
|
const MAX_RETRIES = 3;
|
|
962
991
|
const COMPLETION_DATABASE_RETRY_DELAYS_MS = [250, 750, 1_500];
|
|
963
992
|
export async function runCompletionCallbackWithDatabaseRetry(callback, options) {
|
|
@@ -6336,6 +6365,9 @@ export function createProductionAgentHandler(options) {
|
|
|
6336
6365
|
};
|
|
6337
6366
|
const getEngineTools = (actions) => actionsToEngineTools(getRequestActions(actions));
|
|
6338
6367
|
return defineEventHandler(async (event) => {
|
|
6368
|
+
let completionTrackingSource = options.onRunComplete
|
|
6369
|
+
? snapshotAgentRunTrackingSource()
|
|
6370
|
+
: undefined;
|
|
6339
6371
|
const setupT0 = Date.now();
|
|
6340
6372
|
const setupMarks = {};
|
|
6341
6373
|
const setupMark = (k) => {
|
|
@@ -7634,12 +7666,15 @@ export function createProductionAgentHandler(options) {
|
|
|
7634
7666
|
const baseHandleRunComplete = options.onRunComplete || trackedProgressRunId
|
|
7635
7667
|
? async (run) => {
|
|
7636
7668
|
try {
|
|
7637
|
-
await runCompletionCallbackWithDatabaseRetry(() => options.onRunComplete?.(run, threadId));
|
|
7669
|
+
await runCompletionCallbackWithDatabaseRetry(() => options.onRunComplete?.(run, threadId, completionTrackingSource));
|
|
7638
7670
|
}
|
|
7639
7671
|
catch (err) {
|
|
7640
7672
|
await completeTrackedProgressRun(run, err);
|
|
7641
7673
|
throw err;
|
|
7642
7674
|
}
|
|
7675
|
+
finally {
|
|
7676
|
+
completionTrackingSource = undefined;
|
|
7677
|
+
}
|
|
7643
7678
|
await completeTrackedProgressRun(run);
|
|
7644
7679
|
}
|
|
7645
7680
|
: undefined;
|
|
@@ -51,6 +51,7 @@ export interface DesignConnectManifest {
|
|
|
51
51
|
}
|
|
52
52
|
export interface DesignConnectBridge {
|
|
53
53
|
server: Server;
|
|
54
|
+
close: () => Promise<void>;
|
|
54
55
|
manifest: DesignConnectManifest;
|
|
55
56
|
/** Per-rootPath bridge token. Kept in-process only; never serialised into
|
|
56
57
|
* the manifest JSON so it is not exposed over the network via GET /manifest.
|
|
@@ -5,6 +5,7 @@ import fs from "node:fs/promises";
|
|
|
5
5
|
import http from "node:http";
|
|
6
6
|
import https from "node:https";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import { WebSocket, WebSocketServer } from "ws";
|
|
8
9
|
import { injectDocumentMarkup } from "../shared/html-document.js";
|
|
9
10
|
const DEFAULT_BRIDGE_PORT = 7331;
|
|
10
11
|
const ROUTE_MANIFEST_FILE = path.join(".agent-native", "design-routes.json");
|
|
@@ -1200,6 +1201,53 @@ function addPreviewTokenToResourceUrl(resourceUrl, previewToken) {
|
|
|
1200
1201
|
const withoutStaleToken = stripQueryPair(search, "previewToken");
|
|
1201
1202
|
return `${pathname}${appendQueryPair(withoutStaleToken, "previewToken", previewToken)}${hash}`;
|
|
1202
1203
|
}
|
|
1204
|
+
const MAX_PREVIEW_HMR_MESSAGE_BYTES = 1024 * 1024;
|
|
1205
|
+
function rewriteViteHmrUpdate(payload, previewToken) {
|
|
1206
|
+
if (payload.length > MAX_PREVIEW_HMR_MESSAGE_BYTES)
|
|
1207
|
+
return undefined;
|
|
1208
|
+
let message;
|
|
1209
|
+
try {
|
|
1210
|
+
message = JSON.parse(payload.toString("utf8"));
|
|
1211
|
+
}
|
|
1212
|
+
catch {
|
|
1213
|
+
// coercion-ok: non-JSON Vite control frames are relayed unchanged.
|
|
1214
|
+
return undefined;
|
|
1215
|
+
}
|
|
1216
|
+
if (!message ||
|
|
1217
|
+
typeof message !== "object" ||
|
|
1218
|
+
!("type" in message) ||
|
|
1219
|
+
message.type !== "update" ||
|
|
1220
|
+
!("updates" in message) ||
|
|
1221
|
+
!Array.isArray(message.updates)) {
|
|
1222
|
+
return undefined;
|
|
1223
|
+
}
|
|
1224
|
+
let changed = false;
|
|
1225
|
+
for (const candidate of message.updates) {
|
|
1226
|
+
if (!candidate ||
|
|
1227
|
+
typeof candidate !== "object" ||
|
|
1228
|
+
!("type" in candidate) ||
|
|
1229
|
+
candidate.type !== "js-update" ||
|
|
1230
|
+
!("acceptedPath" in candidate) ||
|
|
1231
|
+
typeof candidate.acceptedPath !== "string" ||
|
|
1232
|
+
!("timestamp" in candidate) ||
|
|
1233
|
+
typeof candidate.timestamp !== "number" ||
|
|
1234
|
+
!Number.isSafeInteger(candidate.timestamp)) {
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1237
|
+
// Vite compares path and acceptedPath as module identities before it imports
|
|
1238
|
+
// the update, so carry proxy auth in its cache-busting query instead.
|
|
1239
|
+
candidate.timestamp = `${candidate.timestamp}&previewToken=${encodeURIComponent(previewToken)}`;
|
|
1240
|
+
changed = true;
|
|
1241
|
+
}
|
|
1242
|
+
return changed ? Buffer.from(JSON.stringify(message)) : undefined;
|
|
1243
|
+
}
|
|
1244
|
+
function webSocketDataBuffer(data) {
|
|
1245
|
+
if (Buffer.isBuffer(data))
|
|
1246
|
+
return data;
|
|
1247
|
+
if (Array.isArray(data))
|
|
1248
|
+
return Buffer.concat(data);
|
|
1249
|
+
return Buffer.from(data);
|
|
1250
|
+
}
|
|
1203
1251
|
function addOpaqueFrameCredentials(html, previewToken) {
|
|
1204
1252
|
const withCredentialedResources = html.replace(/<(script|link|img|audio|video|source|track|iframe)\b([^>]*?)>/gi, (fullTag, tagName, attributes) => {
|
|
1205
1253
|
const resourceMatch = attributes.match(/\b(src|href)\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i);
|
|
@@ -1243,9 +1291,12 @@ function addOpaqueFrameCredentials(html, previewToken) {
|
|
|
1243
1291
|
},
|
|
1244
1292
|
});
|
|
1245
1293
|
const withImportMap = injectDocumentMarkup(withHmrToken, `<script type="importmap" data-agent-native-opaque-preview-imports>${previewImportMap}</script>`, { target: "head" });
|
|
1246
|
-
|
|
1294
|
+
const withViteHmrStyleAuth = injectDocumentMarkup(withImportMap,
|
|
1295
|
+
// coercion-ok: malformed Vite-generated CSS URLs stay unchanged in the frame.
|
|
1296
|
+
`<script data-agent-native-vite-css-auth>(function(t){var p=Element.prototype.after;Element.prototype.after=function(){for(var i=0;i<arguments.length;i++){var n=arguments[i];if(!n||n.nodeType!==1||n.tagName!=="LINK")continue;try{var b=new URL(document.baseURI),u=new URL(n.getAttribute("href"),b);if(u.origin===b.origin&&!u.searchParams.has("previewToken")){u.searchParams.set("previewToken",t);n.setAttribute("href",u.toString())}}catch(_){}}return p.apply(this,arguments)}})(${previewTokenLiteral});</script>`, { target: "head" });
|
|
1297
|
+
return injectDocumentMarkup(withViteHmrStyleAuth,
|
|
1247
1298
|
// coercion-ok: invalid browser-owned URLs stay unchanged in the frame.
|
|
1248
|
-
String.raw `<script data-agent-native-opaque-preview-auth>(function(){var t=${previewTokenLiteral},o,h;try{var b=new URL(document.baseURI);o=b.origin;h=b.host}catch(_){return}function u(v){try{var a=new URL(String(v),document.baseURI),same=a.origin===o||(h===a.host&&(a.protocol==="ws:"||a.protocol==="wss:"));if(!same||a.searchParams.has("previewToken"))return null;a.searchParams.set("previewToken",t);return a.toString()}catch(_){return null}}function c(v){return String(v).replace(/url\(\s*(["']?)([^"'()]+)\1\s*\)/gi,function(h,q,v){var s=u(v);return s?"url("+q+s+q+")":h})}var f=window.fetch.bind(window);window.fetch=function(i,n){var v=i instanceof Request?i.url:i,s=u(v);return s?f(i instanceof Request?new Request(s,i):s,n):f(i,n)};var x=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(m,v){var s=u(v);return x.call(this,m,s||v,...Array.prototype.slice.call(arguments,2))};var e=window.EventSource;if(e){var E=function(v,n){return new e(u(v)||v,n);};E.prototype=e.prototype;window.EventSource=E}var W=window.WebSocket;if(W){var S=function(v,p){var s=u(v);return p===undefined?new W(s||v):new W(s||v,p)};S.prototype=W.prototype;S.CONNECTING=W.CONNECTING;S.OPEN=W.OPEN;S.CLOSING=W.CLOSING;S.CLOSED=W.CLOSED;window.WebSocket=S}
|
|
1299
|
+
String.raw `<script data-agent-native-opaque-preview-auth>(function(){var t=${previewTokenLiteral},o,h;try{var b=new URL(document.baseURI);o=b.origin;h=b.host}catch(_){return}function u(v){try{var a=new URL(String(v),document.baseURI),same=a.origin===o||(h===a.host&&(a.protocol==="ws:"||a.protocol==="wss:"));if(!same||a.searchParams.has("previewToken"))return null;a.searchParams.set("previewToken",t);return a.toString()}catch(_){return null}}function c(v){return String(v).replace(/url\(\s*(["']?)([^"'()]+)\1\s*\)/gi,function(h,q,v){var s=u(v);return s?"url("+q+s+q+")":h})}var f=window.fetch.bind(window);window.fetch=function(i,n){var v=i instanceof Request?i.url:i,s=u(v);return s?f(i instanceof Request?new Request(s,i):s,n):f(i,n)};var x=XMLHttpRequest.prototype.open;XMLHttpRequest.prototype.open=function(m,v){var s=u(v);return x.call(this,m,s||v,...Array.prototype.slice.call(arguments,2))};var e=window.EventSource;if(e){var E=function(v,n){return new e(u(v)||v,n);};E.prototype=e.prototype;window.EventSource=E}var W=window.WebSocket;if(W){var S=function(v,p){var s=u(v);return p===undefined?new W(s||v):new W(s||v,p)};S.prototype=W.prototype;S.CONNECTING=W.CONNECTING;S.OPEN=W.OPEN;S.CLOSING=W.CLOSING;S.CLOSED=W.CLOSED;window.WebSocket=S}function d(n){if(n&&n.nodeType===1){var a=n.tagName==="SCRIPT"?"src":n.tagName==="LINK"?"href":n.tagName==="IMG"?"src":n.tagName==="IFRAME"?"src":null;if(a){var v=n.getAttribute(a),s=u(v);if(s)n.setAttribute(a,s)}else if(n.tagName==="STYLE"&&n.textContent){n.textContent=c(n.textContent)}}return n}var p=Node.prototype.appendChild;Node.prototype.appendChild=function(n){return p.call(this,d(n))};var i=Node.prototype.insertBefore;Node.prototype.insertBefore=function(n,r){return i.call(this,d(n),r)}})();</script>`, { target: "head" });
|
|
1249
1300
|
}
|
|
1250
1301
|
function addOpaqueFrameResourceTokens(css, previewToken) {
|
|
1251
1302
|
const withImportTokens = css.replace(/(@import\s+)(["'])([^"']+)\2/gi, (_full, prefix, quote, resourceUrl) => `${prefix}${quote}${addPreviewTokenToResourceUrl(resourceUrl, previewToken)}${quote}`);
|
|
@@ -2107,6 +2158,11 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2107
2158
|
const isValidLiveEditRegistrationCapability = (req, designId) => constantTimeTokenMatches(readHeader(req, "x-agent-native-live-edit-registration-capability"), deriveDesignScopedLiveEditRegistrationCapability(bridgeToken, designId));
|
|
2108
2159
|
const bridgeInstanceId = crypto.randomBytes(16).toString("hex");
|
|
2109
2160
|
const previewSessionCookies = new PreviewSessionCookieJar(manifest.devServerUrl);
|
|
2161
|
+
const hmrWebSocketServer = new WebSocketServer({
|
|
2162
|
+
noServer: true,
|
|
2163
|
+
perMessageDeflate: false,
|
|
2164
|
+
handleProtocols: (protocols) => protocols.has("vite-hmr") ? "vite-hmr" : false,
|
|
2165
|
+
});
|
|
2110
2166
|
const server = http.createServer((req, res) => {
|
|
2111
2167
|
const requestUrl = new URL(req.url ?? "/", manifest.bridgeUrl);
|
|
2112
2168
|
const pathname = requestUrl.pathname;
|
|
@@ -2326,6 +2382,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2326
2382
|
sendJson(res, 200, {
|
|
2327
2383
|
ok: true,
|
|
2328
2384
|
pending: pendingVisualEditPayloads.get(designId)?.pending ?? null,
|
|
2385
|
+
revision: pendingVisualEditRevisionHighWaterMarks.get(designId) ?? 0,
|
|
2329
2386
|
});
|
|
2330
2387
|
return;
|
|
2331
2388
|
}
|
|
@@ -2406,7 +2463,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2406
2463
|
: stored === "stale"
|
|
2407
2464
|
? "stale pending publication revision"
|
|
2408
2465
|
: "conflicting pending publication revision",
|
|
2409
|
-
revision:
|
|
2466
|
+
revision: pendingVisualEditRevisionHighWaterMarks.get(pendingDesignId) ?? 0,
|
|
2410
2467
|
});
|
|
2411
2468
|
return;
|
|
2412
2469
|
}
|
|
@@ -2472,7 +2529,7 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2472
2529
|
: stored === "stale"
|
|
2473
2530
|
? "stale pending publication revision"
|
|
2474
2531
|
: "conflicting pending publication revision",
|
|
2475
|
-
revision:
|
|
2532
|
+
revision: pendingVisualEditRevisionHighWaterMarks.get(candidate.designId) ?? 0,
|
|
2476
2533
|
});
|
|
2477
2534
|
return;
|
|
2478
2535
|
}
|
|
@@ -2889,6 +2946,16 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2889
2946
|
}
|
|
2890
2947
|
sendJson(res, 404, { ok: false, error: "not found" });
|
|
2891
2948
|
});
|
|
2949
|
+
const terminateHmrClients = () => {
|
|
2950
|
+
for (const client of hmrWebSocketServer.clients)
|
|
2951
|
+
client.terminate();
|
|
2952
|
+
};
|
|
2953
|
+
// noServer upgrades are not closed by http.Server.close().
|
|
2954
|
+
const closeHttpServer = server.close.bind(server);
|
|
2955
|
+
server.close = (callback) => {
|
|
2956
|
+
terminateHmrClients();
|
|
2957
|
+
return closeHttpServer(callback);
|
|
2958
|
+
};
|
|
2892
2959
|
// Vite's proxied /@vite/client derives its HMR socket from the document's
|
|
2893
2960
|
// bridge origin. Tunnel WebSocket upgrades to the one connected dev-server
|
|
2894
2961
|
// origin so Fast Refresh remains live inside URL-backed screens. The target
|
|
@@ -2903,6 +2970,9 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2903
2970
|
"";
|
|
2904
2971
|
const browserOrigin = readHeader(req, "origin");
|
|
2905
2972
|
const sameBridgeOrigin = browserOrigin === new URL(manifest.bridgeUrl).origin;
|
|
2973
|
+
const isViteHmrSocket = readHeader(req, "sec-websocket-protocol")
|
|
2974
|
+
.split(",")
|
|
2975
|
+
.some((protocol) => protocol.trim() === "vite-hmr");
|
|
2906
2976
|
if (!constantTimeTokenMatches(providedPreviewToken, previewToken)) {
|
|
2907
2977
|
clientSocket.end("HTTP/1.1 401 Unauthorized\r\nConnection: close\r\nContent-Length: 0\r\n\r\n");
|
|
2908
2978
|
return;
|
|
@@ -2921,11 +2991,60 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2921
2991
|
delete upstreamHeaders["x-agent-native-live-edit-capability"];
|
|
2922
2992
|
delete upstreamHeaders["authorization"];
|
|
2923
2993
|
delete upstreamHeaders["cookie"];
|
|
2994
|
+
if (isViteHmrSocket) {
|
|
2995
|
+
delete upstreamHeaders["connection"];
|
|
2996
|
+
delete upstreamHeaders["upgrade"];
|
|
2997
|
+
delete upstreamHeaders["sec-websocket-key"];
|
|
2998
|
+
delete upstreamHeaders["sec-websocket-version"];
|
|
2999
|
+
delete upstreamHeaders["sec-websocket-protocol"];
|
|
3000
|
+
delete upstreamHeaders["sec-websocket-extensions"];
|
|
3001
|
+
}
|
|
2924
3002
|
upstreamHeaders.host = targetUrl.host;
|
|
2925
3003
|
upstreamHeaders.origin = new URL(manifest.devServerUrl).origin;
|
|
2926
3004
|
const cookie = mergePreviewCookieHeaders(previewSessionCookies.headerFor(targetUrl.toString()), sameBridgeOrigin ? readHeader(req, "cookie") : "");
|
|
2927
3005
|
if (cookie)
|
|
2928
3006
|
upstreamHeaders.cookie = cookie;
|
|
3007
|
+
if (isViteHmrSocket) {
|
|
3008
|
+
const hmrUrl = new URL(targetUrl);
|
|
3009
|
+
hmrUrl.protocol = targetUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
3010
|
+
hmrWebSocketServer.handleUpgrade(req, clientSocket, clientHead, (browserSocket) => {
|
|
3011
|
+
const upstreamSocket = new WebSocket(hmrUrl, "vite-hmr", {
|
|
3012
|
+
headers: upstreamHeaders,
|
|
3013
|
+
perMessageDeflate: false,
|
|
3014
|
+
});
|
|
3015
|
+
const queuedMessages = [];
|
|
3016
|
+
browserSocket.on("message", (data, isBinary) => {
|
|
3017
|
+
if (upstreamSocket.readyState === WebSocket.OPEN) {
|
|
3018
|
+
upstreamSocket.send(data, { binary: isBinary });
|
|
3019
|
+
}
|
|
3020
|
+
else if (upstreamSocket.readyState === WebSocket.CONNECTING) {
|
|
3021
|
+
queuedMessages.push({ data, isBinary });
|
|
3022
|
+
}
|
|
3023
|
+
});
|
|
3024
|
+
upstreamSocket.once("open", () => {
|
|
3025
|
+
for (const message of queuedMessages) {
|
|
3026
|
+
upstreamSocket.send(message.data, { binary: message.isBinary });
|
|
3027
|
+
}
|
|
3028
|
+
queuedMessages.length = 0;
|
|
3029
|
+
});
|
|
3030
|
+
upstreamSocket.on("message", (data, isBinary) => {
|
|
3031
|
+
const payload = webSocketDataBuffer(data);
|
|
3032
|
+
const rewritten = isBinary
|
|
3033
|
+
? undefined
|
|
3034
|
+
: rewriteViteHmrUpdate(payload, previewToken);
|
|
3035
|
+
browserSocket.send(rewritten ?? payload, { binary: isBinary });
|
|
3036
|
+
});
|
|
3037
|
+
browserSocket.once("close", () => upstreamSocket.terminate());
|
|
3038
|
+
upstreamSocket.once("close", () => browserSocket.close());
|
|
3039
|
+
upstreamSocket.on("error", () => {
|
|
3040
|
+
if (browserSocket.readyState === WebSocket.OPEN) {
|
|
3041
|
+
browserSocket.close(1011, "Dev server HMR connection failed");
|
|
3042
|
+
}
|
|
3043
|
+
});
|
|
3044
|
+
browserSocket.on("error", () => upstreamSocket.terminate());
|
|
3045
|
+
});
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
2929
3048
|
const requestImpl = targetUrl.protocol === "https:" ? https : http;
|
|
2930
3049
|
let upgraded = false;
|
|
2931
3050
|
const upstreamRequest = requestImpl.request({
|
|
@@ -2972,6 +3091,17 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2972
3091
|
});
|
|
2973
3092
|
upstreamRequest.end();
|
|
2974
3093
|
});
|
|
3094
|
+
let closePromise;
|
|
3095
|
+
const close = () => {
|
|
3096
|
+
closePromise ??= (async () => {
|
|
3097
|
+
terminateHmrClients();
|
|
3098
|
+
await new Promise((resolve) => hmrWebSocketServer.close(resolve));
|
|
3099
|
+
await new Promise((resolve, reject) => {
|
|
3100
|
+
server.close((error) => (error ? reject(error) : resolve()));
|
|
3101
|
+
});
|
|
3102
|
+
})();
|
|
3103
|
+
return closePromise;
|
|
3104
|
+
};
|
|
2975
3105
|
await new Promise((resolve, reject) => {
|
|
2976
3106
|
server.once("error", reject);
|
|
2977
3107
|
server.listen(new URL(manifest.bridgeUrl).port, "127.0.0.1", () => {
|
|
@@ -2984,11 +3114,18 @@ export async function startDesignConnectBridge(manifest, seedOrOptions) {
|
|
|
2984
3114
|
await persistBridgeToken(manifest.rootPath, bridgeToken);
|
|
2985
3115
|
}
|
|
2986
3116
|
catch (error) {
|
|
2987
|
-
await
|
|
3117
|
+
await close();
|
|
2988
3118
|
throw error;
|
|
2989
3119
|
}
|
|
2990
3120
|
}
|
|
2991
|
-
return {
|
|
3121
|
+
return {
|
|
3122
|
+
close,
|
|
3123
|
+
server,
|
|
3124
|
+
manifest,
|
|
3125
|
+
bridgeToken,
|
|
3126
|
+
previewToken,
|
|
3127
|
+
bridgeInstanceId,
|
|
3128
|
+
};
|
|
2992
3129
|
}
|
|
2993
3130
|
export function resolveAppUrl(explicit) {
|
|
2994
3131
|
const raw = explicit ||
|
|
@@ -3338,7 +3475,10 @@ export async function runDesign(argv) {
|
|
|
3338
3475
|
}
|
|
3339
3476
|
return await new Promise((resolve) => {
|
|
3340
3477
|
const stop = () => {
|
|
3341
|
-
bridge.
|
|
3478
|
+
void bridge.close().then(() => resolve(0), (error) => {
|
|
3479
|
+
console.error("[design connect] bridge shutdown failed", error);
|
|
3480
|
+
resolve(1);
|
|
3481
|
+
});
|
|
3342
3482
|
};
|
|
3343
3483
|
for (const signal of ["SIGINT", "SIGTERM", "SIGHUP"]) {
|
|
3344
3484
|
process.once(signal, stop);
|
|
@@ -38,19 +38,19 @@ export declare const postAwareness: import("h3").EventHandlerWithFetch<import("h
|
|
|
38
38
|
error: string;
|
|
39
39
|
states?: undefined;
|
|
40
40
|
} | {
|
|
41
|
+
error?: undefined;
|
|
41
42
|
states: {
|
|
42
43
|
clientId: number;
|
|
43
44
|
state: string;
|
|
44
45
|
}[];
|
|
45
|
-
error?: undefined;
|
|
46
46
|
}>>;
|
|
47
47
|
export declare const getActiveUsers: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
48
48
|
error: string;
|
|
49
49
|
users?: undefined;
|
|
50
50
|
} | {
|
|
51
|
+
error?: undefined;
|
|
51
52
|
users: {
|
|
52
53
|
clientId: number;
|
|
53
54
|
lastSeen: number;
|
|
54
55
|
}[];
|
|
55
|
-
error?: undefined;
|
|
56
56
|
}>>;
|
package/dist/collab/routes.d.ts
CHANGED
|
@@ -8,8 +8,8 @@ export declare const getCollabState: import("h3").EventHandlerWithFetch<import("
|
|
|
8
8
|
state: string;
|
|
9
9
|
}>>;
|
|
10
10
|
export declare const postCollabUpdate: import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
|
-
error: string;
|
|
12
11
|
ok?: undefined;
|
|
12
|
+
error: string;
|
|
13
13
|
} | {
|
|
14
14
|
error?: undefined;
|
|
15
15
|
ok: boolean;
|
|
@@ -34,6 +34,13 @@ async function assertOk(res, label) {
|
|
|
34
34
|
throw Object.assign(new Error(`${label} (${res.status}): ${body || res.statusText}`), { status: res.status });
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
function confirmedBuilderAuthorizationFailure(error) {
|
|
38
|
+
const cause = error instanceof Error ? error : new Error(String(error));
|
|
39
|
+
return Object.assign(new Error(cause.message, { cause }), {
|
|
40
|
+
status: 401,
|
|
41
|
+
errorCode: "builder_credentials_rejected",
|
|
42
|
+
});
|
|
43
|
+
}
|
|
37
44
|
/**
|
|
38
45
|
* Run a Builder asset API call, and on a 401 refresh the OAuth access token
|
|
39
46
|
* once and retry. A token can be revoked or rotated before its stated
|
|
@@ -51,10 +58,21 @@ async function withAssetAuthorization(run, held = {}) {
|
|
|
51
58
|
const refreshed = await assetAuthorization({ forceRefresh: true });
|
|
52
59
|
// The same token again (no refresh token, a key credential) would only
|
|
53
60
|
// repeat the 401; report the original refusal instead.
|
|
54
|
-
if (refreshed.authorization === auth.authorization)
|
|
61
|
+
if (refreshed.authorization === auth.authorization) {
|
|
62
|
+
if (auth.apiKey)
|
|
63
|
+
throw confirmedBuilderAuthorizationFailure(error);
|
|
55
64
|
throw error;
|
|
65
|
+
}
|
|
56
66
|
held.auth = refreshed;
|
|
57
|
-
|
|
67
|
+
try {
|
|
68
|
+
return await run(refreshed);
|
|
69
|
+
}
|
|
70
|
+
catch (retryError) {
|
|
71
|
+
if (retryError?.status !== 401) {
|
|
72
|
+
throw retryError;
|
|
73
|
+
}
|
|
74
|
+
throw confirmedBuilderAuthorizationFailure(retryError);
|
|
75
|
+
}
|
|
58
76
|
}
|
|
59
77
|
}
|
|
60
78
|
async function uploadLargeFileViaSignedUrl(input, held, bareMimeType, bytes) {
|
|
@@ -11,9 +11,9 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
11
11
|
enabled?: undefined;
|
|
12
12
|
nextRun?: undefined;
|
|
13
13
|
} | {
|
|
14
|
+
deleted?: undefined;
|
|
14
15
|
name: string;
|
|
15
16
|
enabled: boolean;
|
|
16
17
|
nextRun: string;
|
|
17
|
-
deleted?: undefined;
|
|
18
18
|
}>;
|
|
19
19
|
export default _default;
|
|
@@ -10,10 +10,20 @@ export interface AppMcpTool {
|
|
|
10
10
|
}
|
|
11
11
|
export interface ListVisibleMcpToolsOptions {
|
|
12
12
|
serverId?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Keep only tools served from this provider's MCP endpoint, matched on the
|
|
15
|
+
* server URL. A server id is a name the user chose, so it cannot prove which
|
|
16
|
+
* provider answers the call.
|
|
17
|
+
*/
|
|
18
|
+
providerId?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface CallMcpToolOptions {
|
|
21
|
+
/** Refuse the call unless the server's URL belongs to this provider. */
|
|
22
|
+
providerId?: string;
|
|
13
23
|
}
|
|
14
24
|
export declare class McpAppApiError extends Error {
|
|
15
25
|
readonly statusCode: 401 | 403 | 503;
|
|
16
26
|
constructor(message: string, statusCode: 401 | 403 | 503);
|
|
17
27
|
}
|
|
18
28
|
export declare function listVisibleMcpTools(options?: ListVisibleMcpToolsOptions): Promise<AppMcpTool[]>;
|
|
19
|
-
export declare function callMcpTool(serverId: string, originalToolName: string, args?: Record<string, unknown
|
|
29
|
+
export declare function callMcpTool(serverId: string, originalToolName: string, args?: Record<string, unknown>, options?: CallMcpToolOptions): Promise<unknown>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isToolVisibilityModelOnly } from "@modelcontextprotocol/ext-apps/app-bridge";
|
|
2
2
|
import { getMcpManagerForPrincipal } from "../server/agent-chat/mcp-glue.js";
|
|
3
3
|
import { getRequestContext } from "../server/request-context.js";
|
|
4
|
+
import { hasMcpProviderMatchRules, mcpServerUrlMatchesProvider, } from "../shared/mcp-provider-hosts.js";
|
|
4
5
|
import { buildMcpToolName, } from "./manager.js";
|
|
5
6
|
import { normalizeMcpPrincipal } from "./principal.js";
|
|
6
7
|
import { parseMergedKey } from "./remote-store.js";
|
|
@@ -20,16 +21,19 @@ export async function listVisibleMcpTools(options = {}) {
|
|
|
20
21
|
? manager.getToolsForServer(options.serverId)
|
|
21
22
|
: manager.getTools();
|
|
22
23
|
return tools
|
|
23
|
-
.filter((tool) => isToolVisibleToApp(tool, context)
|
|
24
|
+
.filter((tool) => isToolVisibleToApp(tool, context) &&
|
|
25
|
+
isServerForProvider(manager, tool.source, options.providerId))
|
|
24
26
|
.map(toAppMcpTool);
|
|
25
27
|
}
|
|
26
|
-
export async function callMcpTool(serverId, originalToolName, args = {}) {
|
|
28
|
+
export async function callMcpTool(serverId, originalToolName, args = {}, options = {}) {
|
|
27
29
|
const context = requireAuthenticatedRequest();
|
|
28
30
|
const manager = await requireMcpManager(context);
|
|
29
31
|
const tool = manager
|
|
30
32
|
.getToolsForServer(serverId)
|
|
31
33
|
.find((candidate) => candidate.originalName === originalToolName);
|
|
32
|
-
if (!tool ||
|
|
34
|
+
if (!tool ||
|
|
35
|
+
!isToolVisibleToApp(tool, context) ||
|
|
36
|
+
!isServerForProvider(manager, serverId, options.providerId)) {
|
|
33
37
|
throw new McpAppApiError("MCP tool is not available in this request scope.", 403);
|
|
34
38
|
}
|
|
35
39
|
return manager.callTool(buildMcpToolName(serverId, originalToolName), args);
|
|
@@ -81,6 +85,16 @@ function isToolVisibleToApp(tool, context) {
|
|
|
81
85
|
return false;
|
|
82
86
|
}
|
|
83
87
|
}
|
|
88
|
+
function isServerForProvider(manager, serverId, providerId) {
|
|
89
|
+
if (providerId === undefined)
|
|
90
|
+
return true;
|
|
91
|
+
if (!hasMcpProviderMatchRules(providerId)) {
|
|
92
|
+
throw new Error(`No MCP provider match rules for "${providerId}". Add it to MCP_PROVIDER_ENDPOINTS or MCP_LINK_HOSTS before filtering by it.`);
|
|
93
|
+
}
|
|
94
|
+
const config = manager.getServerConfig(serverId);
|
|
95
|
+
return (config?.type === "http" &&
|
|
96
|
+
mcpServerUrlMatchesProvider(providerId, config.url) === true);
|
|
97
|
+
}
|
|
84
98
|
function toAppMcpTool(tool) {
|
|
85
99
|
return {
|
|
86
100
|
serverId: tool.source,
|
|
@@ -10,7 +10,7 @@ export { mountMcpServersRoutes, buildMergedConfig, builtinMergedConfigKey, McpCo
|
|
|
10
10
|
export { mountMcpHubRoutes, listHubServers, getHubStatus, isHubServeEnabled, isHubConsumeEnabled, type HubServerRecord, type HubServersResponse, } from "./hub-routes.js";
|
|
11
11
|
export { fetchHubServers } from "./hub-client.js";
|
|
12
12
|
export { isMcpToolAllowedForRequest } from "./visibility.js";
|
|
13
|
-
export { callMcpTool, listVisibleMcpTools, McpAppApiError, type AppMcpTool, type ListVisibleMcpToolsOptions, } from "./app-api.js";
|
|
13
|
+
export { callMcpTool, listVisibleMcpTools, McpAppApiError, type AppMcpTool, type CallMcpToolOptions, type ListVisibleMcpToolsOptions, } from "./app-api.js";
|
|
14
14
|
export { classifyMcpToolCall, evaluateMcpToolCallPolicy, type McpToolCallClassification, type McpToolEffect, type McpToolFamily, type McpToolInvocationPolicy, type McpToolPolicyDecision, } from "./tool-policy.js";
|
|
15
15
|
export { configureScreenMemory, queryScreenMemoryForAgent, queryScreenMemoryContext, readScreenMemoryStatus, type ScreenMemoryConfig, type ScreenMemoryAgentQueryResult, type ScreenMemoryContextItem, type ScreenMemoryCoverageGap, type ScreenMemoryEvidenceItem, type ScreenMemoryEvidenceSourceType, type ScreenMemoryQueryResult, type ScreenMemoryRetrievalCoverage, type ScreenMemorySegmentReference, type ScreenMemoryStatus, type ScreenMemoryTimeRange, type ScreenMemoryTruncation, } from "./screen-memory-local.js";
|
|
16
16
|
export { MCP_ACTION_RESULT_MARKER, isMcpActionResult, type AgentMcpAppPayload, type AgentMcpAppResourceContent, type McpActionResult, } from "./app-result.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpConfig } from "./config.js";
|
|
1
|
+
import type { McpConfig, McpServerConfig } from "./config.js";
|
|
2
2
|
export declare const MCP_TOOL_PREFIX = "mcp__";
|
|
3
3
|
export interface McpTool {
|
|
4
4
|
source: string;
|
|
@@ -66,6 +66,8 @@ export declare class McpClientManager {
|
|
|
66
66
|
getTools(): McpTool[];
|
|
67
67
|
getTool(prefixedName: string): McpTool | null;
|
|
68
68
|
getToolsForServer(serverId: string): McpTool[];
|
|
69
|
+
/** The config the server's current tools were loaded from. */
|
|
70
|
+
getServerConfig(serverId: string): McpServerConfig | null;
|
|
69
71
|
hasServer(serverId: string): boolean;
|
|
70
72
|
callTool(prefixedName: string, args: unknown): Promise<unknown>;
|
|
71
73
|
readResource(serverId: string, uri: string): Promise<unknown>;
|
|
@@ -526,6 +526,10 @@ export class McpClientManager {
|
|
|
526
526
|
getToolsForServer(serverId) {
|
|
527
527
|
return [...(this.servers.get(serverId)?.tools ?? [])];
|
|
528
528
|
}
|
|
529
|
+
/** The config the server's current tools were loaded from. */
|
|
530
|
+
getServerConfig(serverId) {
|
|
531
|
+
return this.servers.get(serverId)?.config ?? null;
|
|
532
|
+
}
|
|
529
533
|
hasServer(serverId) {
|
|
530
534
|
const entry = this.servers.get(serverId);
|
|
531
535
|
return !!entry?.client && !entry.error;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
export declare function createNotificationsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<"" | import("./types.js").Notification[] | {
|
|
2
|
+
error?: undefined;
|
|
2
3
|
count: number;
|
|
3
4
|
updated?: undefined;
|
|
4
5
|
ok?: undefined;
|
|
5
|
-
error?: undefined;
|
|
6
6
|
} | {
|
|
7
|
+
error?: undefined;
|
|
7
8
|
count?: undefined;
|
|
8
9
|
updated: number;
|
|
9
10
|
ok?: undefined;
|
|
10
|
-
error?: undefined;
|
|
11
11
|
} | {
|
|
12
12
|
count?: undefined;
|
|
13
13
|
updated?: undefined;
|
|
14
14
|
error: string;
|
|
15
15
|
ok?: undefined;
|
|
16
16
|
} | {
|
|
17
|
+
error?: undefined;
|
|
17
18
|
count?: undefined;
|
|
18
19
|
updated?: undefined;
|
|
19
20
|
ok: boolean;
|
|
20
|
-
error?: undefined;
|
|
21
21
|
}>>;
|
|
@@ -3,4 +3,11 @@ import type { SandboxCodeEvaluator } from "../../coding-tools/run-code.js";
|
|
|
3
3
|
export declare function loadRunCodeToolEntries(supplier: () => Record<string, ActionEntry>, runCodeOptions?: {
|
|
4
4
|
bridgeTools?: string[];
|
|
5
5
|
evaluator?: SandboxCodeEvaluator;
|
|
6
|
+
/**
|
|
7
|
+
* Names of actions the app defines itself. These entries are spread after
|
|
8
|
+
* the app's actions, so a same-named entry here would silently replace the
|
|
9
|
+
* app's version (and drop its `mcpTool` exposure). Leave those names to
|
|
10
|
+
* the app.
|
|
11
|
+
*/
|
|
12
|
+
appActionNames?: Iterable<string>;
|
|
6
13
|
}): Promise<Record<string, ActionEntry>>;
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { getAppConfig } from "../../app-config/index.js";
|
|
2
2
|
export async function loadRunCodeToolEntries(supplier, runCodeOptions) {
|
|
3
|
+
const entries = await createRunCodeToolEntries(supplier, runCodeOptions);
|
|
4
|
+
for (const name of runCodeOptions?.appActionNames ?? []) {
|
|
5
|
+
delete entries[name];
|
|
6
|
+
}
|
|
7
|
+
return entries;
|
|
8
|
+
}
|
|
9
|
+
async function createRunCodeToolEntries(supplier, runCodeOptions) {
|
|
3
10
|
try {
|
|
4
11
|
const { createRunCodeEntry, createGetCodeExecutionEntry } = await import("../../coding-tools/run-code.js");
|
|
5
12
|
const { createToolOrchestrationEntry } = await import("../../coding-tools/tool-orchestration.js");
|
|
@@ -5,10 +5,14 @@ import { foldAssistantTurn, type ThreadSuggestionRun } from "../agent/thread-dat
|
|
|
5
5
|
import type { AgentChatEvent, AgentChatScope } from "../agent/types.js";
|
|
6
6
|
import { type QueuedMessage } from "../chat-threads/store.js";
|
|
7
7
|
import type { ResolvedKeyReference } from "../secrets/substitution.js";
|
|
8
|
+
import { type TrackingMeta } from "../tracking/registry.js";
|
|
8
9
|
import { handleSharedThreadRequest, type SharedThreadRouteDependencies } from "./agent-chat/shared-thread.js";
|
|
9
10
|
export { handleSharedThreadRequest };
|
|
10
11
|
export type { SharedThreadRouteDependencies };
|
|
11
|
-
|
|
12
|
+
type AgentChatRunTrackingSource = Pick<TrackingMeta, "userId" | "authUserId" | "anonymousId" | "sessionId"> & {
|
|
13
|
+
isSyntheticTraffic?: boolean;
|
|
14
|
+
};
|
|
15
|
+
export declare function trackAgentChatRunLifecycle(event: "run_started" | "run_finished" | "run_no_reply", threadId: string | undefined, attemptId: string | undefined, userId?: string, properties?: Record<string, unknown>, appId?: string, trackingSource?: AgentChatRunTrackingSource): void;
|
|
12
16
|
import { buildSelectedA2AReceiverContext, createA2AEngineToolSurface, DEFAULT_DELEGATED_MAX_ITERATIONS, DEFAULT_DELEGATED_MAX_RUN_INPUT_TOKENS, DEFAULT_DELEGATED_MAX_TOOL_RESULT_CHARS, isSelectedA2AReceiver, runA2AAgentLoop, runMCPAgentLoop, assembleA2AFinalResponse, buildPublicAgentA2ASkills } from "./agent-chat/action-filters-a2a.js";
|
|
13
17
|
import { _agentChatPromptSectionsForTests } from "./agent-chat/framework-prompts.js";
|
|
14
18
|
import { type AgentChatPluginOptions, type NitroPluginDef } from "./agent-chat/plugin-options.js";
|
|
@@ -71,15 +71,18 @@ import { getModelFamilyOverlay } from "./prompts/index.js";
|
|
|
71
71
|
import { mountRealtimeVoiceRoutes } from "./realtime-voice.js";
|
|
72
72
|
import { runWithRequestContext, getRequestContext, getRequestOrgId, getRequestUserEmail, getRequestRunContext, ensureRequestRunContext, } from "./request-context.js";
|
|
73
73
|
export { handleSharedThreadRequest };
|
|
74
|
-
export function trackAgentChatRunLifecycle(event, threadId, attemptId, userId, properties = {}, appId) {
|
|
75
|
-
if (!threadId?.trim() ||
|
|
74
|
+
export function trackAgentChatRunLifecycle(event, threadId, attemptId, userId, properties = {}, appId, trackingSource) {
|
|
75
|
+
if (!threadId?.trim() ||
|
|
76
|
+
!attemptId?.trim() ||
|
|
77
|
+
trackingSource?.isSyntheticTraffic === true) {
|
|
76
78
|
return;
|
|
79
|
+
}
|
|
77
80
|
track(event, {
|
|
78
81
|
...properties,
|
|
79
82
|
...(appId ? { app_name: appId, template_name: appId } : {}),
|
|
80
83
|
thread_id: threadId,
|
|
81
84
|
attempt_id: attemptId,
|
|
82
|
-
}, runLifecycleTrackingSource(userId));
|
|
85
|
+
}, trackingSource ?? runLifecycleTrackingSource(userId));
|
|
83
86
|
}
|
|
84
87
|
/**
|
|
85
88
|
* The run's owner is set on the run context only once its system prompt is
|
|
@@ -1392,6 +1395,7 @@ export function createAgentChatPlugin(options) {
|
|
|
1392
1395
|
() => filterRuntimeActionsToSurface(prodRunCodeToolActions), {
|
|
1393
1396
|
bridgeTools: options?.codeExecution?.bridgeTools,
|
|
1394
1397
|
evaluator: productionEvaluator,
|
|
1398
|
+
appActionNames: Object.keys(templateScriptsAll),
|
|
1395
1399
|
});
|
|
1396
1400
|
const leanRunCodeTool = await loadRunCodeToolEntries(
|
|
1397
1401
|
// Lean prompt mode intentionally exposes a much smaller action
|
|
@@ -1399,6 +1403,7 @@ export function createAgentChatPlugin(options) {
|
|
|
1399
1403
|
() => filterRuntimeActionsToSurface(leanRunCodeToolActions), {
|
|
1400
1404
|
bridgeTools: options?.codeExecution?.bridgeTools,
|
|
1401
1405
|
evaluator: productionEvaluator,
|
|
1406
|
+
appActionNames: Object.keys(templateScriptsAll),
|
|
1402
1407
|
});
|
|
1403
1408
|
// Full coding tool registry (bash/read/edit/write) for "trusted" prod.
|
|
1404
1409
|
// In dev mode this is handled separately via devHandler below.
|
|
@@ -1431,6 +1436,7 @@ export function createAgentChatPlugin(options) {
|
|
|
1431
1436
|
? await loadRunCodeToolEntries(() => filterRuntimeActionsToSurface(devRunCodeToolActions), {
|
|
1432
1437
|
bridgeTools: options?.codeExecution?.bridgeTools,
|
|
1433
1438
|
evaluator: "node",
|
|
1439
|
+
appActionNames: Object.keys(templateScriptsAll),
|
|
1434
1440
|
})
|
|
1435
1441
|
: {};
|
|
1436
1442
|
// Registry `generateCorpusToolsPrompt` (below) reads from to decide what
|
|
@@ -2656,7 +2662,7 @@ export function createAgentChatPlugin(options) {
|
|
|
2656
2662
|
}
|
|
2657
2663
|
// Callback to persist agent response when run finishes (even if client disconnected).
|
|
2658
2664
|
// Reconstructs the assistant message from buffered events and appends to thread_data.
|
|
2659
|
-
const onRunComplete = async (run, threadId) => {
|
|
2665
|
+
const onRunComplete = async (run, threadId, trackingSource) => {
|
|
2660
2666
|
const runThreadId = String(run?.threadId ?? threadId ?? "");
|
|
2661
2667
|
const chatScope = getRequestRunContext()?.chatScope;
|
|
2662
2668
|
const assistantMsg = buildAssistantMessage(run.events ?? [], run.runId, {
|
|
@@ -2682,9 +2688,9 @@ export function createAgentChatPlugin(options) {
|
|
|
2682
2688
|
...(failureCode?.type === "error"
|
|
2683
2689
|
? { failure_code: failureCode.errorCode ?? "unknown" }
|
|
2684
2690
|
: {}),
|
|
2685
|
-
}, options?.appId);
|
|
2691
|
+
}, options?.appId, trackingSource);
|
|
2686
2692
|
if (!assistantMsg) {
|
|
2687
|
-
trackAgentChatRunLifecycle("run_no_reply", runThreadId || undefined, run.runId, getRequestRunContext()?.owner, {}, options?.appId);
|
|
2693
|
+
trackAgentChatRunLifecycle("run_no_reply", runThreadId || undefined, run.runId, getRequestRunContext()?.owner, {}, options?.appId, trackingSource);
|
|
2688
2694
|
}
|
|
2689
2695
|
if (!threadId) {
|
|
2690
2696
|
if (runThreadId)
|
|
@@ -3535,10 +3541,10 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
3535
3541
|
trackAgentChatRunLifecycle("run_started", threadId, runId, runCtx?.owner, {}, options?.appId);
|
|
3536
3542
|
await runPreAgentTurnAutosave(options?.onAgentTurnStart, runCtx?.chatScope, { threadId, runId });
|
|
3537
3543
|
},
|
|
3538
|
-
onRunComplete: async (run, threadId) => {
|
|
3544
|
+
onRunComplete: async (run, threadId, trackingSource) => {
|
|
3539
3545
|
if (threadId)
|
|
3540
3546
|
_runSendByThread.delete(threadId);
|
|
3541
|
-
await onRunComplete(run, threadId);
|
|
3547
|
+
await onRunComplete(run, threadId, trackingSource);
|
|
3542
3548
|
},
|
|
3543
3549
|
resolveAdditionalActions: ({ ownerEmail, orgId }) => getMcpActionEntriesForPrincipal(ownerEmail, orgId),
|
|
3544
3550
|
// Resolve owner from session for usage attribution in hosted prod
|
|
@@ -3588,10 +3594,10 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
3588
3594
|
}
|
|
3589
3595
|
trackAgentChatRunLifecycle("run_started", threadId, runId, runCtx?.owner, {}, options?.appId);
|
|
3590
3596
|
},
|
|
3591
|
-
onRunComplete: async (run, threadId) => {
|
|
3597
|
+
onRunComplete: async (run, threadId, trackingSource) => {
|
|
3592
3598
|
if (threadId)
|
|
3593
3599
|
_runSendByThread.delete(threadId);
|
|
3594
|
-
await onRunComplete(run, threadId);
|
|
3600
|
+
await onRunComplete(run, threadId, trackingSource);
|
|
3595
3601
|
},
|
|
3596
3602
|
resolveOwnerEmail: getOwnerFromEvent,
|
|
3597
3603
|
})
|
|
@@ -3790,10 +3796,10 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
3790
3796
|
trackAgentChatRunLifecycle("run_started", threadId, runId, runCtx?.owner, {}, options?.appId);
|
|
3791
3797
|
await runPreAgentTurnAutosave(options?.onAgentTurnStart, runCtx?.chatScope, { threadId, runId });
|
|
3792
3798
|
},
|
|
3793
|
-
onRunComplete: async (run, threadId) => {
|
|
3799
|
+
onRunComplete: async (run, threadId, trackingSource) => {
|
|
3794
3800
|
if (threadId)
|
|
3795
3801
|
_runSendByThread.delete(threadId);
|
|
3796
|
-
await onRunComplete(run, threadId);
|
|
3802
|
+
await onRunComplete(run, threadId, trackingSource);
|
|
3797
3803
|
},
|
|
3798
3804
|
});
|
|
3799
3805
|
}
|
|
@@ -16,9 +16,9 @@ export declare function createAgentEngineDisconnectHandler(): import("h3").Event
|
|
|
16
16
|
error: any;
|
|
17
17
|
scope?: undefined;
|
|
18
18
|
} | {
|
|
19
|
+
error?: undefined;
|
|
19
20
|
ok: boolean;
|
|
20
21
|
scope: "org" | "user";
|
|
21
|
-
error?: undefined;
|
|
22
22
|
}>>;
|
|
23
23
|
export interface DefaultModelSelectionRequest {
|
|
24
24
|
engine: string;
|
|
@@ -626,8 +626,8 @@ export declare function createPublicRemoteAgentsHandler(discover?: PublicAgentDi
|
|
|
626
626
|
error: string;
|
|
627
627
|
agents?: undefined;
|
|
628
628
|
} | {
|
|
629
|
-
error?: undefined;
|
|
630
629
|
agents: Omit<import("./agent-discovery.js").DiscoveredAgent, "auth" | "kind">[];
|
|
630
|
+
error?: undefined;
|
|
631
631
|
}>>;
|
|
632
632
|
export declare function getBuilderConnectErrorDisposition(error: unknown, connectAttemptId: string | null): "correlated" | "legacy" | null;
|
|
633
633
|
export declare function getBuilderConnectErrorKey(ownerEmail: string, connectAttemptId?: string | null): string;
|
|
@@ -54,8 +54,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
54
54
|
expiresAt?: undefined;
|
|
55
55
|
ttlSeconds?: undefined;
|
|
56
56
|
} | {
|
|
57
|
+
error?: undefined;
|
|
57
58
|
token: string;
|
|
58
59
|
expiresAt: string;
|
|
59
60
|
ttlSeconds: number;
|
|
60
|
-
error?: undefined;
|
|
61
61
|
}>>;
|
|
@@ -13,6 +13,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
13
13
|
executionEngine?: string;
|
|
14
14
|
executionCwd?: string;
|
|
15
15
|
}, {
|
|
16
|
+
deleted?: undefined;
|
|
16
17
|
created: boolean;
|
|
17
18
|
name: string;
|
|
18
19
|
scope: "organization" | "personal";
|
|
@@ -23,7 +24,6 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
23
24
|
reasoningEffort: "auto" | "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh";
|
|
24
25
|
webhookPath: string;
|
|
25
26
|
nextRun: string;
|
|
26
|
-
deleted?: undefined;
|
|
27
27
|
enabled?: undefined;
|
|
28
28
|
executionHostId?: undefined;
|
|
29
29
|
executionEngine?: undefined;
|
|
@@ -45,11 +45,11 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
45
45
|
nextRun?: undefined;
|
|
46
46
|
webhookPath?: undefined;
|
|
47
47
|
} | {
|
|
48
|
+
deleted?: undefined;
|
|
48
49
|
created?: undefined;
|
|
49
50
|
scope?: undefined;
|
|
50
51
|
triggerType?: undefined;
|
|
51
52
|
event?: undefined;
|
|
52
|
-
deleted?: undefined;
|
|
53
53
|
name: string;
|
|
54
54
|
enabled: boolean;
|
|
55
55
|
schedule: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.200.0
|
|
3
|
+
"version": "0.200.0",
|
|
4
4
|
"description": "The agentic application framework for building autonomous agents with intuitive UIs",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -663,12 +663,13 @@
|
|
|
663
663
|
"safe-regex2": "5.1.1",
|
|
664
664
|
"turndown": "^7.2.4",
|
|
665
665
|
"undici": "^7.28.0",
|
|
666
|
+
"ws": "^8.22.0",
|
|
666
667
|
"y-protocols": "^1.0.7",
|
|
667
668
|
"yaml": "^2.9.0",
|
|
668
669
|
"yjs": "^13.6.33",
|
|
669
670
|
"zod": "^4.3.6",
|
|
670
|
-
"@agent-native/agentkit": "^0.200.0
|
|
671
|
-
"@agent-native/recap-cli": "^0.5.
|
|
671
|
+
"@agent-native/agentkit": "^0.200.0",
|
|
672
|
+
"@agent-native/recap-cli": "^0.5.60"
|
|
672
673
|
},
|
|
673
674
|
"devDependencies": {
|
|
674
675
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -735,11 +736,10 @@
|
|
|
735
736
|
"typescript-7": "npm:typescript@^7.0.2",
|
|
736
737
|
"vite": "8.1.0",
|
|
737
738
|
"vitest": "^4.1.5",
|
|
738
|
-
"ws": "^8.18.0",
|
|
739
739
|
"xlsx": "^0.18.5"
|
|
740
740
|
},
|
|
741
741
|
"peerDependencies": {
|
|
742
|
-
"@agent-native/core-corpus": "0.
|
|
742
|
+
"@agent-native/core-corpus": ">=0.196.0",
|
|
743
743
|
"@ai-sdk/anthropic": ">=3",
|
|
744
744
|
"@ai-sdk/cohere": ">=3",
|
|
745
745
|
"@ai-sdk/google": ">=3",
|
|
@@ -781,7 +781,6 @@
|
|
|
781
781
|
"tailwindcss": ">=4",
|
|
782
782
|
"ts-morph": "^28.0.0",
|
|
783
783
|
"vite": ">=7",
|
|
784
|
-
"ws": ">=8",
|
|
785
784
|
"xlsx": "^0.18.5"
|
|
786
785
|
},
|
|
787
786
|
"peerDependenciesMeta": {
|
|
@@ -914,9 +913,6 @@
|
|
|
914
913
|
"vite": {
|
|
915
914
|
"optional": true
|
|
916
915
|
},
|
|
917
|
-
"ws": {
|
|
918
|
-
"optional": true
|
|
919
|
-
},
|
|
920
916
|
"xlsx": {
|
|
921
917
|
"optional": true
|
|
922
918
|
}
|