@agent-native/core 0.209.1-nightly-20261015153252 → 0.209.1
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/a2a/index.d.ts +1 -1
- package/dist/a2a/index.js +1 -1
- package/dist/a2a/server.d.ts +10 -0
- package/dist/a2a/server.js +96 -0
- package/dist/agent/production-agent.d.ts +2 -0
- package/dist/agent/production-agent.js +43 -6
- package/dist/agent/submission-deadline.d.ts +1 -0
- package/dist/agent/submission-deadline.js +27 -0
- package/dist/agent/thread-data-builder.d.ts +2 -1
- package/dist/agent/thread-data-builder.js +37 -6
- package/dist/authorization/check-action.js +4 -3
- package/dist/chat-threads/store.d.ts +1 -0
- package/dist/chat-threads/store.js +34 -2
- package/dist/client/agent-chat.d.ts +3 -0
- package/dist/client/agent-chat.js +9 -0
- package/dist/client/chat/agentkit-agent-native.js +126 -3
- package/dist/client/error-format.d.ts +2 -0
- package/dist/client/error-format.js +10 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/org/index.d.ts +1 -1
- package/dist/org/index.js +1 -1
- package/dist/org/workspace-app-access-outcome.d.ts +45 -0
- package/dist/org/workspace-app-access-outcome.js +80 -0
- package/dist/org/workspace-app-access-request.d.ts +2 -2
- package/dist/org/workspace-app-access-request.js +2 -2
- package/dist/org/workspace-app-access.d.ts +8 -3
- package/dist/org/workspace-app-access.js +122 -30
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +6 -6
- package/dist/server/action-routes.js +10 -7
- package/dist/server/agent-chat-plugin.js +28 -2
- package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
- package/dist/server/auth.js +3 -3
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/triggers/actions/manage-automation.d.ts +3 -3
- package/package.json +4 -4
|
@@ -9,11 +9,33 @@ import { isHostedWorkspaceRuntime, resolveVercelDeploymentProtectionHeaders, } f
|
|
|
9
9
|
import { workspaceUserGroupsIncludeUser } from "../workspace-connections/groups.js";
|
|
10
10
|
import { isMissingOrganizationTableError } from "./membership.js";
|
|
11
11
|
import { getCachedWorkspaceAccess, invalidateMemberOrgCaches, rememberWorkspaceAccess, workspaceAccessGenerationNow, } from "./request-org-cache.js";
|
|
12
|
+
import { describeFetchFailure, isWorkspaceAppAccessUnavailable, registryErrorDetail, workspaceAppAccessUnavailable, WORKSPACE_APP_ACCESS_UNAVAILABLE, } from "./workspace-app-access-outcome.js";
|
|
13
|
+
export { WORKSPACE_APP_ACCESS_UNAVAILABLE, WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE, isWorkspaceAppAccessUnavailable, workspaceAppAccessUnavailableBody, } from "./workspace-app-access-outcome.js";
|
|
12
14
|
const WORKSPACE_APPS_ACTION_PATH = "/_agent-native/actions/list-workspace-apps";
|
|
13
15
|
const WORKSPACE_APP_CLAIM_ACTION_PATH = "/_agent-native/actions/claim-workspace-app-organization";
|
|
14
16
|
const WORKSPACE_APP_ACCESS_TIMEOUT_MS = 10_000;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
// An unavailable registry is re-asked on every request, so one failing page
|
|
18
|
+
// load would otherwise log the same cause dozens of times. The key is
|
|
19
|
+
// categorical only: `detail` is upstream text, and a per-request id in it would
|
|
20
|
+
// grow this set without bound.
|
|
21
|
+
const reportedUnavailable = new Set();
|
|
22
|
+
function reportUnavailable(outcome) {
|
|
23
|
+
const key = [
|
|
24
|
+
outcome.reason,
|
|
25
|
+
outcome.upstreamStatus ?? "",
|
|
26
|
+
outcome.audience ?? "",
|
|
27
|
+
].join("|");
|
|
28
|
+
if (reportedUnavailable.has(key))
|
|
29
|
+
return outcome;
|
|
30
|
+
reportedUnavailable.add(key);
|
|
31
|
+
console.error("[workspace-app-access] unavailable", {
|
|
32
|
+
reason: outcome.reason,
|
|
33
|
+
upstreamStatus: outcome.upstreamStatus,
|
|
34
|
+
audience: outcome.audience,
|
|
35
|
+
detail: outcome.detail,
|
|
36
|
+
});
|
|
37
|
+
return outcome;
|
|
38
|
+
}
|
|
17
39
|
const inFlightWorkspaceAppRegistryReads = new Map();
|
|
18
40
|
function normalizedEmail(email) {
|
|
19
41
|
return email.trim().toLowerCase();
|
|
@@ -153,19 +175,26 @@ async function hostedWorkspaceAppAccess(appId, context, email) {
|
|
|
153
175
|
if (!configuredDirectory)
|
|
154
176
|
return null;
|
|
155
177
|
const auth = await resolveHostedWorkspaceAppAuth(configuredDirectory, context, email);
|
|
156
|
-
if (
|
|
157
|
-
return
|
|
178
|
+
if (isWorkspaceAppAccessUnavailable(auth))
|
|
179
|
+
return reportUnavailable(auth);
|
|
158
180
|
const controller = new AbortController();
|
|
159
181
|
const timeout = setTimeout(() => controller.abort(), WORKSPACE_APP_ACCESS_TIMEOUT_MS);
|
|
160
182
|
try {
|
|
161
183
|
const registry = await waitForRegistryResult(getHostedWorkspaceAppRegistry(auth), controller.signal);
|
|
162
|
-
if (!registry
|
|
163
|
-
return
|
|
184
|
+
if (!registry) {
|
|
185
|
+
return reportUnavailable(workspaceAppAccessUnavailable("registry-timeout", {
|
|
186
|
+
audience: auth.audience,
|
|
187
|
+
}));
|
|
164
188
|
}
|
|
189
|
+
if (registry.status === "unavailable")
|
|
190
|
+
return reportUnavailable(registry);
|
|
165
191
|
const matchingApp = registry.apps.find((app) => app.id === appId);
|
|
166
192
|
if (matchingApp)
|
|
167
193
|
return !workspaceAppIsDisabled(matchingApp);
|
|
168
|
-
|
|
194
|
+
const claimed = await claimHostedWorkspaceApp(auth, appId, controller.signal);
|
|
195
|
+
return isWorkspaceAppAccessUnavailable(claimed)
|
|
196
|
+
? reportUnavailable(claimed)
|
|
197
|
+
: claimed;
|
|
169
198
|
}
|
|
170
199
|
finally {
|
|
171
200
|
clearTimeout(timeout);
|
|
@@ -185,20 +214,25 @@ async function cachedOrgDomain(orgId) {
|
|
|
185
214
|
async function resolveHostedWorkspaceAppAuth(configuredDirectory, context, email) {
|
|
186
215
|
const url = workspaceAppsActionUrl(configuredDirectory);
|
|
187
216
|
if (!url)
|
|
188
|
-
return
|
|
217
|
+
return workspaceAppAccessUnavailable("directory-url-invalid");
|
|
189
218
|
const orgId = context.orgId?.trim() || null;
|
|
219
|
+
const audience = canonicalA2AAudience(configuredDirectory);
|
|
220
|
+
let stage = "org-domain-lookup-failed";
|
|
190
221
|
try {
|
|
191
222
|
const orgDomain = orgId ? await cachedOrgDomain(orgId) : null;
|
|
192
223
|
const normalizedOrgDomain = orgDomain?.trim() || undefined;
|
|
193
|
-
if (orgId && !normalizedOrgDomain)
|
|
194
|
-
return
|
|
224
|
+
if (orgId && !normalizedOrgDomain) {
|
|
225
|
+
return workspaceAppAccessUnavailable("org-domain-missing", { audience });
|
|
226
|
+
}
|
|
195
227
|
const signingSecret = readDeployCredentialEnv("A2A_SECRET")?.trim();
|
|
196
|
-
if (!signingSecret)
|
|
197
|
-
return
|
|
228
|
+
if (!signingSecret) {
|
|
229
|
+
return workspaceAppAccessUnavailable("a2a-secret-missing", { audience });
|
|
230
|
+
}
|
|
231
|
+
stage = "token-signing-failed";
|
|
198
232
|
const token = await signA2AToken(email, normalizedOrgDomain, undefined, {
|
|
199
233
|
expiresIn: "1m",
|
|
200
234
|
preferGlobalSecret: true,
|
|
201
|
-
audience
|
|
235
|
+
audience,
|
|
202
236
|
extraClaims: {
|
|
203
237
|
jti: randomUUID(),
|
|
204
238
|
},
|
|
@@ -216,6 +250,7 @@ async function resolveHostedWorkspaceAppAuth(configuredDirectory, context, email
|
|
|
216
250
|
.digest("hex");
|
|
217
251
|
return {
|
|
218
252
|
url,
|
|
253
|
+
audience,
|
|
219
254
|
requestKey,
|
|
220
255
|
protectionHeaders,
|
|
221
256
|
headers: {
|
|
@@ -227,7 +262,7 @@ async function resolveHostedWorkspaceAppAuth(configuredDirectory, context, email
|
|
|
227
262
|
}
|
|
228
263
|
catch (error) {
|
|
229
264
|
console.error("[workspace-app-access] registry auth unavailable", error);
|
|
230
|
-
return
|
|
265
|
+
return workspaceAppAccessUnavailable(stage, { audience });
|
|
231
266
|
}
|
|
232
267
|
}
|
|
233
268
|
function waitForRegistryResult(request, signal) {
|
|
@@ -279,24 +314,50 @@ async function fetchHostedWorkspaceAppRegistry(auth) {
|
|
|
279
314
|
: {}),
|
|
280
315
|
signal: controller.signal,
|
|
281
316
|
});
|
|
282
|
-
if (!response.ok)
|
|
283
|
-
return
|
|
317
|
+
if (!response.ok) {
|
|
318
|
+
return workspaceAppAccessUnavailable("registry-http-error", {
|
|
319
|
+
upstreamStatus: response.status,
|
|
320
|
+
audience: auth.audience,
|
|
321
|
+
detail: registryErrorDetail(
|
|
322
|
+
// coercion-ok: an unreadable error body only drops the optional detail; the status is already on the outcome.
|
|
323
|
+
await response.json().catch(() => null)),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
284
326
|
const apps = workspaceAppsFromResponse(
|
|
285
327
|
// coercion-ok: malformed registry JSON is an authorization failure.
|
|
286
328
|
await response.json().catch(() => null));
|
|
287
|
-
return apps
|
|
329
|
+
return apps
|
|
330
|
+
? { status: "available", apps }
|
|
331
|
+
: workspaceAppAccessUnavailable("registry-malformed-response", {
|
|
332
|
+
upstreamStatus: response.status,
|
|
333
|
+
audience: auth.audience,
|
|
334
|
+
});
|
|
288
335
|
}
|
|
289
336
|
catch (error) {
|
|
290
337
|
console.error("[workspace-app-access] registry access check failed", error);
|
|
291
|
-
return
|
|
338
|
+
return registryFetchFailure(error, auth);
|
|
292
339
|
}
|
|
293
340
|
finally {
|
|
294
341
|
clearTimeout(timeout);
|
|
295
342
|
}
|
|
296
343
|
}
|
|
344
|
+
function registryFetchFailure(error, auth) {
|
|
345
|
+
const failure = describeFetchFailure(error);
|
|
346
|
+
return failure.timedOut
|
|
347
|
+
? workspaceAppAccessUnavailable("registry-timeout", {
|
|
348
|
+
audience: auth.audience,
|
|
349
|
+
})
|
|
350
|
+
: workspaceAppAccessUnavailable("registry-fetch-failed", {
|
|
351
|
+
audience: auth.audience,
|
|
352
|
+
detail: failure.detail,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
297
355
|
async function claimHostedWorkspaceApp(auth, appId, signal) {
|
|
356
|
+
const timedOut = () => workspaceAppAccessUnavailable("registry-timeout", {
|
|
357
|
+
audience: auth.audience,
|
|
358
|
+
});
|
|
298
359
|
if (signal.aborted)
|
|
299
|
-
return
|
|
360
|
+
return timedOut();
|
|
300
361
|
const claimUrl = new URL(auth.url);
|
|
301
362
|
claimUrl.pathname = claimUrl.pathname.replace(WORKSPACE_APPS_ACTION_PATH, WORKSPACE_APP_CLAIM_ACTION_PATH);
|
|
302
363
|
claimUrl.search = "";
|
|
@@ -313,12 +374,23 @@ async function claimHostedWorkspaceApp(auth, appId, signal) {
|
|
|
313
374
|
body: JSON.stringify({ appId }),
|
|
314
375
|
signal,
|
|
315
376
|
});
|
|
316
|
-
if (
|
|
317
|
-
return
|
|
377
|
+
if (signal.aborted)
|
|
378
|
+
return timedOut();
|
|
379
|
+
if (!claimResponse.ok) {
|
|
380
|
+
return workspaceAppAccessUnavailable("claim-http-error", {
|
|
381
|
+
upstreamStatus: claimResponse.status,
|
|
382
|
+
audience: auth.audience,
|
|
383
|
+
detail: registryErrorDetail(
|
|
384
|
+
// coercion-ok: an unreadable error body only drops the optional detail; the status is already on the outcome.
|
|
385
|
+
await claimResponse.json().catch(() => null)),
|
|
386
|
+
});
|
|
318
387
|
}
|
|
319
388
|
const claim = (await claimResponse.json().catch(() => null));
|
|
320
389
|
if (!claim || typeof claim.allowed !== "boolean") {
|
|
321
|
-
return
|
|
390
|
+
return workspaceAppAccessUnavailable("claim-malformed-response", {
|
|
391
|
+
upstreamStatus: claimResponse.status,
|
|
392
|
+
audience: auth.audience,
|
|
393
|
+
});
|
|
322
394
|
}
|
|
323
395
|
if (!claim.allowed)
|
|
324
396
|
return false;
|
|
@@ -331,20 +403,32 @@ async function claimHostedWorkspaceApp(auth, appId, signal) {
|
|
|
331
403
|
: {}),
|
|
332
404
|
signal,
|
|
333
405
|
});
|
|
334
|
-
if (
|
|
335
|
-
return
|
|
406
|
+
if (signal.aborted)
|
|
407
|
+
return timedOut();
|
|
408
|
+
if (!refreshedResponse.ok) {
|
|
409
|
+
return workspaceAppAccessUnavailable("registry-http-error", {
|
|
410
|
+
upstreamStatus: refreshedResponse.status,
|
|
411
|
+
audience: auth.audience,
|
|
412
|
+
detail: registryErrorDetail(
|
|
413
|
+
// coercion-ok: an unreadable error body only drops the optional detail; the status is already on the outcome.
|
|
414
|
+
await refreshedResponse.json().catch(() => null)),
|
|
415
|
+
});
|
|
336
416
|
}
|
|
337
417
|
const refreshedApps = workspaceAppsFromResponse(
|
|
338
418
|
// coercion-ok: malformed registry JSON is an authorization failure.
|
|
339
419
|
await refreshedResponse.json().catch(() => null));
|
|
340
|
-
if (!refreshedApps)
|
|
341
|
-
return
|
|
420
|
+
if (!refreshedApps) {
|
|
421
|
+
return workspaceAppAccessUnavailable("registry-malformed-response", {
|
|
422
|
+
upstreamStatus: refreshedResponse.status,
|
|
423
|
+
audience: auth.audience,
|
|
424
|
+
});
|
|
425
|
+
}
|
|
342
426
|
const refreshedApp = refreshedApps.find((app) => app.id === appId);
|
|
343
427
|
return refreshedApp ? !workspaceAppIsDisabled(refreshedApp) : false;
|
|
344
428
|
}
|
|
345
429
|
catch (error) {
|
|
346
430
|
console.error("[workspace-app-access] registry access check failed", error);
|
|
347
|
-
return
|
|
431
|
+
return registryFetchFailure(error, auth);
|
|
348
432
|
}
|
|
349
433
|
}
|
|
350
434
|
async function localOrganizationAppEnabled(appId, orgId) {
|
|
@@ -528,7 +612,18 @@ async function isDispatchWorkspaceAppAccessAllowed(context, email) {
|
|
|
528
612
|
return false;
|
|
529
613
|
}
|
|
530
614
|
}
|
|
615
|
+
/**
|
|
616
|
+
* Keeps the contract this function has always had: `true`, `false`, or the
|
|
617
|
+
* `"unavailable"` sentinel. Use `checkWorkspaceAppAccess` to learn why a verdict
|
|
618
|
+
* could not be reached.
|
|
619
|
+
*/
|
|
531
620
|
export async function isWorkspaceAppAccessAllowed(appId, context) {
|
|
621
|
+
const check = await checkWorkspaceAppAccess(appId, context);
|
|
622
|
+
return isWorkspaceAppAccessUnavailable(check)
|
|
623
|
+
? WORKSPACE_APP_ACCESS_UNAVAILABLE
|
|
624
|
+
: check;
|
|
625
|
+
}
|
|
626
|
+
export async function checkWorkspaceAppAccess(appId, context) {
|
|
532
627
|
const normalizedAppId = appId.trim();
|
|
533
628
|
const email = normalizedEmail(context.email);
|
|
534
629
|
if (!normalizedAppId || !email) {
|
|
@@ -543,9 +638,6 @@ export async function isWorkspaceAppAccessAllowed(appId, context) {
|
|
|
543
638
|
return false;
|
|
544
639
|
}
|
|
545
640
|
const hostedAccess = await hostedWorkspaceAppAccess(normalizedAppId, context, email);
|
|
546
|
-
if (hostedAccess === WORKSPACE_APP_ACCESS_UNAVAILABLE) {
|
|
547
|
-
return WORKSPACE_APP_ACCESS_UNAVAILABLE;
|
|
548
|
-
}
|
|
549
641
|
if (hostedAccess !== null)
|
|
550
642
|
return hostedAccess;
|
|
551
643
|
try {
|
|
@@ -75,10 +75,10 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
message?: undefined;
|
|
79
78
|
id?: undefined;
|
|
80
79
|
provider?: undefined;
|
|
81
80
|
deleted?: undefined;
|
|
81
|
+
message?: undefined;
|
|
82
82
|
providers: {
|
|
83
83
|
id: string;
|
|
84
84
|
label: string;
|
|
@@ -93,9 +93,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
93
93
|
registered?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
message?: undefined;
|
|
97
96
|
id?: undefined;
|
|
98
97
|
deleted?: undefined;
|
|
98
|
+
message?: undefined;
|
|
99
99
|
providers?: undefined;
|
|
100
100
|
count?: undefined;
|
|
101
101
|
found: boolean;
|
|
@@ -103,9 +103,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
103
103
|
registered?: undefined;
|
|
104
104
|
label?: undefined;
|
|
105
105
|
} | {
|
|
106
|
-
message?: undefined;
|
|
107
106
|
provider?: undefined;
|
|
108
107
|
deleted?: undefined;
|
|
108
|
+
message?: undefined;
|
|
109
109
|
providers?: undefined;
|
|
110
110
|
count?: undefined;
|
|
111
111
|
found: boolean;
|
|
@@ -113,8 +113,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
113
113
|
registered?: undefined;
|
|
114
114
|
label?: undefined;
|
|
115
115
|
} | {
|
|
116
|
-
message?: undefined;
|
|
117
116
|
provider?: undefined;
|
|
117
|
+
message?: undefined;
|
|
118
118
|
providers?: undefined;
|
|
119
119
|
count?: undefined;
|
|
120
120
|
found?: undefined;
|
|
@@ -316,10 +316,10 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
316
316
|
notes?: string | undefined;
|
|
317
317
|
scope?: "org" | "user" | undefined;
|
|
318
318
|
}, {
|
|
319
|
-
|
|
319
|
+
message?: undefined;
|
|
320
320
|
id?: undefined;
|
|
321
|
+
deleted?: undefined;
|
|
321
322
|
provider?: undefined;
|
|
322
|
-
message?: undefined;
|
|
323
323
|
providers: {
|
|
324
324
|
id: string;
|
|
325
325
|
label: string;
|
|
@@ -334,9 +334,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
334
334
|
registered?: undefined;
|
|
335
335
|
label?: undefined;
|
|
336
336
|
} | {
|
|
337
|
-
deleted?: undefined;
|
|
338
|
-
id?: undefined;
|
|
339
337
|
message?: undefined;
|
|
338
|
+
id?: undefined;
|
|
339
|
+
deleted?: undefined;
|
|
340
340
|
providers?: undefined;
|
|
341
341
|
count?: undefined;
|
|
342
342
|
found: boolean;
|
|
@@ -344,9 +344,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
344
344
|
registered?: undefined;
|
|
345
345
|
label?: undefined;
|
|
346
346
|
} | {
|
|
347
|
+
message?: undefined;
|
|
347
348
|
deleted?: undefined;
|
|
348
349
|
provider?: undefined;
|
|
349
|
-
message?: undefined;
|
|
350
350
|
providers?: undefined;
|
|
351
351
|
count?: undefined;
|
|
352
352
|
found: boolean;
|
|
@@ -354,8 +354,8 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
354
354
|
registered?: undefined;
|
|
355
355
|
label?: undefined;
|
|
356
356
|
} | {
|
|
357
|
-
provider?: undefined;
|
|
358
357
|
message?: undefined;
|
|
358
|
+
provider?: undefined;
|
|
359
359
|
providers?: undefined;
|
|
360
360
|
count?: undefined;
|
|
361
361
|
found?: undefined;
|
|
@@ -9,8 +9,8 @@ import { isTransientDatabaseError } from "../db/client.js";
|
|
|
9
9
|
import { declaresFeatureFlagDelegation } from "../feature-flags/a2a-action-route.js";
|
|
10
10
|
import { isFeatureFlagAdminEmail } from "../feature-flags/permissions.js";
|
|
11
11
|
import { isFederationMembershipValidatedForEvent, resolveOrgIdForEmail, } from "../org/context.js";
|
|
12
|
+
import { isWorkspaceAppAccessUnavailable, workspaceAppAccessUnavailableBody, } from "../org/workspace-app-access-outcome.js";
|
|
12
13
|
import { checkWorkspaceAppAccessForRequest } from "../org/workspace-app-access-request.js";
|
|
13
|
-
import { WORKSPACE_APP_ACCESS_UNAVAILABLE, WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE, } from "../org/workspace-app-access.js";
|
|
14
14
|
import { ACTION_BROWSER_PERSIST_ALLOW, ACTION_BROWSER_PERSIST_HEADER, } from "../shared/action-browser-persist.js";
|
|
15
15
|
import { ACTION_CHANGE_MARKER_FAILED, ACTION_CHANGE_MARKER_HEADER, } from "../shared/action-change-marker-header.js";
|
|
16
16
|
import { LLM_PROVIDER_MISSING_ERROR_CODE, LLM_PROVIDER_MISSING_STATUS, } from "../shared/action-error-codes.js";
|
|
@@ -345,13 +345,16 @@ async function denyWithoutWorkspaceAppAccess(event, name, ownerContext, resolved
|
|
|
345
345
|
email: ownerContext.owner,
|
|
346
346
|
orgId: workspaceOrgId,
|
|
347
347
|
});
|
|
348
|
-
if (workspaceAppAccess
|
|
349
|
-
return {
|
|
348
|
+
if (isWorkspaceAppAccessUnavailable(workspaceAppAccess)) {
|
|
349
|
+
return {
|
|
350
|
+
status: 503,
|
|
351
|
+
body: workspaceAppAccessUnavailableBody(workspaceAppAccess),
|
|
352
|
+
};
|
|
350
353
|
}
|
|
351
354
|
if (workspaceAppAccess === false) {
|
|
352
355
|
return {
|
|
353
356
|
status: 403,
|
|
354
|
-
error: "You do not have access to this workspace app.",
|
|
357
|
+
body: { error: "You do not have access to this workspace app." },
|
|
355
358
|
};
|
|
356
359
|
}
|
|
357
360
|
return null;
|
|
@@ -587,7 +590,7 @@ function mountActionRoutesInternal(nitroApp, actions, options) {
|
|
|
587
590
|
const denied = await denyWithoutWorkspaceAppAccess(event, name, ownerContext, null, options?.resolveOrgId);
|
|
588
591
|
if (denied) {
|
|
589
592
|
setResponseStatus(event, denied.status);
|
|
590
|
-
return
|
|
593
|
+
return denied.body;
|
|
591
594
|
}
|
|
592
595
|
}
|
|
593
596
|
catch (error) {
|
|
@@ -601,7 +604,7 @@ function mountActionRoutesInternal(nitroApp, actions, options) {
|
|
|
601
604
|
const denied = await denyWithoutWorkspaceAppAccess(event, name, resolvedCaller, resolvedCaller, options?.resolveOrgId);
|
|
602
605
|
if (denied) {
|
|
603
606
|
setResponseStatus(event, denied.status);
|
|
604
|
-
return
|
|
607
|
+
return denied.body;
|
|
605
608
|
}
|
|
606
609
|
}
|
|
607
610
|
}
|
|
@@ -640,7 +643,7 @@ function mountActionRoutesInternal(nitroApp, actions, options) {
|
|
|
640
643
|
const denied = await denyWithoutWorkspaceAppAccess(event, name, ownerContext, resolvedCaller, options?.resolveOrgId);
|
|
641
644
|
if (denied) {
|
|
642
645
|
setResponseStatus(event, denied.status);
|
|
643
|
-
return
|
|
646
|
+
return denied.body;
|
|
644
647
|
}
|
|
645
648
|
}
|
|
646
649
|
if (!resolvedCaller &&
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import nodePath from "node:path";
|
|
3
|
-
import { AgentProtocolValidationError, parseQueueMessageInput, } from "@agent-native/agentkit/protocol";
|
|
3
|
+
import { AgentProtocolValidationError, AGENT_NATIVE_SUBMISSION_DEADLINES_CAPABILITY_ID, parseQueueMessageInput, } from "@agent-native/agentkit/protocol";
|
|
4
4
|
import { createError, defineEventHandler, setResponseStatus, setResponseHeader, getMethod, getQuery, getHeader, getRequestIP, readBody as readH3Body, } from "h3";
|
|
5
5
|
import { applyA2AAgentActivityEvent, buildA2AAgentActivityPart, createA2AAgentActivityState, } from "../a2a/activity.js";
|
|
6
6
|
import { appendA2AArtifactLinks, buildA2ARecoverableArtifactMessage, } from "../a2a/artifact-response.js";
|
|
@@ -2968,6 +2968,11 @@ export function createAgentChatPlugin(options) {
|
|
|
2968
2968
|
turnId: details.turnId,
|
|
2969
2969
|
agentKitMessageId: details.agentKitMessageId,
|
|
2970
2970
|
queuedMessageId: details.queuedMessageId,
|
|
2971
|
+
...(Object.prototype.hasOwnProperty.call(details, "submissionExpiresAt")
|
|
2972
|
+
? {
|
|
2973
|
+
submissionExpiresAt: details.submissionExpiresAt,
|
|
2974
|
+
}
|
|
2975
|
+
: {}),
|
|
2971
2976
|
...(details.failure
|
|
2972
2977
|
? { refusedRetry: details.retryContext ?? {} }
|
|
2973
2978
|
: {}),
|
|
@@ -3009,7 +3014,7 @@ export function createAgentChatPlugin(options) {
|
|
|
3009
3014
|
submissionFailure = result.status;
|
|
3010
3015
|
return threadData;
|
|
3011
3016
|
}
|
|
3012
|
-
const submitted = details.failure
|
|
3017
|
+
const submitted = details.failure && result.status !== "already_submitted"
|
|
3013
3018
|
? foldUnstartedTurnFailure(result.repo, {
|
|
3014
3019
|
runId: details.runId,
|
|
3015
3020
|
threadId,
|
|
@@ -3038,6 +3043,13 @@ export function createAgentChatPlugin(options) {
|
|
|
3038
3043
|
data: { code: "run_slot_busy", retryable: true },
|
|
3039
3044
|
});
|
|
3040
3045
|
}
|
|
3046
|
+
if (submissionFailure === "submission_expired") {
|
|
3047
|
+
throw createError({
|
|
3048
|
+
statusCode: 409,
|
|
3049
|
+
statusMessage: "Prompt submission expired before it could start",
|
|
3050
|
+
data: { code: "submission_expired", retryable: false },
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
3041
3053
|
if (submissionFailure === "invalid_thread_data") {
|
|
3042
3054
|
throw new TypeError("Agent chat thread data is not valid JSON.");
|
|
3043
3055
|
}
|
|
@@ -6305,6 +6317,20 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
6305
6317
|
// This is mounted last because h3's use() is prefix-based, meaning /_agent-native/agent-chat
|
|
6306
6318
|
// also matches /_agent-native/agent-chat/threads/... — we skip sub-path requests here so the
|
|
6307
6319
|
// earlier-mounted handlers (mode, save-key, files, skills, mentions, threads) handle them.
|
|
6320
|
+
const capabilitiesPath = `${routePath}/capabilities`;
|
|
6321
|
+
getH3App(nitroApp).use(capabilitiesPath, defineEventHandler((event) => {
|
|
6322
|
+
const requestPath = new URL(event.node?.req?.url || event.path || "", "http://localhost").pathname;
|
|
6323
|
+
if (requestPath !== capabilitiesPath) {
|
|
6324
|
+
setResponseStatus(event, 404);
|
|
6325
|
+
return { error: "Not found" };
|
|
6326
|
+
}
|
|
6327
|
+
if (getMethod(event) !== "GET") {
|
|
6328
|
+
setResponseStatus(event, 405);
|
|
6329
|
+
return { error: "Method not allowed" };
|
|
6330
|
+
}
|
|
6331
|
+
setResponseHeader(event, "Cache-Control", "no-store");
|
|
6332
|
+
return { [AGENT_NATIVE_SUBMISSION_DEADLINES_CAPABILITY_ID]: true };
|
|
6333
|
+
}));
|
|
6308
6334
|
getH3App(nitroApp).use(routePath, withTransientDatabaseFallback(routePath, async (event) => {
|
|
6309
6335
|
// Skip sub-path requests — they're handled by earlier-mounted handlers
|
|
6310
6336
|
const url = event.node?.req?.url || event.path || "";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
2
2
|
error: string;
|
|
3
|
-
ok?: undefined;
|
|
4
3
|
models?: undefined;
|
|
4
|
+
ok?: undefined;
|
|
5
5
|
} | {
|
|
6
|
-
error?: undefined;
|
|
7
6
|
ok: boolean;
|
|
8
7
|
models: string[];
|
|
8
|
+
error?: undefined;
|
|
9
9
|
}>>;
|
package/dist/server/auth.js
CHANGED
|
@@ -3,8 +3,8 @@ import { defineEventHandler, getMethod, getQuery, setResponseHeader, setResponse
|
|
|
3
3
|
import { getAppConfig, resolveAppHomePath } from "../app-config/index.js";
|
|
4
4
|
import { acceptPendingInvitationsForEmail } from "../org/accept-pending.js";
|
|
5
5
|
import { newOrgSelection, ORG_SELECTION_COOKIE, } from "../org/request-org-cache.js";
|
|
6
|
+
import { isWorkspaceAppAccessUnavailable, workspaceAppAccessUnavailableBody, } from "../org/workspace-app-access-outcome.js";
|
|
6
7
|
import { checkWorkspaceAppAccessForRequest } from "../org/workspace-app-access-request.js";
|
|
7
|
-
import { WORKSPACE_APP_ACCESS_UNAVAILABLE, WORKSPACE_APP_ACCESS_UNAVAILABLE_MESSAGE, } from "../org/workspace-app-access.js";
|
|
8
8
|
import { EMBED_SESSION_COOKIE, EMBED_START_PATH, EMBED_TARGET_HEADER, isMcpDirectoryWidgetCapabilityScope, } from "../shared/embed-auth.js";
|
|
9
9
|
import { FIRST_RUN_ONBOARDING_COOKIE, FIRST_RUN_ONBOARDING_MAX_AGE, } from "../shared/first-run-onboarding.js";
|
|
10
10
|
import { isGoogleProfileImageUrl } from "../shared/google-profile-image.js";
|
|
@@ -3114,9 +3114,9 @@ function createAuthGuardFn(app) {
|
|
|
3114
3114
|
email: session.email,
|
|
3115
3115
|
orgId: session.orgId,
|
|
3116
3116
|
});
|
|
3117
|
-
if (workspaceAppAccess
|
|
3117
|
+
if (isWorkspaceAppAccessUnavailable(workspaceAppAccess)) {
|
|
3118
3118
|
setResponseStatus(event, 503);
|
|
3119
|
-
return
|
|
3119
|
+
return workspaceAppAccessUnavailableBody(workspaceAppAccess);
|
|
3120
3120
|
}
|
|
3121
3121
|
if (workspaceAppAccess === false) {
|
|
3122
3122
|
setResponseStatus(event, 403);
|
|
@@ -54,8 +54,8 @@ export declare function createRealtimeTokenHandler(): import("h3").EventHandlerW
|
|
|
54
54
|
expiresAt?: undefined;
|
|
55
55
|
ttlSeconds?: undefined;
|
|
56
56
|
} | {
|
|
57
|
-
error?: undefined;
|
|
58
57
|
token: string;
|
|
59
58
|
expiresAt: string;
|
|
60
59
|
ttlSeconds: number;
|
|
60
|
+
error?: undefined;
|
|
61
61
|
}>>;
|
|
@@ -14,6 +14,7 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
14
14
|
executionCwd?: string;
|
|
15
15
|
}, {
|
|
16
16
|
deleted?: undefined;
|
|
17
|
+
enabled?: undefined;
|
|
17
18
|
created: boolean;
|
|
18
19
|
name: string;
|
|
19
20
|
scope: "organization" | "personal";
|
|
@@ -24,25 +25,24 @@ declare const _default: import("../../action.js").ActionDefinition<{
|
|
|
24
25
|
reasoningEffort: "auto" | "high" | "low" | "max" | "medium" | "minimal" | "none" | "xhigh";
|
|
25
26
|
webhookPath: string;
|
|
26
27
|
nextRun: string;
|
|
27
|
-
enabled?: undefined;
|
|
28
28
|
executionHostId?: undefined;
|
|
29
29
|
executionEngine?: undefined;
|
|
30
30
|
executionCwd?: undefined;
|
|
31
31
|
} | {
|
|
32
|
+
enabled?: undefined;
|
|
33
|
+
nextRun?: undefined;
|
|
32
34
|
created?: undefined;
|
|
33
35
|
scope?: undefined;
|
|
34
36
|
triggerType?: undefined;
|
|
35
37
|
event?: undefined;
|
|
36
38
|
deleted: boolean;
|
|
37
39
|
name: string;
|
|
38
|
-
enabled?: undefined;
|
|
39
40
|
schedule?: undefined;
|
|
40
41
|
timezone?: undefined;
|
|
41
42
|
reasoningEffort?: undefined;
|
|
42
43
|
executionHostId?: undefined;
|
|
43
44
|
executionEngine?: undefined;
|
|
44
45
|
executionCwd?: undefined;
|
|
45
|
-
nextRun?: undefined;
|
|
46
46
|
webhookPath?: undefined;
|
|
47
47
|
} | {
|
|
48
48
|
deleted?: undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.209.1
|
|
3
|
+
"version": "0.209.1",
|
|
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": {
|
|
@@ -704,8 +704,8 @@
|
|
|
704
704
|
"yaml": "^2.9.0",
|
|
705
705
|
"yjs": "^13.6.33",
|
|
706
706
|
"zod": "^4.3.6",
|
|
707
|
-
"@agent-native/agentkit": "^0.209.1
|
|
708
|
-
"@agent-native/recap-cli": "^0.5.
|
|
707
|
+
"@agent-native/agentkit": "^0.209.1",
|
|
708
|
+
"@agent-native/recap-cli": "^0.5.73"
|
|
709
709
|
},
|
|
710
710
|
"devDependencies": {
|
|
711
711
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -775,7 +775,7 @@
|
|
|
775
775
|
"xlsx": "^0.18.5"
|
|
776
776
|
},
|
|
777
777
|
"peerDependencies": {
|
|
778
|
-
"@agent-native/core-corpus": "0.
|
|
778
|
+
"@agent-native/core-corpus": ">=0.196.0",
|
|
779
779
|
"@ai-sdk/anthropic": ">=3",
|
|
780
780
|
"@ai-sdk/cohere": ">=3",
|
|
781
781
|
"@ai-sdk/google": ">=3",
|