@the-open-engine/zeroshot 6.34.1 → 6.34.3

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/cli/index.js CHANGED
@@ -3295,22 +3295,19 @@ program
3295
3295
  throw new Error(`Cluster ${clusterId} not found (no DB file)`);
3296
3296
  }
3297
3297
 
3298
- const ledger = new Ledger(dbPath);
3299
- const messages = ledger.getAll(clusterId);
3300
- ledger.close();
3301
-
3302
3298
  // JSON export
3303
3299
  if (options.format === 'json') {
3304
- const data = JSON.stringify({ cluster_id: clusterId, messages }, null, 2);
3300
+ exportClusterJson(dbPath, clusterId, options.output || null);
3305
3301
  if (options.output) {
3306
- require('fs').writeFileSync(options.output, data, 'utf8');
3307
3302
  console.log(`Exported to ${options.output}`);
3308
- } else {
3309
- console.log(data);
3310
3303
  }
3311
3304
  return;
3312
3305
  }
3313
3306
 
3307
+ const ledger = new Ledger(dbPath);
3308
+ const messages = ledger.getAll(clusterId);
3309
+ ledger.close();
3310
+
3314
3311
  // Terminal-style export (for markdown and pdf)
3315
3312
  const terminalOutput = renderMessagesToTerminal(clusterId, messages);
3316
3313
 
@@ -6067,6 +6064,35 @@ async function handleNoArgumentInvocation({
6067
6064
  return true;
6068
6065
  }
6069
6066
 
6067
+ function tryExportClusterJsonSnapshot(dbPath, clusterId, outputPath) {
6068
+ const Ledger = require('../src/ledger');
6069
+ const { streamClusterJsonExport } = require('./json-export');
6070
+ const ledger = new Ledger(dbPath, { readonly: true });
6071
+ try {
6072
+ return ledger.withReadSnapshot(() => {
6073
+ if (ledger.needsAgentOutputReconciliation(clusterId)) return false;
6074
+ streamClusterJsonExport({ ledger, clusterId, outputPath });
6075
+ return true;
6076
+ });
6077
+ } finally {
6078
+ ledger.close();
6079
+ }
6080
+ }
6081
+
6082
+ function exportClusterJson(dbPath, clusterId, outputPath) {
6083
+ const Ledger = require('../src/ledger');
6084
+ const maxReconciliationAttempts = 3;
6085
+ for (let attempt = 0; attempt <= maxReconciliationAttempts; attempt += 1) {
6086
+ if (tryExportClusterJsonSnapshot(dbPath, clusterId, outputPath)) return;
6087
+ if (attempt === maxReconciliationAttempts) break;
6088
+ const reconciliationLedger = new Ledger(dbPath);
6089
+ reconciliationLedger.close();
6090
+ }
6091
+ throw new Error(
6092
+ `Cluster ${clusterId} output changed during ${maxReconciliationAttempts} reconciliation attempts`
6093
+ );
6094
+ }
6095
+
6070
6096
  // Main entry point
6071
6097
  async function main() {
6072
6098
  printLegacyDistroNotice();
@@ -0,0 +1,77 @@
1
+ const fs = require('fs');
2
+
3
+ function indentJson(value, spaces) {
4
+ const prefix = ' '.repeat(spaces);
5
+ return JSON.stringify(value, null, 2)
6
+ .split('\n')
7
+ .map((line) => `${prefix}${line}`)
8
+ .join('\n');
9
+ }
10
+
11
+ function writeAll(fd, value) {
12
+ const bytes = Buffer.from(value);
13
+ let offset = 0;
14
+ while (offset < bytes.length) {
15
+ const written = fs.writeSync(fd, bytes, offset, bytes.length - offset);
16
+ if (!Number.isInteger(written) || written <= 0) {
17
+ throw new Error('JSON export destination stopped accepting bytes');
18
+ }
19
+ offset += written;
20
+ }
21
+ }
22
+
23
+ function createDestination(outputPath, stdout) {
24
+ if (outputPath) {
25
+ const fd = fs.openSync(outputPath, 'w');
26
+ return {
27
+ close: () => fs.closeSync(fd),
28
+ write: (value) => writeAll(fd, value),
29
+ };
30
+ }
31
+
32
+ if (Number.isInteger(stdout.fd)) {
33
+ return {
34
+ close() {},
35
+ write: (value) => writeAll(stdout.fd, value),
36
+ };
37
+ }
38
+
39
+ return {
40
+ close() {},
41
+ write: (value) => stdout.write(value),
42
+ };
43
+ }
44
+
45
+ function streamClusterJsonExport({
46
+ ledger,
47
+ clusterId,
48
+ outputPath = null,
49
+ stdout = process.stdout,
50
+ }) {
51
+ const destination = createDestination(outputPath, stdout);
52
+ const iterator = ledger.iterateAll(clusterId);
53
+ try {
54
+ destination.write(`{\n "cluster_id": ${JSON.stringify(clusterId)},\n "messages": `);
55
+ let current = iterator.next();
56
+ if (current.done) {
57
+ destination.write('[]\n}\n');
58
+ return;
59
+ }
60
+
61
+ destination.write('[\n');
62
+ while (!current.done) {
63
+ destination.write(indentJson(current.value, 4));
64
+ current = iterator.next();
65
+ destination.write(current.done ? '\n' : ',\n');
66
+ }
67
+ destination.write(' ]\n}\n');
68
+ } finally {
69
+ try {
70
+ if (typeof iterator.return === 'function') iterator.return();
71
+ } finally {
72
+ destination.close();
73
+ }
74
+ }
75
+ }
76
+
77
+ module.exports = { streamClusterJsonExport };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@the-open-engine/zeroshot",
3
- "version": "6.34.1",
3
+ "version": "6.34.3",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@the-open-engine/zeroshot",
9
- "version": "6.34.1",
9
+ "version": "6.34.3",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@the-open-engine/zeroshot",
3
- "version": "6.34.1",
3
+ "version": "6.34.3",
4
4
  "description": "Independent executor–verifier orchestration for software changes.",
5
5
  "main": "src/orchestrator.js",
6
6
  "bin": {
@@ -24,6 +24,7 @@ const { findPlatformMismatchReason } = require('./validation-platform');
24
24
  const { calculateRateLimitDelay, isRateLimitError } = require('./rate-limit-backoff');
25
25
  const { updateAgentProviderSession } = require('./provider-session');
26
26
  const { rebuildProviderSessionAfterCommit } = require('./agent-task-executor');
27
+ const providerFailures = require('./provider-terminal-failure');
27
28
  const {
28
29
  buildStructuredOutputClusterFailure,
29
30
  isStructuredOutputInvalidError,
@@ -660,6 +661,7 @@ async function runTaskAttempt(agent, triggeringMessage) {
660
661
  error.code = result.code || result.errorType || null;
661
662
  error.taskId = result.taskId || null;
662
663
  error.vertexModelError = result.vertexModelError || null;
664
+ providerFailures.decorateError(error, result.providerFailure);
663
665
  throw error;
664
666
  }
665
667
 
@@ -795,6 +797,16 @@ ${'='.repeat(80)}`);
795
797
 
796
798
  // Non-validator agents: publish error and stop
797
799
  agent.state = 'error';
800
+ const workerFailure = providerFailures.workerFailure(error);
801
+ // Synchronous terminal listeners must see the final failure truth before persisting a stop.
802
+ agent.cluster.failureInfo = providerFailures.buildFinalFailureInfo({
803
+ agent,
804
+ error,
805
+ attempts: failureAttempts,
806
+ worker: workerFailure,
807
+ unsupportedCapability,
808
+ structuredOutputInvalid,
809
+ });
798
810
 
799
811
  // Hook failure: fail the whole cluster so it gets stopped + persisted (prevents deadlocked "running" clusters).
800
812
  if (error?.hookFailure) {
@@ -872,25 +884,14 @@ ${'='.repeat(80)}`);
872
884
  });
873
885
  }
