chore: import upstream snapshot with attribution
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Has been cancelled
Publish Python SDK / publish-pypi (push) Has been cancelled
Publish TypeScript SDK / publish-npm (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { executeInE2B } from '@/lib/execution/e2b'
|
||||
import { CodeLanguage } from '@/lib/execution/languages'
|
||||
import { compileDoc, DocCompileUserError } from './doc-compile'
|
||||
|
||||
const logger = createLogger('CopilotDocRecalc')
|
||||
|
||||
const RECALC_TIMEOUT_MS = 150_000
|
||||
const MAX_REPORTED_ERRORS = 50
|
||||
|
||||
export interface XlsxCellError {
|
||||
sheet: string
|
||||
cell: string
|
||||
error: string
|
||||
}
|
||||
|
||||
export interface XlsxRecalcResult {
|
||||
ok: boolean
|
||||
errors: XlsxCellError[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans an .xlsx workbook for spilled error values (#REF!/#DIV/0!/etc.) — the
|
||||
* spreadsheet equivalent of the visual QA loop.
|
||||
*
|
||||
* Precondition: the binary must already be recalculated (cached values present).
|
||||
* compileDoc bakes a LibreOffice recalc into every xlsx artifact, so the input
|
||||
* here always has cached values — meaning we can read them with openpyxl
|
||||
* (data_only) directly and skip a second LibreOffice cold-start. Throws on
|
||||
* sandbox/infra failure.
|
||||
*/
|
||||
export async function recalcXlsx(args: {
|
||||
binary: Buffer
|
||||
workspaceId: string
|
||||
}): Promise<XlsxRecalcResult> {
|
||||
const script = `
|
||||
import json, openpyxl
|
||||
|
||||
ERR = {"#REF!", "#DIV/0!", "#VALUE!", "#NAME?", "#N/A", "#NULL!", "#NUM!"}
|
||||
|
||||
# Input is already recalculated by compileDoc, so cached values are present.
|
||||
wb = openpyxl.load_workbook("/home/user/input.xlsx", data_only=True)
|
||||
errors = []
|
||||
for ws in wb.worksheets:
|
||||
for row in ws.iter_rows():
|
||||
for c in row:
|
||||
if isinstance(c.value, str) and c.value.strip() in ERR:
|
||||
errors.append({"sheet": ws.title, "cell": c.coordinate, "error": c.value.strip()})
|
||||
|
||||
print("__SIM_RESULT__=" + json.dumps({"ok": len(errors) == 0, "errors": errors[:${MAX_REPORTED_ERRORS}]}))
|
||||
`.trim()
|
||||
|
||||
const result = await executeInE2B({
|
||||
code: script,
|
||||
language: CodeLanguage.Python,
|
||||
timeoutMs: RECALC_TIMEOUT_MS,
|
||||
sandboxKind: 'doc',
|
||||
sandboxFiles: [
|
||||
{
|
||||
path: '/home/user/input.xlsx',
|
||||
content: args.binary.toString('base64'),
|
||||
encoding: 'base64',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
if (result.error) {
|
||||
throw new Error(`Spreadsheet recalc failed: ${result.error}`)
|
||||
}
|
||||
const payload = result.result as XlsxRecalcResult | null
|
||||
if (!payload || typeof payload.ok !== 'boolean') {
|
||||
logger.warn('Recalc returned no structured result', { workspaceId: args.workspaceId })
|
||||
return { ok: true, errors: [] }
|
||||
}
|
||||
return { ok: payload.ok, errors: Array.isArray(payload.errors) ? payload.errors : [] }
|
||||
}
|
||||
|
||||
/** Single-line summary of the first few formula errors, for the compiled-check result. */
|
||||
export function formatXlsxErrors(errors: XlsxCellError[]): string {
|
||||
return `${errors.length} formula error(s): ${errors
|
||||
.slice(0, 5)
|
||||
.map((e) => `${e.sheet}!${e.cell}=${e.error}`)
|
||||
.join(', ')}`
|
||||
}
|
||||
|
||||
export interface CompiledCheckResult {
|
||||
ok: boolean
|
||||
error?: string
|
||||
errors?: XlsxCellError[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiles a generated doc (and, for xlsx, recalc-scans its formulas) to verify
|
||||
* it builds — the shared body behind the /compiled-check route and the VFS
|
||||
* compiled-check read. Returns { ok: false } only for a DocCompileUserError (the
|
||||
* agent's script is wrong); infra failures (E2B/S3) rethrow so callers surface a
|
||||
* 5xx instead of telling the agent to fix its script.
|
||||
*/
|
||||
export async function runE2BCompiledCheck(args: {
|
||||
source: string
|
||||
fileName: string
|
||||
workspaceId: string
|
||||
ext: string
|
||||
}): Promise<CompiledCheckResult> {
|
||||
try {
|
||||
const compiled = await compileDoc({
|
||||
source: args.source,
|
||||
fileName: args.fileName,
|
||||
workspaceId: args.workspaceId,
|
||||
})
|
||||
if (args.ext === 'xlsx') {
|
||||
const recalc = await recalcXlsx({ binary: compiled.buffer, workspaceId: args.workspaceId })
|
||||
return recalc.ok
|
||||
? { ok: true }
|
||||
: { ok: false, error: formatXlsxErrors(recalc.errors), errors: recalc.errors }
|
||||
}
|
||||
return { ok: true }
|
||||
} catch (err) {
|
||||
if (err instanceof DocCompileUserError) return { ok: false, error: err.message }
|
||||
throw err
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user