@prefactor/core 0.2.0 → 0.2.1

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.
Files changed (82) hide show
  1. package/dist/agent/instance-manager.d.ts +5 -8
  2. package/dist/agent/instance-manager.d.ts.map +1 -1
  3. package/dist/agent/instance-manager.js +34 -55
  4. package/dist/agent/instance-manager.js.map +1 -1
  5. package/dist/config.d.ts +15 -63
  6. package/dist/config.d.ts.map +1 -1
  7. package/dist/config.js +29 -20
  8. package/dist/config.js.map +1 -1
  9. package/dist/create-core.d.ts +0 -2
  10. package/dist/create-core.d.ts.map +1 -1
  11. package/dist/create-core.js +10 -28
  12. package/dist/create-core.js.map +1 -1
  13. package/dist/index.cjs +577 -457
  14. package/dist/index.cjs.map +17 -15
  15. package/dist/index.d.ts +2 -7
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +577 -457
  18. package/dist/index.js.map +17 -15
  19. package/dist/queue/actions.d.ts +15 -26
  20. package/dist/queue/actions.d.ts.map +1 -1
  21. package/dist/queue/base.d.ts +15 -3
  22. package/dist/queue/base.d.ts.map +1 -1
  23. package/dist/queue/in-memory-queue.d.ts +11 -0
  24. package/dist/queue/in-memory-queue.d.ts.map +1 -0
  25. package/dist/queue/in-memory-queue.js +46 -0
  26. package/dist/queue/in-memory-queue.js.map +1 -0
  27. package/dist/queue/task-executor.d.ts +18 -0
  28. package/dist/queue/task-executor.d.ts.map +1 -0
  29. package/dist/queue/task-executor.js +77 -0
  30. package/dist/queue/task-executor.js.map +1 -0
  31. package/dist/tracing/span.d.ts +7 -14
  32. package/dist/tracing/span.d.ts.map +1 -1
  33. package/dist/tracing/span.js +5 -36
  34. package/dist/tracing/span.js.map +1 -1
  35. package/dist/tracing/tracer.d.ts +6 -7
  36. package/dist/tracing/tracer.d.ts.map +1 -1
  37. package/dist/tracing/tracer.js +27 -12
  38. package/dist/tracing/tracer.js.map +1 -1
  39. package/dist/transport/http/agent-instance-client.d.ts +23 -0
  40. package/dist/transport/http/agent-instance-client.d.ts.map +1 -0
  41. package/dist/transport/http/agent-instance-client.js +25 -0
  42. package/dist/transport/http/agent-instance-client.js.map +1 -0
  43. package/dist/transport/http/agent-span-client.d.ts +25 -0
  44. package/dist/transport/http/agent-span-client.d.ts.map +1 -0
  45. package/dist/transport/http/agent-span-client.js +37 -0
  46. package/dist/transport/http/agent-span-client.js.map +1 -0
  47. package/dist/transport/http/http-client.d.ts +43 -0
  48. package/dist/transport/http/http-client.d.ts.map +1 -0
  49. package/dist/transport/http/http-client.js +127 -0
  50. package/dist/transport/http/http-client.js.map +1 -0
  51. package/dist/transport/http/retry-policy.d.ts +4 -0
  52. package/dist/transport/http/retry-policy.d.ts.map +1 -0
  53. package/dist/transport/http/retry-policy.js +10 -0
  54. package/dist/transport/http/retry-policy.js.map +1 -0
  55. package/dist/transport/http.d.ts +31 -50
  56. package/dist/transport/http.d.ts.map +1 -1
  57. package/dist/transport/http.js +138 -227
  58. package/dist/transport/http.js.map +1 -1
  59. package/dist/utils/logging.d.ts.map +1 -1
  60. package/dist/utils/logging.js +7 -1
  61. package/dist/utils/logging.js.map +1 -1
  62. package/package.json +1 -1
  63. package/dist/agent/schema-registry.d.ts +0 -9
  64. package/dist/agent/schema-registry.d.ts.map +0 -1
  65. package/dist/agent/schema-registry.js +0 -16
  66. package/dist/agent/schema-registry.js.map +0 -1
  67. package/dist/queue/in-memory.d.ts +0 -9
  68. package/dist/queue/in-memory.d.ts.map +0 -1
  69. package/dist/queue/in-memory.js +0 -18
  70. package/dist/queue/in-memory.js.map +0 -1
  71. package/dist/transport/base.d.ts +0 -18
  72. package/dist/transport/base.d.ts.map +0 -1
  73. package/dist/transport/base.js +0 -2
  74. package/dist/transport/base.js.map +0 -1
  75. package/dist/transport/stdio.d.ts +0 -36
  76. package/dist/transport/stdio.d.ts.map +0 -1
  77. package/dist/transport/stdio.js +0 -56
  78. package/dist/transport/stdio.js.map +0 -1
  79. package/dist/transport/worker.d.ts +0 -22
  80. package/dist/transport/worker.d.ts.map +0 -1
  81. package/dist/transport/worker.js +0 -85
  82. package/dist/transport/worker.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../../src/transport/http/http-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { HttpTransportConfig } from '../../config.js';
