@finalai/final-agent-provider 0.10.0 → 0.11.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/HOSTING.md +334 -245
- package/README.md +126 -40
- package/WORKSPACE-EGRESS.md +11 -11
- package/dist/modules/catalog.d.mts +9 -0
- package/dist/modules/catalog.mjs +21 -0
- package/dist/modules/catalog.mjs.map +7 -0
- package/dist/modules/channels/projection.mjs +15 -8
- package/dist/modules/channels/projection.mjs.map +2 -2
- package/dist/modules/harnesses/acp-agent.d.mts +4 -0
- package/dist/modules/harnesses/acp-agent.mjs +35 -0
- package/dist/modules/harnesses/acp-agent.mjs.map +7 -0
- package/dist/modules/harnesses/adapters.d.mts +7 -0
- package/dist/modules/harnesses/adapters.mjs +74 -0
- package/dist/modules/harnesses/adapters.mjs.map +7 -0
- package/dist/modules/harnesses/claude-code.d.mts +14 -0
- package/dist/modules/harnesses/claude-code.mjs +79 -0
- package/dist/modules/harnesses/claude-code.mjs.map +7 -0
- package/dist/modules/harnesses/codex.d.mts +12 -0
- package/dist/modules/harnesses/codex.mjs +90 -0
- package/dist/modules/harnesses/codex.mjs.map +7 -0
- package/dist/modules/harnesses/config-fields.d.mts +98 -57
- package/dist/modules/harnesses/config-fields.mjs +58 -35
- package/dist/modules/harnesses/config-fields.mjs.map +3 -3
- package/dist/modules/harnesses/definitions.d.mts +3 -0
- package/dist/modules/harnesses/definitions.mjs +21 -0
- package/dist/modules/harnesses/definitions.mjs.map +7 -0
- package/dist/modules/harnesses/fidelity.d.mts +1 -1
- package/dist/modules/harnesses/fidelity.mjs +19 -16
- package/dist/modules/harnesses/fidelity.mjs.map +2 -2
- package/dist/modules/harnesses/final.d.mts +12 -0
- package/dist/modules/harnesses/final.mjs +70 -0
- package/dist/modules/harnesses/final.mjs.map +7 -0
- package/dist/modules/harnesses/index.d.mts +13 -12
- package/dist/modules/harnesses/index.mjs +86 -45
- package/dist/modules/harnesses/index.mjs.map +3 -3
- package/dist/modules/harnesses/names.d.mts +43 -0
- package/dist/modules/harnesses/names.mjs +59 -0
- package/dist/modules/harnesses/names.mjs.map +7 -0
- package/dist/modules/harnesses/nanocode-claude.d.mts +18 -0
- package/dist/modules/harnesses/nanocode-claude.mjs +101 -0
- package/dist/modules/harnesses/nanocode-claude.mjs.map +7 -0
- package/dist/modules/harnesses/nanocode-codex.d.mts +13 -0
- package/dist/modules/harnesses/nanocode-codex.mjs +64 -0
- package/dist/modules/harnesses/nanocode-codex.mjs.map +7 -0
- package/dist/modules/harnesses/pi.d.mts +12 -0
- package/dist/modules/harnesses/pi.mjs +71 -0
- package/dist/modules/harnesses/pi.mjs.map +7 -0
- package/dist/modules/integrations.d.mts +9 -0
- package/dist/modules/integrations.mjs +29 -0
- package/dist/modules/integrations.mjs.map +7 -0
- package/dist/modules/provider/general.bundle.d.mts +1 -0
- package/dist/modules/provider/general.bundle.mjs +5 -0
- package/dist/modules/provider/general.bundle.mjs.map +7 -0
- package/dist/modules/provider/general.d.mts +11 -0
- package/dist/modules/provider/general.mjs +130 -0
- package/dist/modules/provider/general.mjs.map +7 -0
- package/dist/modules/provider/index.d.mts +3 -0
- package/dist/modules/provider/index.mjs +13 -0
- package/dist/modules/provider/index.mjs.map +7 -0
- package/dist/modules/sandboxes/access.d.mts +34 -0
- package/dist/modules/sandboxes/access.mjs +15 -0
- package/dist/modules/sandboxes/access.mjs.map +7 -0
- package/dist/modules/sandboxes/computer.d.mts +24 -51
- package/dist/modules/sandboxes/computer.mjs +523 -888
- package/dist/modules/sandboxes/computer.mjs.map +3 -3
- package/dist/modules/sandboxes/computers-api.d.mts +3 -2
- package/dist/modules/sandboxes/computers-api.mjs +2 -4
- package/dist/modules/sandboxes/computers-api.mjs.map +2 -2
- package/dist/modules/sandboxes/device-api.d.mts +4 -3
- package/dist/modules/sandboxes/device-api.mjs +2 -4
- package/dist/modules/sandboxes/device-api.mjs.map +2 -2
- package/dist/modules/sandboxes/device.d.mts +6 -6
- package/dist/modules/sandboxes/device.mjs +126 -121
- package/dist/modules/sandboxes/device.mjs.map +3 -3
- package/dist/modules/sandboxes/egress.d.mts +10 -9
- package/dist/modules/sandboxes/egress.mjs +73 -56
- package/dist/modules/sandboxes/egress.mjs.map +2 -2
- package/dist/modules/sandboxes/environment.d.mts +35 -269
- package/dist/modules/sandboxes/environment.mjs +27 -104
- package/dist/modules/sandboxes/environment.mjs.map +3 -3
- package/dist/modules/sandboxes/index.d.mts +9 -69
- package/dist/modules/sandboxes/index.mjs +35 -95
- package/dist/modules/sandboxes/index.mjs.map +3 -3
- package/dist/modules/sandboxes/local.d.mts +28 -0
- package/dist/modules/sandboxes/local.mjs +499 -0
- package/dist/modules/sandboxes/local.mjs.map +7 -0
- package/dist/modules/sandboxes/session.d.mts +0 -3
- package/dist/modules/sandboxes/session.mjs +2 -22
- package/dist/modules/sandboxes/session.mjs.map +2 -2
- package/dist/modules/sandboxes/testing/fake-machine.mjs +0 -28
- package/dist/modules/sandboxes/testing/fake-machine.mjs.map +2 -2
- package/package.json +76 -104
- package/dist/modules/connections.d.mts +0 -11
- package/dist/modules/connections.mjs +0 -16
- package/dist/modules/connections.mjs.map +0 -7
- package/dist/modules/harnesses/acp-describe.d.mts +0 -20
- package/dist/modules/harnesses/acp-describe.mjs +0 -110
- package/dist/modules/harnesses/acp-describe.mjs.map +0 -7
- package/dist/modules/harnesses/local-stdio.d.mts +0 -47
- package/dist/modules/harnesses/local-stdio.mjs +0 -41
- package/dist/modules/harnesses/local-stdio.mjs.map +0 -7
- package/dist/modules/harnesses/remote-acp.d.mts +0 -76
- package/dist/modules/harnesses/remote-acp.mjs +0 -83
- package/dist/modules/harnesses/remote-acp.mjs.map +0 -7
- package/dist/modules/harnesses/remote-claude-code.d.mts +0 -88
- package/dist/modules/harnesses/remote-claude-code.mjs +0 -113
- package/dist/modules/harnesses/remote-claude-code.mjs.map +0 -7
- package/dist/modules/harnesses/remote-client-tls.d.mts +0 -35
- package/dist/modules/harnesses/remote-client-tls.mjs +0 -37
- package/dist/modules/harnesses/remote-client-tls.mjs.map +0 -7
- package/dist/modules/harnesses/remote-codex.d.mts +0 -98
- package/dist/modules/harnesses/remote-codex.mjs +0 -128
- package/dist/modules/harnesses/remote-codex.mjs.map +0 -7
- package/dist/modules/harnesses/remote-pi.d.mts +0 -78
- package/dist/modules/harnesses/remote-pi.mjs +0 -104
- package/dist/modules/harnesses/remote-pi.mjs.map +0 -7
- package/dist/modules/harnesses/remote-url.d.mts +0 -5
- package/dist/modules/harnesses/remote-url.mjs +0 -19
- package/dist/modules/harnesses/remote-url.mjs.map +0 -7
- package/dist/modules/harnesses/serverless-final.d.mts +0 -63
- package/dist/modules/harnesses/serverless-final.mjs +0 -88
- package/dist/modules/harnesses/serverless-final.mjs.map +0 -7
- package/dist/modules/harnesses/serverless-nanocode-claude.d.mts +0 -64
- package/dist/modules/harnesses/serverless-nanocode-claude.mjs +0 -105
- package/dist/modules/harnesses/serverless-nanocode-claude.mjs.map +0 -7
- package/dist/modules/harnesses/serverless-nanocode-codex.d.mts +0 -66
- package/dist/modules/harnesses/serverless-nanocode-codex.mjs +0 -113
- package/dist/modules/harnesses/serverless-nanocode-codex.mjs.map +0 -7
- package/dist/modules/harnesses/serverless-pi.d.mts +0 -64
- package/dist/modules/harnesses/serverless-pi.mjs +0 -98
- package/dist/modules/harnesses/serverless-pi.mjs.map +0 -7
- package/dist/modules/runtime/index.d.mts +0 -7
- package/dist/modules/runtime/index.mjs +0 -18
- package/dist/modules/runtime/index.mjs.map +0 -7
- package/dist/modules/runtime/local-stdio.d.mts +0 -10
- package/dist/modules/runtime/local-stdio.mjs +0 -106
- package/dist/modules/runtime/local-stdio.mjs.map +0 -7
- package/dist/modules/runtime/remote-acp.d.mts +0 -16
- package/dist/modules/runtime/remote-acp.mjs +0 -152
- package/dist/modules/runtime/remote-acp.mjs.map +0 -7
- package/dist/modules/runtime/remote-claude-code.d.mts +0 -5
- package/dist/modules/runtime/remote-claude-code.mjs +0 -47
- package/dist/modules/runtime/remote-claude-code.mjs.map +0 -7
- package/dist/modules/runtime/remote-codex.d.mts +0 -5
- package/dist/modules/runtime/remote-codex.mjs +0 -47
- package/dist/modules/runtime/remote-codex.mjs.map +0 -7
- package/dist/modules/runtime/remote-host.d.mts +0 -127
- package/dist/modules/runtime/remote-host.mjs +0 -387
- package/dist/modules/runtime/remote-host.mjs.map +0 -7
- package/dist/modules/runtime/remote-pi.d.mts +0 -5
- package/dist/modules/runtime/remote-pi.mjs +0 -44
- package/dist/modules/runtime/remote-pi.mjs.map +0 -7
- package/dist/modules/sandboxes/guide.d.mts +0 -35
- package/dist/modules/sandboxes/guide.mjs +0 -119
- package/dist/modules/sandboxes/guide.mjs.map +0 -7
- package/dist/modules/sandboxes/workspace-setup.d.mts +0 -42
- package/dist/modules/sandboxes/workspace-setup.mjs +0 -242
- package/dist/modules/sandboxes/workspace-setup.mjs.map +0 -7
- package/dist/modules/testing/harness.d.mts +0 -9
- package/dist/modules/testing/harness.mjs +0 -123
- package/dist/modules/testing/harness.mjs.map +0 -7
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
NetworkPolicy
|
|
3
|
-
} from "@finalai/agent-provider";
|
|
4
|
-
import { canonicalJson, sha256Hex } from "./bytes.mjs";
|
|
5
|
-
import {
|
|
6
|
-
computerParametersSchema,
|
|
7
|
-
computerTemplateSchema,
|
|
8
|
-
ComputerWorkspacePolicy
|
|
9
|
-
} from "./environment.mjs";
|
|
10
|
-
const ARTIFACT_KEY_VERSION = 1;
|
|
11
|
-
const PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION = 2;
|
|
12
|
-
const DEFAULT_COMPUTER_IMAGE = "lineage:sandbox";
|
|
13
|
-
const computerNeedsBuild = (inputs) => inputs.template.build.steps.length > 0 || inputs.template.build.verify.length > 0;
|
|
14
|
-
const computeComputerArtifactKey = async (inputs) => {
|
|
15
|
-
if (!computerNeedsBuild(inputs)) {
|
|
16
|
-
const hex2 = await sha256Hex(canonicalJson({ v: ARTIFACT_KEY_VERSION, image: inputs.image }));
|
|
17
|
-
return `img-${hex2.slice(0, 16)}`;
|
|
18
|
-
}
|
|
19
|
-
const hex = await sha256Hex(
|
|
20
|
-
canonicalJson({
|
|
21
|
-
v: ARTIFACT_KEY_VERSION,
|
|
22
|
-
image: inputs.image,
|
|
23
|
-
build: inputs.template.build,
|
|
24
|
-
diskGb: inputs.diskGb
|
|
25
|
-
})
|
|
26
|
-
);
|
|
27
|
-
return `pa-g${hex.slice(0, 16)}-c${PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION}`;
|
|
28
|
-
};
|
|
29
|
-
const toNetworkPolicy = (option) => {
|
|
30
|
-
if (option == null) return void 0;
|
|
31
|
-
if (option instanceof Object) return { mode: option.mode, allow: option.allow };
|
|
32
|
-
return { mode: option, allow: [] };
|
|
33
|
-
};
|
|
34
|
-
const mergeComputerParameters = (base, override) => {
|
|
35
|
-
const repositories = /* @__PURE__ */ new Map();
|
|
36
|
-
for (const repository of [...base.repositories ?? [], ...override.repositories ?? []]) {
|
|
37
|
-
repositories.set(repository.alias, repository);
|
|
38
|
-
}
|
|
39
|
-
return {
|
|
40
|
-
repositories: [...repositories.values()],
|
|
41
|
-
variables: [.../* @__PURE__ */ new Set([...base.variables ?? [], ...override.variables ?? []])],
|
|
42
|
-
workspace: override.workspace ?? base.workspace ?? ComputerWorkspacePolicy.Session,
|
|
43
|
-
networkPolicy: toNetworkPolicy(override.networkPolicy) ?? toNetworkPolicy(base.networkPolicy) ?? { mode: NetworkPolicy.AllowAll, allow: [] },
|
|
44
|
-
env: { ...base.env, ...override.env }
|
|
45
|
-
};
|
|
46
|
-
};
|
|
47
|
-
const fromVersion = (version, override) => {
|
|
48
|
-
const template = computerTemplateSchema.safeParse(version.templateConfig);
|
|
49
|
-
if (!template.success) {
|
|
50
|
-
throw new Error(
|
|
51
|
-
`computer setup guide ${version.slug} v${version.number} has an invalid template`
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
const defaults = computerParametersSchema.safeParse(version.defaultParameters);
|
|
55
|
-
if (!defaults.success) {
|
|
56
|
-
throw new Error(
|
|
57
|
-
`computer setup guide ${version.slug} v${version.number} has invalid default parameters`
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
image: version.image,
|
|
62
|
-
template: template.data,
|
|
63
|
-
parameters: mergeComputerParameters(defaults.data, override),
|
|
64
|
-
guide: {
|
|
65
|
-
guideId: version.guideId,
|
|
66
|
-
versionId: version.versionId,
|
|
67
|
-
slug: version.slug,
|
|
68
|
-
title: version.title,
|
|
69
|
-
number: version.number,
|
|
70
|
-
preparedArtifact: version.preparedArtifact
|
|
71
|
-
},
|
|
72
|
-
instructionsMarkdown: version.instructionsMarkdown
|
|
73
|
-
};
|
|
74
|
-
};
|
|
75
|
-
const imageOnly = (image, override) => ({
|
|
76
|
-
image,
|
|
77
|
-
template: computerTemplateSchema.parse({}),
|
|
78
|
-
parameters: mergeComputerParameters({ workspace: ComputerWorkspacePolicy.Ephemeral }, override),
|
|
79
|
-
guide: null,
|
|
80
|
-
instructionsMarkdown: null
|
|
81
|
-
});
|
|
82
|
-
const resolveComputerSpec = async (args) => {
|
|
83
|
-
const { options } = args;
|
|
84
|
-
if ("guide" in options) {
|
|
85
|
-
const version = await args.guides.get({
|
|
86
|
-
ref: options.guide.ref,
|
|
87
|
-
version: options.guide.version
|
|
88
|
-
});
|
|
89
|
-
if (version == null) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
`computer setup guide ${options.guide.ref}@${options.guide.version} was not found`
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
return fromVersion(version, options.parameters);
|
|
95
|
-
}
|
|
96
|
-
if ("inline" in options) {
|
|
97
|
-
return {
|
|
98
|
-
image: options.inline.image,
|
|
99
|
-
template: options.inline.template,
|
|
100
|
-
parameters: mergeComputerParameters(
|
|
101
|
-
{ repositories: options.inline.repositories, variables: options.inline.variables },
|
|
102
|
-
options.parameters
|
|
103
|
-
),
|
|
104
|
-
guide: null,
|
|
105
|
-
instructionsMarkdown: null
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
if ("image" in options) return imageOnly(options.image, options.parameters);
|
|
109
|
-
const fallback = await args.guides.default();
|
|
110
|
-
return fallback == null ? imageOnly(args.defaultImage, options.parameters) : fromVersion(fallback, options.parameters);
|
|
111
|
-
};
|
|
112
|
-
export {
|
|
113
|
-
DEFAULT_COMPUTER_IMAGE,
|
|
114
|
-
computeComputerArtifactKey,
|
|
115
|
-
computerNeedsBuild,
|
|
116
|
-
mergeComputerParameters,
|
|
117
|
-
resolveComputerSpec
|
|
118
|
-
};
|
|
119
|
-
//# sourceMappingURL=guide.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/sandboxes/guide.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n NetworkPolicy,\n type SandboxGuidesIface,\n type SandboxGuideVersionIface,\n} from '@finalai/agent-provider';\nimport { canonicalJson, sha256Hex } from \"./bytes.mjs\";\nimport {\n computerParametersSchema,\n computerTemplateSchema,\n ComputerWorkspacePolicy,\n type ComputerEnvironmentOptions,\n type ComputerNetworkPolicyOption,\n type ComputerParametersIface,\n type ComputerRepositoryIface,\n type ComputerTemplateIface,\n} from \"./environment.mjs\";\n\n// Computer setup guides: resolving a reference (or an inline guide) into the\n// build-time inputs that define the base and the start-time inputs applied per\n// computer.\n\n// One saved version (agent.computer_setup_guide_versions), as the platform\n// serves it to every provider through the contract's `guides` reader.\nexport type ComputerGuideVersionIface = SandboxGuideVersionIface;\n\nexport interface ResolvedNetworkPolicyIface {\n mode: NetworkPolicy;\n allow: string[];\n}\n\nexport interface ResolvedComputerParametersIface {\n repositories: ComputerRepositoryIface[];\n variables: string[];\n workspace: ComputerWorkspacePolicy;\n networkPolicy: ResolvedNetworkPolicyIface;\n env: Record<string, string>;\n}\n\nexport interface ResolvedComputerSpecIface {\n image: string;\n template: ComputerTemplateIface;\n parameters: ResolvedComputerParametersIface;\n guide: Pick<\n ComputerGuideVersionIface,\n 'guideId' | 'versionId' | 'slug' | 'title' | 'number' | 'preparedArtifact'\n > | null;\n instructionsMarkdown: string | null;\n}\n\n// Bumped when the meaning of the build inputs changes (forces rebuilds).\nconst ARTIFACT_KEY_VERSION = 1;\n// Part of a built base's key; bumping it rebuilds every guide's base.\nconst PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION = 2;\nexport const DEFAULT_COMPUTER_IMAGE = 'lineage:sandbox';\n\nexport interface ComputerBuildInputsIface {\n image: string;\n template: ComputerTemplateIface;\n diskGb: number | null;\n}\n\n// Build steps and verify steps are the only build-time inputs besides the image.\nexport const computerNeedsBuild = (inputs: Pick<ComputerBuildInputsIface, 'template'>): boolean =>\n inputs.template.build.steps.length > 0 || inputs.template.build.verify.length > 0;\n\n// The base's identity: a hash of the build-time inputs only (no guide id, no\n// start-time inputs), so identical guides share one base. B6 stores the same key in\n// computer_setup_guide_versions.build_artifact_key.\nexport const computeComputerArtifactKey = async (\n inputs: ComputerBuildInputsIface,\n): Promise<string> => {\n if (!computerNeedsBuild(inputs)) {\n const hex = await sha256Hex(canonicalJson({ v: ARTIFACT_KEY_VERSION, image: inputs.image }));\n return `img-${hex.slice(0, 16)}`;\n }\n const hex = await sha256Hex(\n canonicalJson({\n v: ARTIFACT_KEY_VERSION,\n image: inputs.image,\n build: inputs.template.build,\n diskGb: inputs.diskGb,\n }),\n );\n return `pa-g${hex.slice(0, 16)}-c${PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION}`;\n};\n\nconst toNetworkPolicy = (\n option: ComputerNetworkPolicyOption | undefined,\n): ResolvedNetworkPolicyIface | undefined => {\n if (option == null) return undefined;\n if (option instanceof Object) return { mode: option.mode, allow: option.allow };\n return { mode: option, allow: [] };\n};\n\n// Saved defaults overridden by the binding: repositories merge by alias, variables\n// union by name, env merges by key, scalars replace.\nexport const mergeComputerParameters = (\n base: ComputerParametersIface,\n override: ComputerParametersIface,\n): ResolvedComputerParametersIface => {\n const repositories = new Map<string, ComputerRepositoryIface>();\n for (const repository of [...(base.repositories ?? []), ...(override.repositories ?? [])]) {\n repositories.set(repository.alias, repository);\n }\n return {\n repositories: [...repositories.values()],\n variables: [...new Set([...(base.variables ?? []), ...(override.variables ?? [])])],\n workspace: override.workspace ?? base.workspace ?? ComputerWorkspacePolicy.Session,\n networkPolicy: toNetworkPolicy(override.networkPolicy) ??\n toNetworkPolicy(base.networkPolicy) ?? { mode: NetworkPolicy.AllowAll, allow: [] },\n env: { ...base.env, ...override.env },\n };\n};\n\nconst fromVersion = (\n version: ComputerGuideVersionIface,\n override: ComputerParametersIface,\n): ResolvedComputerSpecIface => {\n const template = computerTemplateSchema.safeParse(version.templateConfig);\n if (!template.success) {\n throw new Error(\n `computer setup guide ${version.slug} v${version.number} has an invalid template`,\n );\n }\n const defaults = computerParametersSchema.safeParse(version.defaultParameters);\n if (!defaults.success) {\n throw new Error(\n `computer setup guide ${version.slug} v${version.number} has invalid default parameters`,\n );\n }\n return {\n image: version.image,\n template: template.data,\n parameters: mergeComputerParameters(defaults.data, override),\n guide: {\n guideId: version.guideId,\n versionId: version.versionId,\n slug: version.slug,\n title: version.title,\n number: version.number,\n preparedArtifact: version.preparedArtifact,\n },\n instructionsMarkdown: version.instructionsMarkdown,\n };\n};\n\nconst imageOnly = (\n image: string,\n override: ComputerParametersIface,\n): ResolvedComputerSpecIface => ({\n image,\n template: computerTemplateSchema.parse({}),\n parameters: mergeComputerParameters({ workspace: ComputerWorkspacePolicy.Ephemeral }, override),\n guide: null,\n instructionsMarkdown: null,\n});\n\n// Guides come from the contract's `guides` reader (the session's organization).\nexport const resolveComputerSpec = async (args: {\n options: ComputerEnvironmentOptions;\n guides: SandboxGuidesIface;\n defaultImage: string;\n}): Promise<ResolvedComputerSpecIface> => {\n const { options } = args;\n if ('guide' in options) {\n const version = await args.guides.get({\n ref: options.guide.ref,\n version: options.guide.version,\n });\n if (version == null) {\n throw new Error(\n `computer setup guide ${options.guide.ref}@${options.guide.version} was not found`,\n );\n }\n return fromVersion(version, options.parameters);\n }\n if ('inline' in options) {\n return {\n image: options.inline.image,\n template: options.inline.template,\n parameters: mergeComputerParameters(\n { repositories: options.inline.repositories, variables: options.inline.variables },\n options.parameters,\n ),\n guide: null,\n instructionsMarkdown: null,\n };\n }\n if ('image' in options) return imageOnly(options.image, options.parameters);\n const fallback = await args.guides.default();\n return fallback == null\n ? imageOnly(args.defaultImage, options.parameters)\n : fromVersion(fallback, options.parameters);\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["hex"]
|
|
7
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import type { NetworkSandboxSessionIface, SandboxRepositoriesIface, SandboxRepositoryCloneSourceIface } from '@finalai/agent-provider/sandbox';
|
|
2
|
-
import { type ComputerRepositoryIface, type ComputerTemplateIface } from "./environment.mjs";
|
|
3
|
-
import type { SandboxTransportIface } from "./transport.mjs";
|
|
4
|
-
export declare const WORKSPACE_ROOT = "/workspaces";
|
|
5
|
-
export interface GuideCommandIface {
|
|
6
|
-
name: string;
|
|
7
|
-
path: string;
|
|
8
|
-
description: string | null;
|
|
9
|
-
cwd: string;
|
|
10
|
-
timeoutMs: number;
|
|
11
|
-
}
|
|
12
|
-
export declare const guideCommands: (template: ComputerTemplateIface) => Promise<GuideCommandIface[]>;
|
|
13
|
-
export declare const GUIDE_COMMAND_PROTOCOL = "guide-command-v1";
|
|
14
|
-
export declare const installGuideCommands: (args: {
|
|
15
|
-
sandbox: Pick<NetworkSandboxSessionIface, "run">;
|
|
16
|
-
template: ComputerTemplateIface;
|
|
17
|
-
}) => Promise<void>;
|
|
18
|
-
export type RepositoryCloneSourceIface = SandboxRepositoryCloneSourceIface;
|
|
19
|
-
export interface SetupLogIface {
|
|
20
|
-
(message: string, fields?: Record<string, string | number | boolean | null>): void;
|
|
21
|
-
}
|
|
22
|
-
export declare const repositoryPath: (alias: string) => string;
|
|
23
|
-
export declare const mountRepositories: (args: {
|
|
24
|
-
sandbox: NetworkSandboxSessionIface;
|
|
25
|
-
repositories: ComputerRepositoryIface[];
|
|
26
|
-
resolver: SandboxRepositoriesIface;
|
|
27
|
-
log: SetupLogIface;
|
|
28
|
-
}) => Promise<void>;
|
|
29
|
-
export declare const runWorkspaceSetup: (args: {
|
|
30
|
-
sandbox: NetworkSandboxSessionIface;
|
|
31
|
-
template: ComputerTemplateIface;
|
|
32
|
-
repositories: ComputerRepositoryIface[];
|
|
33
|
-
log: SetupLogIface;
|
|
34
|
-
}) => Promise<string | null>;
|
|
35
|
-
export declare const startServices: (args: {
|
|
36
|
-
sandbox: NetworkSandboxSessionIface;
|
|
37
|
-
transport: SandboxTransportIface;
|
|
38
|
-
template: ComputerTemplateIface;
|
|
39
|
-
env: Record<string, string>;
|
|
40
|
-
randomUuid: () => string;
|
|
41
|
-
log: SetupLogIface;
|
|
42
|
-
}) => Promise<string[]>;
|
|
@@ -1,242 +0,0 @@
|
|
|
1
|
-
import { canonicalJson, sha256Hex } from "./bytes.mjs";
|
|
2
|
-
import {
|
|
3
|
-
TemplateWhenMissing
|
|
4
|
-
} from "./environment.mjs";
|
|
5
|
-
import { shellQuote } from "./paths.mjs";
|
|
6
|
-
const WORKSPACE_ROOT = "/workspaces";
|
|
7
|
-
const SETUP_MARKER_ROOT = "/workspaces/.final/setup";
|
|
8
|
-
const guideCommands = async (template) => {
|
|
9
|
-
const hash = await sha256Hex(canonicalJson(template.commands));
|
|
10
|
-
return Object.entries(template.commands).map(([name, command]) => ({
|
|
11
|
-
name,
|
|
12
|
-
path: `${WORKSPACE_ROOT}/.final/commands/${hash}/${name}`,
|
|
13
|
-
description: command.description,
|
|
14
|
-
cwd: stepCwd(command.cwd),
|
|
15
|
-
timeoutMs: command.timeoutMinutes * 6e4
|
|
16
|
-
}));
|
|
17
|
-
};
|
|
18
|
-
const GUIDE_COMMAND_PROTOCOL = "guide-command-v1";
|
|
19
|
-
const INSTALL_GUIDE_COMMANDS_SCRIPT = `# ${GUIDE_COMMAND_PROTOCOL}
|
|
20
|
-
import json, os, stat, sys, uuid
|
|
21
|
-
p = json.load(sys.stdin)
|
|
22
|
-
flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
|
|
23
|
-
root = os.open('/', flags)
|
|
24
|
-
try:
|
|
25
|
-
for part in p['root'].split('/'):
|
|
26
|
-
if not part:
|
|
27
|
-
continue
|
|
28
|
-
if part in ('.', '..'):
|
|
29
|
-
raise ValueError('invalid command root')
|
|
30
|
-
try:
|
|
31
|
-
os.mkdir(part, dir_fd=root)
|
|
32
|
-
except FileExistsError:
|
|
33
|
-
pass
|
|
34
|
-
child = os.open(part, flags, dir_fd=root)
|
|
35
|
-
os.close(root)
|
|
36
|
-
root = child
|
|
37
|
-
for name, content in p['files'].items():
|
|
38
|
-
if '/' in name or name in ('.', '..'):
|
|
39
|
-
raise ValueError('invalid command name')
|
|
40
|
-
temporary = '.command-' + uuid.uuid4().hex
|
|
41
|
-
try:
|
|
42
|
-
fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o700, dir_fd=root)
|
|
43
|
-
with os.fdopen(fd, 'wb') as f:
|
|
44
|
-
f.write(content.encode('utf-8'))
|
|
45
|
-
try:
|
|
46
|
-
os.link(temporary, name, src_dir_fd=root, dst_dir_fd=root, follow_symlinks=False)
|
|
47
|
-
except FileExistsError:
|
|
48
|
-
fd = os.open(name, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK, dir_fd=root)
|
|
49
|
-
with os.fdopen(fd, 'rb') as f:
|
|
50
|
-
if not stat.S_ISREG(os.fstat(f.fileno()).st_mode) or f.read(len(content.encode('utf-8')) + 1) != content.encode('utf-8'):
|
|
51
|
-
raise ValueError('guide command differs from its pinned source')
|
|
52
|
-
finally:
|
|
53
|
-
os.unlink(temporary, dir_fd=root)
|
|
54
|
-
finally:
|
|
55
|
-
os.close(root)
|
|
56
|
-
`;
|
|
57
|
-
const installGuideCommands = async (args) => {
|
|
58
|
-
const commands = await guideCommands(args.template);
|
|
59
|
-
const first = commands[0];
|
|
60
|
-
if (first == null) return;
|
|
61
|
-
const files = {};
|
|
62
|
-
for (const command of commands) {
|
|
63
|
-
const source = args.template.commands[command.name];
|
|
64
|
-
if (source == null) throw new Error("guide command source is missing");
|
|
65
|
-
const missingExit = source.whenMissing === TemplateWhenMissing.Fail ? 1 : 0;
|
|
66
|
-
files[command.name] = `#!/bin/bash
|
|
67
|
-
set -eu
|
|
68
|
-
if [ ! -d ${shellQuote(command.cwd)} ]; then
|
|
69
|
-
printf '%s\\n' ${shellQuote(`guide command ${command.name}: missing ${command.cwd}`)} >&2
|
|
70
|
-
exit ${missingExit}
|
|
71
|
-
fi
|
|
72
|
-
cd -- ${shellQuote(command.cwd)}
|
|
73
|
-
exec timeout --signal=TERM --kill-after=10s ${source.timeoutMinutes * 60}s bash -c ${shellQuote(source.run)} ${shellQuote(command.name)} "$@"
|
|
74
|
-
`;
|
|
75
|
-
}
|
|
76
|
-
const result = await args.sandbox.run({
|
|
77
|
-
command: "python3",
|
|
78
|
-
args: ["-c", INSTALL_GUIDE_COMMANDS_SCRIPT],
|
|
79
|
-
cwd: "/",
|
|
80
|
-
stdin: JSON.stringify({ root: first.path.slice(0, first.path.lastIndexOf("/")), files }),
|
|
81
|
-
timeoutMs: 6e4
|
|
82
|
-
});
|
|
83
|
-
if (result.exitCode !== 0)
|
|
84
|
-
throw new Error(`guide command installation failed: ${result.stderr.trim().slice(-2e3)}`);
|
|
85
|
-
};
|
|
86
|
-
const isGitUrl = (value) => /^(https?:\/\/|ssh:\/\/|git@)/.test(value);
|
|
87
|
-
const repositoryPath = (alias) => `${WORKSPACE_ROOT}/${alias}`;
|
|
88
|
-
const stepCwd = (cwd) => cwd === "." ? WORKSPACE_ROOT : repositoryPath(cwd);
|
|
89
|
-
const runOrThrow = async (sandbox, label, options) => {
|
|
90
|
-
const result = await sandbox.run(options);
|
|
91
|
-
if (result.exitCode !== 0) {
|
|
92
|
-
throw new Error(
|
|
93
|
-
`${label} failed (exit ${result.exitCode}): ${result.stderr.trim().slice(-2e3)}`
|
|
94
|
-
);
|
|
95
|
-
}
|
|
96
|
-
};
|
|
97
|
-
const mountRepositories = async (args) => {
|
|
98
|
-
for (const repository of args.repositories) {
|
|
99
|
-
const destination = repositoryPath(repository.alias);
|
|
100
|
-
if (await args.sandbox.stat({ path: `${destination}/.git` }) != null) {
|
|
101
|
-
await runOrThrow(args.sandbox, `existing checkout ${repository.alias}`, {
|
|
102
|
-
command: `git -C ${shellQuote(destination)} rev-parse --verify HEAD`,
|
|
103
|
-
shell: true,
|
|
104
|
-
cwd: "/",
|
|
105
|
-
timeoutMs: 3e4
|
|
106
|
-
});
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
const source = await args.resolver.cloneSource({
|
|
110
|
-
repository: repository.repository,
|
|
111
|
-
ref: repository.ref
|
|
112
|
-
}) ?? (isGitUrl(repository.repository) ? { url: repository.repository, ref: repository.ref, authorization: null } : null);
|
|
113
|
-
if (source == null) {
|
|
114
|
-
throw new Error(
|
|
115
|
-
`repository ${repository.repository} (${repository.alias}) cannot be resolved to a clone source`
|
|
116
|
-
);
|
|
117
|
-
}
|
|
118
|
-
const env = source.authorization == null ? {} : {
|
|
119
|
-
GIT_CONFIG_COUNT: "1",
|
|
120
|
-
GIT_CONFIG_KEY_0: "http.extraHeader",
|
|
121
|
-
GIT_CONFIG_VALUE_0: `Authorization: ${source.authorization}`
|
|
122
|
-
};
|
|
123
|
-
const checkout = source.ref == null ? "" : ` && git -C ${shellQuote(destination)} checkout --quiet ${shellQuote(source.ref)}`;
|
|
124
|
-
args.log("computer_sandbox.repository_clone", { alias: repository.alias });
|
|
125
|
-
await runOrThrow(args.sandbox, `clone ${repository.alias}`, {
|
|
126
|
-
command: `set -eu; mkdir -p ${WORKSPACE_ROOT}; git clone --quiet -- ${shellQuote(source.url)} ${shellQuote(destination)}${checkout} && git -C ${shellQuote(destination)} rev-parse --verify HEAD`,
|
|
127
|
-
shell: true,
|
|
128
|
-
cwd: "/",
|
|
129
|
-
env: { GIT_TERMINAL_PROMPT: "0", ...env },
|
|
130
|
-
timeoutMs: 20 * 6e4
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
const aliasMissing = async (sandbox, cwd) => cwd !== "." && await sandbox.stat({ path: repositoryPath(cwd) }) == null;
|
|
135
|
-
const runWorkspaceSetup = async (args) => {
|
|
136
|
-
const steps = args.template.workspace.setup;
|
|
137
|
-
if (steps.length === 0) return null;
|
|
138
|
-
const hash = (await sha256Hex(
|
|
139
|
-
canonicalJson({
|
|
140
|
-
steps,
|
|
141
|
-
repositories: args.repositories.map((repository) => [
|
|
142
|
-
repository.alias,
|
|
143
|
-
repository.repository,
|
|
144
|
-
repository.ref
|
|
145
|
-
])
|
|
146
|
-
})
|
|
147
|
-
)).slice(0, 24);
|
|
148
|
-
const marker = `${SETUP_MARKER_ROOT}/${hash}`;
|
|
149
|
-
if (await args.sandbox.stat({ path: marker }) != null) return hash;
|
|
150
|
-
for (const [index, step] of steps.entries()) {
|
|
151
|
-
if (await aliasMissing(args.sandbox, step.cwd)) {
|
|
152
|
-
if (step.whenMissing === TemplateWhenMissing.Fail) {
|
|
153
|
-
throw new Error(
|
|
154
|
-
`workspace setup step ${index + 1} needs /workspaces/${step.cwd}, which is missing`
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
continue;
|
|
158
|
-
}
|
|
159
|
-
args.log("computer_sandbox.setup_step", { index });
|
|
160
|
-
try {
|
|
161
|
-
await runOrThrow(args.sandbox, `workspace setup step ${index + 1}`, {
|
|
162
|
-
command: `set -eu
|
|
163
|
-
${step.run}`,
|
|
164
|
-
shell: true,
|
|
165
|
-
cwd: stepCwd(step.cwd),
|
|
166
|
-
timeoutMs: step.timeoutMinutes * 6e4
|
|
167
|
-
});
|
|
168
|
-
} catch (error) {
|
|
169
|
-
if (step.required) throw error;
|
|
170
|
-
args.log("computer_sandbox.setup_step_failed", { index, required: false });
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
await args.sandbox.writeTextFile({ path: marker, content: (/* @__PURE__ */ new Date()).toISOString() });
|
|
174
|
-
return hash;
|
|
175
|
-
};
|
|
176
|
-
const readyScript = (url, timeoutSeconds) => `
|
|
177
|
-
end=$(( $(date +%s) + ${timeoutSeconds} ))
|
|
178
|
-
while :; do
|
|
179
|
-
code=$(curl -s -o /dev/null -w '%{http_code}' ${shellQuote(url)} || true)
|
|
180
|
-
if [ "$code" -ge 200 ] 2>/dev/null && [ "$code" -lt 500 ]; then exit 0; fi
|
|
181
|
-
if [ "$(date +%s)" -ge "$end" ]; then exit 1; fi
|
|
182
|
-
sleep 2
|
|
183
|
-
done`;
|
|
184
|
-
const startServices = async (args) => {
|
|
185
|
-
const started = [];
|
|
186
|
-
for (const service of args.template.services) {
|
|
187
|
-
if (await aliasMissing(args.sandbox, service.cwd)) {
|
|
188
|
-
if (service.whenMissing === TemplateWhenMissing.Fail) {
|
|
189
|
-
throw new Error(
|
|
190
|
-
`service ${service.name} needs /workspaces/${service.cwd}, which is missing`
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
continue;
|
|
194
|
-
}
|
|
195
|
-
await args.transport.exec({
|
|
196
|
-
id: args.randomUuid(),
|
|
197
|
-
command: `exec bash -lc ${shellQuote(service.run)}`,
|
|
198
|
-
cwd: stepCwd(service.cwd),
|
|
199
|
-
env: args.env,
|
|
200
|
-
timeoutMs: null
|
|
201
|
-
});
|
|
202
|
-
started.push(service.name);
|
|
203
|
-
args.log("computer_sandbox.service_started", { service: service.name });
|
|
204
|
-
}
|
|
205
|
-
await Promise.all(
|
|
206
|
-
args.template.services.filter((service) => service.ready != null && started.includes(service.name)).map(async (service) => {
|
|
207
|
-
const ready = service.ready;
|
|
208
|
-
if (ready == null) return;
|
|
209
|
-
const result = await args.sandbox.run({
|
|
210
|
-
command: readyScript(ready.url, ready.timeoutSeconds),
|
|
211
|
-
shell: true,
|
|
212
|
-
cwd: "/",
|
|
213
|
-
timeoutMs: (ready.timeoutSeconds + 30) * 1e3
|
|
214
|
-
});
|
|
215
|
-
if (result.exitCode === 0) {
|
|
216
|
-
args.log("computer_sandbox.service_ready", { service: service.name });
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
if (service.required) {
|
|
220
|
-
throw new Error(
|
|
221
|
-
`service ${service.name} was not ready at ${ready.url} within ${ready.timeoutSeconds} s`
|
|
222
|
-
);
|
|
223
|
-
}
|
|
224
|
-
args.log("computer_sandbox.service_ready_timeout", {
|
|
225
|
-
service: service.name,
|
|
226
|
-
required: false
|
|
227
|
-
});
|
|
228
|
-
})
|
|
229
|
-
);
|
|
230
|
-
return started;
|
|
231
|
-
};
|
|
232
|
-
export {
|
|
233
|
-
GUIDE_COMMAND_PROTOCOL,
|
|
234
|
-
WORKSPACE_ROOT,
|
|
235
|
-
guideCommands,
|
|
236
|
-
installGuideCommands,
|
|
237
|
-
mountRepositories,
|
|
238
|
-
repositoryPath,
|
|
239
|
-
runWorkspaceSetup,
|
|
240
|
-
startServices
|
|
241
|
-
};
|
|
242
|
-
//# sourceMappingURL=workspace-setup.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/sandboxes/workspace-setup.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n NetworkSandboxSessionIface,\n SandboxRepositoriesIface,\n SandboxRepositoryCloneSourceIface,\n} from '@finalai/agent-provider/sandbox';\nimport { canonicalJson, sha256Hex } from \"./bytes.mjs\";\nimport {\n TemplateWhenMissing,\n type ComputerRepositoryIface,\n type ComputerTemplateIface,\n} from \"./environment.mjs\";\nimport { shellQuote } from \"./paths.mjs\";\nimport type { SandboxTransportIface } from \"./transport.mjs\";\n\n// Start-time inputs: repositories, named commands, setup once per workspace and services.\n\nexport const WORKSPACE_ROOT = '/workspaces';\nconst SETUP_MARKER_ROOT = '/workspaces/.final/setup';\n\nexport interface GuideCommandIface {\n name: string;\n path: string;\n description: string | null;\n cwd: string;\n timeoutMs: number;\n}\n\nexport const guideCommands = async (\n template: ComputerTemplateIface,\n): Promise<GuideCommandIface[]> => {\n const hash = await sha256Hex(canonicalJson(template.commands));\n return Object.entries(template.commands).map(([name, command]) => ({\n name,\n path: `${WORKSPACE_ROOT}/.final/commands/${hash}/${name}`,\n description: command.description,\n cwd: stepCwd(command.cwd),\n timeoutMs: command.timeoutMinutes * 60_000,\n }));\n};\n\n// Pin directories and publish complete scripts without following workspace symlinks.\nexport const GUIDE_COMMAND_PROTOCOL = 'guide-command-v1';\nconst INSTALL_GUIDE_COMMANDS_SCRIPT = `# ${GUIDE_COMMAND_PROTOCOL}\nimport json, os, stat, sys, uuid\np = json.load(sys.stdin)\nflags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW\nroot = os.open('/', flags)\ntry:\n for part in p['root'].split('/'):\n if not part:\n continue\n if part in ('.', '..'):\n raise ValueError('invalid command root')\n try:\n os.mkdir(part, dir_fd=root)\n except FileExistsError:\n pass\n child = os.open(part, flags, dir_fd=root)\n os.close(root)\n root = child\n for name, content in p['files'].items():\n if '/' in name or name in ('.', '..'):\n raise ValueError('invalid command name')\n temporary = '.command-' + uuid.uuid4().hex\n try:\n fd = os.open(temporary, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o700, dir_fd=root)\n with os.fdopen(fd, 'wb') as f:\n f.write(content.encode('utf-8'))\n try:\n os.link(temporary, name, src_dir_fd=root, dst_dir_fd=root, follow_symlinks=False)\n except FileExistsError:\n fd = os.open(name, os.O_RDONLY | os.O_NOFOLLOW | os.O_NONBLOCK, dir_fd=root)\n with os.fdopen(fd, 'rb') as f:\n if not stat.S_ISREG(os.fstat(f.fileno()).st_mode) or f.read(len(content.encode('utf-8')) + 1) != content.encode('utf-8'):\n raise ValueError('guide command differs from its pinned source')\n finally:\n os.unlink(temporary, dir_fd=root)\nfinally:\n os.close(root)\n`;\n\nexport const installGuideCommands = async (args: {\n sandbox: Pick<NetworkSandboxSessionIface, 'run'>;\n template: ComputerTemplateIface;\n}): Promise<void> => {\n const commands = await guideCommands(args.template);\n const first = commands[0];\n if (first == null) return;\n const files: Record<string, string> = {};\n for (const command of commands) {\n const source = args.template.commands[command.name];\n if (source == null) throw new Error('guide command source is missing');\n const missingExit = source.whenMissing === TemplateWhenMissing.Fail ? 1 : 0;\n files[command.name] =\n `#!/bin/bash\\nset -eu\\nif [ ! -d ${shellQuote(command.cwd)} ]; then\\n printf '%s\\\\n' ${shellQuote(`guide command ${command.name}: missing ${command.cwd}`)} >&2\\n exit ${missingExit}\\nfi\\ncd -- ${shellQuote(command.cwd)}\\nexec timeout --signal=TERM --kill-after=10s ${source.timeoutMinutes * 60}s bash -c ${shellQuote(source.run)} ${shellQuote(command.name)} \"$@\"\\n`;\n }\n const result = await args.sandbox.run({\n command: 'python3',\n args: ['-c', INSTALL_GUIDE_COMMANDS_SCRIPT],\n cwd: '/',\n stdin: JSON.stringify({ root: first.path.slice(0, first.path.lastIndexOf('/')), files }),\n timeoutMs: 60_000,\n });\n if (result.exitCode !== 0)\n throw new Error(`guide command installation failed: ${result.stderr.trim().slice(-2000)}`);\n};\n\nexport type RepositoryCloneSourceIface = SandboxRepositoryCloneSourceIface;\n\nexport interface SetupLogIface {\n (message: string, fields?: Record<string, string | number | boolean | null>): void;\n}\n\nconst isGitUrl = (value: string): boolean => /^(https?:\\/\\/|ssh:\\/\\/|git@)/.test(value);\n\nexport const repositoryPath = (alias: string): string => `${WORKSPACE_ROOT}/${alias}`;\n\nconst stepCwd = (cwd: string): string => (cwd === '.' ? WORKSPACE_ROOT : repositoryPath(cwd));\n\nconst runOrThrow = async (\n sandbox: Pick<NetworkSandboxSessionIface, 'run'>,\n label: string,\n options: Parameters<NetworkSandboxSessionIface['run']>[0],\n): Promise<void> => {\n const result = await sandbox.run(options);\n if (result.exitCode !== 0) {\n throw new Error(\n `${label} failed (exit ${result.exitCode}): ${result.stderr.trim().slice(-2000)}`,\n );\n }\n};\n\nexport const mountRepositories = async (args: {\n sandbox: NetworkSandboxSessionIface;\n repositories: ComputerRepositoryIface[];\n // The contract's repository credentials (the start context's `repositories`).\n resolver: SandboxRepositoriesIface;\n log: SetupLogIface;\n}): Promise<void> => {\n for (const repository of args.repositories) {\n const destination = repositoryPath(repository.alias);\n if ((await args.sandbox.stat({ path: `${destination}/.git` })) != null) {\n await runOrThrow(args.sandbox, `existing checkout ${repository.alias}`, {\n command: `git -C ${shellQuote(destination)} rev-parse --verify HEAD`,\n shell: true,\n cwd: '/',\n timeoutMs: 30_000,\n });\n continue;\n }\n const source =\n (await args.resolver.cloneSource({\n repository: repository.repository,\n ref: repository.ref,\n })) ??\n (isGitUrl(repository.repository)\n ? { url: repository.repository, ref: repository.ref, authorization: null }\n : null);\n if (source == null) {\n throw new Error(\n `repository ${repository.repository} (${repository.alias}) cannot be resolved to a clone source`,\n );\n }\n // GIT_CONFIG_* applies the header for this process only.\n const env: Record<string, string> =\n source.authorization == null\n ? {}\n : {\n GIT_CONFIG_COUNT: '1',\n GIT_CONFIG_KEY_0: 'http.extraHeader',\n GIT_CONFIG_VALUE_0: `Authorization: ${source.authorization}`,\n };\n const checkout =\n source.ref == null\n ? ''\n : ` && git -C ${shellQuote(destination)} checkout --quiet ${shellQuote(source.ref)}`;\n args.log('computer_sandbox.repository_clone', { alias: repository.alias });\n await runOrThrow(args.sandbox, `clone ${repository.alias}`, {\n command: `set -eu; mkdir -p ${WORKSPACE_ROOT}; git clone --quiet -- ${shellQuote(source.url)} ${shellQuote(destination)}${checkout} && git -C ${shellQuote(destination)} rev-parse --verify HEAD`,\n shell: true,\n cwd: '/',\n env: { GIT_TERMINAL_PROMPT: '0', ...env },\n timeoutMs: 20 * 60_000,\n });\n }\n};\n\nconst aliasMissing = async (sandbox: NetworkSandboxSessionIface, cwd: string): Promise<boolean> =>\n cwd !== '.' && (await sandbox.stat({ path: repositoryPath(cwd) })) == null;\n\nexport const runWorkspaceSetup = async (args: {\n sandbox: NetworkSandboxSessionIface;\n template: ComputerTemplateIface;\n repositories: ComputerRepositoryIface[];\n log: SetupLogIface;\n}): Promise<string | null> => {\n const steps = args.template.workspace.setup;\n if (steps.length === 0) return null;\n const hash = (\n await sha256Hex(\n canonicalJson({\n steps,\n repositories: args.repositories.map((repository) => [\n repository.alias,\n repository.repository,\n repository.ref,\n ]),\n }),\n )\n ).slice(0, 24);\n const marker = `${SETUP_MARKER_ROOT}/${hash}`;\n if ((await args.sandbox.stat({ path: marker })) != null) return hash;\n for (const [index, step] of steps.entries()) {\n if (await aliasMissing(args.sandbox, step.cwd)) {\n if (step.whenMissing === TemplateWhenMissing.Fail) {\n throw new Error(\n `workspace setup step ${index + 1} needs /workspaces/${step.cwd}, which is missing`,\n );\n }\n continue;\n }\n args.log('computer_sandbox.setup_step', { index });\n try {\n await runOrThrow(args.sandbox, `workspace setup step ${index + 1}`, {\n command: `set -eu\\n${step.run}`,\n shell: true,\n cwd: stepCwd(step.cwd),\n timeoutMs: step.timeoutMinutes * 60_000,\n });\n } catch (error) {\n if (step.required) throw error;\n args.log('computer_sandbox.setup_step_failed', { index, required: false });\n }\n }\n await args.sandbox.writeTextFile({ path: marker, content: new Date().toISOString() });\n return hash;\n};\n\nconst readyScript = (url: string, timeoutSeconds: number): string => `\nend=$(( $(date +%s) + ${timeoutSeconds} ))\nwhile :; do\n code=$(curl -s -o /dev/null -w '%{http_code}' ${shellQuote(url)} || true)\n if [ \"$code\" -ge 200 ] 2>/dev/null && [ \"$code\" -lt 500 ]; then exit 0; fi\n if [ \"$(date +%s)\" -ge \"$end\" ]; then exit 1; fi\n sleep 2\ndone`;\n\n// Starts each service as a managed process (not followed, so nothing polls its\n// output) and waits for the required ones to answer their ready check.\nexport const startServices = async (args: {\n sandbox: NetworkSandboxSessionIface;\n transport: SandboxTransportIface;\n template: ComputerTemplateIface;\n env: Record<string, string>;\n randomUuid: () => string;\n log: SetupLogIface;\n}): Promise<string[]> => {\n const started: string[] = [];\n for (const service of args.template.services) {\n if (await aliasMissing(args.sandbox, service.cwd)) {\n if (service.whenMissing === TemplateWhenMissing.Fail) {\n throw new Error(\n `service ${service.name} needs /workspaces/${service.cwd}, which is missing`,\n );\n }\n continue;\n }\n await args.transport.exec({\n id: args.randomUuid(),\n command: `exec bash -lc ${shellQuote(service.run)}`,\n cwd: stepCwd(service.cwd),\n env: args.env,\n timeoutMs: null,\n });\n started.push(service.name);\n args.log('computer_sandbox.service_started', { service: service.name });\n }\n await Promise.all(\n args.template.services\n .filter((service) => service.ready != null && started.includes(service.name))\n .map(async (service) => {\n const ready = service.ready;\n if (ready == null) return;\n const result = await args.sandbox.run({\n command: readyScript(ready.url, ready.timeoutSeconds),\n shell: true,\n cwd: '/',\n timeoutMs: (ready.timeoutSeconds + 30) * 1000,\n });\n if (result.exitCode === 0) {\n args.log('computer_sandbox.service_ready', { service: service.name });\n return;\n }\n if (service.required) {\n throw new Error(\n `service ${service.name} was not ready at ${ready.url} within ${ready.timeoutSeconds} s`,\n );\n }\n args.log('computer_sandbox.service_ready_timeout', {\n service: service.name,\n required: false,\n });\n }),\n );\n return started;\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type OpenHarnessSessionArgsIface, type ResolvedAgentManifestIface, type SandboxTargetEndpointIface } from '@finalai/agent-provider';
|
|
2
|
-
export declare const SESSION_ID = "0192f7a0-0000-7000-8000-000000000001";
|
|
3
|
-
export declare const HARNESS_SESSION_ID = "0192f7a0-0000-7000-8000-0000000000aa";
|
|
4
|
-
export declare const EXPIRES_AT = "2026-10-10T00:15:00.000Z";
|
|
5
|
-
export declare const computerEndpoint: SandboxTargetEndpointIface;
|
|
6
|
-
export declare const deviceEndpoint: SandboxTargetEndpointIface;
|
|
7
|
-
export declare const resolvedManifest: () => ResolvedAgentManifestIface;
|
|
8
|
-
export declare const openArgs: (config: unknown, secrets?: Record<string, string>) => OpenHarnessSessionArgsIface;
|
|
9
|
-
export declare const idSequence: (prefix: string) => (() => string);
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
BaseCapability,
|
|
3
|
-
CredentialRoute,
|
|
4
|
-
credentials,
|
|
5
|
-
jsonObjectSchema,
|
|
6
|
-
MANIFEST_VERSION,
|
|
7
|
-
packageRef,
|
|
8
|
-
ToolApproval
|
|
9
|
-
} from "@finalai/agent-provider";
|
|
10
|
-
const SESSION_ID = "0192f7a0-0000-7000-8000-000000000001";
|
|
11
|
-
const HARNESS_SESSION_ID = "0192f7a0-0000-7000-8000-0000000000aa";
|
|
12
|
-
const EXPIRES_AT = "2026-10-10T00:15:00.000Z";
|
|
13
|
-
const computerEndpoint = {
|
|
14
|
-
target: "computer",
|
|
15
|
-
bindingId: "0192f7a0-0000-7000-8000-0000000000c1",
|
|
16
|
-
capabilities: ["shell", "files", "process"],
|
|
17
|
-
rpc: { url: "wss://agent-session.test/sandboxes/b/c1", token: "rpc-c1", expiresAt: EXPIRES_AT },
|
|
18
|
-
mcp: {
|
|
19
|
-
url: "https://agent-session.test/sandboxes/b/c1/mcp",
|
|
20
|
-
token: "mcp-c1",
|
|
21
|
-
expiresAt: EXPIRES_AT
|
|
22
|
-
}
|
|
23
|
-
};
|
|
24
|
-
const deviceEndpoint = {
|
|
25
|
-
target: "device",
|
|
26
|
-
bindingId: "0192f7a0-0000-7000-8000-0000000000d1",
|
|
27
|
-
capabilities: ["computerUse"],
|
|
28
|
-
rpc: null,
|
|
29
|
-
mcp: {
|
|
30
|
-
url: "https://agent-session.test/sandboxes/b/d1/mcp",
|
|
31
|
-
token: "mcp-d1",
|
|
32
|
-
expiresAt: EXPIRES_AT
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
const resolvedManifest = () => ({
|
|
36
|
-
version: MANIFEST_VERSION,
|
|
37
|
-
identity: { name: "Release Scout", description: null },
|
|
38
|
-
harness: {
|
|
39
|
-
harness: packageRef("@finalai/final-agent-provider/harnesses/serverless-pi"),
|
|
40
|
-
config: {}
|
|
41
|
-
},
|
|
42
|
-
mcpServers: [],
|
|
43
|
-
sandboxes: {},
|
|
44
|
-
tools: {
|
|
45
|
-
base: {
|
|
46
|
-
shell: { target: "computer" },
|
|
47
|
-
files: { target: "computer" },
|
|
48
|
-
computerUse: { target: "device" }
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
secrets: [],
|
|
52
|
-
toolPolicy: {
|
|
53
|
-
shell: ToolApproval.Ask,
|
|
54
|
-
"files.write": ToolApproval.Ask,
|
|
55
|
-
create_issue: ToolApproval.Allow
|
|
56
|
-
},
|
|
57
|
-
channels: [],
|
|
58
|
-
hooks: [],
|
|
59
|
-
schedules: [],
|
|
60
|
-
bundle: null
|
|
61
|
-
});
|
|
62
|
-
const openArgs = (config, secrets = {}) => ({
|
|
63
|
-
harnessSessionId: "0192f7a0-0000-7000-8000-0000000000a1",
|
|
64
|
-
session: {
|
|
65
|
-
sessionId: SESSION_ID,
|
|
66
|
-
organizationId: "0192f7a0-0000-7000-8000-0000000000o1",
|
|
67
|
-
definitionId: "0192f7a0-0000-7000-8000-0000000000e1",
|
|
68
|
-
revisionId: "0192f7a0-0000-7000-8000-0000000000r1",
|
|
69
|
-
sessionServiceUrl: "https://agent-session.test"
|
|
70
|
-
},
|
|
71
|
-
config: {
|
|
72
|
-
credentials: credentials.chain({
|
|
73
|
-
payer: "organization",
|
|
74
|
-
tryInOrder: [credentials.apiKey({ owner: "organization" }), credentials.platform()]
|
|
75
|
-
}),
|
|
76
|
-
...jsonObjectSchema.parse(config)
|
|
77
|
-
},
|
|
78
|
-
manifest: resolvedManifest(),
|
|
79
|
-
mcpServers: [],
|
|
80
|
-
baseTools: {
|
|
81
|
-
[BaseCapability.Shell]: computerEndpoint,
|
|
82
|
-
[BaseCapability.Files]: computerEndpoint,
|
|
83
|
-
[BaseCapability.ComputerUse]: deviceEndpoint
|
|
84
|
-
},
|
|
85
|
-
sandboxes: { computer: computerEndpoint, device: deviceEndpoint },
|
|
86
|
-
credentials: {
|
|
87
|
-
brokerUrl: "https://credentials.example.com/provider",
|
|
88
|
-
grants: [
|
|
89
|
-
{ route: CredentialRoute.Model, token: "grant-model", expiresAt: EXPIRES_AT },
|
|
90
|
-
{ route: CredentialRoute.Mcp, token: "grant-mcp", expiresAt: EXPIRES_AT }
|
|
91
|
-
],
|
|
92
|
-
atOpen: null,
|
|
93
|
-
refresh: {
|
|
94
|
-
url: "https://credentials.example.com/provider/refresh",
|
|
95
|
-
token: "grant-model",
|
|
96
|
-
harnessSessionId: "0192f7a0-0000-7000-8000-0000000000a1",
|
|
97
|
-
expiresAt: EXPIRES_AT
|
|
98
|
-
}
|
|
99
|
-
},
|
|
100
|
-
secrets: { get: async (name) => secrets[name] ?? null },
|
|
101
|
-
trace: {
|
|
102
|
-
traceparent: "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01",
|
|
103
|
-
tracestate: null
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
const idSequence = (prefix) => {
|
|
107
|
-
let next = 0;
|
|
108
|
-
return () => {
|
|
109
|
-
next += 1;
|
|
110
|
-
return `${prefix}-7000-8000-${String(next).padStart(12, "0")}`;
|
|
111
|
-
};
|
|
112
|
-
};
|
|
113
|
-
export {
|
|
114
|
-
EXPIRES_AT,
|
|
115
|
-
HARNESS_SESSION_ID,
|
|
116
|
-
SESSION_ID,
|
|
117
|
-
computerEndpoint,
|
|
118
|
-
deviceEndpoint,
|
|
119
|
-
idSequence,
|
|
120
|
-
openArgs,
|
|
121
|
-
resolvedManifest
|
|
122
|
-
};
|
|
123
|
-
//# sourceMappingURL=harness.mjs.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../../src/testing/harness.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n BaseCapability,\n CredentialRoute,\n credentials,\n jsonObjectSchema,\n MANIFEST_VERSION,\n packageRef,\n ToolApproval,\n type OpenHarnessSessionArgsIface,\n type ResolvedAgentManifestIface,\n type SandboxTargetEndpointIface,\n} from '@finalai/agent-provider';\n\n// Shared fixtures for the harness tests (no module mocks: fakes go in through\n// each factory's fetch/now/newId seams).\n\nexport const SESSION_ID = '0192f7a0-0000-7000-8000-000000000001';\nexport const HARNESS_SESSION_ID = '0192f7a0-0000-7000-8000-0000000000aa';\nexport const EXPIRES_AT = '2026-10-10T00:15:00.000Z';\n\nexport const computerEndpoint: SandboxTargetEndpointIface = {\n target: 'computer',\n bindingId: '0192f7a0-0000-7000-8000-0000000000c1',\n capabilities: ['shell', 'files', 'process'],\n rpc: { url: 'wss://agent-session.test/sandboxes/b/c1', token: 'rpc-c1', expiresAt: EXPIRES_AT },\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/c1/mcp',\n token: 'mcp-c1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const deviceEndpoint: SandboxTargetEndpointIface = {\n target: 'device',\n bindingId: '0192f7a0-0000-7000-8000-0000000000d1',\n capabilities: ['computerUse'],\n rpc: null,\n mcp: {\n url: 'https://agent-session.test/sandboxes/b/d1/mcp',\n token: 'mcp-d1',\n expiresAt: EXPIRES_AT,\n },\n};\n\nexport const resolvedManifest = (): ResolvedAgentManifestIface => ({\n version: MANIFEST_VERSION,\n identity: { name: 'Release Scout', description: null },\n harness: {\n harness: packageRef('@finalai/final-agent-provider/harnesses/serverless-pi'),\n config: {},\n },\n mcpServers: [],\n sandboxes: {},\n tools: {\n base: {\n shell: { target: 'computer' },\n files: { target: 'computer' },\n computerUse: { target: 'device' },\n },\n },\n secrets: [],\n toolPolicy: {\n shell: ToolApproval.Ask,\n 'files.write': ToolApproval.Ask,\n create_issue: ToolApproval.Allow,\n },\n channels: [],\n hooks: [],\n schedules: [],\n bundle: null,\n});\n\nexport const openArgs = (\n config: unknown,\n secrets: Record<string, string> = {},\n): OpenHarnessSessionArgsIface => ({\n harnessSessionId: '0192f7a0-0000-7000-8000-0000000000a1',\n session: {\n sessionId: SESSION_ID,\n organizationId: '0192f7a0-0000-7000-8000-0000000000o1',\n definitionId: '0192f7a0-0000-7000-8000-0000000000e1',\n revisionId: '0192f7a0-0000-7000-8000-0000000000r1',\n sessionServiceUrl: 'https://agent-session.test',\n },\n config: {\n credentials: credentials.chain({\n payer: 'organization',\n tryInOrder: [credentials.apiKey({ owner: 'organization' }), credentials.platform()],\n }),\n ...jsonObjectSchema.parse(config),\n },\n manifest: resolvedManifest(),\n mcpServers: [],\n baseTools: {\n [BaseCapability.Shell]: computerEndpoint,\n [BaseCapability.Files]: computerEndpoint,\n [BaseCapability.ComputerUse]: deviceEndpoint,\n },\n sandboxes: { computer: computerEndpoint, device: deviceEndpoint },\n credentials: {\n brokerUrl: 'https://credentials.example.com/provider',\n grants: [\n { route: CredentialRoute.Model, token: 'grant-model', expiresAt: EXPIRES_AT },\n { route: CredentialRoute.Mcp, token: 'grant-mcp', expiresAt: EXPIRES_AT },\n ],\n atOpen: null,\n refresh: {\n url: 'https://credentials.example.com/provider/refresh',\n token: 'grant-model',\n harnessSessionId: '0192f7a0-0000-7000-8000-0000000000a1',\n expiresAt: EXPIRES_AT,\n },\n },\n secrets: { get: async (name) => secrets[name] ?? null },\n trace: {\n traceparent: '00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01',\n tracestate: null,\n },\n});\n\n// Monotonic ids so assertions can name them.\nexport const idSequence = (prefix: string): (() => string) => {\n let next = 0;\n return () => {\n next += 1;\n return `${prefix}-7000-8000-${String(next).padStart(12, '0')}`;\n };\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|