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