@traccia2/sdk 0.0.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 (130) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +503 -0
  3. package/dist/auto.d.ts +27 -0
  4. package/dist/auto.d.ts.map +1 -0
  5. package/dist/auto.js +171 -0
  6. package/dist/auto.js.map +1 -0
  7. package/dist/config/env-config.d.ts +21 -0
  8. package/dist/config/env-config.d.ts.map +1 -0
  9. package/dist/config/env-config.js +111 -0
  10. package/dist/config/env-config.js.map +1 -0
  11. package/dist/config/pricing-config.d.ts +27 -0
  12. package/dist/config/pricing-config.d.ts.map +1 -0
  13. package/dist/config/pricing-config.js +74 -0
  14. package/dist/config/pricing-config.js.map +1 -0
  15. package/dist/config/runtime-config.d.ts +65 -0
  16. package/dist/config/runtime-config.d.ts.map +1 -0
  17. package/dist/config/runtime-config.js +97 -0
  18. package/dist/config/runtime-config.js.map +1 -0
  19. package/dist/context/context.d.ts +29 -0
  20. package/dist/context/context.d.ts.map +1 -0
  21. package/dist/context/context.js +48 -0
  22. package/dist/context/context.js.map +1 -0
  23. package/dist/exporter/console-exporter.d.ts +18 -0
  24. package/dist/exporter/console-exporter.d.ts.map +1 -0
  25. package/dist/exporter/console-exporter.js +39 -0
  26. package/dist/exporter/console-exporter.js.map +1 -0
  27. package/dist/exporter/http-exporter.d.ts +57 -0
  28. package/dist/exporter/http-exporter.d.ts.map +1 -0
  29. package/dist/exporter/http-exporter.js +181 -0
  30. package/dist/exporter/http-exporter.js.map +1 -0
  31. package/dist/exporter/index.d.ts +7 -0
  32. package/dist/exporter/index.d.ts.map +1 -0
  33. package/dist/exporter/index.js +12 -0
  34. package/dist/exporter/index.js.map +1 -0
  35. package/dist/index.d.ts +10 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +32 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/integrations/index.d.ts +9 -0
  40. package/dist/integrations/index.d.ts.map +1 -0
  41. package/dist/integrations/index.js +16 -0
  42. package/dist/integrations/index.js.map +1 -0
  43. package/dist/integrations/langchain-callback.d.ts +72 -0
  44. package/dist/integrations/langchain-callback.d.ts.map +1 -0
  45. package/dist/integrations/langchain-callback.js +201 -0
  46. package/dist/integrations/langchain-callback.js.map +1 -0
  47. package/dist/integrations/langgraph-instrumentation.d.ts +57 -0
  48. package/dist/integrations/langgraph-instrumentation.d.ts.map +1 -0
  49. package/dist/integrations/langgraph-instrumentation.js +162 -0
  50. package/dist/integrations/langgraph-instrumentation.js.map +1 -0
  51. package/dist/processor/batch-processor.d.ts +68 -0
  52. package/dist/processor/batch-processor.d.ts.map +1 -0
  53. package/dist/processor/batch-processor.js +150 -0
  54. package/dist/processor/batch-processor.js.map +1 -0
  55. package/dist/processor/cost-processor.d.ts +16 -0
  56. package/dist/processor/cost-processor.d.ts.map +1 -0
  57. package/dist/processor/cost-processor.js +50 -0
  58. package/dist/processor/cost-processor.js.map +1 -0
  59. package/dist/processor/index.d.ts +9 -0
  60. package/dist/processor/index.d.ts.map +1 -0
  61. package/dist/processor/index.js +18 -0
  62. package/dist/processor/index.js.map +1 -0
  63. package/dist/processor/logging-processor.d.ts +13 -0
  64. package/dist/processor/logging-processor.d.ts.map +1 -0
  65. package/dist/processor/logging-processor.js +26 -0
  66. package/dist/processor/logging-processor.js.map +1 -0
  67. package/dist/processor/sampler.d.ts +20 -0
  68. package/dist/processor/sampler.d.ts.map +1 -0
  69. package/dist/processor/sampler.js +33 -0
  70. package/dist/processor/sampler.js.map +1 -0
  71. package/dist/processor/token-counter.d.ts +13 -0
  72. package/dist/processor/token-counter.d.ts.map +1 -0
  73. package/dist/processor/token-counter.js +40 -0
  74. package/dist/processor/token-counter.js.map +1 -0
  75. package/dist/tracer/index.d.ts +8 -0
  76. package/dist/tracer/index.d.ts.map +1 -0
  77. package/dist/tracer/index.js +15 -0
  78. package/dist/tracer/index.js.map +1 -0
  79. package/dist/tracer/provider.d.ts +59 -0
  80. package/dist/tracer/provider.d.ts.map +1 -0
  81. package/dist/tracer/provider.js +114 -0
  82. package/dist/tracer/provider.js.map +1 -0
  83. package/dist/tracer/span-context.d.ts +23 -0
  84. package/dist/tracer/span-context.d.ts.map +1 -0
  85. package/dist/tracer/span-context.js +34 -0
  86. package/dist/tracer/span-context.js.map +1 -0
  87. package/dist/tracer/span.d.ts +49 -0
  88. package/dist/tracer/span.d.ts.map +1 -0
  89. package/dist/tracer/span.js +118 -0
  90. package/dist/tracer/span.js.map +1 -0
  91. package/dist/tracer/tracer.d.ts +28 -0
  92. package/dist/tracer/tracer.d.ts.map +1 -0
  93. package/dist/tracer/tracer.js +75 -0
  94. package/dist/tracer/tracer.js.map +1 -0
  95. package/dist/types.d.ts +135 -0
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +16 -0
  98. package/dist/types.js.map +1 -0
  99. package/package.json +79 -0
  100. package/src/__tests__/exporter.test.ts +62 -0
  101. package/src/__tests__/integrations-langchain.test.ts +384 -0
  102. package/src/__tests__/integrations-langgraph.test.ts +479 -0
  103. package/src/__tests__/processor.test.ts +89 -0
  104. package/src/__tests__/span.test.ts +103 -0
  105. package/src/__tests__/tracer.test.ts +89 -0
  106. package/src/auto.ts +198 -0
  107. package/src/config/env-config.ts +93 -0
  108. package/src/config/pricing-config.ts +84 -0
  109. package/src/config/runtime-config.ts +108 -0
  110. package/src/context/context.ts +52 -0
  111. package/src/exporter/console-exporter.ts +38 -0
  112. package/src/exporter/http-exporter.ts +188 -0
  113. package/src/exporter/index.ts +7 -0
  114. package/src/index.ts +51 -0
  115. package/src/integrations/README.md +287 -0
  116. package/src/integrations/index.ts +13 -0
  117. package/src/integrations/langchain-callback.ts +229 -0
  118. package/src/integrations/langgraph-instrumentation.ts +174 -0
  119. package/src/processor/batch-processor.ts +180 -0
  120. package/src/processor/cost-processor.ts +57 -0
  121. package/src/processor/index.ts +9 -0
  122. package/src/processor/logging-processor.ts +26 -0
  123. package/src/processor/sampler.ts +35 -0
  124. package/src/processor/token-counter.ts +42 -0
  125. package/src/tracer/index.ts +8 -0
  126. package/src/tracer/provider.ts +130 -0
  127. package/src/tracer/span-context.ts +46 -0
  128. package/src/tracer/span.ts +145 -0
  129. package/src/tracer/tracer.ts +100 -0
  130. package/src/types.ts +155 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Tests for tracer and provider.
