Spaces:
Sleeping
Sleeping
| function quoteToml(value) { | |
| return `"${String(value).replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`; | |
| } | |
| function json(value) { | |
| return JSON.stringify(value, null, 2); | |
| } | |
| function safeContextWindow(modelData) { | |
| return ( | |
| modelData?.gguf?.context_length ?? | |
| modelData?.config?.max_position_embeddings ?? | |
| modelData?.transformersInfo?.max_position_embeddings ?? | |
| 128000 | |
| ); | |
| } | |
| function safeMaxTokens(modelData) { | |
| const contextWindow = safeContextWindow(modelData); | |
| return Math.min(Math.max(4096, Math.floor(contextWindow / 8)), 32768); | |
| } | |
| function agentDisplayName(modelData) { | |
| return modelData.repoId.split("/").pop() ?? modelData.repoId; | |
| } | |
| export const AGENTS = { | |
| pi: { | |
| apiFormats: ["openai-completions"] | |
| }, | |
| openclaw: { | |
| apiFormats: ["openai-completions", "openai-responses", "anthropic-messages"] | |
| }, | |
| opencode: { | |
| apiFormats: ["openai-completions"] | |
| }, | |
| codex: { | |
| apiFormats: ["openai-responses"] | |
| }, | |
| claude: { | |
| apiFormats: ["anthropic-messages"] | |
| } | |
| }; | |
| export function assertAgentCompatibility(agent, runtime) { | |
| const descriptor = AGENTS[agent]; | |
| if (!descriptor) { | |
| throw new Error(`Unknown agent "${agent}".`); | |
| } | |
| if (!descriptor.apiFormats.includes(runtime.apiFormat)) { | |
| throw new Error( | |
| [ | |
| `Agent "${agent}" is incompatible with runtime "${runtime.key}".`, | |
| `Agent "${agent}" needs one of: ${descriptor.apiFormats.join(", ")}.`, | |
| `Runtime "${runtime.key}" exposes: ${runtime.apiFormat}.` | |
| ].join(" ") | |
| ); | |
| } | |
| } | |
| function renderPiArtifacts({ baseUrl, servedModelId, modelData }) { | |
| const content = { | |
| providers: { | |
| "hf-local": { | |
| baseUrl, | |
| api: "openai-completions", | |
| apiKey: "none", | |
| models: [ | |
| { | |
| id: servedModelId, | |
| contextWindow: safeContextWindow(modelData) | |
| } | |
| ] | |
| } | |
| } | |
| }; | |
| return { | |
| files: [ | |
| { | |
| name: "pi.models.json", | |
| targetPath: "~/.pi/agent/models.json", | |
| content: json(content) | |
| } | |
| ], | |
| cliCommands: [] | |
| }; | |
| } | |
| function renderOpenClawArtifacts({ baseUrl, servedModelId, modelData, runtime }) { | |
| const primaryRef = `hf-local/${servedModelId}`; | |
| const configFragment = { | |
| agents: { | |
| defaults: { | |
| model: { | |
| primary: primaryRef | |
| }, | |
| models: { | |
| [primaryRef]: { | |
| alias: agentDisplayName(modelData) | |
| } | |
| } | |
| } | |
| }, | |
| models: { | |
| mode: "merge", | |
| providers: { | |
| "hf-local": { | |
| baseUrl, | |
| apiKey: "none", | |
| api: runtime.apiFormat, | |
| models: [ | |
| { | |
| id: servedModelId, | |
| name: agentDisplayName(modelData), | |
| reasoning: false, | |
| input: ["text"], | |
| cost: { | |
| input: 0, | |
| output: 0, | |
| cacheRead: 0, | |
| cacheWrite: 0 | |
| }, | |
| contextWindow: safeContextWindow(modelData), | |
| maxTokens: safeMaxTokens(modelData) | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| }; | |
| const cliCommands = []; | |
| if (runtime.apiFormat === "openai-completions") { | |
| const onboardCommand = [ | |
| "openclaw onboard --non-interactive \\", | |
| " --auth-choice custom-api-key \\", | |
| ` --custom-base-url "${baseUrl}" \\`, | |
| ` --custom-model-id "${servedModelId}" \\`, | |
| ' --custom-api-key "hf-local" \\', | |
| ' --secret-input-mode plaintext \\', | |
| ' --custom-compatibility openai \\', | |
| " --accept-risk" | |
| ].join("\n"); | |
| cliCommands.push({ | |
| title: "openclaw onboard", | |
| content: onboardCommand | |
| }); | |
| } | |
| return { | |
| files: [ | |
| { | |
| name: "openclaw.config.json", | |
| targetPath: "merge into your OpenClaw config or agent models.json", | |
| content: json(configFragment) | |
| } | |
| ], | |
| cliCommands | |
| }; | |
| } | |
| function renderOpenCodeArtifacts({ baseUrl, servedModelId, modelData }) { | |
| const contextWindow = safeContextWindow(modelData); | |
| const outputTokens = safeMaxTokens(modelData); | |
| const content = { | |
| $schema: "https://opencode.ai/config.json", | |
| provider: { | |
| "hf-local": { | |
| npm: "@ai-sdk/openai-compatible", | |
| name: "HF Local", | |
| options: { | |
| baseURL: baseUrl, | |
| apiKey: "none" | |
| }, | |
| models: { | |
| [servedModelId]: { | |
| name: agentDisplayName(modelData), | |
| limit: { | |
| context: contextWindow, | |
| output: outputTokens | |
| } | |
| } | |
| } | |
| } | |
| }, | |
| model: `hf-local/${servedModelId}` | |
| }; | |
| return { | |
| files: [ | |
| { | |
| name: "opencode.json", | |
| targetPath: "~/.config/opencode/opencode.json", | |
| content: json(content) | |
| } | |
| ], | |
| cliCommands: [] | |
| }; | |
| } | |
| function renderCodexArtifacts({ baseUrl, servedModelId }) { | |
| const content = [ | |
| 'model_provider = "hf_local"', | |
| `model = ${quoteToml(servedModelId)}`, | |
| "", | |
| "[model_providers.hf_local]", | |
| 'name = "HF Local Responses"', | |
| `base_url = ${quoteToml(baseUrl)}`, | |
| 'wire_api = "responses"', | |
| "requires_openai_auth = false", | |
| "supports_websockets = false" | |
| ].join("\n"); | |
| return { | |
| files: [ | |
| { | |
| name: "codex.config.toml", | |
| targetPath: "~/.codex/config.toml", | |
| content | |
| } | |
| ], | |
| cliCommands: [] | |
| }; | |
| } | |
| function renderClaudeArtifacts({ baseUrl, servedModelId }) { | |
| const content = { | |
| model: servedModelId, | |
| env: { | |
| ANTHROPIC_BASE_URL: baseUrl, | |
| ANTHROPIC_MODEL: servedModelId, | |
| ANTHROPIC_CUSTOM_MODEL_OPTION: servedModelId, | |
| ANTHROPIC_CUSTOM_MODEL_OPTION_NAME: "HF Local", | |
| ANTHROPIC_CUSTOM_MODEL_OPTION_DESCRIPTION: "Gateway-routed Hugging Face local model" | |
| } | |
| }; | |
| return { | |
| files: [ | |
| { | |
| name: "claude.settings.json", | |
| targetPath: "~/.claude/settings.json", | |
| content: json(content) | |
| } | |
| ], | |
| cliCommands: [] | |
| }; | |
| } | |
| export function buildAgentArtifacts({ agent, runtime, baseUrl, servedModelId, modelData }) { | |
| assertAgentCompatibility(agent, runtime); | |
| if (!baseUrl) { | |
| throw new Error(`Agent "${agent}" requires a base URL, but runtime "${runtime.key}" does not define one. Pass --base-url.`); | |
| } | |
| if (agent === "pi") { | |
| return renderPiArtifacts({ baseUrl, servedModelId, modelData }); | |
| } | |
| if (agent === "openclaw") { | |
| return renderOpenClawArtifacts({ baseUrl, servedModelId, modelData, runtime }); | |
| } | |
| if (agent === "opencode") { | |
| return renderOpenCodeArtifacts({ baseUrl, servedModelId, modelData }); | |
| } | |
| if (agent === "codex") { | |
| return renderCodexArtifacts({ baseUrl, servedModelId }); | |
| } | |
| if (agent === "claude") { | |
| return renderClaudeArtifacts({ baseUrl, servedModelId }); | |
| } | |
| throw new Error(`Unknown agent "${agent}".`); | |
| } | |