fix(agent): pass IT0_AGENT_SERVICE_URL env var to openclaw container

supervisord uses %(ENV_IT0_AGENT_SERVICE_URL)s expansion which fails
if the var is not present, crashing the entire supervisor process.
Add AGENT_SERVICE_PUBLIC_URL config and inject it via docker run -e.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-08 05:01:55 -07:00
parent 3790284bc9
commit 90f11fc572
1 changed files with 28 additions and 6 deletions

View File

@ -26,6 +26,8 @@ interface DeployOptions {
userId: string; userId: string;
claudeApiKey: string; claudeApiKey: string;
openclawToken: string; openclawToken: string;
dingTalkClientId?: string;
dingTalkClientSecret?: string;
} }
@Injectable() @Injectable()
@ -34,6 +36,7 @@ export class AgentInstanceDeployService {
private readonly inventoryUrl: string; private readonly inventoryUrl: string;
private readonly internalApiKey: string; private readonly internalApiKey: string;
private readonly encKey: string; private readonly encKey: string;
private readonly agentServicePublicUrl: string;
constructor( constructor(
private readonly configService: ConfigService, private readonly configService: ConfigService,
@ -43,11 +46,17 @@ export class AgentInstanceDeployService {
this.inventoryUrl = this.configService.get<string>('INVENTORY_SERVICE_URL', 'http://inventory-service:3004'); this.inventoryUrl = this.configService.get<string>('INVENTORY_SERVICE_URL', 'http://inventory-service:3004');
this.internalApiKey = this.configService.get<string>('INTERNAL_API_KEY', ''); this.internalApiKey = this.configService.get<string>('INTERNAL_API_KEY', '');
this.encKey = this.configService.get<string>('VAULT_MASTER_KEY', 'dev-master-key'); this.encKey = this.configService.get<string>('VAULT_MASTER_KEY', 'dev-master-key');
this.agentServicePublicUrl = this.configService.get<string>('AGENT_SERVICE_PUBLIC_URL', '');
} }
// ── Public API ──────────────────────────────────────────────────────────── // ── Public API ────────────────────────────────────────────────────────────
async deployFromPool(instance: AgentInstance, claudeApiKey: string): Promise<void> { async deployFromPool(
instance: AgentInstance,
claudeApiKey: string,
dingTalkClientId?: string,
dingTalkClientSecret?: string,
): Promise<void> {
const server = await this.pickPoolServer(); const server = await this.pickPoolServer();
const creds = await this.fetchSshCreds(server.id); const creds = await this.fetchSshCreds(server.id);
const hostPort = await this.allocatePort(creds.host); const hostPort = await this.allocatePort(creds.host);
@ -58,7 +67,7 @@ export class AgentInstanceDeployService {
instance.hostPort = hostPort; instance.hostPort = hostPort;
instance.poolServerId = server.id; instance.poolServerId = server.id;
await this.runDeploy(instance, creds, claudeApiKey); await this.runDeploy(instance, creds, claudeApiKey, dingTalkClientId, dingTalkClientSecret);
await this.notifyPoolIncrement(server.id); await this.notifyPoolIncrement(server.id);
} }
@ -66,6 +75,8 @@ export class AgentInstanceDeployService {
instance: AgentInstance, instance: AgentInstance,
sshKey: string, sshKey: string,
claudeApiKey: string, claudeApiKey: string,
dingTalkClientId?: string,
dingTalkClientSecret?: string,
): Promise<void> { ): Promise<void> {
const creds: PoolServerCreds = { const creds: PoolServerCreds = {
id: '', id: '',
@ -77,7 +88,7 @@ export class AgentInstanceDeployService {
const hostPort = await this.allocatePort(creds.host); const hostPort = await this.allocatePort(creds.host);
instance.hostPort = hostPort; instance.hostPort = hostPort;
await this.runDeploy(instance, creds, claudeApiKey); await this.runDeploy(instance, creds, claudeApiKey, dingTalkClientId, dingTalkClientSecret);
} }
async stopInstance(instance: AgentInstance): Promise<void> { async stopInstance(instance: AgentInstance): Promise<void> {
@ -163,21 +174,32 @@ export class AgentInstanceDeployService {
instance: AgentInstance, instance: AgentInstance,
creds: PoolServerCreds, creds: PoolServerCreds,
claudeApiKey: string, claudeApiKey: string,
dingTalkClientId?: string,
dingTalkClientSecret?: string,
): Promise<void> { ): Promise<void> {
const token = crypto.randomBytes(32).toString('hex'); const token = crypto.randomBytes(32).toString('hex');
const { encrypted, iv } = this.encryptToken(token); const { encrypted, iv } = this.encryptToken(token);
instance.openclawToken = encrypted; instance.openclawToken = encrypted;
instance.openclawTokenIv = iv; instance.openclawTokenIv = iv;
const envParts = [
`-e OPENCLAW_GATEWAY_TOKEN=${token}`,
`-e IT0_INSTANCE_ID=${instance.id}`,
`-e CLAUDE_API_KEY=${claudeApiKey}`,
`-e IT0_AGENT_SERVICE_URL=${this.agentServicePublicUrl}`,
];
if (dingTalkClientId && dingTalkClientSecret) {
envParts.push(`-e DINGTALK_CLIENT_ID=${dingTalkClientId}`);
envParts.push(`-e DINGTALK_CLIENT_SECRET=${dingTalkClientSecret}`);
}
const cmd = [ const cmd = [
'docker run -d', 'docker run -d',
`--name ${instance.containerName}`, `--name ${instance.containerName}`,
`--restart unless-stopped`, `--restart unless-stopped`,
`-p ${instance.hostPort}:3000`, `-p ${instance.hostPort}:3000`,
`-v /data/openclaw/${instance.id}:/home/node/.openclaw`, `-v /data/openclaw/${instance.id}:/home/node/.openclaw`,
`-e OPENCLAW_GATEWAY_TOKEN=${token}`, ...envParts,
`-e IT0_INSTANCE_ID=${instance.id}`,
`-e CLAUDE_API_KEY=${claudeApiKey}`,
OPENCLAW_IMAGE, OPENCLAW_IMAGE,
].join(' '); ].join(' ');