@toolproof-core/lib 1.0.34 → 1.0.37

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.
Files changed (114) hide show
  1. package/dist/integrations/firebase/firebaseAdminHelpers.d.ts +3 -10
  2. package/dist/integrations/firebase/firebaseAdminHelpers.js +43 -148
  3. package/dist/integrations/firebase/firebaseAdminInit.d.ts +0 -1
  4. package/dist/integrations/firebase/firebaseAdminInit.js +0 -1
  5. package/dist/lookups/lookups.d.ts +214 -0
  6. package/dist/lookups/lookups.js +33 -0
  7. package/dist/types/types.d.ts +15 -15
  8. package/dist/types/types.js +2 -3
  9. package/dist/utils/cosmosDataExtraction.d.ts +5 -0
  10. package/dist/utils/cosmosDataExtraction.js +15 -0
  11. package/dist/utils/identifierGeneration.d.ts +2 -0
  12. package/dist/utils/identifierGeneration.js +5 -0
  13. package/dist/utils/mutableStrategyOverlay.d.ts +55 -0
  14. package/dist/utils/mutableStrategyOverlay.js +115 -0
  15. package/dist/utils/resourceCreation.d.ts +11 -0
  16. package/dist/utils/resourceCreation.js +32 -0
  17. package/dist/utils/stepCreation.d.ts +9 -0
  18. package/dist/utils/stepCreation.js +79 -0
  19. package/dist/utils/stepParallelization.d.ts +2 -0
  20. package/dist/utils/{parallelizeSteps.js → stepParallelization.js} +40 -55
  21. package/dist/utils/strategyAssembly.d.ts +3 -0
  22. package/dist/utils/strategyAssembly.js +6 -0
  23. package/dist/utils/strategyCanonicalization.d.ts +4 -0
  24. package/dist/utils/strategyCanonicalization.js +215 -0
  25. package/dist/utils/strategyExtraction.d.ts +17 -0
  26. package/dist/utils/strategyExtraction.js +88 -0
  27. package/dist/utils/strategyStateResolution.d.ts +17 -0
  28. package/dist/utils/strategyStateResolution.js +27 -0
  29. package/dist/utils/strategyThreading.d.ts +2 -0
  30. package/dist/utils/strategyThreading.js +10 -0
  31. package/dist/utils/toolStepPaths.d.ts +2 -0
  32. package/dist/utils/toolStepPaths.js +21 -0
  33. package/package.json +43 -23
  34. package/src/integrations/firebase/firebaseAdminHelpers.ts +57 -180
  35. package/src/lookups/lookups.ts +35 -0
  36. package/src/types/types.ts +16 -13
  37. package/src/utils/cosmosDataExtraction.ts +25 -0
  38. package/src/utils/identifierGeneration.ts +12 -0
  39. package/src/utils/mutableStrategyOverlay.ts +286 -0
  40. package/src/utils/resourceCreation.ts +87 -0
  41. package/src/utils/stepCreation.ts +114 -0
  42. package/src/utils/stepParallelization.ts +181 -0
  43. package/src/utils/strategyAssembly.ts +14 -0
  44. package/src/utils/strategyCanonicalization.ts +294 -0
  45. package/src/utils/strategyExtraction.ts +150 -0
  46. package/src/utils/strategyStateResolution.ts +57 -0
  47. package/src/utils/strategyThreading.ts +27 -0
  48. package/src/utils/toolStepPaths.ts +34 -0
  49. package/tsconfig.tsbuildinfo +1 -1
  50. package/dist/artifacts/artifacts.d.ts +0 -175
  51. package/dist/artifacts/artifacts.d.ts.map +0 -1
  52. package/dist/artifacts/artifacts.js +0 -48
  53. package/dist/artifacts/artifacts.js.map +0 -1
  54. package/dist/integrations/firebase/createStep.d.ts +0 -11
  55. package/dist/integrations/firebase/createStep.d.ts.map +0 -1
  56. package/dist/integrations/firebase/createStep.js +0 -43
  57. package/dist/integrations/firebase/createStep.js.map +0 -1
  58. package/dist/integrations/firebase/createThreadedStrategy.d.ts +0 -3
  59. package/dist/integrations/firebase/createThreadedStrategy.d.ts.map +0 -1
  60. package/dist/integrations/firebase/createThreadedStrategy.js +0 -9
  61. package/dist/integrations/firebase/createThreadedStrategy.js.map +0 -1
  62. package/dist/integrations/firebase/firebaseAdminHelpers.d.ts.map +0 -1
  63. package/dist/integrations/firebase/firebaseAdminHelpers.js.map +0 -1
  64. package/dist/integrations/firebase/firebaseAdminInit.d.ts.map +0 -1
  65. package/dist/integrations/firebase/firebaseAdminInit.js.map +0 -1
  66. package/dist/types/types.d.ts.map +0 -1
  67. package/dist/types/types.js.map +0 -1
  68. package/dist/utils/bindInputRoleToResource.d.ts +0 -6
  69. package/dist/utils/bindInputRoleToResource.d.ts.map +0 -1
  70. package/dist/utils/bindInputRoleToResource.js +0 -25
  71. package/dist/utils/bindInputRoleToResource.js.map +0 -1
  72. package/dist/utils/creation/resourceCreation.d.ts +0 -21
  73. package/dist/utils/creation/resourceCreation.d.ts.map +0 -1
  74. package/dist/utils/creation/resourceCreation.js +0 -66
  75. package/dist/utils/creation/resourceCreation.js.map +0 -1
  76. package/dist/utils/creation/stepCreation.d.ts +0 -51
  77. package/dist/utils/creation/stepCreation.d.ts.map +0 -1
  78. package/dist/utils/creation/stepCreation.js +0 -90
  79. package/dist/utils/creation/stepCreation.js.map +0 -1
  80. package/dist/utils/creation/threadedStrategyCreation.d.ts +0 -19
  81. package/dist/utils/creation/threadedStrategyCreation.d.ts.map +0 -1
  82. package/dist/utils/creation/threadedStrategyCreation.js +0 -17
  83. package/dist/utils/creation/threadedStrategyCreation.js.map +0 -1
  84. package/dist/utils/extractData.d.ts +0 -13
  85. package/dist/utils/extractData.d.ts.map +0 -1
  86. package/dist/utils/extractData.js +0 -74
  87. package/dist/utils/extractData.js.map +0 -1
  88. package/dist/utils/parallelizeSteps.d.ts +0 -4
  89. package/dist/utils/parallelizeSteps.d.ts.map +0 -1
  90. package/dist/utils/parallelizeSteps.js.map +0 -1
  91. package/dist/utils/resolveResourceChain.d.ts +0 -19
  92. package/dist/utils/resolveResourceChain.d.ts.map +0 -1
  93. package/dist/utils/resolveResourceChain.js +0 -31
  94. package/dist/utils/resolveResourceChain.js.map +0 -1
  95. package/dist/utils/roleSpec.d.ts +0 -17
  96. package/dist/utils/roleSpec.d.ts.map +0 -1
  97. package/dist/utils/roleSpec.js +0 -58
  98. package/dist/utils/roleSpec.js.map +0 -1
  99. package/dist/utils/strategyState.d.ts +0 -8
  100. package/dist/utils/strategyState.d.ts.map +0 -1
  101. package/dist/utils/strategyState.js +0 -29
  102. package/dist/utils/strategyState.js.map +0 -1
  103. package/src/artifacts/artifacts.ts +0 -49
  104. package/src/integrations/firebase/createStep.ts +0 -71
  105. package/src/integrations/firebase/createThreadedStrategy.ts +0 -19
  106. package/src/utils/bindInputRoleToResource.ts +0 -54
  107. package/src/utils/creation/resourceCreation.ts +0 -121
  108. package/src/utils/creation/stepCreation.ts +0 -165
  109. package/src/utils/creation/threadedStrategyCreation.ts +0 -42
  110. package/src/utils/extractData.ts +0 -129
  111. package/src/utils/parallelizeSteps.ts +0 -187
  112. package/src/utils/resolveResourceChain.ts +0 -52
  113. package/src/utils/roleSpec.ts +0 -84
  114. package/src/utils/strategyState.ts +0 -57
