risicare 0.1.0 → 0.1.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/index.cjs +225 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -2
- package/dist/index.d.ts +27 -2
- package/dist/index.js +223 -68
- package/dist/index.js.map +1 -1
- package/dist/providers/anthropic/index.cjs +23 -7
- package/dist/providers/anthropic/index.cjs.map +1 -1
- package/dist/providers/anthropic/index.js +23 -7
- package/dist/providers/anthropic/index.js.map +1 -1
- package/dist/providers/openai/index.cjs +23 -6
- package/dist/providers/openai/index.cjs.map +1 -1
- package/dist/providers/openai/index.js +23 -6
- package/dist/providers/openai/index.js.map +1 -1
- package/dist/providers/vercel-ai/index.cjs +27 -9
- package/dist/providers/vercel-ai/index.cjs.map +1 -1
- package/dist/providers/vercel-ai/index.js +27 -9
- package/dist/providers/vercel-ai/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,8 @@ interface RisicareConfig {
|
|
|
31
31
|
maxQueueSize?: number;
|
|
32
32
|
/** Enable debug logging (default: false) */
|
|
33
33
|
debug?: boolean;
|
|
34
|
+
/** Enable gzip compression for HTTP exports (default: false) */
|
|
35
|
+
compress?: boolean;
|
|
34
36
|
/** Custom metadata attached to all spans */
|
|
35
37
|
metadata?: Record<string, unknown>;
|
|
36
38
|
}
|
|
@@ -69,7 +71,10 @@ declare enum SemanticPhase {
|
|
|
69
71
|
THINK = "think",
|
|
70
72
|
DECIDE = "decide",
|
|
71
73
|
ACT = "act",
|
|
72
|
-
OBSERVE = "observe"
|
|
74
|
+
OBSERVE = "observe",
|
|
75
|
+
REFLECT = "reflect",
|
|
76
|
+
COMMUNICATE = "communicate",
|
|
77
|
+
COORDINATE = "coordinate"
|
|
73
78
|
}
|
|
74
79
|
declare enum AgentRole {
|
|
75
80
|
ORCHESTRATOR = "orchestrator",
|
|
@@ -241,14 +246,18 @@ interface TracerConfig {
|
|
|
241
246
|
sampleRate?: number;
|
|
242
247
|
/** Whether tracing is enabled */
|
|
243
248
|
enabled?: boolean;
|
|
249
|
+
/** Whether to capture prompt/completion content (default: true) */
|
|
250
|
+
traceContent?: boolean;
|
|
244
251
|
}
|
|
245
252
|
declare class Tracer {
|
|
246
253
|
private _onSpanEnd;
|
|
247
254
|
private _sampleRate;
|
|
248
255
|
private _enabled;
|
|
256
|
+
private _traceContent;
|
|
249
257
|
constructor(config: TracerConfig);
|
|
250
258
|
get enabled(): boolean;
|
|
251
259
|
set enabled(value: boolean);
|
|
260
|
+
get traceContent(): boolean;
|
|
252
261
|
/**
|
|
253
262
|
* Start a span, run the callback within its context, and auto-end on completion.
|
|
254
263
|
*
|
|
@@ -316,6 +325,22 @@ declare function isEnabled(): boolean;
|
|
|
316
325
|
* Get the global tracer instance. Returns undefined if not initialized.
|
|
317
326
|
*/
|
|
318
327
|
declare function getTracer(): Tracer | undefined;
|
|
328
|
+
/**
|
|
329
|
+
* Check whether content tracing (prompt/completion capture) is enabled.
|
|
330
|
+
*/
|
|
331
|
+
declare function getTraceContent(): boolean;
|
|
332
|
+
/**
|
|
333
|
+
* Get SDK metrics: exported spans, dropped spans, failed exports, queue stats.
|
|
334
|
+
* Returns zero-valued metrics if SDK is not initialized.
|
|
335
|
+
*/
|
|
336
|
+
declare function getMetrics(): {
|
|
337
|
+
exportedSpans: number;
|
|
338
|
+
droppedSpans: number;
|
|
339
|
+
failedExports: number;
|
|
340
|
+
queueSize: number;
|
|
341
|
+
queueCapacity: number;
|
|
342
|
+
queueUtilization: number;
|
|
343
|
+
};
|
|
319
344
|
|
|
320
345
|
/**
|
|
321
346
|
* Agent context — identifies which agent is executing.
|
|
@@ -561,4 +586,4 @@ declare function registerSpan(span: Span, ttlMs?: number): void;
|
|
|
561
586
|
declare function getSpanById(spanId: string): Span | undefined;
|
|
562
587
|
declare function unregisterSpan(spanId: string): void;
|
|
563
588
|
|
|
564
|
-
export { type AgentContext, type AgentOptions, AgentRole, MessageType, type RisicareConfig, SemanticPhase, type SessionContext, type SessionOptions, Span, SpanKind, type SpanOptions, SpanStatus, type StartSpanOptions, type TraceContext, Tracer, agent, disable, enable, extractTraceContext, flush, getCurrentAgent, getCurrentAgentId, getCurrentContext, getCurrentPhase, getCurrentSession, getCurrentSessionId, getCurrentSpan, getCurrentSpanId, getCurrentTraceId, getSpanById, getTraceContext, getTracer, init, injectTraceContext, isEnabled, registerSpan, session, shutdown, traceAct, traceCoordinate, traceDecide, traceDelegate, traceMessage, traceObserve, traceThink, unregisterSpan, withAgent, withPhase, withSession };
|
|
589
|
+
export { type AgentContext, type AgentOptions, AgentRole, MessageType, type RisicareConfig, SemanticPhase, type SessionContext, type SessionOptions, Span, SpanKind, type SpanOptions, SpanStatus, type StartSpanOptions, type TraceContext, Tracer, agent, disable, enable, extractTraceContext, flush, getCurrentAgent, getCurrentAgentId, getCurrentContext, getCurrentPhase, getCurrentSession, getCurrentSessionId, getCurrentSpan, getCurrentSpanId, getCurrentTraceId, getMetrics, getSpanById, getTraceContent, getTraceContext, getTracer, init, injectTraceContext, isEnabled, registerSpan, session, shutdown, traceAct, traceCoordinate, traceDecide, traceDelegate, traceMessage, traceObserve, traceThink, unregisterSpan, withAgent, withPhase, withSession };
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ function resolveConfig(config) {
|
|
|
11
11
|
const traceContent = config?.traceContent ?? parseBool(env.RISICARE_TRACE_CONTENT, true);
|
|
12
12
|
const sampleRate = config?.sampleRate ?? parseFloat(env.RISICARE_SAMPLE_RATE ?? "1.0");
|
|
13
13
|
const debug2 = config?.debug ?? parseBool(env.RISICARE_DEBUG, false);
|
|
14
|
+
const compress = config?.compress ?? parseBool(env.RISICARE_COMPRESS, false);
|
|
14
15
|
const batchSize = config?.batchSize ?? 100;
|
|
15
16
|
const batchTimeoutMs = config?.batchTimeoutMs ?? 1e3;
|
|
16
17
|
const maxQueueSize = config?.maxQueueSize ?? 1e4;
|
|
@@ -36,6 +37,7 @@ function resolveConfig(config) {
|
|
|
36
37
|
batchTimeoutMs,
|
|
37
38
|
maxQueueSize,
|
|
38
39
|
debug: debug2,
|
|
40
|
+
compress,
|
|
39
41
|
metadata: config?.metadata ?? {}
|
|
40
42
|
};
|
|
41
43
|
}
|
|
@@ -56,7 +58,7 @@ function generateSpanId() {
|
|
|
56
58
|
return randomBytes(8).toString("hex");
|
|
57
59
|
}
|
|
58
60
|
function generateAgentId(prefix) {
|
|
59
|
-
const suffix = randomBytes(
|
|
61
|
+
const suffix = randomBytes(8).toString("hex");
|
|
60
62
|
return prefix ? `${prefix}-${suffix}` : suffix;
|
|
61
63
|
}
|
|
62
64
|
function validateTraceId(id) {
|
|
@@ -98,6 +100,9 @@ var SemanticPhase = /* @__PURE__ */ ((SemanticPhase2) => {
|
|
|
98
100
|
SemanticPhase2["DECIDE"] = "decide";
|
|
99
101
|
SemanticPhase2["ACT"] = "act";
|
|
100
102
|
SemanticPhase2["OBSERVE"] = "observe";
|
|
103
|
+
SemanticPhase2["REFLECT"] = "reflect";
|
|
104
|
+
SemanticPhase2["COMMUNICATE"] = "communicate";
|
|
105
|
+
SemanticPhase2["COORDINATE"] = "coordinate";
|
|
101
106
|
return SemanticPhase2;
|
|
102
107
|
})(SemanticPhase || {});
|
|
103
108
|
var AgentRole = /* @__PURE__ */ ((AgentRole2) => {
|
|
@@ -373,16 +378,58 @@ function shouldSample(traceId, sampleRate) {
|
|
|
373
378
|
return hash / 4294967295 < sampleRate;
|
|
374
379
|
}
|
|
375
380
|
|
|
376
|
-
// src/
|
|
381
|
+
// src/globals.ts
|
|
377
382
|
import { AsyncLocalStorage } from "async_hooks";
|
|
378
|
-
var
|
|
383
|
+
var G = globalThis;
|
|
384
|
+
var PREFIX = "__risicare_";
|
|
385
|
+
function getClient() {
|
|
386
|
+
return G[PREFIX + "client"];
|
|
387
|
+
}
|
|
388
|
+
function setClient(client) {
|
|
389
|
+
G[PREFIX + "client"] = client;
|
|
390
|
+
}
|
|
391
|
+
function getTracer() {
|
|
392
|
+
return G[PREFIX + "tracer"];
|
|
393
|
+
}
|
|
394
|
+
function setTracer(tracer) {
|
|
395
|
+
G[PREFIX + "tracer"] = tracer;
|
|
396
|
+
}
|
|
397
|
+
function getContextStorage() {
|
|
398
|
+
if (!G[PREFIX + "ctx"]) {
|
|
399
|
+
G[PREFIX + "ctx"] = new AsyncLocalStorage();
|
|
400
|
+
}
|
|
401
|
+
return G[PREFIX + "ctx"];
|
|
402
|
+
}
|
|
403
|
+
function getRegistry() {
|
|
404
|
+
if (!G[PREFIX + "registry"]) {
|
|
405
|
+
G[PREFIX + "registry"] = /* @__PURE__ */ new Map();
|
|
406
|
+
}
|
|
407
|
+
return G[PREFIX + "registry"];
|
|
408
|
+
}
|
|
409
|
+
function getOpCount() {
|
|
410
|
+
return G[PREFIX + "opcount"] ?? 0;
|
|
411
|
+
}
|
|
412
|
+
function setOpCount(n) {
|
|
413
|
+
G[PREFIX + "opcount"] = n;
|
|
414
|
+
}
|
|
415
|
+
function getDebug() {
|
|
416
|
+
return G[PREFIX + "debug"] ?? false;
|
|
417
|
+
}
|
|
418
|
+
function setDebugFlag(enabled) {
|
|
419
|
+
G[PREFIX + "debug"] = enabled;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// src/context/storage.ts
|
|
423
|
+
function storage() {
|
|
424
|
+
return getContextStorage();
|
|
425
|
+
}
|
|
379
426
|
function getContext() {
|
|
380
|
-
return
|
|
427
|
+
return storage().getStore() ?? {};
|
|
381
428
|
}
|
|
382
429
|
function runWithContext(overrides, fn) {
|
|
383
430
|
const parent = getContext();
|
|
384
431
|
const merged = { ...parent, ...overrides };
|
|
385
|
-
return
|
|
432
|
+
return storage().run(merged, fn);
|
|
386
433
|
}
|
|
387
434
|
function getCurrentSession() {
|
|
388
435
|
return getContext().session;
|
|
@@ -411,8 +458,22 @@ function getCurrentSpanId() {
|
|
|
411
458
|
function getCurrentContext() {
|
|
412
459
|
const ctx = getContext();
|
|
413
460
|
return {
|
|
414
|
-
session: ctx.session ? {
|
|
415
|
-
|
|
461
|
+
session: ctx.session ? {
|
|
462
|
+
sessionId: ctx.session.sessionId,
|
|
463
|
+
userId: ctx.session.userId,
|
|
464
|
+
...ctx.session.parentSessionId !== void 0 ? { parentSessionId: ctx.session.parentSessionId } : {},
|
|
465
|
+
...ctx.session.turnNumber !== void 0 ? { turnNumber: ctx.session.turnNumber } : {},
|
|
466
|
+
...ctx.session.metadata !== void 0 ? { metadata: ctx.session.metadata } : {}
|
|
467
|
+
} : null,
|
|
468
|
+
agent: ctx.agent ? {
|
|
469
|
+
agentId: ctx.agent.agentId,
|
|
470
|
+
agentName: ctx.agent.agentName,
|
|
471
|
+
agentRole: ctx.agent.agentRole,
|
|
472
|
+
agentType: ctx.agent.agentType,
|
|
473
|
+
...ctx.agent.parentAgentId !== void 0 ? { parentAgentId: ctx.agent.parentAgentId } : {},
|
|
474
|
+
...ctx.agent.version !== void 0 ? { version: ctx.agent.version } : {},
|
|
475
|
+
...ctx.agent.metadata !== void 0 ? { metadata: ctx.agent.metadata } : {}
|
|
476
|
+
} : null,
|
|
416
477
|
span: ctx.span ? { spanId: ctx.span.spanId, traceId: ctx.span.traceId } : null,
|
|
417
478
|
phase: ctx.phase ?? null
|
|
418
479
|
};
|
|
@@ -423,10 +484,12 @@ var Tracer = class {
|
|
|
423
484
|
_onSpanEnd;
|
|
424
485
|
_sampleRate;
|
|
425
486
|
_enabled;
|
|
487
|
+
_traceContent;
|
|
426
488
|
constructor(config) {
|
|
427
489
|
this._onSpanEnd = config.onSpanEnd;
|
|
428
490
|
this._sampleRate = config.sampleRate ?? 1;
|
|
429
491
|
this._enabled = config.enabled ?? true;
|
|
492
|
+
this._traceContent = config.traceContent ?? true;
|
|
430
493
|
}
|
|
431
494
|
get enabled() {
|
|
432
495
|
return this._enabled;
|
|
@@ -434,6 +497,9 @@ var Tracer = class {
|
|
|
434
497
|
set enabled(value) {
|
|
435
498
|
this._enabled = value;
|
|
436
499
|
}
|
|
500
|
+
get traceContent() {
|
|
501
|
+
return this._traceContent;
|
|
502
|
+
}
|
|
437
503
|
/**
|
|
438
504
|
* Start a span, run the callback within its context, and auto-end on completion.
|
|
439
505
|
*
|
|
@@ -467,7 +533,13 @@ var Tracer = class {
|
|
|
467
533
|
kind: opts.kind ?? "internal" /* INTERNAL */,
|
|
468
534
|
traceId,
|
|
469
535
|
parentSpanId,
|
|
470
|
-
attributes:
|
|
536
|
+
attributes: {
|
|
537
|
+
...opts.attributes,
|
|
538
|
+
// Propagate context fields as attributes (matching Python SDK tracer.py:497-511)
|
|
539
|
+
...agent2?.agentRole ? { "agent.role": agent2.agentRole } : {},
|
|
540
|
+
...agent2?.parentAgentId ? { "parent_agent_id": agent2.parentAgentId } : {},
|
|
541
|
+
...session2?.userId ? { "session.user_id": session2.userId } : {}
|
|
542
|
+
},
|
|
471
543
|
sessionId: session2?.sessionId,
|
|
472
544
|
agentId: agent2?.agentId,
|
|
473
545
|
agentName: agent2?.agentName,
|
|
@@ -526,7 +598,13 @@ var Tracer = class {
|
|
|
526
598
|
kind: opts.kind ?? "internal" /* INTERNAL */,
|
|
527
599
|
traceId,
|
|
528
600
|
parentSpanId,
|
|
529
|
-
attributes:
|
|
601
|
+
attributes: {
|
|
602
|
+
...opts.attributes,
|
|
603
|
+
// Propagate context fields as attributes (matching Python SDK tracer.py:497-511)
|
|
604
|
+
...agent2?.agentRole ? { "agent.role": agent2.agentRole } : {},
|
|
605
|
+
...agent2?.parentAgentId ? { "parent_agent_id": agent2.parentAgentId } : {},
|
|
606
|
+
...session2?.userId ? { "session.user_id": session2.userId } : {}
|
|
607
|
+
},
|
|
530
608
|
sessionId: session2?.sessionId,
|
|
531
609
|
agentId: agent2?.agentId,
|
|
532
610
|
agentName: agent2?.agentName,
|
|
@@ -539,12 +617,11 @@ var Tracer = class {
|
|
|
539
617
|
};
|
|
540
618
|
|
|
541
619
|
// src/utils/log.ts
|
|
542
|
-
var _debug = false;
|
|
543
620
|
function setDebug(enabled) {
|
|
544
|
-
|
|
621
|
+
setDebugFlag(enabled);
|
|
545
622
|
}
|
|
546
623
|
function debug(msg) {
|
|
547
|
-
if (
|
|
624
|
+
if (getDebug()) {
|
|
548
625
|
process.stderr.write(`[risicare] ${msg}
|
|
549
626
|
`);
|
|
550
627
|
}
|
|
@@ -555,7 +632,7 @@ function warn(msg) {
|
|
|
555
632
|
}
|
|
556
633
|
|
|
557
634
|
// src/exporters/batch.ts
|
|
558
|
-
var BatchSpanProcessor = class {
|
|
635
|
+
var BatchSpanProcessor = class _BatchSpanProcessor {
|
|
559
636
|
_exporters;
|
|
560
637
|
_batchSize;
|
|
561
638
|
_batchTimeoutMs;
|
|
@@ -565,6 +642,10 @@ var BatchSpanProcessor = class {
|
|
|
565
642
|
_timer = null;
|
|
566
643
|
_started = false;
|
|
567
644
|
_flushing = false;
|
|
645
|
+
_beforeExitHandler = null;
|
|
646
|
+
// Retry tracking for failed batches (Audit #5)
|
|
647
|
+
_retryCounts = /* @__PURE__ */ new Map();
|
|
648
|
+
static MAX_RETRIES = 3;
|
|
568
649
|
// Metrics
|
|
569
650
|
droppedSpans = 0;
|
|
570
651
|
exportedSpans = 0;
|
|
@@ -583,9 +664,10 @@ var BatchSpanProcessor = class {
|
|
|
583
664
|
void this._exportBatch();
|
|
584
665
|
}, this._batchTimeoutMs);
|
|
585
666
|
this._timer.unref();
|
|
586
|
-
|
|
667
|
+
this._beforeExitHandler = () => {
|
|
587
668
|
void this.shutdown();
|
|
588
|
-
}
|
|
669
|
+
};
|
|
670
|
+
process.once("beforeExit", this._beforeExitHandler);
|
|
589
671
|
}
|
|
590
672
|
async shutdown(timeoutMs = 5e3) {
|
|
591
673
|
if (!this._started) return;
|
|
@@ -594,6 +676,10 @@ var BatchSpanProcessor = class {
|
|
|
594
676
|
clearInterval(this._timer);
|
|
595
677
|
this._timer = null;
|
|
596
678
|
}
|
|
679
|
+
if (this._beforeExitHandler) {
|
|
680
|
+
process.removeListener("beforeExit", this._beforeExitHandler);
|
|
681
|
+
this._beforeExitHandler = null;
|
|
682
|
+
}
|
|
597
683
|
const flushPromise = this._exportBatch();
|
|
598
684
|
const timeoutPromise = new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
599
685
|
await Promise.race([flushPromise, timeoutPromise]);
|
|
@@ -604,6 +690,7 @@ var BatchSpanProcessor = class {
|
|
|
604
690
|
debug(`Error shutting down ${exporter.name}: ${e}`);
|
|
605
691
|
}
|
|
606
692
|
}
|
|
693
|
+
this._retryCounts.clear();
|
|
607
694
|
debug(
|
|
608
695
|
`BatchSpanProcessor shutdown. Exported: ${this.exportedSpans}, Dropped: ${this.droppedSpans}, Failed: ${this.failedExports}`
|
|
609
696
|
);
|
|
@@ -660,6 +747,9 @@ var BatchSpanProcessor = class {
|
|
|
660
747
|
if (!batchExported) {
|
|
661
748
|
this.exportedSpans += batch.length;
|
|
662
749
|
batchExported = true;
|
|
750
|
+
for (const span of batch) {
|
|
751
|
+
this._retryCounts.delete(span.spanId);
|
|
752
|
+
}
|
|
663
753
|
}
|
|
664
754
|
} else {
|
|
665
755
|
this.failedExports++;
|
|
@@ -669,6 +759,22 @@ var BatchSpanProcessor = class {
|
|
|
669
759
|
debug(`Export to ${exporter.name} failed: ${e}`);
|
|
670
760
|
}
|
|
671
761
|
}
|
|
762
|
+
if (!batchExported) {
|
|
763
|
+
const retryable = batch.filter((span) => {
|
|
764
|
+
const count = (this._retryCounts.get(span.spanId) ?? 0) + 1;
|
|
765
|
+
if (count > _BatchSpanProcessor.MAX_RETRIES) {
|
|
766
|
+
this._retryCounts.delete(span.spanId);
|
|
767
|
+
this.droppedSpans++;
|
|
768
|
+
return false;
|
|
769
|
+
}
|
|
770
|
+
this._retryCounts.set(span.spanId, count);
|
|
771
|
+
return true;
|
|
772
|
+
});
|
|
773
|
+
if (retryable.length > 0) {
|
|
774
|
+
this._queue.unshift(...retryable);
|
|
775
|
+
debug(`Re-queued ${retryable.length} spans for retry (${batch.length - retryable.length} dropped after max retries)`);
|
|
776
|
+
}
|
|
777
|
+
}
|
|
672
778
|
} finally {
|
|
673
779
|
this._flushing = false;
|
|
674
780
|
}
|
|
@@ -676,6 +782,7 @@ var BatchSpanProcessor = class {
|
|
|
676
782
|
};
|
|
677
783
|
|
|
678
784
|
// src/exporters/http.ts
|
|
785
|
+
var SDK_VERSION = "0.1.1";
|
|
679
786
|
var HttpExporter = class {
|
|
680
787
|
name = "http";
|
|
681
788
|
_endpoint;
|
|
@@ -702,23 +809,26 @@ var HttpExporter = class {
|
|
|
702
809
|
async export(spans) {
|
|
703
810
|
if (spans.length === 0) return "success" /* SUCCESS */;
|
|
704
811
|
const now = Date.now();
|
|
812
|
+
let isHalfOpen = false;
|
|
705
813
|
if (this._consecutiveFailures >= this._circuitBreakerThreshold) {
|
|
706
814
|
if (now < this._circuitOpenUntil) {
|
|
707
815
|
return "failure" /* FAILURE */;
|
|
708
816
|
}
|
|
817
|
+
isHalfOpen = true;
|
|
709
818
|
}
|
|
710
819
|
const body = {
|
|
711
820
|
spans: spans.map((s) => s.toPayload())
|
|
712
821
|
};
|
|
713
822
|
if (this._projectId) body.projectId = this._projectId;
|
|
714
823
|
if (this._environment) body.environment = this._environment;
|
|
715
|
-
|
|
824
|
+
const maxAttempts = isHalfOpen ? 1 : this._maxRetries;
|
|
825
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
716
826
|
const result = await this._sendRequest(body);
|
|
717
827
|
if (result === "success" /* SUCCESS */) {
|
|
718
828
|
this._consecutiveFailures = 0;
|
|
719
829
|
return result;
|
|
720
830
|
}
|
|
721
|
-
if (attempt <
|
|
831
|
+
if (attempt < maxAttempts - 1) {
|
|
722
832
|
await sleep(100 * Math.pow(2, attempt));
|
|
723
833
|
}
|
|
724
834
|
}
|
|
@@ -734,7 +844,8 @@ var HttpExporter = class {
|
|
|
734
844
|
async _sendRequest(body) {
|
|
735
845
|
const url = `${this._endpoint}/v1/spans`;
|
|
736
846
|
const headers = {
|
|
737
|
-
"Content-Type": "application/json"
|
|
847
|
+
"Content-Type": "application/json",
|
|
848
|
+
"User-Agent": `risicare-js/${SDK_VERSION} node/${process.version}`
|
|
738
849
|
};
|
|
739
850
|
if (this._apiKey) {
|
|
740
851
|
headers["Authorization"] = `Bearer ${this._apiKey}`;
|
|
@@ -745,7 +856,8 @@ var HttpExporter = class {
|
|
|
745
856
|
const { gzipSync } = await import("zlib");
|
|
746
857
|
payload = gzipSync(Buffer.from(payload));
|
|
747
858
|
headers["Content-Encoding"] = "gzip";
|
|
748
|
-
} catch {
|
|
859
|
+
} catch (e) {
|
|
860
|
+
debug(`Gzip compression failed, sending uncompressed: ${e}`);
|
|
749
861
|
}
|
|
750
862
|
}
|
|
751
863
|
try {
|
|
@@ -795,15 +907,17 @@ var ConsoleExporter = class {
|
|
|
795
907
|
};
|
|
796
908
|
|
|
797
909
|
// src/client.ts
|
|
798
|
-
var _client;
|
|
799
|
-
var _tracer;
|
|
800
910
|
var RisicareClient = class {
|
|
801
911
|
config;
|
|
802
912
|
processor;
|
|
803
913
|
tracer;
|
|
804
|
-
|
|
914
|
+
_shutdownPromise;
|
|
915
|
+
_shutdownHandlers = [];
|
|
805
916
|
constructor(config) {
|
|
806
917
|
this.config = resolveConfig(config);
|
|
918
|
+
if (this.config.apiKey && !this.config.apiKey.startsWith("rsk-")) {
|
|
919
|
+
debug('Warning: API key should start with "rsk-". Got: ' + this.config.apiKey.slice(0, 4) + "...");
|
|
920
|
+
}
|
|
807
921
|
let exporter;
|
|
808
922
|
if (this.config.debug && !this.config.apiKey) {
|
|
809
923
|
exporter = new ConsoleExporter();
|
|
@@ -812,7 +926,8 @@ var RisicareClient = class {
|
|
|
812
926
|
endpoint: this.config.endpoint,
|
|
813
927
|
apiKey: this.config.apiKey,
|
|
814
928
|
projectId: this.config.projectId || void 0,
|
|
815
|
-
environment: this.config.environment || void 0
|
|
929
|
+
environment: this.config.environment || void 0,
|
|
930
|
+
compress: this.config.compress
|
|
816
931
|
});
|
|
817
932
|
} else {
|
|
818
933
|
exporter = new ConsoleExporter();
|
|
@@ -827,7 +942,8 @@ var RisicareClient = class {
|
|
|
827
942
|
this.tracer = new Tracer({
|
|
828
943
|
onSpanEnd: (span) => this.processor.onSpanEnd(span),
|
|
829
944
|
sampleRate: this.config.sampleRate,
|
|
830
|
-
enabled: this.config.enabled
|
|
945
|
+
enabled: this.config.enabled,
|
|
946
|
+
traceContent: this.config.traceContent
|
|
831
947
|
});
|
|
832
948
|
this.processor.start();
|
|
833
949
|
this._registerShutdownHooks();
|
|
@@ -840,10 +956,18 @@ var RisicareClient = class {
|
|
|
840
956
|
set enabled(value) {
|
|
841
957
|
this.tracer.enabled = value;
|
|
842
958
|
}
|
|
959
|
+
// Audit #6: Promise-based shutdown dedup (fixes TOCTOU race condition)
|
|
843
960
|
async shutdown() {
|
|
844
|
-
if (this.
|
|
845
|
-
this.
|
|
961
|
+
if (this._shutdownPromise) return this._shutdownPromise;
|
|
962
|
+
this._shutdownPromise = this._doShutdown();
|
|
963
|
+
return this._shutdownPromise;
|
|
964
|
+
}
|
|
965
|
+
async _doShutdown() {
|
|
846
966
|
debug("Shutting down...");
|
|
967
|
+
for (const { signal, handler } of this._shutdownHandlers) {
|
|
968
|
+
process.removeListener(signal, handler);
|
|
969
|
+
}
|
|
970
|
+
this._shutdownHandlers = [];
|
|
847
971
|
await this.processor.shutdown();
|
|
848
972
|
}
|
|
849
973
|
async flush() {
|
|
@@ -851,43 +975,68 @@ var RisicareClient = class {
|
|
|
851
975
|
}
|
|
852
976
|
_registerShutdownHooks() {
|
|
853
977
|
const onShutdown = () => {
|
|
978
|
+
const timeout = setTimeout(() => process.exit(1), 5e3);
|
|
979
|
+
timeout.unref();
|
|
854
980
|
this.shutdown().catch(() => {
|
|
855
|
-
});
|
|
981
|
+
}).finally(() => clearTimeout(timeout));
|
|
856
982
|
};
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
983
|
+
const signals = ["beforeExit", "SIGTERM", "SIGINT"];
|
|
984
|
+
for (const signal of signals) {
|
|
985
|
+
process.once(signal, onShutdown);
|
|
986
|
+
this._shutdownHandlers.push({ signal, handler: onShutdown });
|
|
987
|
+
}
|
|
860
988
|
}
|
|
861
989
|
};
|
|
862
990
|
function init(config) {
|
|
863
|
-
if (
|
|
991
|
+
if (getClient()) {
|
|
864
992
|
debug("Already initialized. Call shutdown() first to re-initialize.");
|
|
865
993
|
return;
|
|
866
994
|
}
|
|
867
|
-
|
|
868
|
-
|
|
995
|
+
const client = new RisicareClient(config);
|
|
996
|
+
setClient(client);
|
|
997
|
+
setTracer(client.tracer);
|
|
869
998
|
}
|
|
870
999
|
async function shutdown() {
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1000
|
+
const client = getClient();
|
|
1001
|
+
if (!client) return;
|
|
1002
|
+
await client.shutdown();
|
|
1003
|
+
setClient(void 0);
|
|
1004
|
+
setTracer(void 0);
|
|
875
1005
|
}
|
|
876
1006
|
async function flush() {
|
|
877
|
-
|
|
878
|
-
|
|
1007
|
+
const client = getClient();
|
|
1008
|
+
if (!client) return;
|
|
1009
|
+
await client.flush();
|
|
879
1010
|
}
|
|
880
1011
|
function enable() {
|
|
881
|
-
|
|
1012
|
+
const client = getClient();
|
|
1013
|
+
if (client) client.enabled = true;
|
|
882
1014
|
}
|
|
883
1015
|
function disable() {
|
|
884
|
-
|
|
1016
|
+
const client = getClient();
|
|
1017
|
+
if (client) client.enabled = false;
|
|
885
1018
|
}
|
|
886
1019
|
function isEnabled() {
|
|
887
|
-
|
|
1020
|
+
const client = getClient();
|
|
1021
|
+
return client?.enabled ?? false;
|
|
888
1022
|
}
|
|
889
|
-
function
|
|
890
|
-
return
|
|
1023
|
+
function getTracer2() {
|
|
1024
|
+
return getTracer();
|
|
1025
|
+
}
|
|
1026
|
+
function getTraceContent() {
|
|
1027
|
+
const tracer = getTracer();
|
|
1028
|
+
return tracer?.traceContent ?? true;
|
|
1029
|
+
}
|
|
1030
|
+
function getMetrics() {
|
|
1031
|
+
const client = getClient();
|
|
1032
|
+
return client?.processor.getMetrics() ?? {
|
|
1033
|
+
exportedSpans: 0,
|
|
1034
|
+
droppedSpans: 0,
|
|
1035
|
+
failedExports: 0,
|
|
1036
|
+
queueSize: 0,
|
|
1037
|
+
queueCapacity: 0,
|
|
1038
|
+
queueUtilization: 0
|
|
1039
|
+
};
|
|
891
1040
|
}
|
|
892
1041
|
|
|
893
1042
|
// src/context/agent.ts
|
|
@@ -911,7 +1060,7 @@ function withAgent(options, fn) {
|
|
|
911
1060
|
function agent(options, fn) {
|
|
912
1061
|
const spanName = `agent:${options.name ?? "agent"}`;
|
|
913
1062
|
return (...args) => {
|
|
914
|
-
const tracer =
|
|
1063
|
+
const tracer = getTracer2();
|
|
915
1064
|
if (!tracer) {
|
|
916
1065
|
return fn(...args);
|
|
917
1066
|
}
|
|
@@ -951,28 +1100,28 @@ function withPhase(phase, fn) {
|
|
|
951
1100
|
}
|
|
952
1101
|
|
|
953
1102
|
// src/decorators/phase.ts
|
|
954
|
-
function phaseWrapper(phase, fn) {
|
|
1103
|
+
function phaseWrapper(phase, kind, fn) {
|
|
955
1104
|
return (...args) => {
|
|
956
|
-
const tracer =
|
|
1105
|
+
const tracer = getTracer2();
|
|
957
1106
|
if (!tracer) {
|
|
958
1107
|
return fn(...args);
|
|
959
1108
|
}
|
|
960
1109
|
return withPhase(phase, () => {
|
|
961
|
-
return tracer.startSpan({ name: `phase:${phase}
|
|
1110
|
+
return tracer.startSpan({ name: `phase:${phase}`, kind }, () => fn(...args));
|
|
962
1111
|
});
|
|
963
1112
|
};
|
|
964
1113
|
}
|
|
965
1114
|
function traceThink(fn) {
|
|
966
|
-
return phaseWrapper("think" /* THINK */, fn);
|
|
1115
|
+
return phaseWrapper("think" /* THINK */, "think" /* THINK */, fn);
|
|
967
1116
|
}
|
|
968
1117
|
function traceDecide(fn) {
|
|
969
|
-
return phaseWrapper("decide" /* DECIDE */, fn);
|
|
1118
|
+
return phaseWrapper("decide" /* DECIDE */, "decide" /* DECIDE */, fn);
|
|
970
1119
|
}
|
|
971
1120
|
function traceAct(fn) {
|
|
972
|
-
return phaseWrapper("act" /* ACT */, fn);
|
|
1121
|
+
return phaseWrapper("act" /* ACT */, "tool_call" /* TOOL_CALL */, fn);
|
|
973
1122
|
}
|
|
974
1123
|
function traceObserve(fn) {
|
|
975
|
-
return phaseWrapper("observe" /* OBSERVE */, fn);
|
|
1124
|
+
return phaseWrapper("observe" /* OBSERVE */, "observe" /* OBSERVE */, fn);
|
|
976
1125
|
}
|
|
977
1126
|
|
|
978
1127
|
// src/decorators/multi-agent.ts
|
|
@@ -987,7 +1136,7 @@ function namespacedMetadata(metadata) {
|
|
|
987
1136
|
function traceMessage(options, fn) {
|
|
988
1137
|
const msgType = options.type ?? "request" /* REQUEST */;
|
|
989
1138
|
return (...args) => {
|
|
990
|
-
const tracer =
|
|
1139
|
+
const tracer = getTracer2();
|
|
991
1140
|
if (!tracer) return fn(...args);
|
|
992
1141
|
return tracer.startSpan(
|
|
993
1142
|
{
|
|
@@ -1006,7 +1155,7 @@ function traceMessage(options, fn) {
|
|
|
1006
1155
|
}
|
|
1007
1156
|
function traceDelegate(options, fn) {
|
|
1008
1157
|
return (...args) => {
|
|
1009
|
-
const tracer =
|
|
1158
|
+
const tracer = getTracer2();
|
|
1010
1159
|
if (!tracer) return fn(...args);
|
|
1011
1160
|
return tracer.startSpan(
|
|
1012
1161
|
{
|
|
@@ -1025,7 +1174,7 @@ function traceDelegate(options, fn) {
|
|
|
1025
1174
|
}
|
|
1026
1175
|
function traceCoordinate(options, fn) {
|
|
1027
1176
|
return (...args) => {
|
|
1028
|
-
const tracer =
|
|
1177
|
+
const tracer = getTracer2();
|
|
1029
1178
|
if (!tracer) return fn(...args);
|
|
1030
1179
|
return tracer.startSpan(
|
|
1031
1180
|
{
|
|
@@ -1103,7 +1252,10 @@ function extractTraceContext(headers) {
|
|
|
1103
1252
|
if (eqIdx > 0) {
|
|
1104
1253
|
const key = kv.slice(0, eqIdx).trim();
|
|
1105
1254
|
const value = kv.slice(eqIdx + 1).trim();
|
|
1106
|
-
if (key && value)
|
|
1255
|
+
if (key && value) {
|
|
1256
|
+
const camelKey = key === "session_id" ? "sessionId" : key === "agent_id" ? "agentId" : key;
|
|
1257
|
+
result[camelKey] = value;
|
|
1258
|
+
}
|
|
1107
1259
|
}
|
|
1108
1260
|
}
|
|
1109
1261
|
}
|
|
@@ -1116,36 +1268,37 @@ function extractTraceContext(headers) {
|
|
|
1116
1268
|
var DEFAULT_TTL_MS = 6e4;
|
|
1117
1269
|
var MAX_ENTRIES = 1e4;
|
|
1118
1270
|
var CLEANUP_INTERVAL = 100;
|
|
1119
|
-
|
|
1120
|
-
|
|
1271
|
+
function entries() {
|
|
1272
|
+
return getRegistry();
|
|
1273
|
+
}
|
|
1121
1274
|
function registerSpan(span, ttlMs = DEFAULT_TTL_MS) {
|
|
1122
|
-
entries.set(span.spanId, {
|
|
1275
|
+
entries().set(span.spanId, {
|
|
1123
1276
|
span,
|
|
1124
1277
|
registeredAt: Date.now(),
|
|
1125
1278
|
ttlMs
|
|
1126
1279
|
});
|
|
1127
|
-
|
|
1280
|
+
setOpCount(getOpCount() + 1);
|
|
1128
1281
|
maybeCleanup();
|
|
1129
1282
|
}
|
|
1130
1283
|
function getSpanById(spanId) {
|
|
1131
|
-
const entry = entries.get(spanId);
|
|
1284
|
+
const entry = entries().get(spanId);
|
|
1132
1285
|
if (!entry) return void 0;
|
|
1133
1286
|
if (Date.now() - entry.registeredAt > entry.ttlMs) {
|
|
1134
|
-
entries.delete(spanId);
|
|
1287
|
+
entries().delete(spanId);
|
|
1135
1288
|
return void 0;
|
|
1136
1289
|
}
|
|
1137
1290
|
return entry.span;
|
|
1138
1291
|
}
|
|
1139
1292
|
function unregisterSpan(spanId) {
|
|
1140
|
-
entries.delete(spanId);
|
|
1293
|
+
entries().delete(spanId);
|
|
1141
1294
|
}
|
|
1142
1295
|
function maybeCleanup() {
|
|
1143
|
-
if (
|
|
1144
|
-
if (entries.size <= MAX_ENTRIES) return;
|
|
1296
|
+
if (getOpCount() % CLEANUP_INTERVAL !== 0) return;
|
|
1297
|
+
if (entries().size <= MAX_ENTRIES) return;
|
|
1145
1298
|
const now = Date.now();
|
|
1146
|
-
for (const [id, entry] of entries) {
|
|
1299
|
+
for (const [id, entry] of entries()) {
|
|
1147
1300
|
if (now - entry.registeredAt > entry.ttlMs) {
|
|
1148
|
-
entries.delete(id);
|
|
1301
|
+
entries().delete(id);
|
|
1149
1302
|
}
|
|
1150
1303
|
}
|
|
1151
1304
|
}
|
|
@@ -1169,9 +1322,11 @@ export {
|
|
|
1169
1322
|
getCurrentSpan,
|
|
1170
1323
|
getCurrentSpanId,
|
|
1171
1324
|
getCurrentTraceId,
|
|
1325
|
+
getMetrics,
|
|
1172
1326
|
getSpanById,
|
|
1327
|
+
getTraceContent,
|
|
1173
1328
|
getTraceContext,
|
|
1174
|
-
getTracer,
|
|
1329
|
+
getTracer2 as getTracer,
|
|
1175
1330
|
init,
|
|
1176
1331
|
injectTraceContext,
|
|
1177
1332
|
isEnabled,
|