@firstflow/core 0.0.6 → 0.0.9
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/anthropic.d.mts +9 -0
- package/dist/anthropic.d.ts +9 -0
- package/dist/anthropic.mjs +3 -2
- package/dist/{chunk-RZMKPIBO.mjs → chunk-KAH2MUTQ.mjs} +4 -2
- package/dist/{chunk-X3T7X4JQ.mjs → chunk-QBEGXT76.mjs} +12 -407
- package/dist/chunk-WQZUOUMF.mjs +404 -0
- package/dist/index.mjs +5 -3
- package/dist/langchain.d.mts +56 -0
- package/dist/langchain.d.ts +56 -0
- package/dist/langchain.js +1661 -0
- package/dist/langchain.mjs +277 -0
- package/dist/openai.d.mts +9 -0
- package/dist/openai.d.ts +9 -0
- package/dist/openai.mjs +3 -2
- package/package.json +22 -3
package/dist/anthropic.d.mts
CHANGED
|
@@ -15,5 +15,14 @@ declare module "@anthropic-ai/sdk/resources/messages/messages" {
|
|
|
15
15
|
|
|
16
16
|
/** Drop-in `Anthropic` client with Firstflow observability built in. */
|
|
17
17
|
declare const Anthropic: typeof RealAnthropic;
|
|
18
|
+
/**
|
|
19
|
+
* Instance type of the wrapped client, so consumers can annotate naturally:
|
|
20
|
+
*
|
|
21
|
+
* private readonly client: Anthropic = new Anthropic();
|
|
22
|
+
*
|
|
23
|
+
* `Anthropic` lives in both the value and type namespaces (the `const` above is
|
|
24
|
+
* the value; this alias is the type), mirroring how the real SDK's class works.
|
|
25
|
+
*/
|
|
26
|
+
type Anthropic = RealAnthropic;
|
|
18
27
|
|
|
19
28
|
export { Anthropic };
|
package/dist/anthropic.d.ts
CHANGED
|
@@ -15,5 +15,14 @@ declare module "@anthropic-ai/sdk/resources/messages/messages" {
|
|
|
15
15
|
|
|
16
16
|
/** Drop-in `Anthropic` client with Firstflow observability built in. */
|
|
17
17
|
declare const Anthropic: typeof RealAnthropic;
|
|
18
|
+
/**
|
|
19
|
+
* Instance type of the wrapped client, so consumers can annotate naturally:
|
|
20
|
+
*
|
|
21
|
+
* private readonly client: Anthropic = new Anthropic();
|
|
22
|
+
*
|
|
23
|
+
* `Anthropic` lives in both the value and type namespaces (the `const` above is
|
|
24
|
+
* the value; this alias is the type), mirroring how the real SDK's class works.
|
|
25
|
+
*/
|
|
26
|
+
type Anthropic = RealAnthropic;
|
|
18
27
|
|
|
19
28
|
export { Anthropic };
|
package/dist/anthropic.mjs
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
// src/constants.ts
|
|
2
|
+
var DEFAULT_FIRSTFLOW_BASE_URL = "https://api.firstflow.app";
|
|
3
|
+
var FIRSTFLOW_SERVER_PACKAGE_VERSION = "0.0.1-alpha.0";
|
|
4
|
+
|
|
5
|
+
// src/runtime.ts
|
|
6
|
+
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
7
|
+
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
8
|
+
import { OpenAIInstrumentation } from "@opentelemetry/instrumentation-openai";
|
|
9
|
+
import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
|
|
10
|
+
|
|
1
11
|
// node_modules/@opentelemetry/api/build/esm/version.js
|
|
2
12
|
var VERSION = "1.9.1";
|
|
3
13
|
|
|
@@ -500,412 +510,6 @@ var PropagationAPI = class _PropagationAPI {
|
|
|
500
510
|
// node_modules/@opentelemetry/api/build/esm/propagation-api.js
|
|
501
511
|
var propagation = PropagationAPI.getInstance();
|
|
502
512
|
|
|
503
|
-
// src/wrap.ts
|
|
504
|
-
var INSTRUMENTED_PATHS = /* @__PURE__ */ new Set([
|
|
505
|
-
"chat.completions.create",
|
|
506
|
-
"embeddings.create",
|
|
507
|
-
"responses.create",
|
|
508
|
-
"messages.create"
|
|
509
|
-
]);
|
|
510
|
-
var warnedIncompleteTagging = false;
|
|
511
|
-
function parseFirstflowMeta(args) {
|
|
512
|
-
const nextArgs = [...args];
|
|
513
|
-
for (let i = 0; i < nextArgs.length; i++) {
|
|
514
|
-
const a = nextArgs[i];
|
|
515
|
-
if (typeof a !== "object" || a === null) continue;
|
|
516
|
-
const rec = a;
|
|
517
|
-
if (!("firstflowAgentId" in rec) && !("sessionId" in rec) && !("userId" in rec)) {
|
|
518
|
-
continue;
|
|
519
|
-
}
|
|
520
|
-
const agentId = typeof rec.firstflowAgentId === "string" ? rec.firstflowAgentId.trim() : "";
|
|
521
|
-
const sessionId = typeof rec.sessionId === "string" ? rec.sessionId.trim() : "";
|
|
522
|
-
const userId = typeof rec.userId === "string" ? rec.userId.trim() : "";
|
|
523
|
-
const { firstflowAgentId: _a, sessionId: _s, userId: _u, ...rest } = rec;
|
|
524
|
-
nextArgs[i] = rest;
|
|
525
|
-
if (!agentId || !sessionId || !userId) {
|
|
526
|
-
if (!warnedIncompleteTagging) {
|
|
527
|
-
warnedIncompleteTagging = true;
|
|
528
|
-
console.warn(
|
|
529
|
-
"[@firstflow/core] LLM call tagged with some but not all of `firstflowAgentId`, `sessionId`, `userId` \u2014 the call was NOT observed. Provide all three to track it."
|
|
530
|
-
);
|
|
531
|
-
}
|
|
532
|
-
return { nextArgs };
|
|
533
|
-
}
|
|
534
|
-
return { nextArgs, meta: { agentId, userId, conversationId: sessionId } };
|
|
535
|
-
}
|
|
536
|
-
return { nextArgs };
|
|
537
|
-
}
|
|
538
|
-
function extractModel(nextArgs) {
|
|
539
|
-
const body = nextArgs[0];
|
|
540
|
-
if (!body || typeof body !== "object") return void 0;
|
|
541
|
-
const m = body.model;
|
|
542
|
-
return typeof m === "string" ? m : void 0;
|
|
543
|
-
}
|
|
544
|
-
function detectProvider(path) {
|
|
545
|
-
return path === "messages.create" ? "anthropic" : "openai";
|
|
546
|
-
}
|
|
547
|
-
function injectOpenAiStreamUsage(nextArgs) {
|
|
548
|
-
const body = nextArgs[0];
|
|
549
|
-
if (!body || typeof body !== "object") return nextArgs;
|
|
550
|
-
const b = body;
|
|
551
|
-
if (b.stream !== true) return nextArgs;
|
|
552
|
-
const existing = b.stream_options ?? {};
|
|
553
|
-
if (existing.include_usage === true) return nextArgs;
|
|
554
|
-
const patched = [...nextArgs];
|
|
555
|
-
patched[0] = { ...b, stream_options: { ...existing, include_usage: true } };
|
|
556
|
-
return patched;
|
|
557
|
-
}
|
|
558
|
-
function extractOpenAiResponseMeta(res) {
|
|
559
|
-
const usage = res.usage;
|
|
560
|
-
const details = usage?.prompt_tokens_details;
|
|
561
|
-
const choice = Array.isArray(res.choices) ? res.choices[0] : void 0;
|
|
562
|
-
return {
|
|
563
|
-
inputTokens: typeof usage?.prompt_tokens === "number" ? usage.prompt_tokens : void 0,
|
|
564
|
-
outputTokens: typeof usage?.completion_tokens === "number" ? usage.completion_tokens : void 0,
|
|
565
|
-
cacheReadTokens: typeof details?.cached_tokens === "number" ? details.cached_tokens : void 0,
|
|
566
|
-
finishReason: typeof choice?.finish_reason === "string" ? choice.finish_reason : void 0
|
|
567
|
-
};
|
|
568
|
-
}
|
|
569
|
-
function extractAnthropicResponseMeta(res) {
|
|
570
|
-
const usage = res.usage;
|
|
571
|
-
return {
|
|
572
|
-
inputTokens: typeof usage?.input_tokens === "number" ? usage.input_tokens : void 0,
|
|
573
|
-
outputTokens: typeof usage?.output_tokens === "number" ? usage.output_tokens : void 0,
|
|
574
|
-
cacheReadTokens: typeof usage?.cache_read_input_tokens === "number" ? usage.cache_read_input_tokens : void 0,
|
|
575
|
-
cacheCreationTokens: typeof usage?.cache_creation_input_tokens === "number" ? usage.cache_creation_input_tokens : void 0,
|
|
576
|
-
finishReason: typeof res.stop_reason === "string" ? res.stop_reason : void 0
|
|
577
|
-
};
|
|
578
|
-
}
|
|
579
|
-
function accumOpenAiStreamChunkMeta(chunk, acc) {
|
|
580
|
-
if (!chunk || typeof chunk !== "object") return;
|
|
581
|
-
const c = chunk;
|
|
582
|
-
if (c.usage && typeof c.usage === "object") {
|
|
583
|
-
const usage = c.usage;
|
|
584
|
-
const details = usage.prompt_tokens_details;
|
|
585
|
-
if (typeof usage.prompt_tokens === "number") acc.inputTokens = usage.prompt_tokens;
|
|
586
|
-
if (typeof usage.completion_tokens === "number") acc.outputTokens = usage.completion_tokens;
|
|
587
|
-
if (typeof details?.cached_tokens === "number") acc.cacheReadTokens = details.cached_tokens;
|
|
588
|
-
}
|
|
589
|
-
if (Array.isArray(c.choices) && c.choices[0]) {
|
|
590
|
-
const choice = c.choices[0];
|
|
591
|
-
if (typeof choice.finish_reason === "string" && choice.finish_reason) {
|
|
592
|
-
acc.finishReason = choice.finish_reason;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
function accumAnthropicStreamChunkMeta(chunk, acc) {
|
|
597
|
-
if (!chunk || typeof chunk !== "object") return;
|
|
598
|
-
const c = chunk;
|
|
599
|
-
if (c.type === "message_start") {
|
|
600
|
-
const msg = c.message;
|
|
601
|
-
const usage = msg?.usage;
|
|
602
|
-
if (typeof usage?.input_tokens === "number") acc.inputTokens = usage.input_tokens;
|
|
603
|
-
if (typeof usage?.cache_read_input_tokens === "number")
|
|
604
|
-
acc.cacheReadTokens = usage.cache_read_input_tokens;
|
|
605
|
-
if (typeof usage?.cache_creation_input_tokens === "number")
|
|
606
|
-
acc.cacheCreationTokens = usage.cache_creation_input_tokens;
|
|
607
|
-
}
|
|
608
|
-
if (c.type === "message_delta") {
|
|
609
|
-
const usage = c.usage;
|
|
610
|
-
const delta = c.delta;
|
|
611
|
-
if (typeof usage?.output_tokens === "number") acc.outputTokens = usage.output_tokens;
|
|
612
|
-
if (typeof delta?.stop_reason === "string") acc.finishReason = delta.stop_reason;
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
function isAsyncIterable(v) {
|
|
616
|
-
return typeof v === "object" && v !== null && Symbol.asyncIterator in v && typeof v[Symbol.asyncIterator] === "function";
|
|
617
|
-
}
|
|
618
|
-
function streamChunkText(chunk) {
|
|
619
|
-
if (!chunk || typeof chunk !== "object") return "";
|
|
620
|
-
const c = chunk;
|
|
621
|
-
if (Array.isArray(c.choices)) {
|
|
622
|
-
const choice = c.choices[0];
|
|
623
|
-
if (choice && typeof choice === "object") {
|
|
624
|
-
const delta = choice.delta;
|
|
625
|
-
if (delta && typeof delta === "object") {
|
|
626
|
-
const content = delta.content;
|
|
627
|
-
if (typeof content === "string") return content;
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
if (c.type === "content_block_delta") {
|
|
632
|
-
const delta = c.delta;
|
|
633
|
-
if (delta && typeof delta === "object") {
|
|
634
|
-
const d = delta;
|
|
635
|
-
if (d.type === "text_delta" && typeof d.text === "string") return d.text;
|
|
636
|
-
}
|
|
637
|
-
}
|
|
638
|
-
return "";
|
|
639
|
-
}
|
|
640
|
-
function wrapAsyncIterableForAssistantHook(stream, hook, provider, startTime) {
|
|
641
|
-
return {
|
|
642
|
-
async *[Symbol.asyncIterator]() {
|
|
643
|
-
let content = "";
|
|
644
|
-
let firstChunkTime = -1;
|
|
645
|
-
let streamError;
|
|
646
|
-
const acc = {};
|
|
647
|
-
const accumChunkMeta = provider === "anthropic" ? accumAnthropicStreamChunkMeta : accumOpenAiStreamChunkMeta;
|
|
648
|
-
try {
|
|
649
|
-
for await (const chunk of stream) {
|
|
650
|
-
if (firstChunkTime === -1) firstChunkTime = Date.now();
|
|
651
|
-
content += streamChunkText(chunk);
|
|
652
|
-
accumChunkMeta(chunk, acc);
|
|
653
|
-
yield chunk;
|
|
654
|
-
}
|
|
655
|
-
} catch (err) {
|
|
656
|
-
streamError = err;
|
|
657
|
-
throw err;
|
|
658
|
-
} finally {
|
|
659
|
-
hook(content, {
|
|
660
|
-
...acc,
|
|
661
|
-
httpStatus: streamError != null ? streamError.status ?? 500 : 200,
|
|
662
|
-
latencyMs: Date.now() - startTime,
|
|
663
|
-
timeToFirstTokenMs: firstChunkTime === -1 ? void 0 : firstChunkTime - startTime
|
|
664
|
-
});
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
function firstArgBodyStream(nextArgs) {
|
|
670
|
-
const body = nextArgs[0];
|
|
671
|
-
return !!(body && typeof body === "object" && body !== null && body.stream === true);
|
|
672
|
-
}
|
|
673
|
-
function extractAnthropicAssistantText(res) {
|
|
674
|
-
const content = res.content;
|
|
675
|
-
if (!Array.isArray(content)) return "";
|
|
676
|
-
let acc = "";
|
|
677
|
-
for (const item of content) {
|
|
678
|
-
if (item && typeof item === "object" && !Array.isArray(item)) {
|
|
679
|
-
const o = item;
|
|
680
|
-
if (o.type === "text" && typeof o.text === "string") {
|
|
681
|
-
acc += o.text;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
return acc;
|
|
686
|
-
}
|
|
687
|
-
function extractOpenAiAssistantText(res) {
|
|
688
|
-
if (!Array.isArray(res.choices) || !res.choices[0] || typeof res.choices[0] !== "object") {
|
|
689
|
-
return "";
|
|
690
|
-
}
|
|
691
|
-
const message = res.choices[0].message;
|
|
692
|
-
return typeof message?.content === "string" ? message.content : "";
|
|
693
|
-
}
|
|
694
|
-
function isThenable(v) {
|
|
695
|
-
return !!v && (typeof v === "object" || typeof v === "function") && "then" in v && typeof v.then === "function";
|
|
696
|
-
}
|
|
697
|
-
function messageContentToText(content) {
|
|
698
|
-
if (typeof content === "string") return content;
|
|
699
|
-
if (!Array.isArray(content)) return "";
|
|
700
|
-
let acc = "";
|
|
701
|
-
for (const part of content) {
|
|
702
|
-
if (part && typeof part === "object" && !Array.isArray(part)) {
|
|
703
|
-
const p = part;
|
|
704
|
-
if (p.type === "text" && typeof p.text === "string") acc += p.text;
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
return acc;
|
|
708
|
-
}
|
|
709
|
-
function extractRecentMessages(nextArgs) {
|
|
710
|
-
const body = nextArgs[0];
|
|
711
|
-
if (!body || typeof body !== "object") return [];
|
|
712
|
-
const messages = body.messages;
|
|
713
|
-
if (!Array.isArray(messages)) return [];
|
|
714
|
-
const out = [];
|
|
715
|
-
for (const m of messages) {
|
|
716
|
-
if (!m || typeof m !== "object") continue;
|
|
717
|
-
const rec = m;
|
|
718
|
-
if (rec.role !== "user" && rec.role !== "assistant") continue;
|
|
719
|
-
const content = messageContentToText(rec.content).trim();
|
|
720
|
-
if (!content) continue;
|
|
721
|
-
out.push({ role: rec.role, content });
|
|
722
|
-
}
|
|
723
|
-
return out;
|
|
724
|
-
}
|
|
725
|
-
function extractTurnStartUserMessage(nextArgs) {
|
|
726
|
-
const body = nextArgs[0];
|
|
727
|
-
if (!body || typeof body !== "object") return void 0;
|
|
728
|
-
const messages = body.messages;
|
|
729
|
-
if (!Array.isArray(messages) || messages.length === 0) return void 0;
|
|
730
|
-
const last = messages[messages.length - 1];
|
|
731
|
-
if (!last || typeof last !== "object") return void 0;
|
|
732
|
-
const rec = last;
|
|
733
|
-
if (rec.role !== "user") return void 0;
|
|
734
|
-
const text = messageContentToText(rec.content).trim();
|
|
735
|
-
return text || void 0;
|
|
736
|
-
}
|
|
737
|
-
function withFirstflowBaggage(meta, fn) {
|
|
738
|
-
const base = propagation.getBaggage(context.active()) ?? propagation.createBaggage();
|
|
739
|
-
const bag = base.setEntry("firstflow.user_id", { value: meta.userId }).setEntry("firstflow.agent_id", { value: meta.agentId });
|
|
740
|
-
return context.with(propagation.setBaggage(context.active(), bag), fn);
|
|
741
|
-
}
|
|
742
|
-
function maybeObserveUserMessage(path, nextArgs, meta, ctx) {
|
|
743
|
-
if (!ctx.onUserMessage) return;
|
|
744
|
-
if (path !== "chat.completions.create" && path !== "messages.create") return;
|
|
745
|
-
if (!meta.conversationId) return;
|
|
746
|
-
const content = extractTurnStartUserMessage(nextArgs);
|
|
747
|
-
if (!content) return;
|
|
748
|
-
const recentMessages = extractRecentMessages(nextArgs);
|
|
749
|
-
ctx.onUserMessage({
|
|
750
|
-
agentId: meta.agentId,
|
|
751
|
-
conversationId: meta.conversationId,
|
|
752
|
-
userId: meta.userId,
|
|
753
|
-
role: "user",
|
|
754
|
-
content,
|
|
755
|
-
model: extractModel(nextArgs),
|
|
756
|
-
provider: detectProvider(path),
|
|
757
|
-
...recentMessages.length ? { recentMessages } : {}
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
function maybeAttachAssistantHook(path, nextArgs, result, meta, ctx, startTime) {
|
|
761
|
-
if (!ctx.onAssistantComplete) return void 0;
|
|
762
|
-
if (path !== "chat.completions.create" && path !== "messages.create") {
|
|
763
|
-
return void 0;
|
|
764
|
-
}
|
|
765
|
-
const convId = meta.conversationId;
|
|
766
|
-
const recentMessages = extractRecentMessages(nextArgs);
|
|
767
|
-
const model = extractModel(nextArgs);
|
|
768
|
-
const provider = detectProvider(path);
|
|
769
|
-
const extractFull = path === "chat.completions.create" ? extractOpenAiAssistantText : extractAnthropicAssistantText;
|
|
770
|
-
const extractMeta = path === "chat.completions.create" ? extractOpenAiResponseMeta : extractAnthropicResponseMeta;
|
|
771
|
-
const emit = (content, llmMeta) => {
|
|
772
|
-
if (!convId) return;
|
|
773
|
-
ctx.onAssistantComplete?.({
|
|
774
|
-
agentId: meta.agentId,
|
|
775
|
-
conversationId: convId,
|
|
776
|
-
userId: meta.userId,
|
|
777
|
-
role: "assistant",
|
|
778
|
-
content,
|
|
779
|
-
model,
|
|
780
|
-
provider,
|
|
781
|
-
...llmMeta,
|
|
782
|
-
...recentMessages.length ? { recentMessages } : {}
|
|
783
|
-
});
|
|
784
|
-
};
|
|
785
|
-
if (firstArgBodyStream(nextArgs)) {
|
|
786
|
-
const wrapStream = (stream) => wrapAsyncIterableForAssistantHook(
|
|
787
|
-
stream,
|
|
788
|
-
(content, streamMeta) => emit(content, streamMeta),
|
|
789
|
-
provider,
|
|
790
|
-
startTime
|
|
791
|
-
);
|
|
792
|
-
if (isAsyncIterable(result)) {
|
|
793
|
-
return wrapStream(result);
|
|
794
|
-
}
|
|
795
|
-
if (isThenable(result)) {
|
|
796
|
-
return result.then(
|
|
797
|
-
(resolved) => isAsyncIterable(resolved) ? wrapStream(resolved) : resolved
|
|
798
|
-
);
|
|
799
|
-
}
|
|
800
|
-
return void 0;
|
|
801
|
-
}
|
|
802
|
-
if (isThenable(result)) {
|
|
803
|
-
return result.then((res) => {
|
|
804
|
-
const latencyMs = Date.now() - startTime;
|
|
805
|
-
const resMeta = extractMeta(res ?? {});
|
|
806
|
-
emit(extractFull(res ?? {}), { ...resMeta, latencyMs, httpStatus: 200 });
|
|
807
|
-
return res;
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
return void 0;
|
|
811
|
-
}
|
|
812
|
-
function wrapInstrumentedInvocation(path, original, thisArg, args, ctx) {
|
|
813
|
-
const parsed = parseFirstflowMeta(args);
|
|
814
|
-
const { meta } = parsed;
|
|
815
|
-
let nextArgs = parsed.nextArgs;
|
|
816
|
-
if (path === "chat.completions.create") {
|
|
817
|
-
nextArgs = injectOpenAiStreamUsage(nextArgs);
|
|
818
|
-
}
|
|
819
|
-
const startTime = Date.now();
|
|
820
|
-
const run = () => {
|
|
821
|
-
if (meta) maybeObserveUserMessage(path, nextArgs, meta, ctx);
|
|
822
|
-
let result;
|
|
823
|
-
try {
|
|
824
|
-
result = Reflect.apply(original, thisArg, nextArgs);
|
|
825
|
-
} catch (err) {
|
|
826
|
-
if (meta?.conversationId && ctx.onError) {
|
|
827
|
-
ctx.onError({
|
|
828
|
-
agentId: meta.agentId,
|
|
829
|
-
conversationId: meta.conversationId,
|
|
830
|
-
userId: meta.userId,
|
|
831
|
-
isError: true,
|
|
832
|
-
error: err instanceof Error ? err.message : String(err),
|
|
833
|
-
model: extractModel(nextArgs),
|
|
834
|
-
provider: detectProvider(path),
|
|
835
|
-
latencyMs: Date.now() - startTime,
|
|
836
|
-
httpStatus: err.status
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
throw err;
|
|
840
|
-
}
|
|
841
|
-
if (isThenable(result) && meta?.conversationId && ctx.onError) {
|
|
842
|
-
result = result.catch((err) => {
|
|
843
|
-
ctx.onError({
|
|
844
|
-
agentId: meta.agentId,
|
|
845
|
-
conversationId: meta.conversationId,
|
|
846
|
-
userId: meta.userId,
|
|
847
|
-
isError: true,
|
|
848
|
-
error: err instanceof Error ? err.message : String(err),
|
|
849
|
-
model: extractModel(nextArgs),
|
|
850
|
-
provider: detectProvider(path),
|
|
851
|
-
latencyMs: Date.now() - startTime,
|
|
852
|
-
httpStatus: err.status
|
|
853
|
-
});
|
|
854
|
-
return Promise.reject(err);
|
|
855
|
-
});
|
|
856
|
-
}
|
|
857
|
-
if (meta) {
|
|
858
|
-
const hooked = maybeAttachAssistantHook(path, nextArgs, result, meta, ctx, startTime);
|
|
859
|
-
if (hooked !== void 0) return hooked;
|
|
860
|
-
}
|
|
861
|
-
return result;
|
|
862
|
-
};
|
|
863
|
-
if (meta) {
|
|
864
|
-
return withFirstflowBaggage(meta, run);
|
|
865
|
-
}
|
|
866
|
-
return run();
|
|
867
|
-
}
|
|
868
|
-
function createNestedProxy(target, path, ctx) {
|
|
869
|
-
return new Proxy(target, {
|
|
870
|
-
get(_t, prop, receiver) {
|
|
871
|
-
const key = String(prop);
|
|
872
|
-
const value = Reflect.get(target, prop, receiver);
|
|
873
|
-
if (typeof value === "function") {
|
|
874
|
-
const joined = [...path, key].join(".");
|
|
875
|
-
return (...fnArgs) => {
|
|
876
|
-
if (INSTRUMENTED_PATHS.has(joined)) {
|
|
877
|
-
return wrapInstrumentedInvocation(
|
|
878
|
-
joined,
|
|
879
|
-
value,
|
|
880
|
-
target,
|
|
881
|
-
fnArgs,
|
|
882
|
-
ctx
|
|
883
|
-
);
|
|
884
|
-
}
|
|
885
|
-
return Reflect.apply(value, target, fnArgs);
|
|
886
|
-
};
|
|
887
|
-
}
|
|
888
|
-
if (value !== null && typeof value === "object") {
|
|
889
|
-
return createNestedProxy(value, [...path, key], ctx);
|
|
890
|
-
}
|
|
891
|
-
return value;
|
|
892
|
-
}
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
function wrapClient(client, ctx) {
|
|
896
|
-
return createNestedProxy(client, [], ctx);
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
// src/constants.ts
|
|
900
|
-
var DEFAULT_FIRSTFLOW_BASE_URL = "https://api.firstflow.app";
|
|
901
|
-
var FIRSTFLOW_SERVER_PACKAGE_VERSION = "0.0.1-alpha.0";
|
|
902
|
-
|
|
903
|
-
// src/runtime.ts
|
|
904
|
-
import { NodeSDK } from "@opentelemetry/sdk-node";
|
|
905
|
-
import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
906
|
-
import { OpenAIInstrumentation } from "@opentelemetry/instrumentation-openai";
|
|
907
|
-
import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
|
|
908
|
-
|
|
909
513
|
// src/firstflow-span-processor.ts
|
|
910
514
|
var FLUSH_SIZE = 20;
|
|
911
515
|
var FLUSH_INTERVAL_MS = 2e3;
|
|
@@ -1751,7 +1355,8 @@ function getRuntime() {
|
|
|
1751
1355
|
}
|
|
1752
1356
|
|
|
1753
1357
|
export {
|
|
1754
|
-
|
|
1358
|
+
context,
|
|
1359
|
+
propagation,
|
|
1755
1360
|
DEFAULT_FIRSTFLOW_BASE_URL,
|
|
1756
1361
|
FIRSTFLOW_SERVER_PACKAGE_VERSION,
|
|
1757
1362
|
getRuntime
|