@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 @@
|
|
|
1
|
+
{"version":3,"file":"json-patch.d.ts","sourceRoot":"","sources":["../../../src/dsl/json-patch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAE3C;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,GAAG,SAAS,CAKzE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,KAAK,CAQlF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonArray = JsonValue[];
|
|
3
|
+
export type JsonObject = {
|
|
4
|
+
[Key in string]?: JsonValue;
|
|
5
|
+
};
|
|
6
|
+
export type JsonValue = JsonPrimitive | JsonArray | JsonObject;
|
|
7
|
+
export type State = JsonObject;
|
|
8
|
+
export type JsonPatch = {
|
|
9
|
+
op: 'add' | 'remove' | 'replace' | 'move' | 'copy' | 'test';
|
|
10
|
+
path: string;
|
|
11
|
+
value?: JsonValue;
|
|
12
|
+
from?: string;
|
|
13
|
+
}[];
|
|
14
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/dsl/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAC7D,MAAM,MAAM,SAAS,GAAG,SAAS,EAAE,CAAC;AACpC,MAAM,MAAM,UAAU,GAAG;KAAG,GAAG,IAAI,MAAM,CAAC,CAAC,EAAE,SAAS;CAAE,CAAC;AACzD,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,SAAS,GAAG,UAAU,CAAC;AAE/D,MAAM,MAAM,KAAK,GAAG,UAAU,CAAC;AAE/B,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,EAAE,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Adapter } from "../adapters/types";
|
|
2
|
+
import type { FileStore } from "../file-stores/types";
|
|
3
|
+
import type { SerializedStep, Workflow } from './workflow';
|
|
4
|
+
import type { State } from './types';
|
|
5
|
+
import type { PromptClient } from '../clients/types';
|
|
6
|
+
interface Logger {
|
|
7
|
+
log(...args: any[]): void;
|
|
8
|
+
}
|
|
9
|
+
export declare class WorkflowRunner {
|
|
10
|
+
private options;
|
|
11
|
+
constructor(options: {
|
|
12
|
+
adapters: Adapter[];
|
|
13
|
+
fileStore: FileStore;
|
|
14
|
+
logger: Logger;
|
|
15
|
+
verbose: boolean;
|
|
16
|
+
client: PromptClient;
|
|
17
|
+
});
|
|
18
|
+
run<TOptions extends object = {}, TState extends State = {}>(workflow: Workflow<TOptions, TState>, { initialState, options, initialCompletedSteps, workflowRunId, endAfter }?: {
|
|
19
|
+
initialState?: TState;
|
|
20
|
+
options?: TOptions;
|
|
21
|
+
initialCompletedSteps?: SerializedStep[] | never;
|
|
22
|
+
workflowRunId?: string | never;
|
|
23
|
+
endAfter?: number;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
private truncateDeep;
|
|
26
|
+
}
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=workflow-runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-runner.d.ts","sourceRoot":"","sources":["../../../src/dsl/workflow-runner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,UAAU,MAAM;IACd,GAAG,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;CAC3B;AAED,qBAAa,cAAc;IAEvB,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE;QACf,QAAQ,EAAE,OAAO,EAAE,CAAC;QACpB,SAAS,EAAE,SAAS,CAAC;QACrB,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,YAAY,CAAA;KACrB;IAGG,GAAG,CACP,QAAQ,SAAS,MAAM,GAAG,EAAE,EAC5B,MAAM,SAAS,KAAK,GAAG,EAAE,EAEzB,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,EACpC,EACE,YAA2B,EAC3B,OAAO,EACP,qBAAqB,EACrB,aAAa,EACb,QAAQ,EACT,GAAE;QACD,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,OAAO,CAAC,EAAE,QAAQ,CAAC;QACnB,qBAAqB,CAAC,EAAE,cAAc,EAAE,GAAG,KAAK,CAAC;QACjD,aAAa,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;QAC/B,QAAQ,CAAC,EAAE,MAAM,CAAA;KACb;IAkER,OAAO,CAAC,YAAY;CAuCrB"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { PromptClient } from "../clients/types";
|
|
3
|
+
import type { State, JsonPatch } from "./types";
|
|
4
|
+
import { STATUS, WORKFLOW_EVENTS } from './constants';
|
|
5
|
+
import type { FileStore } from "../file-stores/types";
|
|
6
|
+
export type SerializedError = {
|
|
7
|
+
name: string;
|
|
8
|
+
message: string;
|
|
9
|
+
stack?: string;
|
|
10
|
+
};
|
|
11
|
+
interface BaseEvent<TOptions extends object = {}> {
|
|
12
|
+
type: typeof WORKFLOW_EVENTS[keyof typeof WORKFLOW_EVENTS];
|
|
13
|
+
options: TOptions;
|
|
14
|
+
workflowRunId: string;
|
|
15
|
+
}
|
|
16
|
+
interface WorkflowBaseEvent<TOptions extends object = {}> extends BaseEvent<TOptions> {
|
|
17
|
+
workflowTitle: string;
|
|
18
|
+
workflowDescription?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface WorkflowStartEvent<TOptions extends object = {}> extends WorkflowBaseEvent<TOptions> {
|
|
21
|
+
type: typeof WORKFLOW_EVENTS.START | typeof WORKFLOW_EVENTS.RESTART;
|
|
22
|
+
initialState: State;
|
|
23
|
+
status: typeof STATUS.RUNNING;
|
|
24
|
+
}
|
|
25
|
+
export interface WorkflowCompleteEvent<TOptions extends object = {}> extends WorkflowBaseEvent<TOptions> {
|
|
26
|
+
type: typeof WORKFLOW_EVENTS.COMPLETE;
|
|
27
|
+
status: typeof STATUS.COMPLETE;
|
|
28
|
+
}
|
|
29
|
+
export interface WorkflowErrorEvent<TOptions extends object = {}> extends WorkflowBaseEvent<TOptions> {
|
|
30
|
+
type: typeof WORKFLOW_EVENTS.ERROR;
|
|
31
|
+
status: typeof STATUS.ERROR;
|
|
32
|
+
error: SerializedError;
|
|
33
|
+
}
|
|
34
|
+
export interface StepStatusEvent<TOptions extends object = {}> extends BaseEvent<TOptions> {
|
|
35
|
+
type: typeof WORKFLOW_EVENTS.STEP_STATUS;
|
|
36
|
+
steps: SerializedStep[];
|
|
37
|
+
}
|
|
38
|
+
export interface StepStartedEvent<TOptions extends object = {}> extends BaseEvent<TOptions> {
|
|
39
|
+
type: typeof WORKFLOW_EVENTS.STEP_START;
|
|
40
|
+
status: typeof STATUS.RUNNING;
|
|
41
|
+
stepTitle: string;
|
|
42
|
+
stepId: string;
|
|
43
|
+
}
|
|
44
|
+
export interface StepCompletedEvent<TOptions extends object = {}> extends BaseEvent<TOptions> {
|
|
45
|
+
type: typeof WORKFLOW_EVENTS.STEP_COMPLETE;
|
|
46
|
+
status: typeof STATUS.RUNNING;
|
|
47
|
+
stepTitle: string;
|
|
48
|
+
stepId: string;
|
|
49
|
+
patch: JsonPatch;
|
|
50
|
+
}
|
|
51
|
+
export type WorkflowEvent<TOptions extends object = {}> = WorkflowStartEvent<TOptions> | WorkflowCompleteEvent<TOptions> | WorkflowErrorEvent<TOptions> | StepStatusEvent<TOptions> | StepStartedEvent<TOptions> | StepCompletedEvent<TOptions>;
|
|
52
|
+
export interface SerializedStep {
|
|
53
|
+
title: string;
|
|
54
|
+
status: typeof STATUS[keyof typeof STATUS];
|
|
55
|
+
id: string;
|
|
56
|
+
patch?: JsonPatch;
|
|
57
|
+
}
|
|
58
|
+
interface BaseRunParams<TOptions extends object = {}> {
|
|
59
|
+
fileStore: FileStore;
|
|
60
|
+
client: PromptClient;
|
|
61
|
+
options?: TOptions;
|
|
62
|
+
}
|
|
63
|
+
export interface InitialRunParams<TOptions extends object = {}> extends BaseRunParams<TOptions> {
|
|
64
|
+
initialState?: State;
|
|
65
|
+
initialCompletedSteps?: never;
|
|
66
|
+
workflowRunId?: never;
|
|
67
|
+
}
|
|
68
|
+
export interface RerunParams<TOptions extends object = {}> extends BaseRunParams<TOptions> {
|
|
69
|
+
initialState: State;
|
|
70
|
+
initialCompletedSteps: SerializedStep[];
|
|
71
|
+
workflowRunId: string;
|
|
72
|
+
}
|
|
73
|
+
export declare class Workflow<TOptions extends object = {}, TState extends State = {}> {
|
|
74
|
+
readonly title: string;
|
|
75
|
+
private description?;
|
|
76
|
+
private blocks;
|
|
77
|
+
type: 'workflow';
|
|
78
|
+
constructor(title: string, description?: string | undefined);
|
|
79
|
+
step<TNewState extends State>(title: string, action: (params: {
|
|
80
|
+
state: TState;
|
|
81
|
+
options: TOptions;
|
|
82
|
+
client: PromptClient;
|
|
83
|
+
fileStore: FileStore;
|
|
84
|
+
}) => TNewState | Promise<TNewState>): Workflow<TOptions, TNewState>;
|
|
85
|
+
workflow<TInnerState extends State, TNewState extends State>(title: string, innerWorkflow: Workflow<TOptions, TInnerState>, action: (params: {
|
|
86
|
+
state: TState;
|
|
87
|
+
workflowState: TInnerState;
|
|
88
|
+
}) => TNewState, initialState?: State | ((state: TState) => State)): Workflow<TOptions, TNewState>;
|
|
89
|
+
prompt<TResponseKey extends string & {
|
|
90
|
+
readonly brand?: unique symbol;
|
|
91
|
+
}, TSchema extends z.ZodObject<any>, TNewState extends State = TState & {
|
|
92
|
+
[K in TResponseKey]: z.infer<TSchema>;
|
|
93
|
+
}>(title: string, config: {
|
|
94
|
+
template: (state: TState) => string;
|
|
95
|
+
responseModel: {
|
|
96
|
+
schema: TSchema;
|
|
97
|
+
name: TResponseKey & (string extends TResponseKey ? never : unknown);
|
|
98
|
+
};
|
|
99
|
+
client?: PromptClient;
|
|
100
|
+
}, reduce?: (params: {
|
|
101
|
+
state: TState;
|
|
102
|
+
response: z.infer<TSchema>;
|
|
103
|
+
options: TOptions;
|
|
104
|
+
prompt: string;
|
|
105
|
+
}) => TNewState | Promise<TNewState>): Workflow<TOptions, TNewState>;
|
|
106
|
+
run(params: InitialRunParams<TOptions>): AsyncGenerator<WorkflowEvent<TOptions>>;
|
|
107
|
+
run(params: RerunParams<TOptions>): AsyncGenerator<WorkflowEvent<TOptions>>;
|
|
108
|
+
private withBlocks;
|
|
109
|
+
private nextWorkflow;
|
|
110
|
+
}
|
|
111
|
+
export declare function disableWorkflowNameUniqueness(): void;
|
|
112
|
+
export declare function enableWorkflowNameUniqueness(): void;
|
|
113
|
+
export declare function workflow<TOptions extends object = {}, TState extends State = {}>(workflowConfig: string | {
|
|
114
|
+
title: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
}): Workflow<TOptions, TState>;
|
|
117
|
+
export {};
|
|
118
|
+
//# sourceMappingURL=workflow.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.d.ts","sourceRoot":"","sources":["../../../src/dsl/workflow.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local-file-store.d.ts","sourceRoot":"","sources":["../../../src/file-stores/local-file-store.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,qBAAa,cAAe,YAAW,SAAS;IAClC,OAAO,CAAC,OAAO;gBAAP,OAAO,EAAE,MAAM;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;CAI9C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/file-stores/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACzC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { Workflow, workflow } from "./dsl/workflow";
|
|
2
|
+
export { WorkflowRunner } from "./dsl/workflow-runner";
|
|
3
|
+
export { createExtension } from "./dsl/extensions";
|
|
4
|
+
export { STATUS, WORKFLOW_EVENTS } from "./dsl/constants";
|
|
5
|
+
export { Adapter } from "./adapters/types";
|
|
6
|
+
export type { WorkflowEvent, SerializedStep, InitialRunParams, RerunParams, WorkflowStartEvent, WorkflowCompleteEvent, WorkflowErrorEvent, StepStatusEvent, StepStartedEvent, StepCompletedEvent } from "./dsl/workflow";
|
|
7
|
+
export type { PromptClient, ResponseModel } from "./clients/types";
|
|
8
|
+
export type { State } from "./dsl/types";
|
|
9
|
+
export type { FileStore } from "./file-stores/types";
|
|
10
|
+
export { createPatch, applyPatches } from "./dsl/json-patch";
|
|
11
|
+
export { LocalFileStore } from "./file-stores/local-file-store";
|
|
12
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,YAAY,EACV,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,kBAAkB,EACnB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnE,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes content to a temporary file and opens it in cursor
|
|
3
|
+
*/
|
|
4
|
+
export declare function writeAndOpenTemp(content: string, prefix: string, extension?: string): Promise<string>;
|
|
5
|
+
/**
|
|
6
|
+
* Writes both prompt and response to temp files and opens them in cursor
|
|
7
|
+
*/
|
|
8
|
+
export declare function writePromptAndResponse(prompt: string, response: unknown, prefix?: string): Promise<{
|
|
9
|
+
promptPath: string;
|
|
10
|
+
responsePath: string;
|
|
11
|
+
}>;
|
|
12
|
+
//# sourceMappingURL=temp-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"temp-files.d.ts","sourceRoot":"","sources":["../../../src/utils/temp-files.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,MAAc,GACxB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,OAAO,EACjB,MAAM,GAAE,MAAgB,GACvB,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,CASvD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@positronic/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "A DSL for AI Workflows",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/src/index.js",
|
|
7
|
+
"types": "dist/types/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"tsc": "tsc --project tsconfig.json",
|
|
10
|
+
"build": "npm run tsc && swc src -d dist",
|
|
11
|
+
"clean": "rm -rf tsconfig.tsbuildinfo dist"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"fast-json-patch": "^3.1.1",
|
|
15
|
+
"uuid": "^11.0.5",
|
|
16
|
+
"zod": "^3.24.1"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/uuid": "^10.0.0"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { WORKFLOW_EVENTS } from '../dsl/constants';
|
|
2
|
+
import type { WorkflowEvent } from '../dsl/workflow';
|
|
3
|
+
|
|
4
|
+
export abstract class Adapter<Options extends object = any> {
|
|
5
|
+
async started?(event: WorkflowEvent<Options>): Promise<void>;
|
|
6
|
+
async updated?(event: WorkflowEvent<Options>): Promise<void>;
|
|
7
|
+
async completed?(event: WorkflowEvent<Options>): Promise<void>;
|
|
8
|
+
async error?(event: WorkflowEvent<Options>): Promise<void>;
|
|
9
|
+
async restarted?(event: WorkflowEvent<Options>): Promise<void>;
|
|
10
|
+
|
|
11
|
+
async dispatch(event: WorkflowEvent<Options>) {
|
|
12
|
+
if (event.type === WORKFLOW_EVENTS.START && this.started) {
|
|
13
|
+
await this.started(event);
|
|
14
|
+
} else if (event.type === WORKFLOW_EVENTS.STEP_COMPLETE && this.updated) {
|
|
15
|
+
await this.updated(event);
|
|
16
|
+
} else if (event.type === WORKFLOW_EVENTS.COMPLETE && this.completed) {
|
|
17
|
+
await this.completed(event);
|
|
18
|
+
} else if (event.type === WORKFLOW_EVENTS.ERROR && this.error) {
|
|
19
|
+
await this.error(event);
|
|
20
|
+
} else if (event.type === WORKFLOW_EVENTS.RESTART && this.restarted) {
|
|
21
|
+
await this.restarted(event);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export type ResponseModel<T extends z.AnyZodObject> = {
|
|
4
|
+
schema: T;
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface PromptClient {
|
|
10
|
+
execute<T extends z.AnyZodObject>(
|
|
11
|
+
prompt: string,
|
|
12
|
+
responseModel: ResponseModel<T>,
|
|
13
|
+
): Promise<z.infer<T>>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const WORKFLOW_EVENTS = {
|
|
2
|
+
START: 'workflow:start',
|
|
3
|
+
RESTART: 'workflow:restart',
|
|
4
|
+
STEP_START: 'step:start',
|
|
5
|
+
STEP_COMPLETE: 'step:complete',
|
|
6
|
+
STEP_STATUS: 'step:status',
|
|
7
|
+
ERROR: 'workflow:error',
|
|
8
|
+
COMPLETE: 'workflow:complete',
|
|
9
|
+
} as const;
|
|
10
|
+
|
|
11
|
+
export const STATUS = {
|
|
12
|
+
PENDING: 'pending',
|
|
13
|
+
RUNNING: 'running',
|
|
14
|
+
COMPLETE: 'complete',
|
|
15
|
+
ERROR: 'error',
|
|
16
|
+
} as const;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Workflow } from "./workflow";
|
|
2
|
+
import type { State } from "./types";
|
|
3
|
+
|
|
4
|
+
type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never;
|
|
5
|
+
|
|
6
|
+
type ExtensionMethods<
|
|
7
|
+
TExtension extends Record<string, any>,
|
|
8
|
+
TOptions extends object,
|
|
9
|
+
TState extends State
|
|
10
|
+
> = TExtension extends ((...args: any[]) => any)
|
|
11
|
+
? TExtension extends ((
|
|
12
|
+
this: any,
|
|
13
|
+
title: string,
|
|
14
|
+
config: infer TConfig
|
|
15
|
+
) => Workflow<any, infer TReturnState>)
|
|
16
|
+
? (
|
|
17
|
+
title: string,
|
|
18
|
+
config: TConfig extends ((ctx: any) => any)
|
|
19
|
+
? { [P in keyof TConfig]: TConfig[P] extends Function ? ((ctx: TState) => any) : TConfig[P] }
|
|
20
|
+
: TConfig
|
|
21
|
+
) => Workflow<TOptions, Expand<TState & TReturnState>>
|
|
22
|
+
: never
|
|
23
|
+
: {
|
|
24
|
+
[K in keyof TExtension]: TExtension[K] extends (
|
|
25
|
+
this: any,
|
|
26
|
+
title: string,
|
|
27
|
+
config: infer TConfig
|
|
28
|
+
) => Workflow<any, infer TReturnState>
|
|
29
|
+
? (
|
|
30
|
+
title: string,
|
|
31
|
+
config: TConfig extends ((ctx: any) => any)
|
|
32
|
+
? { [P in keyof TConfig]: TConfig[P] extends Function ? ((ctx: TState) => any) : TConfig[P] }
|
|
33
|
+
: TConfig
|
|
34
|
+
) => Workflow<TOptions, Expand<TState & TReturnState>>
|
|
35
|
+
: never;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export function createExtension<
|
|
39
|
+
TExtensionKey extends string,
|
|
40
|
+
TExtension extends Record<string, any>
|
|
41
|
+
>(key: TExtensionKey, extension: TExtension) {
|
|
42
|
+
return {
|
|
43
|
+
install() {
|
|
44
|
+
Object.defineProperty(Workflow.prototype, key, {
|
|
45
|
+
get() {
|
|
46
|
+
const boundMethods: Record<string, Function> = {};
|
|
47
|
+
for (const [methodKey, fn] of Object.entries(extension)) {
|
|
48
|
+
boundMethods[methodKey] = fn.bind(this);
|
|
49
|
+
}
|
|
50
|
+
return boundMethods;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
},
|
|
54
|
+
augment<TOptions extends object, TState extends State>(): ExtensionMethods<TExtension, TOptions, TState> {
|
|
55
|
+
return {} as ExtensionMethods<TExtension, TOptions, TState>;
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import pkg from 'fast-json-patch';
|
|
2
|
+
const { compare, applyPatch } = pkg;
|
|
3
|
+
import { JsonPatch, State } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a JSON Patch that describes the changes needed to transform prevState into nextState.
|
|
7
|
+
*/
|
|
8
|
+
export function createPatch(prevState: State, nextState: State): JsonPatch {
|
|
9
|
+
// Filter out non-standard operations and ensure type safety
|
|
10
|
+
return compare(prevState, nextState).filter(op =>
|
|
11
|
+
['add', 'remove', 'replace', 'move', 'copy', 'test'].includes(op.op)
|
|
12
|
+
) as JsonPatch;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Applies one or more JSON Patches to a state object and returns the resulting state.
|
|
17
|
+
* If multiple patches are provided, they are applied in sequence.
|
|
18
|
+
*/
|
|
19
|
+
export function applyPatches(state: State, patches: JsonPatch | JsonPatch[]): State {
|
|
20
|
+
const patchArray = Array.isArray(patches[0]) ? patches as JsonPatch[] : [patches as JsonPatch];
|
|
21
|
+
|
|
22
|
+
// Apply patches in sequence, creating a new state object each time
|
|
23
|
+
return patchArray.reduce((currentState, patch) => {
|
|
24
|
+
const { newDocument } = applyPatch(currentState, patch as any[], true, false);
|
|
25
|
+
return newDocument;
|
|
26
|
+
}, { ...state });
|
|
27
|
+
}
|
package/src/dsl/types.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type JsonPrimitive = string | number | boolean | null;
|
|
2
|
+
export type JsonArray = JsonValue[];
|
|
3
|
+
export type JsonObject = { [Key in string]?: JsonValue };
|
|
4
|
+
export type JsonValue = JsonPrimitive | JsonArray | JsonObject;
|
|
5
|
+
|
|
6
|
+
export type State = JsonObject;
|
|
7
|
+
|
|
8
|
+
export type JsonPatch = {
|
|
9
|
+
op: 'add' | 'remove' | 'replace' | 'move' | 'copy' | 'test';
|
|
10
|
+
path: string;
|
|
11
|
+
value?: JsonValue;
|
|
12
|
+
from?: string;
|
|
13
|
+
}[];
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { WorkflowRunner } from './workflow-runner';
|
|
2
|
+
import { workflow } from './workflow';
|
|
3
|
+
import { WORKFLOW_EVENTS, STATUS } from './constants';
|
|
4
|
+
import type { FileStore } from '../file-stores/types';
|
|
5
|
+
|
|
6
|
+
class TestFileStore implements FileStore {
|
|
7
|
+
async readFile(path: string) {
|
|
8
|
+
return Promise.resolve('');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe('WorkflowRunner', () => {
|
|
13
|
+
const mockClient = {
|
|
14
|
+
execute: jest.fn()
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const mockLogger = {
|
|
18
|
+
log: jest.fn()
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const mockAdapter = {
|
|
22
|
+
dispatch: jest.fn()
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const fileStore = new TestFileStore();
|
|
26
|
+
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
jest.clearAllMocks();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('should run a workflow and dispatch events to adapters', async () => {
|
|
32
|
+
const runner = new WorkflowRunner({
|
|
33
|
+
adapters: [mockAdapter],
|
|
34
|
+
fileStore,
|
|
35
|
+
logger: mockLogger,
|
|
36
|
+
verbose: false,
|
|
37
|
+
client: mockClient
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const testWorkflow = workflow('Test Workflow')
|
|
41
|
+
.step('First Step', () => ({ value: 42 }))
|
|
42
|
+
.step('Async Step', async ({ state}) => {
|
|
43
|
+
await new Promise(resolve => setTimeout(resolve, 10));
|
|
44
|
+
return { ...state, asyncValue: 'completed' };
|
|
45
|
+
})
|
|
46
|
+
.step('Final Step', ({ state }) => ({
|
|
47
|
+
...state,
|
|
48
|
+
finalValue: state.value * 2
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
await runner.run(testWorkflow);
|
|
52
|
+
|
|
53
|
+
// Verify adapter received all events in correct order
|
|
54
|
+
expect(mockAdapter.dispatch).toHaveBeenCalledWith(
|
|
55
|
+
expect.objectContaining({
|
|
56
|
+
type: WORKFLOW_EVENTS.START,
|
|
57
|
+
workflowTitle: 'Test Workflow'
|
|
58
|
+
})
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
expect(mockAdapter.dispatch).toHaveBeenCalledWith(
|
|
62
|
+
expect.objectContaining({
|
|
63
|
+
type: WORKFLOW_EVENTS.STEP_COMPLETE,
|
|
64
|
+
stepTitle: 'First Step'
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(mockAdapter.dispatch).toHaveBeenCalledWith(
|
|
69
|
+
expect.objectContaining({
|
|
70
|
+
type: WORKFLOW_EVENTS.STEP_COMPLETE,
|
|
71
|
+
stepTitle: 'Async Step'
|
|
72
|
+
})
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
expect(mockAdapter.dispatch).toHaveBeenCalledWith(
|
|
76
|
+
expect.objectContaining({
|
|
77
|
+
type: WORKFLOW_EVENTS.STEP_COMPLETE,
|
|
78
|
+
stepTitle: 'Final Step'
|
|
79
|
+
})
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
expect(mockAdapter.dispatch).toHaveBeenCalledWith(
|
|
83
|
+
expect.objectContaining({
|
|
84
|
+
type: WORKFLOW_EVENTS.COMPLETE,
|
|
85
|
+
status: STATUS.COMPLETE
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
// Verify the order of events
|
|
90
|
+
const stepCompletions = mockAdapter.dispatch.mock.calls
|
|
91
|
+
.filter(call => call[0].type === WORKFLOW_EVENTS.STEP_COMPLETE)
|
|
92
|
+
.map(call => call[0].stepTitle);
|
|
93
|
+
|
|
94
|
+
expect(stepCompletions).toEqual([
|
|
95
|
+
'First Step',
|
|
96
|
+
'Async Step',
|
|
97
|
+
'Final Step'
|
|
98
|
+
]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should log final state when verbose is true', async () => {
|
|
102
|
+
const runner = new WorkflowRunner({
|
|
103
|
+
adapters: [],
|
|
104
|
+
fileStore,
|
|
105
|
+
logger: mockLogger,
|
|
106
|
+
verbose: true,
|
|
107
|
+
client: mockClient
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const testWorkflow = workflow('Test Workflow')
|
|
111
|
+
.step('Test Step', () => ({ value: 42 }));
|
|
112
|
+
|
|
113
|
+
await runner.run(testWorkflow);
|
|
114
|
+
|
|
115
|
+
expect(mockLogger.log).toHaveBeenCalledWith(
|
|
116
|
+
expect.stringContaining('Workflow completed:')
|
|
117
|
+
);
|
|
118
|
+
expect(mockLogger.log).toHaveBeenCalledWith(
|
|
119
|
+
expect.stringContaining('"value": 42')
|
|
120
|
+
);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should handle workflow errors', async () => {
|
|
124
|
+
const runner = new WorkflowRunner({
|
|
125
|
+
adapters: [mockAdapter],
|
|
126
|
+
fileStore,
|
|
127
|
+
logger: mockLogger,
|
|
128
|
+
verbose: true,
|
|
129
|
+
client: mockClient
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const errorWorkflow = workflow('Error Workflow')
|
|
133
|
+
.step('Error Step', () => {
|
|
134
|
+
throw new Error('Test error');
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
await runner.run(errorWorkflow);
|
|
139
|
+
} catch (error) {
|
|
140
|
+
// Expected error
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Verify error event was dispatched
|
|
144
|
+
expect(mockAdapter.dispatch).toHaveBeenCalledWith(
|
|
145
|
+
expect.objectContaining({
|
|
146
|
+
type: WORKFLOW_EVENTS.ERROR,
|
|
147
|
+
error: expect.objectContaining({
|
|
148
|
+
message: 'Test error'
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should truncate long values in verbose output', async () => {
|
|
155
|
+
const runner = new WorkflowRunner({
|
|
156
|
+
adapters: [],
|
|
157
|
+
fileStore,
|
|
158
|
+
logger: mockLogger,
|
|
159
|
+
verbose: true,
|
|
160
|
+
client: mockClient
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const longString = 'a'.repeat(1000); // Make string much longer
|
|
164
|
+
const testWorkflow = workflow('Test Workflow')
|
|
165
|
+
.step('Test Step', () => ({
|
|
166
|
+
longString,
|
|
167
|
+
nested: { longString }
|
|
168
|
+
}));
|
|
169
|
+
|
|
170
|
+
await runner.run(testWorkflow);
|
|
171
|
+
|
|
172
|
+
const logCall = mockLogger.log.mock.calls.find(call =>
|
|
173
|
+
call[0].includes('Workflow completed:')
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
expect(logCall[0]).toContain('...');
|
|
177
|
+
expect(logCall[0].length).toBeLessThan(longString.length);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should maintain state between steps', async () => {
|
|
181
|
+
const runner = new WorkflowRunner({
|
|
182
|
+
adapters: [],
|
|
183
|
+
fileStore,
|
|
184
|
+
logger: mockLogger,
|
|
185
|
+
verbose: true,
|
|
186
|
+
client: mockClient
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
const testWorkflow = workflow('Test Workflow')
|
|
190
|
+
.step('First Step', () => ({ count: 1 }))
|
|
191
|
+
.step('Second Step', ({ state }) => ({
|
|
192
|
+
count: state.count + 1
|
|
193
|
+
}));
|
|
194
|
+
|
|
195
|
+
await runner.run(testWorkflow);
|
|
196
|
+
|
|
197
|
+
const finalLog = mockLogger.log.mock.calls.find(call =>
|
|
198
|
+
call[0].includes('Workflow completed:')
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
expect(finalLog[0]).toContain('"count": 2');
|
|
202
|
+
});
|
|
203
|
+
});
|