@radaros/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +887 -0
- package/dist/index.js +3462 -0
- package/package.json +64 -0
- package/src/agent/agent.ts +314 -0
- package/src/agent/llm-loop.ts +263 -0
- package/src/agent/run-context.ts +35 -0
- package/src/agent/types.ts +77 -0
- package/src/events/event-bus.ts +45 -0
- package/src/events/types.ts +16 -0
- package/src/guardrails/types.ts +5 -0
- package/src/hooks/types.ts +6 -0
- package/src/index.ts +111 -0
- package/src/knowledge/knowledge-base.ts +146 -0
- package/src/logger/logger.ts +232 -0
- package/src/memory/memory.ts +87 -0
- package/src/memory/types.ts +13 -0
- package/src/models/provider.ts +22 -0
- package/src/models/providers/anthropic.ts +330 -0
- package/src/models/providers/google.ts +361 -0
- package/src/models/providers/ollama.ts +211 -0
- package/src/models/providers/openai.ts +323 -0
- package/src/models/registry.ts +90 -0
- package/src/models/types.ts +112 -0
- package/src/session/session-manager.ts +75 -0
- package/src/session/types.ts +10 -0
- package/src/storage/driver.ts +10 -0
- package/src/storage/in-memory.ts +44 -0
- package/src/storage/mongodb.ts +70 -0
- package/src/storage/postgres.ts +81 -0
- package/src/storage/sqlite.ts +81 -0
- package/src/team/modes.ts +1 -0
- package/src/team/team.ts +323 -0
- package/src/team/types.ts +26 -0
- package/src/tools/define-tool.ts +20 -0
- package/src/tools/tool-executor.ts +131 -0
- package/src/tools/types.ts +27 -0
- package/src/vector/base.ts +44 -0
- package/src/vector/embeddings/google.ts +64 -0
- package/src/vector/embeddings/openai.ts +66 -0
- package/src/vector/in-memory.ts +115 -0
- package/src/vector/mongodb.ts +241 -0
- package/src/vector/pgvector.ts +169 -0
- package/src/vector/qdrant.ts +203 -0
- package/src/vector/types.ts +55 -0
- package/src/workflow/step-runner.ts +303 -0
- package/src/workflow/types.ts +55 -0
- package/src/workflow/workflow.ts +68 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import type { RunContext } from "../agent/run-context.js";
|
|
2
|
+
import type {
|
|
3
|
+
StepDef,
|
|
4
|
+
StepResult,
|
|
5
|
+
AgentStep,
|
|
6
|
+
FunctionStep,
|
|
7
|
+
ConditionStep,
|
|
8
|
+
ParallelStep,
|
|
9
|
+
} from "./types.js";
|
|
10
|
+
|
|
11
|
+
function isAgentStep<T>(step: StepDef<T>): step is AgentStep<T> {
|
|
12
|
+
return "agent" in step;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function isFunctionStep<T>(step: StepDef<T>): step is FunctionStep<T> {
|
|
16
|
+
return "run" in step;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isConditionStep<T>(step: StepDef<T>): step is ConditionStep<T> {
|
|
20
|
+
return "condition" in step;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function isParallelStep<T>(step: StepDef<T>): step is ParallelStep<T> {
|
|
24
|
+
return "parallel" in step;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export class StepRunner<TState extends Record<string, unknown>> {
|
|
28
|
+
private retryPolicy?: { maxRetries: number; backoffMs: number };
|
|
29
|
+
|
|
30
|
+
constructor(retryPolicy?: { maxRetries: number; backoffMs: number }) {
|
|
31
|
+
this.retryPolicy = retryPolicy;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async executeSteps(
|
|
35
|
+
steps: StepDef<TState>[],
|
|
36
|
+
state: TState,
|
|
37
|
+
ctx: RunContext
|
|
38
|
+
): Promise<{ state: TState; results: StepResult[] }> {
|
|
39
|
+
let currentState = { ...state };
|
|
40
|
+
const allResults: StepResult[] = [];
|
|
41
|
+
|
|
42
|
+
for (const step of steps) {
|
|
43
|
+
const { state: newState, results } = await this.executeStep(
|
|
44
|
+
step,
|
|
45
|
+
currentState,
|
|
46
|
+
ctx
|
|
47
|
+
);
|
|
48
|
+
currentState = newState;
|
|
49
|
+
allResults.push(...results);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { state: currentState, results: allResults };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private async executeStep(
|
|
56
|
+
step: StepDef<TState>,
|
|
57
|
+
state: TState,
|
|
58
|
+
ctx: RunContext
|
|
59
|
+
): Promise<{ state: TState; results: StepResult[] }> {
|
|
60
|
+
if (isConditionStep(step)) {
|
|
61
|
+
return this.executeConditionStep(step, state, ctx);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (isParallelStep(step)) {
|
|
65
|
+
return this.executeParallelStep(step, state, ctx);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (isAgentStep(step)) {
|
|
69
|
+
return this.executeAgentStep(step, state, ctx);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (isFunctionStep(step)) {
|
|
73
|
+
return this.executeFunctionStep(step, state, ctx);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return { state, results: [] };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private async executeAgentStep(
|
|
80
|
+
step: AgentStep<TState>,
|
|
81
|
+
state: TState,
|
|
82
|
+
ctx: RunContext
|
|
83
|
+
): Promise<{ state: TState; results: StepResult[] }> {
|
|
84
|
+
const startTime = Date.now();
|
|
85
|
+
|
|
86
|
+
ctx.eventBus.emit("workflow.step", {
|
|
87
|
+
runId: ctx.runId,
|
|
88
|
+
stepName: step.name,
|
|
89
|
+
status: "start",
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const execute = async (): Promise<StepResult> => {
|
|
93
|
+
const input = step.inputFrom
|
|
94
|
+
? step.inputFrom(state)
|
|
95
|
+
: JSON.stringify(state);
|
|
96
|
+
|
|
97
|
+
const output = await step.agent.run(input, {
|
|
98
|
+
sessionId: ctx.sessionId,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const newState = {
|
|
102
|
+
...state,
|
|
103
|
+
[`${step.name}_output`]: output.text,
|
|
104
|
+
} as TState;
|
|
105
|
+
|
|
106
|
+
Object.assign(state, newState);
|
|
107
|
+
|
|
108
|
+
return {
|
|
109
|
+
stepName: step.name,
|
|
110
|
+
status: "done",
|
|
111
|
+
durationMs: Date.now() - startTime,
|
|
112
|
+
};
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const result = await this.withRetry(step.name, execute, ctx);
|
|
116
|
+
return { state, results: [result] };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
private async executeFunctionStep(
|
|
120
|
+
step: FunctionStep<TState>,
|
|
121
|
+
state: TState,
|
|
122
|
+
ctx: RunContext
|
|
123
|
+
): Promise<{ state: TState; results: StepResult[] }> {
|
|
124
|
+
const startTime = Date.now();
|
|
125
|
+
|
|
126
|
+
ctx.eventBus.emit("workflow.step", {
|
|
127
|
+
runId: ctx.runId,
|
|
128
|
+
stepName: step.name,
|
|
129
|
+
status: "start",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const execute = async (): Promise<StepResult> => {
|
|
133
|
+
const patch = await step.run(state, ctx);
|
|
134
|
+
Object.assign(state, patch);
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
stepName: step.name,
|
|
138
|
+
status: "done",
|
|
139
|
+
durationMs: Date.now() - startTime,
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
const result = await this.withRetry(step.name, execute, ctx);
|
|
144
|
+
return { state, results: [result] };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
private async executeConditionStep(
|
|
148
|
+
step: ConditionStep<TState>,
|
|
149
|
+
state: TState,
|
|
150
|
+
ctx: RunContext
|
|
151
|
+
): Promise<{ state: TState; results: StepResult[] }> {
|
|
152
|
+
const startTime = Date.now();
|
|
153
|
+
|
|
154
|
+
ctx.eventBus.emit("workflow.step", {
|
|
155
|
+
runId: ctx.runId,
|
|
156
|
+
stepName: step.name,
|
|
157
|
+
status: "start",
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
if (step.condition(state)) {
|
|
161
|
+
const { state: newState, results } = await this.executeSteps(
|
|
162
|
+
step.steps,
|
|
163
|
+
state,
|
|
164
|
+
ctx
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
ctx.eventBus.emit("workflow.step", {
|
|
168
|
+
runId: ctx.runId,
|
|
169
|
+
stepName: step.name,
|
|
170
|
+
status: "done",
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
state: newState,
|
|
175
|
+
results: [
|
|
176
|
+
{
|
|
177
|
+
stepName: step.name,
|
|
178
|
+
status: "done",
|
|
179
|
+
durationMs: Date.now() - startTime,
|
|
180
|
+
},
|
|
181
|
+
...results,
|
|
182
|
+
],
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
ctx.eventBus.emit("workflow.step", {
|
|
187
|
+
runId: ctx.runId,
|
|
188
|
+
stepName: step.name,
|
|
189
|
+
status: "done",
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
state,
|
|
194
|
+
results: [
|
|
195
|
+
{
|
|
196
|
+
stepName: step.name,
|
|
197
|
+
status: "skipped",
|
|
198
|
+
durationMs: Date.now() - startTime,
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
private async executeParallelStep(
|
|
205
|
+
step: ParallelStep<TState>,
|
|
206
|
+
state: TState,
|
|
207
|
+
ctx: RunContext
|
|
208
|
+
): Promise<{ state: TState; results: StepResult[] }> {
|
|
209
|
+
const startTime = Date.now();
|
|
210
|
+
|
|
211
|
+
ctx.eventBus.emit("workflow.step", {
|
|
212
|
+
runId: ctx.runId,
|
|
213
|
+
stepName: step.name,
|
|
214
|
+
status: "start",
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
const settled = await Promise.allSettled(
|
|
218
|
+
step.parallel.map((s) => this.executeStep(s, { ...state }, ctx))
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
const allResults: StepResult[] = [];
|
|
222
|
+
let mergedState = { ...state };
|
|
223
|
+
|
|
224
|
+
for (const result of settled) {
|
|
225
|
+
if (result.status === "fulfilled") {
|
|
226
|
+
Object.assign(mergedState, result.value.state);
|
|
227
|
+
allResults.push(...result.value.results);
|
|
228
|
+
} else {
|
|
229
|
+
allResults.push({
|
|
230
|
+
stepName: step.name,
|
|
231
|
+
status: "error",
|
|
232
|
+
error: result.reason?.message ?? "Unknown error",
|
|
233
|
+
durationMs: Date.now() - startTime,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
ctx.eventBus.emit("workflow.step", {
|
|
239
|
+
runId: ctx.runId,
|
|
240
|
+
stepName: step.name,
|
|
241
|
+
status: "done",
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
state: mergedState,
|
|
246
|
+
results: [
|
|
247
|
+
{
|
|
248
|
+
stepName: step.name,
|
|
249
|
+
status: "done",
|
|
250
|
+
durationMs: Date.now() - startTime,
|
|
251
|
+
},
|
|
252
|
+
...allResults,
|
|
253
|
+
],
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
private async withRetry(
|
|
258
|
+
stepName: string,
|
|
259
|
+
fn: () => Promise<StepResult>,
|
|
260
|
+
ctx: RunContext
|
|
261
|
+
): Promise<StepResult> {
|
|
262
|
+
const maxRetries = this.retryPolicy?.maxRetries ?? 0;
|
|
263
|
+
const backoffMs = this.retryPolicy?.backoffMs ?? 1000;
|
|
264
|
+
|
|
265
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
266
|
+
try {
|
|
267
|
+
const result = await fn();
|
|
268
|
+
|
|
269
|
+
ctx.eventBus.emit("workflow.step", {
|
|
270
|
+
runId: ctx.runId,
|
|
271
|
+
stepName,
|
|
272
|
+
status: "done",
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
return result;
|
|
276
|
+
} catch (error) {
|
|
277
|
+
if (attempt === maxRetries) {
|
|
278
|
+
const err =
|
|
279
|
+
error instanceof Error ? error : new Error(String(error));
|
|
280
|
+
|
|
281
|
+
ctx.eventBus.emit("workflow.step", {
|
|
282
|
+
runId: ctx.runId,
|
|
283
|
+
stepName,
|
|
284
|
+
status: "error",
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
stepName,
|
|
289
|
+
status: "error",
|
|
290
|
+
error: err.message,
|
|
291
|
+
durationMs: 0,
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
await new Promise((resolve) =>
|
|
296
|
+
setTimeout(resolve, backoffMs * Math.pow(2, attempt))
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return { stepName, status: "error", error: "Exhausted retries", durationMs: 0 };
|
|
302
|
+
}
|
|
303
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { Agent } from "../agent/agent.js";
|
|
2
|
+
import type { RunContext } from "../agent/run-context.js";
|
|
3
|
+
import type { StorageDriver } from "../storage/driver.js";
|
|
4
|
+
import type { EventBus } from "../events/event-bus.js";
|
|
5
|
+
|
|
6
|
+
export type StepDef<TState> =
|
|
7
|
+
| AgentStep<TState>
|
|
8
|
+
| FunctionStep<TState>
|
|
9
|
+
| ConditionStep<TState>
|
|
10
|
+
| ParallelStep<TState>;
|
|
11
|
+
|
|
12
|
+
export interface AgentStep<TState> {
|
|
13
|
+
name: string;
|
|
14
|
+
agent: Agent;
|
|
15
|
+
inputFrom?: (state: TState) => string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface FunctionStep<TState> {
|
|
19
|
+
name: string;
|
|
20
|
+
run: (state: TState, ctx: RunContext) => Promise<Partial<TState>>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface ConditionStep<TState> {
|
|
24
|
+
name: string;
|
|
25
|
+
condition: (state: TState) => boolean;
|
|
26
|
+
steps: StepDef<TState>[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ParallelStep<TState> {
|
|
30
|
+
name: string;
|
|
31
|
+
parallel: StepDef<TState>[];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface WorkflowConfig<
|
|
35
|
+
TState extends Record<string, unknown> = Record<string, unknown>,
|
|
36
|
+
> {
|
|
37
|
+
name: string;
|
|
38
|
+
initialState: TState;
|
|
39
|
+
steps: StepDef<TState>[];
|
|
40
|
+
storage?: StorageDriver;
|
|
41
|
+
retryPolicy?: { maxRetries: number; backoffMs: number };
|
|
42
|
+
eventBus?: EventBus;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface WorkflowResult<TState> {
|
|
46
|
+
state: TState;
|
|
47
|
+
stepResults: StepResult[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface StepResult {
|
|
51
|
+
stepName: string;
|
|
52
|
+
status: "done" | "error" | "skipped";
|
|
53
|
+
error?: string;
|
|
54
|
+
durationMs: number;
|
|
55
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
|
+
import { EventBus } from "../events/event-bus.js";
|
|
3
|
+
import { RunContext } from "../agent/run-context.js";
|
|
4
|
+
import { StepRunner } from "./step-runner.js";
|
|
5
|
+
import type { WorkflowConfig, WorkflowResult } from "./types.js";
|
|
6
|
+
|
|
7
|
+
export class Workflow<
|
|
8
|
+
TState extends Record<string, unknown> = Record<string, unknown>,
|
|
9
|
+
> {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly eventBus: EventBus;
|
|
12
|
+
|
|
13
|
+
private config: WorkflowConfig<TState>;
|
|
14
|
+
private stepRunner: StepRunner<TState>;
|
|
15
|
+
|
|
16
|
+
constructor(config: WorkflowConfig<TState>) {
|
|
17
|
+
this.config = config;
|
|
18
|
+
this.name = config.name;
|
|
19
|
+
this.eventBus = config.eventBus ?? new EventBus();
|
|
20
|
+
this.stepRunner = new StepRunner<TState>(config.retryPolicy);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async run(opts?: {
|
|
24
|
+
sessionId?: string;
|
|
25
|
+
userId?: string;
|
|
26
|
+
}): Promise<WorkflowResult<TState>> {
|
|
27
|
+
const ctx = new RunContext({
|
|
28
|
+
sessionId: opts?.sessionId ?? uuidv4(),
|
|
29
|
+
userId: opts?.userId,
|
|
30
|
+
eventBus: this.eventBus,
|
|
31
|
+
sessionState: {},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
this.eventBus.emit("run.start", {
|
|
35
|
+
runId: ctx.runId,
|
|
36
|
+
agentName: `workflow:${this.name}`,
|
|
37
|
+
input: JSON.stringify(this.config.initialState),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const { state, results } = await this.stepRunner.executeSteps(
|
|
42
|
+
this.config.steps,
|
|
43
|
+
{ ...this.config.initialState },
|
|
44
|
+
ctx
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const workflowResult: WorkflowResult<TState> = {
|
|
48
|
+
state,
|
|
49
|
+
stepResults: results,
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
this.eventBus.emit("run.complete", {
|
|
53
|
+
runId: ctx.runId,
|
|
54
|
+
output: {
|
|
55
|
+
text: JSON.stringify(state),
|
|
56
|
+
toolCalls: [],
|
|
57
|
+
usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
return workflowResult;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
64
|
+
this.eventBus.emit("run.error", { runId: ctx.runId, error: err });
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|