@granular-software/sdk 0.4.19 → 0.4.20
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 +10 -0
- package/dist/agent-evals.d.mts +1 -1
- package/dist/agent-evals.d.ts +1 -1
- package/dist/agent-evals.js +116 -17
- package/dist/agent-evals.js.map +1 -1
- package/dist/agent-evals.mjs +116 -17
- package/dist/agent-evals.mjs.map +1 -1
- package/dist/cli/index.js +114 -14
- package/dist/{client-BQw_gUK3.d.mts → client-DWYdWpS-.d.mts} +61 -5
- package/dist/{client-BQw_gUK3.d.ts → client-DWYdWpS-.d.ts} +61 -5
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +110 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +110 -11
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/agent-evals.mjs
CHANGED
|
@@ -11231,6 +11231,28 @@ var STANDARD_MODULES_OPERATIONS = [
|
|
|
11231
11231
|
var BUILTIN_MODULES = {
|
|
11232
11232
|
"standard_modules": STANDARD_MODULES_OPERATIONS
|
|
11233
11233
|
};
|
|
11234
|
+
var DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE = 100;
|
|
11235
|
+
var MAX_RECORD_OBJECTS_CONCURRENCY = 16;
|
|
11236
|
+
var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT = 3;
|
|
11237
|
+
var DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_DELAY_MS = 1e3;
|
|
11238
|
+
function planRecordObjectsChunks(records, batchSize) {
|
|
11239
|
+
const total = records.length;
|
|
11240
|
+
const size = Math.max(1, Math.min(batchSize, total));
|
|
11241
|
+
const chunkCount = Math.ceil(total / size);
|
|
11242
|
+
const plans = [];
|
|
11243
|
+
for (let offset = 0, chunkIndex = 0; offset < total; offset += size, chunkIndex += 1) {
|
|
11244
|
+
const slice = records.slice(offset, offset + size);
|
|
11245
|
+
plans.push({ chunkIndex, chunkCount, offset, slice });
|
|
11246
|
+
}
|
|
11247
|
+
return plans;
|
|
11248
|
+
}
|
|
11249
|
+
function sleep(ms) {
|
|
11250
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11251
|
+
}
|
|
11252
|
+
function isRetryableRecordObjectsError(error) {
|
|
11253
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
11254
|
+
return /worker restarted mid-request|econnreset|network|socket connection was closed unexpectedly|timed out/i.test(message);
|
|
11255
|
+
}
|
|
11234
11256
|
function computeEffectKey2(effect) {
|
|
11235
11257
|
const attachedClass = effect.className?.trim();
|
|
11236
11258
|
if (!attachedClass) {
|
|
@@ -12188,24 +12210,101 @@ var Environment = class extends Session {
|
|
|
12188
12210
|
/**
|
|
12189
12211
|
* Batch version of `recordObject()`.
|
|
12190
12212
|
*
|
|
12191
|
-
* Sends
|
|
12192
|
-
*
|
|
12213
|
+
* Sends rows through the control-plane **`/records/batch`** endpoint in **chunks** (default
|
|
12214
|
+
* **100** records per HTTP request) so individual requests stay bounded and gateway timeouts are
|
|
12215
|
+
* unlikely. Each chunk is retried on transient network / worker errors.
|
|
12216
|
+
*
|
|
12217
|
+
* Use the optional second argument to:
|
|
12218
|
+
* - **`batchSize`** — rows per POST (smaller = more progress events; larger = fewer round trips).
|
|
12219
|
+
* - **`concurrency`** — run up to N chunk POSTs in parallel (capped at 16) when you want lower wall time.
|
|
12220
|
+
* - **`onChunkComplete`** — hook for UIs after each chunk succeeds (row order in the returned array
|
|
12221
|
+
* always matches `records`; chunk **completion** order may differ when `concurrency > 1`).
|
|
12222
|
+
*
|
|
12223
|
+
* For **asynchronous** ingestion with worker-side batching and aggregate counters (`queued`,
|
|
12224
|
+
* `completed`, …), use **`enqueueRecordImport`** and poll **`getRecordImport`** /
|
|
12225
|
+
* **`getRecordImportSummary`** — best for very large fire-and-forget loads when immediate
|
|
12226
|
+
* synchronous commit of every row is not required.
|
|
12193
12227
|
*/
|
|
12194
|
-
async recordObjects(records) {
|
|
12228
|
+
async recordObjects(records, options) {
|
|
12195
12229
|
if (!Array.isArray(records) || records.length === 0) {
|
|
12196
12230
|
return [];
|
|
12197
12231
|
}
|
|
12198
|
-
const
|
|
12199
|
-
|
|
12200
|
-
|
|
12201
|
-
|
|
12202
|
-
|
|
12203
|
-
|
|
12232
|
+
const batchSize = Math.max(
|
|
12233
|
+
1,
|
|
12234
|
+
Math.min(
|
|
12235
|
+
records.length,
|
|
12236
|
+
options?.batchSize ?? DEFAULT_DIRECT_RECORD_OBJECTS_REQUEST_BATCH_SIZE
|
|
12237
|
+
)
|
|
12204
12238
|
);
|
|
12205
|
-
|
|
12239
|
+
const concurrency = Math.min(
|
|
12240
|
+
MAX_RECORD_OBJECTS_CONCURRENCY,
|
|
12241
|
+
Math.max(1, options?.concurrency ?? 1)
|
|
12242
|
+
);
|
|
12243
|
+
const plans = planRecordObjectsChunks(records, batchSize);
|
|
12244
|
+
const total = records.length;
|
|
12245
|
+
const results = new Array(total);
|
|
12246
|
+
const onChunk = options?.onChunkComplete;
|
|
12247
|
+
for (let waveStart = 0; waveStart < plans.length; waveStart += concurrency) {
|
|
12248
|
+
const wave = plans.slice(waveStart, waveStart + concurrency);
|
|
12249
|
+
await Promise.all(
|
|
12250
|
+
wave.map(async (plan) => {
|
|
12251
|
+
const { items, durationMs } = await this.executeRecordObjectsChunk(plan.slice);
|
|
12252
|
+
if (items.length !== plan.slice.length) {
|
|
12253
|
+
throw new Error(
|
|
12254
|
+
`recordObjects: chunk ${plan.chunkIndex + 1} returned ${items.length} results, expected ${plan.slice.length}`
|
|
12255
|
+
);
|
|
12256
|
+
}
|
|
12257
|
+
for (let index = 0; index < items.length; index += 1) {
|
|
12258
|
+
results[plan.offset + index] = items[index];
|
|
12259
|
+
}
|
|
12260
|
+
if (onChunk) {
|
|
12261
|
+
const info = {
|
|
12262
|
+
chunkIndex: plan.chunkIndex,
|
|
12263
|
+
totalChunks: plan.chunkCount,
|
|
12264
|
+
offset: plan.offset,
|
|
12265
|
+
recordCount: plan.slice.length,
|
|
12266
|
+
durationMs,
|
|
12267
|
+
results: items
|
|
12268
|
+
};
|
|
12269
|
+
await onChunk(info);
|
|
12270
|
+
}
|
|
12271
|
+
})
|
|
12272
|
+
);
|
|
12273
|
+
}
|
|
12274
|
+
return results;
|
|
12275
|
+
}
|
|
12276
|
+
async executeRecordObjectsChunk(chunk) {
|
|
12277
|
+
const wallStart = Date.now();
|
|
12278
|
+
let lastError;
|
|
12279
|
+
for (let attempt = 1; attempt <= DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT; attempt += 1) {
|
|
12280
|
+
try {
|
|
12281
|
+
const response = await this.controlPlaneRequest(
|
|
12282
|
+
`/control/environments/${this.environmentId}/records/batch`,
|
|
12283
|
+
{
|
|
12284
|
+
method: "POST",
|
|
12285
|
+
body: JSON.stringify({ records: chunk })
|
|
12286
|
+
}
|
|
12287
|
+
);
|
|
12288
|
+
const items = Array.isArray(response.items) ? response.items : [];
|
|
12289
|
+
return { items, durationMs: Date.now() - wallStart };
|
|
12290
|
+
} catch (error) {
|
|
12291
|
+
lastError = error;
|
|
12292
|
+
if (!isRetryableRecordObjectsError(error) || attempt === DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_COUNT) {
|
|
12293
|
+
throw error;
|
|
12294
|
+
}
|
|
12295
|
+
await sleep(DEFAULT_DIRECT_RECORD_OBJECTS_RETRY_DELAY_MS * attempt);
|
|
12296
|
+
}
|
|
12297
|
+
}
|
|
12298
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
12206
12299
|
}
|
|
12207
12300
|
/**
|
|
12208
|
-
* Queue a background record import for this environment.
|
|
12301
|
+
* Queue a background record import for this environment (async worker pipeline).
|
|
12302
|
+
*
|
|
12303
|
+
* **vs `recordObjects`:** this path accepts the full payload in one request, returns an
|
|
12304
|
+
* **`importId`**, and processes rows in the background — use **`getRecordImport`** /
|
|
12305
|
+
* **`getRecordImportSummary`** for progress. Choose it for large bulk loads where you do not
|
|
12306
|
+
* need every row committed before the HTTP call returns. Use **`recordObjects`** when you need
|
|
12307
|
+
* synchronous upserts and fine-grained chunk progress via **`onChunkComplete`**.
|
|
12209
12308
|
*/
|
|
12210
12309
|
async enqueueRecordImport(records, options = {}) {
|
|
12211
12310
|
return this.controlPlaneRequest(
|
|
@@ -14564,7 +14663,7 @@ ${modelOutputInstruction()}` },
|
|
|
14564
14663
|
if (!response.ok) {
|
|
14565
14664
|
const errorText = await response.text();
|
|
14566
14665
|
if (attempt < 3 && (response.status >= 500 || response.status === 429)) {
|
|
14567
|
-
await
|
|
14666
|
+
await sleep2(500 * attempt);
|
|
14568
14667
|
continue;
|
|
14569
14668
|
}
|
|
14570
14669
|
throw new Error(`OpenAI chat generation failed: ${response.status} ${errorText}`);
|
|
@@ -14575,7 +14674,7 @@ ${modelOutputInstruction()}` },
|
|
|
14575
14674
|
const parsed = extractJsonObject(text);
|
|
14576
14675
|
if (!parsed) {
|
|
14577
14676
|
if (attempt < 3) {
|
|
14578
|
-
await
|
|
14677
|
+
await sleep2(300 * attempt);
|
|
14579
14678
|
continue;
|
|
14580
14679
|
}
|
|
14581
14680
|
throw new Error(`Model output was not valid JSON:
|
|
@@ -14589,7 +14688,7 @@ ${text}`);
|
|
|
14589
14688
|
} catch (error) {
|
|
14590
14689
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
14591
14690
|
if (attempt < 3 && /socket connection was closed unexpectedly|ECONNRESET|network|timed out/i.test(lastError.message)) {
|
|
14592
|
-
await
|
|
14691
|
+
await sleep2(500 * attempt);
|
|
14593
14692
|
continue;
|
|
14594
14693
|
}
|
|
14595
14694
|
throw lastError;
|
|
@@ -14601,7 +14700,7 @@ ${text}`);
|
|
|
14601
14700
|
async function ensureDir(dir) {
|
|
14602
14701
|
await mkdir(dir, { recursive: true });
|
|
14603
14702
|
}
|
|
14604
|
-
async function
|
|
14703
|
+
async function sleep2(ms) {
|
|
14605
14704
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
14606
14705
|
}
|
|
14607
14706
|
async function withTimeout(promise, ms, label) {
|
|
@@ -15044,7 +15143,7 @@ function createAgentEvalHarness(options) {
|
|
|
15044
15143
|
stderr: [...pending.stderr, ...resumed.stderr]
|
|
15045
15144
|
};
|
|
15046
15145
|
}
|
|
15047
|
-
await
|
|
15146
|
+
await sleep2(350);
|
|
15048
15147
|
const liveDoc = cloneJson(pending.conversation.environment.document);
|
|
15049
15148
|
const presentation = resolveJobPresentation({
|
|
15050
15149
|
jobId: pending.job.id,
|
|
@@ -15213,7 +15312,7 @@ function createAgentEvalHarness(options) {
|
|
|
15213
15312
|
if (outcome.kind !== "completed") {
|
|
15214
15313
|
throw new Error("Unexpected non-completed outcome after prompt handling");
|
|
15215
15314
|
}
|
|
15216
|
-
await
|
|
15315
|
+
await sleep2(350);
|
|
15217
15316
|
const settledLiveDoc = cloneJson(conversation.environment.document);
|
|
15218
15317
|
const sessionHeap = normalizeHeapSnapshot2(asRecord4(settledLiveDoc?.heap));
|
|
15219
15318
|
const presentation = resolveJobPresentation({
|