@gurulu/node 1.0.2 → 1.0.3
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/core.d.ts +17 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +197 -1
- package/dist/llm.d.ts +40 -0
- package/dist/llm.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/core.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type LlmCaptureInput, type WrapOptions } from './llm.ts';
|
|
1
2
|
import { type ExpressMiddlewareOptions } from './middleware/express.ts';
|
|
2
3
|
import { type FastifyPluginOptions } from './middleware/fastify.ts';
|
|
3
4
|
import { createNextHandler, type NextHandlerOptions } from './middleware/next.ts';
|
|
@@ -16,6 +17,22 @@ export declare class Gurulu {
|
|
|
16
17
|
identify(externalUserId: string, traits?: IdentifyTraits, explicitContext?: ServerContext): Promise<IdentifyResult>;
|
|
17
18
|
/** Outcome event track (queue + auto-flush). */
|
|
18
19
|
track(eventKey: string, properties?: Record<string, unknown>, explicitContext?: ServerContext, eventType?: EventClass): TrackResult;
|
|
20
|
+
/**
|
|
21
|
+
* M46 LLM Analytics (K31) — müşterinin AI özelliği için `llm_request` capture.
|
|
22
|
+
* Interaction (gözlem) — outcome ÜRETMEZ (K16). Content default kapalı; opt-in
|
|
23
|
+
* için input.promptContent/responseContent + captureContent.
|
|
24
|
+
*/
|
|
25
|
+
get llm(): {
|
|
26
|
+
capture: (input: LlmCaptureInput, captureContent?: boolean) => TrackResult;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* OpenAI client'ı yerinde instrument eder — her chat/embedding çağrısı
|
|
30
|
+
* `llm_request` gönderir (token/latency/status otomatik). Zero-dep: OpenAI SDK
|
|
31
|
+
* import edilmez, structural typing. `const ai = gurulu.wrapOpenAI(openai)`.
|
|
32
|
+
*/
|
|
33
|
+
wrapOpenAI<T>(client: T, opts?: WrapOptions): T;
|
|
34
|
+
/** Anthropic client'ı yerinde instrument eder (messages.create). */
|
|
35
|
+
wrapAnthropic<T>(client: T, opts?: WrapOptions): T;
|
|
19
36
|
/** Manual flush (force send current queue). */
|
|
20
37
|
flush(): Promise<FlushResult>;
|
|
21
38
|
/** Graceful shutdown — flush + cancel timer + max 10s timeout. */
|
package/dist/core.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAKA,OAAO,EAA2B,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAIlF,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EAGb,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,EAE1B,MAAM,sBAAsB,CAAC;AA2C9B,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAA6B;gBAEvC,OAAO,CAAC,EAAE,eAAe;IAIrC,6DAA6D;IAC7D,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAOlC,OAAO,CAAC,aAAa;IAKrB,uDAAuD;IACjD,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,aAAa,GAC9B,OAAO,CAAC,cAAc,CAAC;IAO1B,gDAAgD;IAChD,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,eAAe,CAAC,EAAE,aAAa,EAC/B,SAAS,GAAE,UAAsB,GAChC,WAAW;IAad,+CAA+C;IACzC,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAKnC,kEAAkE;IAC5D,QAAQ,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAUrB,+CAA+C;IAC/C,IAAI,QAAQ;;;
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAKA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,WAAW,EAGjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAA2B,KAAK,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACjG,OAAO,EAAuB,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAIlF,OAAO,KAAK,EACV,UAAU,EACV,WAAW,EACX,cAAc,EACd,cAAc,EACd,aAAa,EAGb,aAAa,EACb,eAAe,EACf,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,0BAA0B,EAC/B,KAAK,oBAAoB,EAE1B,MAAM,sBAAsB,CAAC;AA2C9B,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAA+B;IAC7C,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,cAAc,CAA6B;gBAEvC,OAAO,CAAC,EAAE,eAAe;IAIrC,6DAA6D;IAC7D,IAAI,CAAC,KAAK,EAAE,eAAe,GAAG,IAAI;IAOlC,OAAO,CAAC,aAAa;IAKrB,uDAAuD;IACjD,QAAQ,CACZ,cAAc,EAAE,MAAM,EACtB,MAAM,CAAC,EAAE,cAAc,EACvB,eAAe,CAAC,EAAE,aAAa,GAC9B,OAAO,CAAC,cAAc,CAAC;IAO1B,gDAAgD;IAChD,KAAK,CACH,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,eAAe,CAAC,EAAE,aAAa,EAC/B,SAAS,GAAE,UAAsB,GAChC,WAAW;IAad;;;;OAIG;IACH,IAAI,GAAG;yBAGc,eAAe,+BAA2B,WAAW;MAQzE;IAED;;;;OAIG;IACH,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,CAAC;IAW/C,oEAAoE;IACpE,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,CAAC;IAWlD,+CAA+C;IACzC,KAAK,IAAI,OAAO,CAAC,WAAW,CAAC;IAKnC,kEAAkE;IAC5D,QAAQ,CAAC,SAAS,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;IASxD,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,aAAa;IAUrB,+CAA+C;IAC/C,IAAI,QAAQ;;;qFA5E2C,CAAA;iGAGf,CAAC;;;;;mGAjCR,CAAC;;;;;6GAMJ,CAAA;;0BA6GR,0BAA0B,KAAG,oBAAoB;MAGtE;IAED,qDAAqD;IACrD,IAAI,OAAO;4BACoB,wBAAwB;MACtD;IAED,IAAI,OAAO;wBACgB,oBAAoB;MAC9C;IAED,IAAI,IAAI;;MAEP;CACF;AAED,wFAAwF;AACxF,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAE5D;AAKD,wBAAgB,UAAU,IAAI,MAAM,CAGnC;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAI3D;AAED,YAAY,EAAE,wBAAwB,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export declare const VERSION = "0.1.0";
|
|
|
2
2
|
export { contextStorage, getContext, mergeContext, runWithContext } from './context.ts';
|
|
3
3
|
export { createGurulu, Gurulu, getDefault, initDefault } from './core.ts';
|
|
4
4
|
export { GuruluSDKError, InvalidWorkspaceKeyError, NotInitializedError, QueueOverflowError, TransportError, WebhookMappingNotFoundError, WebhookSignatureError, } from './errors.ts';
|
|
5
|
+
export { buildLlmProperties, type LlmCaptureFn, type LlmCaptureInput, type LlmOperation, type LlmProvider, type LlmStatus, type WrapOptions, wrapAnthropicClient, wrapOpenAIClient, } from './llm.ts';
|
|
5
6
|
export { createExpressMiddleware, type ExpressMiddlewareOptions, } from './middleware/express.ts';
|
|
6
7
|
export { createFastifyPlugin, type FastifyPluginOptions } from './middleware/fastify.ts';
|
|
7
8
|
export { createNextHandler, type NextHandlerOptions } from './middleware/next.ts';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,OAAO,UAAU,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG1E,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAElF,YAAY,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAExF,OAAO,EACL,4BAA4B,EAC5B,KAAK,yBAAyB,EAC9B,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,+BAA+B,EAC/B,KAAK,mBAAmB,EACxB,YAAY,GACb,MAAM,sBAAsB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,OAAO,UAAU,CAAC;AAG/B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAExF,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG1E,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,mBAAmB,EACnB,kBAAkB,EAClB,cAAc,EACd,2BAA2B,EAC3B,qBAAqB,GACtB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,SAAS,EACd,KAAK,WAAW,EAChB,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,UAAU,CAAC;AAElB,OAAO,EACL,uBAAuB,EACvB,KAAK,wBAAwB,GAC9B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,mBAAmB,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAElF,YAAY,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,cAAc,EACd,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,aAAa,EACb,cAAc,EACd,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAExF,OAAO,EACL,4BAA4B,EAC5B,KAAK,yBAAyB,EAC9B,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,uBAAuB,EACvB,KAAK,oBAAoB,EACzB,aAAa,GACd,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,+BAA+B,EAC/B,KAAK,mBAAmB,EACxB,YAAY,GACb,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -548,6 +548,181 @@ function buildIdentify(input) {
|
|
|
548
548
|
return payload;
|
|
549
549
|
}
|
|
550
550
|
|
|
551
|
+
// src/llm.ts
|
|
552
|
+
function buildLlmProperties(input, captureContent) {
|
|
553
|
+
const total = input.totalTokens ?? input.promptTokens + input.completionTokens;
|
|
554
|
+
const props = {
|
|
555
|
+
provider: input.provider,
|
|
556
|
+
model: input.model,
|
|
557
|
+
operation: input.operation,
|
|
558
|
+
prompt_tokens: input.promptTokens,
|
|
559
|
+
completion_tokens: input.completionTokens,
|
|
560
|
+
total_tokens: total,
|
|
561
|
+
latency_ms: input.latencyMs,
|
|
562
|
+
status: input.status
|
|
563
|
+
};
|
|
564
|
+
if (input.cost != null)
|
|
565
|
+
props.cost = input.cost;
|
|
566
|
+
if (input.currency != null)
|
|
567
|
+
props.currency = input.currency;
|
|
568
|
+
if (input.errorType != null)
|
|
569
|
+
props.error_type = input.errorType;
|
|
570
|
+
if (input.feature != null)
|
|
571
|
+
props.feature = input.feature;
|
|
572
|
+
if (input.cacheHit != null)
|
|
573
|
+
props.cache_hit = input.cacheHit;
|
|
574
|
+
if (input.stream != null)
|
|
575
|
+
props.stream = input.stream;
|
|
576
|
+
if (captureContent) {
|
|
577
|
+
if (input.promptContent !== undefined)
|
|
578
|
+
props.prompt_content = input.promptContent;
|
|
579
|
+
if (input.responseContent !== undefined)
|
|
580
|
+
props.response_content = input.responseContent;
|
|
581
|
+
}
|
|
582
|
+
return props;
|
|
583
|
+
}
|
|
584
|
+
function asRecord(v) {
|
|
585
|
+
return typeof v === "object" && v !== null ? v : null;
|
|
586
|
+
}
|
|
587
|
+
function numField(rec, key) {
|
|
588
|
+
const v = rec?.[key];
|
|
589
|
+
return typeof v === "number" ? v : 0;
|
|
590
|
+
}
|
|
591
|
+
function extractOpenAIUsage(result) {
|
|
592
|
+
const rec = asRecord(result);
|
|
593
|
+
const usage = asRecord(rec?.usage);
|
|
594
|
+
if (!usage)
|
|
595
|
+
return null;
|
|
596
|
+
const cachedRec = asRecord(usage.prompt_tokens_details);
|
|
597
|
+
const cached = numField(cachedRec, "cached_tokens");
|
|
598
|
+
return {
|
|
599
|
+
promptTokens: numField(usage, "prompt_tokens"),
|
|
600
|
+
completionTokens: numField(usage, "completion_tokens"),
|
|
601
|
+
model: typeof rec?.model === "string" ? rec.model : null,
|
|
602
|
+
...cached > 0 ? { cacheHit: true } : {}
|
|
603
|
+
};
|
|
604
|
+
}
|
|
605
|
+
function extractAnthropicUsage(result) {
|
|
606
|
+
const rec = asRecord(result);
|
|
607
|
+
const usage = asRecord(rec?.usage);
|
|
608
|
+
if (!usage)
|
|
609
|
+
return null;
|
|
610
|
+
const cacheRead = numField(usage, "cache_read_input_tokens");
|
|
611
|
+
return {
|
|
612
|
+
promptTokens: numField(usage, "input_tokens"),
|
|
613
|
+
completionTokens: numField(usage, "output_tokens"),
|
|
614
|
+
model: typeof rec?.model === "string" ? rec.model : null,
|
|
615
|
+
...cacheRead > 0 ? { cacheHit: true } : {}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function classifyError(err) {
|
|
619
|
+
const rec = asRecord(err);
|
|
620
|
+
const httpStatus = typeof rec?.status === "number" ? rec.status : undefined;
|
|
621
|
+
const name = typeof rec?.name === "string" ? rec.name : "Error";
|
|
622
|
+
if (httpStatus === 429)
|
|
623
|
+
return { status: "rate_limited", errorType: "rate_limit" };
|
|
624
|
+
if (name.toLowerCase().includes("timeout") || rec?.code === "ETIMEDOUT") {
|
|
625
|
+
return { status: "timeout", errorType: "timeout" };
|
|
626
|
+
}
|
|
627
|
+
if (httpStatus != null)
|
|
628
|
+
return { status: "error", errorType: `http_${httpStatus}` };
|
|
629
|
+
return { status: "error", errorType: name };
|
|
630
|
+
}
|
|
631
|
+
function instrumentCreate(owner, method, provider, operation, extractUsage, capture, opts) {
|
|
632
|
+
const original = owner[method];
|
|
633
|
+
if (typeof original !== "function")
|
|
634
|
+
return;
|
|
635
|
+
const fn = original;
|
|
636
|
+
owner[method] = function patched(...args) {
|
|
637
|
+
const params = asRecord(args[0]);
|
|
638
|
+
const isStream = params?.stream === true;
|
|
639
|
+
const start = Date.now();
|
|
640
|
+
let result;
|
|
641
|
+
try {
|
|
642
|
+
result = fn.apply(this, args);
|
|
643
|
+
} catch (err) {
|
|
644
|
+
emitError(err);
|
|
645
|
+
throw err;
|
|
646
|
+
}
|
|
647
|
+
if (result != null && typeof result.then === "function") {
|
|
648
|
+
return result.then((resolved) => {
|
|
649
|
+
emitSuccess(resolved, isStream);
|
|
650
|
+
return resolved;
|
|
651
|
+
}, (err) => {
|
|
652
|
+
emitError(err);
|
|
653
|
+
throw err;
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
emitSuccess(result, isStream);
|
|
657
|
+
return result;
|
|
658
|
+
function emitSuccess(resolved, stream) {
|
|
659
|
+
if (stream)
|
|
660
|
+
return;
|
|
661
|
+
const usage = extractUsage(resolved);
|
|
662
|
+
if (!usage)
|
|
663
|
+
return;
|
|
664
|
+
const fallbackModel = typeof params?.model === "string" ? params.model : "unknown";
|
|
665
|
+
capture({
|
|
666
|
+
provider,
|
|
667
|
+
model: usage.model ?? fallbackModel,
|
|
668
|
+
operation,
|
|
669
|
+
promptTokens: usage.promptTokens,
|
|
670
|
+
completionTokens: usage.completionTokens,
|
|
671
|
+
latencyMs: Date.now() - start,
|
|
672
|
+
status: "success",
|
|
673
|
+
...usage.cacheHit != null ? { cacheHit: usage.cacheHit } : {},
|
|
674
|
+
...opts.feature != null ? { feature: opts.feature } : {},
|
|
675
|
+
...opts.captureContent ? { promptContent: params?.messages ?? params?.input ?? params?.prompt } : {},
|
|
676
|
+
...opts.captureContent ? { responseContent: resolved } : {}
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
function emitError(err) {
|
|
680
|
+
const { status, errorType } = classifyError(err);
|
|
681
|
+
const fallbackModel = typeof params?.model === "string" ? params.model : "unknown";
|
|
682
|
+
capture({
|
|
683
|
+
provider,
|
|
684
|
+
model: fallbackModel,
|
|
685
|
+
operation,
|
|
686
|
+
promptTokens: 0,
|
|
687
|
+
completionTokens: 0,
|
|
688
|
+
latencyMs: Date.now() - start,
|
|
689
|
+
status,
|
|
690
|
+
errorType,
|
|
691
|
+
...opts.feature != null ? { feature: opts.feature } : {}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function wrapOpenAIClient(capture, client, opts = {}) {
|
|
697
|
+
const root = asRecord(client);
|
|
698
|
+
if (!root)
|
|
699
|
+
return client;
|
|
700
|
+
const chat = asRecord(root.chat);
|
|
701
|
+
const completions = asRecord(chat?.completions);
|
|
702
|
+
if (completions) {
|
|
703
|
+
instrumentCreate(completions, "create", "openai", "chat", extractOpenAIUsage, capture, opts);
|
|
704
|
+
}
|
|
705
|
+
const embeddings = asRecord(root.embeddings);
|
|
706
|
+
if (embeddings) {
|
|
707
|
+
instrumentCreate(embeddings, "create", "openai", "embedding", extractOpenAIUsage, capture, opts);
|
|
708
|
+
}
|
|
709
|
+
const responses = asRecord(root.responses);
|
|
710
|
+
if (responses) {
|
|
711
|
+
instrumentCreate(responses, "create", "openai", "chat", extractOpenAIUsage, capture, opts);
|
|
712
|
+
}
|
|
713
|
+
return client;
|
|
714
|
+
}
|
|
715
|
+
function wrapAnthropicClient(capture, client, opts = {}) {
|
|
716
|
+
const root = asRecord(client);
|
|
717
|
+
if (!root)
|
|
718
|
+
return client;
|
|
719
|
+
const messages = asRecord(root.messages);
|
|
720
|
+
if (messages) {
|
|
721
|
+
instrumentCreate(messages, "create", "anthropic", "chat", extractAnthropicUsage, capture, opts);
|
|
722
|
+
}
|
|
723
|
+
return client;
|
|
724
|
+
}
|
|
725
|
+
|
|
551
726
|
// src/transport.ts
|
|
552
727
|
var USER_AGENT = `gurulu-node/0.1.0 (${process.platform}; node ${process.version})`;
|
|
553
728
|
function sleep(ms) {
|
|
@@ -576,7 +751,7 @@ async function postWithRetry(config, input) {
|
|
|
576
751
|
headers: {
|
|
577
752
|
"content-type": "application/json",
|
|
578
753
|
"user-agent": USER_AGENT,
|
|
579
|
-
|
|
754
|
+
authorization: `Bearer ${config.workspaceKey}`
|
|
580
755
|
},
|
|
581
756
|
body: payload
|
|
582
757
|
});
|
|
@@ -840,6 +1015,24 @@ class Gurulu {
|
|
|
840
1015
|
const res = this.queue?.enqueue(event) ?? { queued: false, dropped: 0 };
|
|
841
1016
|
return { queued: res.queued, queueSize: this.queue?.size() ?? 0 };
|
|
842
1017
|
}
|
|
1018
|
+
get llm() {
|
|
1019
|
+
this.requireConfig();
|
|
1020
|
+
return {
|
|
1021
|
+
capture: (input, captureContent = false) => this.track("llm_request", buildLlmProperties(input, captureContent), undefined, "interaction")
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
wrapOpenAI(client, opts) {
|
|
1025
|
+
const captureContent = opts?.captureContent ?? false;
|
|
1026
|
+
return wrapOpenAIClient((input) => {
|
|
1027
|
+
this.llm.capture(input, captureContent);
|
|
1028
|
+
}, client, opts);
|
|
1029
|
+
}
|
|
1030
|
+
wrapAnthropic(client, opts) {
|
|
1031
|
+
const captureContent = opts?.captureContent ?? false;
|
|
1032
|
+
return wrapAnthropicClient((input) => {
|
|
1033
|
+
this.llm.capture(input, captureContent);
|
|
1034
|
+
}, client, opts);
|
|
1035
|
+
}
|
|
843
1036
|
async flush() {
|
|
844
1037
|
this.requireConfig();
|
|
845
1038
|
return await this.queue?.flush() ?? { attempted: 0, succeeded: 0, dropped: 0 };
|
|
@@ -915,6 +1108,8 @@ function initDefault(config) {
|
|
|
915
1108
|
// src/index.ts
|
|
916
1109
|
var VERSION = "0.1.0";
|
|
917
1110
|
export {
|
|
1111
|
+
wrapOpenAIClient,
|
|
1112
|
+
wrapAnthropicClient,
|
|
918
1113
|
verifyStripe,
|
|
919
1114
|
verifyShopify,
|
|
920
1115
|
verifyLemonSqueezy,
|
|
@@ -931,6 +1126,7 @@ export {
|
|
|
931
1126
|
createFastifyPlugin,
|
|
932
1127
|
createExpressMiddleware,
|
|
933
1128
|
contextStorage,
|
|
1129
|
+
buildLlmProperties,
|
|
934
1130
|
WebhookSignatureError,
|
|
935
1131
|
WebhookMappingNotFoundError,
|
|
936
1132
|
VERSION,
|
package/dist/llm.d.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export type LlmProvider = 'openai' | 'anthropic' | 'google' | 'azure' | 'bedrock' | 'local' | 'other';
|
|
2
|
+
export type LlmOperation = 'chat' | 'completion' | 'embedding' | 'rerank' | 'image';
|
|
3
|
+
export type LlmStatus = 'success' | 'error' | 'timeout' | 'rate_limited';
|
|
4
|
+
export interface LlmCaptureInput {
|
|
5
|
+
provider: LlmProvider | string;
|
|
6
|
+
model: string;
|
|
7
|
+
operation: LlmOperation | string;
|
|
8
|
+
promptTokens: number;
|
|
9
|
+
completionTokens: number;
|
|
10
|
+
/** Yoksa prompt+completion (capture türetir). */
|
|
11
|
+
totalTokens?: number;
|
|
12
|
+
latencyMs: number;
|
|
13
|
+
status: LlmStatus | string;
|
|
14
|
+
/** Müşteri ham $ cost — verilirse backend bunu kullanır (yoksa map'ten türer). */
|
|
15
|
+
cost?: number;
|
|
16
|
+
currency?: string;
|
|
17
|
+
errorType?: string;
|
|
18
|
+
/** Müşterinin AI özellik adı (chatbot/rag/copilot) — gruplama. */
|
|
19
|
+
feature?: string;
|
|
20
|
+
cacheHit?: boolean;
|
|
21
|
+
stream?: boolean;
|
|
22
|
+
/** Opt-in içerik — sadece captureContent:true ile gönderilir (K31). */
|
|
23
|
+
promptContent?: unknown;
|
|
24
|
+
responseContent?: unknown;
|
|
25
|
+
}
|
|
26
|
+
export interface WrapOptions {
|
|
27
|
+
/** AI özellik adı — yakalanan tüm çağrılara feature olarak eklenir. */
|
|
28
|
+
feature?: string;
|
|
29
|
+
/** Opt-in: prompt/response gövdesini de gönder (default false). */
|
|
30
|
+
captureContent?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** LlmCaptureInput → registry `llm_request` property paketi (snake_case, K17). */
|
|
33
|
+
export declare function buildLlmProperties(input: LlmCaptureInput, captureContent: boolean): Record<string, unknown>;
|
|
34
|
+
/** capture callback — Gurulu.llm.capture'a bağlanır. */
|
|
35
|
+
export type LlmCaptureFn = (input: LlmCaptureInput) => void;
|
|
36
|
+
/** OpenAI client'ı yerinde instrument eder (chat.completions + embeddings + responses). */
|
|
37
|
+
export declare function wrapOpenAIClient<T>(capture: LlmCaptureFn, client: T, opts?: WrapOptions): T;
|
|
38
|
+
/** Anthropic client'ı yerinde instrument eder (messages.create). */
|
|
39
|
+
export declare function wrapAnthropicClient<T>(capture: LlmCaptureFn, client: T, opts?: WrapOptions): T;
|
|
40
|
+
//# sourceMappingURL=llm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"AAWA,MAAM,MAAM,WAAW,GACnB,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,OAAO,GACP,SAAS,GACT,OAAO,GACP,OAAO,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAC;AACpF,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,CAAC;AAEzE,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,GAAG,MAAM,CAAC;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,YAAY,GAAG,MAAM,CAAC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,GAAG,MAAM,CAAC;IAC3B,kFAAkF;IAClF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,eAAe,EACtB,cAAc,EAAE,OAAO,GACtB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAwBzB;AAED,wDAAwD;AACxD,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AA0J5D,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,GAAE,WAAgB,GAAG,CAAC,CAyB/F;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,CAAC,EACT,IAAI,GAAE,WAAgB,GACrB,CAAC,CAQH"}
|