@growthub/cli 0.14.0 → 0.14.2
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/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/helper/apply/route.js +99 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/helper/query/route.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/login/route.js +3 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/logout/route.js +3 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-agent-auth/status/route.js +3 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/api/workspace/sandbox-run/route.js +84 -10
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/components/WorkspaceHelperSetupModal.jsx +2 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/AgentSwarmPanel.jsx +107 -34
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/DataModelShell.jsx +72 -15
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/HelperSidecar.jsx +264 -22
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationGraphCanvas.jsx +81 -10
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/OrchestrationNodeConfigPanel.jsx +179 -117
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SandboxAgentAuthPanel.jsx +34 -14
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SidecarExpandView.jsx +37 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/SwarmRunCockpit.jsx +625 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/data-model/components/helper-commands.js +150 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/globals.css +136 -3
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/app/workflows/WorkflowSurface.jsx +61 -13
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/docs/sandbox-environment-primitive.md +26 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/adapters/local-intelligence-browser-access.js +516 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/default-local-agent-host.js +224 -11
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/default-local-intelligence.js +4 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/default-local-process.js +3 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/index.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/adapters/sandboxes/sandbox-adapter-registry.js +5 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/data-model/field-contracts.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-agent-swarm.js +254 -4
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph-runner.js +3 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-graph.js +10 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/orchestration-run-console.js +412 -1
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-agent-auth.js +82 -27
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/sandbox-serverless-flow.js +4 -2
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-data-model.js +1 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-helper.js +23 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-metadata-store.js +8 -6
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-schema.js +6 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/lib/workspace-swarm-proposal.js +554 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package-lock.json +364 -0
- package/assets/worker-kits/growthub-custom-workspace-starter-v1/apps/workspace/package.json +1 -0
- package/package.json +1 -1
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useMemo } from "react";
|
|
4
|
-
import { Plus, Trash2 } from "lucide-react";
|
|
4
|
+
import { Check, Plus, Trash2 } from "lucide-react";
|
|
5
5
|
import { HOST_AUTH_CATALOG } from "@/lib/sandbox-agent-host-catalog";
|
|
6
|
+
import { SandboxAgentAuthPanel } from "./SandboxAgentAuthPanel.jsx";
|
|
7
|
+
import { isSandboxLocalAgentHost } from "@/lib/sandbox-agent-auth-eligibility";
|
|
8
|
+
|
|
9
|
+
const EMPTY_AGENT_AUTH_PATCH = {
|
|
10
|
+
agentAuthStatus: "",
|
|
11
|
+
agentAuthProvider: "",
|
|
12
|
+
agentAuthLastChecked: "",
|
|
13
|
+
agentAuthLastExitCode: "",
|
|
14
|
+
agentAuthLastMessage: "",
|
|
15
|
+
agentAuthLastLoginUrl: ""
|
|
16
|
+
};
|
|
6
17
|
|
|
7
18
|
function getHostOptions() {
|
|
8
19
|
return Object.entries(HOST_AUTH_CATALOG || {}).map(([slug, host]) => ({
|
|
@@ -11,31 +22,74 @@ function getHostOptions() {
|
|
|
11
22
|
}));
|
|
12
23
|
}
|
|
13
24
|
|
|
14
|
-
function
|
|
25
|
+
function nodeSandboxRecordRef(objectId, rowName, nodeId) {
|
|
26
|
+
return {
|
|
27
|
+
objectId: String(objectId || "").trim(),
|
|
28
|
+
rowName: String(rowName || "").trim(),
|
|
29
|
+
nodeId: String(nodeId || "").trim()
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function withRecordRef(patch, objectId, rowName, nodeId) {
|
|
34
|
+
return {
|
|
35
|
+
...patch,
|
|
36
|
+
sandboxRecordRef: nodeSandboxRecordRef(objectId, rowName, nodeId)
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function buildSubagentAuthDraft(sandboxRow, config) {
|
|
41
|
+
const agentHost = String(config?.agentHost || sandboxRow?.agentHost || "").trim();
|
|
42
|
+
if (!agentHost) return null;
|
|
43
|
+
return {
|
|
44
|
+
...(sandboxRow || {}),
|
|
45
|
+
runLocality: "local",
|
|
46
|
+
adapter: "local-agent-host",
|
|
47
|
+
agentHost
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function WorkflowCheckbox({ checked, disabled, onChange, children, title }) {
|
|
52
|
+
return (
|
|
53
|
+
<label className="dm-orchestration-config__field dm-orchestration-config__field-inline dm-workflow-check" title={title}>
|
|
54
|
+
<input
|
|
55
|
+
type="checkbox"
|
|
56
|
+
checked={checked}
|
|
57
|
+
disabled={disabled}
|
|
58
|
+
onChange={(event) => onChange?.(event.target.checked)}
|
|
59
|
+
/>
|
|
60
|
+
<span className="dm-workflow-check__box" aria-hidden="true">
|
|
61
|
+
{checked ? <Check size={13} strokeWidth={2.4} /> : null}
|
|
62
|
+
</span>
|
|
63
|
+
<span>{children}</span>
|
|
64
|
+
</label>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function patchOrchestrator(graph, patch, objectId, rowName) {
|
|
15
69
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
16
70
|
return {
|
|
17
71
|
...graph,
|
|
18
72
|
nodes: nodes.map((node) =>
|
|
19
73
|
node?.type === "thinAdapter"
|
|
20
|
-
? { ...node, config: { ...(node.config || {}), ...patch } }
|
|
74
|
+
? { ...node, config: { ...(node.config || {}), ...withRecordRef(patch, objectId, rowName, node.id) } }
|
|
21
75
|
: node
|
|
22
76
|
)
|
|
23
77
|
};
|
|
24
78
|
}
|
|
25
79
|
|
|
26
|
-
function patchSynthesis(graph, patch) {
|
|
80
|
+
function patchSynthesis(graph, patch, objectId, rowName) {
|
|
27
81
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
28
82
|
return {
|
|
29
83
|
...graph,
|
|
30
84
|
nodes: nodes.map((node) =>
|
|
31
85
|
node?.type === "tool-result"
|
|
32
|
-
? { ...node, config: { ...(node.config || {}), ...patch } }
|
|
86
|
+
? { ...node, config: { ...(node.config || {}), ...withRecordRef(patch, objectId, rowName, node.id) } }
|
|
33
87
|
: node
|
|
34
88
|
)
|
|
35
89
|
};
|
|
36
90
|
}
|
|
37
91
|
|
|
38
|
-
function patchSubagent(graph, nodeId, patch) {
|
|
92
|
+
function patchSubagent(graph, nodeId, patch, objectId, rowName) {
|
|
39
93
|
const nodes = Array.isArray(graph?.nodes) ? graph.nodes : [];
|
|
40
94
|
return {
|
|
41
95
|
...graph,
|
|
@@ -44,7 +98,7 @@ function patchSubagent(graph, nodeId, patch) {
|
|
|
44
98
|
? {
|
|
45
99
|
...node,
|
|
46
100
|
label: patch.role != null ? String(patch.role) : node.label,
|
|
47
|
-
config: { ...(node.config || {}), ...patch }
|
|
101
|
+
config: { ...(node.config || {}), ...withRecordRef(patch, objectId, rowName, node.id) }
|
|
48
102
|
}
|
|
49
103
|
: node
|
|
50
104
|
)
|
|
@@ -107,7 +161,7 @@ function patchSwarmConfig(graph, patch) {
|
|
|
107
161
|
return { ...graph, swarm: { ...base, ...patch } };
|
|
108
162
|
}
|
|
109
163
|
|
|
110
|
-
export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
164
|
+
export function AgentSwarmPanel({ graph, objectId, rowName, sandboxRow, onSandboxRowPatch, onGraphChange, disabled }) {
|
|
111
165
|
const hostOptions = useMemo(getHostOptions, []);
|
|
112
166
|
if (!graph || typeof graph !== "object") return null;
|
|
113
167
|
|
|
@@ -122,6 +176,21 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
122
176
|
onGraphChange?.(updater);
|
|
123
177
|
}
|
|
124
178
|
|
|
179
|
+
function patchSubagentHost(nodeId, agentHost) {
|
|
180
|
+
const nextHost = String(agentHost || "").trim();
|
|
181
|
+
patchGraph((g) => patchSubagent(g, nodeId, {
|
|
182
|
+
agentHost: nextHost,
|
|
183
|
+
...(nextHost ? { adapter: "local-agent-host" } : {})
|
|
184
|
+
}, objectId, rowName));
|
|
185
|
+
if (nextHost && typeof onSandboxRowPatch === "function") {
|
|
186
|
+
onSandboxRowPatch({
|
|
187
|
+
adapter: "local-agent-host",
|
|
188
|
+
agentHost: nextHost,
|
|
189
|
+
...EMPTY_AGENT_AUTH_PATCH
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
125
194
|
return (
|
|
126
195
|
<div className="dm-orchestration-config dm-agent-swarm-panel">
|
|
127
196
|
<div className="dm-orchestration-config__pane">
|
|
@@ -133,7 +202,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
133
202
|
rows={3}
|
|
134
203
|
value={orchestrator?.config?.prompt || ""}
|
|
135
204
|
disabled={disabled || !orchestrator}
|
|
136
|
-
onChange={(e) => patchGraph((g) => patchOrchestrator(g, { prompt: e.target.value }))}
|
|
205
|
+
onChange={(e) => patchGraph((g) => patchOrchestrator(g, { prompt: e.target.value }, objectId, rowName))}
|
|
137
206
|
/>
|
|
138
207
|
</label>
|
|
139
208
|
</div>
|
|
@@ -155,6 +224,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
155
224
|
)}
|
|
156
225
|
{subagents.map((node) => {
|
|
157
226
|
const cfg = node.config || {};
|
|
227
|
+
const subagentAuthDraft = buildSubagentAuthDraft(sandboxRow, cfg);
|
|
158
228
|
return (
|
|
159
229
|
<div key={node.id} className="dm-agent-swarm-panel__subagent">
|
|
160
230
|
<div className="dm-agent-swarm-panel__row">
|
|
@@ -163,7 +233,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
163
233
|
placeholder="Role"
|
|
164
234
|
value={cfg.role || node.label || ""}
|
|
165
235
|
disabled={disabled}
|
|
166
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { role: e.target.value }))}
|
|
236
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { role: e.target.value }, objectId, rowName))}
|
|
167
237
|
/>
|
|
168
238
|
<button
|
|
169
239
|
type="button"
|
|
@@ -181,7 +251,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
181
251
|
placeholder="One-sentence charter"
|
|
182
252
|
value={cfg.description || ""}
|
|
183
253
|
disabled={disabled}
|
|
184
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { description: e.target.value }))}
|
|
254
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { description: e.target.value }, objectId, rowName))}
|
|
185
255
|
/>
|
|
186
256
|
</label>
|
|
187
257
|
<label className="dm-orchestration-config__field">
|
|
@@ -190,7 +260,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
190
260
|
rows={2}
|
|
191
261
|
value={cfg.taskPrompt || ""}
|
|
192
262
|
disabled={disabled}
|
|
193
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { taskPrompt: e.target.value }))}
|
|
263
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { taskPrompt: e.target.value }, objectId, rowName))}
|
|
194
264
|
/>
|
|
195
265
|
</label>
|
|
196
266
|
<label className="dm-orchestration-config__field">
|
|
@@ -201,7 +271,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
201
271
|
disabled={disabled}
|
|
202
272
|
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, {
|
|
203
273
|
tools: e.target.value.split(",").map((t) => t.trim()).filter(Boolean)
|
|
204
|
-
}))}
|
|
274
|
+
}, objectId, rowName))}
|
|
205
275
|
/>
|
|
206
276
|
</label>
|
|
207
277
|
<label className="dm-orchestration-config__field">
|
|
@@ -212,7 +282,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
212
282
|
placeholder="0 = inherit"
|
|
213
283
|
value={cfg.maxTokens || 0}
|
|
214
284
|
disabled={disabled}
|
|
215
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { maxTokens: Math.max(0, Number(e.target.value) || 0) }))}
|
|
285
|
+
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { maxTokens: Math.max(0, Number(e.target.value) || 0) }, objectId, rowName))}
|
|
216
286
|
/>
|
|
217
287
|
</label>
|
|
218
288
|
<label className="dm-orchestration-config__field">
|
|
@@ -220,7 +290,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
220
290
|
<select
|
|
221
291
|
value={cfg.agentHost || ""}
|
|
222
292
|
disabled={disabled}
|
|
223
|
-
onChange={(e) =>
|
|
293
|
+
onChange={(e) => patchSubagentHost(node.id, e.target.value)}
|
|
224
294
|
>
|
|
225
295
|
<option value="">Inherit</option>
|
|
226
296
|
{hostOptions.map((opt) => (
|
|
@@ -228,27 +298,30 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
228
298
|
))}
|
|
229
299
|
</select>
|
|
230
300
|
</label>
|
|
231
|
-
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
301
|
+
{subagentAuthDraft && isSandboxLocalAgentHost(subagentAuthDraft) && (
|
|
302
|
+
<SandboxAgentAuthPanel
|
|
303
|
+
objectId={objectId}
|
|
304
|
+
rowName={rowName}
|
|
305
|
+
draft={subagentAuthDraft}
|
|
306
|
+
disabled={disabled || typeof onSandboxRowPatch !== "function"}
|
|
307
|
+
onPatchDraft={onSandboxRowPatch}
|
|
237
308
|
/>
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
309
|
+
)}
|
|
310
|
+
<WorkflowCheckbox
|
|
311
|
+
checked={cfg.required !== false}
|
|
312
|
+
disabled={disabled}
|
|
313
|
+
onChange={(checked) => patchGraph((g) => patchSubagent(g, node.id, { required: checked }, objectId, rowName))}
|
|
314
|
+
>
|
|
315
|
+
Required
|
|
316
|
+
</WorkflowCheckbox>
|
|
317
|
+
<WorkflowCheckbox
|
|
318
|
+
checked={cfg.networkAccess === true}
|
|
319
|
+
disabled={disabled}
|
|
242
320
|
title="Network is granted only when both this and the row's networkAllow are on."
|
|
321
|
+
onChange={(checked) => patchGraph((g) => patchSubagent(g, node.id, { networkAccess: checked }, objectId, rowName))}
|
|
243
322
|
>
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
checked={cfg.networkAccess === true}
|
|
247
|
-
disabled={disabled}
|
|
248
|
-
onChange={(e) => patchGraph((g) => patchSubagent(g, node.id, { networkAccess: e.target.checked }))}
|
|
249
|
-
/>
|
|
250
|
-
<span>Network</span>
|
|
251
|
-
</label>
|
|
323
|
+
Network
|
|
324
|
+
</WorkflowCheckbox>
|
|
252
325
|
</div>
|
|
253
326
|
);
|
|
254
327
|
})}
|
|
@@ -315,7 +388,7 @@ export function AgentSwarmPanel({ graph, onGraphChange, disabled }) {
|
|
|
315
388
|
rows={2}
|
|
316
389
|
value={synthesis?.config?.outcomePrompt || ""}
|
|
317
390
|
disabled={disabled}
|
|
318
|
-
onChange={(e) => patchGraph((g) => patchSynthesis(g, { outcomePrompt: e.target.value }))}
|
|
391
|
+
onChange={(e) => patchGraph((g) => patchSynthesis(g, { outcomePrompt: e.target.value }, objectId, rowName))}
|
|
319
392
|
/>
|
|
320
393
|
</label>
|
|
321
394
|
</div>
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
Trash2,
|
|
43
43
|
Type,
|
|
44
44
|
Unlock,
|
|
45
|
+
Upload,
|
|
45
46
|
Users,
|
|
46
47
|
X,
|
|
47
48
|
Zap,
|
|
@@ -646,6 +647,14 @@ function SandboxTraceFieldButton({ label, value, disabled, onOpen }) {
|
|
|
646
647
|
);
|
|
647
648
|
}
|
|
648
649
|
|
|
650
|
+
// Human labels for the per-host browser lanes declared in the
|
|
651
|
+
// local-agent-host catalog — surfaced so the operator's mental model matches
|
|
652
|
+
// exactly what the adapter does under the hood when browserAccess is on.
|
|
653
|
+
const BROWSER_LANE_LABELS = {
|
|
654
|
+
"native-flag": "browser enabled through the host CLI's first-party browser integration flags.",
|
|
655
|
+
"env-signal": "host receives GROWTHUB_SANDBOX_BROWSER_ACCESS=1 — its own configured browser integration honors this setting."
|
|
656
|
+
};
|
|
657
|
+
|
|
649
658
|
function SandboxRecordFields({
|
|
650
659
|
draft,
|
|
651
660
|
setDraft,
|
|
@@ -704,8 +713,21 @@ function SandboxRecordFields({
|
|
|
704
713
|
return { ...fields, ...EMPTY_AGENT_AUTH_PATCH };
|
|
705
714
|
}
|
|
706
715
|
|
|
716
|
+
function defaultSchedulerRegistryId() {
|
|
717
|
+
const objects = Array.isArray(workspaceConfig?.dataModel?.objects) ? workspaceConfig.dataModel.objects : [];
|
|
718
|
+
for (const object of objects) {
|
|
719
|
+
if (object?.objectType !== "api-registry") continue;
|
|
720
|
+
const row = (object.rows || []).find((r) => String(r?.integrationId || "").trim());
|
|
721
|
+
if (row) return String(row.integrationId || "").trim();
|
|
722
|
+
}
|
|
723
|
+
return "";
|
|
724
|
+
}
|
|
725
|
+
|
|
707
726
|
function setRunLocality(next) {
|
|
708
727
|
const fields = { runLocality: next };
|
|
728
|
+
if (next === "serverless") {
|
|
729
|
+
fields.schedulerRegistryId = String(draft.schedulerRegistryId || "").trim() || defaultSchedulerRegistryId();
|
|
730
|
+
}
|
|
709
731
|
if (next === "serverless" && ["local-agent-host", "local-intelligence"].includes(String(draft.adapter || "").trim())) {
|
|
710
732
|
fields.adapter = "local-process";
|
|
711
733
|
fields.agentHost = "";
|
|
@@ -723,6 +745,8 @@ function SandboxRecordFields({
|
|
|
723
745
|
}
|
|
724
746
|
|
|
725
747
|
const netOn = ["true", "1", "on", "yes"].includes(String(draft.networkAllow || "").trim().toLowerCase());
|
|
748
|
+
const browserOn = ["true", "1", "on", "yes"].includes(String(draft.browserAccess || "").trim().toLowerCase());
|
|
749
|
+
const browserHostMeta = (selectedAdapterMeta?.hostCatalog || []).find((h) => h.slug === String(draft.agentHost || "").trim());
|
|
726
750
|
|
|
727
751
|
// Same cockpit interface + mental model as the API Registry lane, driven by
|
|
728
752
|
// the serverless/scheduling/persistence derivation. Steps are status-only
|
|
@@ -734,6 +758,7 @@ function SandboxRecordFields({
|
|
|
734
758
|
persistenceAdapters: serverlessSignals.persistenceAdapters,
|
|
735
759
|
inlineEditing: true,
|
|
736
760
|
});
|
|
761
|
+
const showServerlessUpgrade = String(draft.adapter || "").trim() !== "local-intelligence";
|
|
737
762
|
function handleServerlessAction(action) {
|
|
738
763
|
if (!action) return;
|
|
739
764
|
if (action.id === "toggle-locality") setRunLocality(serverlessState.isServerless ? "local" : "serverless");
|
|
@@ -742,12 +767,14 @@ function SandboxRecordFields({
|
|
|
742
767
|
|
|
743
768
|
return (
|
|
744
769
|
<div className="dm-sandbox-config">
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
770
|
+
{showServerlessUpgrade && (
|
|
771
|
+
<ApiRegistryCreationCockpit
|
|
772
|
+
state={serverlessState}
|
|
773
|
+
onAction={handleServerlessAction}
|
|
774
|
+
disabled={!table.mutable || saving}
|
|
775
|
+
eyebrow={serverlessState.isServerless ? "Serverless workflow" : "Workflow runtime"}
|
|
776
|
+
/>
|
|
777
|
+
)}
|
|
751
778
|
<DrawerSection title="Identity & Mode">
|
|
752
779
|
<label className="dm-record-field">
|
|
753
780
|
<span>Name</span>
|
|
@@ -790,7 +817,7 @@ function SandboxRecordFields({
|
|
|
790
817
|
onChange={setRunLocality}
|
|
791
818
|
/>
|
|
792
819
|
<p className="dm-cell-empty" style={{ fontSize: 11, marginTop: 6 }}>
|
|
793
|
-
|
|
820
|
+
Choose local execution or a scheduled serverless run.
|
|
794
821
|
</p>
|
|
795
822
|
|
|
796
823
|
{locality === "serverless" && table.objectId && (
|
|
@@ -882,7 +909,7 @@ function SandboxRecordFields({
|
|
|
882
909
|
</label>
|
|
883
910
|
|
|
884
911
|
<p className="dm-cell-empty" style={{ fontSize: 11, marginTop: 0 }}>
|
|
885
|
-
Uses <strong>Instructions</strong> + <strong>Command</strong> as the task payload.
|
|
912
|
+
Uses <strong>Instructions</strong> + <strong>Command</strong> as the task payload. With browser access off, tool intents stay proposals. With browser access on, browser tool intents execute through the local browser bridge before the final JSON response is returned.
|
|
886
913
|
</p>
|
|
887
914
|
</div>
|
|
888
915
|
)}
|
|
@@ -920,10 +947,12 @@ function SandboxRecordFields({
|
|
|
920
947
|
</div>
|
|
921
948
|
|
|
922
949
|
<ToggleField
|
|
923
|
-
checked={netOn}
|
|
924
|
-
disabled={!table.mutable || saving}
|
|
950
|
+
checked={netOn || browserOn}
|
|
951
|
+
disabled={!table.mutable || saving || (browserOn && !netOn)}
|
|
925
952
|
label="Network allow-list mode"
|
|
926
|
-
description=
|
|
953
|
+
description={browserOn && !netOn
|
|
954
|
+
? "Network enabled by browser access — the run route grants it even though this row's networkAllow is off. Turn browser access off to control network independently."
|
|
955
|
+
: "When enabled, local runs honor GROWTHUB_SANDBOX_NET_* and the allow list below."}
|
|
927
956
|
onChange={(on) => patchFields({ networkAllow: on ? "true" : "false" })}
|
|
928
957
|
/>
|
|
929
958
|
|
|
@@ -936,6 +965,21 @@ function SandboxRecordFields({
|
|
|
936
965
|
onBlur={(event) => patchFields({ allowList: event.target.value })}
|
|
937
966
|
/>
|
|
938
967
|
</label>
|
|
968
|
+
|
|
969
|
+
<ToggleField
|
|
970
|
+
checked={browserOn}
|
|
971
|
+
disabled={!table.mutable || saving}
|
|
972
|
+
label="Browser access"
|
|
973
|
+
description="Allows this sandbox to use a real browser. Also enables network. Local intelligence uses the Playwright browser bridge; Codex/Claude use their native browser modes."
|
|
974
|
+
onChange={(on) => patchFields(on
|
|
975
|
+
? { browserAccess: "true", networkAllow: "true" }
|
|
976
|
+
: { browserAccess: "false" })}
|
|
977
|
+
/>
|
|
978
|
+
{browserOn && String(draft.adapter || "").trim() === "local-agent-host" && browserHostMeta && (
|
|
979
|
+
<p className="dm-cell-empty" style={{ fontSize: 11, marginTop: 4 }}>
|
|
980
|
+
{browserHostMeta.label}: {BROWSER_LANE_LABELS[browserHostMeta.browserLane] || BROWSER_LANE_LABELS["env-signal"]}
|
|
981
|
+
</p>
|
|
982
|
+
)}
|
|
939
983
|
</DrawerSection>
|
|
940
984
|
|
|
941
985
|
<DrawerSection title="Prompt & Limits">
|
|
@@ -1843,7 +1887,9 @@ function DataModelRecordDrawer({
|
|
|
1843
1887
|
<header className="dm-record-drawer-head">
|
|
1844
1888
|
<div>
|
|
1845
1889
|
<p>Record</p>
|
|
1846
|
-
<h2
|
|
1890
|
+
<h2 title={draft.Name || draft.integrationId || draft.id || `Row ${rowIndex + 1}`}>
|
|
1891
|
+
{draft.Name || draft.integrationId || draft.id || `Row ${rowIndex + 1}`}
|
|
1892
|
+
</h2>
|
|
1847
1893
|
</div>
|
|
1848
1894
|
<div className="dm-record-drawer-actions">
|
|
1849
1895
|
{isSandbox && sidecarMode !== "graph" && sidecarMode !== "trace" && (
|
|
@@ -1854,7 +1900,7 @@ function DataModelRecordDrawer({
|
|
|
1854
1900
|
onClick={runSandbox}
|
|
1855
1901
|
>
|
|
1856
1902
|
<Play size={13} aria-hidden />
|
|
1857
|
-
{sandboxRunning ? "Running…" : "
|
|
1903
|
+
{sandboxRunning ? "Running…" : "Execute"}
|
|
1858
1904
|
</button>
|
|
1859
1905
|
)}
|
|
1860
1906
|
{!isSandbox && sandboxToolFlow !== "draft" && (
|
|
@@ -2457,9 +2503,9 @@ function DataModelTableSurface({
|
|
|
2457
2503
|
const a = document.createElement("a");
|
|
2458
2504
|
a.href = url; a.download = `${table.source.replace(/\s+/g, "-").toLowerCase()}.csv`;
|
|
2459
2505
|
a.click(); URL.revokeObjectURL(url);
|
|
2460
|
-
}}
|
|
2506
|
+
}}><Download size={13} />Export CSV</button>
|
|
2461
2507
|
)}
|
|
2462
|
-
{table.mutable && <button type="button" className="dm-btn-ghost" onClick={() => setCsvOpen((open) => !open)}
|
|
2508
|
+
{table.mutable && <button type="button" className="dm-btn-ghost" onClick={() => setCsvOpen((open) => !open)}><Upload size={13} />Import CSV</button>}
|
|
2463
2509
|
{table.mutable && (
|
|
2464
2510
|
<button type="button" className="dm-btn-primary-sm" disabled={saving} onClick={() => onSave((config) => addTableRow(config, table))}>
|
|
2465
2511
|
<Plus size={13} />Add record
|
|
@@ -3544,6 +3590,17 @@ export default function DataModelShell() {
|
|
|
3544
3590
|
router.push(`/?dashboard=${encodeURIComponent(target.dashboardId)}`);
|
|
3545
3591
|
}
|
|
3546
3592
|
}}
|
|
3593
|
+
onOpenSwarmWorkflow={(target) => {
|
|
3594
|
+
const objectId = String(target?.objectId || "").trim();
|
|
3595
|
+
const rowName = String(target?.name || "").trim();
|
|
3596
|
+
if (!objectId || !rowName) return;
|
|
3597
|
+
const params = new URLSearchParams({
|
|
3598
|
+
object: objectId,
|
|
3599
|
+
row: rowName,
|
|
3600
|
+
field: "orchestrationGraph"
|
|
3601
|
+
});
|
|
3602
|
+
router.push(`/workflows?${params.toString()}`);
|
|
3603
|
+
}}
|
|
3547
3604
|
onApplied={(updatedConfig) => {
|
|
3548
3605
|
// Anchor the user on the most recently created/updated Data Model
|
|
3549
3606
|
// object so a helper-driven object.create lands on the surface
|