@prefactor/core 0.2.0 → 0.2.2
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/agent/instance-manager.d.ts +5 -8
- package/dist/agent/instance-manager.d.ts.map +1 -1
- package/dist/agent/instance-manager.js +34 -55
- package/dist/agent/instance-manager.js.map +1 -1
- package/dist/config.d.ts +15 -63
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +29 -20
- package/dist/config.js.map +1 -1
- package/dist/create-core.d.ts +0 -2
- package/dist/create-core.d.ts.map +1 -1
- package/dist/create-core.js +17 -28
- package/dist/create-core.js.map +1 -1
- package/dist/index.cjs +678 -453
- package/dist/index.cjs.map +20 -15
- package/dist/index.d.ts +4 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +678 -453
- package/dist/index.js.map +20 -15
- package/dist/lifecycle.d.ts +5 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +27 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/queue/actions.d.ts +15 -26
- package/dist/queue/actions.d.ts.map +1 -1
- package/dist/queue/base.d.ts +15 -3
- package/dist/queue/base.d.ts.map +1 -1
- package/dist/queue/in-memory-queue.d.ts +11 -0
- package/dist/queue/in-memory-queue.d.ts.map +1 -0
- package/dist/queue/in-memory-queue.js +46 -0
- package/dist/queue/in-memory-queue.js.map +1 -0
- package/dist/queue/task-executor.d.ts +18 -0
- package/dist/queue/task-executor.d.ts.map +1 -0
- package/dist/queue/task-executor.js +77 -0
- package/dist/queue/task-executor.js.map +1 -0
- package/dist/tracing/active-tracer.d.ts +5 -0
- package/dist/tracing/active-tracer.d.ts.map +1 -0
- package/dist/tracing/active-tracer.js +13 -0
- package/dist/tracing/active-tracer.js.map +1 -0
- package/dist/tracing/span.d.ts +7 -14
- package/dist/tracing/span.d.ts.map +1 -1
- package/dist/tracing/span.js +5 -36
- package/dist/tracing/span.js.map +1 -1
- package/dist/tracing/tracer.d.ts +6 -7
- package/dist/tracing/tracer.d.ts.map +1 -1
- package/dist/tracing/tracer.js +27 -12
- package/dist/tracing/tracer.js.map +1 -1
- package/dist/tracing/with-span.d.ts +4 -0
- package/dist/tracing/with-span.d.ts.map +1 -0
- package/dist/tracing/with-span.js +35 -0
- package/dist/tracing/with-span.js.map +1 -0
- package/dist/transport/http/agent-instance-client.d.ts +23 -0
- package/dist/transport/http/agent-instance-client.d.ts.map +1 -0
- package/dist/transport/http/agent-instance-client.js +25 -0
- package/dist/transport/http/agent-instance-client.js.map +1 -0
- package/dist/transport/http/agent-span-client.d.ts +25 -0
- package/dist/transport/http/agent-span-client.d.ts.map +1 -0
- package/dist/transport/http/agent-span-client.js +37 -0
- package/dist/transport/http/agent-span-client.js.map +1 -0
- package/dist/transport/http/http-client.d.ts +43 -0
- package/dist/transport/http/http-client.d.ts.map +1 -0
- package/dist/transport/http/http-client.js +127 -0
- package/dist/transport/http/http-client.js.map +1 -0
- package/dist/transport/http/retry-policy.d.ts +4 -0
- package/dist/transport/http/retry-policy.d.ts.map +1 -0
- package/dist/transport/http/retry-policy.js +10 -0
- package/dist/transport/http/retry-policy.js.map +1 -0
- package/dist/transport/http.d.ts +34 -50
- package/dist/transport/http.d.ts.map +1 -1
- package/dist/transport/http.js +163 -227
- package/dist/transport/http.js.map +1 -1
- package/dist/utils/logging.d.ts.map +1 -1
- package/dist/utils/logging.js +7 -1
- package/dist/utils/logging.js.map +1 -1
- package/package.json +1 -1
- package/dist/agent/schema-registry.d.ts +0 -9
- package/dist/agent/schema-registry.d.ts.map +0 -1
- package/dist/agent/schema-registry.js +0 -16
- package/dist/agent/schema-registry.js.map +0 -1
- package/dist/queue/in-memory.d.ts +0 -9
- package/dist/queue/in-memory.d.ts.map +0 -1
- package/dist/queue/in-memory.js +0 -18
- package/dist/queue/in-memory.js.map +0 -1
- package/dist/transport/base.d.ts +0 -18
- package/dist/transport/base.d.ts.map +0 -1
- package/dist/transport/base.js +0 -2
- package/dist/transport/base.js.map +0 -1
- package/dist/transport/stdio.d.ts +0 -36
- package/dist/transport/stdio.d.ts.map +0 -1
- package/dist/transport/stdio.js +0 -56
- package/dist/transport/stdio.js.map +0 -1
- package/dist/transport/worker.d.ts +0 -22
- package/dist/transport/worker.d.ts.map +0 -1
- package/dist/transport/worker.js +0 -85
- package/dist/transport/worker.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,90 +1,60 @@
|
|
|
1
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
2
|
class AgentInstanceManager {
|
|
47
|
-
|
|
3
|
+
transport;
|
|
48
4
|
options;
|
|
49
|
-
|
|
50
|
-
constructor(
|
|
51
|
-
this.
|
|
5
|
+
registeredSchema = null;
|
|
6
|
+
constructor(transport, options) {
|
|
7
|
+
this.transport = transport;
|
|
52
8
|
this.options = options;
|
|
53
9
|
}
|
|
54
10
|
registerSchema(schema) {
|
|
55
|
-
if (this.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
console.warn(`Schema ${this.options.schemaName}@${this.options.schemaIdentifier} is already registered with a different payload. Ignoring registration.`);
|
|
59
|
-
}
|
|
11
|
+
if (this.registeredSchema === null) {
|
|
12
|
+
this.registeredSchema = schema;
|
|
13
|
+
this.transport.registerSchema(schema);
|
|
60
14
|
return;
|
|
61
15
|
}
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
schema
|
|
66
|
-
}
|
|
67
|
-
this.schemaRegistry.register(registration);
|
|
68
|
-
this.queue.enqueue({ type: "schema_register", data: registration });
|
|
16
|
+
const existingSchema = stableStringify(this.registeredSchema);
|
|
17
|
+
const incomingSchema = stableStringify(schema);
|
|
18
|
+
if (existingSchema !== incomingSchema) {
|
|
19
|
+
console.warn("A different schema was provided after registration; ignoring subsequent schema.");
|
|
20
|
+
}
|
|
69
21
|
}
|
|
70
22
|
startInstance(options = {}) {
|
|
71
|
-
if (!this.options.allowUnregisteredSchema &&
|
|
72
|
-
console.warn(
|
|
23
|
+
if (!this.options.allowUnregisteredSchema && this.registeredSchema === null) {
|
|
24
|
+
console.warn("Schema must be registered before starting an agent instance.");
|
|
73
25
|
return;
|
|
74
26
|
}
|
|
75
|
-
|
|
76
|
-
...options,
|
|
77
|
-
schemaName: this.options.schemaName,
|
|
78
|
-
schemaIdentifier: this.options.schemaIdentifier
|
|
79
|
-
};
|
|
80
|
-
this.queue.enqueue({ type: "agent_start", data: startData });
|
|
27
|
+
this.transport.startAgentInstance(options);
|
|
81
28
|
}
|
|
82
29
|
finishInstance() {
|
|
83
|
-
this.
|
|
30
|
+
this.transport.finishAgentInstance();
|
|
84
31
|
}
|
|
85
32
|
}
|
|
33
|
+
function stableStringify(value) {
|
|
34
|
+
return JSON.stringify(normalizeValue(value));
|
|
35
|
+
}
|
|
36
|
+
function normalizeValue(value) {
|
|
37
|
+
if (Array.isArray(value)) {
|
|
38
|
+
return value.map((entry) => normalizeValue(entry));
|
|
39
|
+
}
|
|
40
|
+
if (value && typeof value === "object") {
|
|
41
|
+
const normalized = {};
|
|
42
|
+
const objectValue = value;
|
|
43
|
+
const keys = Object.keys(objectValue).sort((a, b) => a.localeCompare(b));
|
|
44
|
+
for (const key of keys) {
|
|
45
|
+
normalized[key] = normalizeValue(objectValue[key]);
|
|
46
|
+
}
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
86
51
|
// packages/core/src/config.ts
|
|
87
52
|
import { z } from "zod";
|
|
53
|
+
var DEFAULT_RETRY_ON_STATUS_CODES = [
|
|
54
|
+
429,
|
|
55
|
+
...Array.from({ length: 100 }, (_, index) => 500 + index)
|
|
56
|
+
];
|
|
57
|
+
var HttpStatusCodeSchema = z.number().int().min(100).max(599);
|
|
88
58
|
var HttpTransportConfigSchema = z.object({
|
|
89
59
|
apiUrl: z.string().url(),
|
|
90
60
|
apiToken: z.string().min(1),
|
|
@@ -92,17 +62,13 @@ var HttpTransportConfigSchema = z.object({
|
|
|
92
62
|
agentIdentifier: z.string().default("v1.0.0"),
|
|
93
63
|
agentName: z.string().optional(),
|
|
94
64
|
agentDescription: z.string().optional(),
|
|
95
|
-
schemaName: z.string().optional(),
|
|
96
|
-
schemaIdentifier: z.string().optional(),
|
|
97
65
|
agentSchema: z.record(z.unknown()).optional(),
|
|
98
|
-
agentSchemaIdentifier: z.string().optional(),
|
|
99
|
-
skipSchema: z.boolean().default(false),
|
|
100
66
|
requestTimeout: z.number().positive().default(30000),
|
|
101
|
-
connectTimeout: z.number().positive().default(1e4),
|
|
102
67
|
maxRetries: z.number().int().nonnegative().default(3),
|
|
103
68
|
initialRetryDelay: z.number().positive().default(1000),
|
|
104
69
|
maxRetryDelay: z.number().positive().default(60000),
|
|
105
|
-
retryMultiplier: z.number().positive().default(2)
|
|
70
|
+
retryMultiplier: z.number().positive().default(2),
|
|
71
|
+
retryOnStatusCodes: z.array(HttpStatusCodeSchema).default([...DEFAULT_RETRY_ON_STATUS_CODES])
|
|
106
72
|
});
|
|
107
73
|
var PartialHttpConfigSchema = z.object({
|
|
108
74
|
apiUrl: z.string().url(),
|
|
@@ -111,20 +77,16 @@ var PartialHttpConfigSchema = z.object({
|
|
|
111
77
|
agentIdentifier: z.string().optional(),
|
|
112
78
|
agentName: z.string().optional(),
|
|
113
79
|
agentDescription: z.string().optional(),
|
|
114
|
-
schemaName: z.string().optional(),
|
|
115
|
-
schemaIdentifier: z.string().optional(),
|
|
116
80
|
agentSchema: z.record(z.unknown()).optional(),
|
|
117
|
-
agentSchemaIdentifier: z.string().optional(),
|
|
118
|
-
skipSchema: z.boolean().optional(),
|
|
119
81
|
requestTimeout: z.number().positive().optional(),
|
|
120
|
-
connectTimeout: z.number().positive().optional(),
|
|
121
82
|
maxRetries: z.number().int().nonnegative().optional(),
|
|
122
83
|
initialRetryDelay: z.number().positive().optional(),
|
|
123
84
|
maxRetryDelay: z.number().positive().optional(),
|
|
124
|
-
retryMultiplier: z.number().positive().optional()
|
|
85
|
+
retryMultiplier: z.number().positive().optional(),
|
|
86
|
+
retryOnStatusCodes: z.array(HttpStatusCodeSchema).optional()
|
|
125
87
|
});
|
|
126
88
|
var ConfigSchema = z.object({
|
|
127
|
-
transportType: z.enum(["
|
|
89
|
+
transportType: z.enum(["http"]).default("http"),
|
|
128
90
|
sampleRate: z.number().min(0).max(1).default(1),
|
|
129
91
|
captureInputs: z.boolean().default(true),
|
|
130
92
|
captureOutputs: z.boolean().default(true),
|
|
@@ -133,37 +95,69 @@ var ConfigSchema = z.object({
|
|
|
133
95
|
httpConfig: PartialHttpConfigSchema.optional()
|
|
134
96
|
});
|
|
135
97
|
function createConfig(options) {
|
|
98
|
+
const retryOnStatusCodesFromEnv = parseRetryOnStatusCodesEnv(process.env.PREFACTOR_RETRY_ON_STATUS_CODES);
|
|
136
99
|
const config = {
|
|
137
|
-
transportType: options?.transportType ?? process.env.PREFACTOR_TRANSPORT ?? "
|
|
100
|
+
transportType: options?.transportType ?? process.env.PREFACTOR_TRANSPORT ?? "http",
|
|
138
101
|
sampleRate: options?.sampleRate ?? parseFloat(process.env.PREFACTOR_SAMPLE_RATE ?? "1.0"),
|
|
139
102
|
captureInputs: options?.captureInputs ?? process.env.PREFACTOR_CAPTURE_INPUTS !== "false",
|
|
140
103
|
captureOutputs: options?.captureOutputs ?? process.env.PREFACTOR_CAPTURE_OUTPUTS !== "false",
|
|
141
104
|
maxInputLength: options?.maxInputLength ?? parseInt(process.env.PREFACTOR_MAX_INPUT_LENGTH ?? "10000", 10),
|
|
142
105
|
maxOutputLength: options?.maxOutputLength ?? parseInt(process.env.PREFACTOR_MAX_OUTPUT_LENGTH ?? "10000", 10),
|
|
143
|
-
httpConfig: options?.httpConfig
|
|
106
|
+
httpConfig: options?.httpConfig ? {
|
|
107
|
+
...options.httpConfig,
|
|
108
|
+
retryOnStatusCodes: options.httpConfig.retryOnStatusCodes ?? retryOnStatusCodesFromEnv
|
|
109
|
+
} : undefined
|
|
144
110
|
};
|
|
145
111
|
return ConfigSchema.parse(config);
|
|
146
112
|
}
|
|
113
|
+
function parseRetryOnStatusCodesEnv(value) {
|
|
114
|
+
if (!value) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const parsedCodes = value.split(",").map((status) => status.trim()).filter((status) => /^\d{3}$/.test(status)).map((status) => Number(status)).filter((status) => status >= 100 && status <= 599);
|
|
118
|
+
return parsedCodes.length > 0 ? parsedCodes : undefined;
|
|
119
|
+
}
|
|
147
120
|
// packages/core/src/create-core.ts
|
|
148
121
|
import { extractPartition } from "@prefactor/pfid";
|
|
149
122
|
|
|
150
|
-
// packages/core/src/
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
123
|
+
// packages/core/src/tracing/active-tracer.ts
|
|
124
|
+
var activeTracer;
|
|
125
|
+
function setActiveTracer(tracer) {
|
|
126
|
+
activeTracer = tracer;
|
|
127
|
+
}
|
|
128
|
+
function getActiveTracer() {
|
|
129
|
+
return activeTracer;
|
|
130
|
+
}
|
|
131
|
+
function clearActiveTracer(tracer) {
|
|
132
|
+
if (!tracer || activeTracer === tracer) {
|
|
133
|
+
activeTracer = undefined;
|
|
160
134
|
}
|
|
161
|
-
|
|
162
|
-
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// packages/core/src/lifecycle.ts
|
|
138
|
+
var shutdownHandlers = new Map;
|
|
139
|
+
var activeCoreRuntime = null;
|
|
140
|
+
function setActiveCoreRuntime(runtime) {
|
|
141
|
+
activeCoreRuntime = runtime;
|
|
142
|
+
}
|
|
143
|
+
function registerShutdownHandler(key, handler) {
|
|
144
|
+
shutdownHandlers.set(key, handler);
|
|
145
|
+
return () => shutdownHandlers.delete(key);
|
|
146
|
+
}
|
|
147
|
+
async function shutdown() {
|
|
148
|
+
for (const handler of shutdownHandlers.values()) {
|
|
149
|
+
try {
|
|
150
|
+
await handler();
|
|
151
|
+
} catch (error) {
|
|
152
|
+
console.error("Error during shutdown handler execution:", error);
|
|
153
|
+
}
|
|
163
154
|
}
|
|
164
|
-
|
|
165
|
-
|
|
155
|
+
if (activeCoreRuntime) {
|
|
156
|
+
const runtime = activeCoreRuntime;
|
|
157
|
+
activeCoreRuntime = null;
|
|
158
|
+
await runtime.shutdown();
|
|
166
159
|
}
|
|
160
|
+
clearActiveTracer();
|
|
167
161
|
}
|
|
168
162
|
|
|
169
163
|
// packages/core/src/tracing/tracer.ts
|
|
@@ -214,38 +208,11 @@ class SpanContext {
|
|
|
214
208
|
}
|
|
215
209
|
|
|
216
210
|
// packages/core/src/tracing/span.ts
|
|
217
|
-
var SpanType
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
SpanType2["CHAIN"] = "chain";
|
|
223
|
-
SpanType2["RETRIEVER"] = "retriever";
|
|
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
|
-
}
|
|
211
|
+
var SpanType = {
|
|
212
|
+
AGENT: "agent",
|
|
213
|
+
LLM: "llm",
|
|
214
|
+
TOOL: "tool",
|
|
215
|
+
CHAIN: "chain"
|
|
249
216
|
};
|
|
250
217
|
var SpanStatus;
|
|
251
218
|
((SpanStatus2) => {
|
|
@@ -256,10 +223,10 @@ var SpanStatus;
|
|
|
256
223
|
|
|
257
224
|
// packages/core/src/tracing/tracer.ts
|
|
258
225
|
class Tracer {
|
|
259
|
-
|
|
226
|
+
transport;
|
|
260
227
|
partition;
|
|
261
|
-
constructor(
|
|
262
|
-
this.
|
|
228
|
+
constructor(transport, partition) {
|
|
229
|
+
this.transport = transport;
|
|
263
230
|
this.partition = partition ?? generatePartition();
|
|
264
231
|
}
|
|
265
232
|
startSpan(options) {
|
|
@@ -279,14 +246,13 @@ class Tracer {
|
|
|
279
246
|
outputs: null,
|
|
280
247
|
tokenUsage: null,
|
|
281
248
|
error: null,
|
|
282
|
-
metadata: options.metadata ?? {}
|
|
283
|
-
tags: options.tags ?? []
|
|
249
|
+
metadata: options.metadata ?? {}
|
|
284
250
|
};
|
|
285
|
-
if (options.spanType ===
|
|
251
|
+
if (options.spanType === SpanType.AGENT) {
|
|
286
252
|
try {
|
|
287
|
-
this.
|
|
253
|
+
this.transport.emit(span);
|
|
288
254
|
} catch (error) {
|
|
289
|
-
console.error("Failed to
|
|
255
|
+
console.error("Failed to emit agent span:", error);
|
|
290
256
|
}
|
|
291
257
|
}
|
|
292
258
|
return span;
|
|
@@ -307,28 +273,180 @@ class Tracer {
|
|
|
307
273
|
span.status = "success" /* SUCCESS */;
|
|
308
274
|
}
|
|
309
275
|
try {
|
|
310
|
-
if (span.spanType ===
|
|
311
|
-
this.
|
|
276
|
+
if (span.spanType === SpanType.AGENT) {
|
|
277
|
+
this.transport.finishSpan(span.spanId, endTime);
|
|
312
278
|
} else {
|
|
313
|
-
this.
|
|
279
|
+
this.transport.emit(span);
|
|
314
280
|
}
|
|
315
281
|
} catch (error) {
|
|
316
|
-
console.error("Failed to
|
|
282
|
+
console.error("Failed to emit span action:", error);
|
|
317
283
|
}
|
|
318
284
|
}
|
|
319
285
|
async close() {
|
|
320
286
|
try {
|
|
321
|
-
await this.
|
|
287
|
+
await this.transport.close();
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.error("Failed to close transport:", error);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
startAgentInstance() {
|
|
293
|
+
try {
|
|
294
|
+
this.transport.startAgentInstance();
|
|
295
|
+
} catch (error) {
|
|
296
|
+
console.error("Failed to start agent instance:", error);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
finishAgentInstance() {
|
|
300
|
+
try {
|
|
301
|
+
this.transport.finishAgentInstance();
|
|
322
302
|
} catch (error) {
|
|
323
|
-
console.error("Failed to
|
|
303
|
+
console.error("Failed to finish agent instance:", error);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// packages/core/src/queue/in-memory-queue.ts
|
|
309
|
+
class InMemoryQueue {
|
|
310
|
+
items = [];
|
|
311
|
+
waiters = [];
|
|
312
|
+
isClosed = false;
|
|
313
|
+
async put(item) {
|
|
314
|
+
if (this.isClosed) {
|
|
315
|
+
throw new Error("Cannot put item into a closed queue");
|
|
316
|
+
}
|
|
317
|
+
const waiter = this.waiters.shift();
|
|
318
|
+
if (waiter) {
|
|
319
|
+
waiter({ done: false, item });
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
this.items.push({ item });
|
|
323
|
+
}
|
|
324
|
+
async get() {
|
|
325
|
+
if (this.items.length > 0) {
|
|
326
|
+
const entry = this.items.shift();
|
|
327
|
+
if (entry) {
|
|
328
|
+
return { done: false, item: entry.item };
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (this.isClosed) {
|
|
332
|
+
return { done: true };
|
|
333
|
+
}
|
|
334
|
+
return new Promise((resolve) => {
|
|
335
|
+
this.waiters.push(resolve);
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
close() {
|
|
339
|
+
if (this.isClosed) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
this.isClosed = true;
|
|
343
|
+
while (this.waiters.length > 0) {
|
|
344
|
+
const waiter = this.waiters.shift();
|
|
345
|
+
if (waiter) {
|
|
346
|
+
waiter({ done: true });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
size() {
|
|
351
|
+
return this.items.length;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// packages/core/src/queue/task-executor.ts
|
|
356
|
+
var DEFAULT_WORKER_COUNT = 1;
|
|
357
|
+
var DEFAULT_MAX_RETRIES = 0;
|
|
358
|
+
var DEFAULT_RETRY_DELAY_MS = 0;
|
|
359
|
+
|
|
360
|
+
class TaskExecutor {
|
|
361
|
+
queue;
|
|
362
|
+
handler;
|
|
363
|
+
isRunning = false;
|
|
364
|
+
workerPromises = [];
|
|
365
|
+
workerCount;
|
|
366
|
+
maxRetries;
|
|
367
|
+
retryDelayMs;
|
|
368
|
+
onError;
|
|
369
|
+
constructor(queue, handler, options = {}) {
|
|
370
|
+
this.queue = queue;
|
|
371
|
+
this.handler = handler;
|
|
372
|
+
this.workerCount = Math.max(options.workerCount ?? DEFAULT_WORKER_COUNT, 1);
|
|
373
|
+
this.maxRetries = Math.max(options.maxRetries ?? DEFAULT_MAX_RETRIES, 0);
|
|
374
|
+
this.retryDelayMs = Math.max(options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS, 0);
|
|
375
|
+
this.onError = options.onError;
|
|
376
|
+
}
|
|
377
|
+
start() {
|
|
378
|
+
if (this.isRunning) {
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
this.isRunning = true;
|
|
382
|
+
this.workerPromises = Array.from({ length: this.workerCount }, () => this.runWorker());
|
|
383
|
+
}
|
|
384
|
+
async stop() {
|
|
385
|
+
if (!this.isRunning) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
this.isRunning = false;
|
|
389
|
+
this.queue.close();
|
|
390
|
+
await Promise.all(this.workerPromises);
|
|
391
|
+
this.workerPromises = [];
|
|
392
|
+
}
|
|
393
|
+
async runWorker() {
|
|
394
|
+
while (true) {
|
|
395
|
+
const result = await this.queue.get();
|
|
396
|
+
if (result.done) {
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
await this.executeWithRetry(result.item);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async executeWithRetry(item) {
|
|
403
|
+
let attempt = 0;
|
|
404
|
+
while (attempt <= this.maxRetries) {
|
|
405
|
+
try {
|
|
406
|
+
await this.handler(item);
|
|
407
|
+
return;
|
|
408
|
+
} catch (error) {
|
|
409
|
+
if (attempt >= this.maxRetries) {
|
|
410
|
+
await this.safeOnError(error, item);
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
if (this.retryDelayMs > 0) {
|
|
414
|
+
await new Promise((resolve) => setTimeout(resolve, this.retryDelayMs));
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
attempt += 1;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
async safeOnError(error, item) {
|
|
421
|
+
if (!this.onError) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
try {
|
|
425
|
+
await this.onError(error, item);
|
|
426
|
+
} catch {
|
|
427
|
+
return;
|
|
324
428
|
}
|
|
325
429
|
}
|
|
326
430
|
}
|
|
327
431
|
|
|
328
432
|
// packages/core/src/utils/logging.ts
|
|
433
|
+
var LogLevel;
|
|
434
|
+
((LogLevel2) => {
|
|
435
|
+
LogLevel2[LogLevel2["DEBUG"] = 0] = "DEBUG";
|
|
436
|
+
LogLevel2[LogLevel2["INFO"] = 1] = "INFO";
|
|
437
|
+
LogLevel2[LogLevel2["WARN"] = 2] = "WARN";
|
|
438
|
+
LogLevel2[LogLevel2["ERROR"] = 3] = "ERROR";
|
|
439
|
+
})(LogLevel ||= {});
|
|
440
|
+
|
|
329
441
|
class Logger {
|
|
330
442
|
namespace;
|
|
331
|
-
static level =
|
|
443
|
+
static level = (() => {
|
|
444
|
+
const level = process.env.PREFACTOR_LOG_LEVEL?.toUpperCase();
|
|
445
|
+
if (level && level in LogLevel) {
|
|
446
|
+
return LogLevel[level];
|
|
447
|
+
}
|
|
448
|
+
return 1 /* INFO */;
|
|
449
|
+
})();
|
|
332
450
|
constructor(namespace) {
|
|
333
451
|
this.namespace = namespace;
|
|
334
452
|
}
|
|
@@ -372,72 +490,331 @@ function configureLogging() {
|
|
|
372
490
|
}
|
|
373
491
|
}
|
|
374
492
|
|
|
493
|
+
// packages/core/src/transport/http/agent-instance-client.ts
|
|
494
|
+
class AgentInstanceClient {
|
|
495
|
+
httpClient;
|
|
496
|
+
constructor(httpClient) {
|
|
497
|
+
this.httpClient = httpClient;
|
|
498
|
+
}
|
|
499
|
+
register(payload) {
|
|
500
|
+
return this.httpClient.request("/api/v1/agent_instance/register", {
|
|
501
|
+
method: "POST",
|
|
502
|
+
body: payload
|
|
503
|
+
});
|
|
504
|
+
}
|
|
505
|
+
async start(agentInstanceId) {
|
|
506
|
+
await this.httpClient.request(`/api/v1/agent_instance/${agentInstanceId}/start`, {
|
|
507
|
+
method: "POST",
|
|
508
|
+
body: {}
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
async finish(agentInstanceId) {
|
|
512
|
+
await this.httpClient.request(`/api/v1/agent_instance/${agentInstanceId}/finish`, {
|
|
513
|
+
method: "POST",
|
|
514
|
+
body: {}
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
// packages/core/src/transport/http/retry-policy.ts
|
|
520
|
+
var JITTER_MIN = 0.5;
|
|
521
|
+
function shouldRetryStatusCode(statusCode, retryOnStatusCodes) {
|
|
522
|
+
return retryOnStatusCodes.includes(statusCode);
|
|
523
|
+
}
|
|
524
|
+
function calculateRetryDelay(attempt, config, random = Math.random) {
|
|
525
|
+
const baseDelay = Math.min(config.initialRetryDelay * config.retryMultiplier ** attempt, config.maxRetryDelay);
|
|
526
|
+
const jitterMultiplier = JITTER_MIN + random() * JITTER_MIN;
|
|
527
|
+
return Math.round(baseDelay * jitterMultiplier);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// packages/core/src/transport/http/http-client.ts
|
|
531
|
+
class HttpClientError extends Error {
|
|
532
|
+
url;
|
|
533
|
+
method;
|
|
534
|
+
status;
|
|
535
|
+
statusText;
|
|
536
|
+
responseBody;
|
|
537
|
+
retryable;
|
|
538
|
+
constructor(message, options) {
|
|
539
|
+
super(message, { cause: options.cause });
|
|
540
|
+
this.name = "HttpClientError";
|
|
541
|
+
this.url = options.url;
|
|
542
|
+
this.method = options.method;
|
|
543
|
+
this.status = options.status;
|
|
544
|
+
this.statusText = options.statusText;
|
|
545
|
+
this.responseBody = options.responseBody;
|
|
546
|
+
this.retryable = options.retryable;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
class HttpClient {
|
|
551
|
+
config;
|
|
552
|
+
fetchFn;
|
|
553
|
+
sleep;
|
|
554
|
+
random;
|
|
555
|
+
constructor(config, dependencies = {}) {
|
|
556
|
+
this.config = config;
|
|
557
|
+
this.fetchFn = dependencies.fetchFn ?? fetch;
|
|
558
|
+
this.sleep = dependencies.sleep ?? ((delayMs) => new Promise((resolve) => setTimeout(resolve, delayMs)));
|
|
559
|
+
this.random = dependencies.random ?? Math.random;
|
|
560
|
+
}
|
|
561
|
+
async request(path, options = {}) {
|
|
562
|
+
const url = new URL(path, this.config.apiUrl).toString();
|
|
563
|
+
const method = options.method ?? "GET";
|
|
564
|
+
let attempt = 0;
|
|
565
|
+
while (true) {
|
|
566
|
+
const headers = new Headers(options.headers);
|
|
567
|
+
headers.set("Authorization", `Bearer ${this.config.apiToken}`);
|
|
568
|
+
if (options.body !== undefined && !headers.has("Content-Type")) {
|
|
569
|
+
headers.set("Content-Type", "application/json");
|
|
570
|
+
}
|
|
571
|
+
const requestInit = {
|
|
572
|
+
...options,
|
|
573
|
+
method,
|
|
574
|
+
headers,
|
|
575
|
+
body: options.body === undefined ? undefined : JSON.stringify(options.body),
|
|
576
|
+
signal: AbortSignal.timeout(options.timeoutMs ?? this.config.requestTimeout)
|
|
577
|
+
};
|
|
578
|
+
try {
|
|
579
|
+
const response = await this.fetchFn(url, requestInit);
|
|
580
|
+
if (response.ok) {
|
|
581
|
+
return await parseResponseBody(response);
|
|
582
|
+
}
|
|
583
|
+
const responseBody = await parseResponseBody(response);
|
|
584
|
+
const canRetry = attempt < this.config.maxRetries && shouldRetryStatusCode(response.status, this.config.retryOnStatusCodes);
|
|
585
|
+
if (canRetry) {
|
|
586
|
+
const delayMs = calculateRetryDelay(attempt, this.config, this.random);
|
|
587
|
+
await this.sleep(delayMs);
|
|
588
|
+
attempt += 1;
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
throw new HttpClientError(`HTTP request failed with status ${response.status}`, {
|
|
592
|
+
url,
|
|
593
|
+
method,
|
|
594
|
+
status: response.status,
|
|
595
|
+
statusText: response.statusText,
|
|
596
|
+
responseBody,
|
|
597
|
+
retryable: shouldRetryStatusCode(response.status, this.config.retryOnStatusCodes)
|
|
598
|
+
});
|
|
599
|
+
} catch (error) {
|
|
600
|
+
if (error instanceof HttpClientError) {
|
|
601
|
+
throw error;
|
|
602
|
+
}
|
|
603
|
+
const canRetry = attempt < this.config.maxRetries && isRetryableNetworkError(error);
|
|
604
|
+
if (canRetry) {
|
|
605
|
+
const delayMs = calculateRetryDelay(attempt, this.config, this.random);
|
|
606
|
+
await this.sleep(delayMs);
|
|
607
|
+
attempt += 1;
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
throw new HttpClientError("HTTP request failed due to network error", {
|
|
611
|
+
url,
|
|
612
|
+
method,
|
|
613
|
+
retryable: false,
|
|
614
|
+
cause: error
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
function isRetryableNetworkError(error) {
|
|
621
|
+
if (error instanceof TypeError) {
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
if (error instanceof DOMException && (error.name === "AbortError" || error.name === "TimeoutError")) {
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
if (error instanceof Error && (error.name === "AbortError" || error.name === "TimeoutError")) {
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
return false;
|
|
631
|
+
}
|
|
632
|
+
async function parseResponseBody(response) {
|
|
633
|
+
const bodyText = await response.text();
|
|
634
|
+
if (!bodyText) {
|
|
635
|
+
return null;
|
|
636
|
+
}
|
|
637
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
638
|
+
if (contentType.includes("application/json")) {
|
|
639
|
+
try {
|
|
640
|
+
return JSON.parse(bodyText);
|
|
641
|
+
} catch {
|
|
642
|
+
return bodyText;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
try {
|
|
646
|
+
return JSON.parse(bodyText);
|
|
647
|
+
} catch {
|
|
648
|
+
return bodyText;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// packages/core/src/transport/http/agent-span-client.ts
|
|
653
|
+
class AgentSpanClient {
|
|
654
|
+
httpClient;
|
|
655
|
+
constructor(httpClient) {
|
|
656
|
+
this.httpClient = httpClient;
|
|
657
|
+
}
|
|
658
|
+
create(payload) {
|
|
659
|
+
return this.httpClient.request("/api/v1/agent_spans", {
|
|
660
|
+
method: "POST",
|
|
661
|
+
body: payload
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
async finish(spanId, timestamp) {
|
|
665
|
+
try {
|
|
666
|
+
await this.httpClient.request(`/api/v1/agent_spans/${spanId}/finish`, {
|
|
667
|
+
method: "POST",
|
|
668
|
+
body: { timestamp }
|
|
669
|
+
});
|
|
670
|
+
} catch (error) {
|
|
671
|
+
if (error instanceof HttpClientError && error.status === 409 && isAlreadyFinishedError(error.responseBody)) {
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
throw error;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function isAlreadyFinishedError(responseBody) {
|
|
679
|
+
if (!responseBody || typeof responseBody !== "object") {
|
|
680
|
+
return false;
|
|
681
|
+
}
|
|
682
|
+
const payload = responseBody;
|
|
683
|
+
return payload.code === "invalid_action";
|
|
684
|
+
}
|
|
685
|
+
|
|
375
686
|
// packages/core/src/transport/http.ts
|
|
376
687
|
var logger = getLogger("http-transport");
|
|
377
688
|
|
|
378
689
|
class HttpTransport {
|
|
379
690
|
config;
|
|
380
691
|
closed = false;
|
|
692
|
+
actionQueue = new InMemoryQueue;
|
|
693
|
+
taskExecutor;
|
|
694
|
+
agentInstanceClient;
|
|
695
|
+
agentSpanClient;
|
|
696
|
+
previousAgentSchema = null;
|
|
697
|
+
requiresNewAgentIdentifier = false;
|
|
698
|
+
previousAgentIdentifier = null;
|
|
381
699
|
agentInstanceId = null;
|
|
382
700
|
spanIdMap = new Map;
|
|
383
701
|
pendingFinishes = new Map;
|
|
702
|
+
pendingChildren = new Map;
|
|
384
703
|
constructor(config) {
|
|
385
704
|
this.config = config;
|
|
705
|
+
const httpClient = new HttpClient(config);
|
|
706
|
+
this.agentInstanceClient = new AgentInstanceClient(httpClient);
|
|
707
|
+
this.agentSpanClient = new AgentSpanClient(httpClient);
|
|
708
|
+
this.taskExecutor = new TaskExecutor(this.actionQueue, this.processAction, {
|
|
709
|
+
workerCount: 1,
|
|
710
|
+
onError: async (error) => {
|
|
711
|
+
logger.error("Error processing HTTP action:", error);
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
this.taskExecutor.start();
|
|
715
|
+
}
|
|
716
|
+
registerSchema(schema) {
|
|
717
|
+
this.enqueue({ type: "schema_register", schema });
|
|
718
|
+
}
|
|
719
|
+
startAgentInstance(options) {
|
|
720
|
+
this.enqueue({ type: "agent_start", options });
|
|
721
|
+
}
|
|
722
|
+
finishAgentInstance() {
|
|
723
|
+
this.enqueue({ type: "agent_finish" });
|
|
724
|
+
}
|
|
725
|
+
emit(span) {
|
|
726
|
+
this.enqueue({ type: "span_end", span });
|
|
727
|
+
}
|
|
728
|
+
finishSpan(spanId, endTime) {
|
|
729
|
+
this.enqueue({ type: "span_finish", spanId, endTime });
|
|
730
|
+
}
|
|
731
|
+
async close() {
|
|
732
|
+
this.closed = true;
|
|
733
|
+
await this.taskExecutor.stop();
|
|
734
|
+
if (this.pendingFinishes.size > 0) {
|
|
735
|
+
logger.warn(`Transport closed with ${this.pendingFinishes.size} pending span finish(es) that could not be processed`);
|
|
736
|
+
this.pendingFinishes.clear();
|
|
737
|
+
}
|
|
738
|
+
if (this.pendingChildren.size > 0) {
|
|
739
|
+
logger.warn(`Transport closed with ${this.pendingChildren.size} unresolved parent span reference(s)`);
|
|
740
|
+
this.pendingChildren.clear();
|
|
741
|
+
}
|
|
386
742
|
}
|
|
387
|
-
|
|
388
|
-
if (this.closed
|
|
743
|
+
enqueue(action) {
|
|
744
|
+
if (this.closed) {
|
|
389
745
|
return;
|
|
390
746
|
}
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
747
|
+
this.actionQueue.put(action).catch((error) => {
|
|
748
|
+
logger.error("Failed to enqueue HTTP action:", error);
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
processAction = async (action) => {
|
|
752
|
+
switch (action.type) {
|
|
753
|
+
case "schema_register": {
|
|
754
|
+
const incomingSchema = JSON.stringify(action.schema);
|
|
755
|
+
if (this.previousAgentSchema !== null && this.previousAgentSchema !== incomingSchema) {
|
|
756
|
+
this.requiresNewAgentIdentifier = true;
|
|
757
|
+
this.previousAgentIdentifier = this.config.agentIdentifier;
|
|
758
|
+
this.agentInstanceId = null;
|
|
759
|
+
}
|
|
760
|
+
this.previousAgentSchema = incomingSchema;
|
|
761
|
+
this.config.agentSchema = action.schema;
|
|
762
|
+
return;
|
|
397
763
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
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;
|
|
410
|
-
await this.startAgentInstanceHttp();
|
|
411
|
-
break;
|
|
412
|
-
case "agent_finish":
|
|
413
|
-
await this.finishAgentInstanceHttp();
|
|
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;
|
|
764
|
+
case "agent_start": {
|
|
765
|
+
if (this.requiresNewAgentIdentifier) {
|
|
766
|
+
const nextAgentIdentifier = action.options?.agentIdentifier;
|
|
767
|
+
if (nextAgentIdentifier === undefined || nextAgentIdentifier === this.previousAgentIdentifier) {
|
|
768
|
+
logger.error("Schema changed; starting an agent requires a new agentIdentifier value.");
|
|
769
|
+
return;
|
|
431
770
|
}
|
|
771
|
+
this.requiresNewAgentIdentifier = false;
|
|
772
|
+
this.previousAgentIdentifier = null;
|
|
432
773
|
}
|
|
433
|
-
|
|
434
|
-
|
|
774
|
+
if (action.options?.agentId !== undefined)
|
|
775
|
+
this.config.agentId = action.options.agentId;
|
|
776
|
+
if (action.options?.agentIdentifier !== undefined) {
|
|
777
|
+
this.config.agentIdentifier = action.options.agentIdentifier;
|
|
778
|
+
}
|
|
779
|
+
if (action.options?.agentName !== undefined)
|
|
780
|
+
this.config.agentName = action.options.agentName;
|
|
781
|
+
if (action.options?.agentDescription !== undefined) {
|
|
782
|
+
this.config.agentDescription = action.options.agentDescription;
|
|
783
|
+
}
|
|
784
|
+
await this.startAgentInstanceHttp();
|
|
785
|
+
return;
|
|
786
|
+
}
|
|
787
|
+
case "agent_finish":
|
|
788
|
+
await this.finishAgentInstanceHttp();
|
|
789
|
+
return;
|
|
790
|
+
case "span_end":
|
|
791
|
+
if (!this.agentInstanceId) {
|
|
792
|
+
await this.ensureAgentRegistered();
|
|
793
|
+
}
|
|
794
|
+
if (action.span.parentSpanId && !this.spanIdMap.has(action.span.parentSpanId)) {
|
|
795
|
+
this.queuePendingChild(action.span.parentSpanId, action.span);
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
await this.sendSpan(action.span);
|
|
799
|
+
return;
|
|
800
|
+
case "span_finish": {
|
|
801
|
+
const backendSpanId = this.spanIdMap.get(action.spanId);
|
|
802
|
+
if (backendSpanId) {
|
|
803
|
+
const timestamp = new Date(action.endTime).toISOString();
|
|
804
|
+
await this.finishSpanHttp({ spanId: action.spanId, timestamp });
|
|
805
|
+
} else {
|
|
806
|
+
this.pendingFinishes.set(action.spanId, action.endTime);
|
|
807
|
+
}
|
|
808
|
+
return;
|
|
435
809
|
}
|
|
436
810
|
}
|
|
437
|
-
}
|
|
811
|
+
};
|
|
438
812
|
async processPendingFinishes(spanId) {
|
|
813
|
+
if (!this.pendingFinishes.has(spanId)) {
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
439
816
|
const pendingEndTime = this.pendingFinishes.get(spanId);
|
|
440
|
-
if (
|
|
817
|
+
if (pendingEndTime === undefined) {
|
|
441
818
|
return;
|
|
442
819
|
}
|
|
443
820
|
try {
|
|
@@ -448,56 +825,48 @@ class HttpTransport {
|
|
|
448
825
|
logger.error("Error processing pending span finish:", error);
|
|
449
826
|
}
|
|
450
827
|
}
|
|
451
|
-
async sendSpan(span
|
|
452
|
-
const url = `${this.config.apiUrl}/api/v1/agent_spans`;
|
|
828
|
+
async sendSpan(span) {
|
|
453
829
|
const payload = this.transformSpanToApiFormat(span);
|
|
454
830
|
try {
|
|
455
|
-
const response = await
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
Authorization: `Bearer ${this.config.apiToken}`,
|
|
459
|
-
"Content-Type": "application/json"
|
|
460
|
-
},
|
|
461
|
-
body: JSON.stringify(payload),
|
|
462
|
-
signal: AbortSignal.timeout(this.config.requestTimeout)
|
|
463
|
-
});
|
|
464
|
-
if (response.ok) {
|
|
465
|
-
const data = await response.json();
|
|
466
|
-
const backendSpanId = data?.details?.id;
|
|
467
|
-
if (backendSpanId) {
|
|
468
|
-
this.spanIdMap.set(span.spanId, backendSpanId);
|
|
469
|
-
await this.processPendingFinishes(span.spanId);
|
|
470
|
-
}
|
|
831
|
+
const response = await this.agentSpanClient.create(payload);
|
|
832
|
+
const backendSpanId = response.details?.id;
|
|
833
|
+
if (!backendSpanId) {
|
|
471
834
|
return;
|
|
472
835
|
}
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
477
|
-
return this.sendSpan(span, retry + 1);
|
|
478
|
-
}
|
|
479
|
-
logger.error(`Failed to send span: ${response.status} ${response.statusText}`);
|
|
836
|
+
this.spanIdMap.set(span.spanId, backendSpanId);
|
|
837
|
+
await this.processPendingFinishes(span.spanId);
|
|
838
|
+
await this.processPendingChildren(span.spanId);
|
|
480
839
|
} catch (error) {
|
|
481
840
|
logger.error("Error sending span:", error);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
queuePendingChild(parentSpanId, childSpan) {
|
|
844
|
+
const existingChildren = this.pendingChildren.get(parentSpanId) ?? [];
|
|
845
|
+
existingChildren.push(childSpan);
|
|
846
|
+
this.pendingChildren.set(parentSpanId, existingChildren);
|
|
847
|
+
}
|
|
848
|
+
async processPendingChildren(parentSpanId) {
|
|
849
|
+
const waitingChildren = this.pendingChildren.get(parentSpanId);
|
|
850
|
+
if (!waitingChildren || waitingChildren.length === 0) {
|
|
851
|
+
return;
|
|
852
|
+
}
|
|
853
|
+
this.pendingChildren.delete(parentSpanId);
|
|
854
|
+
for (const childSpan of waitingChildren) {
|
|
855
|
+
await this.sendSpan(childSpan);
|
|
487
856
|
}
|
|
488
857
|
}
|
|
489
858
|
transformSpanToApiFormat(span) {
|
|
490
859
|
const startedAt = new Date(span.startTime).toISOString();
|
|
491
860
|
const finishedAt = span.endTime ? new Date(span.endTime).toISOString() : null;
|
|
861
|
+
const apiStatus = this.mapStatusForApi(span.status);
|
|
492
862
|
const payload = {
|
|
493
863
|
span_id: span.spanId,
|
|
494
864
|
trace_id: span.traceId,
|
|
495
865
|
name: span.name,
|
|
496
|
-
status:
|
|
866
|
+
status: apiStatus,
|
|
497
867
|
inputs: span.inputs,
|
|
498
868
|
outputs: span.outputs,
|
|
499
869
|
metadata: span.metadata,
|
|
500
|
-
tags: span.tags,
|
|
501
870
|
token_usage: null,
|
|
502
871
|
error: null
|
|
503
872
|
};
|
|
@@ -520,6 +889,7 @@ class HttpTransport {
|
|
|
520
889
|
details: {
|
|
521
890
|
agent_instance_id: this.agentInstanceId,
|
|
522
891
|
schema_name: span.spanType,
|
|
892
|
+
status: apiStatus,
|
|
523
893
|
payload,
|
|
524
894
|
parent_span_id: parentSpanId,
|
|
525
895
|
started_at: startedAt,
|
|
@@ -527,14 +897,22 @@ class HttpTransport {
|
|
|
527
897
|
}
|
|
528
898
|
};
|
|
529
899
|
}
|
|
530
|
-
|
|
531
|
-
|
|
900
|
+
mapStatusForApi(status) {
|
|
901
|
+
switch (status) {
|
|
902
|
+
case "running":
|
|
903
|
+
return "active";
|
|
904
|
+
case "success":
|
|
905
|
+
return "complete";
|
|
906
|
+
case "error":
|
|
907
|
+
return "failed";
|
|
908
|
+
default:
|
|
909
|
+
return "active";
|
|
910
|
+
}
|
|
532
911
|
}
|
|
533
912
|
async ensureAgentRegistered() {
|
|
534
913
|
if (this.agentInstanceId) {
|
|
535
|
-
return;
|
|
914
|
+
return true;
|
|
536
915
|
}
|
|
537
|
-
const url = `${this.config.apiUrl}/api/v1/agent_instance/register`;
|
|
538
916
|
const payload = {};
|
|
539
917
|
if (this.config.agentId)
|
|
540
918
|
payload.agent_id = this.config.agentId;
|
|
@@ -545,61 +923,25 @@ class HttpTransport {
|
|
|
545
923
|
description: this.config.agentDescription || ""
|
|
546
924
|
};
|
|
547
925
|
}
|
|
548
|
-
if (this.config.
|
|
549
|
-
logger.debug("Skipping schema in registration (skipSchema=true)");
|
|
550
|
-
} else if (this.config.agentSchema) {
|
|
551
|
-
logger.debug("Using custom agent schema");
|
|
926
|
+
if (this.config.agentSchema) {
|
|
552
927
|
payload.agent_schema_version = this.config.agentSchema;
|
|
553
|
-
} else if (this.config.agentSchemaIdentifier) {
|
|
554
|
-
logger.debug(`Using schema version: ${this.config.agentSchemaIdentifier}`);
|
|
555
|
-
payload.agent_schema_version = {
|
|
556
|
-
external_identifier: this.config.agentSchemaIdentifier
|
|
557
|
-
};
|
|
558
|
-
} else {
|
|
559
|
-
logger.debug("Using default hardcoded schema (v1.0.0)");
|
|
560
|
-
payload.agent_schema_version = this.getDefaultSchema();
|
|
561
928
|
}
|
|
562
929
|
try {
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
headers: {
|
|
566
|
-
Authorization: `Bearer ${this.config.apiToken}`,
|
|
567
|
-
"Content-Type": "application/json"
|
|
568
|
-
},
|
|
569
|
-
body: JSON.stringify(payload),
|
|
570
|
-
signal: AbortSignal.timeout(this.config.requestTimeout)
|
|
571
|
-
});
|
|
572
|
-
if (response.ok) {
|
|
573
|
-
const data = await response.json();
|
|
574
|
-
this.agentInstanceId = data?.details?.id ?? null;
|
|
575
|
-
logger.debug(`Registered agent instance: ${this.agentInstanceId}`);
|
|
576
|
-
} else {
|
|
577
|
-
logger.error(`Failed to register agent: ${response.status} ${response.statusText}`);
|
|
578
|
-
}
|
|
930
|
+
const data = await this.agentInstanceClient.register(payload);
|
|
931
|
+
this.agentInstanceId = data.details?.id ?? null;
|
|
579
932
|
} catch (error) {
|
|
580
933
|
logger.error("Error registering agent:", error);
|
|
581
934
|
}
|
|
935
|
+
return this.agentInstanceId !== null;
|
|
582
936
|
}
|
|
583
937
|
async startAgentInstanceHttp() {
|
|
584
|
-
await this.ensureAgentRegistered();
|
|
585
|
-
if (!this.agentInstanceId) {
|
|
938
|
+
const isRegistered = await this.ensureAgentRegistered();
|
|
939
|
+
if (!isRegistered || !this.agentInstanceId) {
|
|
586
940
|
logger.error("Cannot start agent instance: not registered");
|
|
587
941
|
return;
|
|
588
942
|
}
|
|
589
|
-
const url = `${this.config.apiUrl}/api/v1/agent_instance/${this.agentInstanceId}/start`;
|
|
590
943
|
try {
|
|
591
|
-
|
|
592
|
-
method: "POST",
|
|
593
|
-
headers: {
|
|
594
|
-
Authorization: `Bearer ${this.config.apiToken}`,
|
|
595
|
-
"Content-Type": "application/json"
|
|
596
|
-
},
|
|
597
|
-
body: JSON.stringify({}),
|
|
598
|
-
signal: AbortSignal.timeout(this.config.requestTimeout)
|
|
599
|
-
});
|
|
600
|
-
if (!response.ok) {
|
|
601
|
-
logger.error(`Failed to start agent instance: ${response.status} ${response.statusText}`);
|
|
602
|
-
}
|
|
944
|
+
await this.agentInstanceClient.start(this.agentInstanceId);
|
|
603
945
|
} catch (error) {
|
|
604
946
|
logger.error("Error starting agent instance:", error);
|
|
605
947
|
}
|
|
@@ -609,20 +951,8 @@ class HttpTransport {
|
|
|
609
951
|
logger.error("Cannot finish agent instance: not registered");
|
|
610
952
|
return;
|
|
611
953
|
}
|
|
612
|
-
const url = `${this.config.apiUrl}/api/v1/agent_instance/${this.agentInstanceId}/finish`;
|
|
613
954
|
try {
|
|
614
|
-
|
|
615
|
-
method: "POST",
|
|
616
|
-
headers: {
|
|
617
|
-
Authorization: `Bearer ${this.config.apiToken}`,
|
|
618
|
-
"Content-Type": "application/json"
|
|
619
|
-
},
|
|
620
|
-
body: JSON.stringify({}),
|
|
621
|
-
signal: AbortSignal.timeout(this.config.requestTimeout)
|
|
622
|
-
});
|
|
623
|
-
if (!response.ok) {
|
|
624
|
-
logger.error(`Failed to finish agent instance: ${response.status} ${response.statusText}`);
|
|
625
|
-
}
|
|
955
|
+
await this.agentInstanceClient.finish(this.agentInstanceId);
|
|
626
956
|
} catch (error) {
|
|
627
957
|
logger.error("Error finishing agent instance:", error);
|
|
628
958
|
}
|
|
@@ -634,33 +964,76 @@ class HttpTransport {
|
|
|
634
964
|
logger.warn(`Cannot finish span ${data.spanId}: backend ID not found`);
|
|
635
965
|
return;
|
|
636
966
|
}
|
|
637
|
-
const url = `${this.config.apiUrl}/api/v1/agent_spans/${backendSpanId}/finish`;
|
|
638
967
|
try {
|
|
639
|
-
|
|
640
|
-
method: "POST",
|
|
641
|
-
headers: {
|
|
642
|
-
Authorization: `Bearer ${this.config.apiToken}`,
|
|
643
|
-
"Content-Type": "application/json"
|
|
644
|
-
},
|
|
645
|
-
body: JSON.stringify({ timestamp: data.timestamp }),
|
|
646
|
-
signal: AbortSignal.timeout(this.config.requestTimeout)
|
|
647
|
-
});
|
|
648
|
-
if (!response.ok) {
|
|
649
|
-
logger.error(`Failed to finish span: ${response.status} ${response.statusText}`);
|
|
650
|
-
}
|
|
968
|
+
await this.agentSpanClient.finish(backendSpanId, data.timestamp);
|
|
651
969
|
} catch (error) {
|
|
652
970
|
logger.error("Error finishing span:", error);
|
|
653
971
|
}
|
|
654
972
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
// packages/core/src/create-core.ts
|
|
976
|
+
function createCore(config) {
|
|
977
|
+
if (!config.httpConfig) {
|
|
978
|
+
throw new Error("HTTP transport requires httpConfig to be provided in configuration");
|
|
979
|
+
}
|
|
980
|
+
const httpConfig = HttpTransportConfigSchema.parse(config.httpConfig);
|
|
981
|
+
const transport = new HttpTransport(httpConfig);
|
|
982
|
+
let partition;
|
|
983
|
+
if (config.httpConfig.agentId) {
|
|
984
|
+
try {
|
|
985
|
+
partition = extractPartition(config.httpConfig.agentId);
|
|
986
|
+
} catch {
|
|
987
|
+
partition = undefined;
|
|
660
988
|
}
|
|
661
989
|
}
|
|
990
|
+
const tracer = new Tracer(transport, partition);
|
|
991
|
+
setActiveTracer(tracer);
|
|
992
|
+
const allowUnregisteredSchema = Boolean(config.httpConfig.agentSchema);
|
|
993
|
+
const agentManager = new AgentInstanceManager(transport, {
|
|
994
|
+
allowUnregisteredSchema
|
|
995
|
+
});
|
|
996
|
+
const shutdown2 = async () => {
|
|
997
|
+
await tracer.close();
|
|
998
|
+
clearActiveTracer(tracer);
|
|
999
|
+
setActiveCoreRuntime(null);
|
|
1000
|
+
};
|
|
1001
|
+
const runtime = { tracer, agentManager, shutdown: shutdown2 };
|
|
1002
|
+
setActiveCoreRuntime(runtime);
|
|
1003
|
+
return runtime;
|
|
1004
|
+
}
|
|
1005
|
+
// packages/core/src/tracing/with-span.ts
|
|
1006
|
+
async function withSpan(tracerOrOptions, optionsOrFn, maybeFn) {
|
|
1007
|
+
const { tracer, options, fn } = resolveArgs(tracerOrOptions, optionsOrFn, maybeFn);
|
|
1008
|
+
const span = tracer.startSpan(options);
|
|
1009
|
+
try {
|
|
1010
|
+
const result = await SpanContext.runAsync(span, async () => await fn());
|
|
1011
|
+
tracer.endSpan(span);
|
|
1012
|
+
return result;
|
|
1013
|
+
} catch (error) {
|
|
1014
|
+
const normalizedError = error instanceof Error ? error : new Error(String(error));
|
|
1015
|
+
tracer.endSpan(span, { error: normalizedError });
|
|
1016
|
+
throw error;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
function resolveArgs(tracerOrOptions, optionsOrFn, maybeFn) {
|
|
1020
|
+
if (maybeFn) {
|
|
1021
|
+
return {
|
|
1022
|
+
tracer: tracerOrOptions,
|
|
1023
|
+
options: optionsOrFn,
|
|
1024
|
+
fn: maybeFn
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
const tracer = getActiveTracer();
|
|
1028
|
+
if (!tracer) {
|
|
1029
|
+
throw new Error("No active tracer found. Initialize Prefactor first or pass a tracer explicitly.");
|
|
1030
|
+
}
|
|
1031
|
+
return {
|
|
1032
|
+
tracer,
|
|
1033
|
+
options: tracerOrOptions,
|
|
1034
|
+
fn: optionsOrFn
|
|
1035
|
+
};
|
|
662
1036
|
}
|
|
663
|
-
|
|
664
1037
|
// packages/core/src/utils/serialization.ts
|
|
665
1038
|
function truncateString(value, maxLength) {
|
|
666
1039
|
if (value.length <= maxLength) {
|
|
@@ -694,173 +1067,25 @@ function serializeValue(value, maxLength = 1e4) {
|
|
|
694
1067
|
return `<${typeof value} object>`;
|
|
695
1068
|
}
|
|
696
1069
|
}
|
|
697
|
-
|
|
698
|
-
// packages/core/src/transport/stdio.ts
|
|
699
|
-
class StdioTransport {
|
|
700
|
-
closed = false;
|
|
701
|
-
writeLock = Promise.resolve();
|
|
702
|
-
async processBatch(items) {
|
|
703
|
-
if (this.closed || items.length === 0) {
|
|
704
|
-
return;
|
|
705
|
-
}
|
|
706
|
-
this.writeLock = this.writeLock.then(async () => {
|
|
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}
|
|
712
|
-
`);
|
|
713
|
-
} catch (error) {
|
|
714
|
-
console.error("Failed to emit queue action to stdout:", error);
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
});
|
|
718
|
-
await this.writeLock;
|
|
719
|
-
}
|
|
720
|
-
async close() {
|
|
721
|
-
this.closed = true;
|
|
722
|
-
await this.writeLock;
|
|
723
|
-
}
|
|
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
|
-
}
|
|
844
1070
|
export {
|
|
1071
|
+
withSpan,
|
|
845
1072
|
truncateString,
|
|
1073
|
+
shutdown,
|
|
846
1074
|
serializeValue,
|
|
1075
|
+
registerShutdownHandler,
|
|
847
1076
|
getLogger,
|
|
848
1077
|
createCore,
|
|
849
1078
|
createConfig,
|
|
850
1079
|
configureLogging,
|
|
851
1080
|
Tracer,
|
|
852
|
-
StdioTransport,
|
|
853
1081
|
SpanType,
|
|
854
1082
|
SpanStatus,
|
|
855
1083
|
SpanContext,
|
|
856
|
-
SchemaRegistry,
|
|
857
1084
|
PartialHttpConfigSchema,
|
|
858
|
-
InMemoryQueue,
|
|
859
1085
|
HttpTransportConfigSchema,
|
|
860
1086
|
HttpTransport,
|
|
861
|
-
DEFAULT_AGENT_SCHEMA,
|
|
862
1087
|
ConfigSchema,
|
|
863
1088
|
AgentInstanceManager
|
|
864
1089
|
};
|
|
865
1090
|
|
|
866
|
-
//# debugId=
|
|
1091
|
+
//# debugId=9E6C81B271F2076D64756E2164756E21
|