@agent-native/core 0.207.0-nightly-20261011124220 → 0.207.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.js +23 -6
- package/dist/agent/thread-data-builder.js +7 -4
- package/dist/cli/eval.js +20 -4
- package/dist/client/analytics/index.d.ts +1 -1
- package/dist/client/analytics.d.ts +12 -3
- package/dist/client/analytics.js +51 -17
- package/dist/client/onboarding/use-onboarding.d.ts +1 -0
- package/dist/client/onboarding/use-onboarding.js +19 -6
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/eval/agent-runner.js +18 -8
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/connect-route.js +9 -4
- package/dist/observability/routes.d.ts +7 -7
- package/dist/onboarding/plugin.js +15 -45
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/store.js +25 -30
- package/dist/server/agent-discovery.js +47 -53
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
- package/dist/server/builtin-agents.d.ts +2 -0
- package/dist/server/builtin-agents.js +50 -3
- package/dist/server/credential-provider.d.ts +6 -9
- package/dist/server/credential-provider.js +33 -21
- package/dist/templates/builder-code-starter/.agents/skills/adding-a-feature/SKILL.md.patch +1 -1
- package/dist/templates/builder-code-starter/AGENTS.md.patch +3 -3
- package/dist/templates/builder-code-starter/app/components/layout/Layout.tsx.patch +6 -7
- package/dist/templates/builder-code-starter/app/hooks/use-navigation-state.ts.patch +21 -28
- package/dist/templates/builder-code-starter/app/root.tsx.patch +16 -5
- package/dist/templates/builder-code-starter/template-layer.json +4 -0
- package/dist/templates/chat/.agents/skills/secrets/SKILL.md +6 -2
- package/dist/templates/chat/AGENTS.md +3 -3
- package/dist/templates/chat/CHANGELOG.md +6 -0
- package/dist/templates/chat/app/components/chat/ChatHomeRedirect.tsx +25 -0
- package/dist/templates/chat/app/components/chat/ChatRouteContent.tsx +828 -15
- package/dist/templates/chat/app/components/home/HomePage.tsx +332 -0
- package/dist/templates/chat/app/components/layout/AgentInspector.tsx +2 -4
- package/dist/templates/chat/app/components/layout/Header.tsx +1 -1
- package/dist/templates/chat/app/components/layout/Layout.tsx +5 -6
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +35 -11
- package/dist/templates/chat/app/components/ui/item.tsx +1 -0
- package/dist/templates/chat/app/components/ui/separator.tsx +1 -0
- package/dist/templates/chat/app/components/ui/skeleton.tsx +1 -0
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +16 -22
- package/dist/templates/chat/app/i18n/ar-SA.ts +25 -0
- package/dist/templates/chat/app/i18n/de-DE.ts +26 -0
- package/dist/templates/chat/app/i18n/en-US.ts +25 -0
- package/dist/templates/chat/app/i18n/es-ES.ts +26 -0
- package/dist/templates/chat/app/i18n/fr-FR.ts +26 -0
- package/dist/templates/chat/app/i18n/hi-IN.ts +26 -0
- package/dist/templates/chat/app/i18n/ja-JP.ts +26 -0
- package/dist/templates/chat/app/i18n/ko-KR.ts +26 -0
- package/dist/templates/chat/app/i18n/pt-BR.ts +26 -0
- package/dist/templates/chat/app/i18n/zh-CN.ts +25 -0
- package/dist/templates/chat/app/i18n/zh-TW.ts +25 -0
- package/dist/templates/chat/app/lib/chat-paths.ts +479 -0
- package/dist/templates/chat/app/root.tsx +14 -3
- package/dist/templates/chat/app/routes/chat._index.tsx +5 -0
- package/dist/templates/chat/app/routes/home.tsx +3 -22
- package/dist/templates/chat/changelog/2026-10-10-home-handoff-recovery-capacity.md +6 -0
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +6 -2
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +6 -2
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +6 -2
- package/dist/triggers/actions/manage-automation.d.ts +2 -2
- package/docs/content/deployment-environment-variables.mdx +10 -10
- package/docs/content/environment-variables.mdx +38 -6
- package/docs/content/getting-started.mdx +7 -7
- package/docs/content/multi-app-workspace.mdx +7 -3
- package/docs/content/template-chat-first-edits.mdx +46 -33
- package/package.json +4 -4
- package/src/templates/builder-code-starter/.agents/skills/adding-a-feature/SKILL.md.patch +1 -1
- package/src/templates/builder-code-starter/AGENTS.md.patch +3 -3
- package/src/templates/builder-code-starter/app/components/layout/Layout.tsx.patch +6 -7
- package/src/templates/builder-code-starter/app/hooks/use-navigation-state.ts.patch +21 -28
- package/src/templates/builder-code-starter/app/root.tsx.patch +16 -5
- package/src/templates/builder-code-starter/template-layer.json +4 -0
- package/src/templates/chat/.agents/skills/secrets/SKILL.md +6 -2
- package/src/templates/chat/AGENTS.md +3 -3
- package/src/templates/chat/CHANGELOG.md +6 -0
- package/src/templates/chat/app/components/chat/ChatHomeRedirect.tsx +25 -0
- package/src/templates/chat/app/components/chat/ChatRouteContent.tsx +828 -15
- package/src/templates/chat/app/components/home/HomePage.tsx +332 -0
- package/src/templates/chat/app/components/layout/AgentInspector.tsx +2 -4
- package/src/templates/chat/app/components/layout/Header.tsx +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +5 -6
- package/src/templates/chat/app/components/layout/Sidebar.tsx +35 -11
- package/src/templates/chat/app/components/ui/item.tsx +1 -0
- package/src/templates/chat/app/components/ui/separator.tsx +1 -0
- package/src/templates/chat/app/components/ui/skeleton.tsx +1 -0
- package/src/templates/chat/app/hooks/use-navigation-state.ts +16 -22
- package/src/templates/chat/app/i18n/ar-SA.ts +25 -0
- package/src/templates/chat/app/i18n/de-DE.ts +26 -0
- package/src/templates/chat/app/i18n/en-US.ts +25 -0
- package/src/templates/chat/app/i18n/es-ES.ts +26 -0
- package/src/templates/chat/app/i18n/fr-FR.ts +26 -0
- package/src/templates/chat/app/i18n/hi-IN.ts +26 -0
- package/src/templates/chat/app/i18n/ja-JP.ts +26 -0
- package/src/templates/chat/app/i18n/ko-KR.ts +26 -0
- package/src/templates/chat/app/i18n/pt-BR.ts +26 -0
- package/src/templates/chat/app/i18n/zh-CN.ts +25 -0
- package/src/templates/chat/app/i18n/zh-TW.ts +25 -0
- package/src/templates/chat/app/lib/chat-paths.ts +479 -0
- package/src/templates/chat/app/root.tsx +14 -3
- package/src/templates/chat/app/routes/chat._index.tsx +5 -0
- package/src/templates/chat/app/routes/home.tsx +3 -22
- package/src/templates/chat/changelog/2026-10-10-home-handoff-recovery-capacity.md +6 -0
- package/src/templates/default/.agents/skills/secrets/SKILL.md +6 -2
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +6 -2
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +6 -2
package/dist/resources/store.js
CHANGED
|
@@ -982,36 +982,31 @@ async function _doEnsureTable() {
|
|
|
982
982
|
now,
|
|
983
983
|
],
|
|
984
984
|
});
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
});
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
catch {
|
|
1014
|
-
// Agent discovery not available — skip seeding
|
|
985
|
+
const { getBuiltinAgentsForSeeding } = await import("../server/agent-discovery.js");
|
|
986
|
+
const builtins = getBuiltinAgentsForSeeding();
|
|
987
|
+
for (const agent of builtins) {
|
|
988
|
+
const agentJson = JSON.stringify({
|
|
989
|
+
id: agent.id,
|
|
990
|
+
name: agent.name,
|
|
991
|
+
description: agent.description,
|
|
992
|
+
url: agent.url, // always prod
|
|
993
|
+
color: agent.color,
|
|
994
|
+
}, null, 2);
|
|
995
|
+
assertResourcePayloadIsSqlSafe(agentJson, "application/json");
|
|
996
|
+
const agentSize = Buffer.byteLength(agentJson, "utf8");
|
|
997
|
+
await client.execute({
|
|
998
|
+
sql: seedSql,
|
|
999
|
+
args: [
|
|
1000
|
+
crypto.randomUUID(),
|
|
1001
|
+
`remote-agents/${agent.id}.json`,
|
|
1002
|
+
SHARED_OWNER,
|
|
1003
|
+
agentJson,
|
|
1004
|
+
"application/json",
|
|
1005
|
+
agentSize,
|
|
1006
|
+
now,
|
|
1007
|
+
now,
|
|
1008
|
+
],
|
|
1009
|
+
});
|
|
1015
1010
|
}
|
|
1016
1011
|
try {
|
|
1017
1012
|
const legacy = await client.execute({
|
|
@@ -6,7 +6,7 @@ import { HIDDEN_FIRST_PARTY_AGENT_IDS, isBuiltinAgentCatalogId, normalizeAgentId
|
|
|
6
6
|
import { DEFAULT_WORKSPACE_APP_AUDIENCE, normalizeWorkspaceAppAudience, normalizeWorkspaceAppHomePath, normalizeWorkspaceAppPathList, workspaceAppAudienceFromPackageJson, workspaceAppRouteAccessFromPackageJson, } from "../shared/workspace-app-audience.js";
|
|
7
7
|
import { inferWorkspaceAppRootHomePath, readConfiguredWorkspaceAppHomePath, } from "../workspace-app-config.js";
|
|
8
8
|
import { resolveAppRuntimeUrl } from "./app-url.js";
|
|
9
|
-
import { readBuiltinAgentsConfig } from "./builtin-agents.js";
|
|
9
|
+
import { readBuiltinAgentsConfig, } from "./builtin-agents.js";
|
|
10
10
|
import { getRequestContext, getRequestOrgId, getRequestUserEmail, } from "./request-context.js";
|
|
11
11
|
import { findWorkspaceRoot, readJson } from "./workspace-root.js";
|
|
12
12
|
export { isBuiltinAgentCatalogId, normalizeAgentId };
|
|
@@ -199,23 +199,57 @@ export function shouldIncludeRemoteAgentManifest(manifest, selfAppId) {
|
|
|
199
199
|
}
|
|
200
200
|
return !HIDDEN_FIRST_PARTY_AGENT_IDS.has(normalizedId);
|
|
201
201
|
}
|
|
202
|
-
function builtinAgentsFor(
|
|
202
|
+
function builtinAgentsFor(config, selfAppId, options) {
|
|
203
203
|
const normalizedSelfAppId = selfAppId ? normalizeAgentId(selfAppId) : "";
|
|
204
|
-
|
|
204
|
+
const useLocalUrls = options?.preferLocalUrls === true || shouldUseLocalAgentUrls();
|
|
205
|
+
return BUILTIN_AGENT_CATALOG.filter((app) => config.include.includes(app.id) &&
|
|
206
|
+
app.id !== normalizedSelfAppId &&
|
|
207
|
+
app.url).map((app) => ({
|
|
205
208
|
id: app.id,
|
|
206
209
|
name: app.name,
|
|
207
210
|
description: app.description,
|
|
208
|
-
url:
|
|
211
|
+
url: !useLocalUrls && config.urls?.[app.id]
|
|
212
|
+
? config.urls[app.id]
|
|
213
|
+
: resolveAgentUrl(app, options?.preferLocalUrls),
|
|
209
214
|
color: app.color,
|
|
210
215
|
}));
|
|
211
216
|
}
|
|
212
217
|
/** Built-ins the workspace builder offers (`agent-native.builtinAgents`). */
|
|
213
218
|
export function getBuiltinAgents(selfAppId, options) {
|
|
214
|
-
return builtinAgentsFor(readBuiltinAgentsConfig()
|
|
219
|
+
return builtinAgentsFor(readBuiltinAgentsConfig(), selfAppId, options);
|
|
215
220
|
}
|
|
216
221
|
function isUnofferedBuiltinManifest(manifestId, offeredBuiltinIds) {
|
|
217
222
|
return (isBuiltinAgentCatalogId(manifestId) && !offeredBuiltinIds.has(manifestId));
|
|
218
223
|
}
|
|
224
|
+
function resolveRemoteAgentManifestUrl(manifestId, rawManifestId, manifestUrl, builtin, options) {
|
|
225
|
+
const catalogBuiltin = BUILTIN_AGENT_CATALOG.find((candidate) => candidate.id === manifestId);
|
|
226
|
+
const hosted = isHostedRuntime();
|
|
227
|
+
let url = manifestUrl;
|
|
228
|
+
if (hosted && isLoopbackUrl(url)) {
|
|
229
|
+
if (builtin?.url)
|
|
230
|
+
url = builtin.url;
|
|
231
|
+
else
|
|
232
|
+
return undefined;
|
|
233
|
+
}
|
|
234
|
+
if (catalogBuiltin && builtin && manifestUrl === catalogBuiltin.url) {
|
|
235
|
+
url = builtin.url;
|
|
236
|
+
}
|
|
237
|
+
if (options?.preferLocalUrls && builtin && catalogBuiltin) {
|
|
238
|
+
url = builtin.url;
|
|
239
|
+
}
|
|
240
|
+
const isLegacyAssetsManifest = rawManifestId.trim().toLowerCase() !== manifestId;
|
|
241
|
+
if (isLegacyAssetsManifest && builtin?.url) {
|
|
242
|
+
try {
|
|
243
|
+
if (new URL(url).hostname === "images.agent-native.com") {
|
|
244
|
+
url = builtin.url;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
catch {
|
|
248
|
+
url = builtin.url;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
return { url, isLegacyAssetsManifest };
|
|
252
|
+
}
|
|
219
253
|
export async function discoverAgents(selfAppId, options) {
|
|
220
254
|
const builtins = getBuiltinAgents(selfAppId, options);
|
|
221
255
|
const offeredBuiltinIds = new Set(builtins.map((agent) => agent.id));
|
|
@@ -281,32 +315,11 @@ export async function discoverAgents(selfAppId, options) {
|
|
|
281
315
|
const manifestId = normalizeAgentId(manifest.id);
|
|
282
316
|
if (isUnofferedBuiltinManifest(manifestId, offeredBuiltinIds))
|
|
283
317
|
continue;
|
|
284
|
-
let url = manifest.url;
|
|
285
|
-
const isHosted = isHostedRuntime();
|
|
286
|
-
if (isHosted && typeof url === "string" && isLoopbackUrl(url)) {
|
|
287
|
-
const builtin = agentsById.get(manifestId);
|
|
288
|
-
if (builtin?.url)
|
|
289
|
-
url = builtin.url;
|
|
290
|
-
else
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
318
|
const builtin = agentsById.get(manifestId);
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
const isLegacyAssetsManifest = manifest.id.trim().toLowerCase() !== manifestId;
|
|
300
|
-
if (isLegacyAssetsManifest && builtin?.url) {
|
|
301
|
-
try {
|
|
302
|
-
if (new URL(url).hostname === "images.agent-native.com") {
|
|
303
|
-
url = builtin.url;
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
catch {
|
|
307
|
-
url = builtin.url;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
319
|
+
const resolved = resolveRemoteAgentManifestUrl(manifestId, manifest.id, manifest.url, builtin, options);
|
|
320
|
+
if (!resolved)
|
|
321
|
+
continue;
|
|
322
|
+
const { url, isLegacyAssetsManifest } = resolved;
|
|
310
323
|
agentsById.set(manifestId, {
|
|
311
324
|
id: manifestId,
|
|
312
325
|
name: isLegacyAssetsManifest && builtin?.name
|
|
@@ -414,30 +427,11 @@ async function overlayRemoteAgentResources(agentsById, offeredBuiltinIds, resour
|
|
|
414
427
|
const manifestId = normalizeAgentId(manifest.id);
|
|
415
428
|
if (isUnofferedBuiltinManifest(manifestId, offeredBuiltinIds))
|
|
416
429
|
continue;
|
|
417
|
-
let url = manifest.url;
|
|
418
430
|
const builtin = agentsById.get(manifestId);
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
continue;
|
|
424
|
-
}
|
|
425
|
-
if (options?.preferLocalUrls &&
|
|
426
|
-
builtin &&
|
|
427
|
-
BUILTIN_AGENT_CATALOG.some((candidate) => candidate.id === manifestId)) {
|
|
428
|
-
url = builtin.url;
|
|
429
|
-
}
|
|
430
|
-
const isLegacyAssetsManifest = manifest.id.trim().toLowerCase() !== manifestId;
|
|
431
|
-
if (isLegacyAssetsManifest && builtin?.url) {
|
|
432
|
-
try {
|
|
433
|
-
if (new URL(url).hostname === "images.agent-native.com") {
|
|
434
|
-
url = builtin.url;
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
catch {
|
|
438
|
-
url = builtin.url;
|
|
439
|
-
}
|
|
440
|
-
}
|
|
431
|
+
const resolved = resolveRemoteAgentManifestUrl(manifestId, manifest.id, manifest.url, builtin, options);
|
|
432
|
+
if (!resolved)
|
|
433
|
+
continue;
|
|
434
|
+
const { url, isLegacyAssetsManifest } = resolved;
|
|
441
435
|
agentsById.set(manifestId, {
|
|
442
436
|
id: manifestId,
|
|
443
437
|
name: isLegacyAssetsManifest && builtin?.name ? builtin.name : manifest.name,
|
|
@@ -66,6 +66,7 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
|
|
|
66
66
|
error: any;
|
|
67
67
|
code: any;
|
|
68
68
|
} | {
|
|
69
|
+
error?: undefined;
|
|
69
70
|
errorCode?: undefined;
|
|
70
71
|
code?: undefined;
|
|
71
72
|
ok: boolean;
|
|
@@ -73,6 +74,5 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
|
|
|
73
74
|
baseUrlKey?: string;
|
|
74
75
|
scope: AgentEngineApiKeyScope;
|
|
75
76
|
defaultModel?: import("./agent-engine-default-model-route.js").SavedKeyDefaultModelOutcome;
|
|
76
|
-
error?: undefined;
|
|
77
77
|
}>>;
|
|
78
78
|
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
2
2
|
error: string;
|
|
3
|
-
models?: undefined;
|
|
4
3
|
ok?: undefined;
|
|
4
|
+
models?: undefined;
|
|
5
5
|
} | {
|
|
6
|
+
error?: undefined;
|
|
6
7
|
ok: boolean;
|
|
7
8
|
models: string[];
|
|
8
|
-
error?: undefined;
|
|
9
9
|
}>>;
|
|
@@ -3,6 +3,8 @@ export interface BuiltinAgentsConfig {
|
|
|
3
3
|
mode: BuiltinAgentsMode;
|
|
4
4
|
/** Built-ins this workspace offers. Anything else is unknown to it. */
|
|
5
5
|
include: string[];
|
|
6
|
+
/** Hosted URL overrides, applied only when a built-in is offered. */
|
|
7
|
+
urls?: Record<string, string>;
|
|
6
8
|
}
|
|
7
9
|
export declare const BUILTIN_AGENTS_ENV_KEY = "AGENT_NATIVE_BUILTIN_AGENTS_JSON";
|
|
8
10
|
export declare function frameworkDefaultBuiltinAgentsConfig(): BuiltinAgentsConfig;
|
|
@@ -32,6 +32,48 @@ function parseIdList(value, field, warnings) {
|
|
|
32
32
|
}
|
|
33
33
|
return ids;
|
|
34
34
|
}
|
|
35
|
+
function parseBuiltinAgentUrls(value) {
|
|
36
|
+
if (value === undefined)
|
|
37
|
+
return undefined;
|
|
38
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
39
|
+
throw new Error("builtinAgents.urls must be an object mapping built-in ids to URLs");
|
|
40
|
+
}
|
|
41
|
+
const urls = {};
|
|
42
|
+
const seenIds = new Set();
|
|
43
|
+
for (const [rawId, rawUrl] of Object.entries(value)) {
|
|
44
|
+
const id = normalizeAgentId(rawId);
|
|
45
|
+
if (!BUILTIN_AGENT_CATALOG_IDS.includes(id)) {
|
|
46
|
+
throw new Error("builtinAgents.urls contains an unknown built-in agent id");
|
|
47
|
+
}
|
|
48
|
+
if (seenIds.has(id)) {
|
|
49
|
+
throw new Error("builtinAgents.urls contains duplicate built-in agent ids");
|
|
50
|
+
}
|
|
51
|
+
seenIds.add(id);
|
|
52
|
+
if (typeof rawUrl !== "string" || rawUrl.trim() !== rawUrl) {
|
|
53
|
+
throw new Error("builtinAgents.urls values must be absolute HTTPS URLs without credentials, query, or fragment");
|
|
54
|
+
}
|
|
55
|
+
let url;
|
|
56
|
+
try {
|
|
57
|
+
url = new URL(rawUrl);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
throw new Error("builtinAgents.urls values must be absolute HTTPS URLs without credentials, query, or fragment");
|
|
61
|
+
}
|
|
62
|
+
if (/[\s\p{Cc}]/u.test(rawUrl) ||
|
|
63
|
+
!/^https:\/\//i.test(rawUrl) ||
|
|
64
|
+
url.protocol !== "https:" ||
|
|
65
|
+
!url.hostname ||
|
|
66
|
+
url.username ||
|
|
67
|
+
url.password ||
|
|
68
|
+
url.search ||
|
|
69
|
+
url.hash ||
|
|
70
|
+
/[?#]/.test(rawUrl)) {
|
|
71
|
+
throw new Error("builtinAgents.urls values must be absolute HTTPS URLs without credentials, query, or fragment");
|
|
72
|
+
}
|
|
73
|
+
urls[id] = rawUrl;
|
|
74
|
+
}
|
|
75
|
+
return urls;
|
|
76
|
+
}
|
|
35
77
|
export function parseBuiltinAgentsConfig(raw) {
|
|
36
78
|
const warnings = [];
|
|
37
79
|
if (raw === undefined || raw === null) {
|
|
@@ -42,13 +84,18 @@ export function parseBuiltinAgentsConfig(raw) {
|
|
|
42
84
|
return { config: frameworkDefaultBuiltinAgentsConfig(), warnings };
|
|
43
85
|
}
|
|
44
86
|
const record = raw;
|
|
87
|
+
const urls = parseBuiltinAgentUrls(record.urls);
|
|
88
|
+
const urlsConfig = urls === undefined ? {} : { urls };
|
|
45
89
|
const mode = record.mode ?? "all";
|
|
46
90
|
if (mode !== "all" && mode !== "none" && mode !== "selected") {
|
|
47
91
|
warnings.push(`builtinAgents.mode must be "all", "none", or "selected"; using the default`);
|
|
48
|
-
return {
|
|
92
|
+
return {
|
|
93
|
+
config: { ...frameworkDefaultBuiltinAgentsConfig(), ...urlsConfig },
|
|
94
|
+
warnings,
|
|
95
|
+
};
|
|
49
96
|
}
|
|
50
97
|
if (mode === "none") {
|
|
51
|
-
return { config: { mode, include: [] }, warnings };
|
|
98
|
+
return { config: { mode, include: [], ...urlsConfig }, warnings };
|
|
52
99
|
}
|
|
53
100
|
let include;
|
|
54
101
|
if (mode === "all") {
|
|
@@ -64,7 +111,7 @@ export function parseBuiltinAgentsConfig(raw) {
|
|
|
64
111
|
include =
|
|
65
112
|
parseIdList(record.include, "builtinAgents.include", warnings) ?? [];
|
|
66
113
|
}
|
|
67
|
-
return { config: { mode, include }, warnings };
|
|
114
|
+
return { config: { mode, include, ...urlsConfig }, warnings };
|
|
68
115
|
}
|
|
69
116
|
function readRawBuiltinAgentsConfig() {
|
|
70
117
|
const envJson = getAppConfig().workspace.builtinAgentsJson;
|
|
@@ -38,18 +38,15 @@ export declare function assertCredentialStoreReadable(result: {
|
|
|
38
38
|
cause?: unknown;
|
|
39
39
|
}): void;
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
41
|
+
* Read deployment-owned configuration. LLM provider keys have an app-wide
|
|
42
|
+
* fallback policy; user and workspace credentials must use scoped resolvers.
|
|
43
43
|
*/
|
|
44
44
|
export declare function readDeployCredentialEnv(key: string): string | undefined;
|
|
45
45
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* they bill the app owner. Other app-provided service credentials configure
|
|
51
|
-
* the deployed app itself, such as email transport and OAuth client
|
|
52
|
-
* credentials whose per-user identity remains in scoped OAuth tokens.
|
|
46
|
+
* Legacy deployment-level credential policy for non-provider call sites.
|
|
47
|
+
* Model-provider env keys use `canUseDeployCredentialFallbackForRequest()` so
|
|
48
|
+
* self-hosted apps and local PGlite development can share an app-owned
|
|
49
|
+
* inference key.
|
|
53
50
|
*
|
|
54
51
|
* @deprecated Use `canUseDeployCredentialFallbackForRequest()` for generic
|
|
55
52
|
* provider secrets. This stricter helper remains for legacy call sites with
|
|
@@ -96,23 +96,27 @@ export function assertCredentialStoreReadable(result) {
|
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
100
|
-
*
|
|
99
|
+
* Read deployment-owned configuration. LLM provider keys have an app-wide
|
|
100
|
+
* fallback policy; user and workspace credentials must use scoped resolvers.
|
|
101
101
|
*/
|
|
102
102
|
export function readDeployCredentialEnv(key) {
|
|
103
|
-
if (
|
|
103
|
+
if (key === "GOOGLE_APPLICATION_CREDENTIALS" &&
|
|
104
|
+
(getRequestContext()?.isSyntheticTraffic === true ||
|
|
105
|
+
isHostedWorkspaceRuntime() ||
|
|
106
|
+
!isDeployCredentialFallbackAllowed())) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
if ((DEPLOY_LLM_PROVIDER_ENV_KEYS.has(key) ||
|
|
110
|
+
BUILDER_CREDITS_DEPLOY_ENV_KEYS.has(key)) &&
|
|
104
111
|
!canUseDeployCredentialFallbackForRequest(key)) {
|
|
105
112
|
return undefined;
|
|
106
113
|
}
|
|
107
114
|
return process.env[key] || undefined;
|
|
108
115
|
}
|
|
109
|
-
const
|
|
116
|
+
const DEPLOY_LLM_PROVIDER_ENV_KEYS = new Set([
|
|
110
117
|
"ANTHROPIC_API_KEY",
|
|
111
|
-
"BUILDER_GATEWAY_SPACE_ID",
|
|
112
|
-
"BUILDER_GATEWAY_TOKEN",
|
|
113
118
|
"COHERE_API_KEY",
|
|
114
119
|
"GEMINI_API_KEY",
|
|
115
|
-
"GOOGLE_APPLICATION_CREDENTIALS",
|
|
116
120
|
"GOOGLE_GENERATIVE_AI_API_KEY",
|
|
117
121
|
"GROQ_API_KEY",
|
|
118
122
|
"JEV_API_KEY",
|
|
@@ -122,6 +126,10 @@ const HOSTED_MODEL_PROVIDER_ENV_KEYS = new Set([
|
|
|
122
126
|
"TYPESAFE_API_KEY",
|
|
123
127
|
"VOYAGE_API_KEY",
|
|
124
128
|
]);
|
|
129
|
+
const BUILDER_CREDITS_DEPLOY_ENV_KEYS = new Set([
|
|
130
|
+
"BUILDER_GATEWAY_SPACE_ID",
|
|
131
|
+
"BUILDER_GATEWAY_TOKEN",
|
|
132
|
+
]);
|
|
125
133
|
const APP_PROVIDED_DEPLOY_CREDENTIAL_KEYS = new Set([
|
|
126
134
|
"EMAIL_FROM",
|
|
127
135
|
"EMAIL_INBOUND_WEBHOOK_SECRET",
|
|
@@ -142,13 +150,10 @@ function isAppProvidedDeployCredentialKey(key) {
|
|
|
142
150
|
return !!key && APP_PROVIDED_DEPLOY_CREDENTIAL_KEYS.has(key);
|
|
143
151
|
}
|
|
144
152
|
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* they bill the app owner. Other app-provided service credentials configure
|
|
150
|
-
* the deployed app itself, such as email transport and OAuth client
|
|
151
|
-
* credentials whose per-user identity remains in scoped OAuth tokens.
|
|
153
|
+
* Legacy deployment-level credential policy for non-provider call sites.
|
|
154
|
+
* Model-provider env keys use `canUseDeployCredentialFallbackForRequest()` so
|
|
155
|
+
* self-hosted apps and local PGlite development can share an app-owned
|
|
156
|
+
* inference key.
|
|
152
157
|
*
|
|
153
158
|
* @deprecated Use `canUseDeployCredentialFallbackForRequest()` for generic
|
|
154
159
|
* provider secrets. This stricter helper remains for legacy call sites with
|
|
@@ -160,16 +165,23 @@ export function isDeployCredentialFallbackAllowed() {
|
|
|
160
165
|
return isLocalDatabase();
|
|
161
166
|
}
|
|
162
167
|
export function canUseDeployCredentialFallbackForRequest(key) {
|
|
168
|
+
const requestContext = getRequestContext();
|
|
163
169
|
// Synthetic checks must never fall through to a deploy-wide provider key.
|
|
164
|
-
//
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
// Anonymous public runs must not consume the deployment owner's key either.
|
|
171
|
+
if (requestContext?.isSyntheticTraffic === true ||
|
|
172
|
+
requestContext?.agentRunAnonymous === true) {
|
|
167
173
|
return false;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
174
|
+
}
|
|
175
|
+
if (key && BUILDER_CREDITS_DEPLOY_ENV_KEYS.has(key)) {
|
|
176
|
+
return isTrustedSelfHostedRuntime();
|
|
177
|
+
}
|
|
178
|
+
if (key && DEPLOY_LLM_PROVIDER_ENV_KEYS.has(key)) {
|
|
179
|
+
const hostedWorkspace = isHostedWorkspaceRuntime();
|
|
180
|
+
if (hostedWorkspace && isProductionLikeRuntime())
|
|
172
181
|
return false;
|
|
182
|
+
if (isLocalDatabase())
|
|
183
|
+
return true;
|
|
184
|
+
return !hostedWorkspace;
|
|
173
185
|
}
|
|
174
186
|
const email = getRequestUserEmail();
|
|
175
187
|
if (!email)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
===================================================================
|
|
2
2
|
--- a/.agents/skills/adding-a-feature/SKILL.md
|
|
3
3
|
+++ b/.agents/skills/adding-a-feature/SKILL.md
|
|
4
|
-
@@ -
|
|
4
|
+
@@ -131,11 +131,12 @@
|
|
5
5
|
Instruction examples may name secret keys like `SLACK_WEBHOOK`, but must use
|
|
6
6
|
placeholders such as `${keys.SLACK_WEBHOOK}` or `<SLACK_WEBHOOK>`. Do not paste
|
|
7
7
|
real keys, internal data, or customer data into instructions as examples.
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
-# Chat — Agent Guide
|
|
6
6
|
+# App — Agent Guide
|
|
7
7
|
|
|
8
|
-
-Chat is the minimal chat-first agent-native app. `/` redirects to shared sign-in
|
|
8
|
+
-Chat is the minimal chat-first agent-native app. `/` redirects to shared sign-in, then `/home`, the editable Get started page. Chat lives at `/chat`; new chats start there. Actions carry capabilities; screens exist only for durable workflows.
|
|
9
9
|
+This starter ships as a blank Agent-Native app canvas — that describes its
|
|
10
10
|
+initial state, not necessarily its current one. See `DEVELOPING.md` before
|
|
11
11
|
+making any source code change.
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
|
|
31
31
|
## Application state
|
|
32
32
|
|
|
33
|
-
-- `navigation` describes the view and selected ids. Chat is `chat` at `/home`; `/` opens shared sign-in/signup.
|
|
33
|
+
-- `navigation` describes the view and selected ids. Chat is `chat` at `/chat` and `/chat/<threadId>`; the Get started page is `home` at `/home`; `/` opens shared sign-in/signup.
|
|
34
34
|
+- `navigation` describes the view and selected ids. The default home view is
|
|
35
35
|
+ `home` at `/` (blank app canvas). No agent rail or chat is mounted by
|
|
36
36
|
+ default; add one only when the user asks.
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
## Building a domain app
|
|
40
40
|
|
|
41
|
-
-Choose the primary workflow and route before editing. Add a domain route under `app/routes/` and set `app.homePath` in `server/plugins/agent-native-email-branding.ts` with `defineAppConfig`.
|
|
41
|
+
-Choose the primary workflow and route before editing. Add a domain route under `app/routes/` and set `app.homePath` in `server/plugins/agent-native-email-branding.ts` with `defineAppConfig`. The default Get started page lives at `/home`, and Chat stays at `/chat`; edit `app/routes/home.tsx` when replacing that page with a domain-specific home. Add a static link in `app/components/layout/Sidebar.tsx` before `ChatThreadsSection`; `Header.tsx` uses `APP_TITLE` elsewhere. Shared sidebar and AgentInspector remain.
|
|
42
42
|
+Choose the primary workflow and route before editing. Build on the blank canvas in `app/routes/_index.tsx` or add domain routes under `app/routes/`. This starter has no Chat route, sidebar, header, or agent rail; add only the navigation the product needs. Set `app.homePath` in the existing `defineAppConfig` in `server/plugins/config.ts` as `DEVELOPING.md` describes.
|
|
43
43
|
|
|
44
44
|
-Use `adding-a-feature` for functional parity and `frontend-design` for a user-facing screen. Keep feature guidance here; do not rewrite `README.md` or `DESIGN.md`. After all edits, run one typecheck, one doctor check, and one browser smoke of the primary workflow, including overlap rejection, cancellation freeing the slot, and authenticated landing. Skip production build and extra test suites.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
===================================================================
|
|
2
2
|
--- a/app/components/layout/Layout.tsx
|
|
3
3
|
+++ b/app/components/layout/Layout.tsx
|
|
4
|
-
@@ -1,
|
|
4
|
+
@@ -1,188 +1,28 @@
|
|
5
5
|
-import { useT } from "@agent-native/core/client/i18n";
|
|
6
6
|
-import { HeaderActionsProvider } from "@agent-native/toolkit/app-shell/header-actions";
|
|
7
7
|
-import {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
- SheetTitle,
|
|
24
24
|
-} from "@/components/ui/sheet";
|
|
25
25
|
-import { APP_TITLE } from "@/lib/app-config";
|
|
26
|
+
-import { HOME_PATH, isChatPathname } from "@/lib/chat-paths";
|
|
26
27
|
-
|
|
27
28
|
-import { Sidebar } from "./Sidebar";
|
|
28
29
|
-
|
|
@@ -43,8 +44,8 @@
|
|
|
43
44
|
-
|
|
44
45
|
-function routeOwnsToolbar(pathname: string): boolean {
|
|
45
46
|
- return (
|
|
46
|
-
- pathname ===
|
|
47
|
-
- pathname
|
|
47
|
+
- pathname === HOME_PATH ||
|
|
48
|
+
- isChatPathname(pathname) ||
|
|
48
49
|
- pathname === "/database" ||
|
|
49
50
|
- pathname.startsWith("/extensions")
|
|
50
51
|
- );
|
|
@@ -66,8 +67,7 @@
|
|
|
66
67
|
- const t = useT();
|
|
67
68
|
- const [mobileSidebarOpen, setMobileSidebarOpen] = useState(false);
|
|
68
69
|
- const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
|
|
69
|
-
- const isChatRoute =
|
|
70
|
-
- location.pathname === "/home" || location.pathname.startsWith("/chat/");
|
|
70
|
+
- const isChatRoute = isChatPathname(location.pathname);
|
|
71
71
|
- // Settings brings its own navigation, header, and agent toggle, so it
|
|
72
72
|
- // renders full width.
|
|
73
73
|
- const settingsOwnsChrome = isSettingsPathname(location.pathname);
|
|
@@ -79,8 +79,7 @@
|
|
|
79
79
|
- const chatHomeHandoffPending = isAgentChatHomeHandoffActive("chat");
|
|
80
80
|
- useAgentChatHomeHandoffLinks({
|
|
81
81
|
- storageKey: "chat",
|
|
82
|
-
- isChatPath:
|
|
83
|
-
- pathname === "/home" || pathname.startsWith("/chat/"),
|
|
82
|
+
- isChatPath: isChatPathname,
|
|
84
83
|
- requireActiveHandoff: true,
|
|
85
84
|
- });
|
|
86
85
|
-
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
===================================================================
|
|
2
2
|
--- a/app/hooks/use-navigation-state.ts
|
|
3
3
|
+++ b/app/hooks/use-navigation-state.ts
|
|
4
|
-
@@ -
|
|
4
|
+
@@ -1,85 +1,41 @@
|
|
5
|
+
import { appBasePath, appPath } from "@agent-native/core/client/api-path";
|
|
6
|
+
import { useAgentRouteState } from "@agent-native/core/client/navigation";
|
|
7
|
+
|
|
8
|
+
-import {
|
|
9
|
+
- chatThreadPath,
|
|
10
|
+
- HOME_PATH,
|
|
11
|
+
- isChatPathname,
|
|
12
|
+
- NEW_CHAT_PATH,
|
|
13
|
+
- threadIdFromPath,
|
|
14
|
+
-} from "@/lib/chat-paths";
|
|
15
|
+
import { TAB_ID } from "@/lib/tab-id";
|
|
5
16
|
|
|
6
17
|
export interface NavigationState {
|
|
7
18
|
view: string;
|
|
@@ -31,19 +42,9 @@
|
|
|
31
42
|
});
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
-function threadIdFromPath(pathname: string): string | null {
|
|
35
|
-
- const match = pathname.match(/^\/chat\/([^/]+)/);
|
|
36
|
-
- if (!match) return null;
|
|
37
|
-
- try {
|
|
38
|
-
- const value = decodeURIComponent(match[1]).trim();
|
|
39
|
-
- return value || null;
|
|
40
|
-
- } catch {
|
|
41
|
-
- return null;
|
|
42
|
-
- }
|
|
43
|
-
-}
|
|
44
|
-
-
|
|
45
45
|
function viewForPath(pathname: string): string {
|
|
46
|
-
- if (
|
|
46
|
+
- if (isChatPathname(pathname)) return "chat";
|
|
47
|
+
- if (pathname === HOME_PATH) return "home";
|
|
47
48
|
- if (pathname.startsWith("/database")) return "database";
|
|
48
49
|
- if (pathname.startsWith("/extensions")) return "extensions";
|
|
49
50
|
- if (pathname.startsWith("/observability")) return "observability";
|
|
@@ -60,9 +61,10 @@
|
|
|
60
61
|
function pathForView(view?: string): string {
|
|
61
62
|
switch (view) {
|
|
62
63
|
- case "chat":
|
|
63
|
-
case "home":
|
|
64
64
|
- case "ask":
|
|
65
|
-
- return
|
|
65
|
+
- return NEW_CHAT_PATH;
|
|
66
|
+
case "home":
|
|
67
|
+
- return HOME_PATH;
|
|
66
68
|
- case "database":
|
|
67
69
|
- return "/database";
|
|
68
70
|
- case "extensions":
|
|
@@ -77,29 +79,20 @@
|
|
|
77
79
|
- return "/settings/organization";
|
|
78
80
|
+ return "/";
|
|
79
81
|
default:
|
|
80
|
-
- return
|
|
82
|
+
- return HOME_PATH;
|
|
81
83
|
+ return "/";
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
|
|
85
|
-
-function pathForCommand(command: any): string {
|
|
87
|
+
-export function pathForCommand(command: any): string {
|
|
86
88
|
- const path = pathForView(command?.view);
|
|
87
|
-
- if (
|
|
89
|
+
- if (command?.view !== "chat" && command?.view !== "ask") return path;
|
|
88
90
|
- const threadId =
|
|
89
91
|
- typeof command?.threadId === "string" ? command.threadId.trim() : "";
|
|
90
|
-
- return threadId ?
|
|
92
|
+
- return threadId ? chatThreadPath(threadId) : path;
|
|
91
93
|
-}
|
|
92
94
|
-
|
|
93
95
|
function routerPath(path: string): string {
|
|
94
96
|
const basePath = appBasePath();
|
|
95
97
|
if (!basePath) return path;
|
|
96
98
|
if (path === basePath) return "/";
|
|
97
|
-
@@ -89,8 +43,4 @@
|
|
98
|
-
return path.slice(basePath.length) || "/";
|
|
99
|
-
}
|
|
100
|
-
return path;
|
|
101
|
-
}
|
|
102
|
-
-
|
|
103
|
-
-function isChatPath(pathname: string): boolean {
|
|
104
|
-
- return pathname === "/home" || pathname.startsWith("/chat/");
|
|
105
|
-
-}
|