@prefactor/core 0.1.0 → 0.2.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/README.md +234 -0
- package/dist/agent/instance-manager.d.ts +19 -0
- package/dist/agent/instance-manager.d.ts.map +1 -0
- package/dist/agent/instance-manager.js +71 -0
- package/dist/agent/instance-manager.js.map +1 -0
- package/dist/agent/schema-registry.d.ts +9 -0
- package/dist/agent/schema-registry.d.ts.map +1 -0
- package/dist/agent/schema-registry.js +16 -0
- package/dist/agent/schema-registry.js.map +1 -0
- package/dist/config.d.ts +49 -25
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -7
- package/dist/config.js.map +1 -1
- package/dist/create-core.d.ts +12 -0
- package/dist/create-core.d.ts.map +1 -0
- package/dist/create-core.js +49 -0
- package/dist/create-core.js.map +1 -0
- package/dist/index.cjs +390 -134
- package/dist/index.cjs.map +14 -9
- package/dist/index.d.ts +7 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +391 -135
- package/dist/index.js.map +14 -9
- package/dist/queue/actions.d.ts +35 -0
- package/dist/queue/actions.d.ts.map +1 -0
- package/dist/queue/actions.js +2 -0
- package/dist/queue/actions.js.map +1 -0
- package/dist/queue/base.d.ts +7 -0
- package/dist/queue/base.d.ts.map +1 -0
- package/dist/queue/base.js +2 -0
- package/dist/queue/base.js.map +1 -0
- package/dist/queue/in-memory.d.ts +9 -0
- package/dist/queue/in-memory.d.ts.map +1 -0
- package/dist/queue/in-memory.js +18 -0
- package/dist/queue/in-memory.js.map +1 -0
- package/dist/tracing/context.d.ts +12 -0
- package/dist/tracing/context.d.ts.map +1 -1
- package/dist/tracing/context.js +41 -5
- package/dist/tracing/context.js.map +1 -1
- package/dist/tracing/span.d.ts +5 -0
- package/dist/tracing/span.d.ts.map +1 -1
- package/dist/tracing/span.js +29 -0
- package/dist/tracing/span.js.map +1 -1
- package/dist/tracing/tracer.d.ts +7 -17
- package/dist/tracing/tracer.d.ts.map +1 -1
- package/dist/tracing/tracer.js +20 -39
- package/dist/tracing/tracer.js.map +1 -1
- package/dist/transport/base.d.ts +2 -22
- package/dist/transport/base.d.ts.map +1 -1
- package/dist/transport/http.d.ts +5 -28
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +76 -110
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/stdio.d.ts +4 -16
- package/dist/transport/stdio.d.ts.map +1 -1
- package/dist/transport/stdio.js +14 -29
- package/dist/transport/stdio.js.map +1 -1
- package/dist/transport/worker.d.ts +22 -0
- package/dist/transport/worker.d.ts.map +1 -0
- package/dist/transport/worker.js +85 -0
- package/dist/transport/worker.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,14 +1,101 @@
|
|
|
1
|
+
// packages/core/src/agent/instance-manager.ts
|
|
2
|
+
import { isDeepStrictEqual } from "node:util";
|
|
3
|
+
|
|
4
|
+
// packages/core/src/agent/schema-registry.ts
|
|
5
|
+
class SchemaRegistry {
|
|
6
|
+
schemas = new Map;
|
|
7
|
+
register(schema) {
|
|
8
|
+
this.schemas.set(this.getKey(schema.schemaName, schema.schemaIdentifier), schema);
|
|
9
|
+
}
|
|
10
|
+
has(schemaName, schemaIdentifier) {
|
|
11
|
+
return this.schemas.has(this.getKey(schemaName, schemaIdentifier));
|
|
12
|
+
}
|
|
13
|
+
get(schemaName, schemaIdentifier) {
|
|
14
|
+
return this.schemas.get(this.getKey(schemaName, schemaIdentifier));
|
|
15
|
+
}
|
|
16
|
+
getKey(schemaName, schemaIdentifier) {
|
|
17
|
+
return `${schemaName}@${schemaIdentifier}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// packages/core/src/agent/instance-manager.ts
|
|
22
|
+
var orderInsensitiveArrayKeys = new Set(["required", "enum", "oneOf", "allOf", "anyOf", "type"]);
|
|
23
|
+
var stableStringify = (value) => JSON.stringify(value) ?? "undefined";
|
|
24
|
+
var normalizeSchema = (value, arrayKey) => {
|
|
25
|
+
if (Array.isArray(value)) {
|
|
26
|
+
const normalizedItems = value.map((item) => normalizeSchema(item));
|
|
27
|
+
if (arrayKey && orderInsensitiveArrayKeys.has(arrayKey)) {
|
|
28
|
+
return normalizedItems.map((item) => ({ item, key: stableStringify(item) })).sort((left, right) => left.key.localeCompare(right.key)).map(({ item }) => item);
|
|
29
|
+
}
|
|
30
|
+
return normalizedItems;
|
|
31
|
+
}
|
|
32
|
+
if (value && typeof value === "object") {
|
|
33
|
+
const proto = Object.getPrototypeOf(value);
|
|
34
|
+
if (proto === Object.prototype || proto === null) {
|
|
35
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
36
|
+
const normalized = {};
|
|
37
|
+
for (const [key, entryValue] of entries) {
|
|
38
|
+
normalized[key] = normalizeSchema(entryValue, key);
|
|
39
|
+
}
|
|
40
|
+
return normalized;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return value;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
class AgentInstanceManager {
|
|
47
|
+
queue;
|
|
48
|
+
options;
|
|
49
|
+
schemaRegistry = new SchemaRegistry;
|
|
50
|
+
constructor(queue, options) {
|
|
51
|
+
this.queue = queue;
|
|
52
|
+
this.options = options;
|
|
53
|
+
}
|
|
54
|
+
registerSchema(schema) {
|
|
55
|
+
if (this.schemaRegistry.has(this.options.schemaName, this.options.schemaIdentifier)) {
|
|
56
|
+
const existing = this.schemaRegistry.get(this.options.schemaName, this.options.schemaIdentifier);
|
|
57
|
+
if (existing && !isDeepStrictEqual(normalizeSchema(existing.schema), normalizeSchema(schema))) {
|
|
58
|
+
console.warn(`Schema ${this.options.schemaName}@${this.options.schemaIdentifier} is already registered with a different payload. Ignoring registration.`);
|
|
59
|
+
}
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const registration = {
|
|
63
|
+
schemaName: this.options.schemaName,
|
|
64
|
+
schemaIdentifier: this.options.schemaIdentifier,
|
|
65
|
+
schema
|
|
66
|
+
};
|
|
67
|
+
this.schemaRegistry.register(registration);
|
|
68
|
+
this.queue.enqueue({ type: "schema_register", data: registration });
|
|
69
|
+
}
|
|
70
|
+
startInstance(options = {}) {
|
|
71
|
+
if (!this.options.allowUnregisteredSchema && !this.schemaRegistry.has(this.options.schemaName, this.options.schemaIdentifier)) {
|
|
72
|
+
console.warn(`Schema ${this.options.schemaName}@${this.options.schemaIdentifier} must be registered before starting an agent instance.`);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const startData = {
|
|
76
|
+
...options,
|
|
77
|
+
schemaName: this.options.schemaName,
|
|
78
|
+
schemaIdentifier: this.options.schemaIdentifier
|
|
79
|
+
};
|
|
80
|
+
this.queue.enqueue({ type: "agent_start", data: startData });
|
|
81
|
+
}
|
|
82
|
+
finishInstance() {
|
|
83
|
+
this.queue.enqueue({ type: "agent_finish", data: {} });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
1
86
|
// packages/core/src/config.ts
|
|
2
87
|
import { z } from "zod";
|
|
3
88
|
var HttpTransportConfigSchema = z.object({
|
|
4
89
|
apiUrl: z.string().url(),
|
|
5
90
|
apiToken: z.string().min(1),
|
|
6
91
|
agentId: z.string().optional(),
|
|
7
|
-
|
|
92
|
+
agentIdentifier: z.string().default("v1.0.0"),
|
|
8
93
|
agentName: z.string().optional(),
|
|
9
94
|
agentDescription: z.string().optional(),
|
|
95
|
+
schemaName: z.string().optional(),
|
|
96
|
+
schemaIdentifier: z.string().optional(),
|
|
10
97
|
agentSchema: z.record(z.unknown()).optional(),
|
|
11
|
-
|
|
98
|
+
agentSchemaIdentifier: z.string().optional(),
|
|
12
99
|
skipSchema: z.boolean().default(false),
|
|
13
100
|
requestTimeout: z.number().positive().default(30000),
|
|
14
101
|
connectTimeout: z.number().positive().default(1e4),
|
|
@@ -21,11 +108,13 @@ var PartialHttpConfigSchema = z.object({
|
|
|
21
108
|
apiUrl: z.string().url(),
|
|
22
109
|
apiToken: z.string().min(1),
|
|
23
110
|
agentId: z.string().optional(),
|
|
24
|
-
|
|
111
|
+
agentIdentifier: z.string().optional(),
|
|
25
112
|
agentName: z.string().optional(),
|
|
26
113
|
agentDescription: z.string().optional(),
|
|
114
|
+
schemaName: z.string().optional(),
|
|
115
|
+
schemaIdentifier: z.string().optional(),
|
|
27
116
|
agentSchema: z.record(z.unknown()).optional(),
|
|
28
|
-
|
|
117
|
+
agentSchemaIdentifier: z.string().optional(),
|
|
29
118
|
skipSchema: z.boolean().optional(),
|
|
30
119
|
requestTimeout: z.number().positive().optional(),
|
|
31
120
|
connectTimeout: z.number().positive().optional(),
|
|
@@ -55,24 +144,75 @@ function createConfig(options) {
|
|
|
55
144
|
};
|
|
56
145
|
return ConfigSchema.parse(config);
|
|
57
146
|
}
|
|
147
|
+
// packages/core/src/create-core.ts
|
|
148
|
+
import { extractPartition } from "@prefactor/pfid";
|
|
149
|
+
|
|
150
|
+
// packages/core/src/queue/in-memory.ts
|
|
151
|
+
class InMemoryQueue {
|
|
152
|
+
items = [];
|
|
153
|
+
enqueue(item) {
|
|
154
|
+
this.items.push(item);
|
|
155
|
+
}
|
|
156
|
+
dequeueBatch(maxItems) {
|
|
157
|
+
if (this.items.length === 0)
|
|
158
|
+
return [];
|
|
159
|
+
return this.items.splice(0, maxItems);
|
|
160
|
+
}
|
|
161
|
+
size() {
|
|
162
|
+
return this.items.length;
|
|
163
|
+
}
|
|
164
|
+
async flush() {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// packages/core/src/tracing/tracer.ts
|
|
170
|
+
import { generate, generatePartition } from "@prefactor/pfid";
|
|
171
|
+
|
|
58
172
|
// packages/core/src/tracing/context.ts
|
|
59
|
-
import { AsyncLocalStorage } from "node:async_hooks";
|
|
173
|
+
import { AsyncLocalStorage, AsyncResource } from "node:async_hooks";
|
|
60
174
|
var spanStorage = new AsyncLocalStorage;
|
|
61
175
|
|
|
62
176
|
class SpanContext {
|
|
63
177
|
static getCurrent() {
|
|
64
|
-
|
|
178
|
+
const stack = spanStorage.getStore() ?? [];
|
|
179
|
+
return stack[stack.length - 1];
|
|
180
|
+
}
|
|
181
|
+
static getStack() {
|
|
182
|
+
return [...spanStorage.getStore() ?? []];
|
|
183
|
+
}
|
|
184
|
+
static enter(span) {
|
|
185
|
+
const stack = [...spanStorage.getStore() ?? [], span];
|
|
186
|
+
spanStorage.enterWith(stack);
|
|
187
|
+
}
|
|
188
|
+
static exit() {
|
|
189
|
+
const stack = [...spanStorage.getStore() ?? []];
|
|
190
|
+
stack.pop();
|
|
191
|
+
spanStorage.enterWith(stack);
|
|
65
192
|
}
|
|
66
193
|
static run(span, fn) {
|
|
67
|
-
|
|
194
|
+
const stack = spanStorage.getStore() ?? [];
|
|
195
|
+
const resource = new AsyncResource("SpanContext.run");
|
|
196
|
+
try {
|
|
197
|
+
return resource.runInAsyncScope(() => spanStorage.run([...stack, span], fn));
|
|
198
|
+
} finally {
|
|
199
|
+
resource.emitDestroy();
|
|
200
|
+
}
|
|
68
201
|
}
|
|
69
202
|
static async runAsync(span, fn) {
|
|
70
|
-
|
|
203
|
+
const stack = spanStorage.getStore() ?? [];
|
|
204
|
+
const resource = new AsyncResource("SpanContext.runAsync");
|
|
205
|
+
try {
|
|
206
|
+
return await resource.runInAsyncScope(() => spanStorage.run([...stack, span], fn));
|
|
207
|
+
} finally {
|
|
208
|
+
resource.emitDestroy();
|
|
209
|
+
}
|
|
71
210
|
}
|
|
72
211
|
static clear() {
|
|
73
212
|
spanStorage.disable();
|
|
74
213
|
}
|
|
75
214
|
}
|
|
215
|
+
|
|
76
216
|
// packages/core/src/tracing/span.ts
|
|
77
217
|
var SpanType;
|
|
78
218
|
((SpanType2) => {
|
|
@@ -82,27 +222,53 @@ var SpanType;
|
|
|
82
222
|
SpanType2["CHAIN"] = "chain";
|
|
83
223
|
SpanType2["RETRIEVER"] = "retriever";
|
|
84
224
|
})(SpanType ||= {});
|
|
225
|
+
var DEFAULT_AGENT_SCHEMA = {
|
|
226
|
+
external_identifier: "1.0.0",
|
|
227
|
+
span_schemas: {
|
|
228
|
+
agent: {
|
|
229
|
+
type: "object",
|
|
230
|
+
properties: { type: { type: "string", const: "agent" } }
|
|
231
|
+
},
|
|
232
|
+
llm: {
|
|
233
|
+
type: "object",
|
|
234
|
+
properties: { type: { type: "string", const: "llm" } }
|
|
235
|
+
},
|
|
236
|
+
tool: {
|
|
237
|
+
type: "object",
|
|
238
|
+
properties: { type: { type: "string", const: "tool" } }
|
|
239
|
+
},
|
|
240
|
+
chain: {
|
|
241
|
+
type: "object",
|
|
242
|
+
properties: { type: { type: "string", const: "chain" } }
|
|
243
|
+
},
|
|
244
|
+
retriever: {
|
|
245
|
+
type: "object",
|
|
246
|
+
properties: { type: { type: "string", const: "retriever" } }
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
};
|
|
85
250
|
var SpanStatus;
|
|
86
251
|
((SpanStatus2) => {
|
|
87
252
|
SpanStatus2["RUNNING"] = "running";
|
|
88
253
|
SpanStatus2["SUCCESS"] = "success";
|
|
89
254
|
SpanStatus2["ERROR"] = "error";
|
|
90
255
|
})(SpanStatus ||= {});
|
|
256
|
+
|
|
91
257
|
// packages/core/src/tracing/tracer.ts
|
|
92
|
-
import { generate, generatePartition } from "@prefactor/pfid";
|
|
93
258
|
class Tracer {
|
|
94
|
-
|
|
259
|
+
queue;
|
|
95
260
|
partition;
|
|
96
|
-
constructor(
|
|
97
|
-
this.
|
|
261
|
+
constructor(queue, partition) {
|
|
262
|
+
this.queue = queue;
|
|
98
263
|
this.partition = partition ?? generatePartition();
|
|
99
264
|
}
|
|
100
265
|
startSpan(options) {
|
|
266
|
+
const parentSpan = SpanContext.getCurrent();
|
|
101
267
|
const spanId = generate(this.partition);
|
|
102
|
-
const traceId =
|
|
268
|
+
const traceId = parentSpan?.traceId ?? generate(this.partition);
|
|
103
269
|
const span = {
|
|
104
270
|
spanId,
|
|
105
|
-
parentSpanId:
|
|
271
|
+
parentSpanId: parentSpan?.spanId ?? null,
|
|
106
272
|
traceId,
|
|
107
273
|
name: options.name,
|
|
108
274
|
spanType: options.spanType,
|
|
@@ -116,17 +282,18 @@ class Tracer {
|
|
|
116
282
|
metadata: options.metadata ?? {},
|
|
117
283
|
tags: options.tags ?? []
|
|
118
284
|
};
|
|
119
|
-
if (options.spanType === "agent") {
|
|
285
|
+
if (options.spanType === "agent" /* AGENT */) {
|
|
120
286
|
try {
|
|
121
|
-
this.
|
|
287
|
+
this.queue.enqueue({ type: "span_end", data: span });
|
|
122
288
|
} catch (error) {
|
|
123
|
-
console.error("Failed to
|
|
289
|
+
console.error("Failed to enqueue agent span:", error);
|
|
124
290
|
}
|
|
125
291
|
}
|
|
126
292
|
return span;
|
|
127
293
|
}
|
|
128
294
|
endSpan(span, options) {
|
|
129
|
-
|
|
295
|
+
const endTime = Date.now();
|
|
296
|
+
span.endTime = endTime;
|
|
130
297
|
span.outputs = options?.outputs ?? null;
|
|
131
298
|
span.tokenUsage = options?.tokenUsage ?? null;
|
|
132
299
|
if (options?.error) {
|
|
@@ -140,37 +307,24 @@ class Tracer {
|
|
|
140
307
|
span.status = "success" /* SUCCESS */;
|
|
141
308
|
}
|
|
142
309
|
try {
|
|
143
|
-
if (span.spanType === "agent") {
|
|
144
|
-
this.
|
|
310
|
+
if (span.spanType === "agent" /* AGENT */) {
|
|
311
|
+
this.queue.enqueue({ type: "span_finish", data: { spanId: span.spanId, endTime } });
|
|
145
312
|
} else {
|
|
146
|
-
this.
|
|
313
|
+
this.queue.enqueue({ type: "span_end", data: span });
|
|
147
314
|
}
|
|
148
315
|
} catch (error) {
|
|
149
|
-
console.error("Failed to
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
startAgentInstance() {
|
|
153
|
-
try {
|
|
154
|
-
this.transport.startAgentInstance();
|
|
155
|
-
} catch (error) {
|
|
156
|
-
console.error("Failed to start agent instance:", error);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
finishAgentInstance() {
|
|
160
|
-
try {
|
|
161
|
-
this.transport.finishAgentInstance();
|
|
162
|
-
} catch (error) {
|
|
163
|
-
console.error("Failed to finish agent instance:", error);
|
|
316
|
+
console.error("Failed to enqueue span action:", error);
|
|
164
317
|
}
|
|
165
318
|
}
|
|
166
319
|
async close() {
|
|
167
320
|
try {
|
|
168
|
-
await this.
|
|
321
|
+
await this.queue.flush();
|
|
169
322
|
} catch (error) {
|
|
170
|
-
console.error("Failed to
|
|
323
|
+
console.error("Failed to flush queue:", error);
|
|
171
324
|
}
|
|
172
325
|
}
|
|
173
326
|
}
|
|
327
|
+
|
|
174
328
|
// packages/core/src/utils/logging.ts
|
|
175
329
|
class Logger {
|
|
176
330
|
namespace;
|
|
@@ -223,73 +377,76 @@ var logger = getLogger("http-transport");
|
|
|
223
377
|
|
|
224
378
|
class HttpTransport {
|
|
225
379
|
config;
|
|
226
|
-
queue = [];
|
|
227
|
-
processing = false;
|
|
228
380
|
closed = false;
|
|
229
381
|
agentInstanceId = null;
|
|
230
382
|
spanIdMap = new Map;
|
|
383
|
+
pendingFinishes = new Map;
|
|
231
384
|
constructor(config) {
|
|
232
385
|
this.config = config;
|
|
233
|
-
this.startProcessing();
|
|
234
|
-
}
|
|
235
|
-
emit(span) {
|
|
236
|
-
if (this.closed) {
|
|
237
|
-
return;
|
|
238
|
-
}
|
|
239
|
-
this.queue.push({ type: "span", data: span });
|
|
240
|
-
}
|
|
241
|
-
finishSpan(spanId, endTime) {
|
|
242
|
-
if (this.closed) {
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
const timestamp = new Date(endTime).toISOString();
|
|
246
|
-
this.queue.push({ type: "finish_span", data: { spanId, timestamp } });
|
|
247
|
-
}
|
|
248
|
-
startAgentInstance() {
|
|
249
|
-
if (this.closed) {
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
this.queue.push({ type: "start_agent", data: null });
|
|
253
386
|
}
|
|
254
|
-
|
|
255
|
-
if (this.closed) {
|
|
387
|
+
async processBatch(items) {
|
|
388
|
+
if (this.closed || items.length === 0) {
|
|
256
389
|
return;
|
|
257
390
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
265
|
-
continue;
|
|
391
|
+
for (const item of items) {
|
|
392
|
+
if (item.type === "schema_register") {
|
|
393
|
+
this.config.agentSchema = item.data.schema;
|
|
394
|
+
this.config.agentSchemaIdentifier = item.data.schemaIdentifier;
|
|
395
|
+
this.config.schemaName = item.data.schemaName;
|
|
396
|
+
this.config.schemaIdentifier = item.data.schemaIdentifier;
|
|
266
397
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
continue;
|
|
398
|
+
}
|
|
399
|
+
for (const item of items) {
|
|
270
400
|
try {
|
|
271
|
-
if (!this.agentInstanceId && item.type !== "start_agent") {
|
|
272
|
-
await this.ensureAgentRegistered();
|
|
273
|
-
}
|
|
274
401
|
switch (item.type) {
|
|
275
|
-
case "
|
|
276
|
-
await this.sendSpan(item.data);
|
|
277
|
-
break;
|
|
278
|
-
case "finish_span":
|
|
279
|
-
await this.finishSpanHttp(item.data);
|
|
402
|
+
case "schema_register":
|
|
280
403
|
break;
|
|
281
|
-
case "
|
|
404
|
+
case "agent_start":
|
|
405
|
+
this.config.agentId = item.data.agentId;
|
|
406
|
+
if (item.data.agentIdentifier !== undefined)
|
|
407
|
+
this.config.agentIdentifier = item.data.agentIdentifier;
|
|
408
|
+
this.config.agentName = item.data.agentName;
|
|
409
|
+
this.config.agentDescription = item.data.agentDescription;
|
|
282
410
|
await this.startAgentInstanceHttp();
|
|
283
411
|
break;
|
|
284
|
-
case "
|
|
412
|
+
case "agent_finish":
|
|
285
413
|
await this.finishAgentInstanceHttp();
|
|
286
414
|
break;
|
|
415
|
+
case "span_end":
|
|
416
|
+
if (!this.agentInstanceId) {
|
|
417
|
+
await this.ensureAgentRegistered();
|
|
418
|
+
}
|
|
419
|
+
await this.sendSpan(item.data);
|
|
420
|
+
break;
|
|
421
|
+
case "span_finish": {
|
|
422
|
+
const spanId = item.data.spanId;
|
|
423
|
+
const backendSpanId = this.spanIdMap.get(spanId);
|
|
424
|
+
if (backendSpanId) {
|
|
425
|
+
const timestamp = new Date(item.data.endTime).toISOString();
|
|
426
|
+
await this.finishSpanHttp({ spanId, timestamp });
|
|
427
|
+
} else {
|
|
428
|
+
this.pendingFinishes.set(spanId, item.data.endTime);
|
|
429
|
+
}
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
287
432
|
}
|
|
288
433
|
} catch (error) {
|
|
289
|
-
logger.error("Error processing
|
|
434
|
+
logger.error("Error processing batch item:", error);
|
|
290
435
|
}
|
|
291
436
|
}
|
|
292
|
-
|
|
437
|
+
}
|
|
438
|
+
async processPendingFinishes(spanId) {
|
|
439
|
+
const pendingEndTime = this.pendingFinishes.get(spanId);
|
|
440
|
+
if (!pendingEndTime) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
try {
|
|
444
|
+
const timestamp = new Date(pendingEndTime).toISOString();
|
|
445
|
+
await this.finishSpanHttp({ spanId, timestamp });
|
|
446
|
+
this.pendingFinishes.delete(spanId);
|
|
447
|
+
} catch (error) {
|
|
448
|
+
logger.error("Error processing pending span finish:", error);
|
|
449
|
+
}
|
|
293
450
|
}
|
|
294
451
|
async sendSpan(span, retry = 0) {
|
|
295
452
|
const url = `${this.config.apiUrl}/api/v1/agent_spans`;
|
|
@@ -309,6 +466,7 @@ class HttpTransport {
|
|
|
309
466
|
const backendSpanId = data?.details?.id;
|
|
310
467
|
if (backendSpanId) {
|
|
311
468
|
this.spanIdMap.set(span.spanId, backendSpanId);
|
|
469
|
+
await this.processPendingFinishes(span.spanId);
|
|
312
470
|
}
|
|
313
471
|
return;
|
|
314
472
|
}
|
|
@@ -370,31 +528,7 @@ class HttpTransport {
|
|
|
370
528
|
};
|
|
371
529
|
}
|
|
372
530
|
getDefaultSchema() {
|
|
373
|
-
return
|
|
374
|
-
external_identifier: "1.0.0",
|
|
375
|
-
span_schemas: {
|
|
376
|
-
agent: {
|
|
377
|
-
type: "object",
|
|
378
|
-
properties: { type: { type: "string", const: "agent" } }
|
|
379
|
-
},
|
|
380
|
-
llm: {
|
|
381
|
-
type: "object",
|
|
382
|
-
properties: { type: { type: "string", const: "llm" } }
|
|
383
|
-
},
|
|
384
|
-
tool: {
|
|
385
|
-
type: "object",
|
|
386
|
-
properties: { type: { type: "string", const: "tool" } }
|
|
387
|
-
},
|
|
388
|
-
chain: {
|
|
389
|
-
type: "object",
|
|
390
|
-
properties: { type: { type: "string", const: "chain" } }
|
|
391
|
-
},
|
|
392
|
-
retriever: {
|
|
393
|
-
type: "object",
|
|
394
|
-
properties: { type: { type: "string", const: "retriever" } }
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
};
|
|
531
|
+
return DEFAULT_AGENT_SCHEMA;
|
|
398
532
|
}
|
|
399
533
|
async ensureAgentRegistered() {
|
|
400
534
|
if (this.agentInstanceId) {
|
|
@@ -404,9 +538,9 @@ class HttpTransport {
|
|
|
404
538
|
const payload = {};
|
|
405
539
|
if (this.config.agentId)
|
|
406
540
|
payload.agent_id = this.config.agentId;
|
|
407
|
-
if (this.config.
|
|
541
|
+
if (this.config.agentIdentifier) {
|
|
408
542
|
payload.agent_version = {
|
|
409
|
-
external_identifier: this.config.
|
|
543
|
+
external_identifier: this.config.agentIdentifier,
|
|
410
544
|
name: this.config.agentName || "Agent",
|
|
411
545
|
description: this.config.agentDescription || ""
|
|
412
546
|
};
|
|
@@ -416,10 +550,10 @@ class HttpTransport {
|
|
|
416
550
|
} else if (this.config.agentSchema) {
|
|
417
551
|
logger.debug("Using custom agent schema");
|
|
418
552
|
payload.agent_schema_version = this.config.agentSchema;
|
|
419
|
-
} else if (this.config.
|
|
420
|
-
logger.debug(`Using schema version: ${this.config.
|
|
553
|
+
} else if (this.config.agentSchemaIdentifier) {
|
|
554
|
+
logger.debug(`Using schema version: ${this.config.agentSchemaIdentifier}`);
|
|
421
555
|
payload.agent_schema_version = {
|
|
422
|
-
external_identifier: this.config.
|
|
556
|
+
external_identifier: this.config.agentSchemaIdentifier
|
|
423
557
|
};
|
|
424
558
|
} else {
|
|
425
559
|
logger.debug("Using default hardcoded schema (v1.0.0)");
|
|
@@ -492,6 +626,7 @@ class HttpTransport {
|
|
|
492
626
|
} catch (error) {
|
|
493
627
|
logger.error("Error finishing agent instance:", error);
|
|
494
628
|
}
|
|
629
|
+
this.agentInstanceId = null;
|
|
495
630
|
}
|
|
496
631
|
async finishSpanHttp(data) {
|
|
497
632
|
const backendSpanId = this.spanIdMap.get(data.spanId);
|
|
@@ -519,16 +654,13 @@ class HttpTransport {
|
|
|
519
654
|
}
|
|
520
655
|
async close() {
|
|
521
656
|
this.closed = true;
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
526
|
-
}
|
|
527
|
-
if (this.processing) {
|
|
528
|
-
logger.warn("Transport closed with pending queue items");
|
|
657
|
+
if (this.pendingFinishes.size > 0) {
|
|
658
|
+
logger.warn(`Transport closed with ${this.pendingFinishes.size} pending span finish(es) that could not be processed`);
|
|
659
|
+
this.pendingFinishes.clear();
|
|
529
660
|
}
|
|
530
661
|
}
|
|
531
662
|
}
|
|
663
|
+
|
|
532
664
|
// packages/core/src/utils/serialization.ts
|
|
533
665
|
function truncateString(value, maxLength) {
|
|
534
666
|
if (value.length <= maxLength) {
|
|
@@ -567,33 +699,153 @@ function serializeValue(value, maxLength = 1e4) {
|
|
|
567
699
|
class StdioTransport {
|
|
568
700
|
closed = false;
|
|
569
701
|
writeLock = Promise.resolve();
|
|
570
|
-
|
|
571
|
-
if (this.closed) {
|
|
702
|
+
async processBatch(items) {
|
|
703
|
+
if (this.closed || items.length === 0) {
|
|
572
704
|
return;
|
|
573
705
|
}
|
|
574
706
|
this.writeLock = this.writeLock.then(async () => {
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
707
|
+
for (const item of items) {
|
|
708
|
+
try {
|
|
709
|
+
const serialized = serializeValue(item);
|
|
710
|
+
const json = JSON.stringify(serialized);
|
|
711
|
+
await Bun.write(Bun.stdout, `${json}
|
|
579
712
|
`);
|
|
580
|
-
|
|
581
|
-
|
|
713
|
+
} catch (error) {
|
|
714
|
+
console.error("Failed to emit queue action to stdout:", error);
|
|
715
|
+
}
|
|
582
716
|
}
|
|
583
717
|
});
|
|
718
|
+
await this.writeLock;
|
|
584
719
|
}
|
|
585
|
-
finishSpan() {}
|
|
586
|
-
startAgentInstance() {}
|
|
587
|
-
finishAgentInstance() {}
|
|
588
720
|
async close() {
|
|
589
721
|
this.closed = true;
|
|
590
722
|
await this.writeLock;
|
|
591
723
|
}
|
|
592
724
|
}
|
|
725
|
+
|
|
726
|
+
// packages/core/src/transport/worker.ts
|
|
727
|
+
class TransportWorker {
|
|
728
|
+
queue;
|
|
729
|
+
transport;
|
|
730
|
+
config;
|
|
731
|
+
closed = false;
|
|
732
|
+
inFlightPromise = null;
|
|
733
|
+
loopPromise;
|
|
734
|
+
pendingBatch = null;
|
|
735
|
+
constructor(queue, transport, config) {
|
|
736
|
+
this.queue = queue;
|
|
737
|
+
this.transport = transport;
|
|
738
|
+
this.config = config;
|
|
739
|
+
this.loopPromise = this.start();
|
|
740
|
+
}
|
|
741
|
+
async start() {
|
|
742
|
+
while (!this.closed || this.pendingBatch || this.queue.size() > 0 || this.inFlightPromise) {
|
|
743
|
+
const batch = this.pendingBatch ?? this.queue.dequeueBatch(this.config.batchSize);
|
|
744
|
+
if (batch.length === 0) {
|
|
745
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.intervalMs));
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
try {
|
|
749
|
+
const inFlight = this.transport.processBatch(batch);
|
|
750
|
+
this.inFlightPromise = inFlight;
|
|
751
|
+
await inFlight;
|
|
752
|
+
this.pendingBatch = null;
|
|
753
|
+
} catch (error) {
|
|
754
|
+
this.pendingBatch = batch;
|
|
755
|
+
console.error("TransportWorker.processBatch failed", error);
|
|
756
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.intervalMs));
|
|
757
|
+
} finally {
|
|
758
|
+
this.inFlightPromise = null;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
async flush(timeoutMs) {
|
|
763
|
+
const start = Date.now();
|
|
764
|
+
while ((this.queue.size() > 0 || this.pendingBatch || this.inFlightPromise) && Date.now() - start < timeoutMs) {
|
|
765
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.intervalMs));
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
async close(timeoutMs = this.config.intervalMs * 50) {
|
|
769
|
+
this.closed = true;
|
|
770
|
+
const deadline = Date.now() + timeoutMs;
|
|
771
|
+
const awaitWithTimeout = async (promise, label, timeoutMs2, warnOnTimeout = true) => {
|
|
772
|
+
if (timeoutMs2 <= 0) {
|
|
773
|
+
if (warnOnTimeout) {
|
|
774
|
+
console.warn(`TransportWorker.close timed out waiting for ${label}`);
|
|
775
|
+
}
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
const resolvedPromise = Promise.resolve(promise);
|
|
779
|
+
let timeoutId = null;
|
|
780
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
781
|
+
timeoutId = setTimeout(() => resolve(false), timeoutMs2);
|
|
782
|
+
});
|
|
783
|
+
const completed = await Promise.race([resolvedPromise.then(() => true), timeoutPromise]);
|
|
784
|
+
if (timeoutId) {
|
|
785
|
+
clearTimeout(timeoutId);
|
|
786
|
+
}
|
|
787
|
+
if (!completed && warnOnTimeout) {
|
|
788
|
+
console.warn(`TransportWorker.close timed out waiting for ${label}`);
|
|
789
|
+
}
|
|
790
|
+
return completed;
|
|
791
|
+
};
|
|
792
|
+
const remainingTime = () => Math.max(0, deadline - Date.now());
|
|
793
|
+
const loopCompleted = await awaitWithTimeout(this.loopPromise, "loop to finish", remainingTime(), false);
|
|
794
|
+
if (!loopCompleted) {
|
|
795
|
+
console.warn("TransportWorker.close timed out waiting for loop to finish; closing transport now may cause potential data loss");
|
|
796
|
+
}
|
|
797
|
+
const safeTransportClose = async () => {
|
|
798
|
+
try {
|
|
799
|
+
await this.transport.close();
|
|
800
|
+
} catch (error) {
|
|
801
|
+
console.error("TransportWorker.close failed", error);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
await awaitWithTimeout(safeTransportClose(), "transport to close", remainingTime());
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// packages/core/src/create-core.ts
|
|
809
|
+
function createCore(config) {
|
|
810
|
+
let transport;
|
|
811
|
+
if (config.transportType === "stdio") {
|
|
812
|
+
transport = new StdioTransport;
|
|
813
|
+
} else {
|
|
814
|
+
if (!config.httpConfig) {
|
|
815
|
+
throw new Error("HTTP transport requires httpConfig to be provided in configuration");
|
|
816
|
+
}
|
|
817
|
+
const httpConfig = HttpTransportConfigSchema.parse(config.httpConfig);
|
|
818
|
+
transport = new HttpTransport(httpConfig);
|
|
819
|
+
}
|
|
820
|
+
let partition;
|
|
821
|
+
if (config.httpConfig?.agentId) {
|
|
822
|
+
try {
|
|
823
|
+
partition = extractPartition(config.httpConfig.agentId);
|
|
824
|
+
} catch {
|
|
825
|
+
partition = undefined;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
const queue = new InMemoryQueue;
|
|
829
|
+
const worker = new TransportWorker(queue, transport, { batchSize: 25, intervalMs: 50 });
|
|
830
|
+
const tracer = new Tracer(queue, partition);
|
|
831
|
+
const schemaName = config.httpConfig?.schemaName ?? "prefactor:agent";
|
|
832
|
+
const schemaIdentifier = config.httpConfig?.schemaIdentifier ?? "1.0.0";
|
|
833
|
+
const allowUnregisteredSchema = config.transportType === "http" && Boolean(config.httpConfig?.skipSchema || config.httpConfig?.agentSchema || config.httpConfig?.agentSchemaIdentifier);
|
|
834
|
+
const agentManager = new AgentInstanceManager(queue, {
|
|
835
|
+
schemaName,
|
|
836
|
+
schemaIdentifier,
|
|
837
|
+
allowUnregisteredSchema
|
|
838
|
+
});
|
|
839
|
+
const shutdown = async () => {
|
|
840
|
+
await worker.close();
|
|
841
|
+
};
|
|
842
|
+
return { tracer, agentManager, worker, shutdown };
|
|
843
|
+
}
|
|
593
844
|
export {
|
|
594
845
|
truncateString,
|
|
595
846
|
serializeValue,
|
|
596
847
|
getLogger,
|
|
848
|
+
createCore,
|
|
597
849
|
createConfig,
|
|
598
850
|
configureLogging,
|
|
599
851
|
Tracer,
|
|
@@ -601,10 +853,14 @@ export {
|
|
|
601
853
|
SpanType,
|
|
602
854
|
SpanStatus,
|
|
603
855
|
SpanContext,
|
|
856
|
+
SchemaRegistry,
|
|
604
857
|
PartialHttpConfigSchema,
|
|
858
|
+
InMemoryQueue,
|
|
605
859
|
HttpTransportConfigSchema,
|
|
606
860
|
HttpTransport,
|
|
607
|
-
|
|
861
|
+
DEFAULT_AGENT_SCHEMA,
|
|
862
|
+
ConfigSchema,
|
|
863
|
+
AgentInstanceManager
|
|
608
864
|
};
|
|
609
865
|
|
|
610
|
-
//# debugId=
|
|
866
|
+
//# debugId=AE4689D591D1DB9C64756E2164756E21
|