@builder.io/ai-utils 0.111.0 → 0.112.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/package.json +1 -1
- package/src/codegen.d.ts +150 -41
- package/src/codegen.js +54 -5
- package/src/events.d.ts +9 -1
- package/src/events.js +4 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +1 -0
- package/src/messages.d.ts +9 -0
- package/src/messages.js +6 -0
- package/src/propose-config.test.d.ts +1 -0
- package/src/propose-config.test.js +94 -0
- package/src/tool-failure.d.ts +95 -0
- package/src/tool-failure.js +68 -0
- package/src/tool-failure.test.d.ts +1 -0
- package/src/tool-failure.test.js +57 -0
package/package.json
CHANGED
package/src/codegen.d.ts
CHANGED
|
@@ -528,10 +528,10 @@ export declare const PublishEvidenceToolInputSchema: z.ZodObject<{
|
|
|
528
528
|
"not-reproduced": "not-reproduced";
|
|
529
529
|
}>;
|
|
530
530
|
summary: z.ZodString;
|
|
531
|
-
screenshots: z.ZodArray<z.ZodObject<{
|
|
531
|
+
screenshots: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
532
532
|
path: z.ZodString;
|
|
533
533
|
caption: z.ZodString;
|
|
534
|
-
}, z.core.$strip
|
|
534
|
+
}, z.core.$strip>>>;
|
|
535
535
|
recordings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
536
536
|
recording_id: z.ZodString;
|
|
537
537
|
}, z.core.$strip>>>;
|
|
@@ -680,7 +680,7 @@ export interface TimelineSubmissionMetadata {
|
|
|
680
680
|
* Configuration values proposed by the setup analyzer agent
|
|
681
681
|
*/
|
|
682
682
|
export declare const SetupAnalysisValuesSchema: z.ZodObject<{
|
|
683
|
-
projectOverview: z.ZodObject<{
|
|
683
|
+
projectOverview: z.ZodNullable<z.ZodObject<{
|
|
684
684
|
framework: z.ZodNullable<z.ZodString>;
|
|
685
685
|
packageManager: z.ZodNullable<z.ZodEnum<{
|
|
686
686
|
bun: "bun";
|
|
@@ -693,7 +693,7 @@ export declare const SetupAnalysisValuesSchema: z.ZodObject<{
|
|
|
693
693
|
javascript: "javascript";
|
|
694
694
|
typescript: "typescript";
|
|
695
695
|
}>>;
|
|
696
|
-
}, z.core.$strip
|
|
696
|
+
}, z.core.$strip>>;
|
|
697
697
|
rootDirectory: z.ZodNullable<z.ZodObject<{
|
|
698
698
|
path: z.ZodString;
|
|
699
699
|
reason: z.ZodString;
|
|
@@ -732,9 +732,86 @@ export declare const SetupAnalysisValuesSchema: z.ZodObject<{
|
|
|
732
732
|
}, z.core.$strip>>;
|
|
733
733
|
}, z.core.$strip>;
|
|
734
734
|
export type SetupAnalysisValues = z.infer<typeof SetupAnalysisValuesSchema>;
|
|
735
|
+
/**
|
|
736
|
+
* What a ProposeConfig call may carry: any subset of the setup values. A
|
|
737
|
+
* nullable field set to null, or any field omitted, means "no suggestion";
|
|
738
|
+
* the array fields (runtimeDependencies, environmentVariables) aren't
|
|
739
|
+
* nullable, so `[]` or omitting them means the same. Either way the existing
|
|
740
|
+
* value is left unchanged when the user applies the proposal.
|
|
741
|
+
*/
|
|
742
|
+
export declare const ProposedSetupValuesSchema: z.ZodObject<{
|
|
743
|
+
projectOverview: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
744
|
+
framework: z.ZodNullable<z.ZodString>;
|
|
745
|
+
packageManager: z.ZodNullable<z.ZodEnum<{
|
|
746
|
+
bun: "bun";
|
|
747
|
+
npm: "npm";
|
|
748
|
+
pnpm: "pnpm";
|
|
749
|
+
yarn: "yarn";
|
|
750
|
+
}>>;
|
|
751
|
+
isMonorepo: z.ZodBoolean;
|
|
752
|
+
detectedLanguage: z.ZodNullable<z.ZodEnum<{
|
|
753
|
+
javascript: "javascript";
|
|
754
|
+
typescript: "typescript";
|
|
755
|
+
}>>;
|
|
756
|
+
}, z.core.$strip>>>;
|
|
757
|
+
rootDirectory: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
758
|
+
path: z.ZodString;
|
|
759
|
+
reason: z.ZodString;
|
|
760
|
+
}, z.core.$strip>>>;
|
|
761
|
+
installCommand: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
762
|
+
command: z.ZodString;
|
|
763
|
+
reason: z.ZodString;
|
|
764
|
+
}, z.core.$strip>>>;
|
|
765
|
+
runtimeDependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
766
|
+
tool: z.ZodString;
|
|
767
|
+
version: z.ZodString;
|
|
768
|
+
source: z.ZodString;
|
|
769
|
+
}, z.core.$strip>>>;
|
|
770
|
+
devServer: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
771
|
+
command: z.ZodString;
|
|
772
|
+
url: z.ZodString;
|
|
773
|
+
port: z.ZodNumber;
|
|
774
|
+
reason: z.ZodString;
|
|
775
|
+
}, z.core.$strip>>>;
|
|
776
|
+
environmentVariables: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
777
|
+
key: z.ZodString;
|
|
778
|
+
description: z.ZodString;
|
|
779
|
+
isRequired: z.ZodBoolean;
|
|
780
|
+
isSecret: z.ZodBoolean;
|
|
781
|
+
defaultValue: z.ZodNullable<z.ZodString>;
|
|
782
|
+
source: z.ZodString;
|
|
783
|
+
}, z.core.$strip>>>;
|
|
784
|
+
validationScript: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
785
|
+
command: z.ZodString;
|
|
786
|
+
reason: z.ZodString;
|
|
787
|
+
}, z.core.$strip>>>;
|
|
788
|
+
npmrcContents: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
789
|
+
hasHotModuleReload: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
790
|
+
value: z.ZodBoolean;
|
|
791
|
+
reason: z.ZodString;
|
|
792
|
+
}, z.core.$strip>>>;
|
|
793
|
+
}, z.core.$strip>;
|
|
794
|
+
export type ProposedSetupValues = z.infer<typeof ProposedSetupValuesSchema>;
|
|
795
|
+
/**
|
|
796
|
+
* True only when a proposal affirmatively says nothing needs installing: an
|
|
797
|
+
* explicitly empty install command (`{ command: "" }`) and an explicit empty
|
|
798
|
+
* `runtimeDependencies` list. A null or omitted install command means "no
|
|
799
|
+
* suggestion", so it is unknown rather than "no dependencies", even when the
|
|
800
|
+
* proposal also carries projectOverview.
|
|
801
|
+
*/
|
|
802
|
+
export declare function proposalNeedsNoDependencies(config: ProposedSetupValues | null | undefined): boolean;
|
|
803
|
+
/**
|
|
804
|
+
* `noDependencies` for replaying a stored propose_config step. Uses the
|
|
805
|
+
* decision recorded on the action (`toolMeta.noDependencies`) when present,
|
|
806
|
+
* so a replay always matches the live run. Actions recorded before that
|
|
807
|
+
* marker existed keep the original replay reading (no install command and no
|
|
808
|
+
* runtime dependencies means nothing to install), so old sessions don't
|
|
809
|
+
* change on reload.
|
|
810
|
+
*/
|
|
811
|
+
export declare function replayedProposalNeedsNoDependencies(config: ProposedSetupValues | null | undefined, recorded: ToolActionMeta | undefined): boolean;
|
|
735
812
|
export declare const ProposeConfigToolInputSchema: z.ZodObject<{
|
|
736
813
|
config: z.ZodObject<{
|
|
737
|
-
projectOverview: z.ZodObject<{
|
|
814
|
+
projectOverview: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
738
815
|
framework: z.ZodNullable<z.ZodString>;
|
|
739
816
|
packageManager: z.ZodNullable<z.ZodEnum<{
|
|
740
817
|
bun: "bun";
|
|
@@ -747,43 +824,43 @@ export declare const ProposeConfigToolInputSchema: z.ZodObject<{
|
|
|
747
824
|
javascript: "javascript";
|
|
748
825
|
typescript: "typescript";
|
|
749
826
|
}>>;
|
|
750
|
-
}, z.core.$strip
|
|
751
|
-
rootDirectory: z.ZodNullable<z.ZodObject<{
|
|
827
|
+
}, z.core.$strip>>>;
|
|
828
|
+
rootDirectory: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
752
829
|
path: z.ZodString;
|
|
753
830
|
reason: z.ZodString;
|
|
754
|
-
}, z.core.$strip
|
|
755
|
-
installCommand: z.ZodNullable<z.ZodObject<{
|
|
831
|
+
}, z.core.$strip>>>;
|
|
832
|
+
installCommand: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
756
833
|
command: z.ZodString;
|
|
757
834
|
reason: z.ZodString;
|
|
758
|
-
}, z.core.$strip
|
|
759
|
-
runtimeDependencies: z.ZodArray<z.ZodObject<{
|
|
835
|
+
}, z.core.$strip>>>;
|
|
836
|
+
runtimeDependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
760
837
|
tool: z.ZodString;
|
|
761
838
|
version: z.ZodString;
|
|
762
839
|
source: z.ZodString;
|
|
763
|
-
}, z.core.$strip
|
|
764
|
-
devServer: z.ZodNullable<z.ZodObject<{
|
|
840
|
+
}, z.core.$strip>>>;
|
|
841
|
+
devServer: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
765
842
|
command: z.ZodString;
|
|
766
843
|
url: z.ZodString;
|
|
767
844
|
port: z.ZodNumber;
|
|
768
845
|
reason: z.ZodString;
|
|
769
|
-
}, z.core.$strip
|
|
770
|
-
environmentVariables: z.ZodArray<z.ZodObject<{
|
|
846
|
+
}, z.core.$strip>>>;
|
|
847
|
+
environmentVariables: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
771
848
|
key: z.ZodString;
|
|
772
849
|
description: z.ZodString;
|
|
773
850
|
isRequired: z.ZodBoolean;
|
|
774
851
|
isSecret: z.ZodBoolean;
|
|
775
852
|
defaultValue: z.ZodNullable<z.ZodString>;
|
|
776
853
|
source: z.ZodString;
|
|
777
|
-
}, z.core.$strip
|
|
778
|
-
validationScript: z.ZodNullable<z.ZodObject<{
|
|
854
|
+
}, z.core.$strip>>>;
|
|
855
|
+
validationScript: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
779
856
|
command: z.ZodString;
|
|
780
857
|
reason: z.ZodString;
|
|
781
|
-
}, z.core.$strip
|
|
782
|
-
npmrcContents: z.ZodNullable<z.ZodString
|
|
783
|
-
hasHotModuleReload: z.ZodNullable<z.ZodObject<{
|
|
858
|
+
}, z.core.$strip>>>;
|
|
859
|
+
npmrcContents: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
860
|
+
hasHotModuleReload: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
784
861
|
value: z.ZodBoolean;
|
|
785
862
|
reason: z.ZodString;
|
|
786
|
-
}, z.core.$strip
|
|
863
|
+
}, z.core.$strip>>>;
|
|
787
864
|
}, z.core.$strip>;
|
|
788
865
|
message: z.ZodOptional<z.ZodString>;
|
|
789
866
|
}, z.core.$strip>;
|
|
@@ -1706,10 +1783,10 @@ export declare const CodeGenToolMapSchema: z.ZodObject<{
|
|
|
1706
1783
|
"not-reproduced": "not-reproduced";
|
|
1707
1784
|
}>;
|
|
1708
1785
|
summary: z.ZodString;
|
|
1709
|
-
screenshots: z.ZodArray<z.ZodObject<{
|
|
1786
|
+
screenshots: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1710
1787
|
path: z.ZodString;
|
|
1711
1788
|
caption: z.ZodString;
|
|
1712
|
-
}, z.core.$strip
|
|
1789
|
+
}, z.core.$strip>>>;
|
|
1713
1790
|
recordings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1714
1791
|
recording_id: z.ZodString;
|
|
1715
1792
|
}, z.core.$strip>>>;
|
|
@@ -1762,7 +1839,7 @@ export declare const CodeGenToolMapSchema: z.ZodObject<{
|
|
|
1762
1839
|
}, z.core.$strip>;
|
|
1763
1840
|
ProposeConfig: z.ZodObject<{
|
|
1764
1841
|
config: z.ZodObject<{
|
|
1765
|
-
projectOverview: z.ZodObject<{
|
|
1842
|
+
projectOverview: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
1766
1843
|
framework: z.ZodNullable<z.ZodString>;
|
|
1767
1844
|
packageManager: z.ZodNullable<z.ZodEnum<{
|
|
1768
1845
|
bun: "bun";
|
|
@@ -1775,43 +1852,43 @@ export declare const CodeGenToolMapSchema: z.ZodObject<{
|
|
|
1775
1852
|
javascript: "javascript";
|
|
1776
1853
|
typescript: "typescript";
|
|
1777
1854
|
}>>;
|
|
1778
|
-
}, z.core.$strip
|
|
1779
|
-
rootDirectory: z.ZodNullable<z.ZodObject<{
|
|
1855
|
+
}, z.core.$strip>>>;
|
|
1856
|
+
rootDirectory: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
1780
1857
|
path: z.ZodString;
|
|
1781
1858
|
reason: z.ZodString;
|
|
1782
|
-
}, z.core.$strip
|
|
1783
|
-
installCommand: z.ZodNullable<z.ZodObject<{
|
|
1859
|
+
}, z.core.$strip>>>;
|
|
1860
|
+
installCommand: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
1784
1861
|
command: z.ZodString;
|
|
1785
1862
|
reason: z.ZodString;
|
|
1786
|
-
}, z.core.$strip
|
|
1787
|
-
runtimeDependencies: z.ZodArray<z.ZodObject<{
|
|
1863
|
+
}, z.core.$strip>>>;
|
|
1864
|
+
runtimeDependencies: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1788
1865
|
tool: z.ZodString;
|
|
1789
1866
|
version: z.ZodString;
|
|
1790
1867
|
source: z.ZodString;
|
|
1791
|
-
}, z.core.$strip
|
|
1792
|
-
devServer: z.ZodNullable<z.ZodObject<{
|
|
1868
|
+
}, z.core.$strip>>>;
|
|
1869
|
+
devServer: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
1793
1870
|
command: z.ZodString;
|
|
1794
1871
|
url: z.ZodString;
|
|
1795
1872
|
port: z.ZodNumber;
|
|
1796
1873
|
reason: z.ZodString;
|
|
1797
|
-
}, z.core.$strip
|
|
1798
|
-
environmentVariables: z.ZodArray<z.ZodObject<{
|
|
1874
|
+
}, z.core.$strip>>>;
|
|
1875
|
+
environmentVariables: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
1799
1876
|
key: z.ZodString;
|
|
1800
1877
|
description: z.ZodString;
|
|
1801
1878
|
isRequired: z.ZodBoolean;
|
|
1802
1879
|
isSecret: z.ZodBoolean;
|
|
1803
1880
|
defaultValue: z.ZodNullable<z.ZodString>;
|
|
1804
1881
|
source: z.ZodString;
|
|
1805
|
-
}, z.core.$strip
|
|
1806
|
-
validationScript: z.ZodNullable<z.ZodObject<{
|
|
1882
|
+
}, z.core.$strip>>>;
|
|
1883
|
+
validationScript: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
1807
1884
|
command: z.ZodString;
|
|
1808
1885
|
reason: z.ZodString;
|
|
1809
|
-
}, z.core.$strip
|
|
1810
|
-
npmrcContents: z.ZodNullable<z.ZodString
|
|
1811
|
-
hasHotModuleReload: z.ZodNullable<z.ZodObject<{
|
|
1886
|
+
}, z.core.$strip>>>;
|
|
1887
|
+
npmrcContents: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1888
|
+
hasHotModuleReload: z.ZodOptional<z.ZodNullable<z.ZodObject<{
|
|
1812
1889
|
value: z.ZodBoolean;
|
|
1813
1890
|
reason: z.ZodString;
|
|
1814
|
-
}, z.core.$strip
|
|
1891
|
+
}, z.core.$strip>>>;
|
|
1815
1892
|
}, z.core.$strip>;
|
|
1816
1893
|
message: z.ZodOptional<z.ZodString>;
|
|
1817
1894
|
}, z.core.$strip>;
|
|
@@ -2406,6 +2483,15 @@ export declare const PublishAgentMessageRequestSchema: z.ZodObject<{
|
|
|
2406
2483
|
}, z.core.$strip>;
|
|
2407
2484
|
}, z.core.$strip>], "type">>]>;
|
|
2408
2485
|
is_error: z.ZodOptional<z.ZodBoolean>;
|
|
2486
|
+
error_kind: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
2487
|
+
command_not_found: "command_not_found";
|
|
2488
|
+
guardrail: "guardrail";
|
|
2489
|
+
invalid_input: "invalid_input";
|
|
2490
|
+
non_zero_exit: "non_zero_exit";
|
|
2491
|
+
policy_block: "policy_block";
|
|
2492
|
+
tool_failure: "tool_failure";
|
|
2493
|
+
user_abort: "user_abort";
|
|
2494
|
+
}>>>;
|
|
2409
2495
|
cache: z.ZodOptional<z.ZodBoolean>;
|
|
2410
2496
|
ephemeral: z.ZodOptional<z.ZodBoolean>;
|
|
2411
2497
|
structured_result: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
@@ -2817,6 +2903,15 @@ export declare const CodeGenInputOptionsSchema: z.ZodObject<{
|
|
|
2817
2903
|
}, z.core.$strip>;
|
|
2818
2904
|
}, z.core.$strip>], "type">>]>;
|
|
2819
2905
|
is_error: z.ZodOptional<z.ZodBoolean>;
|
|
2906
|
+
error_kind: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
2907
|
+
command_not_found: "command_not_found";
|
|
2908
|
+
guardrail: "guardrail";
|
|
2909
|
+
invalid_input: "invalid_input";
|
|
2910
|
+
non_zero_exit: "non_zero_exit";
|
|
2911
|
+
policy_block: "policy_block";
|
|
2912
|
+
tool_failure: "tool_failure";
|
|
2913
|
+
user_abort: "user_abort";
|
|
2914
|
+
}>>>;
|
|
2820
2915
|
cache: z.ZodOptional<z.ZodBoolean>;
|
|
2821
2916
|
ephemeral: z.ZodOptional<z.ZodBoolean>;
|
|
2822
2917
|
structured_result: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
@@ -3185,6 +3280,19 @@ export interface ActionItem {
|
|
|
3185
3280
|
incomplete?: boolean;
|
|
3186
3281
|
suggestions?: PromptSuggestion[];
|
|
3187
3282
|
errors?: string[];
|
|
3283
|
+
/**
|
|
3284
|
+
* Decisions the service recorded for a tool call, persisted with the
|
|
3285
|
+
* action so replays reproduce what the live run showed. Optional and
|
|
3286
|
+
* ignored by clients that don't know it.
|
|
3287
|
+
*/
|
|
3288
|
+
toolMeta?: ToolActionMeta;
|
|
3289
|
+
}
|
|
3290
|
+
export interface ToolActionMeta {
|
|
3291
|
+
/**
|
|
3292
|
+
* ProposeConfig: `proposalNeedsNoDependencies` for this call's config.
|
|
3293
|
+
* Absent on actions recorded before it existed.
|
|
3294
|
+
*/
|
|
3295
|
+
noDependencies?: boolean;
|
|
3188
3296
|
}
|
|
3189
3297
|
export interface GenerateCompletionStepThinking {
|
|
3190
3298
|
type: "thinking";
|
|
@@ -3647,7 +3755,8 @@ export interface GenerateCompletionStepIde {
|
|
|
3647
3755
|
}
|
|
3648
3756
|
export interface GenerateCompletionStepProposeConfig {
|
|
3649
3757
|
type: "propose_config";
|
|
3650
|
-
|
|
3758
|
+
/** May be partial: omitted or null fields mean "no suggestion". */
|
|
3759
|
+
config: ProposedSetupValues;
|
|
3651
3760
|
message?: string;
|
|
3652
3761
|
/** When true, the project requires no dependency installation. The UI should not show an Apply dialog for dependencies. */
|
|
3653
3762
|
noDependencies?: boolean;
|
package/src/codegen.js
CHANGED
|
@@ -277,7 +277,7 @@ export const PowerShellToolInputSchema = z
|
|
|
277
277
|
description: "The PowerShell command to run, for example 'npm install' or 'yarn test'",
|
|
278
278
|
}),
|
|
279
279
|
timeout: z.number().nullish().meta({
|
|
280
|
-
description: "
|
|
280
|
+
description: "Optional timeout in milliseconds (max/default 600000). Omit it for installs, builds, type checks and test runs, which are often slow on Windows.",
|
|
281
281
|
}),
|
|
282
282
|
description: z.string().nullish().meta({
|
|
283
283
|
description: "A human readable description of the command to run, for example 'install dependencies' or 'run tests'. This description will be used to explain the command to the user.",
|
|
@@ -789,8 +789,9 @@ export const PublishEvidenceToolInputSchema = z
|
|
|
789
789
|
}),
|
|
790
790
|
caption: z.string(),
|
|
791
791
|
}))
|
|
792
|
+
.optional()
|
|
792
793
|
.meta({
|
|
793
|
-
description: "Stills that support the fix; the PR shows them under the recording.",
|
|
794
|
+
description: "Stills that support the fix; the PR shows them under the recording. Expected for a 'fixed' issue; omit it or send [] when there are none.",
|
|
794
795
|
}),
|
|
795
796
|
recordings: z
|
|
796
797
|
.array(z.object({
|
|
@@ -847,12 +848,17 @@ export const ReportTestOutcomeToolInputSchema = z
|
|
|
847
848
|
*/
|
|
848
849
|
export const SetupAnalysisValuesSchema = z
|
|
849
850
|
.object({
|
|
850
|
-
|
|
851
|
+
// Nullable: in a partial proposal (e.g. only runtimeDependencies) a null
|
|
852
|
+
// field, or an empty array field, means "no suggestion" and leaves the
|
|
853
|
+
// existing value unchanged when applied.
|
|
854
|
+
projectOverview: z
|
|
855
|
+
.object({
|
|
851
856
|
framework: z.string().nullable(),
|
|
852
857
|
packageManager: z.enum(["npm", "yarn", "pnpm", "bun"]).nullable(),
|
|
853
858
|
isMonorepo: z.boolean(),
|
|
854
859
|
detectedLanguage: z.enum(["typescript", "javascript"]).nullable(),
|
|
855
|
-
})
|
|
860
|
+
})
|
|
861
|
+
.nullable(),
|
|
856
862
|
rootDirectory: z
|
|
857
863
|
.object({
|
|
858
864
|
path: z.string(),
|
|
@@ -901,9 +907,52 @@ export const SetupAnalysisValuesSchema = z
|
|
|
901
907
|
.nullable(),
|
|
902
908
|
})
|
|
903
909
|
.meta({ title: "SetupAnalysisValues" });
|
|
910
|
+
/**
|
|
911
|
+
* What a ProposeConfig call may carry: any subset of the setup values. A
|
|
912
|
+
* nullable field set to null, or any field omitted, means "no suggestion";
|
|
913
|
+
* the array fields (runtimeDependencies, environmentVariables) aren't
|
|
914
|
+
* nullable, so `[]` or omitting them means the same. Either way the existing
|
|
915
|
+
* value is left unchanged when the user applies the proposal.
|
|
916
|
+
*/
|
|
917
|
+
export const ProposedSetupValuesSchema = SetupAnalysisValuesSchema.partial().meta({ title: "ProposedSetupValues" });
|
|
918
|
+
/**
|
|
919
|
+
* True only when a proposal affirmatively says nothing needs installing: an
|
|
920
|
+
* explicitly empty install command (`{ command: "" }`) and an explicit empty
|
|
921
|
+
* `runtimeDependencies` list. A null or omitted install command means "no
|
|
922
|
+
* suggestion", so it is unknown rather than "no dependencies", even when the
|
|
923
|
+
* proposal also carries projectOverview.
|
|
924
|
+
*/
|
|
925
|
+
export function proposalNeedsNoDependencies(config) {
|
|
926
|
+
var _a;
|
|
927
|
+
if (!config || !Array.isArray(config.runtimeDependencies))
|
|
928
|
+
return false;
|
|
929
|
+
if (config.runtimeDependencies.length > 0)
|
|
930
|
+
return false;
|
|
931
|
+
const installCommand = config.installCommand;
|
|
932
|
+
return (installCommand != null &&
|
|
933
|
+
typeof installCommand === "object" &&
|
|
934
|
+
!((_a = installCommand.command) === null || _a === void 0 ? void 0 : _a.trim()));
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* `noDependencies` for replaying a stored propose_config step. Uses the
|
|
938
|
+
* decision recorded on the action (`toolMeta.noDependencies`) when present,
|
|
939
|
+
* so a replay always matches the live run. Actions recorded before that
|
|
940
|
+
* marker existed keep the original replay reading (no install command and no
|
|
941
|
+
* runtime dependencies means nothing to install), so old sessions don't
|
|
942
|
+
* change on reload.
|
|
943
|
+
*/
|
|
944
|
+
export function replayedProposalNeedsNoDependencies(config, recorded) {
|
|
945
|
+
var _a;
|
|
946
|
+
if (typeof (recorded === null || recorded === void 0 ? void 0 : recorded.noDependencies) === "boolean") {
|
|
947
|
+
return recorded.noDependencies;
|
|
948
|
+
}
|
|
949
|
+
return (config != null &&
|
|
950
|
+
!((_a = config.installCommand) === null || _a === void 0 ? void 0 : _a.command) &&
|
|
951
|
+
(!config.runtimeDependencies || config.runtimeDependencies.length === 0));
|
|
952
|
+
}
|
|
904
953
|
export const ProposeConfigToolInputSchema = z
|
|
905
954
|
.object({
|
|
906
|
-
config:
|
|
955
|
+
config: ProposedSetupValuesSchema,
|
|
907
956
|
message: z.string().optional(),
|
|
908
957
|
})
|
|
909
958
|
.meta({ title: "ProposeConfigToolInput" });
|
package/src/events.d.ts
CHANGED
|
@@ -1499,7 +1499,15 @@ export declare const HostingCustomDomainDelegationCheckV1: {
|
|
|
1499
1499
|
eventName: "hosting.custom-domain.delegation-check";
|
|
1500
1500
|
version: "1";
|
|
1501
1501
|
};
|
|
1502
|
-
export type
|
|
1502
|
+
export type BillingAutoTopupRequestedV1 = FusionEventVariant<"billing.auto-topup.requested", {
|
|
1503
|
+
balance: number;
|
|
1504
|
+
thresholdCredits: number;
|
|
1505
|
+
}, {}, 1>;
|
|
1506
|
+
export declare const BillingAutoTopupRequestedV1: {
|
|
1507
|
+
eventName: "billing.auto-topup.requested";
|
|
1508
|
+
version: "1";
|
|
1509
|
+
};
|
|
1510
|
+
export type FusionEvent = ClientDevtoolsSessionStartedEvent | ClientDevtoolsSessionIdleEventV1 | ClientDevtoolsToolCallRequestV1 | ClientDevtoolsToolCallV1 | ClientDevtoolsToolResultV1 | ClientDevtoolsBuildMigratedV1 | ClientDevtoolsBuildCompletedV1 | ClientDevtoolsBuildUploadedV1 | ClientDevtoolsBuildFailedV1 | FusionProjectCreatedV1 | FusionShapeIssuedV1 | FusionShapeAssembledV1 | FusionShapeResolvedV1 | FusionShapeQuestionAnsweredV1 | FusionShapeQuestionSkippedV1 | SetupAgentCompletedV1 | GitPrMergedV1 | GitPrCreatedV1 | GitPrClosedV1 | ForceSetupAgentV1 | ClawMessageSentV1 | CodegenCompletionV1 | CodegenUserPromptV1 | GitWebhooksRegisterV1 | FusionProjectSettingsUpdatedV1 | VideoRecordingCompletedV1 | TimelineRecordingReadyV1 | FusionBranchCreatedV1 | FusionContainerStartedV1 | FusionContainerFailedV1 | FusionPreviewReadyV1 | FusionPreviewFailedV1 | FusionBranchFailedV1 | BotMentionGitHubExternalPrV1 | BotMentionGitHubInternalPrV1 | BotMentionGitLabPrV1 | BotMentionBitbucketPrV1 | BotMentionAzurePrV1 | ReviewSubmittedV1 | PrReviewRequestedV1 | FigmaDecodeJobV1 | ProjectSnapshotRefreshV1 | ProjectSnapshotGoldenWatchdogV1 | ProjectSnapshotGoldenRetryV1 | ProjectSnapshotCapturedV1 | ProjectSnapshotCreatedV1 | ProjectSnapshotFailedV1 | ProjectSnapshotReadyCheckV1 | ProjectSnapshotPodWatchV1 | McpPrototypePulledV1 | HostingCustomDomainCertCheckV1 | HostingCustomDomainServingCheckV1 | HostingCustomDomainDelegationCheckV1 | BillingAutoTopupRequestedV1;
|
|
1503
1511
|
export interface ModelPermissionRequiredEvent {
|
|
1504
1512
|
type: "assistant.model.permission.required";
|
|
1505
1513
|
data: {
|
package/src/events.js
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -26,4 +26,5 @@ export * from "./credits.js";
|
|
|
26
26
|
export * from "./embeddings.js";
|
|
27
27
|
export * from "./system-one.js";
|
|
28
28
|
export * from "./mcp-servers.js";
|
|
29
|
+
export * from "./tool-failure.js";
|
|
29
30
|
export { connectivityErrorCodeToLikelyCause, mapConnectivityErrorMessage, } from "./connectivity/error-codes.js";
|
package/src/index.js
CHANGED
|
@@ -26,4 +26,5 @@ export * from "./credits.js";
|
|
|
26
26
|
export * from "./embeddings.js";
|
|
27
27
|
export * from "./system-one.js";
|
|
28
28
|
export * from "./mcp-servers.js";
|
|
29
|
+
export * from "./tool-failure.js";
|
|
29
30
|
export { connectivityErrorCodeToLikelyCause, mapConnectivityErrorMessage, } from "./connectivity/error-codes.js";
|
package/src/messages.d.ts
CHANGED
|
@@ -570,6 +570,15 @@ export declare const ContentMessageItemToolResultSchema: z.ZodObject<{
|
|
|
570
570
|
}, z.core.$strip>;
|
|
571
571
|
}, z.core.$strip>], "type">>]>;
|
|
572
572
|
is_error: z.ZodOptional<z.ZodBoolean>;
|
|
573
|
+
error_kind: z.ZodCatch<z.ZodOptional<z.ZodEnum<{
|
|
574
|
+
command_not_found: "command_not_found";
|
|
575
|
+
guardrail: "guardrail";
|
|
576
|
+
invalid_input: "invalid_input";
|
|
577
|
+
non_zero_exit: "non_zero_exit";
|
|
578
|
+
policy_block: "policy_block";
|
|
579
|
+
tool_failure: "tool_failure";
|
|
580
|
+
user_abort: "user_abort";
|
|
581
|
+
}>>>;
|
|
573
582
|
cache: z.ZodOptional<z.ZodBoolean>;
|
|
574
583
|
ephemeral: z.ZodOptional<z.ZodBoolean>;
|
|
575
584
|
structured_result: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
package/src/messages.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { ToolFailureKindSchema } from "./tool-failure.js";
|
|
2
3
|
export function getContentText(message) {
|
|
3
4
|
if (typeof message === "string") {
|
|
4
5
|
return message;
|
|
@@ -167,6 +168,11 @@ export const ContentMessageItemToolResultSchema = z
|
|
|
167
168
|
])),
|
|
168
169
|
]),
|
|
169
170
|
is_error: z.boolean().optional(),
|
|
171
|
+
// An unrecognized kind (e.g. from a newer client) parses as absent so a
|
|
172
|
+
// strict parse never rejects the request over it.
|
|
173
|
+
error_kind: ToolFailureKindSchema.optional().catch(undefined).meta({
|
|
174
|
+
description: "Why the call failed, set by the code that failed. Only meaningful with `is_error: true`; when absent the service infers the reason from the message.",
|
|
175
|
+
}),
|
|
170
176
|
cache: z.boolean().optional(),
|
|
171
177
|
ephemeral: z.boolean().optional(),
|
|
172
178
|
structured_result: z.record(z.string(), z.any()).optional(),
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { proposalNeedsNoDependencies, replayedProposalNeedsNoDependencies, } from "./codegen";
|
|
3
|
+
const overview = {
|
|
4
|
+
framework: "vite",
|
|
5
|
+
packageManager: "npm",
|
|
6
|
+
isMonorepo: false,
|
|
7
|
+
detectedLanguage: "typescript",
|
|
8
|
+
};
|
|
9
|
+
describe("proposalNeedsNoDependencies", () => {
|
|
10
|
+
it("is unknown (false) when the install command is null, even with projectOverview", () => {
|
|
11
|
+
// null means "no suggestion", and partial proposals may carry
|
|
12
|
+
// projectOverview forward, so this is not an affirmative signal.
|
|
13
|
+
expect(proposalNeedsNoDependencies({
|
|
14
|
+
projectOverview: overview,
|
|
15
|
+
installCommand: null,
|
|
16
|
+
runtimeDependencies: [],
|
|
17
|
+
})).toBe(false);
|
|
18
|
+
});
|
|
19
|
+
it("is true for an explicitly empty install command and no runtime deps", () => {
|
|
20
|
+
expect(proposalNeedsNoDependencies({
|
|
21
|
+
installCommand: { command: "", reason: "nothing to install" },
|
|
22
|
+
runtimeDependencies: [],
|
|
23
|
+
})).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
it("is unknown (false) for a partial env-vars-only proposal", () => {
|
|
26
|
+
expect(proposalNeedsNoDependencies({
|
|
27
|
+
projectOverview: null,
|
|
28
|
+
installCommand: null,
|
|
29
|
+
runtimeDependencies: [],
|
|
30
|
+
environmentVariables: [
|
|
31
|
+
{
|
|
32
|
+
key: "API_URL",
|
|
33
|
+
description: "",
|
|
34
|
+
isRequired: true,
|
|
35
|
+
isSecret: false,
|
|
36
|
+
defaultValue: null,
|
|
37
|
+
source: ".env.example",
|
|
38
|
+
},
|
|
39
|
+
],
|
|
40
|
+
})).toBe(false);
|
|
41
|
+
expect(proposalNeedsNoDependencies({ environmentVariables: [] })).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
it("is false when something needs installing or config is missing", () => {
|
|
44
|
+
expect(proposalNeedsNoDependencies({
|
|
45
|
+
projectOverview: overview,
|
|
46
|
+
installCommand: { command: "npm ci", reason: "lockfile" },
|
|
47
|
+
runtimeDependencies: [],
|
|
48
|
+
})).toBe(false);
|
|
49
|
+
expect(proposalNeedsNoDependencies({
|
|
50
|
+
projectOverview: overview,
|
|
51
|
+
installCommand: null,
|
|
52
|
+
runtimeDependencies: [{ tool: "node", version: "22", source: "" }],
|
|
53
|
+
})).toBe(false);
|
|
54
|
+
expect(proposalNeedsNoDependencies(undefined)).toBe(false);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
describe("replayedProposalNeedsNoDependencies", () => {
|
|
58
|
+
const fullShapeProposal = {
|
|
59
|
+
projectOverview: overview,
|
|
60
|
+
rootDirectory: null,
|
|
61
|
+
installCommand: null,
|
|
62
|
+
runtimeDependencies: [],
|
|
63
|
+
devServer: null,
|
|
64
|
+
environmentVariables: [],
|
|
65
|
+
validationScript: null,
|
|
66
|
+
npmrcContents: null,
|
|
67
|
+
hasHotModuleReload: null,
|
|
68
|
+
};
|
|
69
|
+
it("uses the recorded decision, so a new full-shape proposal replays like live", () => {
|
|
70
|
+
const live = proposalNeedsNoDependencies(fullShapeProposal);
|
|
71
|
+
expect(live).toBe(false);
|
|
72
|
+
expect(replayedProposalNeedsNoDependencies(fullShapeProposal, {
|
|
73
|
+
noDependencies: live,
|
|
74
|
+
})).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
it("uses a recorded decision for a partial proposal too", () => {
|
|
77
|
+
const partial = { environmentVariables: [], runtimeDependencies: [] };
|
|
78
|
+
expect(replayedProposalNeedsNoDependencies(partial, {
|
|
79
|
+
noDependencies: proposalNeedsNoDependencies(partial),
|
|
80
|
+
})).toBe(false);
|
|
81
|
+
expect(replayedProposalNeedsNoDependencies({
|
|
82
|
+
installCommand: { command: "", reason: "static" },
|
|
83
|
+
runtimeDependencies: [],
|
|
84
|
+
}, { noDependencies: true })).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
it("keeps the original replay reading for legacy actions without a marker", () => {
|
|
87
|
+
expect(replayedProposalNeedsNoDependencies(fullShapeProposal, undefined)).toBe(true);
|
|
88
|
+
expect(replayedProposalNeedsNoDependencies({
|
|
89
|
+
...fullShapeProposal,
|
|
90
|
+
installCommand: { command: "npm ci", reason: "lockfile" },
|
|
91
|
+
}, undefined)).toBe(false);
|
|
92
|
+
expect(replayedProposalNeedsNoDependencies(undefined, undefined)).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Why a tool result came out the way it did. `is_error` alone conflates a
|
|
4
|
+
* broken tool with a tool that worked and reported a negative outcome (no
|
|
5
|
+
* matches, failing tests), so only `tool_failure` means the tool itself broke.
|
|
6
|
+
* Closed set: these are the values of the `reason` label on the service's
|
|
7
|
+
* tool-result metric, so adding one adds metric series.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ToolResultReasonSchema: z.ZodEnum<{
|
|
10
|
+
command_not_found: "command_not_found";
|
|
11
|
+
empty_result: "empty_result";
|
|
12
|
+
guardrail: "guardrail";
|
|
13
|
+
invalid_input: "invalid_input";
|
|
14
|
+
non_zero_exit: "non_zero_exit";
|
|
15
|
+
policy_block: "policy_block";
|
|
16
|
+
success: "success";
|
|
17
|
+
tool_failure: "tool_failure";
|
|
18
|
+
user_abort: "user_abort";
|
|
19
|
+
}>;
|
|
20
|
+
export type ToolResultReason = z.infer<typeof ToolResultReasonSchema>;
|
|
21
|
+
/** A reason only a failed tool call can have. */
|
|
22
|
+
export declare const ToolFailureKindSchema: z.ZodEnum<{
|
|
23
|
+
command_not_found: "command_not_found";
|
|
24
|
+
guardrail: "guardrail";
|
|
25
|
+
invalid_input: "invalid_input";
|
|
26
|
+
non_zero_exit: "non_zero_exit";
|
|
27
|
+
policy_block: "policy_block";
|
|
28
|
+
tool_failure: "tool_failure";
|
|
29
|
+
user_abort: "user_abort";
|
|
30
|
+
}>;
|
|
31
|
+
export type ToolFailureKind = z.infer<typeof ToolFailureKindSchema>;
|
|
32
|
+
export declare function isToolFailureKind(value: unknown): value is ToolFailureKind;
|
|
33
|
+
export interface ToolFailure {
|
|
34
|
+
kind: ToolFailureKind;
|
|
35
|
+
/** Tool-specific detail for logs and tests. Never a metric label. */
|
|
36
|
+
code?: string;
|
|
37
|
+
/** Whether repeating the same call unchanged can succeed. */
|
|
38
|
+
retryable: boolean;
|
|
39
|
+
}
|
|
40
|
+
export interface Failure extends ToolFailure {
|
|
41
|
+
/** Shown to the model or the user; never empty. */
|
|
42
|
+
message: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Return type for fallible helpers, in place of `T | undefined`, so a caller
|
|
46
|
+
* can't drop the reason a call failed.
|
|
47
|
+
*/
|
|
48
|
+
export type Result<T> = {
|
|
49
|
+
ok: true;
|
|
50
|
+
value: T;
|
|
51
|
+
} | {
|
|
52
|
+
ok: false;
|
|
53
|
+
error: Failure;
|
|
54
|
+
};
|
|
55
|
+
export declare function okResult<T>(value: T): {
|
|
56
|
+
ok: true;
|
|
57
|
+
value: T;
|
|
58
|
+
};
|
|
59
|
+
export declare function failResult(kind: ToolFailureKind, message: string, options: {
|
|
60
|
+
retryable: boolean;
|
|
61
|
+
code?: string;
|
|
62
|
+
}): {
|
|
63
|
+
ok: false;
|
|
64
|
+
error: Failure;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Throw from inside a tool to fail it with a kind. A tool runner turns it
|
|
68
|
+
* into a typed failure; any other thrown error stays untyped.
|
|
69
|
+
*/
|
|
70
|
+
export declare class ToolError extends Error {
|
|
71
|
+
readonly failure: ToolFailure;
|
|
72
|
+
constructor(kind: ToolFailureKind, message: string, options: {
|
|
73
|
+
retryable: boolean;
|
|
74
|
+
code?: string;
|
|
75
|
+
cause?: unknown;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
/** A failed tool resolution, in the shape both the CLI and the service runners accept. */
|
|
79
|
+
export interface ToolFailureReturn {
|
|
80
|
+
isError: true;
|
|
81
|
+
toolResult: string;
|
|
82
|
+
error: ToolFailure;
|
|
83
|
+
title?: string;
|
|
84
|
+
structuredResult?: Record<string, any>;
|
|
85
|
+
}
|
|
86
|
+
export declare function toolFail(kind: ToolFailureKind, message: string, options: {
|
|
87
|
+
retryable: boolean;
|
|
88
|
+
code?: string;
|
|
89
|
+
title?: string;
|
|
90
|
+
structuredResult?: Record<string, any>;
|
|
91
|
+
}): ToolFailureReturn;
|
|
92
|
+
/** Passes a fallible helper's failure through as the tool's own. */
|
|
93
|
+
export declare function toolFailFrom(failure: Failure, options?: {
|
|
94
|
+
title?: string;
|
|
95
|
+
}): ToolFailureReturn;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* Why a tool result came out the way it did. `is_error` alone conflates a
|
|
4
|
+
* broken tool with a tool that worked and reported a negative outcome (no
|
|
5
|
+
* matches, failing tests), so only `tool_failure` means the tool itself broke.
|
|
6
|
+
* Closed set: these are the values of the `reason` label on the service's
|
|
7
|
+
* tool-result metric, so adding one adds metric series.
|
|
8
|
+
*/
|
|
9
|
+
export const ToolResultReasonSchema = z
|
|
10
|
+
.enum([
|
|
11
|
+
"success",
|
|
12
|
+
"empty_result",
|
|
13
|
+
"non_zero_exit",
|
|
14
|
+
"command_not_found",
|
|
15
|
+
"policy_block",
|
|
16
|
+
"guardrail",
|
|
17
|
+
"invalid_input",
|
|
18
|
+
"user_abort",
|
|
19
|
+
"tool_failure",
|
|
20
|
+
])
|
|
21
|
+
.meta({ title: "ToolResultReason" });
|
|
22
|
+
/** A reason only a failed tool call can have. */
|
|
23
|
+
export const ToolFailureKindSchema = ToolResultReasonSchema.exclude([
|
|
24
|
+
"success",
|
|
25
|
+
"empty_result",
|
|
26
|
+
]).meta({ title: "ToolFailureKind" });
|
|
27
|
+
export function isToolFailureKind(value) {
|
|
28
|
+
return ToolFailureKindSchema.safeParse(value).success;
|
|
29
|
+
}
|
|
30
|
+
export function okResult(value) {
|
|
31
|
+
return { ok: true, value };
|
|
32
|
+
}
|
|
33
|
+
export function failResult(kind, message, options) {
|
|
34
|
+
return { ok: false, error: { kind, message, ...options } };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Throw from inside a tool to fail it with a kind. A tool runner turns it
|
|
38
|
+
* into a typed failure; any other thrown error stays untyped.
|
|
39
|
+
*/
|
|
40
|
+
export class ToolError extends Error {
|
|
41
|
+
constructor(kind, message, options) {
|
|
42
|
+
super(message, { cause: options.cause });
|
|
43
|
+
this.name = "ToolError";
|
|
44
|
+
this.failure = {
|
|
45
|
+
kind,
|
|
46
|
+
retryable: options.retryable,
|
|
47
|
+
...(options.code ? { code: options.code } : {}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function toolFail(kind, message, options) {
|
|
52
|
+
const { retryable, code, title, structuredResult } = options;
|
|
53
|
+
return {
|
|
54
|
+
isError: true,
|
|
55
|
+
toolResult: message,
|
|
56
|
+
error: { kind, retryable, ...(code ? { code } : {}) },
|
|
57
|
+
...(title !== undefined ? { title } : {}),
|
|
58
|
+
...(structuredResult ? { structuredResult } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Passes a fallible helper's failure through as the tool's own. */
|
|
62
|
+
export function toolFailFrom(failure, options = {}) {
|
|
63
|
+
return toolFail(failure.kind, failure.message, {
|
|
64
|
+
retryable: failure.retryable,
|
|
65
|
+
code: failure.code,
|
|
66
|
+
title: options.title,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { ContentMessageItemToolResultSchema } from "./messages";
|
|
3
|
+
import { failResult, isToolFailureKind, okResult } from "./tool-failure";
|
|
4
|
+
const base = {
|
|
5
|
+
type: "tool_result",
|
|
6
|
+
tool_use_id: "toolu_1",
|
|
7
|
+
content: "Grep produced too much output.",
|
|
8
|
+
is_error: true,
|
|
9
|
+
};
|
|
10
|
+
describe("tool_result error_kind", () => {
|
|
11
|
+
it("keeps a valid kind", () => {
|
|
12
|
+
expect(ContentMessageItemToolResultSchema.parse({
|
|
13
|
+
...base,
|
|
14
|
+
error_kind: "guardrail",
|
|
15
|
+
}).error_kind).toBe("guardrail");
|
|
16
|
+
});
|
|
17
|
+
it("parses an unknown kind as absent instead of rejecting", () => {
|
|
18
|
+
const parsed = ContentMessageItemToolResultSchema.parse({
|
|
19
|
+
...base,
|
|
20
|
+
error_kind: "rate_limited",
|
|
21
|
+
});
|
|
22
|
+
expect(parsed.error_kind).toBeUndefined();
|
|
23
|
+
expect(parsed.content).toBe(base.content);
|
|
24
|
+
});
|
|
25
|
+
it("parses a result without a kind", () => {
|
|
26
|
+
expect(ContentMessageItemToolResultSchema.parse(base).error_kind).toBeUndefined();
|
|
27
|
+
});
|
|
28
|
+
it("strips other unknown keys, as older schemas strip error_kind", () => {
|
|
29
|
+
const parsed = ContentMessageItemToolResultSchema.parse({
|
|
30
|
+
...base,
|
|
31
|
+
error_code: "x",
|
|
32
|
+
});
|
|
33
|
+
expect(parsed).not.toHaveProperty("error_code");
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
describe("isToolFailureKind", () => {
|
|
37
|
+
it.each(["guardrail", "tool_failure", "user_abort"])("accepts %s", (kind) => {
|
|
38
|
+
expect(isToolFailureKind(kind)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it.each(["success", "empty_result", "rate_limited", 1, undefined])("rejects %s", (kind) => {
|
|
41
|
+
expect(isToolFailureKind(kind)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe("Result helpers", () => {
|
|
45
|
+
it("builds both variants", () => {
|
|
46
|
+
expect(okResult(3)).toEqual({ ok: true, value: 3 });
|
|
47
|
+
expect(failResult("invalid_input", "Bad URL", { retryable: false, code: "url" })).toEqual({
|
|
48
|
+
ok: false,
|
|
49
|
+
error: {
|
|
50
|
+
kind: "invalid_input",
|
|
51
|
+
message: "Bad URL",
|
|
52
|
+
retryable: false,
|
|
53
|
+
code: "url",
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|