@@ -1,54 +0,0 @@
1
- import type {
2
- CreationContext,
3
- Resource,
4
- ReferenceInput,
5
- ValueInput,
6
- } from '@toolproof-core/schema';
7
- import {
8
- clearStrategyStateEntry,
9
- getStrategyStateEntry,
10
- setStrategyStateEntry,
11
- type StrategyState,
12
- type StrategyStateLike,
13
- } from './strategyState.js';
14
-
15
-
16
- export function bindInputResInStrategyState<TStrategyState extends StrategyStateLike>(
17
- strategyState: TStrategyState,
18
- target: CreationContext,
19
- resource: Resource
20
- ): TStrategyState {
21
- const entry: ValueInput = {
22
- strategyStateInputKind: 'valueInput',
23
- resourceTypeId: resource.resourceTypeId,
24
- nucleus: resource.nucleus,
25
- };
26
-
27
- return setStrategyStateEntry(strategyState, target, entry);
28
- }
29
-
30
- export function bindInputRefInStrategyState<TStrategyState extends StrategyStateLike>(
31
- strategyState: TStrategyState,
32
- target: CreationContext,
33
- source: CreationContext
34
- ): TStrategyState {
35
- const sourceEntry = getStrategyStateEntry(strategyState, source);
36
- if (!sourceEntry) {
37
- throw new Error(`resourceEntry not found for source (${source.toolStepPath}, ${source.roleName})`);
38
- }
39
-
40
- const entry: ReferenceInput = {
41
- strategyStateInputKind: 'referenceInput',
42
- toolStepPath: source.toolStepPath,
43
- roleName: source.roleName,
44
- };
45
-
46
- return setStrategyStateEntry(strategyState, target, entry);
47
- }
48
-
49
- export function clearInputBindingInStrategyState<TStrategyState extends StrategyStateLike>(
50
- strategyState: TStrategyState,
51
- target: CreationContext
52
- ): TStrategyState {
53
- return clearStrategyStateEntry(strategyState, target);
54
- }
@@ -1,121 +0,0 @@
1
- import type {
2
- CreationContext,
3
- ExternalInput,
4
- ReferenceInput,
5
- ResourceId,
6
- Resource,
7
- ResourceTypeId,
8
- StrategyRunId,
9
- } from '@toolproof-core/schema';
10
-
11
- export interface OutputPotential {
12
- id: ResourceId;
13
- resourceTypeId: ResourceTypeId;
14
- creationContext: CreationContext;
15
- strategyRunId?: StrategyRunId;
16
- }
17
-
18
- export type InputPotential = ReferenceInput & {
19
- id: ResourceId;
20
- resourceTypeId: ResourceTypeId;
21
- creationContext: CreationContext;
22
- strategyRunId?: StrategyRunId;
23
- };
24
-
25
- export function generatePath(resourceTypeId: ResourceTypeId, id: ResourceId): string {
26
- return `${resourceTypeId}/${id}.json`;
27
- }
28
-
29
- export function createMaterializedFromOutputPotential(
30
- outputPotential: OutputPotential,
31
- nucleus: unknown,
32
- timestamp?: string,
33
- ): Resource {
34
- const { id, resourceTypeId, creationContext } = outputPotential;
35
- const path = generatePath(resourceTypeId, id);
36
-
37
- return {
38
- id,
39
- resourceTypeId,
40
- provenance: {
41
- resourceProvenanceKind: 'strategy',
42
- strategyRunId: outputPotential.strategyRunId ?? ('STRATEGY_RUN-UNKNOWN' as StrategyRunId),
43
- creationContext,
44
- },
45
- version: 1,
46
- timestamp: timestamp ?? new Date().toISOString(),
47
- path,
48
- nucleus,
49
- };
50
- }
51
-
52
- export function createMaterializedFromInputPotential(
53
- inputPotential: InputPotential,
54
- nucleus: unknown,
55
- timestamp?: string,
56
- ): Resource {
57
- const { id, resourceTypeId, creationContext } = inputPotential;
58
- const path = generatePath(resourceTypeId, id);
59
-
60
- return {
61
- id,
62
- resourceTypeId,
63
- provenance: {
64
- resourceProvenanceKind: 'strategy',
65
- strategyRunId: inputPotential.strategyRunId ?? ('STRATEGY_RUN-UNKNOWN' as StrategyRunId),
66
- creationContext,
67
- },
68
- version: 1,
69
- timestamp: timestamp ?? new Date().toISOString(),
70
- path,
71
- nucleus,
72
- };
73
- }
74
-
75
- export function createMaterializedFromPotential(
76
- potential: InputPotential | OutputPotential,
77
- nucleus: unknown,
78
- timestamp?: string,
79
- ): Resource {
80
- if ('strategyStateInputKind' in potential && potential.strategyStateInputKind === 'referenceInput') {
81
- return createMaterializedFromInputPotential(potential, nucleus, timestamp);
82
- }
83
-
84
- return createMaterializedFromOutputPotential(potential, nucleus, timestamp);
85
- }
86
-
87
- export function createExternalInputPotential(
88
- _id: ResourceId,
89
- _resourceTypeId: ResourceTypeId,
90
- ): ExternalInput {
91
- return {
92
- strategyStateInputKind: 'externalInput',
93
- };
94
- }
95
-
96
- export function createInputPotential(
97
- id: ResourceId,
98
- resourceTypeId: ResourceTypeId,
99
- creationContext: CreationContext,
100
- ): InputPotential {
101
- return {
102
- id,
103
- resourceTypeId,
104
- strategyStateInputKind: 'referenceInput',
105
- toolStepPath: creationContext.toolStepPath,
106
- roleName: creationContext.roleName,
107
- creationContext,
108
- };
109
- }
110
-
111
- export function createOutputPotential(
112
- id: ResourceId,
113
- resourceTypeId: ResourceTypeId,
114
- creationContext: CreationContext,
115
- ): OutputPotential {
116
- return {
117
- id,
118
- resourceTypeId,
119
- creationContext,
120
- };
121
- }
@@ -1,165 +0,0 @@
1
- import type {
2
- BranchStep,
3
- Case,
4
- ForStep,
5
- Tool,
6
- ToolStep,
7
- WhileStep,
8
- } from '@toolproof-core/schema';
9
- import { CONSTANTS } from '../../artifacts/artifacts.js';
10
- import { getInputRoleNames, getOutputRoleNames } from '../roleSpec.js';
11
-
12
- type ToolStepId = string;
13
- type BranchStepId = string;
14
- type ForStepId = string;
15
- type WhileStepId = string;
16
-
17
- type ToolStepWithId = ToolStep & { id: ToolStepId };
18
- type BranchStepWithId = BranchStep & { id: BranchStepId };
19
- type ForStepWithId = ForStep & { id: ForStepId };
20
- type WhileStepWithId = WhileStep & { id: WhileStepId };
21
-
22
- export type LoopStepBuildIdentities =
23
- | {
24
- stepKind: typeof CONSTANTS.Enums.StepKind.for;
25
- stepId: ForStepId;
26
- whatId: ToolStepId;
27
- whenId: ToolStepId;
28
- }
29
- | {
30
- stepKind: typeof CONSTANTS.Enums.StepKind.while;
31
- stepId: WhileStepId;
32
- whatId: ToolStepId;
33
- whenId: ToolStepId;
34
- };
35
-
36
- export type BranchCaseBuildIdentities = {
37
- whatId: ToolStepId;
38
- whenId: ToolStepId;
39
- };
40
-
41
- function assertNonEmpty<T>(arr: T[], msg: string): asserts arr is [T, ...T[]] {
42
- if (arr.length === 0) {
43
- throw new Error(msg);
44
- }
45
- }
46
-
47
- function getRoleBindingSpec(tool: Tool): ToolStep['roleBindingSpec'] {
48
- return {
49
- inputBindings: getInputRoleNames(tool),
50
- outputBindings: getOutputRoleNames(tool),
51
- };
52
- }
53
-
54
- export function buildToolStepFromTool(
55
- tool: Tool,
56
- id: ToolStepId,
57
- ): ToolStepWithId {
58
- return {
59
- id,
60
- stepKind: CONSTANTS.Enums.StepKind.tool,
61
- toolId: tool.id,
62
- roleBindingSpec: getRoleBindingSpec(tool),
63
- } as ToolStepWithId;
64
- }
65
-
66
- export function buildLoopStepFromToolPair(
67
- whatTool: Tool,
68
- whenTool: Tool,
69
- identities: LoopStepBuildIdentities,
70
- ): ForStep | WhileStep {
71
- const what = buildToolStepFromTool(whatTool, identities.whatId);
72
- const when = buildToolStepFromTool(whenTool, identities.whenId);
73
-
74
- if (identities.stepKind === CONSTANTS.Enums.StepKind.for) {
75
- return {
76
- id: identities.stepId,
77
- stepKind: CONSTANTS.Enums.StepKind.for,
78
- case: { what, when },
79
- } as ForStepWithId;
80
- }
81
-
82
- return {
83
- id: identities.stepId,
84
- stepKind: CONSTANTS.Enums.StepKind.while,
85
- case: { what, when },
86
- } as WhileStepWithId;
87
- }
88
-
89
- export function buildBranchStepFromToolPairs(
90
- cases: Array<{ whatTool: Tool; whenTool: Tool }>,
91
- branchId: BranchStepId,
92
- caseIdentities: BranchCaseBuildIdentities[],
93
- ): BranchStepWithId {
94
- if (cases.length !== caseIdentities.length) {
95
- throw new Error('buildBranchStepFromToolPairs requires one id pair per case');
96
- }
97
-
98
- const resolved = cases.map(({ whatTool, whenTool }, index) => {
99
- const identities = caseIdentities[index];
100
-
101
- if (!identities) {
102
- throw new Error(`Missing case identities for case index ${index}`);
103
- }
104
-
105
- const what = buildToolStepFromTool(whatTool, identities.whatId);
106
- const when = buildToolStepFromTool(whenTool, identities.whenId);
107
- return { what, when } satisfies Case;
108
- });
109
-
110
- assertNonEmpty(resolved, 'buildBranchStepFromToolPairs requires at least one case');
111
-
112
- return {
113
- id: branchId,
114
- stepKind: CONSTANTS.Enums.StepKind.branch,
115
- cases: resolved,
116
- } as BranchStepWithId;
117
- }
118
-
119
- export function cloneForStepWithIdentities(
120
- forStep: ForStep,
121
- identities: {
122
- stepId: ForStepId;
123
- whatId: ToolStepId;
124
- whenId: ToolStepId;
125
- },
126
- ): ForStepWithId {
127
- return {
128
- id: identities.stepId,
129
- stepKind: CONSTANTS.Enums.StepKind.for,
130
- case: {
131
- what: {
132
- ...forStep.case.what,
133
- id: identities.whatId,
134
- },
135
- when: {
136
- ...forStep.case.when,
137
- id: identities.whenId,
138
- },
139
- },
140
- } as ForStepWithId;
141
- }
142
-
143
- export function cloneWhileStepWithIdentities(
144
- whileStep: WhileStep,
145
- identities: {
146
- stepId: WhileStepId;
147
- whatId: ToolStepId;
148
- whenId: ToolStepId;
149
- },
150
- ): WhileStepWithId {
151
- return {
152
- id: identities.stepId,
153
- stepKind: CONSTANTS.Enums.StepKind.while,
154
- case: {
155
- what: {
156
- ...whileStep.case.what,
157
- id: identities.whatId,
158
- },
159
- when: {
160
- ...whileStep.case.when,
161
- id: identities.whenId,
162
- },
163
- },
164
- } as WhileStepWithId;
165
- }
@@ -1,42 +0,0 @@
1
- import type {
2
- Step,
3
- StrategyId,
4
- } from '@toolproof-core/schema';
5
- import { getIndependentThreads } from '../parallelizeSteps.js';
6
- import { CONSTANTS } from '../../artifacts/artifacts.js';
7
-
8
- export type ThreadableStrategy<TStrategyState = unknown> = {
9
- id: StrategyId;
10
- strategyState: TStrategyState;
11
- } & (
12
- | { steps: Step[] }
13
- | { stepsByThreadIndex: Step[][] }
14
- );
15
-
16
- export type ThreadedStrategyLike<TStrategyState = unknown> = {
17
- id: StrategyId;
18
- strategyKind: typeof CONSTANTS.Enums.StrategyKind.threaded;
19
- stepsByThreadIndex: Step[][];
20
- strategyState: TStrategyState;
21
- };
22
-
23
- export function getThreadedStrategyStepGroups<TStrategyState>(strategy: ThreadableStrategy<TStrategyState>): Step[][] {
24
- if ('steps' in strategy) {
25
- return getIndependentThreads(strategy.steps, strategy.strategyState as any);
26
- }
27
-
28
- return strategy.stepsByThreadIndex;
29
- }
30
-
31
- export function buildThreadedStrategy<TStrategyState>(
32
- threadStepGroups: Step[][],
33
- threadedStrategyId: StrategyId,
34
- strategy: ThreadableStrategy<TStrategyState>,
35
- ): ThreadedStrategyLike<TStrategyState> {
36
- return {
37
- id: threadedStrategyId,
38
- strategyKind: CONSTANTS.Enums.StrategyKind.threaded,
39
- stepsByThreadIndex: threadStepGroups,
40
- strategyState: strategy.strategyState,
41
- };
42
- }
@@ -1,129 +0,0 @@
1
- import type {
2
- RoleName,
3
- RoleValue,
4
- ToolId,
5
- Tool,
6
- ToolStep,
7
- ResourceId,
8
- ResourceTypeId,
9
- Resource,
10
- } from '@toolproof-core/schema';
11
- import { CONSTANTS } from '../artifacts/artifacts.js';
12
- import {
13
- extractToolStepsFromStrategy,
14
- getInputRoleEntries,
15
- getOutputRoleEntries,
16
- toToolRoleDescriptor,
17
- type StrategyStepGraph,
18
- type ToolRoleDescriptor,
19
- } from './roleSpec.js';
20
-
21
-
22
- export function extractToolIdsFromUnthreadedStrategy(unthreadedStrategy: StrategyStepGraph): ToolId[] {
23
- const toolSteps = extractToolStepsFromUnthreadedStrategy(unthreadedStrategy);
24
- const ids = new Set<ToolId>();
25
- for (const jStep of toolSteps) {
26
- ids.add(jStep.toolId);
27
- }
28
- return Array.from(ids);
29
- }
30
-
31
- export function extractToolStepsFromUnthreadedStrategy(unthreadedStrategy: StrategyStepGraph): ToolStep[] {
32
- return extractToolStepsFromStrategy(unthreadedStrategy);
33
- }
34
-
35
-
36
- export function extractRoleMapFromUnthreadedStrategy(unthreadedStrategy: StrategyStepGraph, toolMap: Map<ToolId, Tool>): Map<RoleName, ToolRoleDescriptor> {
37
- const roleMap = new Map<RoleName, ToolRoleDescriptor>();
38
- const toolIds = extractToolIdsFromUnthreadedStrategy(unthreadedStrategy);
39
-
40
- for (const toolId of toolIds) {
41
- const tool = toolMap.get(toolId);
42
- if (!tool) continue;
43
-
44
- for (const entry of getInputRoleEntries(tool)) {
45
- roleMap.set(entry[0], toToolRoleDescriptor(entry));
46
- }
47
- for (const entry of getOutputRoleEntries(tool)) {
48
- roleMap.set(entry[0], toToolRoleDescriptor(entry));
49
- }
50
- }
51
-
52
- return roleMap;
53
- }
54
-
55
- export function extractSingleNonErrorOutputTypeId(tool: Tool): ResourceTypeId | null {
56
- const errorRoleId = CONSTANTS.Cosmos.ROLE_ErrorOutput;
57
- const outputEntries = getOutputRoleEntries(tool).filter(([roleName]) => roleName !== errorRoleId);
58
- if (!outputEntries || !outputEntries[0] || outputEntries.length !== 1) {
59
- throw new Error(`Tool ${tool.id} must have exactly one non-error output role to be branchable/loopable`);
60
- } // ATTENTION_PUREIFY
61
- const outputRole = outputEntries[0][1] as RoleValue;
62
- return outputRole.resourceTypeId;
63
- }
64
-
65
-
66
-
67
- export function extractResourceMapForType<TResource extends Resource = Resource>(
68
- resourcesByType: Partial<Record<ResourceTypeId, TResource[]>>,
69
- resourceTypeId: ResourceTypeId
70
- ): Map<ResourceId, TResource> {
71
- const resources = resourcesByType[resourceTypeId] ?? [];
72
- const map = new Map<ResourceId, TResource>();
73
-
74
- for (const resource of resources) {
75
- map.set(resource.id, resource);
76
- }
77
-
78
- return map;
79
- }
80
-
81
- // Only use this for resource types whose nuclei are entity-like objects with their own intrinsic id.
82
- export function extractIdKeyedNucleusMapForType<
83
- TKey extends string = string,
84
- TNucleus extends { id: string | number | boolean } = { id: string | number | boolean },
85
- TResource extends Resource = Resource
86
- >(
87
- resourcesByType: Partial<Record<ResourceTypeId, TResource[]>>,
88
- resourceTypeId: ResourceTypeId,
89
- ): Map<TKey, TNucleus> {
90
- const resourceMap = extractResourceMapForType<TResource>(resourcesByType, resourceTypeId);
91
- const out = new Map<TKey, TNucleus>();
92
-
93
- for (const resource of resourceMap.values()) {
94
- const data = (resource as any).nucleus as unknown;
95
- if (data === null || data === undefined) {
96
- throw new Error(
97
- `Expected resource '${resource.id}' of type '${resourceTypeId}' to have a nucleus`
98
- );
99
- }
100
- if (typeof data !== 'object') {
101
- throw new Error(
102
- `Expected resource '${resource.id}' of type '${resourceTypeId}' to have an object nucleus with id`
103
- );
104
- }
105
-
106
- const maybeId = (data as any).id as unknown;
107
- if (maybeId === null || maybeId === undefined) {
108
- throw new Error(
109
- `Expected resource '${resource.id}' of type '${resourceTypeId}' to have nucleus.id`
110
- );
111
- }
112
- if (
113
- typeof maybeId !== 'string' &&
114
- typeof maybeId !== 'number' &&
115
- typeof maybeId !== 'boolean'
116
- ) {
117
- throw new Error(
118
- `Expected resource '${resource.id}' of type '${resourceTypeId}' to have nucleus.id as string, number, or boolean`
119
- );
120
- }
121
-
122
- const value = data as TNucleus;
123
- const key = String(maybeId) as TKey;
124
-
125
- out.set(key, value);
126
- }
127
-
128
- return out;
129
- }
@@ -1,187 +0,0 @@
1
- import type {
2
- BranchStep,
3
- ForStep,
4
- ToolStep,
5
- Step,
6
- WhileStep,
7
- } from '@toolproof-core/schema';
8
- import { CONSTANTS } from '../artifacts/artifacts.js';
9
- import type { StrategyState } from './strategyState.js';
10
-
11
- type ToolStepId = string;
12
- type ToolStepWithId = ToolStep & { id: ToolStepId };
13
-
14
- function getToolStepId(toolStep: ToolStep | undefined): ToolStepId | undefined {
15
- const maybeId = (toolStep as Partial<ToolStepWithId> | undefined)?.id;
16
- return typeof maybeId === 'string' ? maybeId : undefined;
17
- }
18
-
19
-
20
- export function getIndependentThreads(steps: Step[], strategyState: StrategyState): Step[][] {
21
- type OwnerIndex = number;
22
-
23
- const getOwnerLabel = (ownerIndex: OwnerIndex) => {
24
- const step = steps[ownerIndex];
25
- return `steps[${ownerIndex}] stepKind=${(step as any)?.stepKind ?? 'unknown'}`;
26
- };
27
-
28
- // Map each toolStep.id (including macro-nested tool steps) to owning top-level step index.
29
- const toolStepIdToOwner = new Map<ToolStepId, OwnerIndex>();
30
- const ownerToToolStepIds = new Map<OwnerIndex, ToolStepId[]>();
31
- const toolStepById = new Map<ToolStepId, ToolStepWithId>();
32
-
33
- const addToolStep = (toolStep: ToolStep | undefined, ownerIndex: OwnerIndex) => {
34
- const toolStepId = getToolStepId(toolStep);
35
- if (!toolStepId || !toolStep) return;
36
-
37
- const existingOwner = toolStepIdToOwner.get(toolStepId);
38
- if (existingOwner !== undefined) {
39
- throw new Error(
40
- `Duplicate toolStep.id '${toolStepId}' found in ${getOwnerLabel(ownerIndex)} and ${getOwnerLabel(existingOwner)}`
41
- );
42
- }
43
-
44
- toolStepIdToOwner.set(toolStepId, ownerIndex);
45
- toolStepById.set(toolStepId, toolStep as ToolStepWithId);
46
- const bucket = ownerToToolStepIds.get(ownerIndex) ?? [];
47
- bucket.push(toolStepId);
48
- ownerToToolStepIds.set(ownerIndex, bucket);
49
- };
50
-
51
- steps.forEach((step, ownerIndex) => {
52
- if (step.stepKind === CONSTANTS.Enums.StepKind.tool) {
53
- addToolStep(step as ToolStep, ownerIndex);
54
- return;
55
- }
56
-
57
- if (step.stepKind === CONSTANTS.Enums.StepKind.for) {
58
- const loop = step as ForStep;
59
- addToolStep(loop.case?.what, ownerIndex);
60
- addToolStep(loop.case?.when, ownerIndex);
61
- return;
62
- }
63
-
64
- if (step.stepKind === CONSTANTS.Enums.StepKind.while) {
65
- const loop = step as WhileStep;
66
- addToolStep(loop.case?.what, ownerIndex);
67
- addToolStep(loop.case?.when, ownerIndex);
68
- return;
69
- }
70
-
71
- if (step.stepKind === CONSTANTS.Enums.StepKind.branch) {
72
- const branch = step as BranchStep;
73
- for (const caseItem of branch.cases ?? []) {
74
- addToolStep(caseItem?.what, ownerIndex);
75
- addToolStep(caseItem?.when, ownerIndex);
76
- }
77
- return;
78
- }
79
- });
80
-
81
- // Undirected adjacency used for connected components (thread groups).
82
- const ownerAdj = new Map<OwnerIndex, Set<OwnerIndex>>();
83
- // Directed dependencies used for strict ordering validation: owner -> producers it depends on.
84
- const ownerDeps = new Map<OwnerIndex, Set<OwnerIndex>>();
85
-
86
- const ensureOwner = (ownerIndex: OwnerIndex) => {
87
- if (!ownerAdj.has(ownerIndex)) ownerAdj.set(ownerIndex, new Set());
88
- if (!ownerDeps.has(ownerIndex)) ownerDeps.set(ownerIndex, new Set());
89
- };
90
-
91
- for (let i = 0; i < steps.length; i++) {
92
- ensureOwner(i);
93
- }
94
-
95
- // Discover dependencies from strategyState.
96
- for (const [toolStepId, ownerIndex] of toolStepIdToOwner) {
97
- ensureOwner(ownerIndex);
98
-
99
- const toolStep = toolStepById.get(toolStepId);
100
- const inputBindings = toolStep?.roleBindingSpec?.inputBindings ?? [];
101
- const bucket = strategyState?.[toolStepId] ?? ({} as any);
102
-
103
- for (const inputRoleId of inputBindings) {
104
- const entry = bucket?.[inputRoleId] as any;
105
- if (!entry || entry.strategyStateInputKind !== 'referenceInput') continue;
106
-
107
- const creatorToolStepId = typeof entry?.toolStepPath === 'string'
108
- ? entry.toolStepPath as ToolStepId
109
- : undefined;
110
- if (!creatorToolStepId) {
111
- throw new Error(
112
- `Unresolvable referenceInput in toolStep '${toolStepId}' (${getOwnerLabel(ownerIndex)}): missing toolStepPath for role '${inputRoleId}'`
113
- );
114
- }
115
-
116
- const producerOwner = toolStepIdToOwner.get(creatorToolStepId);
117
- if (producerOwner === undefined) {
118
- throw new Error(
119
- `Unresolvable referenceInput in toolStep '${toolStepId}' (${getOwnerLabel(ownerIndex)}): creator toolStepPath '${creatorToolStepId}' not found in strategy steps`
120
- );
121
- }
122
-
123
- ensureOwner(producerOwner);
124
- ownerAdj.get(ownerIndex)!.add(producerOwner);
125
- ownerAdj.get(producerOwner)!.add(ownerIndex);
126
- ownerDeps.get(ownerIndex)!.add(producerOwner);
127
- }
128
- }
129
-
130
- // Connected components over owners.
131
- const visited = new Set<OwnerIndex>();
132
- const components: OwnerIndex[][] = [];
133
-
134
- for (let ownerIndex = 0; ownerIndex < steps.length; ownerIndex++) {
135
- if (visited.has(ownerIndex)) continue;
136
- const component: OwnerIndex[] = [];
137
- const queue: OwnerIndex[] = [ownerIndex];
138
- visited.add(ownerIndex);
139
- while (queue.length > 0) {
140
- const node = queue.shift()!;
141
- component.push(node);
142
- for (const neighbor of ownerAdj.get(node) ?? []) {
143
- if (!visited.has(neighbor)) {
144
- visited.add(neighbor);
145
- queue.push(neighbor);
146
- }
147
- }
148
- }
149
- components.push(component);
150
- }
151
-
152
- // Strict validation: within a thread, the linear order must not contain forward refs.
153
- for (const comp of components) {
154
- const compSet = new Set(comp);
155
- const ownersInOrder = steps.map((_, i) => i).filter((i) => compSet.has(i));
156
-
157
- const position = new Map<OwnerIndex, number>();
158
- ownersInOrder.forEach((owner, idx) => position.set(owner, idx));
159
-
160
- for (const consumerOwner of ownersInOrder) {
161
- const deps = ownerDeps.get(consumerOwner);
162
- if (!deps || deps.size === 0) continue;
163
-
164
- const consumerPos = position.get(consumerOwner)!;
165
- for (const producerOwner of deps) {
166
- const producerPos = position.get(producerOwner);
167
- if (producerPos === undefined) {
168
- throw new Error(
169
- `Internal error: dependency producer ${getOwnerLabel(producerOwner)} missing from computed thread for ${getOwnerLabel(consumerOwner)}`
170
- );
171
- }
172
- if (producerPos >= consumerPos) {
173
- throw new Error(
174
- `Invalid step order in thread: ${getOwnerLabel(consumerOwner)} depends on ${getOwnerLabel(producerOwner)}, but producer is not scheduled before consumer`
175
- );
176
- }
177
- }
178
- }
179
- }
180
-
181
- return components
182
- .map((compOwners) => {
183
- const ownerSet = new Set(compOwners);
184
- return steps.filter((_, i) => ownerSet.has(i));
185
- })
186
- .filter((group) => group.length > 0);
187
- }