@smithers-orchestrator/errors 0.24.2 → 0.25.0
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/package.json +1 -1
- package/src/assertZodV4.js +45 -0
- package/src/errorToJson.js +99 -1
- package/src/index.d.ts +103 -36
- package/src/index.js +1 -0
- package/src/isSmithersError.js +1 -10
- package/src/smithersErrorDefinitions.js +27 -1
- package/src/toTaggedErrorPayload.js +21 -7
- package/src/tagged.js +0 -24
package/package.json
CHANGED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { SmithersError } from "./SmithersError.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Assert that a user-supplied schema is a Zod v4 schema, failing fast and clearly
|
|
5
|
+
* when it is a Zod v3 (or otherwise pre-v4) schema.
|
|
6
|
+
*
|
|
7
|
+
* smithers introspects schemas through Zod v4 runtime internals (`schema._zod`)
|
|
8
|
+
* and the v4-only static `z.toJSONSchema()`. A Zod v3 schema has no `_zod`, so
|
|
9
|
+
* without this guard it would (a) silently degrade every output column to a JSON
|
|
10
|
+
* text column in `zodToTable` (optional chaining swallows the missing `_zod`),
|
|
11
|
+
* then (b) detonate later, deep inside `z.toJSONSchema`, with the cryptic
|
|
12
|
+
* `undefined is not an object (evaluating 'schema._zod.def')`. This converts both
|
|
13
|
+
* failure modes into one actionable error at the earliest boundary — workflow
|
|
14
|
+
* construction.
|
|
15
|
+
*
|
|
16
|
+
* Detection signal: every Zod v4 schema instance carries
|
|
17
|
+
* `schema._zod.version.major === 4`; Zod v3 schemas have no `_zod` at all.
|
|
18
|
+
*
|
|
19
|
+
* @param {unknown} schema - the candidate schema
|
|
20
|
+
* @param {string} [where] - name of the schema (e.g. an output key) for the message
|
|
21
|
+
* @returns {void}
|
|
22
|
+
*/
|
|
23
|
+
export function assertZodV4(schema, where) {
|
|
24
|
+
if (!schema || typeof schema !== "object")
|
|
25
|
+
return;
|
|
26
|
+
const internal = /** @type {{ _zod?: { version?: { major?: number } } }} */ (schema);
|
|
27
|
+
// Zod v4 fast-path: accept and return. Verified robust across object/string/
|
|
28
|
+
// array/union/enum/optional plus refine/transform/pipe/lazy/brand/coerce —
|
|
29
|
+
// every v4 schema instance carries _zod.version.major === 4.
|
|
30
|
+
if (internal._zod?.version?.major === 4)
|
|
31
|
+
return;
|
|
32
|
+
// Only error on things that are recognizably a Zod schema, so a plain config
|
|
33
|
+
// object that happens to flow through here is never rejected. NOTE: this is
|
|
34
|
+
// purely an "is this Zod-shaped at all" gate — Zod v4 schemas ALSO carry
|
|
35
|
+
// `_def`/`parse`, so this clause does NOT discriminate the version; the
|
|
36
|
+
// `_zod.version` check above is the version discriminator.
|
|
37
|
+
const candidate = /** @type {{ parse?: unknown }} */ (schema);
|
|
38
|
+
const looksLikeZod = typeof candidate.parse === "function" || "_def" in schema || "shape" in schema;
|
|
39
|
+
if (!looksLikeZod)
|
|
40
|
+
return;
|
|
41
|
+
const target = where ? ` for "${where}"` : "";
|
|
42
|
+
throw new SmithersError("INVALID_INPUT", `smithers requires Zod v4 schemas${target}, but received what looks like a Zod v3 (or pre-v4) schema. ` +
|
|
43
|
+
`Upgrade your project to "zod": "^4" and import schemas from "zod". ` +
|
|
44
|
+
`smithers reads Zod v4 internals (schema._zod) and uses z.toJSONSchema(), neither of which exists on a Zod v3 schema.`, where ? { schema: where } : undefined);
|
|
45
|
+
}
|
package/src/errorToJson.js
CHANGED
|
@@ -1,13 +1,100 @@
|
|
|
1
|
+
import { EngineError } from "./EngineError.js";
|
|
1
2
|
import { SmithersError } from "./SmithersError.js";
|
|
2
3
|
import { fromTaggedError } from "./fromTaggedError.js";
|
|
4
|
+
/**
|
|
5
|
+
* Deeply convert a value into a structure that `JSON.stringify` can never throw
|
|
6
|
+
* on. `errorToJson` output is fed straight into `JSON.stringify` on the engine's
|
|
7
|
+
* durable failed-task write path, so a circular `cause`, a `BigInt` detail, or a
|
|
8
|
+
* throwing getter must not be able to crash the error-recording code.
|
|
9
|
+
*
|
|
10
|
+
* @param {unknown} value
|
|
11
|
+
* @param {WeakSet<object>} seen
|
|
12
|
+
* @returns {unknown}
|
|
13
|
+
*/
|
|
14
|
+
function toJsonSafe(value, seen) {
|
|
15
|
+
if (value === null)
|
|
16
|
+
return null;
|
|
17
|
+
const type = typeof value;
|
|
18
|
+
if (type === "string" || type === "boolean")
|
|
19
|
+
return value;
|
|
20
|
+
if (type === "number")
|
|
21
|
+
return Number.isFinite(value) ? value : null;
|
|
22
|
+
if (type === "bigint")
|
|
23
|
+
return value.toString();
|
|
24
|
+
if (type === "undefined" || type === "function" || type === "symbol")
|
|
25
|
+
return undefined;
|
|
26
|
+
// value is an object at this point.
|
|
27
|
+
const obj = /** @type {object} */ (value);
|
|
28
|
+
if (seen.has(obj))
|
|
29
|
+
return "[Circular]";
|
|
30
|
+
seen.add(obj);
|
|
31
|
+
try {
|
|
32
|
+
if (obj instanceof Error) {
|
|
33
|
+
/** @type {Record<string, unknown>} */
|
|
34
|
+
const out = {
|
|
35
|
+
name: obj.name,
|
|
36
|
+
message: obj.message,
|
|
37
|
+
stack: obj.stack,
|
|
38
|
+
};
|
|
39
|
+
if (obj.cause !== undefined)
|
|
40
|
+
out.cause = toJsonSafe(obj.cause, seen);
|
|
41
|
+
for (const key of Object.keys(obj)) {
|
|
42
|
+
if (key in out)
|
|
43
|
+
continue;
|
|
44
|
+
let raw;
|
|
45
|
+
try {
|
|
46
|
+
raw = /** @type {Record<string, unknown>} */ (obj)[key];
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const safe = toJsonSafe(raw, seen);
|
|
52
|
+
if (safe !== undefined)
|
|
53
|
+
out[key] = safe;
|
|
54
|
+
}
|
|
55
|
+
return out;
|
|
56
|
+
}
|
|
57
|
+
if (Array.isArray(obj)) {
|
|
58
|
+
return obj.map((item) => {
|
|
59
|
+
const safe = toJsonSafe(item, seen);
|
|
60
|
+
return safe === undefined ? null : safe;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
/** @type {Record<string, unknown>} */
|
|
64
|
+
const out = {};
|
|
65
|
+
for (const key of Object.keys(obj)) {
|
|
66
|
+
let raw;
|
|
67
|
+
try {
|
|
68
|
+
raw = /** @type {Record<string, unknown>} */ (obj)[key];
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const safe = toJsonSafe(raw, seen);
|
|
74
|
+
if (safe !== undefined)
|
|
75
|
+
out[key] = safe;
|
|
76
|
+
}
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
seen.delete(obj);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
3
83
|
/**
|
|
4
84
|
* @param {unknown} error
|
|
5
85
|
* @returns {Record<string, unknown>}
|
|
6
86
|
*/
|
|
7
87
|
export function errorToJson(error) {
|
|
88
|
+
return /** @type {Record<string, unknown>} */ (toJsonSafe(buildErrorJson(error), new WeakSet()));
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* @param {unknown} error
|
|
92
|
+
* @returns {Record<string, unknown>}
|
|
93
|
+
*/
|
|
94
|
+
function buildErrorJson(error) {
|
|
8
95
|
const taggedError = fromTaggedError(error);
|
|
9
96
|
if (taggedError) {
|
|
10
|
-
return
|
|
97
|
+
return buildErrorJson(taggedError);
|
|
11
98
|
}
|
|
12
99
|
if (error instanceof SmithersError) {
|
|
13
100
|
return {
|
|
@@ -21,6 +108,17 @@ export function errorToJson(error) {
|
|
|
21
108
|
details: error.details,
|
|
22
109
|
};
|
|
23
110
|
}
|
|
111
|
+
if (error instanceof EngineError) {
|
|
112
|
+
return {
|
|
113
|
+
name: error.name,
|
|
114
|
+
code: error.code,
|
|
115
|
+
message: error.message,
|
|
116
|
+
stack: error.stack,
|
|
117
|
+
cause: error.cause,
|
|
118
|
+
summary: error.message,
|
|
119
|
+
details: error.context,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
24
122
|
if (error instanceof Error) {
|
|
25
123
|
return {
|
|
26
124
|
name: error.name,
|
package/src/index.d.ts
CHANGED
|
@@ -232,6 +232,31 @@ declare namespace smithersErrorDefinitions {
|
|
|
232
232
|
let details_4: string;
|
|
233
233
|
export { details_4 as details };
|
|
234
234
|
}
|
|
235
|
+
namespace TASK_HIJACK_UNSUPPORTED {
|
|
236
|
+
let category: string;
|
|
237
|
+
let when: string;
|
|
238
|
+
let details: string;
|
|
239
|
+
}
|
|
240
|
+
namespace TASK_FORK_SOURCE_NOT_FOUND {
|
|
241
|
+
let category: string;
|
|
242
|
+
let when: string;
|
|
243
|
+
let details: string;
|
|
244
|
+
}
|
|
245
|
+
namespace TASK_FORK_SOURCE_NOT_COMPLETE {
|
|
246
|
+
let category: string;
|
|
247
|
+
let when: string;
|
|
248
|
+
let details: string;
|
|
249
|
+
}
|
|
250
|
+
namespace TASK_FORK_SESSION_UNAVAILABLE {
|
|
251
|
+
let category: string;
|
|
252
|
+
let when: string;
|
|
253
|
+
let details: string;
|
|
254
|
+
}
|
|
255
|
+
namespace TASK_FORK_CYCLE {
|
|
256
|
+
let category: string;
|
|
257
|
+
let when: string;
|
|
258
|
+
let details: string;
|
|
259
|
+
}
|
|
235
260
|
namespace RUN_NOT_FOUND {
|
|
236
261
|
let category_11: string;
|
|
237
262
|
export { category_11 as category };
|
|
@@ -570,6 +595,16 @@ declare namespace smithersErrorDefinitions {
|
|
|
570
595
|
let when_58: string;
|
|
571
596
|
export { when_58 as when };
|
|
572
597
|
}
|
|
598
|
+
namespace AGENT_CONFIG_INVALID {
|
|
599
|
+
let category: string;
|
|
600
|
+
let when: string;
|
|
601
|
+
}
|
|
602
|
+
namespace AGENT_QUOTA_EXCEEDED {
|
|
603
|
+
let category_90: string;
|
|
604
|
+
export { category_90 as category };
|
|
605
|
+
let when_90: string;
|
|
606
|
+
export { when_90 as when };
|
|
607
|
+
}
|
|
573
608
|
namespace AGENT_RPC_FILE_ARGS {
|
|
574
609
|
let category_59: string;
|
|
575
610
|
export { category_59 as category };
|
|
@@ -588,161 +623,193 @@ declare namespace smithersErrorDefinitions {
|
|
|
588
623
|
let when_61: string;
|
|
589
624
|
export { when_61 as when };
|
|
590
625
|
}
|
|
591
|
-
namespace
|
|
626
|
+
namespace ACCOUNT_INVALID {
|
|
592
627
|
let category_62: string;
|
|
593
628
|
export { category_62 as category };
|
|
594
629
|
let when_62: string;
|
|
595
630
|
export { when_62 as when };
|
|
596
631
|
}
|
|
597
|
-
namespace
|
|
632
|
+
namespace ACCOUNT_NOT_FOUND {
|
|
598
633
|
let category_63: string;
|
|
599
634
|
export { category_63 as category };
|
|
600
635
|
let when_63: string;
|
|
601
636
|
export { when_63 as when };
|
|
602
637
|
}
|
|
603
|
-
namespace
|
|
638
|
+
namespace ACCOUNT_DUPLICATE_LABEL {
|
|
604
639
|
let category_64: string;
|
|
605
640
|
export { category_64 as category };
|
|
606
641
|
let when_64: string;
|
|
607
642
|
export { when_64 as when };
|
|
608
643
|
}
|
|
609
|
-
namespace
|
|
644
|
+
namespace ACCOUNTS_FILE_INVALID {
|
|
610
645
|
let category_65: string;
|
|
611
646
|
export { category_65 as category };
|
|
612
647
|
let when_65: string;
|
|
613
648
|
export { when_65 as when };
|
|
614
649
|
}
|
|
615
|
-
namespace
|
|
650
|
+
namespace DB_MISSING_COLUMNS {
|
|
616
651
|
let category_66: string;
|
|
617
652
|
export { category_66 as category };
|
|
618
653
|
let when_66: string;
|
|
619
654
|
export { when_66 as when };
|
|
620
655
|
}
|
|
621
|
-
namespace
|
|
656
|
+
namespace DB_REQUIRES_BUN_SQLITE {
|
|
622
657
|
let category_67: string;
|
|
623
658
|
export { category_67 as category };
|
|
624
659
|
let when_67: string;
|
|
625
660
|
export { when_67 as when };
|
|
626
661
|
}
|
|
627
|
-
namespace
|
|
662
|
+
namespace DB_QUERY_FAILED {
|
|
628
663
|
let category_68: string;
|
|
629
664
|
export { category_68 as category };
|
|
630
665
|
let when_68: string;
|
|
631
666
|
export { when_68 as when };
|
|
632
|
-
let details_30: string;
|
|
633
|
-
export { details_30 as details };
|
|
634
667
|
}
|
|
635
|
-
namespace
|
|
668
|
+
namespace DB_WRITE_FAILED {
|
|
636
669
|
let category_69: string;
|
|
637
670
|
export { category_69 as category };
|
|
638
671
|
let when_69: string;
|
|
639
672
|
export { when_69 as when };
|
|
640
|
-
let details_31: string;
|
|
641
|
-
export { details_31 as details };
|
|
642
673
|
}
|
|
643
|
-
namespace
|
|
674
|
+
namespace SMITHERS_MIGRATION_REQUIRED {
|
|
675
|
+
let category_mig: string;
|
|
676
|
+
export { category_mig as category };
|
|
677
|
+
let when_mig: string;
|
|
678
|
+
export { when_mig as when };
|
|
679
|
+
let details_mig: string;
|
|
680
|
+
export { details_mig as details };
|
|
681
|
+
}
|
|
682
|
+
namespace STORAGE_ERROR {
|
|
644
683
|
let category_70: string;
|
|
645
684
|
export { category_70 as category };
|
|
646
685
|
let when_70: string;
|
|
647
686
|
export { when_70 as when };
|
|
648
|
-
let details_32: string;
|
|
649
|
-
export { details_32 as details };
|
|
650
687
|
}
|
|
651
|
-
namespace
|
|
688
|
+
namespace INTERNAL_ERROR {
|
|
652
689
|
let category_71: string;
|
|
653
690
|
export { category_71 as category };
|
|
654
691
|
let when_71: string;
|
|
655
692
|
export { when_71 as when };
|
|
656
|
-
let details_33: string;
|
|
657
|
-
export { details_33 as details };
|
|
658
693
|
}
|
|
659
|
-
namespace
|
|
694
|
+
namespace PROCESS_ABORTED {
|
|
660
695
|
let category_72: string;
|
|
661
696
|
export { category_72 as category };
|
|
662
697
|
let when_72: string;
|
|
663
698
|
export { when_72 as when };
|
|
699
|
+
let details_30: string;
|
|
700
|
+
export { details_30 as details };
|
|
664
701
|
}
|
|
665
|
-
namespace
|
|
702
|
+
namespace PROCESS_TIMEOUT {
|
|
666
703
|
let category_73: string;
|
|
667
704
|
export { category_73 as category };
|
|
668
705
|
let when_73: string;
|
|
669
706
|
export { when_73 as when };
|
|
707
|
+
let details_31: string;
|
|
708
|
+
export { details_31 as details };
|
|
670
709
|
}
|
|
671
|
-
namespace
|
|
710
|
+
namespace PROCESS_IDLE_TIMEOUT {
|
|
672
711
|
let category_74: string;
|
|
673
712
|
export { category_74 as category };
|
|
674
713
|
let when_74: string;
|
|
675
714
|
export { when_74 as when };
|
|
715
|
+
let details_32: string;
|
|
716
|
+
export { details_32 as details };
|
|
676
717
|
}
|
|
677
|
-
namespace
|
|
718
|
+
namespace PROCESS_SPAWN_FAILED {
|
|
678
719
|
let category_75: string;
|
|
679
720
|
export { category_75 as category };
|
|
680
721
|
let when_75: string;
|
|
681
722
|
export { when_75 as when };
|
|
723
|
+
let details_33: string;
|
|
724
|
+
export { details_33 as details };
|
|
682
725
|
}
|
|
683
|
-
namespace
|
|
726
|
+
namespace TASK_RUNTIME_UNAVAILABLE {
|
|
684
727
|
let category_76: string;
|
|
685
728
|
export { category_76 as category };
|
|
686
729
|
let when_76: string;
|
|
687
730
|
export { when_76 as when };
|
|
688
731
|
}
|
|
689
|
-
namespace
|
|
732
|
+
namespace SCHEMA_CHANGE_HOT {
|
|
690
733
|
let category_77: string;
|
|
691
734
|
export { category_77 as category };
|
|
692
735
|
let when_77: string;
|
|
693
736
|
export { when_77 as when };
|
|
694
737
|
}
|
|
695
|
-
namespace
|
|
738
|
+
namespace HOT_OVERLAY_FAILED {
|
|
696
739
|
let category_78: string;
|
|
697
740
|
export { category_78 as category };
|
|
698
741
|
let when_78: string;
|
|
699
742
|
export { when_78 as when };
|
|
700
743
|
}
|
|
701
|
-
namespace
|
|
744
|
+
namespace HOT_RELOAD_INVALID_MODULE {
|
|
702
745
|
let category_79: string;
|
|
703
746
|
export { category_79 as category };
|
|
704
747
|
let when_79: string;
|
|
705
748
|
export { when_79 as when };
|
|
706
749
|
}
|
|
707
|
-
namespace
|
|
750
|
+
namespace SCORER_FAILED {
|
|
708
751
|
let category_80: string;
|
|
709
752
|
export { category_80 as category };
|
|
710
753
|
let when_80: string;
|
|
711
754
|
export { when_80 as when };
|
|
712
755
|
}
|
|
713
|
-
namespace
|
|
756
|
+
namespace WORKFLOW_EXISTS {
|
|
714
757
|
let category_81: string;
|
|
715
758
|
export { category_81 as category };
|
|
716
759
|
let when_81: string;
|
|
717
760
|
export { when_81 as when };
|
|
718
|
-
let details_34: string;
|
|
719
|
-
export { details_34 as details };
|
|
720
761
|
}
|
|
721
|
-
namespace
|
|
762
|
+
namespace CLI_DB_NOT_FOUND {
|
|
722
763
|
let category_82: string;
|
|
723
764
|
export { category_82 as category };
|
|
724
765
|
let when_82: string;
|
|
725
766
|
export { when_82 as when };
|
|
726
|
-
let details_35: string;
|
|
727
|
-
export { details_35 as details };
|
|
728
767
|
}
|
|
729
|
-
namespace
|
|
768
|
+
namespace CLI_AGENT_UNSUPPORTED {
|
|
730
769
|
let category_83: string;
|
|
731
770
|
export { category_83 as category };
|
|
732
771
|
let when_83: string;
|
|
733
772
|
export { when_83 as when };
|
|
734
773
|
}
|
|
735
|
-
namespace
|
|
774
|
+
namespace PI_HTTP_ERROR {
|
|
736
775
|
let category_84: string;
|
|
737
776
|
export { category_84 as category };
|
|
738
777
|
let when_84: string;
|
|
739
778
|
export { when_84 as when };
|
|
740
779
|
}
|
|
741
|
-
namespace
|
|
780
|
+
namespace EXTERNAL_BUILD_FAILED {
|
|
742
781
|
let category_85: string;
|
|
743
782
|
export { category_85 as category };
|
|
744
783
|
let when_85: string;
|
|
745
784
|
export { when_85 as when };
|
|
785
|
+
let details_34: string;
|
|
786
|
+
export { details_34 as details };
|
|
787
|
+
}
|
|
788
|
+
namespace SCHEMA_DISCOVERY_FAILED {
|
|
789
|
+
let category_86: string;
|
|
790
|
+
export { category_86 as category };
|
|
791
|
+
let when_86: string;
|
|
792
|
+
export { when_86 as when };
|
|
793
|
+
let details_35: string;
|
|
794
|
+
export { details_35 as details };
|
|
795
|
+
}
|
|
796
|
+
namespace OPENAPI_SPEC_LOAD_FAILED {
|
|
797
|
+
let category_87: string;
|
|
798
|
+
export { category_87 as category };
|
|
799
|
+
let when_87: string;
|
|
800
|
+
export { when_87 as when };
|
|
801
|
+
}
|
|
802
|
+
namespace OPENAPI_OPERATION_NOT_FOUND {
|
|
803
|
+
let category_88: string;
|
|
804
|
+
export { category_88 as category };
|
|
805
|
+
let when_88: string;
|
|
806
|
+
export { when_88 as when };
|
|
807
|
+
}
|
|
808
|
+
namespace OPENAPI_TOOL_EXECUTION_FAILED {
|
|
809
|
+
let category_89: string;
|
|
810
|
+
export { category_89 as category };
|
|
811
|
+
let when_89: string;
|
|
812
|
+
export { when_89 as when };
|
|
746
813
|
}
|
|
747
814
|
}
|
|
748
815
|
|
package/src/index.js
CHANGED
package/src/isSmithersError.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { isKnownSmithersErrorCode } from "./isKnownSmithersErrorCode.js";
|
|
2
1
|
import { SmithersError } from "./SmithersError.js";
|
|
3
2
|
/** @typedef {import("./SmithersError.js").SmithersError} SmithersError */
|
|
4
3
|
/**
|
|
@@ -6,13 +5,5 @@ import { SmithersError } from "./SmithersError.js";
|
|
|
6
5
|
* @returns {value is SmithersError}
|
|
7
6
|
*/
|
|
8
7
|
export function isSmithersError(value) {
|
|
9
|
-
|
|
10
|
-
return true;
|
|
11
|
-
}
|
|
12
|
-
return Boolean(value &&
|
|
13
|
-
typeof value === "object" &&
|
|
14
|
-
"code" in value &&
|
|
15
|
-
typeof (/** @type {{ code?: unknown }} */ (value).code) === "string" &&
|
|
16
|
-
isKnownSmithersErrorCode(/** @type {{ code: string }} */ (value).code) &&
|
|
17
|
-
"message" in value);
|
|
8
|
+
return value instanceof SmithersError;
|
|
18
9
|
}
|
|
@@ -13,7 +13,7 @@ export const smithersErrorDefinitions = {
|
|
|
13
13
|
},
|
|
14
14
|
RESUME_METADATA_MISMATCH: {
|
|
15
15
|
category: "engine",
|
|
16
|
-
when: "Stored run metadata no longer matches the workflow being resumed.",
|
|
16
|
+
when: "Stored run metadata no longer matches the workflow being resumed. Editing the workflow entry file or an imported module between stop and resume triggers this (resume hashes file content, not git); fork/replay onto the edit or start a fresh run instead of resuming.",
|
|
17
17
|
},
|
|
18
18
|
UNKNOWN_OUTPUT_SCHEMA: {
|
|
19
19
|
category: "engine",
|
|
@@ -290,6 +290,11 @@ export const smithersErrorDefinitions = {
|
|
|
290
290
|
category: "agents",
|
|
291
291
|
when: "A CLI-backed agent exits unsuccessfully, streams an explicit error, or its RPC transport fails.",
|
|
292
292
|
},
|
|
293
|
+
AGENT_QUOTA_EXCEEDED: {
|
|
294
|
+
category: "agents",
|
|
295
|
+
when: "An agent provider returns a usage-limit or quota error. The failure is transient; retries are preserved and the run pauses until the reset time.",
|
|
296
|
+
details: "{ agentId?, agentEngine?, agentModel?, quotaResetAtMs?, resetHint? }",
|
|
297
|
+
},
|
|
293
298
|
AGENT_CONFIG_INVALID: {
|
|
294
299
|
category: "agents",
|
|
295
300
|
when: "A CLI-backed agent fails with a non-retryable configuration error (e.g. unknown model, missing LLM, unsupported model). Includes agent id, engine and model in details so the offending entry in .smithers/agents.ts can be located.",
|
|
@@ -306,6 +311,22 @@ export const smithersErrorDefinitions = {
|
|
|
306
311
|
category: "agents",
|
|
307
312
|
when: "An internal agent diagnostic check exceeds the per-check timeout budget.",
|
|
308
313
|
},
|
|
314
|
+
ACCOUNT_INVALID: {
|
|
315
|
+
category: "integrations",
|
|
316
|
+
when: "An account entry, label, provider, or provider-specific configuration is invalid.",
|
|
317
|
+
},
|
|
318
|
+
ACCOUNT_NOT_FOUND: {
|
|
319
|
+
category: "integrations",
|
|
320
|
+
when: "An account operation references a label that is not registered.",
|
|
321
|
+
},
|
|
322
|
+
ACCOUNT_DUPLICATE_LABEL: {
|
|
323
|
+
category: "integrations",
|
|
324
|
+
when: "An account add operation would create a duplicate label without replace enabled.",
|
|
325
|
+
},
|
|
326
|
+
ACCOUNTS_FILE_INVALID: {
|
|
327
|
+
category: "integrations",
|
|
328
|
+
when: "The accounts.json file is not valid JSON or does not match the expected account registry schema.",
|
|
329
|
+
},
|
|
309
330
|
DB_MISSING_COLUMNS: {
|
|
310
331
|
category: "database",
|
|
311
332
|
when: "A table used by Smithers does not expose required columns such as runId or nodeId.",
|
|
@@ -322,6 +343,11 @@ export const smithersErrorDefinitions = {
|
|
|
322
343
|
category: "database",
|
|
323
344
|
when: "A database write or migration fails, including after SQLite retry exhaustion.",
|
|
324
345
|
},
|
|
346
|
+
SMITHERS_MIGRATION_REQUIRED: {
|
|
347
|
+
category: "cli",
|
|
348
|
+
when: "A legacy SQLite store holds run data but the resolved backend is pglite/postgres with no migrated.json, or the store schema version is unsatisfiable in place.",
|
|
349
|
+
details: "{ dbPath, runCount, schemaVersion, resolvedBackend }",
|
|
350
|
+
},
|
|
325
351
|
STORAGE_ERROR: {
|
|
326
352
|
category: "database",
|
|
327
353
|
when: "A storage service operation fails before surfacing a more specific database code.",
|
|
@@ -10,6 +10,20 @@ import { isSmithersTaggedError } from "./isSmithersTaggedError.js";
|
|
|
10
10
|
function isRecord(value) {
|
|
11
11
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Coerce a value to a finite number. The payload type contract requires these
|
|
15
|
+
* fields to be `number`, but `Number(undefined)` is `NaN`, which `JSON.stringify`
|
|
16
|
+
* silently turns into `null` — corrupting the value that retry/backoff logic
|
|
17
|
+
* reads back after a durable round-trip. Fall back to a defined finite value.
|
|
18
|
+
*
|
|
19
|
+
* @param {unknown} value
|
|
20
|
+
* @param {number} [fallback]
|
|
21
|
+
* @returns {number}
|
|
22
|
+
*/
|
|
23
|
+
function toFiniteNumber(value, fallback = 0) {
|
|
24
|
+
const num = typeof value === "number" ? value : Number(value);
|
|
25
|
+
return Number.isFinite(num) ? num : fallback;
|
|
26
|
+
}
|
|
13
27
|
/**
|
|
14
28
|
* @param {unknown} error
|
|
15
29
|
* @returns {SmithersTaggedErrorPayload | undefined}
|
|
@@ -33,19 +47,19 @@ export function toTaggedErrorPayload(error) {
|
|
|
33
47
|
_tag: "TaskTimeout",
|
|
34
48
|
message: String(error.message),
|
|
35
49
|
nodeId: String(error.nodeId),
|
|
36
|
-
attempt:
|
|
37
|
-
timeoutMs:
|
|
50
|
+
attempt: toFiniteNumber(error.attempt),
|
|
51
|
+
timeoutMs: toFiniteNumber(error.timeoutMs),
|
|
38
52
|
};
|
|
39
53
|
case "TaskHeartbeatTimeout":
|
|
40
54
|
return {
|
|
41
55
|
_tag: "TaskHeartbeatTimeout",
|
|
42
56
|
message: String(error.message),
|
|
43
57
|
nodeId: String(error.nodeId),
|
|
44
|
-
iteration:
|
|
45
|
-
attempt:
|
|
46
|
-
timeoutMs:
|
|
47
|
-
staleForMs:
|
|
48
|
-
lastHeartbeatAtMs:
|
|
58
|
+
iteration: toFiniteNumber(error.iteration),
|
|
59
|
+
attempt: toFiniteNumber(error.attempt),
|
|
60
|
+
timeoutMs: toFiniteNumber(error.timeoutMs),
|
|
61
|
+
staleForMs: toFiniteNumber(error.staleForMs),
|
|
62
|
+
lastHeartbeatAtMs: toFiniteNumber(error.lastHeartbeatAtMs),
|
|
49
63
|
};
|
|
50
64
|
case "RunNotFound":
|
|
51
65
|
return {
|
package/src/tagged.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
// @smithers-type-exports-begin
|
|
2
|
-
/** @typedef {import("./EngineErrorCode.ts").EngineErrorCode} EngineErrorCode */
|
|
3
|
-
/** @typedef {import("./TaggedErrorDetails.ts").GenericTaggedErrorArgs} GenericTaggedErrorArgs */
|
|
4
|
-
/** @typedef {import("./SmithersTaggedError.ts").SmithersTaggedError} SmithersTaggedError */
|
|
5
|
-
/** @typedef {import("./SmithersTaggedErrorPayload.ts").SmithersTaggedErrorPayload} SmithersTaggedErrorPayload */
|
|
6
|
-
/** @typedef {import("./SmithersTaggedErrorTag.ts").SmithersTaggedErrorTag} SmithersTaggedErrorTag */
|
|
7
|
-
/** @typedef {import("./TaggedErrorDetails.ts").TaggedErrorDetails} TaggedErrorDetails */
|
|
8
|
-
// @smithers-type-exports-end
|
|
9
|
-
|
|
10
|
-
export * from "./AgentCliError.js";
|
|
11
|
-
export * from "./DbWriteFailed.js";
|
|
12
|
-
export * from "./EngineError.js";
|
|
13
|
-
export * from "./InvalidInput.js";
|
|
14
|
-
export * from "./RunNotFound.js";
|
|
15
|
-
export * from "./TaskAborted.js";
|
|
16
|
-
export * from "./TaskHeartbeatTimeout.js";
|
|
17
|
-
export * from "./TaskTimeout.js";
|
|
18
|
-
export * from "./WorkflowFailed.js";
|
|
19
|
-
export * from "./fromTaggedError.js";
|
|
20
|
-
export * from "./fromTaggedErrorPayload.js";
|
|
21
|
-
export * from "./isSmithersTaggedError.js";
|
|
22
|
-
export * from "./isSmithersTaggedErrorTag.js";
|
|
23
|
-
export * from "./smithersTaggedErrorCodes.js";
|
|
24
|
-
export * from "./toTaggedErrorPayload.js";
|