mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-19 02:01:37 +00:00
Fix Foundry validation fallout
This commit is contained in:
parent
13fc9cb318
commit
aa332307e5
11 changed files with 25 additions and 7 deletions
|
|
@ -138,6 +138,7 @@ function pullRequestSummaryFromRow(row: any) {
|
||||||
repoId: row.repoId,
|
repoId: row.repoId,
|
||||||
repoFullName: row.repoFullName,
|
repoFullName: row.repoFullName,
|
||||||
number: row.number,
|
number: row.number,
|
||||||
|
status: Boolean(row.isDraft) ? "draft" : "ready",
|
||||||
title: row.title,
|
title: row.title,
|
||||||
state: row.state,
|
state: row.state,
|
||||||
url: row.url,
|
url: row.url,
|
||||||
|
|
|
||||||
|
|
@ -1089,6 +1089,7 @@ export const organizationAppActions = {
|
||||||
},
|
},
|
||||||
pullRequest: {
|
pullRequest: {
|
||||||
number: body.pull_request.number,
|
number: body.pull_request.number,
|
||||||
|
status: body.pull_request.draft ? "draft" : "ready",
|
||||||
title: body.pull_request.title ?? "",
|
title: body.pull_request.title ?? "",
|
||||||
body: body.pull_request.body ?? null,
|
body: body.pull_request.body ?? null,
|
||||||
state: body.pull_request.state ?? "open",
|
state: body.pull_request.state ?? "open",
|
||||||
|
|
|
||||||
|
|
@ -1378,6 +1378,7 @@ export async function publishWorkspacePr(c: any): Promise<void> {
|
||||||
});
|
});
|
||||||
await syncTaskPullRequest(c, {
|
await syncTaskPullRequest(c, {
|
||||||
number: created.number,
|
number: created.number,
|
||||||
|
status: "ready",
|
||||||
title: record.title ?? record.task,
|
title: record.title ?? record.task,
|
||||||
body: null,
|
body: null,
|
||||||
state: "open",
|
state: "open",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import type {
|
||||||
CreateTaskInput,
|
CreateTaskInput,
|
||||||
AppEvent,
|
AppEvent,
|
||||||
SessionEvent,
|
SessionEvent,
|
||||||
|
SandboxProcessSnapshot,
|
||||||
SandboxProcessesEvent,
|
SandboxProcessesEvent,
|
||||||
TaskRecord,
|
TaskRecord,
|
||||||
TaskSummary,
|
TaskSummary,
|
||||||
|
|
@ -40,7 +41,7 @@ import type {
|
||||||
WorkspaceModelGroup,
|
WorkspaceModelGroup,
|
||||||
WorkspaceModelId,
|
WorkspaceModelId,
|
||||||
} from "@sandbox-agent/foundry-shared";
|
} from "@sandbox-agent/foundry-shared";
|
||||||
import type { ProcessCreateRequest, ProcessInfo, ProcessLogFollowQuery, ProcessLogsResponse, ProcessSignalQuery } from "sandbox-agent";
|
import type { ProcessCreateRequest, ProcessLogFollowQuery, ProcessLogsResponse, ProcessSignalQuery } from "sandbox-agent";
|
||||||
import { createMockBackendClient } from "./mock/backend-client.js";
|
import { createMockBackendClient } from "./mock/backend-client.js";
|
||||||
import { taskKey, taskSandboxKey, organizationKey } from "./keys.js";
|
import { taskKey, taskSandboxKey, organizationKey } from "./keys.js";
|
||||||
|
|
||||||
|
|
@ -66,7 +67,7 @@ export interface SandboxSessionEventRecord {
|
||||||
payload: unknown;
|
payload: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SandboxProcessRecord = ProcessInfo;
|
export type SandboxProcessRecord = SandboxProcessSnapshot;
|
||||||
|
|
||||||
export interface ActorConn {
|
export interface ActorConn {
|
||||||
on(event: string, listener: (payload: any) => void): () => void;
|
on(event: string, listener: (payload: any) => void): () => void;
|
||||||
|
|
|
||||||
|
|
@ -142,6 +142,7 @@ class MockWorkspaceStore implements TaskWorkspaceClient {
|
||||||
updatedAtMs: nowMs(),
|
updatedAtMs: nowMs(),
|
||||||
pullRequest: {
|
pullRequest: {
|
||||||
number: nextPrNumber,
|
number: nextPrNumber,
|
||||||
|
status: "ready",
|
||||||
title: task.title,
|
title: task.title,
|
||||||
state: "open",
|
state: "open",
|
||||||
url: `https://example.test/pr/${nextPrNumber}`,
|
url: `https://example.test/pr/${nextPrNumber}`,
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,7 @@ function buildPullRequestSummary(params: {
|
||||||
}) {
|
}) {
|
||||||
return {
|
return {
|
||||||
number: params.number,
|
number: params.number,
|
||||||
|
status: params.status,
|
||||||
title: params.title,
|
title: params.title,
|
||||||
state: "open",
|
state: "open",
|
||||||
url: `https://github.com/${params.repoName}/pull/${params.number}`,
|
url: `https://github.com/${params.repoName}/pull/${params.number}`,
|
||||||
|
|
|
||||||
|
|
@ -132,11 +132,11 @@ describe("e2e(client): full integration stack workflow", () => {
|
||||||
90_000,
|
90_000,
|
||||||
1_000,
|
1_000,
|
||||||
async () => client.getRepoOverview(organizationId, repo.repoId),
|
async () => client.getRepoOverview(organizationId, repo.repoId),
|
||||||
(value) => value.branches.some((row) => row.branchName === seededBranch),
|
(value) => value.branches.some((row: RepoOverview["branches"][number]) => row.branchName === seededBranch),
|
||||||
);
|
);
|
||||||
|
|
||||||
const postActionOverview = await client.getRepoOverview(organizationId, repo.repoId);
|
const postActionOverview = await client.getRepoOverview(organizationId, repo.repoId);
|
||||||
const seededRow = postActionOverview.branches.find((row) => row.branchName === seededBranch);
|
const seededRow = postActionOverview.branches.find((row: RepoOverview["branches"][number]) => row.branchName === seededBranch);
|
||||||
expect(Boolean(seededRow)).toBe(true);
|
expect(Boolean(seededRow)).toBe(true);
|
||||||
expect(postActionOverview.fetchedAt).toBeGreaterThanOrEqual(overview.fetchedAt);
|
expect(postActionOverview.fetchedAt).toBeGreaterThanOrEqual(overview.fetchedAt);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
|
|
@ -176,27 +176,32 @@ describe("e2e(client): workspace flows", () => {
|
||||||
expect(transcriptIncludesAgentText(findTab(initialCompleted, primaryTab.id).transcript, expectedInitialReply)).toBe(true);
|
expect(transcriptIncludesAgentText(findTab(initialCompleted, primaryTab.id).transcript, expectedInitialReply)).toBe(true);
|
||||||
|
|
||||||
await client.renameWorkspaceTask(organizationId, {
|
await client.renameWorkspaceTask(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
value: `Workspace E2E ${runId} Renamed`,
|
value: `Workspace E2E ${runId} Renamed`,
|
||||||
});
|
});
|
||||||
await client.renameWorkspaceSession(organizationId, {
|
await client.renameWorkspaceSession(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
sessionId: primaryTab.id,
|
sessionId: primaryTab.id,
|
||||||
title: "Primary Session",
|
title: "Primary Session",
|
||||||
});
|
});
|
||||||
|
|
||||||
const secondTab = await client.createWorkspaceSession(organizationId, {
|
const secondTab = await client.createWorkspaceSession(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
model,
|
model,
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.renameWorkspaceSession(organizationId, {
|
await client.renameWorkspaceSession(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
sessionId: secondTab.sessionId,
|
sessionId: secondTab.sessionId,
|
||||||
title: "Follow-up Session",
|
title: "Follow-up Session",
|
||||||
});
|
});
|
||||||
|
|
||||||
await client.updateWorkspaceDraft(organizationId, {
|
await client.updateWorkspaceDraft(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
sessionId: secondTab.sessionId,
|
sessionId: secondTab.sessionId,
|
||||||
text: [
|
text: [
|
||||||
|
|
@ -219,6 +224,7 @@ describe("e2e(client): workspace flows", () => {
|
||||||
expect(findTab(drafted, secondTab.sessionId).draft.attachments).toHaveLength(1);
|
expect(findTab(drafted, secondTab.sessionId).draft.attachments).toHaveLength(1);
|
||||||
|
|
||||||
await client.sendWorkspaceMessage(organizationId, {
|
await client.sendWorkspaceMessage(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
sessionId: secondTab.sessionId,
|
sessionId: secondTab.sessionId,
|
||||||
text: [
|
text: [
|
||||||
|
|
@ -254,16 +260,18 @@ describe("e2e(client): workspace flows", () => {
|
||||||
expect(withSecondReply.fileChanges.some((file) => file.path === expectedFile)).toBe(true);
|
expect(withSecondReply.fileChanges.some((file) => file.path === expectedFile)).toBe(true);
|
||||||
|
|
||||||
await client.setWorkspaceSessionUnread(organizationId, {
|
await client.setWorkspaceSessionUnread(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
sessionId: secondTab.sessionId,
|
sessionId: secondTab.sessionId,
|
||||||
unread: false,
|
unread: false,
|
||||||
});
|
});
|
||||||
await client.markWorkspaceUnread(organizationId, { taskId: created.taskId });
|
await client.markWorkspaceUnread(organizationId, { repoId: repo.repoId, taskId: created.taskId });
|
||||||
|
|
||||||
const unreadSnapshot = findTask(await client.getWorkspace(organizationId), created.taskId);
|
const unreadSnapshot = findTask(await client.getWorkspace(organizationId), created.taskId);
|
||||||
expect(unreadSnapshot.sessions.some((tab) => tab.unread)).toBe(true);
|
expect(unreadSnapshot.sessions.some((tab) => tab.unread)).toBe(true);
|
||||||
|
|
||||||
await client.closeWorkspaceSession(organizationId, {
|
await client.closeWorkspaceSession(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
sessionId: secondTab.sessionId,
|
sessionId: secondTab.sessionId,
|
||||||
});
|
});
|
||||||
|
|
@ -278,6 +286,7 @@ describe("e2e(client): workspace flows", () => {
|
||||||
expect(closedSnapshot.sessions).toHaveLength(1);
|
expect(closedSnapshot.sessions).toHaveLength(1);
|
||||||
|
|
||||||
await client.revertWorkspaceFile(organizationId, {
|
await client.revertWorkspaceFile(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
path: expectedFile,
|
path: expectedFile,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -245,12 +245,14 @@ describe("e2e(client): workspace load", () => {
|
||||||
const expectedReply = `LOAD_REPLY_${runId}_${sessionIndex}`;
|
const expectedReply = `LOAD_REPLY_${runId}_${sessionIndex}`;
|
||||||
const createSessionStartedAt = performance.now();
|
const createSessionStartedAt = performance.now();
|
||||||
const createdSession = await client.createWorkspaceSession(organizationId, {
|
const createdSession = await client.createWorkspaceSession(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
model,
|
model,
|
||||||
});
|
});
|
||||||
createSessionLatencies.push(performance.now() - createSessionStartedAt);
|
createSessionLatencies.push(performance.now() - createSessionStartedAt);
|
||||||
|
|
||||||
await client.sendWorkspaceMessage(organizationId, {
|
await client.sendWorkspaceMessage(organizationId, {
|
||||||
|
repoId: repo.repoId,
|
||||||
taskId: created.taskId,
|
taskId: created.taskId,
|
||||||
sessionId: createdSession.sessionId,
|
sessionId: createdSession.sessionId,
|
||||||
text: `Run pwd in the repo, then reply with exactly: ${expectedReply}`,
|
text: `Run pwd in the repo, then reply with exactly: ${expectedReply}`,
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ export type CreateTaskInput = z.infer<typeof CreateTaskInputSchema>;
|
||||||
|
|
||||||
export const WorkspacePullRequestSummarySchema = z.object({
|
export const WorkspacePullRequestSummarySchema = z.object({
|
||||||
number: z.number().int(),
|
number: z.number().int(),
|
||||||
|
status: z.enum(["draft", "ready"]),
|
||||||
title: z.string().min(1),
|
title: z.string().min(1),
|
||||||
state: z.string().min(1),
|
state: z.string().min(1),
|
||||||
url: z.string().min(1),
|
url: z.string().min(1),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { pino, type Logger, type LoggerOptions } from "pino";
|
import { pino, type LogFn, type Logger, type LoggerOptions } from "pino";
|
||||||
|
|
||||||
export interface FoundryLoggerOptions {
|
export interface FoundryLoggerOptions {
|
||||||
service: string;
|
service: string;
|
||||||
|
|
@ -160,7 +160,7 @@ export function createFoundryLogger(options: FoundryLoggerOptions): Logger {
|
||||||
loggerOptions.timestamp = pino.stdTimeFunctions.isoTime;
|
loggerOptions.timestamp = pino.stdTimeFunctions.isoTime;
|
||||||
if (options.format === "logfmt") {
|
if (options.format === "logfmt") {
|
||||||
loggerOptions.hooks = {
|
loggerOptions.hooks = {
|
||||||
logMethod(this: Logger, args, _method, level) {
|
logMethod(this: Logger, args: Parameters<LogFn>, _method: LogFn, level: number) {
|
||||||
const levelLabel = this.levels.labels[level] ?? "info";
|
const levelLabel = this.levels.labels[level] ?? "info";
|
||||||
const record = buildLogRecord(levelLabel, this.bindings(), args);
|
const record = buildLogRecord(levelLabel, this.bindings(), args);
|
||||||
writeLogfmtLine(formatLogfmtLine(record));
|
writeLogfmtLine(formatLogfmtLine(record));
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue