@tangle-network/agent-app 0.46.8 → 0.46.10
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/chat-routes/index.js +1 -1
- package/dist/{chunk-MA2RIIIH.js → chunk-3HBH5GFN.js} +33 -18
- package/dist/chunk-3HBH5GFN.js.map +1 -0
- package/dist/sandbox/index.d.ts +69 -2
- package/dist/sandbox/index.js +7 -1
- package/dist/studio-react/composer-persistence.d.ts +12 -0
- package/dist/studio-react/index.js +93 -1
- package/dist/studio-react/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-MA2RIIIH.js.map +0 -1
package/dist/sandbox/index.d.ts
CHANGED
|
@@ -340,9 +340,76 @@ export declare function sandboxToolPath(options: SandboxToolPathOptions & {
|
|
|
340
340
|
}): string;
|
|
341
341
|
/** Build file mounts for sandbox tools based on provided options and tool configurations */
|
|
342
342
|
export declare function buildSandboxToolFileMounts(options: BuildSandboxToolFileMountsOptions): AgentProfileFileMount[];
|
|
343
|
-
/**
|
|
343
|
+
/**
|
|
344
|
+
* Build the `SANDBOX_TOOL_BIN_DIRS` entry that puts these apps' tool bin dirs on
|
|
345
|
+
* a sandbox PATH. Declare it in the same box env as the mounts from
|
|
346
|
+
* {@link buildSandboxToolFileMounts}: the mounts place the executables, this
|
|
347
|
+
* places the directory that makes a bare tool name resolve.
|
|
348
|
+
*
|
|
349
|
+
* Every sandbox PATH builder appends these directories at the TAIL, after the
|
|
350
|
+
* Nix, npm, and image entries, so a tool never shadows a platform or system
|
|
351
|
+
* binary of the same name. That placement is identical for a non-interactive
|
|
352
|
+
* exec, a sidecar-spawned CLI, and an SSH shell, which is why this variable and
|
|
353
|
+
* not a shell rc file is the mechanism: an exec reads no rc file, and the SSH
|
|
354
|
+
* shell environment assigns PATH absolutely.
|
|
355
|
+
*
|
|
356
|
+
* Entries come from {@link sandboxToolBinDir}, so the value can never name a
|
|
357
|
+
* directory the mounts did not use — a caller that hand-writes the literal
|
|
358
|
+
* instead drifts silently the moment a base dir changes. Order is preserved,
|
|
359
|
+
* and two apps that resolve to one directory collapse to the FIRST position it
|
|
360
|
+
* appeared in.
|
|
361
|
+
*
|
|
362
|
+
* A `:` in a resolved bin dir throws here. The character separates entries both
|
|
363
|
+
* in this variable and in PATH itself, so such a directory is unrepresentable
|
|
364
|
+
* rather than merely awkward: joining it would split one absolute path into a
|
|
365
|
+
* leading path and a relative remainder, and the runtime rejects a relative
|
|
366
|
+
* segment by failing the whole box. Throwing names the offending directory
|
|
367
|
+
* instead.
|
|
368
|
+
*
|
|
369
|
+
* The consuming half lives in agent-dev-container: `resolveSandboxToolBinDirs`
|
|
370
|
+
* parses this value and every PATH builder appends it at the tail — sidecar
|
|
371
|
+
* exec and PTY through `packages/shared/src/cache-env.ts`, an SSH session
|
|
372
|
+
* through `packages/shared/src/ssh-bootstrap.ts`, and a spawned CLI through
|
|
373
|
+
* `packages/sdk-cli-runner/src/cli-process.ts`, each with its own tests. This
|
|
374
|
+
* package has no sandbox runtime, so tail placement is pinned there, not here.
|
|
375
|
+
*/
|
|
376
|
+
export declare function buildSandboxToolBinDirsEnv(apps: readonly SandboxToolPathOptions[]): {
|
|
377
|
+
SANDBOX_TOOL_BIN_DIRS: string;
|
|
378
|
+
};
|
|
379
|
+
/**
|
|
380
|
+
* Build a shell script that creates the sandbox tool binary directory.
|
|
381
|
+
* {@link buildSandboxToolBinDirsEnv}, not this script, puts that directory on a
|
|
382
|
+
* sandbox PATH.
|
|
383
|
+
*
|
|
384
|
+
* The `mkdir -p` makes the directory exist before a tool mount lands in it.
|
|
385
|
+
*/
|
|
386
|
+
export declare function buildSandboxToolBinDirScript(options: SandboxToolPathOptions): string;
|
|
387
|
+
/** Build a shell script that creates the sandbox tool binary directory.
|
|
388
|
+
*
|
|
389
|
+
* @deprecated Renamed to {@link buildSandboxToolBinDirScript}, and the script
|
|
390
|
+
* no longer appends the bin dir to PATH in `~/.profile`, `~/.bashrc` and
|
|
391
|
+
* `~/.zshrc`. Those edits never reached the contexts that run a tool: an exec
|
|
392
|
+
* and a spawned CLI read no rc file, and the SSH shell assigns PATH
|
|
393
|
+
* absolutely, which discards an appended entry. Put the directory on PATH with
|
|
394
|
+
* {@link buildSandboxToolBinDirsEnv} instead. This name forwards to the new
|
|
395
|
+
* one so an existing import keeps resolving; removal is a major.
|
|
396
|
+
*/
|
|
344
397
|
export declare function buildSandboxToolPathSetupScript(options: SandboxToolPathOptions): string;
|
|
345
|
-
/**
|
|
398
|
+
/**
|
|
399
|
+
* Create the sandbox tool binary directory in a running box.
|
|
400
|
+
* {@link buildSandboxToolBinDirsEnv}, not this call, puts it on a sandbox PATH.
|
|
401
|
+
*/
|
|
402
|
+
export declare function ensureSandboxToolBinDir(box: SandboxInstance, options: SandboxToolPathOptions): Promise<Outcome<void>>;
|
|
403
|
+
/** Create the sandbox tool binary directory in a running box.
|
|
404
|
+
*
|
|
405
|
+
* @deprecated Renamed to {@link ensureSandboxToolBinDir}, and the call no
|
|
406
|
+
* longer appends the bin dir to PATH in `~/.profile`, `~/.bashrc` and
|
|
407
|
+
* `~/.zshrc`. Those edits never reached the contexts that run a tool: an exec
|
|
408
|
+
* and a spawned CLI read no rc file, and the SSH shell assigns PATH
|
|
409
|
+
* absolutely, which discards an appended entry. Put the directory on PATH with
|
|
410
|
+
* {@link buildSandboxToolBinDirsEnv} instead. This name forwards to the new
|
|
411
|
+
* one so an existing import keeps resolving; removal is a major.
|
|
412
|
+
*/
|
|
346
413
|
export declare function runSandboxToolPathSetup(box: SandboxInstance, options: SandboxToolPathOptions): Promise<Outcome<void>>;
|
|
347
414
|
/** Split profile files into inline deferred files and a lean profile without them */
|
|
348
415
|
export declare function splitDeferredProfileFiles(profile: AgentProfile): {
|
package/dist/sandbox/index.js
CHANGED
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
attachReasoningEffort,
|
|
29
29
|
buildAppToolMcpServers,
|
|
30
30
|
buildProductEgressPolicy,
|
|
31
|
+
buildSandboxToolBinDirScript,
|
|
32
|
+
buildSandboxToolBinDirsEnv,
|
|
31
33
|
buildSandboxToolFileMounts,
|
|
32
34
|
buildSandboxToolPathSetupScript,
|
|
33
35
|
classifySeveredStream,
|
|
@@ -41,6 +43,7 @@ import {
|
|
|
41
43
|
deleteSecret,
|
|
42
44
|
detectInteractiveQuestion,
|
|
43
45
|
driveSandboxTurn,
|
|
46
|
+
ensureSandboxToolBinDir,
|
|
44
47
|
ensureWorkspaceSandbox,
|
|
45
48
|
flattenHistory,
|
|
46
49
|
formatSandboxProvisioningSupportDetails,
|
|
@@ -88,7 +91,7 @@ import {
|
|
|
88
91
|
workspaceSandboxRecoveryMessage,
|
|
89
92
|
workspaceSandboxRecoveryRecommendedActions,
|
|
90
93
|
writeProfileFilesToBox
|
|
91
|
-
} from "../chunk-
|
|
94
|
+
} from "../chunk-3HBH5GFN.js";
|
|
92
95
|
import "../chunk-TH7L265V.js";
|
|
93
96
|
import "../chunk-LWSJK546.js";
|
|
94
97
|
import "../chunk-P5PIAQVS.js";
|
|
@@ -127,6 +130,8 @@ export {
|
|
|
127
130
|
attachReasoningEffort,
|
|
128
131
|
buildAppToolMcpServers,
|
|
129
132
|
buildProductEgressPolicy,
|
|
133
|
+
buildSandboxToolBinDirScript,
|
|
134
|
+
buildSandboxToolBinDirsEnv,
|
|
130
135
|
buildSandboxToolFileMounts,
|
|
131
136
|
buildSandboxToolPathSetupScript,
|
|
132
137
|
classifySeveredStream,
|
|
@@ -140,6 +145,7 @@ export {
|
|
|
140
145
|
deleteSecret,
|
|
141
146
|
detectInteractiveQuestion,
|
|
142
147
|
driveSandboxTurn,
|
|
148
|
+
ensureSandboxToolBinDir,
|
|
143
149
|
ensureWorkspaceSandbox,
|
|
144
150
|
flattenHistory,
|
|
145
151
|
formatSandboxProvisioningSupportDetails,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ModelOptionValue } from '../studio';
|
|
2
|
+
import type { ComposerType } from './studio-composer';
|
|
3
|
+
export interface PersistedComposerSelections {
|
|
4
|
+
v: 1;
|
|
5
|
+
type: ComposerType;
|
|
6
|
+
selectedModels: Partial<Record<ComposerType, string>>;
|
|
7
|
+
/** Option values are model-specific: two models in one lane may publish
|
|
8
|
+
* different enums for the same parameter. */
|
|
9
|
+
optionsByModel: Record<string, Record<string, ModelOptionValue>>;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadComposerSelections(workspaceId: string): PersistedComposerSelections | null;
|
|
12
|
+
export declare function saveComposerSelections(workspaceId: string, snapshot: PersistedComposerSelections): void;
|
|
@@ -685,6 +685,58 @@ function optionValueLabel(param, value) {
|
|
|
685
685
|
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
686
686
|
}
|
|
687
687
|
|
|
688
|
+
// src/studio-react/composer-persistence.ts
|
|
689
|
+
var COMPOSER_TYPES = ["image", "video", "speech"];
|
|
690
|
+
function storageKey(workspaceId) {
|
|
691
|
+
return `studio-composer:${workspaceId}`;
|
|
692
|
+
}
|
|
693
|
+
function isPlainObject(value) {
|
|
694
|
+
if (value === null || typeof value !== "object") return false;
|
|
695
|
+
const prototype = Object.getPrototypeOf(value);
|
|
696
|
+
return prototype === Object.prototype || prototype === null;
|
|
697
|
+
}
|
|
698
|
+
function isComposerType(value) {
|
|
699
|
+
return COMPOSER_TYPES.some((type) => type === value);
|
|
700
|
+
}
|
|
701
|
+
function isOptionValue(value) {
|
|
702
|
+
return typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value);
|
|
703
|
+
}
|
|
704
|
+
function parseSelections(value) {
|
|
705
|
+
if (!isPlainObject(value) || value.v !== 1 || !isComposerType(value.type)) return null;
|
|
706
|
+
if (!isPlainObject(value.selectedModels) || !isPlainObject(value.optionsByModel)) return null;
|
|
707
|
+
const selectedModels = {};
|
|
708
|
+
for (const type of COMPOSER_TYPES) {
|
|
709
|
+
const modelId = value.selectedModels[type];
|
|
710
|
+
if (typeof modelId === "string") selectedModels[type] = modelId;
|
|
711
|
+
}
|
|
712
|
+
const optionsByModel = {};
|
|
713
|
+
for (const [modelId, rawOptions] of Object.entries(value.optionsByModel)) {
|
|
714
|
+
if (!isPlainObject(rawOptions)) continue;
|
|
715
|
+
const options = {};
|
|
716
|
+
for (const [param, optionValue] of Object.entries(rawOptions)) {
|
|
717
|
+
if (isOptionValue(optionValue)) options[param] = optionValue;
|
|
718
|
+
}
|
|
719
|
+
optionsByModel[modelId] = options;
|
|
720
|
+
}
|
|
721
|
+
return { v: 1, type: value.type, selectedModels, optionsByModel };
|
|
722
|
+
}
|
|
723
|
+
function loadComposerSelections(workspaceId) {
|
|
724
|
+
if (typeof window === "undefined") return null;
|
|
725
|
+
try {
|
|
726
|
+
const raw = window.localStorage.getItem(storageKey(workspaceId));
|
|
727
|
+
return raw === null ? null : parseSelections(JSON.parse(raw));
|
|
728
|
+
} catch {
|
|
729
|
+
return null;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
function saveComposerSelections(workspaceId, snapshot) {
|
|
733
|
+
if (typeof window === "undefined") return;
|
|
734
|
+
try {
|
|
735
|
+
window.localStorage.setItem(storageKey(workspaceId), JSON.stringify(snapshot));
|
|
736
|
+
} catch {
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
688
740
|
// src/studio-react/studio-composer.tsx
|
|
689
741
|
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
690
742
|
var SEGMENTS = [
|
|
@@ -760,8 +812,26 @@ function StudioComposer({
|
|
|
760
812
|
const [referenceImageUrl, setReferenceImageUrl] = useState3(null);
|
|
761
813
|
const [isSubmitting, setIsSubmitting] = useState3(false);
|
|
762
814
|
const [error, setError] = useState3(null);
|
|
815
|
+
const [hydratedWorkspaceId, setHydratedWorkspaceId] = useState3(null);
|
|
763
816
|
const submitLockRef = useRef2(false);
|
|
764
817
|
const bandRef = useRef2(null);
|
|
818
|
+
const hydratedRef = useRef2(false);
|
|
819
|
+
const persistedOptionsRef = useRef2({});
|
|
820
|
+
useEffect3(() => {
|
|
821
|
+
hydratedRef.current = false;
|
|
822
|
+
setHydratedWorkspaceId(null);
|
|
823
|
+
if (!workspaceId) return;
|
|
824
|
+
const persisted = loadComposerSelections(workspaceId);
|
|
825
|
+
if (persisted) {
|
|
826
|
+
setType(persisted.type);
|
|
827
|
+
setSelectedModels(persisted.selectedModels);
|
|
828
|
+
persistedOptionsRef.current = persisted.optionsByModel;
|
|
829
|
+
} else {
|
|
830
|
+
persistedOptionsRef.current = {};
|
|
831
|
+
}
|
|
832
|
+
hydratedRef.current = true;
|
|
833
|
+
setHydratedWorkspaceId(workspaceId);
|
|
834
|
+
}, [workspaceId]);
|
|
765
835
|
useEffect3(() => {
|
|
766
836
|
if (!workspaceId) return;
|
|
767
837
|
let cancelled = false;
|
|
@@ -814,13 +884,35 @@ function StudioComposer({
|
|
|
814
884
|
);
|
|
815
885
|
useEffect3(() => {
|
|
816
886
|
setOptionValues((current) => {
|
|
817
|
-
const
|
|
887
|
+
const seed = { ...persistedOptionsRef.current[modelId], ...current[type] };
|
|
888
|
+
const next = reconcileOptionValues(options, seed, {
|
|
818
889
|
allowCustomSize: supportsCustomImageSize(modelId)
|
|
819
890
|
});
|
|
820
891
|
const unchanged = Object.keys(next).length === Object.keys(current[type]).length && Object.entries(next).every(([key, value]) => current[type][key] === value);
|
|
821
892
|
return unchanged ? current : { ...current, [type]: next };
|
|
822
893
|
});
|
|
823
894
|
}, [modelId, options, type]);
|
|
895
|
+
useEffect3(() => {
|
|
896
|
+
if (!workspaceId || !hydratedRef.current || hydratedWorkspaceId !== workspaceId) return;
|
|
897
|
+
if (!catalog && modelId && persistedOptionsRef.current[modelId] !== void 0 && !options) return;
|
|
898
|
+
const seed = { ...persistedOptionsRef.current[modelId], ...optionValues[type] };
|
|
899
|
+
const reconciled = reconcileOptionValues(options, seed, {
|
|
900
|
+
allowCustomSize: supportsCustomImageSize(modelId)
|
|
901
|
+
});
|
|
902
|
+
const reconciledReady = Object.keys(reconciled).length === Object.keys(optionValues[type]).length && Object.entries(reconciled).every(([key, value]) => optionValues[type][key] === value);
|
|
903
|
+
if (!reconciledReady) return;
|
|
904
|
+
const optionsByModel = {
|
|
905
|
+
...persistedOptionsRef.current,
|
|
906
|
+
...modelId ? { [modelId]: optionValues[type] } : {}
|
|
907
|
+
};
|
|
908
|
+
saveComposerSelections(workspaceId, {
|
|
909
|
+
v: 1,
|
|
910
|
+
type,
|
|
911
|
+
selectedModels,
|
|
912
|
+
optionsByModel
|
|
913
|
+
});
|
|
914
|
+
persistedOptionsRef.current = optionsByModel;
|
|
915
|
+
}, [catalog, hydratedWorkspaceId, modelId, optionValues, options, selectedModels, type, workspaceId]);
|
|
824
916
|
const values = optionValues[type];
|
|
825
917
|
const params = visibleParams(type, options);
|
|
826
918
|
const audioMeta = type === "video" ? options?.audio : void 0;
|