@auvira.ai/sdk 0.2.10 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -11
- package/dist/agent/Agent.d.ts +7 -1
- package/dist/agent/Agent.d.ts.map +1 -1
- package/dist/agent/Agent.js +19 -1
- package/dist/agent/Agent.js.map +1 -1
- package/dist/agent/AgentRegistry.d.ts +1 -1
- package/dist/agent/AgentRegistry.d.ts.map +1 -1
- package/dist/agent/AgentRegistry.js.map +1 -1
- package/dist/agent/ConversationStore.d.ts +2 -0
- package/dist/agent/ConversationStore.d.ts.map +1 -1
- package/dist/agent/ConversationStore.js +4 -0
- package/dist/agent/ConversationStore.js.map +1 -1
- package/dist/agent/resolveModelConfig.d.ts.map +1 -1
- package/dist/agent/resolveModelConfig.js +3 -1
- package/dist/agent/resolveModelConfig.js.map +1 -1
- package/dist/agent/types.d.ts +6 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/runner/abortPoller.d.ts +4 -0
- package/dist/runner/abortPoller.d.ts.map +1 -0
- package/dist/runner/abortPoller.js +22 -0
- package/dist/runner/abortPoller.js.map +1 -0
- package/dist/runner/buildJobResult.d.ts +25 -0
- package/dist/runner/buildJobResult.d.ts.map +1 -0
- package/dist/runner/buildJobResult.js +56 -0
- package/dist/runner/buildJobResult.js.map +1 -0
- package/dist/runner/constants.d.ts +16 -0
- package/dist/runner/constants.d.ts.map +1 -0
- package/dist/runner/constants.js +16 -0
- package/dist/runner/constants.js.map +1 -0
- package/dist/runner/index.d.ts +14 -0
- package/dist/runner/index.d.ts.map +1 -0
- package/dist/runner/index.js +10 -0
- package/dist/runner/index.js.map +1 -0
- package/dist/runner/jobTypes.d.ts +81 -0
- package/dist/runner/jobTypes.d.ts.map +1 -0
- package/dist/runner/jobTypes.js +2 -0
- package/dist/runner/jobTypes.js.map +1 -0
- package/dist/runner/mapStreamEvents.d.ts +18 -0
- package/dist/runner/mapStreamEvents.d.ts.map +1 -0
- package/dist/runner/mapStreamEvents.js +231 -0
- package/dist/runner/mapStreamEvents.js.map +1 -0
- package/dist/runner/ndjsonWriter.d.ts +6 -0
- package/dist/runner/ndjsonWriter.d.ts.map +1 -0
- package/dist/runner/ndjsonWriter.js +18 -0
- package/dist/runner/ndjsonWriter.js.map +1 -0
- package/dist/runner/resolveRunnerEnv.d.ts +10 -0
- package/dist/runner/resolveRunnerEnv.d.ts.map +1 -0
- package/dist/runner/resolveRunnerEnv.js +28 -0
- package/dist/runner/resolveRunnerEnv.js.map +1 -0
- package/dist/runner/run.d.ts +16 -0
- package/dist/runner/run.d.ts.map +1 -0
- package/dist/runner/run.js +126 -0
- package/dist/runner/run.js.map +1 -0
- package/dist/runner/sessionStore.d.ts +12 -0
- package/dist/runner/sessionStore.d.ts.map +1 -0
- package/dist/runner/sessionStore.js +56 -0
- package/dist/runner/sessionStore.js.map +1 -0
- package/dist/runner/validateJob.d.ts +7 -0
- package/dist/runner/validateJob.d.ts.map +1 -0
- package/dist/runner/validateJob.js +158 -0
- package/dist/runner/validateJob.js.map +1 -0
- package/docs/sandbox-runner.md +199 -0
- package/package.json +14 -3
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
export class SandboxJobValidationError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = "SandboxJobValidationError";
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
function isRecord(value) {
|
|
8
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9
|
+
}
|
|
10
|
+
function readString(value, field) {
|
|
11
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
12
|
+
throw new SandboxJobValidationError(`${field} must be a non-empty string`);
|
|
13
|
+
}
|
|
14
|
+
return value.trim();
|
|
15
|
+
}
|
|
16
|
+
function validateModel(raw) {
|
|
17
|
+
if (!isRecord(raw)) {
|
|
18
|
+
throw new SandboxJobValidationError("model must be an object");
|
|
19
|
+
}
|
|
20
|
+
if ("apiKey" in raw && raw.apiKey !== undefined && raw.apiKey !== null) {
|
|
21
|
+
throw new SandboxJobValidationError("model.apiKey is not allowed in job.json — use environment variables");
|
|
22
|
+
}
|
|
23
|
+
const id = readString(raw.id, "model.id");
|
|
24
|
+
const model = { id };
|
|
25
|
+
if (raw.provider !== undefined) {
|
|
26
|
+
if (raw.provider !== "openhands" && raw.provider !== "custom") {
|
|
27
|
+
throw new SandboxJobValidationError('model.provider must be "openhands" or "custom"');
|
|
28
|
+
}
|
|
29
|
+
model.provider = raw.provider;
|
|
30
|
+
}
|
|
31
|
+
if (raw.baseURL !== undefined) {
|
|
32
|
+
model.baseURL = readString(raw.baseURL, "model.baseURL");
|
|
33
|
+
}
|
|
34
|
+
return model;
|
|
35
|
+
}
|
|
36
|
+
function validateImages(raw) {
|
|
37
|
+
if (raw === undefined) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
if (!Array.isArray(raw)) {
|
|
41
|
+
throw new SandboxJobValidationError("images must be an array");
|
|
42
|
+
}
|
|
43
|
+
return raw.map((item, index) => {
|
|
44
|
+
if (!isRecord(item)) {
|
|
45
|
+
throw new SandboxJobValidationError(`images[${index}] must be an object`);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
data: readString(item.data, `images[${index}].data`),
|
|
49
|
+
mimeType: readString(item.mimeType, `images[${index}].mimeType`),
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
function validateCompletion(raw) {
|
|
54
|
+
if (raw === undefined) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
if (!isRecord(raw)) {
|
|
58
|
+
throw new SandboxJobValidationError("completion must be an object");
|
|
59
|
+
}
|
|
60
|
+
if ("isComplete" in raw) {
|
|
61
|
+
throw new SandboxJobValidationError("completion.isComplete is not serializable — omit from job.json");
|
|
62
|
+
}
|
|
63
|
+
const completion = {};
|
|
64
|
+
if (raw.mode !== undefined) {
|
|
65
|
+
if (raw.mode !== "default" && raw.mode !== "multi_file_required") {
|
|
66
|
+
throw new SandboxJobValidationError('completion.mode must be "default" or "multi_file_required"');
|
|
67
|
+
}
|
|
68
|
+
completion.mode = raw.mode;
|
|
69
|
+
}
|
|
70
|
+
if (raw.requireWiringAfterStyle !== undefined) {
|
|
71
|
+
completion.requireWiringAfterStyle = Boolean(raw.requireWiringAfterStyle);
|
|
72
|
+
}
|
|
73
|
+
if (raw.auto !== undefined) {
|
|
74
|
+
completion.auto = Boolean(raw.auto);
|
|
75
|
+
}
|
|
76
|
+
if (raw.confidenceThreshold !== undefined) {
|
|
77
|
+
const threshold = Number(raw.confidenceThreshold);
|
|
78
|
+
if (!Number.isFinite(threshold)) {
|
|
79
|
+
throw new SandboxJobValidationError("completion.confidenceThreshold must be a number");
|
|
80
|
+
}
|
|
81
|
+
completion.confidenceThreshold = threshold;
|
|
82
|
+
}
|
|
83
|
+
if (raw.styleAssetPatterns !== undefined) {
|
|
84
|
+
if (!Array.isArray(raw.styleAssetPatterns)) {
|
|
85
|
+
throw new SandboxJobValidationError("completion.styleAssetPatterns must be an array");
|
|
86
|
+
}
|
|
87
|
+
completion.styleAssetPatterns = raw.styleAssetPatterns.map((p) => readString(p, "styleAssetPatterns[]"));
|
|
88
|
+
}
|
|
89
|
+
if (raw.wiringPatterns !== undefined) {
|
|
90
|
+
if (!Array.isArray(raw.wiringPatterns)) {
|
|
91
|
+
throw new SandboxJobValidationError("completion.wiringPatterns must be an array");
|
|
92
|
+
}
|
|
93
|
+
completion.wiringPatterns = raw.wiringPatterns.map((p) => readString(p, "wiringPatterns[]"));
|
|
94
|
+
}
|
|
95
|
+
if (raw.multiStep !== undefined) {
|
|
96
|
+
if (!isRecord(raw.multiStep)) {
|
|
97
|
+
throw new SandboxJobValidationError("completion.multiStep must be an object");
|
|
98
|
+
}
|
|
99
|
+
completion.multiStep = {};
|
|
100
|
+
for (const key of ["minToolCalls", "minModelTurns", "maxExtraTurnsAfterStyleOnly"]) {
|
|
101
|
+
if (raw.multiStep[key] !== undefined) {
|
|
102
|
+
const value = Number(raw.multiStep[key]);
|
|
103
|
+
if (!Number.isFinite(value)) {
|
|
104
|
+
throw new SandboxJobValidationError(`completion.multiStep.${key} must be a number`);
|
|
105
|
+
}
|
|
106
|
+
completion.multiStep[key] = value;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return completion;
|
|
111
|
+
}
|
|
112
|
+
/** Validates and parses raw job JSON into SandboxAuviraJobInput v1. */
|
|
113
|
+
export function validateSandboxJob(raw) {
|
|
114
|
+
if (!isRecord(raw)) {
|
|
115
|
+
throw new SandboxJobValidationError("job.json must be a JSON object");
|
|
116
|
+
}
|
|
117
|
+
if (raw.version !== 1) {
|
|
118
|
+
throw new SandboxJobValidationError("job.version must be 1");
|
|
119
|
+
}
|
|
120
|
+
if ("apiKey" in raw && raw.apiKey !== undefined) {
|
|
121
|
+
throw new SandboxJobValidationError("apiKey is not allowed in job.json");
|
|
122
|
+
}
|
|
123
|
+
const editJobId = readString(raw.editJobId, "editJobId");
|
|
124
|
+
const workspacePath = raw.workspacePath === undefined
|
|
125
|
+
? "/vercel/sandbox"
|
|
126
|
+
: readString(raw.workspacePath, "workspacePath");
|
|
127
|
+
const promptText = readString(raw.promptText, "promptText");
|
|
128
|
+
const model = validateModel(raw.model);
|
|
129
|
+
const job = {
|
|
130
|
+
version: 1,
|
|
131
|
+
editJobId,
|
|
132
|
+
workspacePath,
|
|
133
|
+
promptText,
|
|
134
|
+
model,
|
|
135
|
+
images: validateImages(raw.images),
|
|
136
|
+
resumeAgentId: raw.resumeAgentId === undefined
|
|
137
|
+
? undefined
|
|
138
|
+
: readString(raw.resumeAgentId, "resumeAgentId"),
|
|
139
|
+
selectedDom: isRecord(raw.selectedDom)
|
|
140
|
+
? raw.selectedDom
|
|
141
|
+
: undefined,
|
|
142
|
+
completion: validateCompletion(raw.completion),
|
|
143
|
+
validation: isRecord(raw.validation)
|
|
144
|
+
? {
|
|
145
|
+
skip: raw.validation.skip === undefined ? undefined : Boolean(raw.validation.skip),
|
|
146
|
+
command: raw.validation.command === undefined
|
|
147
|
+
? undefined
|
|
148
|
+
: readString(raw.validation.command, "validation.command"),
|
|
149
|
+
timeoutMs: raw.validation.timeoutMs === undefined
|
|
150
|
+
? undefined
|
|
151
|
+
: Number(raw.validation.timeoutMs),
|
|
152
|
+
}
|
|
153
|
+
: undefined,
|
|
154
|
+
reuseWorkspace: raw.reuseWorkspace === undefined ? undefined : Boolean(raw.reuseWorkspace),
|
|
155
|
+
};
|
|
156
|
+
return job;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=validateJob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validateJob.js","sourceRoot":"","sources":["../../src/runner/validateJob.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAClD,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;IAC1C,CAAC;CACF;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,UAAU,CAAC,KAAc,EAAE,KAAa;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QAC/C,MAAM,IAAI,yBAAyB,CAAC,GAAG,KAAK,6BAA6B,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,aAAa,CAAC,GAAY;IACjC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,yBAAyB,CAAC,yBAAyB,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,QAAQ,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;QACvE,MAAM,IAAI,yBAAyB,CACjC,qEAAqE,CACtE,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAqB,EAAE,EAAE,EAAE,CAAC;IACvC,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC9D,MAAM,IAAI,yBAAyB,CAAC,gDAAgD,CAAC,CAAC;QACxF,CAAC;QACD,KAAK,CAAC,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC;IAChC,CAAC;IACD,IAAI,GAAG,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,cAAc,CAAC,GAAY;IAClC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,yBAAyB,CAAC,yBAAyB,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QAC7B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACpB,MAAM,IAAI,yBAAyB,CAAC,UAAU,KAAK,qBAAqB,CAAC,CAAC;QAC5E,CAAC;QACD,OAAO;YACL,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,KAAK,QAAQ,CAAC;YACpD,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,KAAK,YAAY,CAAC;SACjE,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAY;IACtC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,yBAAyB,CAAC,8BAA8B,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,YAAY,IAAI,GAAG,EAAE,CAAC;QACxB,MAAM,IAAI,yBAAyB,CACjC,gEAAgE,CACjE,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAqD,EAAE,CAAC;IACxE,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3B,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;YACjE,MAAM,IAAI,yBAAyB,CAAC,4DAA4D,CAAC,CAAC;QACpG,CAAC;QACD,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IAC7B,CAAC;IACD,IAAI,GAAG,CAAC,uBAAuB,KAAK,SAAS,EAAE,CAAC;QAC9C,UAAU,CAAC,uBAAuB,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAC5E,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3B,UAAU,CAAC,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IACD,IAAI,GAAG,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,yBAAyB,CAAC,iDAAiD,CAAC,CAAC;QACzF,CAAC;QACD,UAAU,CAAC,mBAAmB,GAAG,SAAS,CAAC;IAC7C,CAAC;IACD,IAAI,GAAG,CAAC,kBAAkB,KAAK,SAAS,EAAE,CAAC;QACzC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,yBAAyB,CAAC,gDAAgD,CAAC,CAAC;QACxF,CAAC;QACD,UAAU,CAAC,kBAAkB,GAAG,GAAG,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAC3G,CAAC;IACD,IAAI,GAAG,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACrC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,yBAAyB,CAAC,4CAA4C,CAAC,CAAC;QACpF,CAAC;QACD,UAAU,CAAC,cAAc,GAAG,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC;IAC/F,CAAC;IACD,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QAChC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,yBAAyB,CAAC,wCAAwC,CAAC,CAAC;QAChF,CAAC;QACD,UAAU,CAAC,SAAS,GAAG,EAAE,CAAC;QAC1B,KAAK,MAAM,GAAG,IAAI,CAAC,cAAc,EAAE,eAAe,EAAE,6BAA6B,CAAU,EAAE,CAAC;YAC5F,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBACrC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;gBACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC5B,MAAM,IAAI,yBAAyB,CAAC,wBAAwB,GAAG,mBAAmB,CAAC,CAAC;gBACtF,CAAC;gBACD,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,yBAAyB,CAAC,gCAAgC,CAAC,CAAC;IACxE,CAAC;IACD,IAAI,GAAG,CAAC,OAAO,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,yBAAyB,CAAC,uBAAuB,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,QAAQ,IAAI,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChD,MAAM,IAAI,yBAAyB,CAAC,mCAAmC,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;IACzD,MAAM,aAAa,GACjB,GAAG,CAAC,aAAa,KAAK,SAAS;QAC7B,CAAC,CAAC,iBAAiB;QACnB,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,EAAE,eAAe,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,UAAU,CAAC,GAAG,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAEvC,MAAM,GAAG,GAA0B;QACjC,OAAO,EAAE,CAAC;QACV,SAAS;QACT,aAAa;QACb,UAAU;QACV,KAAK;QACL,MAAM,EAAE,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC;QAClC,aAAa,EACX,GAAG,CAAC,aAAa,KAAK,SAAS;YAC7B,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,aAAa,EAAE,eAAe,CAAC;QACpD,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC;YACpC,CAAC,CAAE,GAAG,CAAC,WAAoD;YAC3D,CAAC,CAAC,SAAS;QACb,UAAU,EAAE,kBAAkB,CAAC,GAAG,CAAC,UAAU,CAAC;QAC9C,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC;YAClC,CAAC,CAAC;gBACE,IAAI,EAAE,GAAG,CAAC,UAAU,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC;gBAClF,OAAO,EACL,GAAG,CAAC,UAAU,CAAC,OAAO,KAAK,SAAS;oBAClC,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,oBAAoB,CAAC;gBAC9D,SAAS,EACP,GAAG,CAAC,UAAU,CAAC,SAAS,KAAK,SAAS;oBACpC,CAAC,CAAC,SAAS;oBACX,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC;aACvC;YACH,CAAC,CAAC,SAAS;QACb,cAAc,EACZ,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;KAC7E,CAAC;IAEF,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Vercel Sandbox Runner
|
|
2
|
+
|
|
3
|
+
Run Auvira agent edits inside a Vercel Sandbox VM while the host Next.js API stays in serverless Lambda. This mirrors the Cursor in-VM runner pattern: the host writes a job file, spawns the runner inside the sandbox, and polls NDJSON progress.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
```mermaid
|
|
8
|
+
sequenceDiagram
|
|
9
|
+
participant Host as Host_Lambda
|
|
10
|
+
participant VM as Sandbox_VM
|
|
11
|
+
participant Runner as auvira_sdk_run
|
|
12
|
+
participant Agent as Agent_in_place
|
|
13
|
+
|
|
14
|
+
Host->>VM: write job.json
|
|
15
|
+
Host->>VM: spawn auvira-sdk-run --job editJobId
|
|
16
|
+
Runner->>Agent: Agent.create cwd=/vercel/sandbox
|
|
17
|
+
Runner->>Agent: agent.send(job fields)
|
|
18
|
+
loop stream
|
|
19
|
+
Agent-->>Runner: AgentRunEvent
|
|
20
|
+
Runner-->>VM: append events.ndjson
|
|
21
|
+
end
|
|
22
|
+
Runner->>VM: result.json
|
|
23
|
+
Host->>VM: poll events.ndjson
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The SDK package does **not** call the Vercel Sandbox SDK. The host app (~150 lines) writes jobs and spawns the runner command.
|
|
27
|
+
|
|
28
|
+
## Directory layout
|
|
29
|
+
|
|
30
|
+
Default jobs root: `/vercel/.auvira/auvira-jobs` (override with `AUVIRA_JOBS_ROOT`).
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
{AUVIRA_JOBS_ROOT}/
|
|
34
|
+
{editJobId}/
|
|
35
|
+
job.json # input (no secrets)
|
|
36
|
+
events.ndjson # append-only progress + final result line
|
|
37
|
+
result.json # terminal outcome
|
|
38
|
+
abort.json # host writes to cancel (optional)
|
|
39
|
+
sessions/
|
|
40
|
+
{agentId}.json # conversation + vision state for resume
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Install and run
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @auvira.ai/sdk
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Inside the sandbox VM:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
CUSTOM_MODEL_API_KEY=... \
|
|
53
|
+
CUSTOM_MODEL_JSON_MODE=1 \
|
|
54
|
+
node node_modules/@auvira.ai/sdk/dist/runner/run.js --job <editJobId>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Or use the bin:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
auvira-sdk-run --job <editJobId>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Environment variables
|
|
64
|
+
|
|
65
|
+
| Variable | Required | Description |
|
|
66
|
+
|----------|----------|-------------|
|
|
67
|
+
| `CUSTOM_MODEL_API_KEY` | Yes | Model API key (MiniMax, OpenRouter, etc.) |
|
|
68
|
+
| `CUSTOM_MODEL_BASE_URL` | No | Model base URL override |
|
|
69
|
+
| `CUSTOM_MODEL_ID` | No | Model id override (default `MiniMax-M3`) |
|
|
70
|
+
| `CUSTOM_MODEL_JSON_MODE` | Recommended | Set to `1` for JSON-mode harness |
|
|
71
|
+
| `AUVIRA_JOBS_ROOT` | No | Jobs directory (default `/vercel/.auvira/auvira-jobs`) |
|
|
72
|
+
| `AUVIRA_CURSOR_JOB_ID` | No | Job id if `--job` not passed |
|
|
73
|
+
|
|
74
|
+
`CUSTOM_MODEL_API_KEY` is read from the environment only — never from `job.json`.
|
|
75
|
+
|
|
76
|
+
## Job input (`SandboxAuviraJobInput` v1)
|
|
77
|
+
|
|
78
|
+
```json
|
|
79
|
+
{
|
|
80
|
+
"version": 1,
|
|
81
|
+
"editJobId": "abc123",
|
|
82
|
+
"workspacePath": "/vercel/sandbox",
|
|
83
|
+
"promptText": "CURSOR SYSTEM RULES\n\n---\n\nOWNER REQUEST:\nUpdate hero headline",
|
|
84
|
+
"images": [
|
|
85
|
+
{ "data": "<base64>", "mimeType": "image/png" }
|
|
86
|
+
],
|
|
87
|
+
"selectedDom": {
|
|
88
|
+
"sectionIndex": 6,
|
|
89
|
+
"sectionTitle": "Our Services",
|
|
90
|
+
"kind": "section"
|
|
91
|
+
},
|
|
92
|
+
"completion": {
|
|
93
|
+
"mode": "multi_file_required",
|
|
94
|
+
"requireWiringAfterStyle": true,
|
|
95
|
+
"auto": false
|
|
96
|
+
},
|
|
97
|
+
"validation": { "skip": true },
|
|
98
|
+
"reuseWorkspace": false,
|
|
99
|
+
"resumeAgentId": "optional-agent-uuid",
|
|
100
|
+
"model": {
|
|
101
|
+
"id": "openrouter/minimax/minimax-m3",
|
|
102
|
+
"provider": "custom",
|
|
103
|
+
"baseURL": "https://api.minimax.io/v1"
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `promptText` must use harness format (`\n\n---\n\n` delimiter) for website edits.
|
|
109
|
+
- `images` are base64 only — no host filesystem paths.
|
|
110
|
+
- `completion.isComplete` is not allowed (not JSON-serializable).
|
|
111
|
+
- `model.apiKey` is rejected by the validator.
|
|
112
|
+
|
|
113
|
+
## Result (`SandboxAuviraJobResult`)
|
|
114
|
+
|
|
115
|
+
Written to `result.json` and appended as the final `events.ndjson` line:
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"ok": true,
|
|
120
|
+
"agentId": "uuid",
|
|
121
|
+
"sessionResumed": false,
|
|
122
|
+
"runId": "run-uuid",
|
|
123
|
+
"summary": "Applied 2 edit(s)",
|
|
124
|
+
"tokenUsage": { "inputTokens": 100, "outputTokens": 50 },
|
|
125
|
+
"nativeToolCallCount": 8,
|
|
126
|
+
"cursorReportedSuccess": true
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`changedFiles` are computed by the host (workspace hash before/after), not returned by the runner.
|
|
131
|
+
|
|
132
|
+
## NDJSON protocol
|
|
133
|
+
|
|
134
|
+
Each line in `events.ndjson`:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{"type":"progress","event":{"type":"step","id":"cursor_session","label":"Auvira agent ready","status":"completed"}}
|
|
138
|
+
{"type":"progress","event":{"type":"activity_trace","entry":{"kind":"tool_start","toolName":"read"}}}
|
|
139
|
+
{"type":"result","result":{"ok":true,"cursorReportedSuccess":true}}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Parse lines in the host with:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { parseSandboxAuviraRunnerLine } from "@auvira.ai/sdk";
|
|
146
|
+
|
|
147
|
+
const event = parseSandboxAuviraRunnerLine(line);
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Host spawn (pseudocode)
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
import { join } from "node:path";
|
|
154
|
+
|
|
155
|
+
const jobsRoot = "/vercel/.auvira/auvira-jobs";
|
|
156
|
+
const editJobId = "edit-abc";
|
|
157
|
+
const jobDir = join(jobsRoot, editJobId);
|
|
158
|
+
|
|
159
|
+
await sandbox.fs.writeFile(join(jobDir, "job.json"), JSON.stringify(job));
|
|
160
|
+
|
|
161
|
+
await sandbox.runCommand({
|
|
162
|
+
cmd: "sh",
|
|
163
|
+
args: [
|
|
164
|
+
"-c",
|
|
165
|
+
`CUSTOM_MODEL_API_KEY='$KEY' CUSTOM_MODEL_JSON_MODE=1 node '${runnerPath}/run.js' --job '${editJobId}'`,
|
|
166
|
+
],
|
|
167
|
+
cwd: "/vercel/.auvira/auvira-runner",
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
// Poll join(jobDir, "events.ndjson") for new lines; read result.json when done.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Session resume
|
|
174
|
+
|
|
175
|
+
When `resumeAgentId` is set, the runner loads `{jobsRoot}/sessions/{agentId}.json` and restores conversation + vision images across VM spawns. After a successful run, the runner updates the session file.
|
|
176
|
+
|
|
177
|
+
## Security
|
|
178
|
+
|
|
179
|
+
- Never put API keys, tokens, or secrets in `job.json`.
|
|
180
|
+
- Reference images must be base64 in the job payload.
|
|
181
|
+
- Stream output is secret-masked via the SDK event bus.
|
|
182
|
+
|
|
183
|
+
## Package exports
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
import { parseSandboxAuviraRunnerLine, mapAuviraStreamEventToProgress } from "@auvira.ai/sdk";
|
|
187
|
+
import type { SandboxAuviraJobInput, SandboxAuviraJobResult } from "@auvira.ai/sdk";
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Subpath: `@auvira.ai/sdk/runner` (types + CLI module).
|
|
191
|
+
|
|
192
|
+
## Changelog
|
|
193
|
+
|
|
194
|
+
### 0.3.0
|
|
195
|
+
|
|
196
|
+
- Added Vercel Sandbox runner CLI (`auvira-sdk-run`)
|
|
197
|
+
- Added `@auvira.ai/sdk/runner` export
|
|
198
|
+
- Added session-file resume (`agentId`, `initialConversation` on `Agent.create`)
|
|
199
|
+
- Added NDJSON progress protocol for host polling
|
package/package.json
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@auvira.ai/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Cursor-SDK-compatible visual coding agent with custom model support",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"auvira-sdk-run": "./dist/runner/run.js"
|
|
10
|
+
},
|
|
8
11
|
"exports": {
|
|
9
12
|
".": {
|
|
10
13
|
"types": "./dist/index.d.ts",
|
|
11
14
|
"import": "./dist/index.js"
|
|
15
|
+
},
|
|
16
|
+
"./runner": {
|
|
17
|
+
"types": "./dist/runner/index.d.ts",
|
|
18
|
+
"import": "./dist/runner/run.js"
|
|
12
19
|
}
|
|
13
20
|
},
|
|
14
21
|
"files": [
|
|
15
22
|
"dist",
|
|
16
23
|
"README.md",
|
|
17
|
-
"LICENSE"
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"docs"
|
|
18
26
|
],
|
|
19
27
|
"repository": {
|
|
20
28
|
"type": "git",
|
|
@@ -33,7 +41,10 @@
|
|
|
33
41
|
"test:unit": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__ --exclude 'src/__tests__/real/**' --exclude 'src/__tests__/flex/real-*.e2e.test.ts'",
|
|
34
42
|
"test:flex": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__/flex",
|
|
35
43
|
"test:flex:unit": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__/flex --exclude 'src/__tests__/flex/real-*.e2e.test.ts'",
|
|
36
|
-
"test:real": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__/real src/__tests__/flex/real-*.e2e.test.ts"
|
|
44
|
+
"test:real": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__/real src/__tests__/flex/real-*.e2e.test.ts src/__tests__/runner/run-cli.real.e2e.test.ts",
|
|
45
|
+
"test:runner": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__/runner --exclude 'src/__tests__/runner/**/*.real.e2e.test.ts'",
|
|
46
|
+
"test:runner:real": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__/runner/run-cli.real.e2e.test.ts src/__tests__/runner/run-cli-vibe-consumer.real.e2e.test.ts",
|
|
47
|
+
"test:runner:vibe": "node --env-file=.env ./node_modules/vitest/vitest.mjs run src/__tests__/runner/run-cli-vibe-consumer.real.e2e.test.ts"
|
|
37
48
|
},
|
|
38
49
|
"keywords": [
|
|
39
50
|
"agent",
|