@agent-native/core 0.157.6 → 0.157.8
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/corpus/README.md +1 -1
- package/corpus/templates/analytics/agent-native.config.ts +5 -0
- package/corpus/templates/analytics/netlify.toml +1 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-backend.ts +23 -5
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/assets/netlify.toml +3 -0
- package/corpus/templates/brain/netlify.toml +3 -0
- package/corpus/templates/calendar/agent-native.config.ts +5 -0
- package/corpus/templates/calendar/app/components/layout/AppLayout.tsx +4 -1
- package/corpus/templates/calendar/netlify.toml +3 -0
- package/corpus/templates/chat/agent-native.config.ts +5 -0
- package/corpus/templates/chat/netlify.toml +3 -0
- package/corpus/templates/clips/actions/lib/meeting-content.ts +28 -0
- package/corpus/templates/clips/actions/list-meetings.ts +33 -11
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/lib/meeting-history-query.ts +11 -0
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +47 -21
- package/corpus/templates/clips/netlify.toml +4 -0
- package/corpus/templates/content/netlify.toml +3 -0
- package/corpus/templates/design/app/i18n-data.ts +2 -0
- package/corpus/templates/design/netlify.toml +3 -0
- package/corpus/templates/dispatch/netlify.toml +3 -0
- package/corpus/templates/factory/netlify.toml +3 -0
- package/corpus/templates/forms/netlify.toml +3 -0
- package/corpus/templates/macros/netlify.toml +3 -0
- package/corpus/templates/mail/agent-native.config.ts +5 -0
- package/corpus/templates/mail/netlify.toml +3 -0
- package/corpus/templates/plan/netlify.toml +3 -0
- package/corpus/templates/slides/netlify.toml +3 -0
- package/dist/agent/harness/acp-adapter.js +17 -2
- package/dist/agent/harness/ai-sdk-adapter.js +14 -3
- package/dist/agent/harness/background.js +10 -5
- package/dist/agent/harness/hosted.d.ts +20 -0
- package/dist/agent/harness/hosted.js +100 -0
- package/dist/agent/harness/runner.js +100 -77
- package/dist/agent/observational-memory/observer.js +12 -0
- package/dist/agent/production-agent.d.ts +3 -0
- package/dist/agent/production-agent.js +74 -4
- package/dist/agent/thread-data-builder.d.ts +12 -0
- package/dist/agent/thread-data-builder.js +23 -0
- package/dist/agent/types.d.ts +6 -0
- package/dist/client/AgentPanel.d.ts +5 -1
- package/dist/client/AgentPanel.js +113 -17
- package/dist/client/AgentTaskCard.d.ts +2 -2
- package/dist/client/AgentTaskCard.js +8 -22
- package/dist/client/AssistantChat.d.ts +8 -0
- package/dist/client/AssistantChat.js +106 -59
- package/dist/client/MultiTabAssistantChat.js +50 -6
- package/dist/client/NewWorkspaceAppFlow.js +7 -1
- package/dist/client/agent-chat-adapter.d.ts +6 -0
- package/dist/client/agent-chat-adapter.js +36 -8
- package/dist/client/app-chat-sidebar.d.ts +5 -0
- package/dist/client/app-chat-sidebar.js +53 -9
- package/dist/client/chat/composer-draft.d.ts +4 -0
- package/dist/client/chat/composer-draft.js +63 -0
- package/dist/client/chat-first/apps-rail.js +10 -1
- package/dist/client/chat-first/primary-nav.js +10 -5
- package/dist/client/frame-protocol.d.ts +1 -0
- package/dist/client/hooks/index.d.ts +1 -1
- package/dist/client/hooks/index.js +1 -1
- package/dist/client/i18n.js +5 -2
- package/dist/client/progress/RunsTray.js +129 -16
- package/dist/client/settings/SettingsRow.js +1 -1
- package/dist/client/use-chat-threads.js +11 -6
- package/dist/config.d.ts +11 -0
- package/dist/config.js +52 -0
- package/dist/extensions/actions.js +22 -1
- package/dist/hosted-harness/actions/get-hosted-harness-config.d.ts +2 -0
- package/dist/hosted-harness/actions/get-hosted-harness-config.js +13 -0
- package/dist/hosted-harness/actions/set-hosted-harness-enabled.d.ts +4 -0
- package/dist/hosted-harness/actions/set-hosted-harness-enabled.js +32 -0
- package/dist/localization/default-messages.d.ts +4 -1
- package/dist/localization/default-messages.js +5 -2
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +6 -6
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/server/action-discovery.js +12 -0
- package/dist/server/agent-chat-plugin.js +24 -4
- package/dist/server/agent-teams.d.ts +20 -12
- package/dist/server/agent-teams.js +69 -35
- package/dist/server/hosted-harness-policy.d.ts +17 -0
- package/dist/server/hosted-harness-policy.js +38 -0
- package/dist/server/poll.d.ts +4 -4
- package/dist/server/poll.js +45 -13
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/request-context.d.ts +4 -0
- package/dist/styles/agent-native.css +39 -0
- package/dist/templates/chat/agent-native.config.ts +5 -0
- package/dist/templates/chat/netlify.toml +3 -0
- package/dist/vite/action-types-plugin.js +8 -0
- package/package.json +5 -3
- package/src/templates/chat/agent-native.config.ts +5 -0
- package/src/templates/chat/netlify.toml +3 -0
|
@@ -1242,6 +1242,27 @@ async function summarizeExtensionForAgentRead(row, hiddenIds, includeContent, fo
|
|
|
1242
1242
|
const fingerprint = contentFingerprint(row.content);
|
|
1243
1243
|
if (contentQuery) {
|
|
1244
1244
|
const summary = await summarizeExtension(row, hiddenIds, false);
|
|
1245
|
+
// The whole-body read below is deduped per run, but this branch returned
|
|
1246
|
+
// above it, so a repeated excerpt request re-sent bytes already in context.
|
|
1247
|
+
// One production turn spent 48 of 110 reads re-fetching the same spans.
|
|
1248
|
+
const excerptCtx = getRequestRunContext();
|
|
1249
|
+
const excerpts = excerptCtx
|
|
1250
|
+
? (excerptCtx.extensionExcerptReads ??= {})
|
|
1251
|
+
: undefined;
|
|
1252
|
+
const excerptKey = `${row.id}:${fingerprint}:${contentContextChars}:${contentQuery}`;
|
|
1253
|
+
if (excerpts?.[excerptKey]) {
|
|
1254
|
+
return {
|
|
1255
|
+
...summary,
|
|
1256
|
+
contentOmitted: {
|
|
1257
|
+
reason: "identical-excerpt-already-returned-this-run",
|
|
1258
|
+
contentHash: fingerprint,
|
|
1259
|
+
contentLength: row.content.length,
|
|
1260
|
+
next: 'These exact excerpts were already returned earlier in this run and the body has not changed. Use them to call update-extension with operation="edit"; use a different contentQuery only for a source area you have not read yet.',
|
|
1261
|
+
},
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
if (excerpts)
|
|
1265
|
+
excerpts[excerptKey] = true;
|
|
1245
1266
|
return {
|
|
1246
1267
|
...summary,
|
|
1247
1268
|
contentMatches: findExtensionContentMatches(row.content, contentQuery, contentContextChars),
|
|
@@ -1266,7 +1287,7 @@ async function summarizeExtensionForAgentRead(row, hiddenIds, includeContent, fo
|
|
|
1266
1287
|
contentHash: fingerprint,
|
|
1267
1288
|
contentLength: row.content.length,
|
|
1268
1289
|
inlineContentLimit: LARGE_EXTENSION_INLINE_CONTENT_MAX_CHARS,
|
|
1269
|
-
next:
|
|
1290
|
+
next: `Call get-extension again with contentQuery set to the relevant function, variable, section marker, or literal text. If you expect to read more than about three separate areas of this ${row.content.length}-char body, call get-extension once with forceContent=true instead — repeated excerpt reads of the same file cost more context than one whole read.`,
|
|
1270
1291
|
},
|
|
1271
1292
|
};
|
|
1272
1293
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineAction } from "../../action.js";
|
|
3
|
+
import { hostedHarnessStatusForClient, resolveHostedHarnessPolicy, } from "../../server/hosted-harness-policy.js";
|
|
4
|
+
export default defineAction({
|
|
5
|
+
description: "Return whether this app's hosted tools-only harness is enabled for the current organization and which runtimes are available.",
|
|
6
|
+
schema: z.object({}),
|
|
7
|
+
http: { method: "GET" },
|
|
8
|
+
agentTool: false,
|
|
9
|
+
run: async (_args, context) => hostedHarnessStatusForClient(await resolveHostedHarnessPolicy({
|
|
10
|
+
orgId: context?.orgId,
|
|
11
|
+
userEmail: context?.userEmail,
|
|
12
|
+
})),
|
|
13
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineAction } from "../../action.js";
|
|
3
|
+
import { HOSTED_HARNESS_ORG_SETTING_KEY } from "../../agent/harness/hosted.js";
|
|
4
|
+
import { getOrgRoleForEmail } from "../../mcp/actions/service-token-access.js";
|
|
5
|
+
import { canManageOrg } from "../../org/permissions.js";
|
|
6
|
+
import { hostedHarnessStatusForClient, resolveHostedHarnessPolicy, } from "../../server/hosted-harness-policy.js";
|
|
7
|
+
import { putOrgSetting } from "../../settings/org-settings.js";
|
|
8
|
+
export default defineAction({
|
|
9
|
+
description: "Enable or disable the hosted tools-only harness for the current organization. Organization owners and admins only.",
|
|
10
|
+
schema: z.object({ enabled: z.boolean() }),
|
|
11
|
+
http: { method: "POST" },
|
|
12
|
+
agentTool: false,
|
|
13
|
+
run: async (args, context) => {
|
|
14
|
+
const email = context?.userEmail?.trim().toLowerCase();
|
|
15
|
+
const orgId = context?.orgId?.trim();
|
|
16
|
+
if (!email)
|
|
17
|
+
throw new Error("Sign in to manage hosted harnesses.");
|
|
18
|
+
if (!orgId)
|
|
19
|
+
throw new Error("Select an organization to manage harnesses.");
|
|
20
|
+
const role = await getOrgRoleForEmail(orgId, email);
|
|
21
|
+
if (!canManageOrg(role)) {
|
|
22
|
+
throw new Error("Only organization owners and admins can manage hosted harnesses.");
|
|
23
|
+
}
|
|
24
|
+
await putOrgSetting(orgId, HOSTED_HARNESS_ORG_SETTING_KEY, {
|
|
25
|
+
enabled: args.enabled,
|
|
26
|
+
});
|
|
27
|
+
return hostedHarnessStatusForClient(await resolveHostedHarnessPolicy({
|
|
28
|
+
orgId,
|
|
29
|
+
userEmail: email,
|
|
30
|
+
}));
|
|
31
|
+
},
|
|
32
|
+
});
|
|
@@ -733,6 +733,9 @@ declare const messages: {
|
|
|
733
733
|
statusDone: string;
|
|
734
734
|
statusFailed: string;
|
|
735
735
|
statusStopped: string;
|
|
736
|
+
statusNeedsApproval: string;
|
|
737
|
+
statusNeedsInput: string;
|
|
738
|
+
statusPaused: string;
|
|
736
739
|
updatedJustNow: string;
|
|
737
740
|
finishedJustNow: string;
|
|
738
741
|
updatedMinutes: string;
|
|
@@ -743,7 +746,7 @@ declare const messages: {
|
|
|
743
746
|
finishedDate: string;
|
|
744
747
|
};
|
|
745
748
|
agentTask: {
|
|
746
|
-
|
|
749
|
+
spawnedAgent: string;
|
|
747
750
|
stop: string;
|
|
748
751
|
openThread: string;
|
|
749
752
|
};
|
|
@@ -739,6 +739,9 @@ const messages = {
|
|
|
739
739
|
statusDone: "Done",
|
|
740
740
|
statusFailed: "Failed",
|
|
741
741
|
statusStopped: "Stopped",
|
|
742
|
+
statusNeedsApproval: "Needs approval",
|
|
743
|
+
statusNeedsInput: "Needs input",
|
|
744
|
+
statusPaused: "Paused",
|
|
742
745
|
updatedJustNow: "Updated just now",
|
|
743
746
|
finishedJustNow: "Finished just now",
|
|
744
747
|
updatedMinutes: "Updated {{count}}m ago",
|
|
@@ -749,8 +752,8 @@ const messages = {
|
|
|
749
752
|
finishedDate: "Finished {{date}}",
|
|
750
753
|
},
|
|
751
754
|
agentTask: {
|
|
752
|
-
|
|
753
|
-
stop: "Stop
|
|
755
|
+
spawnedAgent: "Spawned agent",
|
|
756
|
+
stop: "Stop spawned agent",
|
|
754
757
|
openThread: "Open task thread",
|
|
755
758
|
},
|
|
756
759
|
codeRequired: {
|
|
@@ -75,8 +75,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
75
75
|
user: "user";
|
|
76
76
|
}>>;
|
|
77
77
|
}, z.core.$strip>>, {
|
|
78
|
-
id?: undefined;
|
|
79
78
|
message?: undefined;
|
|
79
|
+
id?: undefined;
|
|
80
|
+
provider?: undefined;
|
|
80
81
|
deleted?: undefined;
|
|
81
82
|
providers: {
|
|
82
83
|
id: string;
|
|
@@ -88,14 +89,13 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
88
89
|
updatedAt: number;
|
|
89
90
|
}[];
|
|
90
91
|
count: number;
|
|
91
|
-
provider?: undefined;
|
|
92
92
|
found?: undefined;
|
|
93
93
|
registered?: undefined;
|
|
94
94
|
label?: undefined;
|
|
95
95
|
} | {
|
|
96
|
-
id?: undefined;
|
|
97
96
|
message?: undefined;
|
|
98
97
|
count?: undefined;
|
|
98
|
+
id?: undefined;
|
|
99
99
|
deleted?: undefined;
|
|
100
100
|
providers?: undefined;
|
|
101
101
|
found: boolean;
|
|
@@ -105,9 +105,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
105
105
|
} | {
|
|
106
106
|
message?: undefined;
|
|
107
107
|
count?: undefined;
|
|
108
|
+
provider?: undefined;
|
|
108
109
|
deleted?: undefined;
|
|
109
110
|
providers?: undefined;
|
|
110
|
-
provider?: undefined;
|
|
111
111
|
found: boolean;
|
|
112
112
|
id: string;
|
|
113
113
|
registered?: undefined;
|
|
@@ -115,8 +115,8 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
115
115
|
} | {
|
|
116
116
|
message?: undefined;
|
|
117
117
|
count?: undefined;
|
|
118
|
-
providers?: undefined;
|
|
119
118
|
provider?: undefined;
|
|
119
|
+
providers?: undefined;
|
|
120
120
|
found?: undefined;
|
|
121
121
|
deleted: boolean;
|
|
122
122
|
id: string;
|
|
@@ -124,9 +124,9 @@ export declare function createCustomProviderRegistrationAction<TSchema extends Z
|
|
|
124
124
|
label?: undefined;
|
|
125
125
|
} | {
|
|
126
126
|
count?: undefined;
|
|
127
|
+
provider?: undefined;
|
|
127
128
|
deleted?: undefined;
|
|
128
129
|
providers?: undefined;
|
|
129
|
-
provider?: undefined;
|
|
130
130
|
found?: undefined;
|
|
131
131
|
registered: boolean;
|
|
132
132
|
id: string;
|
|
@@ -313,7 +313,6 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
313
313
|
}, {
|
|
314
314
|
deleted?: undefined;
|
|
315
315
|
id?: undefined;
|
|
316
|
-
provider?: undefined;
|
|
317
316
|
providers: {
|
|
318
317
|
id: string;
|
|
319
318
|
label: string;
|
|
@@ -324,6 +323,7 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
324
323
|
updatedAt: number;
|
|
325
324
|
}[];
|
|
326
325
|
count: number;
|
|
326
|
+
provider?: undefined;
|
|
327
327
|
found?: undefined;
|
|
328
328
|
registered?: undefined;
|
|
329
329
|
label?: undefined;
|
|
@@ -340,18 +340,18 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
340
340
|
message?: undefined;
|
|
341
341
|
} | {
|
|
342
342
|
deleted?: undefined;
|
|
343
|
-
provider?: undefined;
|
|
344
343
|
providers?: undefined;
|
|
345
344
|
count?: undefined;
|
|
345
|
+
provider?: undefined;
|
|
346
346
|
found: boolean;
|
|
347
347
|
id: string;
|
|
348
348
|
registered?: undefined;
|
|
349
349
|
label?: undefined;
|
|
350
350
|
message?: undefined;
|
|
351
351
|
} | {
|
|
352
|
-
provider?: undefined;
|
|
353
352
|
providers?: undefined;
|
|
354
353
|
count?: undefined;
|
|
354
|
+
provider?: undefined;
|
|
355
355
|
found?: undefined;
|
|
356
356
|
deleted: boolean;
|
|
357
357
|
id: string;
|
|
@@ -360,9 +360,9 @@ export declare function createProviderApiActions(runtime: Pick<ProviderApiRuntim
|
|
|
360
360
|
message?: undefined;
|
|
361
361
|
} | {
|
|
362
362
|
deleted?: undefined;
|
|
363
|
-
provider?: undefined;
|
|
364
363
|
providers?: undefined;
|
|
365
364
|
count?: undefined;
|
|
365
|
+
provider?: undefined;
|
|
366
366
|
found?: undefined;
|
|
367
367
|
registered: boolean;
|
|
368
368
|
id: string;
|
|
@@ -529,6 +529,10 @@ export const ALWAYS_ON_CORE_ACTIONS = new Set([
|
|
|
529
529
|
"revoke-org-service-token",
|
|
530
530
|
"list-mcp-tools",
|
|
531
531
|
"call-mcp-tool",
|
|
532
|
+
// Hosted harness capability/policy routes are UI-facing and deliberately
|
|
533
|
+
// never enter the model's action surface (`agentTool: false`).
|
|
534
|
+
"get-hosted-harness-config",
|
|
535
|
+
"set-hosted-harness-enabled",
|
|
532
536
|
]);
|
|
533
537
|
export async function mergeCoreSharingActions(registry) {
|
|
534
538
|
const entries = [
|
|
@@ -592,6 +596,14 @@ export async function mergeCoreSharingActions(registry) {
|
|
|
592
596
|
"get-feature-flags",
|
|
593
597
|
() => import("../feature-flags/actions/get-feature-flags.js"),
|
|
594
598
|
],
|
|
599
|
+
[
|
|
600
|
+
"get-hosted-harness-config",
|
|
601
|
+
() => import("../hosted-harness/actions/get-hosted-harness-config.js"),
|
|
602
|
+
],
|
|
603
|
+
[
|
|
604
|
+
"set-hosted-harness-enabled",
|
|
605
|
+
() => import("../hosted-harness/actions/set-hosted-harness-enabled.js"),
|
|
606
|
+
],
|
|
595
607
|
[
|
|
596
608
|
"list-feature-flags",
|
|
597
609
|
() => import("../feature-flags/actions/list-feature-flags.js"),
|
|
@@ -12,6 +12,7 @@ import { AGENT_CHAT_BACKGROUND_RUN_FIELD, AGENT_CHAT_PROCESS_RUN_PATH, backgroun
|
|
|
12
12
|
import { resolveEngine, createAnthropicEngine, getStoredModelForEngine, normalizeModelForEngine, resolveDelegatedRunModel, getAgentEngineEntry, isAgentEnginePackageInstalled, isStoredEngineUsableForRequest, listAgentEngines, registerBuiltinEngines, } from "../agent/engine/index.js";
|
|
13
13
|
import { SYSTEM_PROMPT_CACHE_SPLIT } from "../agent/engine/prompt-cache.js";
|
|
14
14
|
import { PROVIDER_TO_ENV } from "../agent/engine/provider-env-vars.js";
|
|
15
|
+
import { hostedHarnessSystemPrompt } from "../agent/harness/hosted.js";
|
|
15
16
|
import { createProductionAgentHandler, actionsToEngineTools, executeAgentToolCall, filterActionsByAllowedNames, readPersistedActionSurface, toolCallCacheKey, getActiveRunForThreadAsync, abortRunDurably, abortTurnDurably, subscribeToRun, } from "../agent/production-agent.js";
|
|
16
17
|
import { callerHasRunAccess, callerHasThreadAccess, } from "../agent/run-ownership.js";
|
|
17
18
|
import { markTurnAborted, readBackgroundRunClaim } from "../agent/run-store.js";
|
|
@@ -44,6 +45,7 @@ import { captureError } from "./capture-error.js";
|
|
|
44
45
|
import { getH3App, markDefaultPluginProvided, trackPluginInit, } from "./framework-request-handler.js";
|
|
45
46
|
import { getOrigin } from "./google-oauth.js";
|
|
46
47
|
import { readBody } from "./h3-helpers.js";
|
|
48
|
+
import { loadHostedHarnessConfig } from "./hosted-harness-policy.js";
|
|
47
49
|
import { startIntervalJob } from "./interval-job.js";
|
|
48
50
|
import { getModelFamilyOverlay } from "./prompts/index.js";
|
|
49
51
|
import { mountRealtimeVoiceRoutes } from "./realtime-voice.js";
|
|
@@ -309,6 +311,7 @@ export function createAgentChatPlugin(options) {
|
|
|
309
311
|
// `/runs/active` reaps the requested run on demand, and the periodic
|
|
310
312
|
// recovery sweep below handles abandoned runs with no connected client.
|
|
311
313
|
const env = process.env.NODE_ENV;
|
|
314
|
+
const hostedHarnessConfig = await loadHostedHarnessConfig();
|
|
312
315
|
// AGENT_MODE=production forces production agent constraints even in dev
|
|
313
316
|
const canToggle = (env === "development" || env === "test") &&
|
|
314
317
|
process.env.AGENT_MODE !== "production";
|
|
@@ -2694,6 +2697,13 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2694
2697
|
const codeEditingSurfaceRestriction = shouldBlockInProductCodeEditing(event)
|
|
2695
2698
|
? APP_RENDERED_CHAT_NO_DIRECT_CODE_PROMPT
|
|
2696
2699
|
: "";
|
|
2700
|
+
const hostedHarnessRuntime = getRequestRunContext()?.hostedHarnessRuntime;
|
|
2701
|
+
const hostedHarnessPromptNote = hostedHarnessRuntime
|
|
2702
|
+
? hostedHarnessSystemPrompt(hostedHarnessRuntime)
|
|
2703
|
+
: "";
|
|
2704
|
+
const requestProdCodeExecPromptNote = hostedHarnessRuntime
|
|
2705
|
+
? ""
|
|
2706
|
+
: prodCodeExecPromptNote;
|
|
2697
2707
|
// Per-model overlay: nudge GPT/Gemini engines toward our behavioral norms.
|
|
2698
2708
|
const modelOverlay = resolveModelOverlay();
|
|
2699
2709
|
// Stable-first ordering: base prompt / schema / extra come before
|
|
@@ -2705,7 +2715,7 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2705
2715
|
// `SYSTEM_PROMPT_CACHE_SPLIT` marks where the cacheable prefix ends,
|
|
2706
2716
|
// so everything after it can change without a cache write.
|
|
2707
2717
|
if (leanPrompt) {
|
|
2708
|
-
const leanRunPolicyPrompt = buildLeanRunPolicyPrompt(codeEditingSurfaceRestriction,
|
|
2718
|
+
const leanRunPolicyPrompt = buildLeanRunPolicyPrompt(codeEditingSurfaceRestriction, `${requestProdCodeExecPromptNote}${hostedHarnessPromptNote ? `\n\n${hostedHarnessPromptNote}` : ""}`);
|
|
2709
2719
|
const resources = await loadResourcesForPrompt(owner, true, options?.appId, undefined, { disabledFrameworkGroups });
|
|
2710
2720
|
await emitContextXraySystemSections(event, {
|
|
2711
2721
|
frameworkPrompt: requestLeanPrompt.slice(0, Math.max(0, requestLeanPrompt.length - requestLeanActionsPrompt.length)),
|
|
@@ -2740,20 +2750,26 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
2740
2750
|
extra,
|
|
2741
2751
|
modelOverlay,
|
|
2742
2752
|
runtimeContext,
|
|
2743
|
-
additionalFramework: codeEditingSurfaceRestriction +
|
|
2753
|
+
additionalFramework: codeEditingSurfaceRestriction +
|
|
2754
|
+
requestProdCodeExecPromptNote +
|
|
2755
|
+
(hostedHarnessPromptNote ? `\n\n${hostedHarnessPromptNote}` : ""),
|
|
2744
2756
|
});
|
|
2745
2757
|
return setSystemPromptOnContext(requestBasePrompt +
|
|
2746
2758
|
SYSTEM_PROMPT_CACHE_SPLIT +
|
|
2747
2759
|
resources +
|
|
2748
2760
|
schemaBlock +
|
|
2749
2761
|
codeEditingSurfaceRestriction +
|
|
2750
|
-
|
|
2762
|
+
requestProdCodeExecPromptNote +
|
|
2763
|
+
(hostedHarnessPromptNote
|
|
2764
|
+
? `\n\n${hostedHarnessPromptNote}`
|
|
2765
|
+
: "") +
|
|
2751
2766
|
extra +
|
|
2752
2767
|
modelOverlay +
|
|
2753
2768
|
runtimeContext);
|
|
2754
2769
|
},
|
|
2755
2770
|
model: options?.model,
|
|
2756
2771
|
appId: options?.appId,
|
|
2772
|
+
hostedHarnessConfig,
|
|
2757
2773
|
apiKey: options?.apiKey,
|
|
2758
2774
|
...resolveInteractiveAgentRunOptions(options),
|
|
2759
2775
|
finalResponseGuard: options?.finalResponseGuard,
|
|
@@ -4692,9 +4708,13 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
4692
4708
|
// `prodHandler.systemPrompt` then steers source changes to a
|
|
4693
4709
|
// separate agent surface such as Builder or the dev frame.
|
|
4694
4710
|
const blockInProductCodeEditing = shouldBlockInProductCodeEditing(event);
|
|
4711
|
+
const hostedHarnessRequest = getHeader(event, "x-agent-native-hosted-harness") === "1";
|
|
4695
4712
|
const handler = ownerContext.anonymous && anonymousHandler
|
|
4696
4713
|
? anonymousHandler
|
|
4697
|
-
: !
|
|
4714
|
+
: !hostedHarnessRequest &&
|
|
4715
|
+
!blockInProductCodeEditing &&
|
|
4716
|
+
currentDevMode &&
|
|
4717
|
+
devHandler
|
|
4698
4718
|
? devHandler
|
|
4699
4719
|
: prodHandler;
|
|
4700
4720
|
return handler(event);
|
|
@@ -66,6 +66,10 @@ export interface AgentTask {
|
|
|
66
66
|
taskId: string;
|
|
67
67
|
threadId: string;
|
|
68
68
|
parentThreadId?: string;
|
|
69
|
+
/** Request owner used to scope every browser-visible task read and control. */
|
|
70
|
+
ownerEmail?: string | null;
|
|
71
|
+
/** Organization scope captured when the task was spawned. */
|
|
72
|
+
orgId?: string | null;
|
|
69
73
|
name?: string;
|
|
70
74
|
description: string;
|
|
71
75
|
status: "running" | "completed" | "errored";
|
|
@@ -85,6 +89,10 @@ export interface AgentTask {
|
|
|
85
89
|
*/
|
|
86
90
|
delegationDepth?: number;
|
|
87
91
|
}
|
|
92
|
+
export interface AgentTeamOwnerScope {
|
|
93
|
+
ownerEmail: string | null;
|
|
94
|
+
orgId?: string | null;
|
|
95
|
+
}
|
|
88
96
|
export type AgentTeamBackgroundRun = Omit<BackgroundAgentRun, "kind" | "source" | "sourceRecord" | "status" | "cwd" | "goalId" | "transcriptPath" | "artifactRoot"> & {
|
|
89
97
|
kind: "agent-team";
|
|
90
98
|
source: "hosted-agent-team";
|
|
@@ -272,25 +280,25 @@ export declare function processAgentTeamRun(opts: ProcessAgentTeamRunOptions): P
|
|
|
272
280
|
ok: boolean;
|
|
273
281
|
skipped?: string;
|
|
274
282
|
}>;
|
|
275
|
-
/** Get task by ID */
|
|
276
|
-
export declare function getTask(taskId: string): Promise<AgentTask | undefined>;
|
|
277
|
-
/** Get task by thread ID */
|
|
278
|
-
export declare function getTaskByThread(threadId: string): Promise<AgentTask | undefined>;
|
|
279
|
-
/** List
|
|
280
|
-
export declare function listTasks(): Promise<AgentTask[]>;
|
|
281
|
-
export declare function listAgentTeamBackgroundRuns(): Promise<AgentTeamBackgroundRun[]>;
|
|
282
|
-
export declare function getAgentTeamBackgroundRun(runId: string): Promise<AgentTeamBackgroundRun | null>;
|
|
283
|
-
export declare function listAgentTeamBackgroundTranscriptEvents(runId: string): Promise<AgentTeamBackgroundTranscriptEvent[]>;
|
|
283
|
+
/** Get task by ID, optionally constrained to the current request scope. */
|
|
284
|
+
export declare function getTask(taskId: string, scope?: AgentTeamOwnerScope): Promise<AgentTask | undefined>;
|
|
285
|
+
/** Get task by thread ID, optionally constrained to the current request scope. */
|
|
286
|
+
export declare function getTaskByThread(threadId: string, scope?: AgentTeamOwnerScope): Promise<AgentTask | undefined>;
|
|
287
|
+
/** List tasks in the current owner/org scope (most recent first). */
|
|
288
|
+
export declare function listTasks(scope?: AgentTeamOwnerScope): Promise<AgentTask[]>;
|
|
289
|
+
export declare function listAgentTeamBackgroundRuns(scope?: AgentTeamOwnerScope): Promise<AgentTeamBackgroundRun[]>;
|
|
290
|
+
export declare function getAgentTeamBackgroundRun(runId: string, scope?: AgentTeamOwnerScope): Promise<AgentTeamBackgroundRun | null>;
|
|
291
|
+
export declare function listAgentTeamBackgroundTranscriptEvents(runId: string, scope?: AgentTeamOwnerScope): Promise<AgentTeamBackgroundTranscriptEvent[]>;
|
|
284
292
|
export declare function subscribeToAgentTeamBackgroundRun(runId: string, fromSeq?: number): ReadableStream<Uint8Array> | null;
|
|
285
293
|
/** Send a message/update to a running sub-agent via application state */
|
|
286
|
-
export declare function sendToTask(taskId: string, message: string): Promise<{
|
|
294
|
+
export declare function sendToTask(taskId: string, message: string, scope?: AgentTeamOwnerScope): Promise<{
|
|
287
295
|
ok: boolean;
|
|
288
296
|
error?: string;
|
|
289
297
|
messageId?: string;
|
|
290
298
|
queuedCount?: number;
|
|
291
299
|
}>;
|
|
292
|
-
export declare function sendToAgentTeamBackgroundRun(runId: string, message: string): Promise<SendToAgentTeamBackgroundRunResult>;
|
|
293
|
-
export declare function stopAgentTeamBackgroundRun(runId: string, reason?: string): Promise<ControlAgentTeamBackgroundRunResult>;
|
|
300
|
+
export declare function sendToAgentTeamBackgroundRun(runId: string, message: string, scope?: AgentTeamOwnerScope): Promise<SendToAgentTeamBackgroundRunResult>;
|
|
301
|
+
export declare function stopAgentTeamBackgroundRun(runId: string, reason?: string, scope?: AgentTeamOwnerScope): Promise<ControlAgentTeamBackgroundRunResult>;
|
|
294
302
|
/** Mark a task as errored */
|
|
295
303
|
export declare function markTaskErrored(taskId: string, error: string): Promise<void>;
|
|
296
304
|
export declare const _agentTeamsQueueForTests: {
|
|
@@ -936,10 +936,24 @@ export async function spawnTask(opts) {
|
|
|
936
936
|
}
|
|
937
937
|
const runId = taskRunId(taskId);
|
|
938
938
|
const createdAt = Date.now();
|
|
939
|
+
let orgId;
|
|
940
|
+
if (hasRequestContext()) {
|
|
941
|
+
orgId = getRequestOrgId() ?? null;
|
|
942
|
+
}
|
|
943
|
+
else {
|
|
944
|
+
try {
|
|
945
|
+
orgId = await resolveOrgIdForEmail(opts.ownerEmail);
|
|
946
|
+
}
|
|
947
|
+
catch {
|
|
948
|
+
orgId = null;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
939
951
|
const task = {
|
|
940
952
|
taskId,
|
|
941
953
|
threadId: thread.id,
|
|
942
954
|
...(opts.parentThreadId ? { parentThreadId: opts.parentThreadId } : {}),
|
|
955
|
+
ownerEmail: opts.ownerEmail,
|
|
956
|
+
orgId,
|
|
943
957
|
...(opts.name ? { name: opts.name } : {}),
|
|
944
958
|
description: opts.description,
|
|
945
959
|
status: "running",
|
|
@@ -972,18 +986,6 @@ export async function spawnTask(opts) {
|
|
|
972
986
|
// (integrations/webhook-handler.ts). Execution happens in `processAgentTeamRun`,
|
|
973
987
|
// invoked by the `/_agent-native/agent-teams/_process-run` route mounted
|
|
974
988
|
// inside the agent-chat plugin (where the action/prompt/engine closures live).
|
|
975
|
-
let orgId;
|
|
976
|
-
if (hasRequestContext()) {
|
|
977
|
-
orgId = getRequestOrgId() ?? null;
|
|
978
|
-
}
|
|
979
|
-
else {
|
|
980
|
-
try {
|
|
981
|
-
orgId = await resolveOrgIdForEmail(opts.ownerEmail);
|
|
982
|
-
}
|
|
983
|
-
catch {
|
|
984
|
-
orgId = null;
|
|
985
|
-
}
|
|
986
|
-
}
|
|
987
989
|
const payload = {
|
|
988
990
|
description: opts.description,
|
|
989
991
|
instructions: opts.instructions,
|
|
@@ -1505,35 +1507,45 @@ export async function processAgentTeamRun(opts) {
|
|
|
1505
1507
|
return { ok: true };
|
|
1506
1508
|
});
|
|
1507
1509
|
}
|
|
1508
|
-
/** Get task by ID */
|
|
1509
|
-
export async function getTask(taskId) {
|
|
1510
|
+
/** Get task by ID, optionally constrained to the current request scope. */
|
|
1511
|
+
export async function getTask(taskId, scope) {
|
|
1510
1512
|
const task = await loadTask(taskId);
|
|
1511
|
-
|
|
1513
|
+
if (!task || !taskMatchesOwnerScope(task, resolveOwnerScope(scope))) {
|
|
1514
|
+
return undefined;
|
|
1515
|
+
}
|
|
1516
|
+
return await reconcileTaskWithRun(task);
|
|
1512
1517
|
}
|
|
1513
|
-
/** Get task by thread ID */
|
|
1514
|
-
export async function getTaskByThread(threadId) {
|
|
1518
|
+
/** Get task by thread ID, optionally constrained to the current request scope. */
|
|
1519
|
+
export async function getTaskByThread(threadId, scope) {
|
|
1515
1520
|
const task = await loadTaskByThread(threadId);
|
|
1516
|
-
|
|
1521
|
+
if (!task || !taskMatchesOwnerScope(task, resolveOwnerScope(scope))) {
|
|
1522
|
+
return undefined;
|
|
1523
|
+
}
|
|
1524
|
+
return await reconcileTaskWithRun(task);
|
|
1517
1525
|
}
|
|
1518
|
-
/** List
|
|
1519
|
-
export async function listTasks() {
|
|
1526
|
+
/** List tasks in the current owner/org scope (most recent first). */
|
|
1527
|
+
export async function listTasks(scope) {
|
|
1528
|
+
const ownerScope = resolveOwnerScope(scope);
|
|
1520
1529
|
const entries = await listAppState(TASK_PREFIX);
|
|
1521
|
-
const tasks = entries
|
|
1530
|
+
const tasks = entries
|
|
1531
|
+
.map((e) => e.value)
|
|
1532
|
+
.filter((task) => taskMatchesOwnerScope(task, ownerScope));
|
|
1522
1533
|
const reconciled = await Promise.all(tasks.map(reconcileTaskWithRun));
|
|
1523
1534
|
return reconciled.sort((a, b) => (b.updatedAt ?? b.completedAt ?? b.createdAt) -
|
|
1524
1535
|
(a.updatedAt ?? a.completedAt ?? a.createdAt));
|
|
1525
1536
|
}
|
|
1526
|
-
export async function listAgentTeamBackgroundRuns() {
|
|
1527
|
-
return (await listTasks()).map(toAgentTaskBackgroundRun);
|
|
1537
|
+
export async function listAgentTeamBackgroundRuns(scope) {
|
|
1538
|
+
return (await listTasks(scope)).map(toAgentTaskBackgroundRun);
|
|
1528
1539
|
}
|
|
1529
|
-
export async function getAgentTeamBackgroundRun(runId) {
|
|
1530
|
-
const task = await
|
|
1531
|
-
return task
|
|
1532
|
-
? toAgentTaskBackgroundRun(await reconcileTaskWithRun(task))
|
|
1533
|
-
: null;
|
|
1540
|
+
export async function getAgentTeamBackgroundRun(runId, scope) {
|
|
1541
|
+
const task = await getTask(taskIdFromBackgroundRunId(runId), scope);
|
|
1542
|
+
return task ? toAgentTaskBackgroundRun(task) : null;
|
|
1534
1543
|
}
|
|
1535
|
-
export async function listAgentTeamBackgroundTranscriptEvents(runId) {
|
|
1544
|
+
export async function listAgentTeamBackgroundTranscriptEvents(runId, scope) {
|
|
1536
1545
|
const taskId = taskIdFromBackgroundRunId(runId);
|
|
1546
|
+
const ownerScope = resolveOwnerScope(scope);
|
|
1547
|
+
if (ownerScope && !(await getTask(taskId, ownerScope)))
|
|
1548
|
+
return [];
|
|
1537
1549
|
const normalizedRunId = taskRunId(taskId);
|
|
1538
1550
|
const runIds = await transcriptRunIdsForTask(taskId);
|
|
1539
1551
|
const output = [];
|
|
@@ -1589,10 +1601,11 @@ async function getPersistedRunEvents(runId) {
|
|
|
1589
1601
|
.filter((event) => Boolean(event));
|
|
1590
1602
|
}
|
|
1591
1603
|
/** Send a message/update to a running sub-agent via application state */
|
|
1592
|
-
export async function sendToTask(taskId, message) {
|
|
1604
|
+
export async function sendToTask(taskId, message, scope) {
|
|
1593
1605
|
const task = await loadTask(taskId);
|
|
1594
|
-
if (!task)
|
|
1606
|
+
if (!task || !taskMatchesOwnerScope(task, resolveOwnerScope(scope))) {
|
|
1595
1607
|
return { ok: false, error: "Task not found" };
|
|
1608
|
+
}
|
|
1596
1609
|
if (task.status !== "running")
|
|
1597
1610
|
return { ok: false, error: "Task is not running" };
|
|
1598
1611
|
if (message.trim().length === 0)
|
|
@@ -1612,8 +1625,8 @@ export async function sendToTask(taskId, message) {
|
|
|
1612
1625
|
return { ok: false, error: "Unable to queue message" };
|
|
1613
1626
|
}
|
|
1614
1627
|
}
|
|
1615
|
-
export async function sendToAgentTeamBackgroundRun(runId, message) {
|
|
1616
|
-
return sendToTask(taskIdFromBackgroundRunId(runId), message);
|
|
1628
|
+
export async function sendToAgentTeamBackgroundRun(runId, message, scope) {
|
|
1629
|
+
return sendToTask(taskIdFromBackgroundRunId(runId), message, scope);
|
|
1617
1630
|
}
|
|
1618
1631
|
async function sendAgentTeamBackgroundAgentFollowUp(input) {
|
|
1619
1632
|
const prompt = input.prompt.trim();
|
|
@@ -1655,11 +1668,12 @@ async function controlAgentTeamBackgroundAgentRun(input) {
|
|
|
1655
1668
|
error: result.error,
|
|
1656
1669
|
};
|
|
1657
1670
|
}
|
|
1658
|
-
export async function stopAgentTeamBackgroundRun(runId, reason = "user") {
|
|
1671
|
+
export async function stopAgentTeamBackgroundRun(runId, reason = "user", scope) {
|
|
1659
1672
|
const taskId = taskIdFromBackgroundRunId(runId);
|
|
1660
1673
|
const task = await loadTask(taskId);
|
|
1661
|
-
if (!task)
|
|
1674
|
+
if (!task || !taskMatchesOwnerScope(task, resolveOwnerScope(scope))) {
|
|
1662
1675
|
return { ok: false, error: "Task not found" };
|
|
1676
|
+
}
|
|
1663
1677
|
if (task.status !== "running") {
|
|
1664
1678
|
return { ok: false, error: "Task is not running" };
|
|
1665
1679
|
}
|
|
@@ -1678,6 +1692,26 @@ export async function stopAgentTeamBackgroundRun(runId, reason = "user") {
|
|
|
1678
1692
|
await completeAgentTeamRun(task.taskId, "failed");
|
|
1679
1693
|
return { ok: true };
|
|
1680
1694
|
}
|
|
1695
|
+
function resolveOwnerScope(scope) {
|
|
1696
|
+
if (scope)
|
|
1697
|
+
return scope;
|
|
1698
|
+
const ownerEmail = getRequestUserEmail();
|
|
1699
|
+
if (ownerEmail === undefined)
|
|
1700
|
+
return undefined;
|
|
1701
|
+
return {
|
|
1702
|
+
ownerEmail,
|
|
1703
|
+
// A few non-HTTP test/CLI hosts only provide the user scope. Keep that
|
|
1704
|
+
// owner check active without requiring every lightweight request-context
|
|
1705
|
+
// adapter to implement organization lookup.
|
|
1706
|
+
orgId: typeof getRequestOrgId === "function" ? getRequestOrgId() : undefined,
|
|
1707
|
+
};
|
|
1708
|
+
}
|
|
1709
|
+
function taskMatchesOwnerScope(task, scope) {
|
|
1710
|
+
if (!scope)
|
|
1711
|
+
return true;
|
|
1712
|
+
return ((task.ownerEmail ?? null) === scope.ownerEmail &&
|
|
1713
|
+
(scope.orgId === undefined || (task.orgId ?? null) === scope.orgId));
|
|
1714
|
+
}
|
|
1681
1715
|
/** Mark a task as errored */
|
|
1682
1716
|
export async function markTaskErrored(taskId, error) {
|
|
1683
1717
|
const task = await loadTask(taskId);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type HostedHarnessRuntime } from "../agent/harness/hosted.js";
|
|
2
|
+
import type { AgentNativeHarnessSetting } from "../config.js";
|
|
3
|
+
export interface HostedHarnessPolicy {
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
configEnabled: boolean;
|
|
6
|
+
envEnabled: boolean;
|
|
7
|
+
organizationEnabled: boolean;
|
|
8
|
+
runtimes: HostedHarnessRuntime[];
|
|
9
|
+
}
|
|
10
|
+
export declare function isHostedHarnessEnvEnabled(env?: Record<string, string | undefined>): boolean;
|
|
11
|
+
export declare function loadHostedHarnessConfig(cwd?: string): Promise<AgentNativeHarnessSetting | undefined>;
|
|
12
|
+
export declare function resolveHostedHarnessPolicy(options: {
|
|
13
|
+
config?: AgentNativeHarnessSetting;
|
|
14
|
+
orgId?: string | null;
|
|
15
|
+
userEmail?: string | null;
|
|
16
|
+
}): Promise<HostedHarnessPolicy>;
|
|
17
|
+
export declare function hostedHarnessStatusForClient(policy: HostedHarnessPolicy): HostedHarnessPolicy;
|