2
+ export declare function shouldRetryStatusCode(statusCode: number, retryOnStatusCodes: number[]): boolean;
3
+ export declare function calculateRetryDelay(attempt: number, config: Pick<HttpTransportConfig, 'initialRetryDelay' | 'maxRetryDelay' | 'retryMultiplier'>, random?: () => number): number;
4
+ //# sourceMappingURL=retry-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-policy.d.ts","sourceRoot":"","sources":["../../../src/transport/http/retry-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAI3D,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,EAAE,kBAAkB,EAAE,MAAM,EAAE,GAAG,OAAO,CAE/F;AAED,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,mBAAmB,GAAG,eAAe,GAAG,iBAAiB,CAAC,EAC5F,MAAM,GAAE,MAAM,MAAoB,GACjC,MAAM,CAOR"}
@@ -0,0 +1,10 @@
1
+ const JITTER_MIN = 0.5;
2
+ export function shouldRetryStatusCode(statusCode, retryOnStatusCodes) {
3
+ return retryOnStatusCodes.includes(statusCode);
4
+ }
5
+ export function calculateRetryDelay(attempt, config, random = Math.random) {
6
+ const baseDelay = Math.min(config.initialRetryDelay * config.retryMultiplier ** attempt, config.maxRetryDelay);
7
+ const jitterMultiplier = JITTER_MIN + random() * JITTER_MIN;
8
+ return Math.round(baseDelay * jitterMultiplier);
9
+ }
10
+ //# sourceMappingURL=retry-policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-policy.js","sourceRoot":"","sources":["../../../src/transport/http/retry-policy.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAAG,GAAG,CAAC;AAEvB,MAAM,UAAU,qBAAqB,CAAC,UAAkB,EAAE,kBAA4B;IACpF,OAAO,kBAAkB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,MAA4F,EAC5F,SAAuB,IAAI,CAAC,MAAM;IAElC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CACxB,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,eAAe,IAAI,OAAO,EAC5D,MAAM,CAAC,aAAa,CACrB,CAAC;IACF,MAAM,gBAAgB,GAAG,UAAU,GAAG,MAAM,EAAE,GAAG,UAAU,CAAC;IAC5D,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,gBAAgB,CAAC,CAAC;AAClD,CAAC"}
@@ -1,67 +1,48 @@
1
1
  import type { HttpTransportConfig } from '../config.js';
