@radaros/core 0.3.4 → 0.3.6
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 +1407 -0
- package/dist/index.js +5269 -0
- package/package.json +6 -2
- package/src/a2a/a2a-remote-agent.ts +0 -270
- package/src/a2a/types.ts +0 -142
- package/src/agent/agent.ts +0 -417
- package/src/agent/llm-loop.ts +0 -290
- package/src/agent/run-context.ts +0 -35
- package/src/agent/types.ts +0 -89
- package/src/events/event-bus.ts +0 -45
- package/src/events/types.ts +0 -16
- package/src/guardrails/types.ts +0 -5
- package/src/hooks/types.ts +0 -6
- package/src/index.ts +0 -157
- package/src/knowledge/knowledge-base.ts +0 -146
- package/src/logger/logger.ts +0 -249
- package/src/mcp/mcp-client.ts +0 -264
- package/src/memory/memory.ts +0 -87
- package/src/memory/types.ts +0 -13
- package/src/memory/user-memory.ts +0 -211
- package/src/models/provider.ts +0 -22
- package/src/models/providers/anthropic.ts +0 -360
- package/src/models/providers/google.ts +0 -386
- package/src/models/providers/ollama.ts +0 -211
- package/src/models/providers/openai.ts +0 -345
- package/src/models/providers/vertex.ts +0 -427
- package/src/models/registry.ts +0 -107
- package/src/models/types.ts +0 -124
- package/src/session/session-manager.ts +0 -75
- package/src/session/types.ts +0 -10
- package/src/storage/driver.ts +0 -10
- package/src/storage/in-memory.ts +0 -44
- package/src/storage/mongodb.ts +0 -70
- package/src/storage/postgres.ts +0 -81
- package/src/storage/sqlite.ts +0 -81
- package/src/team/modes.ts +0 -1
- package/src/team/team.ts +0 -323
- package/src/team/types.ts +0 -26
- package/src/toolkits/base.ts +0 -15
- package/src/toolkits/duckduckgo.ts +0 -256
- package/src/toolkits/gmail.ts +0 -226
- package/src/toolkits/hackernews.ts +0 -121
- package/src/toolkits/websearch.ts +0 -158
- package/src/toolkits/whatsapp.ts +0 -209
- package/src/tools/define-tool.ts +0 -22
- package/src/tools/tool-executor.ts +0 -221
- package/src/tools/types.ts +0 -36
- package/src/utils/retry.ts +0 -56
- package/src/vector/base.ts +0 -44
- package/src/vector/embeddings/google.ts +0 -64
- package/src/vector/embeddings/openai.ts +0 -66
- package/src/vector/in-memory.ts +0 -115
- package/src/vector/mongodb.ts +0 -241
- package/src/vector/pgvector.ts +0 -169
- package/src/vector/qdrant.ts +0 -203
- package/src/vector/types.ts +0 -55
- package/src/workflow/step-runner.ts +0 -303
- package/src/workflow/types.ts +0 -55
- package/src/workflow/workflow.ts +0 -68
- package/tsconfig.json +0 -8
package/src/vector/qdrant.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { createRequire } from "node:module";
|
|
2
|
-
import { createHash } from "node:crypto";
|
|
3
|
-
import { BaseVectorStore } from "./base.js";
|
|
4
|
-
import type {
|
|
5
|
-
VectorDocument,
|
|
6
|
-
VectorSearchResult,
|
|
7
|
-
VectorSearchOptions,
|
|
8
|
-
EmbeddingProvider,
|
|
9
|
-
} from "./types.js";
|
|
10
|
-
|
|
11
|
-
const _require = createRequire(import.meta.url);
|
|
12
|
-
|
|
13
|
-
export interface QdrantConfig {
|
|
14
|
-
url?: string;
|
|
15
|
-
apiKey?: string;
|
|
16
|
-
dimensions?: number;
|
|
17
|
-
checkCompatibility?: boolean;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Deterministic UUID from an arbitrary string.
|
|
24
|
-
* Qdrant only accepts UUIDs or unsigned ints as point IDs,
|
|
25
|
-
* so we hash arbitrary strings into valid UUID v4 format
|
|
26
|
-
* and store the original ID in the payload under `_originalId`.
|
|
27
|
-
*/
|
|
28
|
-
function stringToUUID(str: string): string {
|
|
29
|
-
const hex = createHash("md5").update(str).digest("hex");
|
|
30
|
-
return [
|
|
31
|
-
hex.slice(0, 8),
|
|
32
|
-
hex.slice(8, 12),
|
|
33
|
-
"4" + hex.slice(13, 16),
|
|
34
|
-
"8" + hex.slice(17, 20),
|
|
35
|
-
hex.slice(20, 32),
|
|
36
|
-
].join("-");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function toQdrantId(id: string): string | number {
|
|
40
|
-
if (/^\d+$/.test(id)) return Number(id);
|
|
41
|
-
if (UUID_RE.test(id)) return id;
|
|
42
|
-
return stringToUUID(id);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export class QdrantVectorStore extends BaseVectorStore {
|
|
46
|
-
private client: any;
|
|
47
|
-
private dimensions: number;
|
|
48
|
-
private initializedCollections = new Set<string>();
|
|
49
|
-
|
|
50
|
-
constructor(config: QdrantConfig = {}, embedder?: EmbeddingProvider) {
|
|
51
|
-
super(embedder);
|
|
52
|
-
this.dimensions = config.dimensions ?? embedder?.dimensions ?? 1536;
|
|
53
|
-
try {
|
|
54
|
-
const { QdrantClient } = _require("@qdrant/js-client-rest");
|
|
55
|
-
this.client = new QdrantClient({
|
|
56
|
-
url: config.url ?? "http://localhost:6333",
|
|
57
|
-
apiKey: config.apiKey,
|
|
58
|
-
checkCompatibility: config.checkCompatibility ?? false,
|
|
59
|
-
});
|
|
60
|
-
} catch {
|
|
61
|
-
throw new Error(
|
|
62
|
-
"@qdrant/js-client-rest is required for QdrantVectorStore. Install it: npm install @qdrant/js-client-rest"
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
async initialize(): Promise<void> {}
|
|
68
|
-
|
|
69
|
-
private async ensureCollection(collection: string): Promise<void> {
|
|
70
|
-
if (this.initializedCollections.has(collection)) return;
|
|
71
|
-
try {
|
|
72
|
-
await this.client.getCollection(collection);
|
|
73
|
-
} catch {
|
|
74
|
-
await this.client.createCollection(collection, {
|
|
75
|
-
vectors: {
|
|
76
|
-
size: this.dimensions,
|
|
77
|
-
distance: "Cosine",
|
|
78
|
-
},
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
this.initializedCollections.add(collection);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
async upsert(collection: string, doc: VectorDocument): Promise<void> {
|
|
85
|
-
await this.ensureCollection(collection);
|
|
86
|
-
const embedding = await this.ensureEmbedding(doc);
|
|
87
|
-
await this.client.upsert(collection, {
|
|
88
|
-
wait: true,
|
|
89
|
-
points: [
|
|
90
|
-
{
|
|
91
|
-
id: toQdrantId(doc.id),
|
|
92
|
-
vector: embedding,
|
|
93
|
-
payload: {
|
|
94
|
-
_originalId: doc.id,
|
|
95
|
-
content: doc.content,
|
|
96
|
-
...(doc.metadata ?? {}),
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
async upsertBatch(collection: string, docs: VectorDocument[]): Promise<void> {
|
|
104
|
-
await this.ensureCollection(collection);
|
|
105
|
-
const points = await Promise.all(
|
|
106
|
-
docs.map(async (doc) => {
|
|
107
|
-
const embedding = await this.ensureEmbedding(doc);
|
|
108
|
-
return {
|
|
109
|
-
id: toQdrantId(doc.id),
|
|
110
|
-
vector: embedding,
|
|
111
|
-
payload: {
|
|
112
|
-
_originalId: doc.id,
|
|
113
|
-
content: doc.content,
|
|
114
|
-
...(doc.metadata ?? {}),
|
|
115
|
-
},
|
|
116
|
-
};
|
|
117
|
-
})
|
|
118
|
-
);
|
|
119
|
-
await this.client.upsert(collection, { wait: true, points });
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async search(
|
|
123
|
-
collection: string,
|
|
124
|
-
query: number[] | string,
|
|
125
|
-
options?: VectorSearchOptions
|
|
126
|
-
): Promise<VectorSearchResult[]> {
|
|
127
|
-
await this.ensureCollection(collection);
|
|
128
|
-
const vec = await this.ensureQueryVector(query);
|
|
129
|
-
const topK = options?.topK ?? 10;
|
|
130
|
-
|
|
131
|
-
const searchParams: Record<string, unknown> = {
|
|
132
|
-
vector: vec,
|
|
133
|
-
limit: topK,
|
|
134
|
-
with_payload: true,
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
if (options?.filter) {
|
|
138
|
-
searchParams.filter = {
|
|
139
|
-
must: Object.entries(options.filter).map(([key, value]) => ({
|
|
140
|
-
key,
|
|
141
|
-
match: { value },
|
|
142
|
-
})),
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (options?.minScore != null) {
|
|
147
|
-
searchParams.score_threshold = options.minScore;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const results = await this.client.search(collection, searchParams);
|
|
151
|
-
|
|
152
|
-
return results.map((r: any) => {
|
|
153
|
-
const { _originalId, content, ...rest } = r.payload ?? {};
|
|
154
|
-
return {
|
|
155
|
-
id: _originalId ?? String(r.id),
|
|
156
|
-
content: content ?? "",
|
|
157
|
-
score: r.score,
|
|
158
|
-
metadata: rest,
|
|
159
|
-
};
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async delete(collection: string, id: string): Promise<void> {
|
|
164
|
-
await this.ensureCollection(collection);
|
|
165
|
-
await this.client.delete(collection, {
|
|
166
|
-
wait: true,
|
|
167
|
-
points: [toQdrantId(id)],
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
async get(collection: string, id: string): Promise<VectorDocument | null> {
|
|
172
|
-
await this.ensureCollection(collection);
|
|
173
|
-
try {
|
|
174
|
-
const results = await this.client.retrieve(collection, {
|
|
175
|
-
ids: [toQdrantId(id)],
|
|
176
|
-
with_payload: true,
|
|
177
|
-
});
|
|
178
|
-
if (!results || results.length === 0) return null;
|
|
179
|
-
const point = results[0];
|
|
180
|
-
const { _originalId, content, ...rest } = point.payload ?? {};
|
|
181
|
-
return {
|
|
182
|
-
id: _originalId ?? String(point.id),
|
|
183
|
-
content: content ?? "",
|
|
184
|
-
metadata: rest,
|
|
185
|
-
};
|
|
186
|
-
} catch {
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
async dropCollection(collection: string): Promise<void> {
|
|
192
|
-
try {
|
|
193
|
-
await this.client.deleteCollection(collection);
|
|
194
|
-
} catch {
|
|
195
|
-
// collection may not exist
|
|
196
|
-
}
|
|
197
|
-
this.initializedCollections.delete(collection);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async close(): Promise<void> {
|
|
201
|
-
// Qdrant JS client doesn't require explicit close
|
|
202
|
-
}
|
|
203
|
-
}
|
package/src/vector/types.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
export interface VectorDocument {
|
|
2
|
-
id: string;
|
|
3
|
-
content: string;
|
|
4
|
-
embedding?: number[];
|
|
5
|
-
metadata?: Record<string, unknown>;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
export interface VectorSearchResult {
|
|
9
|
-
id: string;
|
|
10
|
-
content: string;
|
|
11
|
-
score: number;
|
|
12
|
-
metadata?: Record<string, unknown>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface VectorSearchOptions {
|
|
16
|
-
topK?: number;
|
|
17
|
-
filter?: Record<string, unknown>;
|
|
18
|
-
minScore?: number;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface EmbeddingProvider {
|
|
22
|
-
readonly dimensions: number;
|
|
23
|
-
embed(text: string): Promise<number[]>;
|
|
24
|
-
embedBatch(texts: string[]): Promise<number[][]>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface VectorStore {
|
|
28
|
-
/** Initialize collections/indexes. Call once before use. */
|
|
29
|
-
initialize(): Promise<void>;
|
|
30
|
-
|
|
31
|
-
/** Upsert a single document (embedding computed if not provided). */
|
|
32
|
-
upsert(collection: string, doc: VectorDocument): Promise<void>;
|
|
33
|
-
|
|
34
|
-
/** Upsert multiple documents in batch. */
|
|
35
|
-
upsertBatch(collection: string, docs: VectorDocument[]): Promise<void>;
|
|
36
|
-
|
|
37
|
-
/** Similarity search by vector or text query. */
|
|
38
|
-
search(
|
|
39
|
-
collection: string,
|
|
40
|
-
query: number[] | string,
|
|
41
|
-
options?: VectorSearchOptions
|
|
42
|
-
): Promise<VectorSearchResult[]>;
|
|
43
|
-
|
|
44
|
-
/** Delete a document by ID. */
|
|
45
|
-
delete(collection: string, id: string): Promise<void>;
|
|
46
|
-
|
|
47
|
-
/** Get a document by ID. */
|
|
48
|
-
get(collection: string, id: string): Promise<VectorDocument | null>;
|
|
49
|
-
|
|
50
|
-
/** Drop an entire collection. */
|
|
51
|
-
dropCollection(collection: string): Promise<void>;
|
|
52
|
-
|
|
53
|
-
/** Close connections. */
|
|
54
|
-
close(): Promise<void>;
|
|
55
|
-
}
|
|
@@ -1,303 +0,0 @@
|
|
|
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
|
-
}
|
package/src/workflow/types.ts
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
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
|
-
}
|
package/src/workflow/workflow.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
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
|
-
}
|