@superblocksteam/gateway 2.0.165-next.0 → 2.0.166-next.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/agents/resolve-orchestrator-url.d.ts +19 -1
- package/dist/agents/resolve-orchestrator-url.js +71 -20
- package/dist/agents/resolve-orchestrator-url.js.map +1 -1
- package/dist/capabilities/integration-metadata.d.ts +3 -0
- package/dist/capabilities/integration-metadata.js +34 -11
- package/dist/capabilities/integration-metadata.js.map +1 -1
- package/dist/capabilities/lifecycle.d.ts +16 -1
- package/dist/capabilities/lifecycle.js +72 -25
- package/dist/capabilities/lifecycle.js.map +1 -1
- package/dist/capabilities/query-integration.d.ts +5 -0
- package/dist/capabilities/query-integration.js +61 -18
- package/dist/capabilities/query-integration.js.map +1 -1
- package/dist/{transports/mcp → capture}/cowork-editor-url.d.ts +2 -2
- package/dist/capture/cowork-editor-url.js +12 -0
- package/dist/capture/cowork-editor-url.js.map +1 -0
- package/dist/integrations/profile-key.d.ts +50 -6
- package/dist/integrations/profile-key.js +101 -22
- package/dist/integrations/profile-key.js.map +1 -1
- package/dist/integrations/resolve-profile.d.ts +30 -0
- package/dist/integrations/resolve-profile.js +104 -0
- package/dist/integrations/resolve-profile.js.map +1 -0
- package/dist/orchestrator/client.d.ts +1 -1
- package/dist/orchestrator/client.js +1 -1
- package/dist/orchestrator/client.js.map +1 -1
- package/dist/sabs/editor-client-methods.d.ts +7 -2
- package/dist/sabs/editor-client-methods.js +10 -2
- package/dist/sabs/editor-client-methods.js.map +1 -1
- package/dist/sabs/recent-tool-runs.d.ts +1 -1
- package/dist/sabs/recent-tool-runs.js +2 -2
- package/dist/sabs/recent-tool-runs.js.map +1 -1
- package/dist/sabs/websocket-session-peer.d.ts +31 -0
- package/dist/sabs/websocket-session-peer.js +202 -35
- package/dist/sabs/websocket-session-peer.js.map +1 -1
- package/dist/server/client.d.ts +67 -15
- package/dist/server/client.js +403 -51
- package/dist/server/client.js.map +1 -1
- package/dist/telemetry/metrics.d.ts +14 -0
- package/dist/telemetry/metrics.js +25 -0
- package/dist/telemetry/metrics.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/check-app-progress.js +6 -2
- package/dist/transports/mcp/instructions/tools/check-app-progress.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/copy.d.ts +2 -0
- package/dist/transports/mcp/instructions/tools/copy.js +31 -1
- package/dist/transports/mcp/instructions/tools/copy.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/edit-app.js +4 -1
- package/dist/transports/mcp/instructions/tools/edit-app.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.js +3 -0
- package/dist/transports/mcp/instructions/tools/get-integration-metadata.js.map +1 -1
- package/dist/transports/mcp/instructions/tools/start-app.js +4 -1
- package/dist/transports/mcp/instructions/tools/start-app.js.map +1 -1
- package/dist/transports/mcp/mount.d.ts +1 -1
- package/dist/transports/mcp/mount.js +80 -10
- package/dist/transports/mcp/mount.js.map +1 -1
- package/dist/transports/mcp/plan-approval.d.ts +29 -0
- package/dist/transports/mcp/plan-approval.js +72 -18
- package/dist/transports/mcp/plan-approval.js.map +1 -1
- package/package.json +5 -5
- package/dist/transports/mcp/cowork-editor-url.js +0 -10
- package/dist/transports/mcp/cowork-editor-url.js.map +0 -1
|
@@ -19,8 +19,12 @@ export type OrchestratorAgentCandidate = {
|
|
|
19
19
|
export type PickOrchestratorBaseUrlInput = {
|
|
20
20
|
agentType: number;
|
|
21
21
|
agents: OrchestratorAgentCandidate[];
|
|
22
|
-
|
|
22
|
+
controlPlaneUrl?: string;
|
|
23
|
+
profileKey?: string;
|
|
23
24
|
};
|
|
25
|
+
/** Matches `@superblocksteam/shared` `AgentType.ONPREMISE`. */
|
|
26
|
+
export declare const AGENT_TYPE_ONPREMISE = 2;
|
|
27
|
+
export declare function cloudOrchestratorBaseUrlFromControlPlane(url: string | undefined): string | undefined;
|
|
24
28
|
/**
|
|
25
29
|
* Rewrites a Superblocks control-plane `/agent` URL to the dedicated
|
|
26
30
|
* orchestrator host. Leaves on-prem, ephemeral `agent-<host>`, and already
|
|
@@ -32,6 +36,20 @@ export type PickOrchestratorBaseUrlInput = {
|
|
|
32
36
|
* prefix. DEDICATED agents advertise a real URL; do not invent a host.
|
|
33
37
|
*/
|
|
34
38
|
export declare function canonicalizeOrchestratorBaseUrl(url: string, agentType?: number): string;
|
|
39
|
+
/**
|
|
40
|
+
* Whether moving between two profile keys can move the orchestrator URL.
|
|
41
|
+
*
|
|
42
|
+
* Only on-prem inventories tag agents by profile. Cloud resolves to one agent
|
|
43
|
+
* host per control plane. A key changing value there picks the same URL
|
|
44
|
+
* so no need to evict the cache.
|
|
45
|
+
*
|
|
46
|
+
* When agent is undefined, the profile key is changing from unset to a value.
|
|
47
|
+
*/
|
|
48
|
+
export declare function orchestratorUrlDependsOnProfile(input: {
|
|
49
|
+
agentType?: number;
|
|
50
|
+
nextProfileKey?: string;
|
|
51
|
+
previousProfileKey?: string;
|
|
52
|
+
}): boolean;
|
|
35
53
|
/**
|
|
36
54
|
* Returns a single orchestrator base URL from Server-reported agents.
|
|
37
55
|
* Throws when none are eligible — same failure mode as the browser's
|
|
@@ -1,18 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
* Picks an orchestrator (agent) base URL the way the browser does: from the
|
|
3
|
-
* Server's agent inventory for the org, filtered by org agent type, Active
|
|
4
|
-
* status, and profile tags. Operators never set this URL.
|
|
5
|
-
*
|
|
6
|
-
* Cloud editor execute then ignores that inventory URL and posts to
|
|
7
|
-
* SUPERBLOCKS_UI_AGENT_BASE_URL (`https://agent.<env>.superblocks.com/` on
|
|
8
|
-
* SaaS, `https://agent.<zone>/` on cloud-prem). The cloud sentinel still
|
|
9
|
-
* advertises `https://<control-plane>/agent`, and nginx on that path returns
|
|
10
|
-
* 405 for POST /v2/execute and /v3/execute. Canonicalize those known-broken
|
|
11
|
-
* paths so Gateway hits the same host the browser uses.
|
|
12
|
-
*/
|
|
1
|
+
import { isIP } from "node:net";
|
|
13
2
|
const ACTIVE_STATUS = "Active";
|
|
14
3
|
/** Matches `@superblocksteam/shared` `AgentType.MULTITENANT`. */
|
|
15
4
|
const AGENT_TYPE_MULTITENANT = 0;
|
|
5
|
+
/** Matches `@superblocksteam/shared` `AgentType.ONPREMISE`. */
|
|
6
|
+
export const AGENT_TYPE_ONPREMISE = 2;
|
|
16
7
|
/**
|
|
17
8
|
* Control-plane hosts whose `/agent` path is not the orchestrator. US prod is
|
|
18
9
|
* the exception to `agent.<control-plane>` (`app.` → `agent.superblocks.com`).
|
|
@@ -25,6 +16,26 @@ const CLOUD_ORCHESTRATOR_URL_BY_CONTROL_PLANE_HOST = {
|
|
|
25
16
|
"staging.superblocks.com": "https://agent.staging.superblocks.com/",
|
|
26
17
|
"dev.superblocks.com": "https://agent.dev.superblocks.com/",
|
|
27
18
|
};
|
|
19
|
+
export function cloudOrchestratorBaseUrlFromControlPlane(url) {
|
|
20
|
+
if (!url) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = new URL(url);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
if (parsed.protocol !== "https:" ||
|
|
31
|
+
parsed.port ||
|
|
32
|
+
parsed.hostname === "localhost" ||
|
|
33
|
+
parsed.hostname.endsWith(".localhost") ||
|
|
34
|
+
isIP(parsed.hostname) !== 0) {
|
|
35
|
+
return undefined;
|
|
36
|
+
}
|
|
37
|
+
return CLOUD_ORCHESTRATOR_URL_BY_CONTROL_PLANE_HOST[parsed.hostname];
|
|
38
|
+
}
|
|
28
39
|
function matchesProfile(tags, profileKey) {
|
|
29
40
|
const profiles = tags.profile;
|
|
30
41
|
if (!profiles || profiles.length === 0) {
|
|
@@ -33,6 +44,10 @@ function matchesProfile(tags, profileKey) {
|
|
|
33
44
|
}
|
|
34
45
|
return profiles.includes("*") || profiles.includes(profileKey);
|
|
35
46
|
}
|
|
47
|
+
function isUniversalProfile(tags) {
|
|
48
|
+
const profiles = tags.profile;
|
|
49
|
+
return !profiles || profiles.length === 0 || profiles.includes("*");
|
|
50
|
+
}
|
|
36
51
|
function withTrailingSlash(url) {
|
|
37
52
|
return url.endsWith("/") ? url : `${url}/`;
|
|
38
53
|
}
|
|
@@ -44,6 +59,14 @@ function withTrailingSlash(url) {
|
|
|
44
59
|
function isAgentPath(pathname) {
|
|
45
60
|
return pathname === "/agent" || pathname === "/agent/";
|
|
46
61
|
}
|
|
62
|
+
function hasAgentPath(url) {
|
|
63
|
+
try {
|
|
64
|
+
return isAgentPath(new URL(url).pathname);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
47
70
|
function isAlreadyDedicatedAgentHost(hostname) {
|
|
48
71
|
return hostname === "agent" || hostname.startsWith("agent.");
|
|
49
72
|
}
|
|
@@ -78,23 +101,51 @@ export function canonicalizeOrchestratorBaseUrl(url, agentType) {
|
|
|
78
101
|
}
|
|
79
102
|
return url;
|
|
80
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Whether moving between two profile keys can move the orchestrator URL.
|
|
106
|
+
*
|
|
107
|
+
* Only on-prem inventories tag agents by profile. Cloud resolves to one agent
|
|
108
|
+
* host per control plane. A key changing value there picks the same URL
|
|
109
|
+
* so no need to evict the cache.
|
|
110
|
+
*
|
|
111
|
+
* When agent is undefined, the profile key is changing from unset to a value.
|
|
112
|
+
*/
|
|
113
|
+
export function orchestratorUrlDependsOnProfile(input) {
|
|
114
|
+
if (input.agentType === undefined ||
|
|
115
|
+
input.agentType === AGENT_TYPE_ONPREMISE) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
return Boolean(input.previousProfileKey) !== Boolean(input.nextProfileKey);
|
|
119
|
+
}
|
|
81
120
|
/**
|
|
82
121
|
* Returns a single orchestrator base URL from Server-reported agents.
|
|
83
122
|
* Throws when none are eligible — same failure mode as the browser's
|
|
84
123
|
* "No active agent found".
|
|
85
124
|
*/
|
|
86
125
|
export function pickOrchestratorBaseUrl(input) {
|
|
87
|
-
const
|
|
126
|
+
const active = input.agents.filter((candidate) => candidate.type === input.agentType &&
|
|
88
127
|
candidate.status === ACTIVE_STATUS &&
|
|
89
|
-
Boolean(candidate.url)
|
|
90
|
-
|
|
91
|
-
if (
|
|
92
|
-
|
|
128
|
+
Boolean(candidate.url));
|
|
129
|
+
let chosen;
|
|
130
|
+
if (input.agentType !== AGENT_TYPE_ONPREMISE) {
|
|
131
|
+
const mapped = cloudOrchestratorBaseUrlFromControlPlane(input.controlPlaneUrl);
|
|
132
|
+
if (mapped) {
|
|
133
|
+
return mapped;
|
|
134
|
+
}
|
|
135
|
+
chosen = active.find((candidate) => hasAgentPath(candidate.url));
|
|
136
|
+
}
|
|
137
|
+
else if (input.profileKey) {
|
|
138
|
+
const profileKey = input.profileKey;
|
|
139
|
+
chosen = active.find((candidate) => matchesProfile(candidate.tags ?? {}, profileKey));
|
|
140
|
+
}
|
|
141
|
+
if (!chosen && !input.profileKey) {
|
|
142
|
+
chosen = active.find((candidate) => isUniversalProfile(candidate.tags ?? {}));
|
|
143
|
+
}
|
|
144
|
+
if (input.agentType !== AGENT_TYPE_ONPREMISE) {
|
|
145
|
+
chosen ??= active[0];
|
|
93
146
|
}
|
|
94
|
-
// Browser picks randomly among matches; stable first is fine for gateway.
|
|
95
|
-
const chosen = eligible[0];
|
|
96
147
|
if (!chosen) {
|
|
97
|
-
throw new Error(`No active agent found for agentType=${input.agentType} profile=${input.profileKey}`);
|
|
148
|
+
throw new Error(`No active agent found for agentType=${input.agentType} profile=${input.profileKey ?? "<unset>"}`);
|
|
98
149
|
}
|
|
99
150
|
return withTrailingSlash(canonicalizeOrchestratorBaseUrl(chosen.url, input.agentType));
|
|
100
151
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-orchestrator-url.js","sourceRoot":"","sources":["../../src/agents/resolve-orchestrator-url.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"resolve-orchestrator-url.js","sourceRoot":"","sources":["../../src/agents/resolve-orchestrator-url.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ResolvedProfileSummary } from "../integrations/resolve-profile.js";
|
|
1
2
|
import { type CapabilityContext } from "./lifecycle.js";
|
|
2
3
|
import type { CapabilityResult } from "./types.js";
|
|
3
4
|
export type GetIntegrationMetadataInput = {
|
|
@@ -21,6 +22,8 @@ export type GetIntegrationMetadataResult = {
|
|
|
21
22
|
nextOffset: number | null;
|
|
22
23
|
offset: number;
|
|
23
24
|
pluginId: string;
|
|
25
|
+
/** Which profile's data this is, so a later change of profile is explainable. */
|
|
26
|
+
profile: ResolvedProfileSummary;
|
|
24
27
|
returnedCount: number;
|
|
25
28
|
totalCount: number;
|
|
26
29
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { pickOrchestratorBaseUrl } from "../agents/resolve-orchestrator-url.js";
|
|
1
|
+
import { AGENT_TYPE_ONPREMISE, pickOrchestratorBaseUrl, } from "../agents/resolve-orchestrator-url.js";
|
|
2
2
|
import { integrationIsToolSupported } from "../integrations/filters.js";
|
|
3
3
|
import { hasBuildPermission } from "../integrations/map.js";
|
|
4
|
-
import {
|
|
4
|
+
import { describeProfile, profileSummary, profileUnresolvedMessage, resolveProfileForApplication, } from "../integrations/resolve-profile.js";
|
|
5
5
|
import { HttpOrchestratorClient } from "../orchestrator/client.js";
|
|
6
6
|
import { sanitizeAgentFacingText, sanitizeAgentFacingValue, } from "../sabs/agent-facing-text.js";
|
|
7
7
|
import { ensurePrincipal, resolveApplicationId, } from "./lifecycle.js";
|
|
@@ -59,6 +59,7 @@ export async function getIntegrationMetadata(context, input) {
|
|
|
59
59
|
return principal;
|
|
60
60
|
}
|
|
61
61
|
let applicationId;
|
|
62
|
+
let profileResolution;
|
|
62
63
|
// Named for the agent before the integration resolves, so a failure on the
|
|
63
64
|
// way to the metadata still reports which integration it was reaching for.
|
|
64
65
|
let label = sanitizeAgentFacingText(input.integrationId);
|
|
@@ -105,20 +106,41 @@ export async function getIntegrationMetadata(context, input) {
|
|
|
105
106
|
message: `${integrationName} is a ${pluginId} integration, which this tool cannot inspect.`,
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
+
({ resolution: profileResolution } = await resolveProfileForApplication({
|
|
109
110
|
apiKey: principal.value.apiKey,
|
|
111
|
+
applicationId,
|
|
112
|
+
configuredKey: context.config.profileKey,
|
|
110
113
|
organizationId: principal.value.organizationId,
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
scope: "integration_metadata",
|
|
115
|
+
server: context.server,
|
|
116
|
+
}));
|
|
117
|
+
const profileKey = profileResolution.key;
|
|
113
118
|
const inventory = await context.server.getAgentInventory({
|
|
114
119
|
apiKey: principal.value.apiKey,
|
|
115
120
|
organizationId: principal.value.organizationId,
|
|
116
121
|
});
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
+
let orchestratorUrl;
|
|
123
|
+
try {
|
|
124
|
+
orchestratorUrl = pickOrchestratorBaseUrl({
|
|
125
|
+
agentType: inventory.agentType,
|
|
126
|
+
agents: inventory.agents,
|
|
127
|
+
controlPlaneUrl: inventory.controlPlaneUrl,
|
|
128
|
+
profileKey,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
// Only on-prem agents are picked by profile tag, so only there does a
|
|
133
|
+
// missing profile explain a missing agent.
|
|
134
|
+
if (profileKey || inventory.agentType !== AGENT_TYPE_ONPREMISE) {
|
|
135
|
+
throw error;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
...(applicationId && { applicationId }),
|
|
139
|
+
kind: "error",
|
|
140
|
+
code: "integration_profile_unresolved",
|
|
141
|
+
message: profileUnresolvedMessage(integrationName, profileResolution),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
122
144
|
const scopedToken = await context.server.issueScopedToken(applicationId
|
|
123
145
|
? {
|
|
124
146
|
apiKey: principal.value.apiKey,
|
|
@@ -156,6 +178,7 @@ export async function getIntegrationMetadata(context, input) {
|
|
|
156
178
|
nextOffset,
|
|
157
179
|
offset,
|
|
158
180
|
pluginId,
|
|
181
|
+
profile: profileSummary(profileResolution),
|
|
159
182
|
returnedCount: entries.length,
|
|
160
183
|
totalCount: matched.length,
|
|
161
184
|
},
|
|
@@ -167,7 +190,7 @@ export async function getIntegrationMetadata(context, input) {
|
|
|
167
190
|
...(applicationId && { applicationId }),
|
|
168
191
|
kind: "error",
|
|
169
192
|
code: "integration_metadata_unavailable",
|
|
170
|
-
message: `Could not load metadata for ${label}: ${detail}`,
|
|
193
|
+
message: `Could not load metadata for ${label}${profileResolution ? ` (${describeProfile(profileResolution)})` : ""}: ${detail}`,
|
|
171
194
|
};
|
|
172
195
|
}
|
|
173
196
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"integration-metadata.js","sourceRoot":"","sources":["../../src/capabilities/integration-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"integration-metadata.js","sourceRoot":"","sources":["../../src/capabilities/integration-metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -60,10 +60,25 @@ export declare function resolveApplicationId(ctx: CapabilityContext, principal:
|
|
|
60
60
|
options?: {
|
|
61
61
|
unambiguous?: boolean;
|
|
62
62
|
}): Promise<CapabilityResult<string>>;
|
|
63
|
+
/**
|
|
64
|
+
* Settles a user's plan approval against what became of the prompt it
|
|
65
|
+
* approved.
|
|
66
|
+
*
|
|
67
|
+
* The approval is claimed before the prompt goes out and spent only once
|
|
68
|
+
* Superblocks accepts it. A prompt that never went out hands the approval
|
|
69
|
+
* back, so the retry builds the plan the user already approved instead of
|
|
70
|
+
* failing with `approval_not_from_user`. A prompt that may have reached
|
|
71
|
+
* Superblocks settles neither way: handing the approval back could build the
|
|
72
|
+
* plan twice.
|
|
73
|
+
*/
|
|
74
|
+
export type ApprovalSettlement = {
|
|
75
|
+
onAccepted(): void;
|
|
76
|
+
onNotSent(): void;
|
|
77
|
+
};
|
|
63
78
|
export declare function startApp(ctx: CapabilityContext, input: StartAppInput): Promise<CapabilityResult<StartAppResult>>;
|
|
64
79
|
export declare function uploadArtifact(ctx: CapabilityContext, input: UploadArtifactInput): Promise<CapabilityResult<UploadArtifactResult>>;
|
|
65
80
|
export declare function checkAppProgress(ctx: CapabilityContext, input: CheckAppProgressInput): Promise<CapabilityResult<CheckAppProgressResult>>;
|
|
66
|
-
export declare function editApp(ctx: CapabilityContext, input: EditAppInput, approvedPlan?: object): Promise<CapabilityResult<EditAppResult>>;
|
|
81
|
+
export declare function editApp(ctx: CapabilityContext, input: EditAppInput, approvedPlan?: object, approvalSettlement?: ApprovalSettlement): Promise<CapabilityResult<EditAppResult>>;
|
|
67
82
|
/**
|
|
68
83
|
* Shows the app's current work on a real URL without deploying it - the
|
|
69
84
|
* editor's Preview button, driven from here.
|
|
@@ -2,7 +2,8 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { readFile, realpath, stat } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { detectAttachmentArchiveType, getAttachmentMimeTypeFromFileName, getTextAttachmentType, isSupportedAttachmentUploadType, } from "@superblocksteam/shared";
|
|
5
|
-
import { buildBrowserDriverContract, needsBrowserDriverError, } from "../capture/browser-contract.js";
|
|
5
|
+
import { buildBrowserDriverContract, HOST_BROWSER_TOOLS_COWORK, needsBrowserDriverError, } from "../capture/browser-contract.js";
|
|
6
|
+
import { withCoworkEditorHost } from "../capture/cowork-editor-url.js";
|
|
6
7
|
import { resolveCaptureMode } from "../capture/mode.js";
|
|
7
8
|
import { gatewayDebug } from "../debug.js";
|
|
8
9
|
import { playwrightChromiumPresent } from "../playwright/ensure-chromium.js";
|
|
@@ -30,18 +31,25 @@ const RECENT_APP_FALLBACK_WINDOW_MS = 30 * 60 * 1000;
|
|
|
30
31
|
* the UI serves from `/code-mode` — the legacy `/applications/:id/edit` route
|
|
31
32
|
* does not open it.
|
|
32
33
|
*/
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
function editorBaseUrl(config, applicationId) {
|
|
35
|
+
return `${config.uiBaseUrl.replace(/\/$/, "")}/code-mode/applications/edit/${applicationId}`;
|
|
36
|
+
}
|
|
37
|
+
/** The editor URL handed to the caller, in the host mode its client renders. */
|
|
38
|
+
function editUrl(ctx, applicationId, branch) {
|
|
39
|
+
const base = editorBaseUrl(ctx.config, applicationId);
|
|
40
|
+
const url = branch
|
|
36
41
|
? `${base}?${new URLSearchParams({ branch }).toString()}`
|
|
37
42
|
: base;
|
|
43
|
+
return ctx.hostBrowserTools === HOST_BROWSER_TOOLS_COWORK
|
|
44
|
+
? withCoworkEditorHost(url)
|
|
45
|
+
: url;
|
|
38
46
|
}
|
|
39
47
|
function fullscreenPreviewUrl(config, applicationId, branch) {
|
|
40
48
|
const params = new URLSearchParams({ fullscreen: "true" });
|
|
41
49
|
if (branch) {
|
|
42
50
|
params.set("branch", branch);
|
|
43
51
|
}
|
|
44
|
-
return `${
|
|
52
|
+
return `${editorBaseUrl(config, applicationId)}?${params.toString()}`;
|
|
45
53
|
}
|
|
46
54
|
function uiOrigin(config) {
|
|
47
55
|
return config.uiBaseUrl.replace(/\/$/, "");
|
|
@@ -237,7 +245,7 @@ function publishUrl(config, applicationId) {
|
|
|
237
245
|
return `${config.uiBaseUrl.replace(/\/$/, "")}/code-mode/applications/${applicationId}`;
|
|
238
246
|
}
|
|
239
247
|
function publishDetailsUrl(config, applicationId, commitId) {
|
|
240
|
-
return `${
|
|
248
|
+
return `${editorBaseUrl(config, applicationId)}?${new URLSearchParams({ commitId }).toString()}`;
|
|
241
249
|
}
|
|
242
250
|
/**
|
|
243
251
|
* Where a built, undeployed commit can be opened — what the editor's Preview
|
|
@@ -380,7 +388,7 @@ async function elicitStepUp(ctx, idempotencyKey, applicationId, branch) {
|
|
|
380
388
|
message: "Step-up authentication completed. Re-invoke the capability to continue.",
|
|
381
389
|
};
|
|
382
390
|
}
|
|
383
|
-
const browser = await browserContractFor(ctx, editUrl(ctx
|
|
391
|
+
const browser = await browserContractFor(ctx, editUrl(ctx, applicationId, branch));
|
|
384
392
|
if (existing?.status === "pending") {
|
|
385
393
|
return {
|
|
386
394
|
kind: "auth_required",
|
|
@@ -838,7 +846,7 @@ async function forwardClarkPrompt(ctx, input) {
|
|
|
838
846
|
return {
|
|
839
847
|
kind: "error",
|
|
840
848
|
code: "superblocks_turn_timeout",
|
|
841
|
-
message: `Superblocks reported that the turn timed out.${forward.reply ? ` Partial reply: ${forward.reply.slice(0, 500)}` : ""} Continue in the editor at ${editUrl(ctx
|
|
849
|
+
message: `Superblocks reported that the turn timed out.${forward.reply ? ` Partial reply: ${forward.reply.slice(0, 500)}` : ""} Continue in the editor at ${editUrl(ctx, input.applicationId, input.branch)}.`,
|
|
842
850
|
pendingAction: "retry_build",
|
|
843
851
|
};
|
|
844
852
|
}
|
|
@@ -1170,7 +1178,7 @@ async function promptNewApplication(ctx, args) {
|
|
|
1170
1178
|
activity: started.value.activity,
|
|
1171
1179
|
applicationId,
|
|
1172
1180
|
...(branch ? { branch } : {}),
|
|
1173
|
-
editUrl: editUrl(ctx
|
|
1181
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
1174
1182
|
liveEditId: started.value.liveEditId ?? session.liveEditId,
|
|
1175
1183
|
mode: promptArgs.mode,
|
|
1176
1184
|
name: await named(),
|
|
@@ -1196,7 +1204,7 @@ async function promptNewApplication(ctx, args) {
|
|
|
1196
1204
|
: {}),
|
|
1197
1205
|
reply: forward.value.reply,
|
|
1198
1206
|
...(forward.value.decision ? { decision: forward.value.decision } : {}),
|
|
1199
|
-
editUrl: editUrl(ctx
|
|
1207
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
1200
1208
|
generationStatus: forward.value.generationStatus,
|
|
1201
1209
|
liveEditId: forward.value.liveEditId ?? session.liveEditId,
|
|
1202
1210
|
mode: promptArgs.mode,
|
|
@@ -1216,6 +1224,13 @@ async function promptNewApplication(ctx, args) {
|
|
|
1216
1224
|
});
|
|
1217
1225
|
return { kind: "ok", value: await withBrowser(ctx, result) };
|
|
1218
1226
|
}
|
|
1227
|
+
/** Whether a result is {@link elicitStepUp} turning the prompt back. */
|
|
1228
|
+
function isStepUp(result) {
|
|
1229
|
+
return (result.kind === "auth_required" ||
|
|
1230
|
+
(result.kind === "error" &&
|
|
1231
|
+
(result.code === "needs_browser_driver" ||
|
|
1232
|
+
result.code === "reinvoke_required")));
|
|
1233
|
+
}
|
|
1219
1234
|
async function runAcknowledgedStart(ctx, args) {
|
|
1220
1235
|
const scope = {
|
|
1221
1236
|
applicationId: args.applicationId,
|
|
@@ -1241,23 +1256,33 @@ async function runAcknowledgedStart(ctx, args) {
|
|
|
1241
1256
|
});
|
|
1242
1257
|
try {
|
|
1243
1258
|
const result = await args.start();
|
|
1259
|
+
if (result.kind === "ok") {
|
|
1260
|
+
args.approvalSettlement?.onAccepted();
|
|
1261
|
+
}
|
|
1262
|
+
else {
|
|
1263
|
+
// An acknowledged start sends from here and nowhere else, and a send
|
|
1264
|
+
// that fails throws instead, so any other answer came back before the
|
|
1265
|
+
// prompt went out.
|
|
1266
|
+
args.approvalSettlement?.onNotSent();
|
|
1267
|
+
}
|
|
1244
1268
|
if (result.kind === "error" && result.code === "reinvoke_required") {
|
|
1245
1269
|
failed(new Error(result.message), `Authentication completed before Superblocks accepted the prompt for application ${args.applicationId}. Call edit_app with that applicationId and the same prompt to continue.`, "live_edit_terminated", "retry_build");
|
|
1246
1270
|
}
|
|
1247
1271
|
else if (result.kind === "auth_required" ||
|
|
1248
1272
|
(result.kind === "error" && result.code === "needs_browser_driver")) {
|
|
1249
|
-
failed(new Error("authentication required"), `Authentication is required before the prompt can continue. Open ${editUrl(ctx
|
|
1273
|
+
failed(new Error("authentication required"), `Authentication is required before the prompt can continue. Open ${editUrl(ctx, args.applicationId, args.branch)} and authenticate, then call edit_app with that applicationId and the same prompt.`, "live_edit_terminated", "retry_build");
|
|
1250
1274
|
}
|
|
1251
1275
|
}
|
|
1252
1276
|
catch (error) {
|
|
1253
1277
|
if (error instanceof PromptNotSentError) {
|
|
1278
|
+
args.approvalSettlement?.onNotSent();
|
|
1254
1279
|
const retryable = error.retryable !== false;
|
|
1255
1280
|
failed(error, retryable
|
|
1256
1281
|
? `The prompt was not sent, so nothing was built. Call edit_app for application ${args.applicationId} with the same instruction to retry. (${error.message})`
|
|
1257
1282
|
: `The replacement live-edit session also stopped responding, so Gateway cannot safely retry this build. Start a new application instead. (${error.message})`, "live_edit_terminated", retryable ? "retry_build" : undefined, error.retryable, error.recoveryAction);
|
|
1258
1283
|
}
|
|
1259
1284
|
else {
|
|
1260
|
-
failed(error, `The prompt acknowledgement was lost and the prompt may have reached Superblocks. Do not resend it; open ${editUrl(ctx
|
|
1285
|
+
failed(error, `The prompt acknowledgement was lost and the prompt may have reached Superblocks. Do not resend it; open ${editUrl(ctx, args.applicationId, args.branch)} to check the existing application. (${error instanceof Error ? error.message : String(error)})`, "detached");
|
|
1261
1286
|
}
|
|
1262
1287
|
}
|
|
1263
1288
|
finally {
|
|
@@ -1355,7 +1380,7 @@ export async function startApp(ctx, input) {
|
|
|
1355
1380
|
value: await withBrowser(ctx, {
|
|
1356
1381
|
applicationId: app.id,
|
|
1357
1382
|
...(branch ? { branch } : {}),
|
|
1358
|
-
editUrl: editUrl(ctx
|
|
1383
|
+
editUrl: editUrl(ctx, app.id, branch),
|
|
1359
1384
|
mode: input.mode ?? "PLAN",
|
|
1360
1385
|
name,
|
|
1361
1386
|
status: "building",
|
|
@@ -1892,7 +1917,7 @@ export async function checkAppProgress(ctx, input) {
|
|
|
1892
1917
|
activity,
|
|
1893
1918
|
applicationId,
|
|
1894
1919
|
...(branch ? { branch } : {}),
|
|
1895
|
-
editUrl: editUrl(ctx
|
|
1920
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
1896
1921
|
elapsedSeconds,
|
|
1897
1922
|
...(update.viewStatus ? { viewStatus: update.viewStatus } : {}),
|
|
1898
1923
|
...("recentRuns" in update &&
|
|
@@ -2024,7 +2049,7 @@ async function recordTurnSignals(ctx, input) {
|
|
|
2024
2049
|
}
|
|
2025
2050
|
return stallHint ? { stallHint } : {};
|
|
2026
2051
|
}
|
|
2027
|
-
export async function editApp(ctx, input, approvedPlan) {
|
|
2052
|
+
export async function editApp(ctx, input, approvedPlan, approvalSettlement) {
|
|
2028
2053
|
const principalResult = await ensurePrincipal(ctx);
|
|
2029
2054
|
if (principalResult.kind !== "ok") {
|
|
2030
2055
|
return principalResult;
|
|
@@ -2038,6 +2063,7 @@ export async function editApp(ctx, input, approvedPlan) {
|
|
|
2038
2063
|
return namingApplication(applicationId, await promptExistingApplication(ctx, {
|
|
2039
2064
|
applicationId,
|
|
2040
2065
|
approvedPlan,
|
|
2066
|
+
...(approvalSettlement ? { approvalSettlement } : {}),
|
|
2041
2067
|
input,
|
|
2042
2068
|
principal,
|
|
2043
2069
|
}));
|
|
@@ -2104,14 +2130,18 @@ async function promptExistingApplication(ctx, args) {
|
|
|
2104
2130
|
userId: principal.userId,
|
|
2105
2131
|
});
|
|
2106
2132
|
const { signal: _requestSignal, ...backgroundContext } = ctx;
|
|
2133
|
+
// Settled by the background start alone, which is the only part that
|
|
2134
|
+
// learns whether the prompt went out.
|
|
2135
|
+
const { approvalSettlement, ...startArgs } = args;
|
|
2107
2136
|
void runAcknowledgedStart(backgroundContext, {
|
|
2108
2137
|
applicationId,
|
|
2138
|
+
...(approvalSettlement ? { approvalSettlement } : {}),
|
|
2109
2139
|
branch,
|
|
2110
2140
|
idempotencyKey: input.idempotencyKey,
|
|
2111
2141
|
pendingStartToken,
|
|
2112
2142
|
principal,
|
|
2113
2143
|
start: () => promptExistingApplication(backgroundContext, {
|
|
2114
|
-
...
|
|
2144
|
+
...startArgs,
|
|
2115
2145
|
...(approvingUncapturedPlan ? { approvingUncapturedPlan } : {}),
|
|
2116
2146
|
input: { ...input, ...(branch ? { branch } : {}) },
|
|
2117
2147
|
pendingStartToken,
|
|
@@ -2126,7 +2156,7 @@ async function promptExistingApplication(ctx, args) {
|
|
|
2126
2156
|
value: await withBrowser(ctx, {
|
|
2127
2157
|
applicationId,
|
|
2128
2158
|
...(branch ? { branch } : {}),
|
|
2129
|
-
editUrl: editUrl(ctx
|
|
2159
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
2130
2160
|
mode,
|
|
2131
2161
|
status: "building",
|
|
2132
2162
|
}),
|
|
@@ -2310,13 +2340,30 @@ async function promptExistingApplication(ctx, args) {
|
|
|
2310
2340
|
activity: started.value.activity,
|
|
2311
2341
|
applicationId,
|
|
2312
2342
|
...(branch ? { branch } : {}),
|
|
2313
|
-
editUrl: editUrl(ctx
|
|
2343
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
2314
2344
|
mode: promptArgs.mode,
|
|
2315
2345
|
status: "building",
|
|
2316
2346
|
}),
|
|
2317
2347
|
};
|
|
2318
2348
|
}
|
|
2319
|
-
|
|
2349
|
+
let forward;
|
|
2350
|
+
try {
|
|
2351
|
+
forward = await forwardClarkPrompt(ctx, promptArgs);
|
|
2352
|
+
}
|
|
2353
|
+
catch (error) {
|
|
2354
|
+
if (error instanceof PromptNotSentError) {
|
|
2355
|
+
args.approvalSettlement?.onNotSent();
|
|
2356
|
+
}
|
|
2357
|
+
throw error;
|
|
2358
|
+
}
|
|
2359
|
+
// A blocking forward returns only once Superblocks took the prompt and ran
|
|
2360
|
+
// the turn, so any answer but a step-up means the approval was used.
|
|
2361
|
+
if (isStepUp(forward)) {
|
|
2362
|
+
args.approvalSettlement?.onNotSent();
|
|
2363
|
+
}
|
|
2364
|
+
else {
|
|
2365
|
+
args.approvalSettlement?.onAccepted();
|
|
2366
|
+
}
|
|
2320
2367
|
if (forward.kind !== "ok") {
|
|
2321
2368
|
return forward;
|
|
2322
2369
|
}
|
|
@@ -2335,7 +2382,7 @@ async function promptExistingApplication(ctx, args) {
|
|
|
2335
2382
|
: {}),
|
|
2336
2383
|
reply: forward.value.reply,
|
|
2337
2384
|
...(forward.value.decision ? { decision: forward.value.decision } : {}),
|
|
2338
|
-
editUrl: editUrl(ctx
|
|
2385
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
2339
2386
|
generationStatus: forward.value.generationStatus,
|
|
2340
2387
|
mode: promptArgs.mode,
|
|
2341
2388
|
...(forward.value.recentRuns && forward.value.recentRuns.length > 0
|
|
@@ -2545,7 +2592,7 @@ export async function previewApp(ctx, input) {
|
|
|
2545
2592
|
...(input.branch ? { branch: input.branch } : {}),
|
|
2546
2593
|
commitId: commit.commitId,
|
|
2547
2594
|
directoryHash,
|
|
2548
|
-
editUrl: editUrl(ctx
|
|
2595
|
+
editUrl: editUrl(ctx, applicationId, input.branch),
|
|
2549
2596
|
...(name ? { name } : {}),
|
|
2550
2597
|
...(needsBrowserDriver ? { needsBrowserDriver: true } : {}),
|
|
2551
2598
|
openableViaHttps: openable.openableViaHttps,
|
|
@@ -2616,7 +2663,7 @@ export async function getPreviewStatus(ctx, input) {
|
|
|
2616
2663
|
kind: "ok",
|
|
2617
2664
|
value: {
|
|
2618
2665
|
...preview,
|
|
2619
|
-
editUrl: editUrl(ctx
|
|
2666
|
+
editUrl: editUrl(ctx, input.applicationId, input.branch),
|
|
2620
2667
|
status,
|
|
2621
2668
|
},
|
|
2622
2669
|
};
|
|
@@ -2773,7 +2820,7 @@ async function unbuiltApp(ctx, principal, applicationId, requestedBranch) {
|
|
|
2773
2820
|
const app = await withBrowser(ctx, {
|
|
2774
2821
|
applicationId,
|
|
2775
2822
|
...(actualBranch ? { branch: actualBranch } : {}),
|
|
2776
|
-
editUrl: editUrl(ctx
|
|
2823
|
+
editUrl: editUrl(ctx, applicationId, actualBranch),
|
|
2777
2824
|
...(name ? { name } : {}),
|
|
2778
2825
|
});
|
|
2779
2826
|
if (reason.kind === "awaiting_decision") {
|
|
@@ -2872,7 +2919,7 @@ export async function askUser(ctx, input) {
|
|
|
2872
2919
|
const app = {
|
|
2873
2920
|
applicationId,
|
|
2874
2921
|
...(branch ? { branch } : {}),
|
|
2875
|
-
editUrl: editUrl(ctx
|
|
2922
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
2876
2923
|
...(unbuilt?.value.name ? { name: unbuilt.value.name } : {}),
|
|
2877
2924
|
};
|
|
2878
2925
|
if (!unbuilt || unbuilt.value.status !== "needs_decision") {
|
|
@@ -2959,7 +3006,7 @@ export async function getApp(ctx, input) {
|
|
|
2959
3006
|
value: await withBrowser(ctx, {
|
|
2960
3007
|
applicationId,
|
|
2961
3008
|
...(branch ? { branch } : {}),
|
|
2962
|
-
editUrl: editUrl(ctx
|
|
3009
|
+
editUrl: editUrl(ctx, applicationId, branch),
|
|
2963
3010
|
...(name ? { name } : {}),
|
|
2964
3011
|
...(liveShot.needsBrowserDriver ? { needsBrowserDriver: true } : {}),
|
|
2965
3012
|
openableViaHttps: isHttpsUrl(previewUrl),
|