3
+ */
4
+
5
+ import { TracerProvider } from '../tracer/provider';
6
+ import { Sampler } from '../processor/sampler';
7
+
8
+ describe('TracerProvider', () => {
9
+ it('should create and cache tracers', () => {
10
+ const provider = new TracerProvider();
11
+ const tracer1 = provider.getTracer('scope1');
12
+ const tracer2 = provider.getTracer('scope1');
13
+
14
+ expect(tracer1).toBe(tracer2);
15
+ });
16
+
17
+ it('should support multiple tracers', () => {
18
+ const provider = new TracerProvider();
19
+ const tracer1 = provider.getTracer('scope1');
20
+ const tracer2 = provider.getTracer('scope2');
21
+
22
+ expect(tracer1).not.toBe(tracer2);
23
+ });
24
+
25
+ it('should set and get sampler', () => {
26
+ const provider = new TracerProvider();
27
+ const sampler = new Sampler(0.5);
28
+
29
+ provider.setSampler(sampler);
30
+ expect(provider.getSampler()).toBe(sampler);
31
+ });
32
+
33
+ it('should generate unique IDs', () => {
34
+ const provider = new TracerProvider();
35
+ const traceId1 = provider.generateTraceId();
36
+ const traceId2 = provider.generateTraceId();
37
+
38
+ expect(traceId1).not.toBe(traceId2);
39
+ expect(traceId1).toHaveLength(32);
40
+ expect(traceId2).toHaveLength(32);
41
+ });
42
+ });
43
+
44
+ describe('Tracer', () => {
45
+ let provider: TracerProvider;
46
+
47
+ beforeEach(() => {
48
+ provider = new TracerProvider();
49
+ });
50
+
51
+ it('should create spans', () => {
52
+ const tracer = provider.getTracer('test');
53
+ const span = tracer.startSpan('test-span');
54
+
55
+ expect(span.name).toBe('test-span');
56
+ expect(span.context.traceId).toBeTruthy();
57
+ expect(span.context.spanId).toBeTruthy();
58
+ });
59
+
60
+ it('should create child spans', () => {
61
+ const tracer = provider.getTracer('test');
62
+ const parent = tracer.startSpan('parent');
63
+ const child = tracer.startSpan('child', { parent });
64
+
65
+ expect(child.context.traceId).toBe(parent.context.traceId);
66
+ expect(child.parentSpanId).toBe(parent.context.spanId);
67
+ });
68
+
69
+ it('should respect sampling', () => {
70
+ const provider2 = new TracerProvider();
71
+ const sampler = new Sampler(0); // Never sample
72
+ provider2.setSampler(sampler);
73
+
74
+ const tracer = provider2.getTracer('test');
75
+ const span = tracer.startSpan('test-span');
76
+
77
+ expect(span.context.traceFlags).toBe(0);
78
+ });
79
+
80
+ it('should support active spans', async () => {
81
+ const tracer = provider.getTracer('test');
82
+ const result = await tracer.startActiveSpan('active-span', async (span) => {
83
+ span.setAttribute('test', 'value');
84
+ return 'result';
85
+ });
86
+
87
+ expect(result).toBe('result');
88
+ });
89
+ });
package/src/auto.ts ADDED
@@ -0,0 +1,198 @@
1
+ /**
2
+ * SDK initialization and global tracer management.
3
+ */
4
+
5
+ import { TracerProvider } from './tracer/provider';
6
+ import { BatchSpanProcessor } from './processor/batch-processor';
7
+ import { Sampler } from './processor/sampler';
8
+ import { TokenCountingProcessor } from './processor/token-counter';
9
+ import { CostAnnotatingProcessor } from './processor/cost-processor';
10
+ import { LoggingSpanProcessor } from './processor/logging-processor';
11
+ import { HttpExporter, DEFAULT_ENDPOINT } from './exporter/http-exporter';
12
+ import { ConsoleExporter } from './exporter/console-exporter';
13
+ import { loadEnvFile, loadEnvConfig, findAgentConfigPath } from './config/env-config';
14
+ import { loadPricingWithSource } from './config/pricing-config';
15
+ import {
16
+ updateConfig,
17
+ setSessionId,
18
+ setUserId,
19
+ setTenantId,
20
+ setProjectId,
21
+ } from './config/runtime-config';
22
+ import { SDKConfig, ISpanExporter, ITracer } from './types';
23
+
24
+ let globalProvider: TracerProvider | null = null;
25
+ let started = false;
26
+
27
+ /**
28
+ * Get the global tracer provider.
29
+ */
30
+ export function getTracerProvider(): TracerProvider {
31
+ if (!globalProvider) {
32
+ globalProvider = new TracerProvider();
33
+ }
34
+ return globalProvider;
35
+ }
36
+
37
+ /**
38
+ * Set the global tracer provider.
39
+ */
40
+ export function setTracerProvider(provider: TracerProvider): void {
41
+ globalProvider = provider;
42
+ }
43
+
44
+ /**
45
+ * Get a tracer from the global provider.
46
+ */
47
+ export function getTracer(name: string, version?: string): ITracer {
48
+ return getTracerProvider().getTracer(name, version);
49
+ }
50
+
51
+ /**
52
+ * Initialize tracing with automatic setup.
53
+ */
54
+ export async function startTracing(config: SDKConfig = {}): Promise<TracerProvider> {
55
+ if (started) {
56
+ return getTracerProvider();
57
+ }
58
+
59
+ started = true;
60
+
61
+ // Load environment
62
+ if (config.loadEnv !== false) {
63
+ loadEnvFile();
64
+ }
65
+
66
+ const overrides: Record<string, string> = {};
67
+ if (config.apiKey) overrides.apiKey = config.apiKey;
68
+ if (config.endpoint) overrides.endpoint = config.endpoint;
69
+ if (config.sampleRate !== undefined) overrides.sampleRate = config.sampleRate.toString();
70
+
71
+ const envConfig = loadEnvConfig(overrides);
72
+
73
+ // Find agent config
74
+ const agentConfigPath = findAgentConfigPath();
75
+ if (agentConfigPath) {
76
+ process.env.AGENT_DASHBOARD_AGENT_CONFIG = agentConfigPath;
77
+ }
78
+
79
+ // Set up runtime config
80
+ updateConfig({
81
+ autoInstrumentTools: config.autoInstrument ?? false,
82
+ toolInclude: config.toolInclude || [],
83
+ maxToolSpans: config.maxToolSpans ?? 100,
84
+ maxSpanDepth: config.maxSpanDepth ?? 10,
85
+ debug: config.debug ?? false,
86
+ attrTruncationLimit: config.attrTruncationLimit,
87
+ });
88
+
89
+ setSessionId(config.sessionId);
90
+ setUserId(config.userId);
91
+ setTenantId(config.tenantId);
92
+ setProjectId(config.projectId);
93
+
94
+ // Get or create provider
95
+ const provider = getTracerProvider();
96
+
97
+ // Set sampler
98
+ const sampleRate = config.sampleRate ?? (envConfig.sampleRate || 1.0);
99
+ const sampler = new Sampler(Math.min(1, Math.max(0, sampleRate)));
100
+ provider.setSampler(sampler);
101
+
102
+ // Create exporter
103
+ const apiKey = config.apiKey || envConfig.apiKey || '';
104
+ const endpoint = config.endpoint || envConfig.endpoint || DEFAULT_ENDPOINT;
105
+ let exporter: ISpanExporter = new HttpExporter({
106
+ endpoint,
107
+ apiKey,
108
+ });
109
+
110
+ if (config.enableConsoleExporter) {
111
+ const consoleExporter = new ConsoleExporter();
112
+ exporter = new CompositeExporter([exporter, consoleExporter]);
113
+ }
114
+
115
+ // Add processors
116
+ if (config.enableTokenCounting !== false) {
117
+ provider.addSpanProcessor(new TokenCountingProcessor());
118
+ }
119
+
120
+ if (config.enableCostTracking !== false) {
121
+ const pricingTable = config.pricingOverride
122
+ ? (config.pricingOverride as Record<string, { inputCost: number; outputCost: number }>)
123
+ : undefined;
124
+ const [pricing] = await loadPricingWithSource(pricingTable);
125
+ provider.addSpanProcessor(new CostAnnotatingProcessor(pricing));
126
+ }
127
+
128
+ if (config.enableSpanLogging) {
129
+ provider.addSpanProcessor(new LoggingSpanProcessor());
130
+ }
131
+
132
+ // Add batch processor with exporter
133
+ const processor = new BatchSpanProcessor({
134
+ exporter,
135
+ maxQueueSize: config.maxQueueSize ?? 5000,
136
+ maxExportBatchSize: config.maxExportBatchSize ?? 512,
137
+ scheduleDelayMs: config.scheduleDelayMs ?? 5000,
138
+ sampler,
139
+ });
140
+
141
+ provider.addSpanProcessor(processor);
142
+ registerShutdown(provider, processor);
143
+
144
+ return provider;
145
+ }
146
+
147
+ /**
148
+ * Stop tracing and shutdown all processors.
149
+ */
150
+ export async function stopTracing(): Promise<void> {
151
+ if (!globalProvider) {
152
+ return;
153
+ }
154
+
155
+ await globalProvider.shutdown();
156
+ started = false;
157
+ globalProvider = null;
158
+ }
159
+
160
+ /**
161
+ * Register shutdown hooks.
162
+ */
163
+ function registerShutdown(provider: TracerProvider, _processor: BatchSpanProcessor): void {
164
+ const shutdown = async (): Promise<void> => {
165
+ try {
166
+ await provider.shutdown();
167
+ } catch {
168
+ // Silently fail
169
+ }
170
+ };
171
+
172
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
173
+ process.on('SIGTERM', shutdown);
174
+ // eslint-disable-next-line @typescript-eslint/no-misused-promises
175
+ process.on('SIGINT', shutdown);
176
+ }
177
+
178
+ /**
179
+ * Composite exporter combining multiple exporters.
180
+ */
181
+ class CompositeExporter implements ISpanExporter {
182
+ private exporters: ISpanExporter[];
183
+
184
+ public constructor(exporters: ISpanExporter[]) {
185
+ this.exporters = exporters;
186
+ }
187
+
188
+ public async export(spans: any[]): Promise<boolean> {
189
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-argument
190
+ const results = await Promise.all(this.exporters.map((e) => e.export(spans)));
191
+ return results.every((r) => r);
192
+ }
193
+
194
+ public async shutdown(): Promise<void> {
195
+ await Promise.all(this.exporters.map((e) => e.shutdown()));
196
+ }
197
+ }
198
+ export { getTracerProvider as initSDK };
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Environment configuration loading.
3
+ */
4
+
5
+ import * as fs from 'fs';
6
+ import * as path from 'path';
7
+
8
+ /**
9
+ * Load .env file into process.env.
10
+ */
11
+ export function loadEnvFile(envPath: string = '.env'): void {
12
+ if (!fs.existsSync(envPath)) {
13
+ return;
14
+ }
15
+
16
+ try {
17
+ const content = fs.readFileSync(envPath, 'utf-8');
18
+ const lines = content.split('\n');
19
+
20
+ for (const line of lines) {
21
+ const trimmed = line.trim();
22
+ if (!trimmed || trimmed.startsWith('#')) {
23
+ continue;
24
+ }
25
+
26
+ const eqIndex = trimmed.indexOf('=');
27
+ if (eqIndex === -1) {
28
+ continue;
29
+ }
30
+
31
+ const key = trimmed.substring(0, eqIndex).trim();
32
+ const value = trimmed.substring(eqIndex + 1).trim().replace(/^["']|["']$/g, '');
33
+
34
+ if (key && !(key in process.env)) {
35
+ process.env[key] = value;
36
+ }
37
+ }
38
+ } catch {
39
+ // Silently fail; best-effort loading
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Load configuration from environment variables.
45
+ */
46
+ export interface EnvConfig {
47
+ apiKey?: string;
48
+ endpoint?: string;
49
+ sampleRate?: number;
50
+ }
51
+
52
+ export function loadEnvConfig(overrides?: Record<string, string>): EnvConfig {
53
+ const config: EnvConfig = {
54
+ apiKey: process.env.AGENT_DASHBOARD_API_KEY,
55
+ endpoint: process.env.AGENT_DASHBOARD_ENDPOINT,
56
+ sampleRate: process.env.AGENT_DASHBOARD_SAMPLE_RATE
57
+ ? parseFloat(process.env.AGENT_DASHBOARD_SAMPLE_RATE)
58
+ : undefined,
59
+ };
60
+
61
+ if (overrides) {
62
+ if (overrides.apiKey !== undefined) {
63
+ config.apiKey = overrides.apiKey;
64
+ }
65
+ if (overrides.endpoint !== undefined) {
66
+ config.endpoint = overrides.endpoint;
67
+ }
68
+ if (overrides.sampleRate !== undefined) {
69
+ config.sampleRate = parseFloat(overrides.sampleRate);
70
+ }
71
+ }
72
+
73
+ return config;
74
+ }
75
+
76
+ /**
77
+ * Find agent config file automatically.
78
+ */
79
+ export function findAgentConfigPath(): string | undefined {
80
+ const candidates = [
81
+ './agent_config.json',
82
+ './agent-config.json',
83
+ './.config/agent_config.json',
84
+ ];
85
+
86
+ for (const candidate of candidates) {
87
+ if (fs.existsSync(candidate)) {
88
+ return path.resolve(candidate);
89
+ }
90
+ }
91
+
92
+ return undefined;
93
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Pricing configuration management.
3
+ */
4
+
5
+ export interface PricingTable {
6
+ [model: string]: {
7
+ inputCost: number;
8
+ outputCost: number;
9
+ };
10
+ }
11
+
12
+ export type PricingSource = 'default' | 'env' | 'override';
13
+
14
+ /**
15
+ * Default pricing table.
16
+ */
17
+ export const DEFAULT_PRICING: PricingTable = {
18
+ 'gpt-3.5-turbo': {
19
+ inputCost: 0.0005,
20
+ outputCost: 0.0015,
21
+ },
22
+ 'gpt-4': {
23
+ inputCost: 0.03,
24
+ outputCost: 0.06,
25
+ },
26
+ 'gpt-4-turbo': {
27
+ inputCost: 0.01,
28
+ outputCost: 0.03,
29
+ },
30
+ 'claude-2': {
31
+ inputCost: 0.008,
32
+ outputCost: 0.024,
33
+ },
34
+ 'claude-3-opus': {
35
+ inputCost: 0.015,
36
+ outputCost: 0.075,
37
+ },
38
+ };
39
+
40
+ /**
41
+ * Fetch remote pricing (placeholder).
42
+ */
43
+ export function fetchRemotePricing(): Promise<PricingTable> {
44
+ // In production, this would fetch from a backend service
45
+ return Promise.resolve(DEFAULT_PRICING);
46
+ }
47
+
48
+ /**
49
+ * Load pricing configuration with source tracking.
50
+ */
51
+ export function loadPricingWithSource(
52
+ override?: PricingTable
53
+ ): Promise<[PricingTable, PricingSource]> {
54
+ let pricing = { ...DEFAULT_PRICING };
55
+ let source: PricingSource = 'default';
56
+
57
+ const envOverride = process.env.AGENT_DASHBOARD_PRICING_JSON;
58
+ if (envOverride) {
59
+ try {
60
+ const envPricing = JSON.parse(envOverride) as PricingTable;
61
+ if (typeof envPricing === 'object') {
62
+ pricing = { ...pricing, ...envPricing };
63
+ source = 'env';
64
+ }
65
+ } catch {
66
+ // Ignore parsing errors
67
+ }
68
+ }
69
+
70
+ if (override) {
71
+ pricing = { ...pricing, ...override };
72
+ source = 'override';
73
+ }
74
+
75
+ return Promise.resolve([pricing, source]);
76
+ }
77
+
78
+ /**
79
+ * Load pricing configuration.
80
+ */
81
+ export async function loadPricing(override?: PricingTable): Promise<PricingTable> {
82
+ const [pricing] = await loadPricingWithSource(override);
83
+ return pricing;
84
+ }
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Runtime configuration management.
3
+ */
4
+
5
+ interface RuntimeConfig {
6
+ autoInstrumentTools: boolean;
7
+ toolInclude: string[];
8
+ maxToolSpans: number;
9
+ maxSpanDepth: number;
10
+ sessionId?: string;
11
+ userId?: string;
12
+ tenantId?: string;
13
+ projectId?: string;
14
+ debug: boolean;
15
+ attrTruncationLimit?: number;
16
+ }
17
+
18
+ let config: RuntimeConfig = {
19
+ autoInstrumentTools: false,
20
+ toolInclude: [],
21
+ maxToolSpans: 100,
22
+ maxSpanDepth: 10,
23
+ debug: false,
24
+ };
25
+
26
+ /**
27
+ * Get the current runtime configuration.
28
+ */
29
+ export function getConfig(): RuntimeConfig {
30
+ return config;
31
+ }
32
+
33
+ /**
34
+ * Update the runtime configuration.
35
+ */
36
+ export function updateConfig(partial: Partial<RuntimeConfig>): void {
37
+ config = { ...config, ...partial };
38
+ }
39
+
40
+ /**
41
+ * Set auto-instrument tools flag.
42
+ */
43
+ export function setAutoInstrumentTools(value: boolean): void {
44
+ config.autoInstrumentTools = value;
45
+ }
46
+
47
+ /**
48
+ * Set tool include list.
49
+ */
50
+ export function setToolInclude(tools: string[]): void {
51
+ config.toolInclude = tools;
52
+ }
53
+
54
+ /**
55
+ * Set max tool spans.
56
+ */
57
+ export function setMaxToolSpans(max: number): void {
58
+ config.maxToolSpans = max;
59
+ }
60
+
61
+ /**
62
+ * Set max span depth.
63
+ */
64
+ export function setMaxSpanDepth(max: number): void {
65
+ config.maxSpanDepth = max;
66
+ }
67
+
68
+ /**
69
+ * Set session ID.
70
+ */
71
+ export function setSessionId(id?: string): void {
72
+ config.sessionId = id;
73
+ }
74
+
75
+ /**
76
+ * Set user ID.
77
+ */
78
+ export function setUserId(id?: string): void {
79
+ config.userId = id;
80
+ }
81
+
82
+ /**
83
+ * Set tenant ID.
84
+ */
85
+ export function setTenantId(id?: string): void {
86
+ config.tenantId = id;
87
+ }
88
+
89
+ /**
90
+ * Set project ID.
91
+ */
92
+ export function setProjectId(id?: string): void {
93
+ config.projectId = id;
94
+ }
95
+
96
+ /**
97
+ * Set debug flag.
98
+ */
99
+ export function setDebug(value: boolean): void {
100
+ config.debug = value;
101
+ }
102
+
103
+ /**
104
+ * Set attribute truncation limit.
105
+ */
106
+ export function setAttrTruncationLimit(limit?: number): void {
107
+ config.attrTruncationLimit = limit;
108
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Context management for spans using async local storage.
3
+ */
4
+
5
+ import { AsyncLocalStorage } from 'async_hooks';
6
+ import { ISpan } from '../types';
7
+
8
+ interface SpanContext {
9
+ span?: ISpan;
10
+ }
11
+
12
+ const spanContext = new AsyncLocalStorage<SpanContext>();
13
+
14
+ /**
15
+ * Get the current span from context.
16
+ */
17
+ export function getCurrentSpan(): ISpan | undefined {
18
+ const ctx = spanContext.getStore();
19
+ return ctx?.span;
20
+ }
21
+
22
+ /**
23
+ * Set the current span in context.
24
+ */
25
+ export function setCurrentSpan(span: ISpan | undefined): void {
26
+ const ctx = spanContext.getStore() || {};
27
+ ctx.span = span;
28
+ if (ctx) {
29
+ spanContext.enterWith(ctx);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Run a function with a specific span as the current span.
35
+ */
36
+ export function runWithSpan<T>(span: ISpan, fn: () => T): T {
37
+ return spanContext.run({ span }, fn);
38
+ }
39
+
40
+ /**
41
+ * Run a function with a specific span as the current span (async).
42
+ */
43
+ export function runWithSpanAsync<T>(span: ISpan, fn: () => Promise<T>): Promise<T> {
44
+ return spanContext.run({ span }, fn);
45
+ }
46
+
47
+ /**
48
+ * Get the current context store.
49
+ */
50
+ export function getContext(): SpanContext {
51
+ return spanContext.getStore() || {};
52
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Console Exporter for debugging purposes.
3
+ */
4
+
5
+ import { ISpan, ISpanExporter } from '../types';
6
+
7
+ /**
8
+ * Console Exporter for printing spans to console.
9
+ */
10
+ export class ConsoleExporter implements ISpanExporter {
11
+ /**
12
+ * Export spans to console.
13
+ */
14
+ public export(spans: ISpan[]): Promise<boolean> {
15
+ for (const span of spans) {
16
+ console.log('=== Span ===');
17
+ console.log(`Name: ${span.name}`);
18
+ console.log(`TraceId: ${span.context.traceId}`);
19
+ console.log(`SpanId: ${span.context.spanId}`);
20
+ console.log(`ParentSpanId: ${span.parentSpanId || 'none'}`);
21
+ console.log(`Duration: ${span.durationNs}ns`);
22
+ console.log(`Status: ${span.status}`);
23
+ if (span.statusDescription) {
24
+ console.log(`Status Description: ${span.statusDescription}`);
25
+ }
26
+ console.log('Attributes:', span.attributes);
27
+ console.log('Events:', span.events);
28
+ }
29
+ return Promise.resolve(true);
30
+ }
31
+
32
+ /**
33
+ * Shutdown the exporter.
34
+ */
35
+ public async shutdown(): Promise<void> {
36
+ // No-op
37
+ }
38
+ }