2
- import type { QueueAction } from '../queue/actions.js';
3
- import type { Transport } from './base.js';
4
- /**
5
- * HTTP transport sends spans to a remote API endpoint.
6
- *
7
- * Features:
8
- * - Exponential backoff retry logic
9
- * - Span ID mapping (SDK ID → backend ID)
10
- * - Agent instance lifecycle management
11
- *
12
- * @example
13
- * ```typescript
14
- * const transport = new HttpTransport({
15
- * apiUrl: 'https://api.prefactor.ai',
16
- * apiToken: process.env.PREFACTOR_API_TOKEN!,
17
- * });
18
- * ```
19
- */
2
+ import type { Span } from '../tracing/span.js';
3
+ export type AgentInstanceOptions = {
4
+ agentId?: string;
5
+ agentIdentifier?: string;
6
+ agentName?: string;
7
+ agentDescription?: string;
8
+ };
9
+ export interface Transport {
10
+ emit(span: Span): void;
11
+ finishSpan(spanId: string, endTime: number): void;
12
+ startAgentInstance(options?: AgentInstanceOptions): void;
13
+ finishAgentInstance(): void;
14
+ registerSchema(schema: Record<string, unknown>): void;
15
+ close(): void | Promise<void>;
16
+ }
20
17
  export declare class HttpTransport implements Transport {
21
18
  private config;
22
19
  private closed;
20
+ private readonly actionQueue;
21
+ private readonly taskExecutor;
22
+ private readonly agentInstanceClient;
23
+ private readonly agentSpanClient;
24
+ private previousAgentSchema;
25
+ private requiresNewAgentIdentifier;
26
+ private previousAgentIdentifier;
23
27
  private agentInstanceId;
24
28
  private spanIdMap;
25
29
  private pendingFinishes;
26
30
  constructor(config: HttpTransportConfig);
27
- processBatch(items: QueueAction[]): Promise<void>;
28
- /**
29
- * Process any pending finishes for a span that was just registered.
30
- */
31
+ registerSchema(schema: Record<string, unknown>): void;
32
+ startAgentInstance(options?: AgentInstanceOptions): void;
33
+ finishAgentInstance(): void;
34
+ emit(span: Span): void;
35
+ finishSpan(spanId: string, endTime: number): void;
36
+ close(): Promise<void>;
37
+ private enqueue;
38
+ private processAction;
31
39
  private processPendingFinishes;
32
- /**
33
- * Send a span to the API
34
- */
35
40
  private sendSpan;
36
- /**
37
- * Transform span to backend API format with nested details/payload structure
38
- */
39
41
  private transformSpanToApiFormat;
40
- /**
41
- * Get default schema (v1.0.0) with span schemas for all supported types
42
- */
43
- private getDefaultSchema;
44
- /**
45
- * Ensure an agent instance is registered
46
- */
42
+ private mapStatusForApi;
47
43
  private ensureAgentRegistered;
48
- /**
49
- * Start agent instance execution
50
- */
51
44
  private startAgentInstanceHttp;
52
- /**
53
- * Finish agent instance execution
54
- */
55
45
  private finishAgentInstanceHttp;
56
- /**
57
- * Finish a span via HTTP
58
- */
59
46
  private finishSpanHttp;
60
- /**
61
- * Close the transport and wait for queue to drain
62
- *
63
- * @returns Promise that resolves when transport is closed
64
- */
65
- close(): Promise<void>;
66
47
  }
67
48
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAI3C;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,YAAW,SAAS;IAOjC,OAAO,CAAC,MAAM;IAN1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,SAAS,CAA6B;IAE9C,OAAO,CAAC,eAAe,CAA6B;gBAEhC,MAAM,EAAE,mBAAmB;IAEzC,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA0DvD;;OAEG;YACW,sBAAsB;IAepC;;OAEG;YACW,QAAQ;IAqDtB;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAmDhC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;OAEG;YACW,qBAAqB;IA4DnC;;OAEG;YACW,sBAAsB;IA6BpC;;OAEG;YACW,uBAAuB;IA8BrC;;OAEG;YACW,cAAc;IA4B5B;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAW7B"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAU/C,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAEvB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAElD,kBAAkB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAEzD,mBAAmB,IAAI,IAAI,CAAC;IAE5B,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAEtD,KAAK,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAID,qBAAa,aAAc,YAAW,SAAS;IAajC,OAAO,CAAC,MAAM;IAZ1B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwC;IACpE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAgC;IAC7D,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAsB;IAC1D,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAkB;IAClD,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,0BAA0B,CAAS;IAC3C,OAAO,CAAC,uBAAuB,CAAuB;IACtD,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,SAAS,CAA6B;IAC9C,OAAO,CAAC,eAAe,CAA6B;gBAEhC,MAAM,EAAE,mBAAmB;IAa/C,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAIrD,kBAAkB,CAAC,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI;IAIxD,mBAAmB,IAAI,IAAI;IAI3B,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAItB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,aAAa,CA6DnB;YAEY,sBAAsB;YAmBtB,QAAQ;IAiBtB,OAAO,CAAC,wBAAwB;IAgDhC,OAAO,CAAC,eAAe;YAaT,qBAAqB;YA8BrB,sBAAsB;YActB,uBAAuB;YAevB,cAAc;CAa7B"}
@@ -1,95 +1,132 @@
1
- import { DEFAULT_AGENT_SCHEMA } from '../tracing/span.js';
1
+ import { InMemoryQueue } from '../queue/in-memory-queue.js';
2
+ import { TaskExecutor } from '../queue/task-executor.js';
2
3
  import { getLogger } from '../utils/logging.js';
