diff --git a/packages/global/core/agentSkills/type.ts b/packages/global/core/agentSkills/type.ts index 6677e5065b..69b3a95202 100644 --- a/packages/global/core/agentSkills/type.ts +++ b/packages/global/core/agentSkills/type.ts @@ -192,7 +192,6 @@ export const SandboxInstanceDetailSchema = z.object({ skillIds: z.array(z.string()).optional(), provider: z.string(), image: SandboxImageConfigSchema, - providerStatus: SandboxProviderStatusSchema, providerCreatedAt: z.date(), endpoint: SkillSandboxEndpointSchema.optional(), storage: SandboxStorageSchema.optional(), diff --git a/packages/service/core/agentSkills/sandboxController.ts b/packages/service/core/agentSkills/sandboxController.ts index d98efd35ad..ccb218739c 100644 --- a/packages/service/core/agentSkills/sandboxController.ts +++ b/packages/service/core/agentSkills/sandboxController.ts @@ -161,6 +161,7 @@ export async function createEditDebugSandbox( ); const endpointInfo = await getProviderSandboxEndpoint(client.provider, defaults.targetPort); + const sandboxInfo = await client.provider.getInfo(); // Wait for the HTTP service inside the container to bind its port before // sending the ready SSE event — prevents ECONNREFUSED in the client iframe. @@ -171,7 +172,7 @@ export async function createEditDebugSandbox( { _id: existingInstance._id }, { 'metadata.endpoint': endpointInfo, - 'metadata.providerStatus': { state: 'Running' } + ...(sandboxInfo?.id && { 'metadata.providerSandboxId': sandboxInfo.id }) } ); @@ -311,13 +312,10 @@ export async function createEditDebugSandbox( teamId, tmbId, skillId, + sessionId, + providerSandboxId: sandboxInfo.id, // real sandbox ID for save-deploy connection provider: providerConfig.provider, image: sandboxInfo.image, - providerStatus: { - state: sandboxInfo.status.state, - message: sandboxInfo.status.message, - reason: sandboxInfo.status.reason - }, providerCreatedAt: sandboxInfo.createdAt, endpoint: endpointInfo, storage: { @@ -351,7 +349,7 @@ export async function createEditDebugSandbox( return { sandboxId: newSandboxDoc._id.toString(), - providerSandboxId: sandboxInfo.id, + providerSandboxId: sessionId, endpoint: endpointInfo, status: { state: sandboxInfo.status.state, @@ -544,6 +542,9 @@ export async function packageSkillInSandbox(params: { size: files[0].content.length }); + // Clean up the zip file after reading to free sandbox storage + await newSandbox.execute(`rm -f "${zipFilePath}"`); + const content = files[0].content; return Buffer.from(content instanceof Uint8Array ? content : Buffer.from(content, 'utf-8')); } catch (error) { diff --git a/packages/service/core/ai/sandbox/type.ts b/packages/service/core/ai/sandbox/type.ts index e2b0e93503..f9e678cf20 100644 --- a/packages/service/core/ai/sandbox/type.ts +++ b/packages/service/core/ai/sandbox/type.ts @@ -48,6 +48,7 @@ export const SandboxMetadataSchema = z.object({ skillId: z.string().optional(), sessionId: z.string().optional(), + providerSandboxId: z.string().optional(), // real provider sandbox ID (different from sessionId) skillIds: z.array(z.string()).optional(), image: SandboxImageSchema, endpoint: SandboxEndpointSchema.optional() diff --git a/packages/service/core/workflow/dispatch/ai/agent/sub/sandbox/lifecycle.ts b/packages/service/core/workflow/dispatch/ai/agent/sub/sandbox/lifecycle.ts index b8298c1896..309cfcaae7 100644 --- a/packages/service/core/workflow/dispatch/ai/agent/sub/sandbox/lifecycle.ts +++ b/packages/service/core/workflow/dispatch/ai/agent/sub/sandbox/lifecycle.ts @@ -338,11 +338,6 @@ export async function createAgentSandbox( skillIds: hasSkills ? deployableSkills.map((s) => s._id) : [], provider: providerConfig.provider, image: sandboxInfo.image, - providerStatus: { - state: sandboxInfo.status.state, - message: sandboxInfo.status.message, - reason: sandboxInfo.status.reason - }, providerCreatedAt: sandboxInfo.createdAt } } diff --git a/projects/app/Dockerfile b/projects/app/Dockerfile index 3252782309..8c97cf9644 100644 --- a/projects/app/Dockerfile +++ b/projects/app/Dockerfile @@ -45,6 +45,17 @@ ENV NODE_OPTIONS="--max-old-space-size=4096" ENV NEXT_PUBLIC_BASE_URL=$base_url RUN pnpm --filter=app build +# Bundle server.ts into a single CJS file; only 'next' is kept external (already in standalone output) +# Banner: mirrors what standalone server.js does — chdir to __dirname and load pre-serialized +# Next.js config so that next() skips webpack (config-utils) during startup. +RUN cd projects/app && ./node_modules/.bin/esbuild server.ts \ + --bundle \ + --platform=node \ + --format=cjs \ + --outfile=server-proxy.js \ + --external:next \ + '--banner:js=process.chdir(__dirname);try{const d=require("./.next/required-server-files.json");process.env.__NEXT_PRIVATE_STANDALONE_CONFIG=JSON.stringify(d.config);}catch(e){}' + # Remove build-time-only packages from standalone output before copying to runner. # These are traced into standalone by mistake (rspack bindings, gnu platform binaries, etc.) RUN rm -rf projects/app/.next/standalone/node_modules/.pnpm/@next+rspack-binding-*/ \ @@ -60,6 +71,8 @@ WORKDIR /app ARG proxy ARG base_url +ARG SHOW_SKILL=false +ENV SHOW_SKILL=$SHOW_SKILL # create user and use it RUN addgroup --system --gid 1001 nodejs @@ -78,6 +91,7 @@ COPY --from=builder --chown=nextjs:nodejs /app/projects/app/.next/static /app/pr COPY --from=builder --chown=nextjs:nodejs /app/projects/app/.next/server/chunks /app/projects/app/.next/server/chunks # copy worker COPY --from=builder --chown=nextjs:nodejs /app/projects/app/worker /app/projects/app/worker +COPY --from=builder --chown=nextjs:nodejs /app/projects/app/server-proxy.js /app/projects/app/server-proxy.js # copy standload packages COPY --from=maindeps /app/node_modules/tiktoken ./node_modules/tiktoken @@ -100,6 +114,4 @@ EXPOSE 3000 USER nextjs -ENV serverPath=./projects/app/server.js - -ENTRYPOINT ["sh","-c","node --max-old-space-size=4096 ${serverPath}"] +ENTRYPOINT ["sh","-c","if [ \"$SHOW_SKILL\" = \"true\" ]; then node --max-old-space-size=4096 ./projects/app/server-proxy.js; else node --max-old-space-size=4096 ./projects/app/server.js; fi"] diff --git a/projects/app/src/pages/api/core/agentSkills/save-deploy.ts b/projects/app/src/pages/api/core/agentSkills/save-deploy.ts index a51f1ebd56..b88ff0e87f 100644 --- a/projects/app/src/pages/api/core/agentSkills/save-deploy.ts +++ b/projects/app/src/pages/api/core/agentSkills/save-deploy.ts @@ -76,7 +76,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) let packageBuffer: Buffer; try { packageBuffer = await packageSkillInSandbox({ - providerSandboxId: sandboxInfo.sandboxId + providerSandboxId: sandboxInfo.metadata?.providerSandboxId ?? sandboxInfo.sandboxId }); } catch (error: any) { return jsonRes(res, { diff --git a/projects/app/test/api/core/agentSkills/debugChat.test.ts b/projects/app/test/api/core/agentSkills/debugChat.test.ts index 28f6138d71..2f1a51695d 100644 --- a/projects/app/test/api/core/agentSkills/debugChat.test.ts +++ b/projects/app/test/api/core/agentSkills/debugChat.test.ts @@ -318,7 +318,6 @@ describe('debugChat handler — parameter validation', () => { skillId, provider: 'opensandbox', image: { repository: 'test-image', tag: 'latest' }, - providerStatus: { state: 'running' }, providerCreatedAt: new Date() } }); diff --git a/test/cases/service/core/agentSkills/sandboxSchema.test.ts b/test/cases/service/core/agentSkills/sandboxSchema.test.ts index 70181b5547..6fd31faf13 100644 --- a/test/cases/service/core/agentSkills/sandboxSchema.test.ts +++ b/test/cases/service/core/agentSkills/sandboxSchema.test.ts @@ -24,9 +24,6 @@ describe('SandboxInstance Schema', () => { repository: 'node', tag: '18-alpine' }, - providerStatus: { - state: 'Running' - }, providerCreatedAt: new Date() } }; @@ -54,7 +51,6 @@ describe('SandboxInstance Schema', () => { tmbId: '507f1f77bcf86cd799439013', provider: 'opensandbox', image: { repository: 'node', tag: 'latest' }, - providerStatus: { state: 'Pending' }, providerCreatedAt: new Date() } }); @@ -79,7 +75,6 @@ describe('SandboxInstance Schema', () => { tmbId: '507f1f77bcf86cd799439013', provider: 'opensandbox', image: { repository: 'node' }, - providerStatus: { state: 'Running' }, providerCreatedAt: new Date() } }); @@ -122,7 +117,6 @@ describe('SandboxInstance Schema', () => { tmbId: '507f1f77bcf86cd799439013', provider: 'opensandbox', image: { repository: 'node' }, - providerStatus: { state: 'Running' }, providerCreatedAt: new Date(), endpoint: { host: 'localhost', @@ -158,7 +152,6 @@ describe('SandboxInstance Schema', () => { tmbId: '507f1f77bcf86cd799439013', provider: 'opensandbox', image: { repository: 'node' }, - providerStatus: { state: 'Succeeded' }, providerCreatedAt: new Date(), skillIds: ['507f1f77bcf86cd799439014', '507f1f77bcf86cd799439015'] }