@positronic/core 0.0.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/.swcrc +31 -0
- package/dist/src/adapters/types.js +16 -0
- package/dist/src/clients/types.js +1 -0
- package/dist/src/dsl/constants.js +15 -0
- package/dist/src/dsl/extensions.js +19 -0
- package/dist/src/dsl/json-patch.js +30 -0
- package/dist/src/dsl/types.js +1 -0
- package/dist/src/dsl/workflow-runner.js +93 -0
- package/dist/src/dsl/workflow.js +308 -0
- package/dist/src/file-stores/local-file-store.js +12 -0
- package/dist/src/file-stores/types.js +1 -0
- package/dist/src/index.js +10 -0
- package/dist/src/utils/temp-files.js +27 -0
- package/dist/types/adapters/types.d.ts +10 -0
- package/dist/types/adapters/types.d.ts.map +1 -0
- package/dist/types/clients/types.d.ts +10 -0
- package/dist/types/clients/types.d.ts.map +1 -0
- package/dist/types/dsl/constants.d.ts +16 -0
- package/dist/types/dsl/constants.d.ts.map +1 -0
- package/dist/types/dsl/extensions.d.ts +18 -0
- package/dist/types/dsl/extensions.d.ts.map +1 -0
- package/dist/types/dsl/json-patch.d.ts +11 -0
- package/dist/types/dsl/json-patch.d.ts.map +1 -0
- package/dist/types/dsl/types.d.ts +14 -0
- package/dist/types/dsl/types.d.ts.map +1 -0
- package/dist/types/dsl/workflow-runner.d.ts +28 -0
- package/dist/types/dsl/workflow-runner.d.ts.map +1 -0
- package/dist/types/dsl/workflow.d.ts +118 -0
- package/dist/types/dsl/workflow.d.ts.map +1 -0
- package/dist/types/file-stores/local-file-store.d.ts +7 -0
- package/dist/types/file-stores/local-file-store.d.ts.map +1 -0
- package/dist/types/file-stores/types.d.ts +4 -0
- package/dist/types/file-stores/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +12 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/utils/temp-files.d.ts +12 -0
- package/dist/types/utils/temp-files.d.ts.map +1 -0
- package/package.json +21 -0
- package/src/adapters/types.ts +24 -0
- package/src/clients/types.ts +14 -0
- package/src/dsl/constants.ts +16 -0
- package/src/dsl/extensions.ts +58 -0
- package/src/dsl/json-patch.ts +27 -0
- package/src/dsl/types.ts +13 -0
- package/src/dsl/workflow-runner.test.ts +203 -0
- package/src/dsl/workflow-runner.ts +146 -0
- package/src/dsl/workflow.test.ts +1435 -0
- package/src/dsl/workflow.ts +554 -0
- package/src/file-stores/local-file-store.ts +11 -0
- package/src/file-stores/types.ts +3 -0
- package/src/index.ts +22 -0
- package/src/utils/temp-files.ts +46 -0
- package/tsconfig.json +10 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { WORKFLOW_EVENTS } from './constants';
|
|
2
|
+
import { applyPatches } from './json-patch';
|
|
3
|
+
import type { Adapter } from "../adapters/types";
|
|
4
|
+
import type { FileStore } from "../file-stores/types";
|
|
5
|
+
import type { SerializedStep, Workflow } from './workflow';
|
|
6
|
+
import type { State } from './types';
|
|
7
|
+
import type { PromptClient } from '../clients/types';
|
|
8
|
+
|
|
9
|
+
interface Logger {
|
|
10
|
+
log(...args: any[]): void;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class WorkflowRunner {
|
|
14
|
+
constructor(
|
|
15
|
+
private options: {
|
|
16
|
+
adapters: Adapter[],
|
|
17
|
+
fileStore: FileStore,
|
|
18
|
+
logger: Logger,
|
|
19
|
+
verbose: boolean,
|
|
20
|
+
client: PromptClient
|
|
21
|
+
}
|
|
22
|
+
) {}
|
|
23
|
+
|
|
24
|
+
async run<
|
|
25
|
+
TOptions extends object = {},
|
|
26
|
+
TState extends State = {}
|
|
27
|
+
>(
|
|
28
|
+
workflow: Workflow<TOptions, TState>,
|
|
29
|
+
{
|
|
30
|
+
initialState = {} as TState,
|
|
31
|
+
options,
|
|
32
|
+
initialCompletedSteps,
|
|
33
|
+
workflowRunId,
|
|
34
|
+
endAfter
|
|
35
|
+
}: {
|
|
36
|
+
initialState?: TState,
|
|
37
|
+
options?: TOptions,
|
|
38
|
+
initialCompletedSteps?: SerializedStep[] | never,
|
|
39
|
+
workflowRunId?: string | never,
|
|
40
|
+
endAfter?: number
|
|
41
|
+
} = {}
|
|
42
|
+
) {
|
|
43
|
+
const {
|
|
44
|
+
adapters,
|
|
45
|
+
logger: { log },
|
|
46
|
+
verbose,
|
|
47
|
+
fileStore,
|
|
48
|
+
client,
|
|
49
|
+
} = this.options;
|
|
50
|
+
|
|
51
|
+
let currentState = initialState ?? ({} as TState);
|
|
52
|
+
let stepNumber = 1;
|
|
53
|
+
|
|
54
|
+
// Apply any patches from completed steps
|
|
55
|
+
// to the initial state so that the workflow
|
|
56
|
+
// starts with a state that reflects all of the completed steps.
|
|
57
|
+
// Need to do this when a workflow is restarted with completed steps.
|
|
58
|
+
initialCompletedSteps?.forEach(step => {
|
|
59
|
+
if (step.patch) {
|
|
60
|
+
currentState = applyPatches(currentState, [step.patch]) as TState;
|
|
61
|
+
stepNumber++;
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const workflowRun = workflowRunId && initialCompletedSteps
|
|
66
|
+
? workflow.run({ initialState, initialCompletedSteps, workflowRunId, options, client, fileStore })
|
|
67
|
+
: workflow.run({ initialState, options, client, fileStore });
|
|
68
|
+
|
|
69
|
+
for await (const event of workflowRun) {
|
|
70
|
+
// Dispatch event to all adapters
|
|
71
|
+
await Promise.all(
|
|
72
|
+
adapters.map(adapter => adapter.dispatch(event))
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// Update current state when steps complete
|
|
76
|
+
if (event.type === WORKFLOW_EVENTS.STEP_COMPLETE) {
|
|
77
|
+
if (event.patch) {
|
|
78
|
+
currentState = applyPatches(currentState, [event.patch]) as TState;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Check if we should stop after this step
|
|
82
|
+
if (endAfter && stepNumber >= endAfter) {
|
|
83
|
+
// Log final state if verbose
|
|
84
|
+
if (verbose) {
|
|
85
|
+
log(`\nWorkflow stopped after step ${endAfter} as requested: \n\n ${JSON.stringify(
|
|
86
|
+
this.truncateDeep(structuredClone(currentState)), null, 2
|
|
87
|
+
)}`);
|
|
88
|
+
}
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
stepNumber++;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Log final state on workflow completion/error if verbose
|
|
96
|
+
if ((
|
|
97
|
+
event.type === WORKFLOW_EVENTS.COMPLETE ||
|
|
98
|
+
event.type === WORKFLOW_EVENTS.ERROR
|
|
99
|
+
) && verbose) {
|
|
100
|
+
log(`\nWorkflow completed: \n\n ${JSON.stringify(
|
|
101
|
+
this.truncateDeep(structuredClone(currentState)), null, 2
|
|
102
|
+
)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private truncateDeep(obj: any, maxLength: number = 100): any {
|
|
108
|
+
if (obj === null || obj === undefined) return obj;
|
|
109
|
+
|
|
110
|
+
if (typeof obj === 'string') {
|
|
111
|
+
return obj.length > maxLength ? obj.slice(0, maxLength) + '...' : obj;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (Array.isArray(obj)) {
|
|
115
|
+
if (obj.length === 0) return obj;
|
|
116
|
+
|
|
117
|
+
let truncatedArray = [];
|
|
118
|
+
let currentLength = 2; // Account for [] brackets
|
|
119
|
+
|
|
120
|
+
for (let i = 0; i < obj.length; i++) {
|
|
121
|
+
const processedItem = this.truncateDeep(obj[i], maxLength);
|
|
122
|
+
const itemStr = JSON.stringify(processedItem);
|
|
123
|
+
|
|
124
|
+
if (currentLength + itemStr.length + (i > 0 ? 1 : 0) > maxLength) {
|
|
125
|
+
truncatedArray.push(`... (${obj.length})`);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
truncatedArray.push(processedItem);
|
|
130
|
+
currentLength += itemStr.length + (i > 0 ? 1 : 0); // Add 1 for comma
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return truncatedArray;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (typeof obj === 'object') {
|
|
137
|
+
const truncated: Record<string, any> = {};
|
|
138
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
139
|
+
truncated[key] = this.truncateDeep(value, maxLength);
|
|
140
|
+
}
|
|
141
|
+
return truncated;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return obj;
|
|
145
|
+
}
|
|
146
|
+
}
|