@agent-native/core 0.163.3 → 0.164.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/corpus/README.md +1 -1
- package/corpus/templates/analytics/app/hooks/use-dashboard-chat-context.ts +29 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +1 -2
- package/corpus/templates/analytics/netlify.toml +2 -0
- package/corpus/templates/assets/netlify.toml +2 -0
- package/corpus/templates/brain/netlify.toml +2 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +2 -1
- package/corpus/templates/calendar/changelog/2026-08-19-calendar-page-loads-stay-fast-after-idle-periods.md +6 -0
- package/corpus/templates/calendar/netlify.toml +2 -0
- package/corpus/templates/chat/netlify.toml +2 -0
- package/corpus/templates/clips/app/components/player/player-controls.tsx +3 -3
- package/corpus/templates/clips/app/components/player/reaction-emojis.ts +12 -0
- package/corpus/templates/clips/app/components/player/reactions-tray.tsx +90 -9
- package/corpus/templates/clips/app/components/player/scrubber.tsx +43 -10
- package/corpus/templates/clips/app/components/player/video-player.tsx +105 -15
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +1 -2
- package/corpus/templates/clips/app/routes/_index.tsx +10 -2
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +13 -8
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +15 -8
- package/corpus/templates/clips/netlify.toml +2 -0
- package/corpus/templates/clips/server/routes/[...page].head.ts +5 -0
- package/corpus/templates/content/netlify.toml +2 -0
- package/corpus/templates/design/.agents/skills/design-editor-architecture/SKILL.md +103 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +2 -1
- package/corpus/templates/design/AGENTS.md +3 -1
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +3 -2
- package/corpus/templates/design/app/components/design/editor/AgentNativeMenuMark.tsx +25 -0
- package/corpus/templates/design/app/components/design/editor/DesignBottomToolbar.tsx +411 -0
- package/corpus/templates/design/app/components/design/editor/DesignCollaborators.tsx +153 -0
- package/corpus/templates/design/app/components/design/editor/DesignWorkspaceRail.tsx +231 -0
- package/corpus/templates/design/app/components/design/editor/MakeRealDialog.tsx +223 -0
- package/corpus/templates/design/app/components/design/editor/PendingScreenDeletionDialog.tsx +58 -0
- package/corpus/templates/design/app/components/design/editor/PendingVisualStyleWarningDialog.tsx +56 -0
- package/corpus/templates/design/app/components/design/editor/ReadOnlyEditorPanel.tsx +23 -0
- package/corpus/templates/design/app/components/design/editor/SaveTemplateDialog.tsx +161 -0
- package/corpus/templates/design/app/components/design/editor/toolbar-controls.tsx +185 -0
- package/corpus/templates/design/app/pages/DesignEditor.tsx +20913 -0
- package/corpus/templates/design/app/pages/design-editor/command-types.ts +120 -0
- package/corpus/templates/design/app/pages/design-editor/commands/README.md +193 -0
- package/corpus/templates/design/app/pages/design-editor/commands/add-auto-layout.ts +416 -0
- package/corpus/templates/design/app/pages/design-editor/commands/add-screen.ts +112 -0
- package/corpus/templates/design/app/pages/design-editor/commands/align-selection.ts +183 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-design-editor-command.ts +243 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +236 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +304 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-pending-visual-styles-with-agent.ts +376 -0
- package/corpus/templates/design/app/pages/design-editor/commands/apply-to-source.ts +132 -0
- package/corpus/templates/design/app/pages/design-editor/commands/can-move-layer.ts +117 -0
- package/corpus/templates/design/app/pages/design-editor/commands/change-selected-z-index.ts +212 -0
- package/corpus/templates/design/app/pages/design-editor/commands/commit-relative-style-delta-to-selected-layers.ts +176 -0
- package/corpus/templates/design/app/pages/design-editor/commands/commit-styles-to-selected-layers.ts +175 -0
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +710 -0
- package/corpus/templates/design/app/pages/design-editor/commands/confirm-make-real.ts +99 -0
- package/corpus/templates/design/app/pages/design-editor/commands/copy-as-figma-svg.ts +95 -0
- package/corpus/templates/design/app/pages/design-editor/commands/copy-selection.ts +156 -0
- package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +291 -0
- package/corpus/templates/design/app/pages/design-editor/commands/create-screen-frame.ts +131 -0
- package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +577 -0
- package/corpus/templates/design/app/pages/design-editor/commands/delete-files.ts +364 -0
- package/corpus/templates/design/app/pages/design-editor/commands/delete-selection.ts +521 -0
- package/corpus/templates/design/app/pages/design-editor/commands/detach-instance-menu-action.ts +88 -0
- package/corpus/templates/design/app/pages/design-editor/commands/distribute-selection.ts +114 -0
- package/corpus/templates/design/app/pages/design-editor/commands/download-all-screens-pdf.ts +116 -0
- package/corpus/templates/design/app/pages/design-editor/commands/download-pdf.ts +103 -0
- package/corpus/templates/design/app/pages/design-editor/commands/download-svg.ts +159 -0
- package/corpus/templates/design/app/pages/design-editor/commands/duplicate-screen.ts +201 -0
- package/corpus/templates/design/app/pages/design-editor/commands/duplicate-selection.ts +279 -0
- package/corpus/templates/design/app/pages/design-editor/commands/editor-paste.ts +81 -0
- package/corpus/templates/design/app/pages/design-editor/commands/enter-hotkey.ts +155 -0
- package/corpus/templates/design/app/pages/design-editor/commands/enter-single-screen.ts +168 -0
- package/corpus/templates/design/app/pages/design-editor/commands/escape-hotkey.ts +212 -0
- package/corpus/templates/design/app/pages/design-editor/commands/frame-selection.ts +119 -0
- package/corpus/templates/design/app/pages/design-editor/commands/geometry-commit.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/commands/get-selected-layer-snapshots.ts +177 -0
- package/corpus/templates/design/app/pages/design-editor/commands/group-selection.ts +127 -0
- package/corpus/templates/design/app/pages/design-editor/commands/iframe-context-menu.ts +121 -0
- package/corpus/templates/design/app/pages/design-editor/commands/import-figma-clipboard-into-design.ts +119 -0
- package/corpus/templates/design/app/pages/design-editor/commands/layer-marquee-selection-change.ts +163 -0
- package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +331 -0
- package/corpus/templates/design/app/pages/design-editor/commands/layer-move.ts +517 -0
- package/corpus/templates/design/app/pages/design-editor/commands/layer-rename.ts +247 -0
- package/corpus/templates/design/app/pages/design-editor/commands/layer-selection-change.ts +161 -0
- package/corpus/templates/design/app/pages/design-editor/commands/mode-change.ts +122 -0
- package/corpus/templates/design/app/pages/design-editor/commands/nudge-selection.ts +213 -0
- package/corpus/templates/design/app/pages/design-editor/commands/overview-primitive-reparent.ts +318 -0
- package/corpus/templates/design/app/pages/design-editor/commands/paste-copied-screens.ts +114 -0
- package/corpus/templates/design/app/pages/design-editor/commands/paste-over-selection.ts +70 -0
- package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +436 -0
- package/corpus/templates/design/app/pages/design-editor/commands/paste-to-replace.ts +135 -0
- package/corpus/templates/design/app/pages/design-editor/commands/pasted-image-files.ts +209 -0
- package/corpus/templates/design/app/pages/design-editor/commands/persist-frame-geometry-save.ts +113 -0
- package/corpus/templates/design/app/pages/design-editor/commands/persist-tweak-save.ts +160 -0
- package/corpus/templates/design/app/pages/design-editor/commands/primitive-created.ts +168 -0
- package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-layer-state-edit.ts +149 -0
- package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-structure-edit.ts +200 -0
- package/corpus/templates/design/app/pages/design-editor/commands/record-pending-live-text-edit.ts +152 -0
- package/corpus/templates/design/app/pages/design-editor/commands/record-pending-visual-style-edit.ts +247 -0
- package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1086 -0
- package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +200 -0
- package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +207 -0
- package/corpus/templates/design/app/pages/design-editor/commands/screen-element-select.ts +262 -0
- package/corpus/templates/design/app/pages/design-editor/commands/screen-text-content-change.ts +216 -0
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-duplicate-change.ts +108 -0
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-structure-change.ts +280 -0
- package/corpus/templates/design/app/pages/design-editor/commands/screen-visual-style-change.ts +151 -0
- package/corpus/templates/design/app/pages/design-editor/commands/send-overview-annotations.ts +88 -0
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-move-semantic-handoff.ts +122 -0
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-semantic-handoff.ts +143 -0
- package/corpus/templates/design/app/pages/design-editor/commands/send-runtime-layer-state-semantic-handoff.ts +115 -0
- package/corpus/templates/design/app/pages/design-editor/commands/start-retry-generation.ts +152 -0
- package/corpus/templates/design/app/pages/design-editor/commands/start-sidebar-resize.ts +99 -0
- package/corpus/templates/design/app/pages/design-editor/commands/style-change.ts +152 -0
- package/corpus/templates/design/app/pages/design-editor/commands/styles-change.ts +155 -0
- package/corpus/templates/design/app/pages/design-editor/commands/suggest-auto-layout.ts +125 -0
- package/corpus/templates/design/app/pages/design-editor/commands/text-content-change.ts +201 -0
- package/corpus/templates/design/app/pages/design-editor/commands/tidy-up.ts +123 -0
- package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-hidden.ts +167 -0
- package/corpus/templates/design/app/pages/design-editor/commands/toggle-layer-locked.ts +175 -0
- package/corpus/templates/design/app/pages/design-editor/commands/toggle-motion-keyframe.ts +99 -0
- package/corpus/templates/design/app/pages/design-editor/commands/tweak-prompt-submit.ts +84 -0
- package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +906 -0
- package/corpus/templates/design/app/pages/design-editor/commands/ungroup-selection.ts +170 -0
- package/corpus/templates/design/app/pages/design-editor/commands/visual-duplicate-change.ts +119 -0
- package/corpus/templates/design/app/pages/design-editor/commands/visual-structure-change.ts +274 -0
- package/corpus/templates/design/app/pages/design-editor/commands/write-frame-geometry-snapshot.ts +99 -0
- package/corpus/templates/design/app/pages/design-editor/derive/design-breakpoints.ts +56 -0
- package/corpus/templates/design/app/pages/design-editor/derive/overview-screens.ts +146 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-tweaks.ts +326 -0
- package/corpus/templates/design/app/pages/design-editor/editor-constants.ts +54 -0
- package/corpus/templates/design/app/pages/design-editor/editor-helpers.ts +183 -0
- package/corpus/templates/design/app/pages/design-editor/effects/adopt-db-file-content.ts +270 -0
- package/corpus/templates/design/app/pages/design-editor/effects/mirror-selection-to-agent-chat.ts +134 -0
- package/corpus/templates/design/app/pages/design-editor/effects/motion-autosave.ts +335 -0
- package/corpus/templates/design/app/pages/design-editor/effects/observe-collab-text.ts +183 -0
- package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +252 -0
- package/corpus/templates/design/app/pages/design-editor/effects/resume-pending-generation.ts +178 -0
- package/corpus/templates/design/app/pages/design-editor/effects/seed-collab-content.ts +157 -0
- package/corpus/templates/design/app/pages/design-editor/preview-html.ts +19 -0
- package/corpus/templates/design/netlify.toml +2 -0
- package/corpus/templates/design/shared/board-file.ts +2 -1
- package/corpus/templates/dispatch/netlify.toml +2 -0
- package/corpus/templates/forms/netlify.toml +2 -0
- package/corpus/templates/mail/netlify.toml +2 -0
- package/corpus/templates/plan/netlify.toml +2 -0
- package/corpus/templates/slides/netlify.toml +2 -0
- package/dist/agent/engine/builder-engine.d.ts +6 -4
- package/dist/agent/engine/builder-engine.js +91 -26
- package/dist/agent/engine/registry.js +16 -0
- package/dist/cli/code-agent-agent-tools.d.ts +2 -0
- package/dist/cli/code-agent-agent-tools.js +188 -0
- package/dist/cli/code-agent-collaboration.d.ts +34 -0
- package/dist/cli/code-agent-collaboration.js +104 -0
- package/dist/cli/code-agent-executor.js +6 -0
- package/dist/cli/code-agent-schedules.d.ts +54 -0
- package/dist/cli/code-agent-schedules.js +198 -0
- package/dist/client/AgentPanel.js +1 -1
- package/dist/client/ConnectBuilderCard.js +5 -2
- package/dist/client/EnvironmentBadge.js +6 -5
- package/dist/client/chat/run-recovery.js +3 -2
- package/dist/client/chat/tool-call-display.js +2 -3
- package/dist/client/components/CodeRequiredDialog.js +4 -2
- package/dist/client/i18n.js +5 -4
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +6 -1
- package/dist/client/settings/useBuilderStatus.js +22 -33
- package/dist/client/transcription/BuilderTranscriptionCta.js +1 -1
- package/dist/code-agents/index.d.ts +2 -0
- package/dist/code-agents/index.js +2 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/localization/shared.d.ts +2 -0
- package/dist/localization/shared.js +5 -0
- package/dist/mcp-client/oauth-client.d.ts +1 -0
- package/dist/mcp-client/oauth-client.js +50 -1
- package/dist/observability/routes.d.ts +1 -1
- package/dist/provider-api/actions/provider-api.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/auth-marketing-locales.d.ts +7 -0
- package/dist/server/auth-marketing-locales.js +1322 -0
- package/dist/server/auth-marketing.d.ts +1 -0
- package/dist/server/auth-marketing.js +35 -6
- package/dist/server/auth.js +4 -17
- package/dist/server/builder-browser.d.ts +22 -0
- package/dist/server/builder-browser.js +77 -1
- package/dist/server/builder-oauth.d.ts +50 -0
- package/dist/server/builder-oauth.js +263 -0
- package/dist/server/core-routes-plugin.d.ts +11 -0
- package/dist/server/core-routes-plugin.js +291 -415
- package/dist/server/credential-provider.d.ts +1 -1
- package/dist/server/credential-provider.js +1 -1
- package/dist/server/csrf.js +2 -2
- package/dist/server/onboarding-html.js +52 -120
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/settings/store.d.ts +9 -0
- package/dist/settings/store.js +19 -0
- package/dist/templates/chat/netlify.toml +2 -0
- package/dist/vite/client.js +35 -37
- package/docs/content/deployment.mdx +2 -0
- package/docs/content/multi-app-workspace.mdx +1 -1
- package/package.json +2 -2
- package/src/templates/chat/netlify.toml +2 -0
|
@@ -8,10 +8,12 @@
|
|
|
8
8
|
* concurrency) into structured stop events that carry an upgrade URL when
|
|
9
9
|
* the chat UI needs to prompt the user to upgrade.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Interactive users authenticate with Builder OAuth. Existing connections may
|
|
12
|
+
* keep using BUILDER_PRIVATE_KEY + BUILDER_PUBLIC_KEY until they reconnect.
|
|
13
|
+
* When neither is present, credentials come from the gateway lane
|
|
14
|
+
* (`resolveBuilderGatewayCredentials`): the user's own Builder connection,
|
|
15
|
+
* otherwise the deployment's Builder-credits pair. Base URL is overridable
|
|
16
|
+
* via BUILDER_GATEWAY_BASE_URL.
|
|
15
17
|
*/
|
|
16
18
|
import { type BuilderGatewayLane } from "../../server/credential-provider.js";
|
|
17
19
|
import type { AgentEngine, EngineCapabilities } from "./types.js";
|
|
@@ -8,13 +8,17 @@
|
|
|
8
8
|
* concurrency) into structured stop events that carry an upgrade URL when
|
|
9
9
|
* the chat UI needs to prompt the user to upgrade.
|
|
10
10
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* Interactive users authenticate with Builder OAuth. Existing connections may
|
|
12
|
+
* keep using BUILDER_PRIVATE_KEY + BUILDER_PUBLIC_KEY until they reconnect.
|
|
13
|
+
* When neither is present, credentials come from the gateway lane
|
|
14
|
+
* (`resolveBuilderGatewayCredentials`): the user's own Builder connection,
|
|
15
|
+
* otherwise the deployment's Builder-credits pair. Base URL is overridable
|
|
16
|
+
* via BUILDER_GATEWAY_BASE_URL.
|
|
15
17
|
*/
|
|
18
|
+
import { BUILDER_OAUTH_SCOPE, hasBuilderOAuthSession, markBuilderOAuthReconnectRequired, resolveBuilderOAuthRequestAccess, } from "../../server/builder-oauth.js";
|
|
16
19
|
import { captureError } from "../../server/capture-error.js";
|
|
17
20
|
import { clearBuilderGatewayAuthFailure, isBuilderGatewayDeployConfigured, resolveBuilderGatewayCredentialsDetailed, getBuilderGatewayBaseUrl, recordBuilderGatewayAuthFailure, } from "../../server/credential-provider.js";
|
|
21
|
+
import { getRequestUserEmail } from "../../server/request-context.js";
|
|
18
22
|
import { applyBuilderUtmTrackingParams } from "../../shared/builder-link-tracking.js";
|
|
19
23
|
import { isGPTReasoningModel, normalizeReasoningEffortForModel, } from "../../shared/reasoning-effort.js";
|
|
20
24
|
import { isInBackgroundFunctionRuntime } from "../durable-background.js";
|
|
@@ -127,11 +131,35 @@ class BuilderEngine {
|
|
|
127
131
|
async *stream(opts) {
|
|
128
132
|
const creds = this.configuredCredentials ??
|
|
129
133
|
(await resolveBuilderGatewayCredentialsDetailed());
|
|
130
|
-
const
|
|
131
|
-
|
|
134
|
+
const ownerEmail = getRequestUserEmail();
|
|
135
|
+
let oauthAccess = null;
|
|
136
|
+
let hasStoredOAuth = false;
|
|
137
|
+
if (ownerEmail) {
|
|
138
|
+
hasStoredOAuth = await hasBuilderOAuthSession(ownerEmail);
|
|
139
|
+
if (hasStoredOAuth) {
|
|
140
|
+
try {
|
|
141
|
+
oauthAccess = await resolveBuilderOAuthRequestAccess({
|
|
142
|
+
ownerEmail,
|
|
143
|
+
requiredScope: BUILDER_OAUTH_SCOPE,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
// coercion-ok: unusable OAuth custody must not fall back to legacy keys.
|
|
148
|
+
oauthAccess = null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Prefer OAuth when present. If OAuth custody exists but is unusable,
|
|
153
|
+
// do not silently fall back to a legacy private key for the same user.
|
|
154
|
+
const authHeader = oauthAccess
|
|
155
|
+
? `Bearer ${oauthAccess.accessToken}`
|
|
156
|
+
: !hasStoredOAuth && creds.privateKey
|
|
157
|
+
? `Bearer ${creds.privateKey}`
|
|
158
|
+
: null;
|
|
132
159
|
const spaceId = creds.publicKey;
|
|
133
|
-
const builderUserId = creds.userId;
|
|
134
|
-
|
|
160
|
+
const builderUserId = oauthAccess ? undefined : creds.userId;
|
|
161
|
+
const creditsLane = oauthAccess ? false : isBuilderCreditsLane(creds);
|
|
162
|
+
if (!authHeader || (!oauthAccess && !spaceId)) {
|
|
135
163
|
yield gatewayErrorStop({
|
|
136
164
|
error: LLM_MISSING_CREDENTIALS_MESSAGE,
|
|
137
165
|
errorCode: LLM_MISSING_CREDENTIALS_ERROR_CODE,
|
|
@@ -246,7 +274,10 @@ class BuilderEngine {
|
|
|
246
274
|
};
|
|
247
275
|
const gatewayBaseUrl = getBuilderGatewayBaseUrl();
|
|
248
276
|
const gatewayUrl = new URL("messages", gatewayBaseUrl.endsWith("/") ? gatewayBaseUrl : `${gatewayBaseUrl}/`);
|
|
249
|
-
|
|
277
|
+
// OAuth tokens carry Space identity in the JWT `org` claim. Sending a
|
|
278
|
+
// client-supplied apiKey/public key is legacy private-key behavior only.
|
|
279
|
+
if (spaceId && !oauthAccess)
|
|
280
|
+
gatewayUrl.searchParams.set("apiKey", spaceId);
|
|
250
281
|
const orgLabel = creds.orgName || "unknown-org";
|
|
251
282
|
const tStart = Date.now();
|
|
252
283
|
console.log(`[builder-engine] → POST ${gatewayUrl.origin}${gatewayUrl.pathname} model=${model} tools=${tools.length} org=${orgLabel}`);
|
|
@@ -260,7 +291,9 @@ class BuilderEngine {
|
|
|
260
291
|
headers: {
|
|
261
292
|
"Content-Type": "application/json",
|
|
262
293
|
Authorization: authHeader,
|
|
263
|
-
|
|
294
|
+
...(spaceId && !oauthAccess
|
|
295
|
+
? { "x-builder-api-key": spaceId }
|
|
296
|
+
: {}),
|
|
264
297
|
...getBuilderGatewayRequestHeaders(),
|
|
265
298
|
...(builderUserId ? { "x-builder-user-id": builderUserId } : {}),
|
|
266
299
|
},
|
|
@@ -288,25 +321,32 @@ class BuilderEngine {
|
|
|
288
321
|
}
|
|
289
322
|
console.log(`[builder-engine] ← ${response.status} ${response.statusText} in ${Date.now() - tStart}ms`);
|
|
290
323
|
if (!response.ok) {
|
|
291
|
-
yield* emitHttpError(response, {
|
|
324
|
+
yield* emitHttpError(response, {
|
|
325
|
+
creditsLane,
|
|
326
|
+
requestShape,
|
|
327
|
+
recordLegacyCredentialFailure: !oauthAccess,
|
|
328
|
+
});
|
|
292
329
|
return;
|
|
293
330
|
}
|
|
294
331
|
// A successful gateway call proves the connected credentials are valid
|
|
295
332
|
// again. Clear any prior auth-failure marker so status / chat-card
|
|
296
333
|
// surfaces stop flagging the connection as broken. This is the only
|
|
297
334
|
// self-healing path for workspace/env-managed credentials, which never
|
|
298
|
-
// flow through writeBuilderCredentials.
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
335
|
+
// flow through writeBuilderCredentials. OAuth failures are not tracked
|
|
336
|
+
// with the legacy private-key fingerprint marker.
|
|
337
|
+
if (!oauthAccess) {
|
|
338
|
+
try {
|
|
339
|
+
const legacyCreds = this.configuredCredentials ??
|
|
340
|
+
(await resolveBuilderGatewayCredentialsDetailed());
|
|
341
|
+
await clearBuilderGatewayAuthFailure({
|
|
342
|
+
privateKey: legacyCreds.privateKey,
|
|
343
|
+
publicKey: legacyCreds.publicKey,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
// coercion-ok: clearing the legacy auth-failure marker is best-effort;
|
|
348
|
+
// a stale marker only keeps the reconnect CTA until the next success.
|
|
349
|
+
}
|
|
310
350
|
}
|
|
311
351
|
const contentType = response.headers.get("content-type") ?? "";
|
|
312
352
|
if (contentType.includes("text/html")) {
|
|
@@ -341,6 +381,7 @@ class BuilderEngine {
|
|
|
341
381
|
gatewayUrl,
|
|
342
382
|
requestStartedAt: tStart,
|
|
343
383
|
requestShape,
|
|
384
|
+
recordLegacyCredentialFailure: !oauthAccess,
|
|
344
385
|
});
|
|
345
386
|
}
|
|
346
387
|
finally {
|
|
@@ -398,6 +439,19 @@ function gatewayErrorStop(details, creditsLane, requestShape) {
|
|
|
398
439
|
...retry,
|
|
399
440
|
};
|
|
400
441
|
}
|
|
442
|
+
async function recordAuthFailureForCurrentLane(opts) {
|
|
443
|
+
if (opts.recordLegacyCredentialFailure !== false) {
|
|
444
|
+
await recordBuilderGatewayAuthFailure({
|
|
445
|
+
status: opts.status,
|
|
446
|
+
code: opts.code,
|
|
447
|
+
message: opts.message,
|
|
448
|
+
});
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
const ownerEmail = getRequestUserEmail();
|
|
452
|
+
if (ownerEmail)
|
|
453
|
+
await markBuilderOAuthReconnectRequired(ownerEmail);
|
|
454
|
+
}
|
|
401
455
|
async function* emitHttpError(response, opts) {
|
|
402
456
|
const status = response.status;
|
|
403
457
|
// Read the body once as text and then try to parse — calling `.json()`
|
|
@@ -432,7 +486,12 @@ async function* emitHttpError(response, opts) {
|
|
|
432
486
|
return;
|
|
433
487
|
}
|
|
434
488
|
if (status === 401 || code === "unauthorized") {
|
|
435
|
-
await
|
|
489
|
+
await recordAuthFailureForCurrentLane({
|
|
490
|
+
recordLegacyCredentialFailure: opts.recordLegacyCredentialFailure,
|
|
491
|
+
status,
|
|
492
|
+
code,
|
|
493
|
+
message,
|
|
494
|
+
});
|
|
436
495
|
yield stop({
|
|
437
496
|
error: "Builder authentication failed. Reconnect Builder (free tier available) via Settings.",
|
|
438
497
|
errorCode: "builder_auth_error",
|
|
@@ -440,7 +499,12 @@ async function* emitHttpError(response, opts) {
|
|
|
440
499
|
return;
|
|
441
500
|
}
|
|
442
501
|
if (status === 403 && isBuilderCredentialAuthError(message)) {
|
|
443
|
-
await
|
|
502
|
+
await recordAuthFailureForCurrentLane({
|
|
503
|
+
recordLegacyCredentialFailure: opts.recordLegacyCredentialFailure,
|
|
504
|
+
status,
|
|
505
|
+
code,
|
|
506
|
+
message,
|
|
507
|
+
});
|
|
444
508
|
yield stop({
|
|
445
509
|
error: "Builder authentication failed. Reconnect Builder (free tier available) via Settings.",
|
|
446
510
|
errorCode: "builder_auth_error",
|
|
@@ -709,7 +773,8 @@ async function* parseJsonlStream(reader, model, captureContext = {}) {
|
|
|
709
773
|
classifyTerminalErrorCode(String(errMsg))));
|
|
710
774
|
console.error(`[builder-engine] stop reason=error model=${model} code=${errCode ?? "(none)"} requestId=${gatewayRequestId ?? "(none)"} error=${errMsg}`);
|
|
711
775
|
if (isCredentialAuthError) {
|
|
712
|
-
await
|
|
776
|
+
await recordAuthFailureForCurrentLane({
|
|
777
|
+
recordLegacyCredentialFailure: captureContext.recordLegacyCredentialFailure,
|
|
713
778
|
code: typeof gatewayErrCode === "string" ? gatewayErrCode : errCode,
|
|
714
779
|
message: String(errMsg),
|
|
715
780
|
});
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { createRequire } from "node:module";
|
|
11
11
|
import { getAppConfig } from "../../app-config/index.js";
|
|
12
|
+
import { BUILDER_OAUTH_SCOPE, hasBuilderOAuthSession, resolveBuilderOAuthRequestAccess, } from "../../server/builder-oauth.js";
|
|
12
13
|
import { assertCredentialStoreReadable, canUseDeployCredentialFallbackForRequest, getBuilderCredentialAuthFailure, getProviderCredentialAuthFailure, readDeployCredentialEnv, resolveBuilderCredentialsDetailed, resolveBuilderGatewayCredentialsDetailed, resolveSecret, } from "../../server/credential-provider.js";
|
|
14
|
+
import { getRequestUserEmail } from "../../server/request-context.js";
|
|
13
15
|
import { getSetting } from "../../settings/store.js";
|
|
14
16
|
import { getAgentAppModelDefaultForCurrentRequest } from "../app-model-defaults.js";
|
|
15
17
|
import { OLLAMA_BASE_URL_ENV_VAR, OPENAI_BASE_URL_ENV_VAR, } from "./openai-compatible-endpoint.js";
|
|
@@ -556,6 +558,20 @@ async function resolveProviderBaseUrl(envVar) {
|
|
|
556
558
|
* whose org-shared keys exist but were unreadable.
|
|
557
559
|
*/
|
|
558
560
|
async function hasUsableBuilderConnection(identity) {
|
|
561
|
+
const ownerEmail = identity?.userEmail?.trim().toLowerCase() || getRequestUserEmail();
|
|
562
|
+
if (ownerEmail && (await hasBuilderOAuthSession(ownerEmail))) {
|
|
563
|
+
try {
|
|
564
|
+
return Boolean(await resolveBuilderOAuthRequestAccess({
|
|
565
|
+
ownerEmail,
|
|
566
|
+
requiredScope: BUILDER_OAUTH_SCOPE,
|
|
567
|
+
}));
|
|
568
|
+
}
|
|
569
|
+
catch {
|
|
570
|
+
// coercion-ok: custody present but unusable is "not usable", not absent;
|
|
571
|
+
// reconnect UX is owned by /builder/status, not this boolean probe.
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
559
575
|
const creds = await resolveBuilderCredentialsDetailed(identity);
|
|
560
576
|
assertCredentialStoreReadable(creds);
|
|
561
577
|
return Boolean(creds.privateKey && creds.publicKey);
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { createCodeAgentThread, listCodeAgentThreadSummaries, messageCodeAgentThread, } from "./code-agent-collaboration.js";
|
|
2
|
+
import { createCodeAgentSchedule, deleteCodeAgentSchedule, listCodeAgentSchedules, updateCodeAgentSchedule, } from "./code-agent-schedules.js";
|
|
3
|
+
export function createCodeAgentAgentTools(runId, cwd, runTitle) {
|
|
4
|
+
return {
|
|
5
|
+
"manage-schedules": {
|
|
6
|
+
tool: {
|
|
7
|
+
description: "Create and manage durable local desktop schedules. A global schedule starts a new Agent-Native Code thread on every interval. A thread schedule queues a message into an existing thread. Use intervalMinutes for intervals such as 360 for every 6 hours.",
|
|
8
|
+
parameters: {
|
|
9
|
+
type: "object",
|
|
10
|
+
properties: {
|
|
11
|
+
action: {
|
|
12
|
+
type: "string",
|
|
13
|
+
enum: ["create", "list", "update", "delete"],
|
|
14
|
+
description: "The schedule operation.",
|
|
15
|
+
},
|
|
16
|
+
scheduleId: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "Required for update or delete.",
|
|
19
|
+
},
|
|
20
|
+
name: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Human-readable schedule name.",
|
|
23
|
+
},
|
|
24
|
+
prompt: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description: "Instructions sent to the new or existing thread.",
|
|
27
|
+
},
|
|
28
|
+
scope: {
|
|
29
|
+
type: "string",
|
|
30
|
+
enum: ["global", "thread"],
|
|
31
|
+
description: "Whether to start a new thread or message an existing one.",
|
|
32
|
+
},
|
|
33
|
+
targetRunId: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "Existing thread id when scope is thread.",
|
|
36
|
+
},
|
|
37
|
+
intervalMinutes: {
|
|
38
|
+
type: "number",
|
|
39
|
+
description: "Whole minutes between runs, for example 360 is every 6 hours.",
|
|
40
|
+
},
|
|
41
|
+
enabled: {
|
|
42
|
+
type: "boolean",
|
|
43
|
+
description: "Whether the schedule is active.",
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
required: ["action"],
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
run: async (args) => {
|
|
50
|
+
try {
|
|
51
|
+
switch (args.action) {
|
|
52
|
+
case "list":
|
|
53
|
+
return JSON.stringify({
|
|
54
|
+
ok: true,
|
|
55
|
+
schedules: listCodeAgentSchedules(),
|
|
56
|
+
});
|
|
57
|
+
case "create": {
|
|
58
|
+
const schedule = createCodeAgentSchedule({
|
|
59
|
+
name: String(args.name ?? ""),
|
|
60
|
+
prompt: String(args.prompt ?? ""),
|
|
61
|
+
scope: args.scope === "thread" ? "thread" : "global",
|
|
62
|
+
targetRunId: typeof args.targetRunId === "string"
|
|
63
|
+
? args.targetRunId
|
|
64
|
+
: undefined,
|
|
65
|
+
intervalMinutes: Number(args.intervalMinutes),
|
|
66
|
+
enabled: args.enabled !== false,
|
|
67
|
+
createdByRunId: runId,
|
|
68
|
+
});
|
|
69
|
+
return JSON.stringify({ ok: true, schedule });
|
|
70
|
+
}
|
|
71
|
+
case "update": {
|
|
72
|
+
const scheduleId = String(args.scheduleId ?? "").trim();
|
|
73
|
+
if (!scheduleId)
|
|
74
|
+
return "Error: scheduleId is required for update.";
|
|
75
|
+
const schedule = updateCodeAgentSchedule(scheduleId, {
|
|
76
|
+
...(typeof args.name === "string" ? { name: args.name } : {}),
|
|
77
|
+
...(typeof args.prompt === "string"
|
|
78
|
+
? { prompt: args.prompt }
|
|
79
|
+
: {}),
|
|
80
|
+
...(args.scope === "global" || args.scope === "thread"
|
|
81
|
+
? { scope: args.scope }
|
|
82
|
+
: {}),
|
|
83
|
+
...(typeof args.targetRunId === "string"
|
|
84
|
+
? { targetRunId: args.targetRunId }
|
|
85
|
+
: {}),
|
|
86
|
+
...(args.intervalMinutes !== undefined
|
|
87
|
+
? { intervalMinutes: Number(args.intervalMinutes) }
|
|
88
|
+
: {}),
|
|
89
|
+
...(typeof args.enabled === "boolean"
|
|
90
|
+
? { enabled: args.enabled }
|
|
91
|
+
: {}),
|
|
92
|
+
});
|
|
93
|
+
return schedule
|
|
94
|
+
? JSON.stringify({ ok: true, schedule })
|
|
95
|
+
: `Error: schedule not found: ${scheduleId}`;
|
|
96
|
+
}
|
|
97
|
+
case "delete": {
|
|
98
|
+
const scheduleId = String(args.scheduleId ?? "").trim();
|
|
99
|
+
if (!scheduleId)
|
|
100
|
+
return "Error: scheduleId is required for delete.";
|
|
101
|
+
return JSON.stringify({
|
|
102
|
+
ok: deleteCodeAgentSchedule(scheduleId),
|
|
103
|
+
scheduleId,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
return "Error: action must be create, list, update, or delete.";
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
"manage-agent-threads": {
|
|
116
|
+
tool: {
|
|
117
|
+
description: "List threads, create a new Agent-Native Code thread, or queue a message to another thread. Messages are durable and include a source-agent marker in the recipient transcript.",
|
|
118
|
+
parameters: {
|
|
119
|
+
type: "object",
|
|
120
|
+
properties: {
|
|
121
|
+
action: {
|
|
122
|
+
type: "string",
|
|
123
|
+
enum: ["list", "create", "message"],
|
|
124
|
+
description: "The thread operation.",
|
|
125
|
+
},
|
|
126
|
+
query: {
|
|
127
|
+
type: "string",
|
|
128
|
+
description: "Optional title/id filter for list.",
|
|
129
|
+
},
|
|
130
|
+
title: { type: "string", description: "Title for a new thread." },
|
|
131
|
+
prompt: {
|
|
132
|
+
type: "string",
|
|
133
|
+
description: "Initial prompt or message.",
|
|
134
|
+
},
|
|
135
|
+
targetRunId: {
|
|
136
|
+
type: "string",
|
|
137
|
+
description: "Recipient thread id when action is message.",
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
required: ["action"],
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
run: async (args) => {
|
|
144
|
+
try {
|
|
145
|
+
switch (args.action) {
|
|
146
|
+
case "list":
|
|
147
|
+
return JSON.stringify({
|
|
148
|
+
ok: true,
|
|
149
|
+
threads: listCodeAgentThreadSummaries(typeof args.query === "string" ? args.query : undefined),
|
|
150
|
+
});
|
|
151
|
+
case "create": {
|
|
152
|
+
const result = createCodeAgentThread({
|
|
153
|
+
title: typeof args.title === "string" ? args.title : undefined,
|
|
154
|
+
prompt: String(args.prompt ?? ""),
|
|
155
|
+
cwd,
|
|
156
|
+
sourceRunId: runId,
|
|
157
|
+
sourceRunTitle: runTitle,
|
|
158
|
+
});
|
|
159
|
+
return JSON.stringify({
|
|
160
|
+
ok: true,
|
|
161
|
+
thread: result.run,
|
|
162
|
+
event: result.event,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
case "message": {
|
|
166
|
+
const result = messageCodeAgentThread({
|
|
167
|
+
targetRunId: String(args.targetRunId ?? ""),
|
|
168
|
+
prompt: String(args.prompt ?? ""),
|
|
169
|
+
sourceRunId: runId,
|
|
170
|
+
sourceRunTitle: runTitle,
|
|
171
|
+
});
|
|
172
|
+
return JSON.stringify({
|
|
173
|
+
ok: true,
|
|
174
|
+
thread: result.run,
|
|
175
|
+
event: result.event,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
default:
|
|
179
|
+
return "Error: action must be list, create, or message.";
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { type CodeAgentPermissionMode, type CodeAgentRunRecord, type CodeAgentTranscriptEvent } from "./code-agent-runs.js";
|
|
2
|
+
export interface CodeAgentThreadSummary {
|
|
3
|
+
id: string;
|
|
4
|
+
goalId: string;
|
|
5
|
+
title: string;
|
|
6
|
+
status: CodeAgentRunRecord["status"];
|
|
7
|
+
updatedAt: string;
|
|
8
|
+
source?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface CreateCodeAgentThreadInput {
|
|
11
|
+
title?: string;
|
|
12
|
+
prompt: string;
|
|
13
|
+
cwd: string;
|
|
14
|
+
permissionMode?: CodeAgentPermissionMode;
|
|
15
|
+
sourceRunId: string;
|
|
16
|
+
sourceRunTitle?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface CreateCodeAgentThreadResult {
|
|
19
|
+
run: CodeAgentRunRecord;
|
|
20
|
+
event: CodeAgentTranscriptEvent;
|
|
21
|
+
}
|
|
22
|
+
export interface MessageCodeAgentThreadInput {
|
|
23
|
+
targetRunId: string;
|
|
24
|
+
prompt: string;
|
|
25
|
+
sourceRunId: string;
|
|
26
|
+
sourceRunTitle?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface MessageCodeAgentThreadResult {
|
|
29
|
+
run: CodeAgentRunRecord;
|
|
30
|
+
event: CodeAgentTranscriptEvent;
|
|
31
|
+
}
|
|
32
|
+
export declare function listCodeAgentThreadSummaries(query?: string): CodeAgentThreadSummary[];
|
|
33
|
+
export declare function createCodeAgentThread(input: CreateCodeAgentThreadInput): CreateCodeAgentThreadResult;
|
|
34
|
+
export declare function messageCodeAgentThread(input: MessageCodeAgentThreadInput): MessageCodeAgentThreadResult;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { appendCodeAgentTranscriptEvent, createCodeAgentRunRecord, getCodeAgentRunRecord, listCodeAgentRunRecords, queueCodeAgentFollowUp, updateCodeAgentRunRecord, } from "./code-agent-runs.js";
|
|
2
|
+
export function listCodeAgentThreadSummaries(query) {
|
|
3
|
+
const normalizedQuery = query?.trim().toLowerCase();
|
|
4
|
+
return listCodeAgentRunRecords()
|
|
5
|
+
.filter((run) => {
|
|
6
|
+
if (!normalizedQuery)
|
|
7
|
+
return true;
|
|
8
|
+
return `${run.title} ${run.id}`.toLowerCase().includes(normalizedQuery);
|
|
9
|
+
})
|
|
10
|
+
.map((run) => ({
|
|
11
|
+
id: run.id,
|
|
12
|
+
goalId: run.goalId,
|
|
13
|
+
title: run.title,
|
|
14
|
+
status: run.status,
|
|
15
|
+
updatedAt: run.updatedAt,
|
|
16
|
+
source: typeof run.metadata?.source === "string"
|
|
17
|
+
? run.metadata.source
|
|
18
|
+
: undefined,
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
export function createCodeAgentThread(input) {
|
|
22
|
+
const prompt = requiredText(input.prompt, "Thread prompt");
|
|
23
|
+
const title = requiredText(input.title ?? titleFromPrompt(prompt), "Thread title");
|
|
24
|
+
const now = new Date().toISOString();
|
|
25
|
+
const run = createCodeAgentRunRecord({
|
|
26
|
+
goalId: "task",
|
|
27
|
+
title,
|
|
28
|
+
subtitle: "Created by another agent",
|
|
29
|
+
status: "queued",
|
|
30
|
+
phase: "queued",
|
|
31
|
+
permissionMode: input.permissionMode ?? "full-auto",
|
|
32
|
+
cwd: input.cwd,
|
|
33
|
+
metadata: {
|
|
34
|
+
source: "agent",
|
|
35
|
+
sourceRunId: input.sourceRunId,
|
|
36
|
+
...(input.sourceRunTitle ? { sourceRunTitle: input.sourceRunTitle } : {}),
|
|
37
|
+
createdByAgent: true,
|
|
38
|
+
startRequested: true,
|
|
39
|
+
createdAtByAgent: now,
|
|
40
|
+
initialPrompt: prompt,
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
const event = appendCodeAgentTranscriptEvent({
|
|
44
|
+
runId: run.id,
|
|
45
|
+
kind: "user",
|
|
46
|
+
message: prompt,
|
|
47
|
+
metadata: {
|
|
48
|
+
source: "agent",
|
|
49
|
+
sourceRunId: input.sourceRunId,
|
|
50
|
+
...(input.sourceRunTitle ? { sourceRunTitle: input.sourceRunTitle } : {}),
|
|
51
|
+
threadCreated: true,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return { run, event };
|
|
55
|
+
}
|
|
56
|
+
export function messageCodeAgentThread(input) {
|
|
57
|
+
const prompt = requiredText(input.prompt, "Thread message");
|
|
58
|
+
if (!input.targetRunId || input.targetRunId === input.sourceRunId) {
|
|
59
|
+
throw new Error("Choose a different target thread.");
|
|
60
|
+
}
|
|
61
|
+
const target = getCodeAgentRunRecord(input.targetRunId);
|
|
62
|
+
if (!target)
|
|
63
|
+
throw new Error(`Thread not found: ${input.targetRunId}`);
|
|
64
|
+
const event = appendCodeAgentTranscriptEvent({
|
|
65
|
+
runId: target.id,
|
|
66
|
+
kind: "user",
|
|
67
|
+
message: prompt,
|
|
68
|
+
metadata: {
|
|
69
|
+
source: "agent",
|
|
70
|
+
sourceRunId: input.sourceRunId,
|
|
71
|
+
...(input.sourceRunTitle ? { sourceRunTitle: input.sourceRunTitle } : {}),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
const followUp = queueCodeAgentFollowUp({
|
|
75
|
+
runId: target.id,
|
|
76
|
+
prompt,
|
|
77
|
+
mode: "queued",
|
|
78
|
+
eventId: event.id,
|
|
79
|
+
source: "agent",
|
|
80
|
+
});
|
|
81
|
+
if (!followUp)
|
|
82
|
+
throw new Error(`Could not queue a message for ${target.id}`);
|
|
83
|
+
const run = updateCodeAgentRunRecord(target.id, {
|
|
84
|
+
metadata: {
|
|
85
|
+
startRequested: true,
|
|
86
|
+
lastMessageSource: "agent",
|
|
87
|
+
lastMessageSourceRunId: input.sourceRunId,
|
|
88
|
+
},
|
|
89
|
+
}) ?? target;
|
|
90
|
+
return { run, event };
|
|
91
|
+
}
|
|
92
|
+
function requiredText(value, label) {
|
|
93
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
94
|
+
if (!text)
|
|
95
|
+
throw new Error(`${label} is required.`);
|
|
96
|
+
return text.slice(0, 8_000);
|
|
97
|
+
}
|
|
98
|
+
function titleFromPrompt(prompt) {
|
|
99
|
+
const firstLine = prompt.split(/\r?\n/, 1)[0]?.trim() ?? "";
|
|
100
|
+
const normalized = firstLine.replace(/^\/+[a-z0-9-]+\s*/i, "").trim();
|
|
101
|
+
if (!normalized)
|
|
102
|
+
return "Agent-created thread";
|
|
103
|
+
return normalized.length > 72 ? `${normalized.slice(0, 69)}...` : normalized;
|
|
104
|
+
}
|
|
@@ -14,6 +14,7 @@ import { buildMergedConfig, McpClientManager, mcpToolsToActionEntries, } from ".
|
|
|
14
14
|
import { readAgentsBundleFromFs, generateDevelopmentSkillsPromptBlock, } from "../server/agents-bundle.js";
|
|
15
15
|
import { getAmbientOrgId, getAmbientUserEmail, runWithRequestContext, } from "../server/request-context.js";
|
|
16
16
|
import { isReasoningEffort, } from "../shared/reasoning-effort.js";
|
|
17
|
+
import { createCodeAgentAgentTools } from "./code-agent-agent-tools.js";
|
|
17
18
|
import { createAgentNativeConfigContext, loadResolvedAgentNativeConfig, } from "../vite/agent-native-config-loader.js";
|
|
18
19
|
import { runClaudeCodeParticipant, } from "./claude-code-participant.js";
|
|
19
20
|
import { codexMcpConfigArgs, mergeCodeAgentMcpConfig, restrictCodeAgentMcpConfig, } from "./code-agent-mcp-config.js";
|
|
@@ -2201,6 +2202,10 @@ Current run mode: ${mode} mode (${permissionMode}).
|
|
|
2201
2202
|
- In an Agent-Native app or workspace, also run \`pnpm agent-native:doctor\` (or \`pnpm doctor\`) after source changes. Treat every finding as a fix-required security issue; do not disable a guard without a reviewer-readable reason.
|
|
2202
2203
|
- Do not claim a change works, tests pass, or a build succeeds unless you actually ran it and saw the result. If you could not verify something, say exactly what is unverified and why.
|
|
2203
2204
|
|
|
2205
|
+
# Schedules and cooperating threads
|
|
2206
|
+
|
|
2207
|
+
In Auto mode, use \`manage-schedules\` for durable local desktop schedules. A global schedule starts a fresh thread on each interval; a thread schedule queues a message into an existing thread. Use \`intervalMinutes: 360\` for every 6 hours. Use \`manage-agent-threads\` to list threads, create a peer thread, or message another thread. Messages include source-agent metadata so the recipient can link back to the sender.
|
|
2208
|
+
|
|
2204
2209
|
# Tools beyond the basics
|
|
2205
2210
|
|
|
2206
2211
|
- Use \`tool-search\` when you need a capability that may come from MCP, including browser automation or computer control.
|
|
@@ -2278,6 +2283,7 @@ function createLocalCodeAgentActions(cwd, permissionMode, runId, onToolMetadata,
|
|
|
2278
2283
|
read: actions.read,
|
|
2279
2284
|
};
|
|
2280
2285
|
}
|
|
2286
|
+
Object.assign(actions, createCodeAgentAgentTools(runId, cwd));
|
|
2281
2287
|
return actions;
|
|
2282
2288
|
}
|
|
2283
2289
|
function resolveCodeAgentToolProfile(value) {
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
export type CodeAgentScheduleScope = "global" | "thread";
|
|
2
|
+
export type CodeAgentScheduleStatus = "queued" | "completed" | "errored";
|
|
3
|
+
export interface CodeAgentScheduleRecord {
|
|
4
|
+
schemaVersion: 1;
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
prompt: string;
|
|
8
|
+
scope: CodeAgentScheduleScope;
|
|
9
|
+
targetRunId?: string;
|
|
10
|
+
intervalMinutes: number;
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
createdAt: string;
|
|
13
|
+
updatedAt: string;
|
|
14
|
+
nextRunAt: string;
|
|
15
|
+
lastRunAt?: string;
|
|
16
|
+
lastStatus?: CodeAgentScheduleStatus;
|
|
17
|
+
lastError?: string;
|
|
18
|
+
lastTriggeredRunId?: string;
|
|
19
|
+
createdByRunId?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface CreateCodeAgentScheduleInput {
|
|
22
|
+
name: string;
|
|
23
|
+
prompt: string;
|
|
24
|
+
scope?: CodeAgentScheduleScope;
|
|
25
|
+
targetRunId?: string;
|
|
26
|
+
intervalMinutes: number;
|
|
27
|
+
enabled?: boolean;
|
|
28
|
+
createdByRunId?: string;
|
|
29
|
+
now?: Date;
|
|
30
|
+
}
|
|
31
|
+
export interface UpdateCodeAgentScheduleInput {
|
|
32
|
+
name?: string;
|
|
33
|
+
prompt?: string;
|
|
34
|
+
scope?: CodeAgentScheduleScope;
|
|
35
|
+
targetRunId?: string | null;
|
|
36
|
+
intervalMinutes?: number;
|
|
37
|
+
enabled?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface CodeAgentScheduleRunPatch {
|
|
40
|
+
lastRunAt: string;
|
|
41
|
+
lastStatus: CodeAgentScheduleStatus;
|
|
42
|
+
nextRunAt?: string;
|
|
43
|
+
lastError?: string | null;
|
|
44
|
+
lastTriggeredRunId?: string;
|
|
45
|
+
}
|
|
46
|
+
export declare function codeAgentSchedulesPath(): string;
|
|
47
|
+
export declare function listCodeAgentSchedules(): CodeAgentScheduleRecord[];
|
|
48
|
+
export declare function getCodeAgentSchedule(scheduleId: string): CodeAgentScheduleRecord | null;
|
|
49
|
+
export declare function createCodeAgentSchedule(input: CreateCodeAgentScheduleInput): CodeAgentScheduleRecord;
|
|
50
|
+
export declare function updateCodeAgentSchedule(scheduleId: string, input: UpdateCodeAgentScheduleInput): CodeAgentScheduleRecord | null;
|
|
51
|
+
export declare function deleteCodeAgentSchedule(scheduleId: string): boolean;
|
|
52
|
+
export declare function markCodeAgentScheduleRun(scheduleId: string, patch: CodeAgentScheduleRunPatch): CodeAgentScheduleRecord | null;
|
|
53
|
+
export declare function isCodeAgentScheduleDue(schedule: CodeAgentScheduleRecord, now?: Date): boolean;
|
|
54
|
+
export declare function nextCodeAgentScheduleRunAt(schedule: CodeAgentScheduleRecord, now?: Date): string;
|