874
886
 
875
- // Save failure info to cluster for resume capability
876
- agent.cluster.failureInfo = {
877
- ...(error?.terminationExhausted ? agent.cluster.failureInfo : {}),
878
- agentId: agent.id,
879
- taskId: error?.taskId || agent.currentTaskId,
880
- iteration: agent.iteration,
881
- error: error.message,
887
+ providerFailures.publishCriticalFailure({
888
+ agent,
889
+ error,
882
890
  attempts: failureAttempts,
883
- ...(unsupportedCapability
884
- ? {
885
- code: error.code,
886
- permanent: true,
887
- provider: error.provider,
888
- capability: error.capability,
889
- }
890
- : {}),
891
- ...(structuredOutputInvalid ? { code: error.code, details: error.details ?? null } : {}),
892
- timestamp: Date.now(),
893
- };
891
+ worker: workerFailure,
892
+ unsupportedCapability,
893
+ structuredOutputInvalid,
894
+ });
894
895
 
895
896
  // Publish error to message bus for visibility in logs
896
897
  agent._publish({
@@ -900,7 +901,7 @@ ${'='.repeat(80)}`);
900
901
  text: `Task execution failed after ${failureAttempts} attempts: ${error.message}`,
901
902
  data: {
902
903
  error: error.message,
903
- stack: error.stack,
904
+ stack: error?.provider ? undefined : error.stack,
904
905
  hookFailure: error?.hookFailure === true,
905
906
  restartExhausted: error?.restartExhausted === true,
906
907
  terminationExhausted: error?.terminationExhausted === true,
@@ -911,6 +912,10 @@ ${'='.repeat(80)}`);
911
912
  iteration: agent.iteration,
912
913
  taskId: error?.taskId || agent.currentTaskId,
913
914
  attempts: failureAttempts,
915
+ ...providerFailures.receiptFields(error),
916
+ ...(error?.provider
917
+ ? { workerCode: workerFailure.code, workerReason: workerFailure.reason }
918
+ : {}),
914
919
  ...(unsupportedCapability
915
920
  ? {
916
921
  code: error.code,