Update formatting on worker
Build and Push Spoon Images / quality (push) Successful in 1m27s
Build and Push Spoon Images / build-images (push) Successful in 7m13s

This commit is contained in:
Gabriel Brown
2026-06-24 08:40:52 -04:00
parent 5f7d56369f
commit 65aae85369
11 changed files with 130 additions and 93 deletions
+50 -36
View File
@@ -1,3 +1,4 @@
import { randomBytes } from 'node:crypto';
import {
access,
mkdir,
@@ -7,7 +8,6 @@ import {
stat,
writeFile,
} from 'node:fs/promises';
import { randomBytes } from 'node:crypto';
import path from 'node:path';
import { ConvexHttpClient } from 'convex/browser';
@@ -15,6 +15,7 @@ import type { Id } from '@spoon/backend/convex/_generated/dataModel.js';
import { api } from '@spoon/backend/convex/_generated/api.js';
import type { NormalizedAgentEvent } from './agent-events';
import type { OpenCodeSession } from './opencode-session';
import { normalizeCodexJsonLine } from './agent-events';
import {
codexContainerRepo,
@@ -30,7 +31,6 @@ import {
run,
} from './git';
import { getInstallationToken, openDraftPullRequest } from './github';
import type { OpenCodeSession } from './opencode-session';
import {
abortOpenCodeSession,
createOpenCodeSession,
@@ -432,7 +432,7 @@ const opencodeModel = (claim: Claim) => {
const codexModel = (claim: Claim) => {
const model = claim.aiProviderProfile?.model ?? claim.openai.model;
return model.includes('/') ? model.split('/').at(-1) ?? model : model;
return model.includes('/') ? (model.split('/').at(-1) ?? model) : model;
};
const codexModelArgs = (claim: Claim) =>
@@ -531,8 +531,7 @@ const handleAgentEvent = async (args: {
return;
}
if (event.kind === 'tool_started' || event.kind === 'tool_completed') {
const detail =
event.kind === 'tool_started' ? event.input : event.output;
const detail = event.kind === 'tool_started' ? event.input : event.output;
await appendMessage({
jobId,
role: 'tool',
@@ -647,22 +646,25 @@ const ensureOpenCodeSession = async (workspace: ActiveWorkspace) => {
let lastError: unknown;
for (let attempt = 0; attempt < 20; attempt += 1) {
try {
const session = await createOpenCodeSession({
baseUrl,
const session = await createOpenCodeSession({
baseUrl,
password,
directory: '/workspace/repo',
title: workspace.claim.job.prompt.slice(0, 80) || 'Spoon workspace',
onEvent: async (event) => {
const messageId = workspaceCurrentMessage.get(workspace.claim.job._id);
const messageId = workspaceCurrentMessage.get(
workspace.claim.job._id,
);
if (!messageId) return;
await handleAgentEvent({
workspace,
event,
assistantMessageId: messageId,
assistantContent:
workspaceCurrentContent.get(workspace.claim.job._id) ?? {
value: '',
},
assistantContent: workspaceCurrentContent.get(
workspace.claim.job._id,
) ?? {
value: '',
},
});
},
});
@@ -1338,8 +1340,8 @@ const runClaim = async (claim: Claim) => {
await sendWorkspaceMessage(jobId, systemPromptForJob(claim), {
recordUserMessage: false,
});
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
} catch (error) {
const message = error instanceof Error ? error.message : String(error);
await appendEvent(
jobId,
'error',
@@ -1491,7 +1493,12 @@ export const abortWorkspaceAgent = async (jobId: string) => {
workspace.agentTurnActive = false;
workspace.resolveTurn?.();
workspace.resolveTurn = undefined;
await appendEvent(workspace.claim.job._id, 'warn', 'cleanup', 'Agent turn aborted.');
await appendEvent(
workspace.claim.job._id,
'warn',
'cleanup',
'Agent turn aborted.',
);
return { success: true };
}
if (workspace.runtimeMode === 'codex_exec') {
@@ -1605,15 +1612,22 @@ export const sendWorkspaceMessage = async (
const secretEnv = Object.fromEntries(
claim.secrets.map((secret) => [secret.name, secret.value]),
);
const result = await run('bash', ['-lc', `opencode run --format json --model ${quoteShell(opencodeModel(claim))} ${quoteShell(prompt)}`], {
cwd: workspace.repoDir,
env: {
...aiEnv,
...secretEnv,
const result = await run(
'bash',
[
'-lc',
`opencode run --format json --model ${quoteShell(opencodeModel(claim))} ${quoteShell(prompt)}`,
],
{
cwd: workspace.repoDir,
env: {
...aiEnv,
...secretEnv,
},
redact,
timeoutMs: env.jobTimeoutMs,
},
redact,
timeoutMs: env.jobTimeoutMs,
});
);
await updateMessage({
messageId: assistantMessageId,
status: result.exitCode === 0 ? 'completed' : 'failed',
@@ -1634,15 +1648,15 @@ export const sendWorkspaceMessage = async (
: 'Codex completed without producing an assistant response.',
);
}
await updateMessage({
messageId: assistantMessageId,
await updateMessage({
messageId: assistantMessageId,
status: 'completed',
content: assistantContent.value,
});
workspace.agentTurnActive = false;
}
workspace.agentTurnActive = false;
if (claim.job.jobType === 'maintenance_review') {
});
workspace.agentTurnActive = false;
}
workspace.agentTurnActive = false;
if (claim.job.jobType === 'maintenance_review') {
const decision = parseMaintenanceDecision(assistantContent.value);
if (decision) {
await addArtifact({
@@ -1660,7 +1674,7 @@ export const sendWorkspaceMessage = async (
});
}
}
const diff = await getWorktreeDiff(workspace.repoDir, redact);
const diff = await getWorktreeDiff(workspace.repoDir, redact);
await addArtifact({
jobId: claim.job._id,
kind: 'diff',
@@ -1669,11 +1683,11 @@ export const sendWorkspaceMessage = async (
contentType: 'text/x-diff',
});
await recordChangedFiles(workspace, 'agent', diff.output);
} catch (error) {
workspace.agentTurnActive = false;
workspace.resolveTurn?.();
workspace.resolveTurn = undefined;
const message = error instanceof Error ? error.message : String(error);
} catch (error) {
workspace.agentTurnActive = false;
workspace.resolveTurn?.();
workspace.resolveTurn = undefined;
const message = error instanceof Error ? error.message : String(error);
console.error(`Agent turn failed for job ${claim.job._id}: ${message}`);
await appendEvent(
claim.job._id,