4
+ import { AgentInstanceClient } from './http/agent-instance-client.js';
5
+ import { AgentSpanClient, } from './http/agent-span-client.js';
6
+ import { HttpClient } from './http/http-client.js';
3
7
  const logger = getLogger('http-transport');
4
- /**
5
- * HTTP transport sends spans to a remote API endpoint.
6
- *
7
- * Features:
8
- * - Exponential backoff retry logic
9
- * - Span ID mapping (SDK ID → backend ID)
10
- * - Agent instance lifecycle management
11
- *
12
- * @example
13
- * ```typescript
14
- * const transport = new HttpTransport({
15
- * apiUrl: 'https://api.prefactor.ai',
16
- * apiToken: process.env.PREFACTOR_API_TOKEN!,
17
- * });
18
- * ```
19
- */
20
8
  export class HttpTransport {
21
9
  config;
22
10
  closed = false;
11
+ actionQueue = new InMemoryQueue();
12
+ taskExecutor;
13
+ agentInstanceClient;
14
+ agentSpanClient;
15
+ previousAgentSchema = null;
16
+ requiresNewAgentIdentifier = false;
17
+ previousAgentIdentifier = null;
23
18
  agentInstanceId = null;
24
19
  spanIdMap = new Map();
25
- // Pending finishes for spans that arrived before their span_end
26
20
  pendingFinishes = new Map();
27
21
  constructor(config) {
28
22
  this.config = config;
23
+ const httpClient = new HttpClient(config);
24
+ this.agentInstanceClient = new AgentInstanceClient(httpClient);
25
+ this.agentSpanClient = new AgentSpanClient(httpClient);
26
+ this.taskExecutor = new TaskExecutor(this.actionQueue, this.processAction, {
27
+ workerCount: 1,
28
+ onError: async (error) => {
29
+ logger.error('Error processing HTTP action:', error);
30
+ },
31
+ });
32
+ this.taskExecutor.start();
33
+ }
34
+ registerSchema(schema) {
35
+ this.enqueue({ type: 'schema_register', schema });
36
+ }
37
+ startAgentInstance(options) {
38
+ this.enqueue({ type: 'agent_start', options });
39
+ }
40
+ finishAgentInstance() {
41
+ this.enqueue({ type: 'agent_finish' });
42
+ }
43
+ emit(span) {
44
+ this.enqueue({ type: 'span_end', span });
45
+ }
46
+ finishSpan(spanId, endTime) {
47
+ this.enqueue({ type: 'span_finish', spanId, endTime });
48
+ }
49
+ async close() {
50
+ this.closed = true;
51
+ await this.taskExecutor.stop();
52
+ if (this.pendingFinishes.size > 0) {
53
+ logger.warn(`Transport closed with ${this.pendingFinishes.size} pending span finish(es) that could not be processed`);
54
+ this.pendingFinishes.clear();
55
+ }
29
56
  }
30
- async processBatch(items) {
31
- if (this.closed || items.length === 0) {
57
+ enqueue(action) {
58
+ if (this.closed) {
32
59
  return;
33
60
  }
34
- // First pass: apply schema updates
35
- for (const item of items) {
36
- if (item.type === 'schema_register') {
37
- this.config.agentSchema = item.data.schema;
38
- this.config.agentSchemaIdentifier = item.data.schemaIdentifier;
39
- this.config.schemaName = item.data.schemaName;
40
- this.config.schemaIdentifier = item.data.schemaIdentifier;
61
+ this.actionQueue.put(action).catch((error) => {
62
+ logger.error('Failed to enqueue HTTP action:', error);
63
+ });
64
+ }
65
+ processAction = async (action) => {
66
+ switch (action.type) {
67
+ case 'schema_register': {
68
+ const incomingSchema = JSON.stringify(action.schema);
69
+ if (this.previousAgentSchema !== null && this.previousAgentSchema !== incomingSchema) {
70
+ this.requiresNewAgentIdentifier = true;
71
+ this.previousAgentIdentifier = this.config.agentIdentifier;
72
+ this.agentInstanceId = null;
73
+ }
74
+ this.previousAgentSchema = incomingSchema;
75
+ this.config.agentSchema = action.schema;
76
+ return;
41
77
  }
42
- }
43
- // Second pass: process actions
44
- for (const item of items) {
45
- try {
46
- switch (item.type) {
47
- case 'schema_register':
48
- break;
49
- case 'agent_start':
50
- this.config.agentId = item.data.agentId;
51
- if (item.data.agentIdentifier !== undefined)
52
- this.config.agentIdentifier = item.data.agentIdentifier;
53
- this.config.agentName = item.data.agentName;
54
- this.config.agentDescription = item.data.agentDescription;
55
- await this.startAgentInstanceHttp();
56
- break;
57
- case 'agent_finish':
58
- await this.finishAgentInstanceHttp();
59
- break;
60
- case 'span_end':
61
- if (!this.agentInstanceId) {
62
- await this.ensureAgentRegistered();
63
- }
64
- await this.sendSpan(item.data);
65
- break;
66
- case 'span_finish': {
67
- const spanId = item.data.spanId;
68
- const backendSpanId = this.spanIdMap.get(spanId);
69
- if (backendSpanId) {
70
- // Span mapping exists, finish immediately
71
- const timestamp = new Date(item.data.endTime).toISOString();
72
- await this.finishSpanHttp({ spanId, timestamp });
73
- }
74
- else {
75
- // Defer finish until span_end creates the mapping
76
- this.pendingFinishes.set(spanId, item.data.endTime);
77
- }
78
- break;
78
+ case 'agent_start': {
79
+ if (this.requiresNewAgentIdentifier) {
80
+ const nextAgentIdentifier = action.options?.agentIdentifier;
81
+ if (nextAgentIdentifier === undefined ||
82
+ nextAgentIdentifier === this.previousAgentIdentifier) {
83
+ logger.error('Schema changed; starting an agent requires a new agentIdentifier value.');
84
+ return;
79
85
  }
86
+ this.requiresNewAgentIdentifier = false;
87
+ this.previousAgentIdentifier = null;
88
+ }
89
+ if (action.options?.agentId !== undefined)
90
+ this.config.agentId = action.options.agentId;
91
+ if (action.options?.agentIdentifier !== undefined) {
92
+ this.config.agentIdentifier = action.options.agentIdentifier;
80
93
  }
94
+ if (action.options?.agentName !== undefined)
95
+ this.config.agentName = action.options.agentName;
96
+ if (action.options?.agentDescription !== undefined) {
97
+ this.config.agentDescription = action.options.agentDescription;
98
+ }
99
+ await this.startAgentInstanceHttp();
100
+ return;
81
101
  }
82
- catch (error) {
83
- logger.error('Error processing batch item:', error);
102
+ case 'agent_finish':
103
+ await this.finishAgentInstanceHttp();
104
+ return;
105
+ case 'span_end':
106
+ if (!this.agentInstanceId) {
107
+ await this.ensureAgentRegistered();
108
+ }
109
+ await this.sendSpan(action.span);
110
+ return;
111
+ case 'span_finish': {
112
+ const backendSpanId = this.spanIdMap.get(action.spanId);
113
+ if (backendSpanId) {
114
+ const timestamp = new Date(action.endTime).toISOString();
115
+ await this.finishSpanHttp({ spanId: action.spanId, timestamp });
116
+ }
117
+ else {
118
+ this.pendingFinishes.set(action.spanId, action.endTime);
119
+ }
120
+ return;
84
121
  }
85
122
  }
86
- }
87
- /**
88
- * Process any pending finishes for a span that was just registered.
89
- */
123
+ };
90
124
  async processPendingFinishes(spanId) {
125
+ if (!this.pendingFinishes.has(spanId)) {
126
+ return;
127
+ }
91
128
  const pendingEndTime = this.pendingFinishes.get(spanId);
92
- if (!pendingEndTime) {
129
+ if (pendingEndTime === undefined) {
93
130
  return;
94
131
  }
95
132
  try {
@@ -101,71 +138,36 @@ export class HttpTransport {
101
138
  logger.error('Error processing pending span finish:', error);
102
139
  }
103
140
  }
104
- /**
105
- * Send a span to the API
106
- */
107
- async sendSpan(span, retry = 0) {
108
- const url = `${this.config.apiUrl}/api/v1/agent_spans`;
141
+ async sendSpan(span) {
109
142
  const payload = this.transformSpanToApiFormat(span);
110
143
  try {
111
- const response = await fetch(url, {
112
- method: 'POST',
113
- headers: {
114
- Authorization: `Bearer ${this.config.apiToken}`,
115
- 'Content-Type': 'application/json',
116
- },
117
- body: JSON.stringify(payload),
118
- signal: AbortSignal.timeout(this.config.requestTimeout),
119
- });
120
- if (response.ok) {
121
- const data = (await response.json());
122
- const backendSpanId = data?.details?.id;
123
- if (backendSpanId) {
124
- this.spanIdMap.set(span.spanId, backendSpanId);
125
- // Process any pending finishes that arrived before this span_end
126
- await this.processPendingFinishes(span.spanId);
127
- }
144
+ const response = await this.agentSpanClient.create(payload);
145
+ const backendSpanId = response.details?.id;
146
+ if (!backendSpanId) {
128
147
  return;
129
148
  }
130
- // Retry on server errors or rate limiting
131
- if ((response.status >= 500 || response.status === 429) && retry < this.config.maxRetries) {
132
- const delay = Math.min(this.config.initialRetryDelay * this.config.retryMultiplier ** retry, this.config.maxRetryDelay);
133
- logger.debug(`Retrying span send after ${delay}ms (attempt ${retry + 1})`);
134
- await new Promise((resolve) => setTimeout(resolve, delay));
135
- return this.sendSpan(span, retry + 1);
136
- }
137
- logger.error(`Failed to send span: ${response.status} ${response.statusText}`);
149
+ this.spanIdMap.set(span.spanId, backendSpanId);
150
+ await this.processPendingFinishes(span.spanId);
138
151
  }
139
152
  catch (error) {
140
153
  logger.error('Error sending span:', error);
141
- // Retry on network errors
142
- if (retry < this.config.maxRetries) {
143
- const delay = Math.min(this.config.initialRetryDelay * this.config.retryMultiplier ** retry, this.config.maxRetryDelay);
144
- await new Promise((resolve) => setTimeout(resolve, delay));
145
- return this.sendSpan(span, retry + 1);
146
- }
147
154
  }
148
155
  }
149
- /**
150
- * Transform span to backend API format with nested details/payload structure
151
- */
152
156
  transformSpanToApiFormat(span) {
153
157
  const startedAt = new Date(span.startTime).toISOString();
154
158
  const finishedAt = span.endTime ? new Date(span.endTime).toISOString() : null;
155
- // Build payload with span data
159
+ const apiStatus = this.mapStatusForApi(span.status);
156
160
  const payload = {
157
161
  span_id: span.spanId,
158
162
  trace_id: span.traceId,
159
163
  name: span.name,
160
- status: span.status,
164
+ status: apiStatus,
161
165
  inputs: span.inputs,
162
166
  outputs: span.outputs,
163
167
  metadata: span.metadata,
164
- tags: span.tags,
165
168
  token_usage: null,
166
169
  error: null,
167
170
  };
168
- // Add optional token_usage
169
171
  if (span.tokenUsage) {
170
172
  payload.token_usage = {
171
173
  prompt_tokens: span.tokenUsage.promptTokens,
@@ -173,7 +175,6 @@ export class HttpTransport {
173
175
  total_tokens: span.tokenUsage.totalTokens,
174
176
  };
175
177
  }
176
- // Add optional error
177
178
  if (span.error) {
178
179
  payload.error = {
179
180
  error_type: span.error.errorType,
@@ -181,12 +182,12 @@ export class HttpTransport {
181
182
  stacktrace: span.error.stacktrace,
182
183
  };
183
184
  }
184
- // Resolve parent span ID to backend ID
185
185
  const parentSpanId = span.parentSpanId ? (this.spanIdMap.get(span.parentSpanId) ?? null) : null;
186
186
  return {
187
187
  details: {
188
188
  agent_instance_id: this.agentInstanceId,
189
189
  schema_name: span.spanType,
190
+ status: apiStatus,
190
191
  payload,
191
192
  parent_span_id: parentSpanId,
192
193
  started_at: startedAt,
@@ -194,20 +195,22 @@ export class HttpTransport {
194
195
  },
195
196
  };
196
197
  }
197
- /**
198
- * Get default schema (v1.0.0) with span schemas for all supported types
199
- */
200
- getDefaultSchema() {
201
- return DEFAULT_AGENT_SCHEMA;
198
+ mapStatusForApi(status) {
199
+ switch (status) {
200
+ case 'running':
201
+ return 'active';
202
+ case 'success':
203
+ return 'complete';
204
+ case 'error':
205
+ return 'failed';
206
+ default:
207
+ return 'active';
208
+ }
202
209
  }
203
- /**
204
- * Ensure an agent instance is registered
205
- */
206
210
  async ensureAgentRegistered() {
207
211
  if (this.agentInstanceId) {
208
- return;
212
+ return true;
209
213
  }
210
- const url = `${this.config.apiUrl}/api/v1/agent_instance/register`;
211
214
  const payload = {};
212
215
  if (this.config.agentId)
213
216
  payload.agent_id = this.config.agentId;
@@ -218,148 +221,56 @@ export class HttpTransport {
218
221
  description: this.config.agentDescription || '',
219
222
  };
220
223
  }
221
- // Schema handling - four modes:
222
- // 1. skipSchema=true: No schema in payload (pre-registered on backend)
223
- // 2. agentSchema provided: Use full custom schema object
224
- // 3. agentSchemaIdentifier provided: Use version identifier only
225
- if (this.config.skipSchema) {
226
- logger.debug('Skipping schema in registration (skipSchema=true)');
227
- // Do not add agent_schema_version key
228
- }
229
- else if (this.config.agentSchema) {
230
- logger.debug('Using custom agent schema');
224
+ if (this.config.agentSchema) {
231
225
  payload.agent_schema_version = this.config.agentSchema;
232
226
  }
233
- else if (this.config.agentSchemaIdentifier) {
234
- logger.debug(`Using schema version: ${this.config.agentSchemaIdentifier}`);
235
- payload.agent_schema_version = {
236
- external_identifier: this.config.agentSchemaIdentifier,
237
- };
238
- }
239
- else {
240
- logger.debug('Using default hardcoded schema (v1.0.0)');
241
- payload.agent_schema_version = this.getDefaultSchema();
242
- }
243
227
  try {
244
- const response = await fetch(url, {
245
- method: 'POST',
246
- headers: {
247
- Authorization: `Bearer ${this.config.apiToken}`,
248
- 'Content-Type': 'application/json',
249
- },
250
- body: JSON.stringify(payload),
251
- signal: AbortSignal.timeout(this.config.requestTimeout),
252
- });
253
- if (response.ok) {
254
- const data = (await response.json());
255
- this.agentInstanceId = data?.details?.id ?? null;
256
- logger.debug(`Registered agent instance: ${this.agentInstanceId}`);
257
- }
258
- else {
259
- logger.error(`Failed to register agent: ${response.status} ${response.statusText}`);
260
- }
228
+ const data = await this.agentInstanceClient.register(payload);
229
+ this.agentInstanceId = data.details?.id ?? null;
261
230
  }
262
231
  catch (error) {
263
232
  logger.error('Error registering agent:', error);
264
233
  }
234
+ return this.agentInstanceId !== null;
265
235
  }
266
- /**
267
- * Start agent instance execution
268
- */
269
236
  async startAgentInstanceHttp() {
270
- await this.ensureAgentRegistered();
271
- if (!this.agentInstanceId) {
237
+ const isRegistered = await this.ensureAgentRegistered();
238
+ if (!isRegistered || !this.agentInstanceId) {
272
239
  logger.error('Cannot start agent instance: not registered');
273
240
  return;
274
241
  }
275
- const url = `${this.config.apiUrl}/api/v1/agent_instance/${this.agentInstanceId}/start`;
276
242
  try {
277
- const response = await fetch(url, {
278
- method: 'POST',
279
- headers: {
280
- Authorization: `Bearer ${this.config.apiToken}`,
281
- 'Content-Type': 'application/json',
282
- },
283
- body: JSON.stringify({}),
284
- signal: AbortSignal.timeout(this.config.requestTimeout),
285
- });
286
- if (!response.ok) {
287
- logger.error(`Failed to start agent instance: ${response.status} ${response.statusText}`);
288
- }
243
+ await this.agentInstanceClient.start(this.agentInstanceId);
289
244
  }
290
245
  catch (error) {
291
246
  logger.error('Error starting agent instance:', error);
292
247
  }
293
248
  }
294
- /**
295
- * Finish agent instance execution
296
- */
297
249
  async finishAgentInstanceHttp() {
298
250
  if (!this.agentInstanceId) {
299
251
  logger.error('Cannot finish agent instance: not registered');
300
252
  return;
301
253
  }
302
- const url = `${this.config.apiUrl}/api/v1/agent_instance/${this.agentInstanceId}/finish`;
303
254
  try {
304
- const response = await fetch(url, {
305
- method: 'POST',
306
- headers: {
307
- Authorization: `Bearer ${this.config.apiToken}`,
308
- 'Content-Type': 'application/json',
309
- },
310
- body: JSON.stringify({}),
311
- signal: AbortSignal.timeout(this.config.requestTimeout),
312
- });
313
- if (!response.ok) {
314
- logger.error(`Failed to finish agent instance: ${response.status} ${response.statusText}`);
315
- }
255
+ await this.agentInstanceClient.finish(this.agentInstanceId);
316
256
  }
317
257
  catch (error) {
318
258
  logger.error('Error finishing agent instance:', error);
319
259
  }
320
- // Reset so the next agent_start registers a fresh instance
321
260
  this.agentInstanceId = null;
322
261
  }
323
- /**
324
- * Finish a span via HTTP
325
- */
326
262
  async finishSpanHttp(data) {
327
263
  const backendSpanId = this.spanIdMap.get(data.spanId);
328
264
  if (!backendSpanId) {
329
265
  logger.warn(`Cannot finish span ${data.spanId}: backend ID not found`);
330
266
  return;
331
267
  }
332
- const url = `${this.config.apiUrl}/api/v1/agent_spans/${backendSpanId}/finish`;
333
268
  try {
334
- const response = await fetch(url, {
335
- method: 'POST',
336
- headers: {
337
- Authorization: `Bearer ${this.config.apiToken}`,
338
- 'Content-Type': 'application/json',
339
- },
340
- body: JSON.stringify({ timestamp: data.timestamp }),
341
- signal: AbortSignal.timeout(this.config.requestTimeout),
342
- });
343
- if (!response.ok) {
344
- logger.error(`Failed to finish span: ${response.status} ${response.statusText}`);
345
- }
269
+ await this.agentSpanClient.finish(backendSpanId, data.timestamp);
346
270
  }
347
271
  catch (error) {
348
272
  logger.error('Error finishing span:', error);
349
273
  }
350
274
  }
351
- /**
352
- * Close the transport and wait for queue to drain
353
- *
354
- * @returns Promise that resolves when transport is closed
355
- */
356
- async close() {
357
- this.closed = true;
358
- // Log warning for any pending finishes that will never be processed
359
- if (this.pendingFinishes.size > 0) {
360
- logger.warn(`Transport closed with ${this.pendingFinishes.size} pending span finish(es) that could not be processed`);
361
- this.pendingFinishes.clear();
362
- }
363
- }
364
275
  }
365
276
  //# sourceMappingURL=http.js.map