@prefactor/core 0.1.1 → 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 +35 -2
- 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.cjs
CHANGED
|
@@ -32,6 +32,7 @@ __export(exports_src, {
|
|
|
32
32
|
truncateString: () => truncateString,
|
|
33
33
|
serializeValue: () => serializeValue,
|
|
34
34
|
getLogger: () => getLogger,
|
|
35
|
+
createCore: () => createCore,
|
|
35
36
|
createConfig: () => createConfig,
|
|
36
37
|
configureLogging: () => configureLogging,
|
|
37
38
|
Tracer: () => Tracer,
|
|
@@ -39,24 +40,115 @@ __export(exports_src, {
|
|
|
39
40
|
SpanType: () => SpanType,
|
|
40
41
|
SpanStatus: () => SpanStatus,
|
|
41
42
|
SpanContext: () => SpanContext,
|
|
43
|
+
SchemaRegistry: () => SchemaRegistry,
|
|
42
44
|
PartialHttpConfigSchema: () => PartialHttpConfigSchema,
|
|
45
|
+
InMemoryQueue: () => InMemoryQueue,
|
|
43
46
|
HttpTransportConfigSchema: () => HttpTransportConfigSchema,
|
|
44
47
|
HttpTransport: () => HttpTransport,
|
|
45
|
-
|
|
48
|
+
DEFAULT_AGENT_SCHEMA: () => DEFAULT_AGENT_SCHEMA,
|
|
49
|
+
ConfigSchema: () => ConfigSchema,
|
|
50
|
+
AgentInstanceManager: () => AgentInstanceManager
|
|
46
51
|
});
|
|
47
52
|
module.exports = __toCommonJS(exports_src);
|
|
48
53
|
|
|
54
|
+
// packages/core/src/agent/instance-manager.ts
|
|
55
|
+
var import_node_util = require("node:util");
|
|
56
|
+
|
|
57
|
+
// packages/core/src/agent/schema-registry.ts
|
|
58
|
+
class SchemaRegistry {
|
|
59
|
+
schemas = new Map;
|
|
60
|
+
register(schema) {
|
|
61
|
+
this.schemas.set(this.getKey(schema.schemaName, schema.schemaIdentifier), schema);
|
|
62
|
+
}
|
|
63
|
+
has(schemaName, schemaIdentifier) {
|
|
64
|
+
return this.schemas.has(this.getKey(schemaName, schemaIdentifier));
|
|
65
|
+
}
|
|
66
|
+
get(schemaName, schemaIdentifier) {
|
|
67
|
+
return this.schemas.get(this.getKey(schemaName, schemaIdentifier));
|
|
68
|
+
}
|
|
69
|
+
getKey(schemaName, schemaIdentifier) {
|
|
70
|
+
return `${schemaName}@${schemaIdentifier}`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// packages/core/src/agent/instance-manager.ts
|
|
75
|
+
var orderInsensitiveArrayKeys = new Set(["required", "enum", "oneOf", "allOf", "anyOf", "type"]);
|
|
76
|
+
var stableStringify = (value) => JSON.stringify(value) ?? "undefined";
|
|
77
|
+
var normalizeSchema = (value, arrayKey) => {
|
|
78
|
+
if (Array.isArray(value)) {
|
|
79
|
+
const normalizedItems = value.map((item) => normalizeSchema(item));
|
|
80
|
+
if (arrayKey && orderInsensitiveArrayKeys.has(arrayKey)) {
|
|
81
|
+
return normalizedItems.map((item) => ({ item, key: stableStringify(item) })).sort((left, right) => left.key.localeCompare(right.key)).map(({ item }) => item);
|
|
82
|
+
}
|
|
83
|
+
return normalizedItems;
|
|
84
|
+
}
|
|
85
|
+
if (value && typeof value === "object") {
|
|
86
|
+
const proto = Object.getPrototypeOf(value);
|
|
87
|
+
if (proto === Object.prototype || proto === null) {
|
|
88
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
89
|
+
const normalized = {};
|
|
90
|
+
for (const [key, entryValue] of entries) {
|
|
91
|
+
normalized[key] = normalizeSchema(entryValue, key);
|
|
92
|
+
}
|
|
93
|
+
return normalized;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
class AgentInstanceManager {
|
|
100
|
+
queue;
|
|
101
|
+
options;
|
|
102
|
+
schemaRegistry = new SchemaRegistry;
|
|
103
|
+
constructor(queue, options) {
|
|
104
|
+
this.queue = queue;
|
|
105
|
+
this.options = options;
|
|
106
|
+
}
|
|
107
|
+
registerSchema(schema) {
|
|
108
|
+
if (this.schemaRegistry.has(this.options.schemaName, this.options.schemaIdentifier)) {
|
|
109
|
+
const existing = this.schemaRegistry.get(this.options.schemaName, this.options.schemaIdentifier);
|
|
110
|
+
if (existing && !import_node_util.isDeepStrictEqual(normalizeSchema(existing.schema), normalizeSchema(schema))) {
|
|
111
|
+
console.warn(`Schema ${this.options.schemaName}@${this.options.schemaIdentifier} is already registered with a different payload. Ignoring registration.`);
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const registration = {
|
|
116
|
+
schemaName: this.options.schemaName,
|
|
117
|
+
schemaIdentifier: this.options.schemaIdentifier,
|
|
118
|
+
schema
|
|
119
|
+
};
|
|
120
|
+
this.schemaRegistry.register(registration);
|
|
121
|
+
this.queue.enqueue({ type: "schema_register", data: registration });
|
|
122
|
+
}
|
|
123
|
+
startInstance(options = {}) {
|
|
124
|
+
if (!this.options.allowUnregisteredSchema && !this.schemaRegistry.has(this.options.schemaName, this.options.schemaIdentifier)) {
|
|
125
|
+
console.warn(`Schema ${this.options.schemaName}@${this.options.schemaIdentifier} must be registered before starting an agent instance.`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const startData = {
|
|
129
|
+
...options,
|
|
130
|
+
schemaName: this.options.schemaName,
|
|
131
|
+
schemaIdentifier: this.options.schemaIdentifier
|
|
132
|
+
};
|
|
133
|
+
this.queue.enqueue({ type: "agent_start", data: startData });
|
|
134
|
+
}
|
|
135
|
+
finishInstance() {
|
|
136
|
+
this.queue.enqueue({ type: "agent_finish", data: {} });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
49
139
|
// packages/core/src/config.ts
|
|
50
140
|
var import_zod = require("zod");
|
|
51
141
|
var HttpTransportConfigSchema = import_zod.z.object({
|
|
52
142
|
apiUrl: import_zod.z.string().url(),
|
|
53
143
|
apiToken: import_zod.z.string().min(1),
|
|
54
144
|
agentId: import_zod.z.string().optional(),
|
|
55
|
-
|
|
145
|
+
agentIdentifier: import_zod.z.string().default("v1.0.0"),
|
|
56
146
|
agentName: import_zod.z.string().optional(),
|
|
57
147
|
agentDescription: import_zod.z.string().optional(),
|
|
148
|
+
schemaName: import_zod.z.string().optional(),
|
|
149
|
+
schemaIdentifier: import_zod.z.string().optional(),
|
|
58
150
|
agentSchema: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
59
|
-
|
|
151
|
+
agentSchemaIdentifier: import_zod.z.string().optional(),
|
|
60
152
|
skipSchema: import_zod.z.boolean().default(false),
|
|
61
153
|
requestTimeout: import_zod.z.number().positive().default(30000),
|
|
62
154
|
connectTimeout: import_zod.z.number().positive().default(1e4),
|
|
@@ -69,11 +161,13 @@ var PartialHttpConfigSchema = import_zod.z.object({
|
|
|
69
161
|
apiUrl: import_zod.z.string().url(),
|
|
70
162
|
apiToken: import_zod.z.string().min(1),
|
|
71
163
|
agentId: import_zod.z.string().optional(),
|
|
72
|
-
|
|
164
|
+
agentIdentifier: import_zod.z.string().optional(),
|
|
73
165
|
agentName: import_zod.z.string().optional(),
|
|
74
166
|
agentDescription: import_zod.z.string().optional(),
|
|
167
|
+
schemaName: import_zod.z.string().optional(),
|
|
168
|
+
schemaIdentifier: import_zod.z.string().optional(),
|
|
75
169
|
agentSchema: import_zod.z.record(import_zod.z.unknown()).optional(),
|
|
76
|
-
|
|
170
|
+
agentSchemaIdentifier: import_zod.z.string().optional(),
|
|
77
171
|
skipSchema: import_zod.z.boolean().optional(),
|
|
78
172
|
requestTimeout: import_zod.z.number().positive().optional(),
|
|
79
173
|
connectTimeout: import_zod.z.number().positive().optional(),
|
|
@@ -103,24 +197,75 @@ function createConfig(options) {
|
|
|
103
197
|
};
|
|
104
198
|
return ConfigSchema.parse(config);
|
|
105
199
|
}
|
|
200
|
+
// packages/core/src/create-core.ts
|
|
201
|
+
var import_pfid2 = require("@prefactor/pfid");
|
|
202
|
+
|
|
203
|
+
// packages/core/src/queue/in-memory.ts
|
|
204
|
+
class InMemoryQueue {
|
|
205
|
+
items = [];
|
|
206
|
+
enqueue(item) {
|
|
207
|
+
this.items.push(item);
|
|
208
|
+
}
|
|
209
|
+
dequeueBatch(maxItems) {
|
|
210
|
+
if (this.items.length === 0)
|
|
211
|
+
return [];
|
|
212
|
+
return this.items.splice(0, maxItems);
|
|
213
|
+
}
|
|
214
|
+
size() {
|
|
215
|
+
return this.items.length;
|
|
216
|
+
}
|
|
217
|
+
async flush() {
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// packages/core/src/tracing/tracer.ts
|
|
223
|
+
var import_pfid = require("@prefactor/pfid");
|
|
224
|
+
|
|
106
225
|
// packages/core/src/tracing/context.ts
|
|
107
226
|
var import_node_async_hooks = require("node:async_hooks");
|
|
108
227
|
var spanStorage = new import_node_async_hooks.AsyncLocalStorage;
|
|
109
228
|
|
|
110
229
|
class SpanContext {
|
|
111
230
|
static getCurrent() {
|
|
112
|
-
|
|
231
|
+
const stack = spanStorage.getStore() ?? [];
|
|
232
|
+
return stack[stack.length - 1];
|
|
233
|
+
}
|
|
234
|
+
static getStack() {
|
|
235
|
+
return [...spanStorage.getStore() ?? []];
|
|
236
|
+
}
|
|
237
|
+
static enter(span) {
|
|
238
|
+
const stack = [...spanStorage.getStore() ?? [], span];
|
|
239
|
+
spanStorage.enterWith(stack);
|
|
240
|
+
}
|
|
241
|
+
static exit() {
|
|
242
|
+
const stack = [...spanStorage.getStore() ?? []];
|
|
243
|
+
stack.pop();
|
|
244
|
+
spanStorage.enterWith(stack);
|
|
113
245
|
}
|
|
114
246
|
static run(span, fn) {
|
|
115
|
-
|
|
247
|
+
const stack = spanStorage.getStore() ?? [];
|
|
248
|
+
const resource = new import_node_async_hooks.AsyncResource("SpanContext.run");
|
|
249
|
+
try {
|
|
250
|
+
return resource.runInAsyncScope(() => spanStorage.run([...stack, span], fn));
|
|
251
|
+
} finally {
|
|
252
|
+
resource.emitDestroy();
|
|
253
|
+
}
|
|
116
254
|
}
|
|
117
255
|
static async runAsync(span, fn) {
|
|
118
|
-
|
|
256
|
+
const stack = spanStorage.getStore() ?? [];
|
|
257
|
+
const resource = new import_node_async_hooks.AsyncResource("SpanContext.runAsync");
|
|
258
|
+
try {
|
|
259
|
+
return await resource.runInAsyncScope(() => spanStorage.run([...stack, span], fn));
|
|
260
|
+
} finally {
|
|
261
|
+
resource.emitDestroy();
|
|
262
|
+
}
|
|
119
263
|
}
|
|
120
264
|
static clear() {
|
|
121
265
|
spanStorage.disable();
|
|
122
266
|
}
|
|
123
267
|
}
|
|
268
|
+
|
|
124
269
|
// packages/core/src/tracing/span.ts
|
|
125
270
|
var SpanType;
|
|
126
271
|
((SpanType2) => {
|
|
@@ -130,27 +275,53 @@ var SpanType;
|
|
|
130
275
|
SpanType2["CHAIN"] = "chain";
|
|
131
276
|
SpanType2["RETRIEVER"] = "retriever";
|
|
132
277
|
})(SpanType ||= {});
|
|
278
|
+
var DEFAULT_AGENT_SCHEMA = {
|
|
279
|
+
external_identifier: "1.0.0",
|
|
280
|
+
span_schemas: {
|
|
281
|
+
agent: {
|
|
282
|
+
type: "object",
|
|
283
|
+
properties: { type: { type: "string", const: "agent" } }
|
|
284
|
+
},
|
|
285
|
+
llm: {
|
|
286
|
+
type: "object",
|
|
287
|
+
properties: { type: { type: "string", const: "llm" } }
|
|
288
|
+
},
|
|
289
|
+
tool: {
|
|
290
|
+
type: "object",
|
|
291
|
+
properties: { type: { type: "string", const: "tool" } }
|
|
292
|
+
},
|
|
293
|
+
chain: {
|
|
294
|
+
type: "object",
|
|
295
|
+
properties: { type: { type: "string", const: "chain" } }
|
|
296
|
+
},
|
|
297
|
+
retriever: {
|
|
298
|
+
type: "object",
|
|
299
|
+
properties: { type: { type: "string", const: "retriever" } }
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
133
303
|
var SpanStatus;
|
|
134
304
|
((SpanStatus2) => {
|
|
135
305
|
SpanStatus2["RUNNING"] = "running";
|
|
136
306
|
SpanStatus2["SUCCESS"] = "success";
|
|
137
307
|
SpanStatus2["ERROR"] = "error";
|
|
138
308
|
})(SpanStatus ||= {});
|
|
309
|
+
|
|
139
310
|
// packages/core/src/tracing/tracer.ts
|
|
140
|
-
var import_pfid = require("@prefactor/pfid");
|
|
141
311
|
class Tracer {
|
|
142
|
-
|
|
312
|
+
queue;
|
|
143
313
|
partition;
|
|
144
|
-
constructor(
|
|
145
|
-
this.
|
|
314
|
+
constructor(queue, partition) {
|
|
315
|
+
this.queue = queue;
|
|
146
316
|
this.partition = partition ?? import_pfid.generatePartition();
|
|
147
317
|
}
|
|
148
318
|
startSpan(options) {
|
|
319
|
+
const parentSpan = SpanContext.getCurrent();
|
|
149
320
|
const spanId = import_pfid.generate(this.partition);
|
|
150
|
-
const traceId =
|
|
321
|
+
const traceId = parentSpan?.traceId ?? import_pfid.generate(this.partition);
|
|
151
322
|
const span = {
|
|
152
323
|
spanId,
|
|
153
|
-
parentSpanId:
|
|
324
|
+
parentSpanId: parentSpan?.spanId ?? null,
|
|
154
325
|
traceId,
|
|
155
326
|
name: options.name,
|
|
156
327
|
spanType: options.spanType,
|
|
@@ -164,17 +335,18 @@ class Tracer {
|
|
|
164
335
|
metadata: options.metadata ?? {},
|
|
165
336
|
tags: options.tags ?? []
|
|
166
337
|
};
|
|
167
|
-
if (options.spanType === "agent") {
|
|
338
|
+
if (options.spanType === "agent" /* AGENT */) {
|
|
168
339
|
try {
|
|
169
|
-
this.
|
|
340
|
+
this.queue.enqueue({ type: "span_end", data: span });
|
|
170
341
|
} catch (error) {
|
|
171
|
-
console.error("Failed to
|
|
342
|
+
console.error("Failed to enqueue agent span:", error);
|
|
172
343
|
}
|
|
173
344
|
}
|
|
174
345
|
return span;
|
|
175
346
|
}
|
|
176
347
|
endSpan(span, options) {
|
|
177
|
-
|
|
348
|
+
const endTime = Date.now();
|
|
349
|
+
span.endTime = endTime;
|
|
178
350
|
span.outputs = options?.outputs ?? null;
|
|
179
351
|
span.tokenUsage = options?.tokenUsage ?? null;
|
|
180
352
|
if (options?.error) {
|
|
@@ -188,37 +360,24 @@ class Tracer {
|
|
|
188
360
|
span.status = "success" /* SUCCESS */;
|
|
189
361
|
}
|
|
190
362
|
try {
|
|
191
|
-
if (span.spanType === "agent") {
|
|
192
|
-
this.
|
|
363
|
+
if (span.spanType === "agent" /* AGENT */) {
|
|
364
|
+
this.queue.enqueue({ type: "span_finish", data: { spanId: span.spanId, endTime } });
|
|
193
365
|
} else {
|
|
194
|
-
this.
|
|
366
|
+
this.queue.enqueue({ type: "span_end", data: span });
|
|
195
367
|
}
|
|
196
368
|
} catch (error) {
|
|
197
|
-
console.error("Failed to
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
startAgentInstance() {
|
|
201
|
-
try {
|
|
202
|
-
this.transport.startAgentInstance();
|
|
203
|
-
} catch (error) {
|
|
204
|
-
console.error("Failed to start agent instance:", error);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
finishAgentInstance() {
|
|
208
|
-
try {
|
|
209
|
-
this.transport.finishAgentInstance();
|
|
210
|
-
} catch (error) {
|
|
211
|
-
console.error("Failed to finish agent instance:", error);
|
|
369
|
+
console.error("Failed to enqueue span action:", error);
|
|
212
370
|
}
|
|
213
371
|
}
|
|
214
372
|
async close() {
|
|
215
373
|
try {
|
|
216
|
-
await this.
|
|
374
|
+
await this.queue.flush();
|
|
217
375
|
} catch (error) {
|
|
218
|
-
console.error("Failed to
|
|
376
|
+
console.error("Failed to flush queue:", error);
|
|
219
377
|
}
|
|
220
378
|
}
|
|
221
379
|
}
|
|
380
|
+
|
|
222
381
|
// packages/core/src/utils/logging.ts
|
|
223
382
|
class Logger {
|
|
224
383
|
namespace;
|
|
@@ -271,73 +430,76 @@ var logger = getLogger("http-transport");
|
|
|
271
430
|
|
|
272
431
|
class HttpTransport {
|
|
273
432
|
config;
|
|
274
|
-
queue = [];
|
|
275
|
-
processing = false;
|
|
276
433
|
closed = false;
|
|
277
434
|
agentInstanceId = null;
|
|
278
435
|
spanIdMap = new Map;
|
|
436
|
+
pendingFinishes = new Map;
|
|
279
437
|
constructor(config) {
|
|
280
438
|
this.config = config;
|
|
281
|
-
this.startProcessing();
|
|
282
|
-
}
|
|
283
|
-
emit(span) {
|
|
284
|
-
if (this.closed) {
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
this.queue.push({ type: "span", data: span });
|
|
288
|
-
}
|
|
289
|
-
finishSpan(spanId, endTime) {
|
|
290
|
-
if (this.closed) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
const timestamp = new Date(endTime).toISOString();
|
|
294
|
-
this.queue.push({ type: "finish_span", data: { spanId, timestamp } });
|
|
295
|
-
}
|
|
296
|
-
startAgentInstance() {
|
|
297
|
-
if (this.closed) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
this.queue.push({ type: "start_agent", data: null });
|
|
301
439
|
}
|
|
302
|
-
|
|
303
|
-
if (this.closed) {
|
|
440
|
+
async processBatch(items) {
|
|
441
|
+
if (this.closed || items.length === 0) {
|
|
304
442
|
return;
|
|
305
443
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
313
|
-
continue;
|
|
444
|
+
for (const item of items) {
|
|
445
|
+
if (item.type === "schema_register") {
|
|
446
|
+
this.config.agentSchema = item.data.schema;
|
|
447
|
+
this.config.agentSchemaIdentifier = item.data.schemaIdentifier;
|
|
448
|
+
this.config.schemaName = item.data.schemaName;
|
|
449
|
+
this.config.schemaIdentifier = item.data.schemaIdentifier;
|
|
314
450
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
continue;
|
|
451
|
+
}
|
|
452
|
+
for (const item of items) {
|
|
318
453
|
try {
|
|
319
|
-
if (!this.agentInstanceId && item.type !== "start_agent") {
|
|
320
|
-
await this.ensureAgentRegistered();
|
|
321
|
-
}
|
|
322
454
|
switch (item.type) {
|
|
323
|
-
case "
|
|
324
|
-
await this.sendSpan(item.data);
|
|
325
|
-
break;
|
|
326
|
-
case "finish_span":
|
|
327
|
-
await this.finishSpanHttp(item.data);
|
|
455
|
+
case "schema_register":
|
|
328
456
|
break;
|
|
329
|
-
case "
|
|
457
|
+
case "agent_start":
|
|
458
|
+
this.config.agentId = item.data.agentId;
|
|
459
|
+
if (item.data.agentIdentifier !== undefined)
|
|
460
|
+
this.config.agentIdentifier = item.data.agentIdentifier;
|
|
461
|
+
this.config.agentName = item.data.agentName;
|
|
462
|
+
this.config.agentDescription = item.data.agentDescription;
|
|
330
463
|
await this.startAgentInstanceHttp();
|
|
331
464
|
break;
|
|
332
|
-
case "
|
|
465
|
+
case "agent_finish":
|
|
333
466
|
await this.finishAgentInstanceHttp();
|
|
334
467
|
break;
|
|
468
|
+
case "span_end":
|
|
469
|
+
if (!this.agentInstanceId) {
|
|
470
|
+
await this.ensureAgentRegistered();
|
|
471
|
+
}
|
|
472
|
+
await this.sendSpan(item.data);
|
|
473
|
+
break;
|
|
474
|
+
case "span_finish": {
|
|
475
|
+
const spanId = item.data.spanId;
|
|
476
|
+
const backendSpanId = this.spanIdMap.get(spanId);
|
|
477
|
+
if (backendSpanId) {
|
|
478
|
+
const timestamp = new Date(item.data.endTime).toISOString();
|
|
479
|
+
await this.finishSpanHttp({ spanId, timestamp });
|
|
480
|
+
} else {
|
|
481
|
+
this.pendingFinishes.set(spanId, item.data.endTime);
|
|
482
|
+
}
|
|
483
|
+
break;
|
|
484
|
+
}
|
|
335
485
|
}
|
|
336
486
|
} catch (error) {
|
|
337
|
-
logger.error("Error processing
|
|
487
|
+
logger.error("Error processing batch item:", error);
|
|
338
488
|
}
|
|
339
489
|
}
|
|
340
|
-
|
|
490
|
+
}
|
|
491
|
+
async processPendingFinishes(spanId) {
|
|
492
|
+
const pendingEndTime = this.pendingFinishes.get(spanId);
|
|
493
|
+
if (!pendingEndTime) {
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
try {
|
|
497
|
+
const timestamp = new Date(pendingEndTime).toISOString();
|
|
498
|
+
await this.finishSpanHttp({ spanId, timestamp });
|
|
499
|
+
this.pendingFinishes.delete(spanId);
|
|
500
|
+
} catch (error) {
|
|
501
|
+
logger.error("Error processing pending span finish:", error);
|
|
502
|
+
}
|
|
341
503
|
}
|
|
342
504
|
async sendSpan(span, retry = 0) {
|
|
343
505
|
const url = `${this.config.apiUrl}/api/v1/agent_spans`;
|
|
@@ -357,6 +519,7 @@ class HttpTransport {
|
|
|
357
519
|
const backendSpanId = data?.details?.id;
|
|
358
520
|
if (backendSpanId) {
|
|
359
521
|
this.spanIdMap.set(span.spanId, backendSpanId);
|
|
522
|
+
await this.processPendingFinishes(span.spanId);
|
|
360
523
|
}
|
|
361
524
|
return;
|
|
362
525
|
}
|
|
@@ -418,31 +581,7 @@ class HttpTransport {
|
|
|
418
581
|
};
|
|
419
582
|
}
|
|
420
583
|
getDefaultSchema() {
|
|
421
|
-
return
|
|
422
|
-
external_identifier: "1.0.0",
|
|
423
|
-
span_schemas: {
|
|
424
|
-
agent: {
|
|
425
|
-
type: "object",
|
|
426
|
-
properties: { type: { type: "string", const: "agent" } }
|
|
427
|
-
},
|
|
428
|
-
llm: {
|
|
429
|
-
type: "object",
|
|
430
|
-
properties: { type: { type: "string", const: "llm" } }
|
|
431
|
-
},
|
|
432
|
-
tool: {
|
|
433
|
-
type: "object",
|
|
434
|
-
properties: { type: { type: "string", const: "tool" } }
|
|
435
|
-
},
|
|
436
|
-
chain: {
|
|
437
|
-
type: "object",
|
|
438
|
-
properties: { type: { type: "string", const: "chain" } }
|
|
439
|
-
},
|
|
440
|
-
retriever: {
|
|
441
|
-
type: "object",
|
|
442
|
-
properties: { type: { type: "string", const: "retriever" } }
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
};
|
|
584
|
+
return DEFAULT_AGENT_SCHEMA;
|
|
446
585
|
}
|
|
447
586
|
async ensureAgentRegistered() {
|
|
448
587
|
if (this.agentInstanceId) {
|
|
@@ -452,9 +591,9 @@ class HttpTransport {
|
|
|
452
591
|
const payload = {};
|
|
453
592
|
if (this.config.agentId)
|
|
454
593
|
payload.agent_id = this.config.agentId;
|
|
455
|
-
if (this.config.
|
|
594
|
+
if (this.config.agentIdentifier) {
|
|
456
595
|
payload.agent_version = {
|
|
457
|
-
external_identifier: this.config.
|
|
596
|
+
external_identifier: this.config.agentIdentifier,
|
|
458
597
|
name: this.config.agentName || "Agent",
|
|
459
598
|
description: this.config.agentDescription || ""
|
|
460
599
|
};
|
|
@@ -464,10 +603,10 @@ class HttpTransport {
|
|
|
464
603
|
} else if (this.config.agentSchema) {
|
|
465
604
|
logger.debug("Using custom agent schema");
|
|
466
605
|
payload.agent_schema_version = this.config.agentSchema;
|
|
467
|
-
} else if (this.config.
|
|
468
|
-
logger.debug(`Using schema version: ${this.config.
|
|
606
|
+
} else if (this.config.agentSchemaIdentifier) {
|
|
607
|
+
logger.debug(`Using schema version: ${this.config.agentSchemaIdentifier}`);
|
|
469
608
|
payload.agent_schema_version = {
|
|
470
|
-
external_identifier: this.config.
|
|
609
|
+
external_identifier: this.config.agentSchemaIdentifier
|
|
471
610
|
};
|
|
472
611
|
} else {
|
|
473
612
|
logger.debug("Using default hardcoded schema (v1.0.0)");
|
|
@@ -540,6 +679,7 @@ class HttpTransport {
|
|
|
540
679
|
} catch (error) {
|
|
541
680
|
logger.error("Error finishing agent instance:", error);
|
|
542
681
|
}
|
|
682
|
+
this.agentInstanceId = null;
|
|
543
683
|
}
|
|
544
684
|
async finishSpanHttp(data) {
|
|
545
685
|
const backendSpanId = this.spanIdMap.get(data.spanId);
|
|
@@ -567,16 +707,13 @@ class HttpTransport {
|
|
|
567
707
|
}
|
|
568
708
|
async close() {
|
|
569
709
|
this.closed = true;
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
574
|
-
}
|
|
575
|
-
if (this.processing) {
|
|
576
|
-
logger.warn("Transport closed with pending queue items");
|
|
710
|
+
if (this.pendingFinishes.size > 0) {
|
|
711
|
+
logger.warn(`Transport closed with ${this.pendingFinishes.size} pending span finish(es) that could not be processed`);
|
|
712
|
+
this.pendingFinishes.clear();
|
|
577
713
|
}
|
|
578
714
|
}
|
|
579
715
|
}
|
|
716
|
+
|
|
580
717
|
// packages/core/src/utils/serialization.ts
|
|
581
718
|
function truncateString(value, maxLength) {
|
|
582
719
|
if (value.length <= maxLength) {
|
|
@@ -615,28 +752,147 @@ function serializeValue(value, maxLength = 1e4) {
|
|
|
615
752
|
class StdioTransport {
|
|
616
753
|
closed = false;
|
|
617
754
|
writeLock = Promise.resolve();
|
|
618
|
-
|
|
619
|
-
if (this.closed) {
|
|
755
|
+
async processBatch(items) {
|
|
756
|
+
if (this.closed || items.length === 0) {
|
|
620
757
|
return;
|
|
621
758
|
}
|
|
622
759
|
this.writeLock = this.writeLock.then(async () => {
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
760
|
+
for (const item of items) {
|
|
761
|
+
try {
|
|
762
|
+
const serialized = serializeValue(item);
|
|
763
|
+
const json = JSON.stringify(serialized);
|
|
764
|
+
await Bun.write(Bun.stdout, `${json}
|
|
627
765
|
`);
|
|
628
|
-
|
|
629
|
-
|
|
766
|
+
} catch (error) {
|
|
767
|
+
console.error("Failed to emit queue action to stdout:", error);
|
|
768
|
+
}
|
|
630
769
|
}
|
|
631
770
|
});
|
|
771
|
+
await this.writeLock;
|
|
632
772
|
}
|
|
633
|
-
finishSpan() {}
|
|
634
|
-
startAgentInstance() {}
|
|
635
|
-
finishAgentInstance() {}
|
|
636
773
|
async close() {
|
|
637
774
|
this.closed = true;
|
|
638
775
|
await this.writeLock;
|
|
639
776
|
}
|
|
640
777
|
}
|
|
641
778
|
|
|
642
|
-
|
|
779
|
+
// packages/core/src/transport/worker.ts
|
|
780
|
+
class TransportWorker {
|
|
781
|
+
queue;
|
|
782
|
+
transport;
|
|
783
|
+
config;
|
|
784
|
+
closed = false;
|
|
785
|
+
inFlightPromise = null;
|
|
786
|
+
loopPromise;
|
|
787
|
+
pendingBatch = null;
|
|
788
|
+
constructor(queue, transport, config) {
|
|
789
|
+
this.queue = queue;
|
|
790
|
+
this.transport = transport;
|
|
791
|
+
this.config = config;
|
|
792
|
+
this.loopPromise = this.start();
|
|
793
|
+
}
|
|
794
|
+
async start() {
|
|
795
|
+
while (!this.closed || this.pendingBatch || this.queue.size() > 0 || this.inFlightPromise) {
|
|
796
|
+
const batch = this.pendingBatch ?? this.queue.dequeueBatch(this.config.batchSize);
|
|
797
|
+
if (batch.length === 0) {
|
|
798
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.intervalMs));
|
|
799
|
+
continue;
|
|
800
|
+
}
|
|
801
|
+
try {
|
|
802
|
+
const inFlight = this.transport.processBatch(batch);
|
|
803
|
+
this.inFlightPromise = inFlight;
|
|
804
|
+
await inFlight;
|
|
805
|
+
this.pendingBatch = null;
|
|
806
|
+
} catch (error) {
|
|
807
|
+
this.pendingBatch = batch;
|
|
808
|
+
console.error("TransportWorker.processBatch failed", error);
|
|
809
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.intervalMs));
|
|
810
|
+
} finally {
|
|
811
|
+
this.inFlightPromise = null;
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
async flush(timeoutMs) {
|
|
816
|
+
const start = Date.now();
|
|
817
|
+
while ((this.queue.size() > 0 || this.pendingBatch || this.inFlightPromise) && Date.now() - start < timeoutMs) {
|
|
818
|
+
await new Promise((resolve) => setTimeout(resolve, this.config.intervalMs));
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
async close(timeoutMs = this.config.intervalMs * 50) {
|
|
822
|
+
this.closed = true;
|
|
823
|
+
const deadline = Date.now() + timeoutMs;
|
|
824
|
+
const awaitWithTimeout = async (promise, label, timeoutMs2, warnOnTimeout = true) => {
|
|
825
|
+
if (timeoutMs2 <= 0) {
|
|
826
|
+
if (warnOnTimeout) {
|
|
827
|
+
console.warn(`TransportWorker.close timed out waiting for ${label}`);
|
|
828
|
+
}
|
|
829
|
+
return false;
|
|
830
|
+
}
|
|
831
|
+
const resolvedPromise = Promise.resolve(promise);
|
|
832
|
+
let timeoutId = null;
|
|
833
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
834
|
+
timeoutId = setTimeout(() => resolve(false), timeoutMs2);
|
|
835
|
+
});
|
|
836
|
+
const completed = await Promise.race([resolvedPromise.then(() => true), timeoutPromise]);
|
|
837
|
+
if (timeoutId) {
|
|
838
|
+
clearTimeout(timeoutId);
|
|
839
|
+
}
|
|
840
|
+
if (!completed && warnOnTimeout) {
|
|
841
|
+
console.warn(`TransportWorker.close timed out waiting for ${label}`);
|
|
842
|
+
}
|
|
843
|
+
return completed;
|
|
844
|
+
};
|
|
845
|
+
const remainingTime = () => Math.max(0, deadline - Date.now());
|
|
846
|
+
const loopCompleted = await awaitWithTimeout(this.loopPromise, "loop to finish", remainingTime(), false);
|
|
847
|
+
if (!loopCompleted) {
|
|
848
|
+
console.warn("TransportWorker.close timed out waiting for loop to finish; closing transport now may cause potential data loss");
|
|
849
|
+
}
|
|
850
|
+
const safeTransportClose = async () => {
|
|
851
|
+
try {
|
|
852
|
+
await this.transport.close();
|
|
853
|
+
} catch (error) {
|
|
854
|
+
console.error("TransportWorker.close failed", error);
|
|
855
|
+
}
|
|
856
|
+
};
|
|
857
|
+
await awaitWithTimeout(safeTransportClose(), "transport to close", remainingTime());
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// packages/core/src/create-core.ts
|
|
862
|
+
function createCore(config) {
|
|
863
|
+
let transport;
|
|
864
|
+
if (config.transportType === "stdio") {
|
|
865
|
+
transport = new StdioTransport;
|
|
866
|
+
} else {
|
|
867
|
+
if (!config.httpConfig) {
|
|
868
|
+
throw new Error("HTTP transport requires httpConfig to be provided in configuration");
|
|
869
|
+
}
|
|
870
|
+
const httpConfig = HttpTransportConfigSchema.parse(config.httpConfig);
|
|
871
|
+
transport = new HttpTransport(httpConfig);
|
|
872
|
+
}
|
|
873
|
+
let partition;
|
|
874
|
+
if (config.httpConfig?.agentId) {
|
|
875
|
+
try {
|
|
876
|
+
partition = import_pfid2.extractPartition(config.httpConfig.agentId);
|
|
877
|
+
} catch {
|
|
878
|
+
partition = undefined;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
const queue = new InMemoryQueue;
|
|
882
|
+
const worker = new TransportWorker(queue, transport, { batchSize: 25, intervalMs: 50 });
|
|
883
|
+
const tracer = new Tracer(queue, partition);
|
|
884
|
+
const schemaName = config.httpConfig?.schemaName ?? "prefactor:agent";
|
|
885
|
+
const schemaIdentifier = config.httpConfig?.schemaIdentifier ?? "1.0.0";
|
|
886
|
+
const allowUnregisteredSchema = config.transportType === "http" && Boolean(config.httpConfig?.skipSchema || config.httpConfig?.agentSchema || config.httpConfig?.agentSchemaIdentifier);
|
|
887
|
+
const agentManager = new AgentInstanceManager(queue, {
|
|
888
|
+
schemaName,
|
|
889
|
+
schemaIdentifier,
|
|
890
|
+
allowUnregisteredSchema
|
|
891
|
+
});
|
|
892
|
+
const shutdown = async () => {
|
|
893
|
+
await worker.close();
|
|
894
|
+
};
|
|
895
|
+
return { tracer, agentManager, worker, shutdown };
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
//# debugId=CE5CB6A1D11DF5BA64756E2164756E21
|