切换 AgentRun 资源装配到 gitbundle
This commit is contained in:
@@ -6,26 +6,18 @@ export const DEFAULT_HWLAB_AGENTRUN_REPO_URL = "http://git-mirror-http.devops-in
|
||||
export const DEFAULT_HWLAB_AGENTRUN_BRANCH = "v0.2";
|
||||
export const DEFAULT_HWLAB_AGENTRUN_BACKEND_PROFILE = "deepseek";
|
||||
export const DEFAULT_UNIDESK_MAIN_SERVER_ENV = "UNIDESK_MAIN_SERVER_IP";
|
||||
export const DEFAULT_HWLAB_AGENTRUN_TOOL_ALIASES = Object.freeze([
|
||||
{ name: "hwpod", path: "tools/hwpod-cli.ts", kind: "bun-script" },
|
||||
{ name: "hwpod-ctl", path: "tools/hwpod-ctl.ts", kind: "bun-script" },
|
||||
{ name: "hwpod-compiler", path: "tools/hwpod-compiler-cli.ts", kind: "bun-script" },
|
||||
{ name: "unidesk-ssh", path: "tools/unidesk-ssh.mjs", kind: "bun-script" }
|
||||
export const DEFAULT_HWLAB_AGENTRUN_GIT_BUNDLES = Object.freeze([
|
||||
{ name: "hwlab-tools", subpath: "tools", target_path: "tools" },
|
||||
{ name: "hwlab-agent-skills", subpath: "skills", target_path: ".agents/skills" }
|
||||
]);
|
||||
export const DEFAULT_HWLAB_AGENTRUN_PROMPT_REFS = Object.freeze([
|
||||
{ name: "hwlab-v02-runtime", path: "internal/agent/prompts/hwlab-v02-runtime.md", inject: "thread-start", required: true }
|
||||
]);
|
||||
export const DEFAULT_HWLAB_AGENTRUN_SKILL_REFS = Object.freeze([
|
||||
{ name: "hwpod-cli", path: "skills/hwpod-cli/SKILL.md", required: true, aggregateAs: "hwpod-cli" },
|
||||
{ name: "hwpod-ctl", path: "skills/hwpod-ctl/SKILL.md", required: true, aggregateAs: "hwpod-ctl" },
|
||||
{ name: "hwlab-agent-runtime", path: "skills/hwlab-agent-runtime/SKILL.md", required: true, aggregateAs: "hwlab-agent-runtime" }
|
||||
]);
|
||||
|
||||
export function createHwlabAgentRunAssemblySummary(options = {}) {
|
||||
const env = options.env ?? process.env;
|
||||
const toolAliases = normalizeResourceToolAliases(options.toolAliases ?? DEFAULT_HWLAB_AGENTRUN_TOOL_ALIASES);
|
||||
const bundles = normalizeResourceGitBundles(options.bundles ?? DEFAULT_HWLAB_AGENTRUN_GIT_BUNDLES);
|
||||
const promptRefs = normalizeResourcePromptRefs(options.promptRefs ?? DEFAULT_HWLAB_AGENTRUN_PROMPT_REFS);
|
||||
const skillRefs = normalizeResourceSkillRefs(options.skillRefs ?? DEFAULT_HWLAB_AGENTRUN_SKILL_REFS);
|
||||
const promptAssembly = createPromptAssemblySummary(promptRefs);
|
||||
const repoUrl = optionalString(options.repoUrl ?? env.HWLAB_CODE_AGENT_AGENTRUN_REPO_URL ?? env.AGENTRUN_REPO_URL) ?? DEFAULT_HWLAB_AGENTRUN_REPO_URL;
|
||||
const branch = optionalString(options.branch ?? env.HWLAB_BOOT_REF ?? env.HWLAB_CODE_AGENT_AGENTRUN_BRANCH ?? env.AGENTRUN_BRANCH) ?? DEFAULT_HWLAB_AGENTRUN_BRANCH;
|
||||
@@ -33,26 +25,24 @@ export function createHwlabAgentRunAssemblySummary(options = {}) {
|
||||
const namespace = optionalString(options.namespace ?? env.AGENTRUN_RUNTIME_NAMESPACE ?? env.HWLAB_CODE_AGENT_AGENTRUN_NAMESPACE) ?? DEFAULT_AGENTRUN_NAMESPACE;
|
||||
const managerUrl = optionalString(options.managerUrl ?? env.HWLAB_CODE_AGENT_AGENTRUN_MGR_URL ?? env.AGENTRUN_MANAGER_URL) ?? DEFAULT_AGENTRUN_MANAGER_URL;
|
||||
return {
|
||||
status: skillRefs.length > 0 ? "ready" : "degraded",
|
||||
status: bundles.length > 0 ? "ready" : "degraded",
|
||||
provider: "agentrun-v01",
|
||||
namespace,
|
||||
managerUrl,
|
||||
resourceBundle: {
|
||||
kind: "git",
|
||||
kind: "gitbundle",
|
||||
repoUrl,
|
||||
branch,
|
||||
commitId,
|
||||
skillsDir: ".agents/skills"
|
||||
},
|
||||
counts: {
|
||||
toolAliases: toolAliases.length,
|
||||
promptRefs: promptRefs.length,
|
||||
skillRefs: skillRefs.length
|
||||
bundles: bundles.length,
|
||||
promptRefs: promptRefs.length
|
||||
},
|
||||
toolAliases: toolAliases.map((item) => ({ ...item })),
|
||||
bundles: bundles.map((item) => ({ ...item })),
|
||||
promptRefs: promptRefs.map((item) => ({ ...item })),
|
||||
promptAssembly,
|
||||
skillRefs: skillRefs.map((item) => ({ ...item })),
|
||||
runtimeEnv: {
|
||||
assembledRuntime: "HWLAB_CODE_AGENT_ASSEMBLED_RUNTIME",
|
||||
skillsDirs: "HWLAB_CODE_AGENT_SKILLS_DIRS"
|
||||
@@ -163,9 +153,8 @@ export function createHwlabAgentRunDispatchAssembly(options = {}) {
|
||||
const branch = nonEmptyString(options.branch ?? DEFAULT_HWLAB_AGENTRUN_BRANCH, "branch");
|
||||
const timeoutMs = positiveInteger(options.timeoutMs ?? 600000, "timeoutMs");
|
||||
const unideskMainServerIp = optionalString(options.unideskMainServerIp ?? env.UNIDESK_MAIN_SERVER_IP ?? env.UNIDESK_MAIN_SERVER_HOST);
|
||||
const toolAliases = normalizeResourceToolAliases(options.toolAliases ?? DEFAULT_HWLAB_AGENTRUN_TOOL_ALIASES);
|
||||
const bundles = normalizeResourceGitBundles(options.bundles ?? DEFAULT_HWLAB_AGENTRUN_GIT_BUNDLES);
|
||||
const promptRefs = normalizeResourcePromptRefs(options.promptRefs ?? DEFAULT_HWLAB_AGENTRUN_PROMPT_REFS);
|
||||
const skillRefs = normalizeResourceSkillRefs(options.skillRefs ?? DEFAULT_HWLAB_AGENTRUN_SKILL_REFS);
|
||||
if (includeUnideskSshToolCredential && !unideskMainServerIp) {
|
||||
throw new Error("unideskMainServerIp is required when UniDesk SSH passthrough is enabled");
|
||||
}
|
||||
@@ -178,14 +167,11 @@ export function createHwlabAgentRunDispatchAssembly(options = {}) {
|
||||
const transientEnv = normalizeTransientEnv(transientEnvWithUnideskMainServer(options.transientEnv ?? [], unideskMainServerIp));
|
||||
const sessionRef = createSessionRef(options);
|
||||
const resourceBundleRef = {
|
||||
kind: "git",
|
||||
kind: "gitbundle",
|
||||
repoUrl,
|
||||
commitId,
|
||||
...(options.subdir ? { subdir: nonEmptyString(options.subdir, "subdir") } : {}),
|
||||
...(Array.isArray(options.sparsePaths) ? { sparsePaths: options.sparsePaths.map((item, index) => nonEmptyString(item, `sparsePaths[${index}]`)) } : {}),
|
||||
...(toolAliases.length > 0 ? { toolAliases } : {}),
|
||||
bundles,
|
||||
...(promptRefs.length > 0 ? { promptRefs } : {}),
|
||||
...(skillRefs.length > 0 ? { skillRefs } : {}),
|
||||
...(options.resourceCredentialRef ? { credentialRef: options.resourceCredentialRef } : {})
|
||||
};
|
||||
|
||||
@@ -246,9 +232,8 @@ export function createHwlabAgentRunDispatchAssembly(options = {}) {
|
||||
githubCredentialSource: includeGithubToolCredential ? "toolCredentials" : null,
|
||||
unideskSshCredentialSource: includeUnideskSshToolCredential ? "toolCredentials" : null,
|
||||
unideskMainServerSource: unideskMainServerIp ? "transientEnv" : null,
|
||||
toolAliases: toolAliases.map((item) => item.name),
|
||||
bundles: bundles.map((item) => item.name),
|
||||
promptRefs: promptRefs.map((item) => item.name),
|
||||
skillRefs: skillRefs.map((item) => item.name),
|
||||
transientEnvNames: transientEnv.map((item) => item.name),
|
||||
forbiddenTransientEnvNames: AGENTRUN_REUSABLE_CREDENTIAL_ENV_NAMES.slice()
|
||||
}
|
||||
@@ -325,21 +310,19 @@ function normalizeToolCredentials(items) {
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeResourceToolAliases(items) {
|
||||
if (!Array.isArray(items)) throw new Error("toolAliases must be an array");
|
||||
const allowedKinds = new Set(["node-script", "bun-script", "sh-script", "executable"]);
|
||||
function normalizeResourceGitBundles(items) {
|
||||
if (!Array.isArray(items)) throw new Error("bundles must be an array");
|
||||
const seen = new Set();
|
||||
return items.map((item, index) => {
|
||||
if (!item || typeof item !== "object") throw new Error(`toolAliases[${index}] must be an object`);
|
||||
const name = nonEmptyString(item.name, `toolAliases[${index}].name`);
|
||||
const aliasPath = nonEmptyString(item.path, `toolAliases[${index}].path`);
|
||||
const kind = nonEmptyString(item.kind, `toolAliases[${index}].kind`);
|
||||
if (!/^[a-z][a-z0-9._-]{0,62}$/u.test(name)) throw new Error(`toolAliases[${index}].name must be a lowercase command name`);
|
||||
if (seen.has(name)) throw new Error(`toolAliases name ${name} is duplicated`);
|
||||
if (aliasPath.startsWith("/") || aliasPath.includes("..")) throw new Error(`toolAliases[${index}].path must stay within the checkout`);
|
||||
if (!allowedKinds.has(kind)) throw new Error(`toolAliases[${index}].kind is not supported`);
|
||||
if (!item || typeof item !== "object") throw new Error(`bundles[${index}] must be an object`);
|
||||
const name = resourceName(item.name, `bundles[${index}].name`);
|
||||
if (seen.has(name)) throw new Error(`bundles name ${name} is duplicated`);
|
||||
seen.add(name);
|
||||
return { name, path: aliasPath, kind };
|
||||
return {
|
||||
name,
|
||||
subpath: resourcePath(item.subpath, `bundles[${index}].subpath`),
|
||||
target_path: workspaceTargetPath(item.target_path ?? item.targetPath, `bundles[${index}].target_path`)
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
@@ -358,21 +341,6 @@ function normalizeResourcePromptRefs(items) {
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeResourceSkillRefs(items) {
|
||||
if (!Array.isArray(items)) throw new Error("skillRefs must be an array");
|
||||
const seen = new Set();
|
||||
return items.map((item, index) => {
|
||||
if (!item || typeof item !== "object") throw new Error(`skillRefs[${index}] must be an object`);
|
||||
const name = resourceName(item.name, `skillRefs[${index}].name`);
|
||||
if (seen.has(name)) throw new Error(`skillRefs name ${name} is duplicated`);
|
||||
seen.add(name);
|
||||
const refPath = resourcePath(item.path, `skillRefs[${index}].path`);
|
||||
if (!refPath.endsWith("SKILL.md")) throw new Error(`skillRefs[${index}].path must point to SKILL.md`);
|
||||
const aggregateAs = optionalString(item.aggregateAs);
|
||||
return { name, path: refPath, required: item.required !== false, ...(aggregateAs ? { aggregateAs: resourceName(aggregateAs, `skillRefs[${index}].aggregateAs`) } : {}) };
|
||||
});
|
||||
}
|
||||
|
||||
function resourceName(value, fieldName) {
|
||||
const name = nonEmptyString(value, fieldName);
|
||||
if (!/^[a-z][a-z0-9._-]{0,62}$/u.test(name)) throw new Error(`${fieldName} must be a lowercase resource name`);
|
||||
@@ -385,6 +353,12 @@ function resourcePath(value, fieldName) {
|
||||
return refPath;
|
||||
}
|
||||
|
||||
function workspaceTargetPath(value, fieldName) {
|
||||
const targetPath = nonEmptyString(value, fieldName);
|
||||
if (targetPath === "." || targetPath.startsWith("/") || targetPath.includes("..")) throw new Error(`${fieldName} must stay within the workspace`);
|
||||
return targetPath;
|
||||
}
|
||||
|
||||
async function postJson(fetchImpl, managerUrl, path, payload) {
|
||||
const response = await fetchImpl(`${managerUrl}${path}`, {
|
||||
method: "POST",
|
||||
|
||||
Reference in New Issue
Block a user