@raindrop-ai/pi-agent 0.1.0 → 0.1.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.
- package/dist/{chunk-XQJ6G4YA.js → chunk-GTKXT2J5.js} +223 -3
- package/dist/extension.cjs +235 -10
- package/dist/extension.js +17 -9
- package/dist/index.cjs +246 -36
- package/dist/index.js +26 -34
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../core/dist/chunk-
|
|
1
|
+
// ../core/dist/chunk-YUIXRQWN.js
|
|
2
2
|
function getCrypto() {
|
|
3
3
|
const c = globalThis.crypto;
|
|
4
4
|
return c;
|
|
@@ -56,6 +56,20 @@ function base64Encode(bytes) {
|
|
|
56
56
|
function generateId() {
|
|
57
57
|
return randomUUID();
|
|
58
58
|
}
|
|
59
|
+
var HANDOFF_ATTRIBUTE_SUFFIXES = {
|
|
60
|
+
mode: "raindrop.handoff.mode",
|
|
61
|
+
childEventId: "raindrop.handoff.childEventId",
|
|
62
|
+
parentEventId: "raindrop.handoff.parentEventId",
|
|
63
|
+
parentSpanId: "raindrop.handoff.parentSpanId",
|
|
64
|
+
name: "raindrop.handoff.name",
|
|
65
|
+
terminal: "raindrop.handoff.terminal",
|
|
66
|
+
agentRole: "raindrop.agent.role"
|
|
67
|
+
};
|
|
68
|
+
var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
|
|
69
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
70
|
+
var BAGGAGE_HEADER = "baggage";
|
|
71
|
+
var HANDOFF_HEADER = "x-raindrop-handoff";
|
|
72
|
+
var UNRESOLVED_CARRIER_WARNING = `[raindrop] resume: headers were supplied but no hand-off carrier was found on them (searched ${HANDOFF_HEADER}, ${TRACEPARENT_HEADER}, ${BAGGAGE_HEADER}). This run reports as an UNLINKED event, and the launcher that dispatched it will stay on "queued" forever because nothing ever references its child. Passing headers means a parent handed off, so no carrier on them is almost certainly a defect: a gateway or proxy stripping ${HANDOFF_HEADER}, a middleware overwriting ${BAGGAGE_HEADER}, a request forwarded without its headers, or a hand-built carrier whose field names do not match. Send every header the launcher's dispatch returned. Logged once per process; pass no headers for a directly-invoked sub-agent to silence it.`;
|
|
59
73
|
function runWithTracingSuppressed(fn) {
|
|
60
74
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
61
75
|
if (typeof hook !== "function") return fn();
|
|
@@ -774,6 +788,194 @@ var EventShipper = class {
|
|
|
774
788
|
}
|
|
775
789
|
}
|
|
776
790
|
};
|
|
791
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
792
|
+
providerName: "gen_ai.provider.name",
|
|
793
|
+
requestModel: "gen_ai.request.model",
|
|
794
|
+
responseModel: "gen_ai.response.model",
|
|
795
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
796
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
797
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
798
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
799
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
800
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
801
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
802
|
+
totalOutputTokens: "raindrop.usage.output_tokens.total",
|
|
803
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
804
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
805
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
806
|
+
};
|
|
807
|
+
var MODEL_PROVIDER_NAMES = [
|
|
808
|
+
["google.vertex", "google-vertex"],
|
|
809
|
+
["vertex.anthropic", "google-vertex"],
|
|
810
|
+
["amazon-bedrock", "amazon-bedrock"],
|
|
811
|
+
["bedrock", "amazon-bedrock"],
|
|
812
|
+
["anthropic", "anthropic"],
|
|
813
|
+
["openai", "openai"],
|
|
814
|
+
["google", "google"],
|
|
815
|
+
["azure", "azure"],
|
|
816
|
+
["openrouter", "openrouter"]
|
|
817
|
+
];
|
|
818
|
+
function canonicalModelProvider(provider) {
|
|
819
|
+
var _a;
|
|
820
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
821
|
+
if (normalizedProvider === "gateway") return "vercel";
|
|
822
|
+
const match = MODEL_PROVIDER_NAMES.find(
|
|
823
|
+
([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
|
|
824
|
+
);
|
|
825
|
+
return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
|
|
826
|
+
}
|
|
827
|
+
function tokenCount(value) {
|
|
828
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
829
|
+
}
|
|
830
|
+
function exclusiveTokens({
|
|
831
|
+
explicit,
|
|
832
|
+
total,
|
|
833
|
+
parts,
|
|
834
|
+
semantics
|
|
835
|
+
}) {
|
|
836
|
+
if (explicit !== void 0) return explicit;
|
|
837
|
+
if (total === void 0) return void 0;
|
|
838
|
+
if (semantics === "exclusive") return total;
|
|
839
|
+
const observedParts = parts.filter((part) => part !== void 0 && part > 0);
|
|
840
|
+
if (semantics === void 0 && observedParts.length > 0) return void 0;
|
|
841
|
+
const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
|
|
842
|
+
return exclusive >= 0 ? exclusive : void 0;
|
|
843
|
+
}
|
|
844
|
+
function buildModelUsageAttributes(usage) {
|
|
845
|
+
const inputTokens = tokenCount(usage.inputTokens);
|
|
846
|
+
const outputTokens = tokenCount(usage.outputTokens);
|
|
847
|
+
const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
|
|
848
|
+
const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
|
|
849
|
+
const reasoningTokens = tokenCount(usage.reasoningTokens);
|
|
850
|
+
const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
|
|
851
|
+
const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
|
|
852
|
+
const nonCachedInputTokens = exclusiveTokens({
|
|
853
|
+
explicit: explicitNonCachedInputTokens,
|
|
854
|
+
total: inputTokens,
|
|
855
|
+
parts: [cacheReadInputTokens, cacheWriteInputTokens],
|
|
856
|
+
semantics: usage.inputTokenSemantics
|
|
857
|
+
});
|
|
858
|
+
const nonReasoningOutputTokens = exclusiveTokens({
|
|
859
|
+
explicit: explicitNonReasoningOutputTokens,
|
|
860
|
+
total: outputTokens,
|
|
861
|
+
parts: [reasoningTokens],
|
|
862
|
+
semantics: usage.outputTokenSemantics
|
|
863
|
+
});
|
|
864
|
+
const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
|
|
865
|
+
// backend consumes this complete raindrop.* set as one atomic billing-pool contract.
|
|
866
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
|
|
867
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
|
|
868
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
|
|
869
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
|
|
870
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
|
|
871
|
+
] : [];
|
|
872
|
+
return [
|
|
873
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
|
|
874
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
|
|
875
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
|
|
876
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
|
|
877
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
|
|
878
|
+
...exclusivePoolAttributes
|
|
879
|
+
].filter((attribute) => attribute !== void 0);
|
|
880
|
+
}
|
|
881
|
+
var STRING_ALIASES = {
|
|
882
|
+
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
883
|
+
};
|
|
884
|
+
var NUMBER_ALIASES = {
|
|
885
|
+
[MODEL_USAGE_ATTRIBUTES.inputTokens]: [
|
|
886
|
+
"gen_ai.usage.prompt_tokens",
|
|
887
|
+
"ai.usage.prompt_tokens",
|
|
888
|
+
"ai.usage.promptTokens",
|
|
889
|
+
"ai.usage.input_tokens",
|
|
890
|
+
"ai.usage.inputTokens"
|
|
891
|
+
],
|
|
892
|
+
[MODEL_USAGE_ATTRIBUTES.outputTokens]: [
|
|
893
|
+
"gen_ai.usage.completion_tokens",
|
|
894
|
+
"ai.usage.completion_tokens",
|
|
895
|
+
"ai.usage.completionTokens",
|
|
896
|
+
"ai.usage.output_tokens",
|
|
897
|
+
"ai.usage.outputTokens"
|
|
898
|
+
],
|
|
899
|
+
[MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
|
|
900
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
901
|
+
"ai.usage.reasoningTokens",
|
|
902
|
+
"ai.usage.thoughts_tokens"
|
|
903
|
+
],
|
|
904
|
+
[MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
|
|
905
|
+
"gen_ai.usage.cache_read_tokens",
|
|
906
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
907
|
+
"ai.usage.cachedInputTokens",
|
|
908
|
+
"ai.usage.cached_tokens",
|
|
909
|
+
"ai.usage.cache_read_tokens",
|
|
910
|
+
"ai.usage.cache_read_input_tokens",
|
|
911
|
+
"ai.usage.cacheReadInputTokens"
|
|
912
|
+
],
|
|
913
|
+
[MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
|
|
914
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
915
|
+
"gen_ai.usage.cache_creation.input_tokens",
|
|
916
|
+
"ai.usage.cacheWriteInputTokens",
|
|
917
|
+
"ai.usage.cache_creation_input_tokens",
|
|
918
|
+
"ai.usage.cacheCreationInputTokens"
|
|
919
|
+
]
|
|
920
|
+
};
|
|
921
|
+
function hasAttribute(attributes, key) {
|
|
922
|
+
return attributes.some((attribute) => attribute.key === key);
|
|
923
|
+
}
|
|
924
|
+
function findStringAttribute(attributes, keys) {
|
|
925
|
+
return attributes.find(
|
|
926
|
+
(attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
|
|
927
|
+
);
|
|
928
|
+
}
|
|
929
|
+
function findNumberAttribute(attributes, keys) {
|
|
930
|
+
return attributes.find((attribute) => {
|
|
931
|
+
if (!keys.includes(attribute.key)) return false;
|
|
932
|
+
if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
|
|
933
|
+
return true;
|
|
934
|
+
}
|
|
935
|
+
const intValue = attribute.value.intValue;
|
|
936
|
+
return integerValue(intValue) !== void 0;
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
function integerValue(value) {
|
|
940
|
+
if (typeof value === "number") {
|
|
941
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
942
|
+
}
|
|
943
|
+
if (typeof value !== "string") return void 0;
|
|
944
|
+
const parsed = Number(value);
|
|
945
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
946
|
+
}
|
|
947
|
+
function appendAlias(attributes, target, source) {
|
|
948
|
+
if (!source || hasAttribute(attributes, target)) return attributes;
|
|
949
|
+
return [...attributes, { key: target, value: { ...source.value } }];
|
|
950
|
+
}
|
|
951
|
+
function appendProviderAlias(attributes) {
|
|
952
|
+
if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
|
|
953
|
+
const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
|
|
954
|
+
if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
|
|
955
|
+
const attribute = attrString(
|
|
956
|
+
MODEL_USAGE_ATTRIBUTES.providerName,
|
|
957
|
+
canonicalModelProvider(source.value.stringValue)
|
|
958
|
+
);
|
|
959
|
+
return attribute ? [...attributes, attribute] : attributes;
|
|
960
|
+
}
|
|
961
|
+
function normalizeModelUsageSpan(span) {
|
|
962
|
+
const original = span.attributes;
|
|
963
|
+
if (!original || original.length === 0) return span;
|
|
964
|
+
const responseModel = findStringAttribute(original, [
|
|
965
|
+
MODEL_USAGE_ATTRIBUTES.responseModel,
|
|
966
|
+
"ai.response.model"
|
|
967
|
+
]);
|
|
968
|
+
if (!responseModel) return span;
|
|
969
|
+
let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
|
|
970
|
+
attributes = appendProviderAlias(attributes);
|
|
971
|
+
for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
|
|
972
|
+
attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
|
|
973
|
+
}
|
|
974
|
+
for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
|
|
975
|
+
attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
|
|
976
|
+
}
|
|
977
|
+
return attributes === original ? span : { ...span, attributes };
|
|
978
|
+
}
|
|
777
979
|
var DEFAULT_SECRET_KEY_NAMES = [
|
|
778
980
|
"apikey",
|
|
779
981
|
"apisecret",
|
|
@@ -974,6 +1176,10 @@ var TraceShipper = class {
|
|
|
974
1176
|
return null;
|
|
975
1177
|
}
|
|
976
1178
|
}
|
|
1179
|
+
try {
|
|
1180
|
+
current = normalizeModelUsageSpan(current);
|
|
1181
|
+
} catch (e) {
|
|
1182
|
+
}
|
|
977
1183
|
if (!this.disableDefaultRedaction) {
|
|
978
1184
|
current = defaultTransformSpan(current);
|
|
979
1185
|
}
|
|
@@ -1219,7 +1425,7 @@ installTracingSuppressionHook();
|
|
|
1219
1425
|
// package.json
|
|
1220
1426
|
var package_default = {
|
|
1221
1427
|
name: "@raindrop-ai/pi-agent",
|
|
1222
|
-
version: "0.1.
|
|
1428
|
+
version: "0.1.1",
|
|
1223
1429
|
description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
|
|
1224
1430
|
type: "module",
|
|
1225
1431
|
license: "MIT",
|
|
@@ -1374,9 +1580,22 @@ function extractTokenUsage(message) {
|
|
|
1374
1580
|
return {
|
|
1375
1581
|
input: usage.input,
|
|
1376
1582
|
output: usage.output,
|
|
1377
|
-
|
|
1583
|
+
cacheRead: typeof usage.cacheRead === "number" ? usage.cacheRead : 0,
|
|
1584
|
+
cacheWrite: typeof usage.cacheWrite === "number" ? usage.cacheWrite : 0
|
|
1378
1585
|
};
|
|
1379
1586
|
}
|
|
1587
|
+
function modelSpendSpanAttributes(input) {
|
|
1588
|
+
const providerAttr = input.provider ? attrString("gen_ai.provider.name", canonicalModelProvider(input.provider)) : void 0;
|
|
1589
|
+
const usageAttrs = input.usage ? buildModelUsageAttributes({
|
|
1590
|
+
inputTokens: input.usage.input,
|
|
1591
|
+
outputTokens: input.usage.output,
|
|
1592
|
+
cacheReadInputTokens: input.usage.cacheRead,
|
|
1593
|
+
cacheWriteInputTokens: input.usage.cacheWrite,
|
|
1594
|
+
reasoningTokens: 0,
|
|
1595
|
+
inputTokenSemantics: "exclusive"
|
|
1596
|
+
}) : [];
|
|
1597
|
+
return providerAttr ? [providerAttr, ...usageAttrs] : usageAttrs;
|
|
1598
|
+
}
|
|
1380
1599
|
function extractAssistantText(message) {
|
|
1381
1600
|
if (!("role" in message) || message.role !== "assistant") return void 0;
|
|
1382
1601
|
if (!Array.isArray(message.content)) return void 0;
|
|
@@ -1530,6 +1749,7 @@ export {
|
|
|
1530
1749
|
extractUserText,
|
|
1531
1750
|
extractModelName,
|
|
1532
1751
|
extractTokenUsage,
|
|
1752
|
+
modelSpendSpanAttributes,
|
|
1533
1753
|
extractAssistantText,
|
|
1534
1754
|
extractToolCallIds,
|
|
1535
1755
|
formatToolSpanName,
|
package/dist/extension.cjs
CHANGED
|
@@ -25,7 +25,7 @@ __export(extension_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(extension_exports);
|
|
27
27
|
|
|
28
|
-
// ../core/dist/chunk-
|
|
28
|
+
// ../core/dist/chunk-YUIXRQWN.js
|
|
29
29
|
function getCrypto() {
|
|
30
30
|
const c = globalThis.crypto;
|
|
31
31
|
return c;
|
|
@@ -83,6 +83,20 @@ function base64Encode(bytes) {
|
|
|
83
83
|
function generateId() {
|
|
84
84
|
return randomUUID();
|
|
85
85
|
}
|
|
86
|
+
var HANDOFF_ATTRIBUTE_SUFFIXES = {
|
|
87
|
+
mode: "raindrop.handoff.mode",
|
|
88
|
+
childEventId: "raindrop.handoff.childEventId",
|
|
89
|
+
parentEventId: "raindrop.handoff.parentEventId",
|
|
90
|
+
parentSpanId: "raindrop.handoff.parentSpanId",
|
|
91
|
+
name: "raindrop.handoff.name",
|
|
92
|
+
terminal: "raindrop.handoff.terminal",
|
|
93
|
+
agentRole: "raindrop.agent.role"
|
|
94
|
+
};
|
|
95
|
+
var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
|
|
96
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
97
|
+
var BAGGAGE_HEADER = "baggage";
|
|
98
|
+
var HANDOFF_HEADER = "x-raindrop-handoff";
|
|
99
|
+
var UNRESOLVED_CARRIER_WARNING = `[raindrop] resume: headers were supplied but no hand-off carrier was found on them (searched ${HANDOFF_HEADER}, ${TRACEPARENT_HEADER}, ${BAGGAGE_HEADER}). This run reports as an UNLINKED event, and the launcher that dispatched it will stay on "queued" forever because nothing ever references its child. Passing headers means a parent handed off, so no carrier on them is almost certainly a defect: a gateway or proxy stripping ${HANDOFF_HEADER}, a middleware overwriting ${BAGGAGE_HEADER}, a request forwarded without its headers, or a hand-built carrier whose field names do not match. Send every header the launcher's dispatch returned. Logged once per process; pass no headers for a directly-invoked sub-agent to silence it.`;
|
|
86
100
|
function runWithTracingSuppressed(fn) {
|
|
87
101
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
88
102
|
if (typeof hook !== "function") return fn();
|
|
@@ -801,6 +815,194 @@ var EventShipper = class {
|
|
|
801
815
|
}
|
|
802
816
|
}
|
|
803
817
|
};
|
|
818
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
819
|
+
providerName: "gen_ai.provider.name",
|
|
820
|
+
requestModel: "gen_ai.request.model",
|
|
821
|
+
responseModel: "gen_ai.response.model",
|
|
822
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
823
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
824
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
825
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
826
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
827
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
828
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
829
|
+
totalOutputTokens: "raindrop.usage.output_tokens.total",
|
|
830
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
831
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
832
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
833
|
+
};
|
|
834
|
+
var MODEL_PROVIDER_NAMES = [
|
|
835
|
+
["google.vertex", "google-vertex"],
|
|
836
|
+
["vertex.anthropic", "google-vertex"],
|
|
837
|
+
["amazon-bedrock", "amazon-bedrock"],
|
|
838
|
+
["bedrock", "amazon-bedrock"],
|
|
839
|
+
["anthropic", "anthropic"],
|
|
840
|
+
["openai", "openai"],
|
|
841
|
+
["google", "google"],
|
|
842
|
+
["azure", "azure"],
|
|
843
|
+
["openrouter", "openrouter"]
|
|
844
|
+
];
|
|
845
|
+
function canonicalModelProvider(provider) {
|
|
846
|
+
var _a;
|
|
847
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
848
|
+
if (normalizedProvider === "gateway") return "vercel";
|
|
849
|
+
const match = MODEL_PROVIDER_NAMES.find(
|
|
850
|
+
([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
|
|
851
|
+
);
|
|
852
|
+
return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
|
|
853
|
+
}
|
|
854
|
+
function tokenCount(value) {
|
|
855
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
856
|
+
}
|
|
857
|
+
function exclusiveTokens({
|
|
858
|
+
explicit,
|
|
859
|
+
total,
|
|
860
|
+
parts,
|
|
861
|
+
semantics
|
|
862
|
+
}) {
|
|
863
|
+
if (explicit !== void 0) return explicit;
|
|
864
|
+
if (total === void 0) return void 0;
|
|
865
|
+
if (semantics === "exclusive") return total;
|
|
866
|
+
const observedParts = parts.filter((part) => part !== void 0 && part > 0);
|
|
867
|
+
if (semantics === void 0 && observedParts.length > 0) return void 0;
|
|
868
|
+
const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
|
|
869
|
+
return exclusive >= 0 ? exclusive : void 0;
|
|
870
|
+
}
|
|
871
|
+
function buildModelUsageAttributes(usage) {
|
|
872
|
+
const inputTokens = tokenCount(usage.inputTokens);
|
|
873
|
+
const outputTokens = tokenCount(usage.outputTokens);
|
|
874
|
+
const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
|
|
875
|
+
const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
|
|
876
|
+
const reasoningTokens = tokenCount(usage.reasoningTokens);
|
|
877
|
+
const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
|
|
878
|
+
const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
|
|
879
|
+
const nonCachedInputTokens = exclusiveTokens({
|
|
880
|
+
explicit: explicitNonCachedInputTokens,
|
|
881
|
+
total: inputTokens,
|
|
882
|
+
parts: [cacheReadInputTokens, cacheWriteInputTokens],
|
|
883
|
+
semantics: usage.inputTokenSemantics
|
|
884
|
+
});
|
|
885
|
+
const nonReasoningOutputTokens = exclusiveTokens({
|
|
886
|
+
explicit: explicitNonReasoningOutputTokens,
|
|
887
|
+
total: outputTokens,
|
|
888
|
+
parts: [reasoningTokens],
|
|
889
|
+
semantics: usage.outputTokenSemantics
|
|
890
|
+
});
|
|
891
|
+
const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
|
|
892
|
+
// backend consumes this complete raindrop.* set as one atomic billing-pool contract.
|
|
893
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
|
|
894
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
|
|
895
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
|
|
896
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
|
|
897
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
|
|
898
|
+
] : [];
|
|
899
|
+
return [
|
|
900
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
|
|
901
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
|
|
902
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
|
|
903
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
|
|
904
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
|
|
905
|
+
...exclusivePoolAttributes
|
|
906
|
+
].filter((attribute) => attribute !== void 0);
|
|
907
|
+
}
|
|
908
|
+
var STRING_ALIASES = {
|
|
909
|
+
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
910
|
+
};
|
|
911
|
+
var NUMBER_ALIASES = {
|
|
912
|
+
[MODEL_USAGE_ATTRIBUTES.inputTokens]: [
|
|
913
|
+
"gen_ai.usage.prompt_tokens",
|
|
914
|
+
"ai.usage.prompt_tokens",
|
|
915
|
+
"ai.usage.promptTokens",
|
|
916
|
+
"ai.usage.input_tokens",
|
|
917
|
+
"ai.usage.inputTokens"
|
|
918
|
+
],
|
|
919
|
+
[MODEL_USAGE_ATTRIBUTES.outputTokens]: [
|
|
920
|
+
"gen_ai.usage.completion_tokens",
|
|
921
|
+
"ai.usage.completion_tokens",
|
|
922
|
+
"ai.usage.completionTokens",
|
|
923
|
+
"ai.usage.output_tokens",
|
|
924
|
+
"ai.usage.outputTokens"
|
|
925
|
+
],
|
|
926
|
+
[MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
|
|
927
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
928
|
+
"ai.usage.reasoningTokens",
|
|
929
|
+
"ai.usage.thoughts_tokens"
|
|
930
|
+
],
|
|
931
|
+
[MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
|
|
932
|
+
"gen_ai.usage.cache_read_tokens",
|
|
933
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
934
|
+
"ai.usage.cachedInputTokens",
|
|
935
|
+
"ai.usage.cached_tokens",
|
|
936
|
+
"ai.usage.cache_read_tokens",
|
|
937
|
+
"ai.usage.cache_read_input_tokens",
|
|
938
|
+
"ai.usage.cacheReadInputTokens"
|
|
939
|
+
],
|
|
940
|
+
[MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
|
|
941
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
942
|
+
"gen_ai.usage.cache_creation.input_tokens",
|
|
943
|
+
"ai.usage.cacheWriteInputTokens",
|
|
944
|
+
"ai.usage.cache_creation_input_tokens",
|
|
945
|
+
"ai.usage.cacheCreationInputTokens"
|
|
946
|
+
]
|
|
947
|
+
};
|
|
948
|
+
function hasAttribute(attributes, key) {
|
|
949
|
+
return attributes.some((attribute) => attribute.key === key);
|
|
950
|
+
}
|
|
951
|
+
function findStringAttribute(attributes, keys) {
|
|
952
|
+
return attributes.find(
|
|
953
|
+
(attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
|
|
954
|
+
);
|
|
955
|
+
}
|
|
956
|
+
function findNumberAttribute(attributes, keys) {
|
|
957
|
+
return attributes.find((attribute) => {
|
|
958
|
+
if (!keys.includes(attribute.key)) return false;
|
|
959
|
+
if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
|
|
960
|
+
return true;
|
|
961
|
+
}
|
|
962
|
+
const intValue = attribute.value.intValue;
|
|
963
|
+
return integerValue(intValue) !== void 0;
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
function integerValue(value) {
|
|
967
|
+
if (typeof value === "number") {
|
|
968
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
969
|
+
}
|
|
970
|
+
if (typeof value !== "string") return void 0;
|
|
971
|
+
const parsed = Number(value);
|
|
972
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
973
|
+
}
|
|
974
|
+
function appendAlias(attributes, target, source) {
|
|
975
|
+
if (!source || hasAttribute(attributes, target)) return attributes;
|
|
976
|
+
return [...attributes, { key: target, value: { ...source.value } }];
|
|
977
|
+
}
|
|
978
|
+
function appendProviderAlias(attributes) {
|
|
979
|
+
if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
|
|
980
|
+
const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
|
|
981
|
+
if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
|
|
982
|
+
const attribute = attrString(
|
|
983
|
+
MODEL_USAGE_ATTRIBUTES.providerName,
|
|
984
|
+
canonicalModelProvider(source.value.stringValue)
|
|
985
|
+
);
|
|
986
|
+
return attribute ? [...attributes, attribute] : attributes;
|
|
987
|
+
}
|
|
988
|
+
function normalizeModelUsageSpan(span) {
|
|
989
|
+
const original = span.attributes;
|
|
990
|
+
if (!original || original.length === 0) return span;
|
|
991
|
+
const responseModel = findStringAttribute(original, [
|
|
992
|
+
MODEL_USAGE_ATTRIBUTES.responseModel,
|
|
993
|
+
"ai.response.model"
|
|
994
|
+
]);
|
|
995
|
+
if (!responseModel) return span;
|
|
996
|
+
let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
|
|
997
|
+
attributes = appendProviderAlias(attributes);
|
|
998
|
+
for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
|
|
999
|
+
attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
|
|
1000
|
+
}
|
|
1001
|
+
for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
|
|
1002
|
+
attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
|
|
1003
|
+
}
|
|
1004
|
+
return attributes === original ? span : { ...span, attributes };
|
|
1005
|
+
}
|
|
804
1006
|
var DEFAULT_SECRET_KEY_NAMES = [
|
|
805
1007
|
"apikey",
|
|
806
1008
|
"apisecret",
|
|
@@ -1001,6 +1203,10 @@ var TraceShipper = class {
|
|
|
1001
1203
|
return null;
|
|
1002
1204
|
}
|
|
1003
1205
|
}
|
|
1206
|
+
try {
|
|
1207
|
+
current = normalizeModelUsageSpan(current);
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
}
|
|
1004
1210
|
if (!this.disableDefaultRedaction) {
|
|
1005
1211
|
current = defaultTransformSpan(current);
|
|
1006
1212
|
}
|
|
@@ -1301,7 +1507,7 @@ function resolveLocalWorkshopUrl(fileValue) {
|
|
|
1301
1507
|
// package.json
|
|
1302
1508
|
var package_default = {
|
|
1303
1509
|
name: "@raindrop-ai/pi-agent",
|
|
1304
|
-
version: "0.1.
|
|
1510
|
+
version: "0.1.1",
|
|
1305
1511
|
description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
|
|
1306
1512
|
type: "module",
|
|
1307
1513
|
license: "MIT",
|
|
@@ -1427,6 +1633,18 @@ var TraceShipper2 = class extends TraceShipper {
|
|
|
1427
1633
|
|
|
1428
1634
|
// src/internal/helpers.ts
|
|
1429
1635
|
var import_node_os2 = require("os");
|
|
1636
|
+
function modelSpendSpanAttributes(input) {
|
|
1637
|
+
const providerAttr = input.provider ? attrString("gen_ai.provider.name", canonicalModelProvider(input.provider)) : void 0;
|
|
1638
|
+
const usageAttrs = input.usage ? buildModelUsageAttributes({
|
|
1639
|
+
inputTokens: input.usage.input,
|
|
1640
|
+
outputTokens: input.usage.output,
|
|
1641
|
+
cacheReadInputTokens: input.usage.cacheRead,
|
|
1642
|
+
cacheWriteInputTokens: input.usage.cacheWrite,
|
|
1643
|
+
reasoningTokens: 0,
|
|
1644
|
+
inputTokenSemantics: "exclusive"
|
|
1645
|
+
}) : [];
|
|
1646
|
+
return providerAttr ? [providerAttr, ...usageAttrs] : usageAttrs;
|
|
1647
|
+
}
|
|
1430
1648
|
function extractAssistantText(message) {
|
|
1431
1649
|
if (!("role" in message) || message.role !== "assistant") return void 0;
|
|
1432
1650
|
if (!Array.isArray(message.content)) return void 0;
|
|
@@ -1755,7 +1973,7 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
1755
1973
|
}
|
|
1756
1974
|
});
|
|
1757
1975
|
pi.on("message_end", async (event, ctx) => {
|
|
1758
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
1976
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
1759
1977
|
try {
|
|
1760
1978
|
if (((_a = event.message) == null ? void 0 : _a.role) !== "assistant") return;
|
|
1761
1979
|
const state = getState(stateRef, ctx);
|
|
@@ -1769,19 +1987,26 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
1769
1987
|
const outputText = capText2(getAssistantText(message));
|
|
1770
1988
|
const inputTokens = (_d = message.usage) == null ? void 0 : _d.input;
|
|
1771
1989
|
const outputTokens = (_e = message.usage) == null ? void 0 : _e.output;
|
|
1772
|
-
const cacheReadTokens = (_f = message.usage) == null ? void 0 : _f.cacheRead;
|
|
1990
|
+
const cacheReadTokens = typeof ((_f = message.usage) == null ? void 0 : _f.cacheRead) === "number" ? message.usage.cacheRead : 0;
|
|
1991
|
+
const cacheWriteTokens = typeof ((_g = message.usage) == null ? void 0 : _g.cacheWrite) === "number" ? message.usage.cacheWrite : 0;
|
|
1773
1992
|
if (typeof inputTokens === "number") state.totalInputTokens += inputTokens;
|
|
1774
1993
|
if (typeof outputTokens === "number") state.totalOutputTokens += outputTokens;
|
|
1775
|
-
if (
|
|
1776
|
-
const turnParent = (
|
|
1994
|
+
if (cacheReadTokens > 0) state.totalCacheReadTokens += cacheReadTokens;
|
|
1995
|
+
const turnParent = (_h = state.currentTurnSpan) != null ? _h : state.currentRootSpan;
|
|
1777
1996
|
const llmAttrs = [
|
|
1778
1997
|
attrString("ai.operationId", "generateText"),
|
|
1779
1998
|
provider ? attrString("gen_ai.system", provider) : void 0,
|
|
1780
1999
|
modelId ? attrString("gen_ai.request.model", modelId) : void 0,
|
|
1781
2000
|
modelId ? attrString("gen_ai.response.model", modelId) : void 0,
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
2001
|
+
...modelSpendSpanAttributes({
|
|
2002
|
+
provider: provider || void 0,
|
|
2003
|
+
usage: typeof inputTokens === "number" && typeof outputTokens === "number" ? {
|
|
2004
|
+
input: inputTokens,
|
|
2005
|
+
output: outputTokens,
|
|
2006
|
+
cacheRead: cacheReadTokens,
|
|
2007
|
+
cacheWrite: cacheWriteTokens
|
|
2008
|
+
} : void 0
|
|
2009
|
+
}),
|
|
1785
2010
|
outputText ? attrString("ai.response.text", truncate(outputText)) : void 0,
|
|
1786
2011
|
state.currentInput ? attrString("ai.prompt", truncate(state.currentInput)) : void 0,
|
|
1787
2012
|
message.stopReason ? attrString("ai.stop_reason", message.stopReason) : void 0,
|
|
@@ -1819,7 +2044,7 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
1819
2044
|
...errorForSpan ? { error: errorForSpan } : {}
|
|
1820
2045
|
});
|
|
1821
2046
|
state.currentRootSpan = void 0;
|
|
1822
|
-
await eventShipper.finish((
|
|
2047
|
+
await eventShipper.finish((_i = state.currentEventRequestId) != null ? _i : state.currentEventId, {
|
|
1823
2048
|
userId: getUserId(state, config.eventMetadata),
|
|
1824
2049
|
...modelId ? { model: modelId } : {},
|
|
1825
2050
|
...!errorForSpan && outputText.trim() ? { output: outputText } : {},
|
package/dist/extension.js
CHANGED
|
@@ -10,11 +10,12 @@ import {
|
|
|
10
10
|
getHostname,
|
|
11
11
|
getUsername,
|
|
12
12
|
libraryVersion,
|
|
13
|
+
modelSpendSpanAttributes,
|
|
13
14
|
nowUnixNanoString,
|
|
14
15
|
resolveLocalDebuggerBaseUrl,
|
|
15
16
|
safeStringify,
|
|
16
17
|
truncate
|
|
17
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-GTKXT2J5.js";
|
|
18
19
|
|
|
19
20
|
// src/internal/config.ts
|
|
20
21
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -270,7 +271,7 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
270
271
|
}
|
|
271
272
|
});
|
|
272
273
|
pi.on("message_end", async (event, ctx) => {
|
|
273
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
274
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
274
275
|
try {
|
|
275
276
|
if (((_a = event.message) == null ? void 0 : _a.role) !== "assistant") return;
|
|
276
277
|
const state = getState(stateRef, ctx);
|
|
@@ -284,19 +285,26 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
284
285
|
const outputText = capText(getAssistantText(message));
|
|
285
286
|
const inputTokens = (_d = message.usage) == null ? void 0 : _d.input;
|
|
286
287
|
const outputTokens = (_e = message.usage) == null ? void 0 : _e.output;
|
|
287
|
-
const cacheReadTokens = (_f = message.usage) == null ? void 0 : _f.cacheRead;
|
|
288
|
+
const cacheReadTokens = typeof ((_f = message.usage) == null ? void 0 : _f.cacheRead) === "number" ? message.usage.cacheRead : 0;
|
|
289
|
+
const cacheWriteTokens = typeof ((_g = message.usage) == null ? void 0 : _g.cacheWrite) === "number" ? message.usage.cacheWrite : 0;
|
|
288
290
|
if (typeof inputTokens === "number") state.totalInputTokens += inputTokens;
|
|
289
291
|
if (typeof outputTokens === "number") state.totalOutputTokens += outputTokens;
|
|
290
|
-
if (
|
|
291
|
-
const turnParent = (
|
|
292
|
+
if (cacheReadTokens > 0) state.totalCacheReadTokens += cacheReadTokens;
|
|
293
|
+
const turnParent = (_h = state.currentTurnSpan) != null ? _h : state.currentRootSpan;
|
|
292
294
|
const llmAttrs = [
|
|
293
295
|
attrString("ai.operationId", "generateText"),
|
|
294
296
|
provider ? attrString("gen_ai.system", provider) : void 0,
|
|
295
297
|
modelId ? attrString("gen_ai.request.model", modelId) : void 0,
|
|
296
298
|
modelId ? attrString("gen_ai.response.model", modelId) : void 0,
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
299
|
+
...modelSpendSpanAttributes({
|
|
300
|
+
provider: provider || void 0,
|
|
301
|
+
usage: typeof inputTokens === "number" && typeof outputTokens === "number" ? {
|
|
302
|
+
input: inputTokens,
|
|
303
|
+
output: outputTokens,
|
|
304
|
+
cacheRead: cacheReadTokens,
|
|
305
|
+
cacheWrite: cacheWriteTokens
|
|
306
|
+
} : void 0
|
|
307
|
+
}),
|
|
300
308
|
outputText ? attrString("ai.response.text", truncate(outputText)) : void 0,
|
|
301
309
|
state.currentInput ? attrString("ai.prompt", truncate(state.currentInput)) : void 0,
|
|
302
310
|
message.stopReason ? attrString("ai.stop_reason", message.stopReason) : void 0,
|
|
@@ -334,7 +342,7 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
334
342
|
...errorForSpan ? { error: errorForSpan } : {}
|
|
335
343
|
});
|
|
336
344
|
state.currentRootSpan = void 0;
|
|
337
|
-
await eventShipper.finish((
|
|
345
|
+
await eventShipper.finish((_i = state.currentEventRequestId) != null ? _i : state.currentEventId, {
|
|
338
346
|
userId: getUserId(state, config.eventMetadata),
|
|
339
347
|
...modelId ? { model: modelId } : {},
|
|
340
348
|
...!errorForSpan && outputText.trim() ? { output: outputText } : {},
|
package/dist/index.cjs
CHANGED
|
@@ -24,7 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
|
|
27
|
-
// ../core/dist/chunk-
|
|
27
|
+
// ../core/dist/chunk-YUIXRQWN.js
|
|
28
28
|
function getCrypto() {
|
|
29
29
|
const c = globalThis.crypto;
|
|
30
30
|
return c;
|
|
@@ -79,6 +79,20 @@ function base64Encode(bytes) {
|
|
|
79
79
|
}
|
|
80
80
|
return out;
|
|
81
81
|
}
|
|
82
|
+
var HANDOFF_ATTRIBUTE_SUFFIXES = {
|
|
83
|
+
mode: "raindrop.handoff.mode",
|
|
84
|
+
childEventId: "raindrop.handoff.childEventId",
|
|
85
|
+
parentEventId: "raindrop.handoff.parentEventId",
|
|
86
|
+
parentSpanId: "raindrop.handoff.parentSpanId",
|
|
87
|
+
name: "raindrop.handoff.name",
|
|
88
|
+
terminal: "raindrop.handoff.terminal",
|
|
89
|
+
agentRole: "raindrop.agent.role"
|
|
90
|
+
};
|
|
91
|
+
var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
|
|
92
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
93
|
+
var BAGGAGE_HEADER = "baggage";
|
|
94
|
+
var HANDOFF_HEADER = "x-raindrop-handoff";
|
|
95
|
+
var UNRESOLVED_CARRIER_WARNING = `[raindrop] resume: headers were supplied but no hand-off carrier was found on them (searched ${HANDOFF_HEADER}, ${TRACEPARENT_HEADER}, ${BAGGAGE_HEADER}). This run reports as an UNLINKED event, and the launcher that dispatched it will stay on "queued" forever because nothing ever references its child. Passing headers means a parent handed off, so no carrier on them is almost certainly a defect: a gateway or proxy stripping ${HANDOFF_HEADER}, a middleware overwriting ${BAGGAGE_HEADER}, a request forwarded without its headers, or a hand-built carrier whose field names do not match. Send every header the launcher's dispatch returned. Logged once per process; pass no headers for a directly-invoked sub-agent to silence it.`;
|
|
82
96
|
function runWithTracingSuppressed(fn) {
|
|
83
97
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
84
98
|
if (typeof hook !== "function") return fn();
|
|
@@ -797,6 +811,194 @@ var EventShipper = class {
|
|
|
797
811
|
}
|
|
798
812
|
}
|
|
799
813
|
};
|
|
814
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
815
|
+
providerName: "gen_ai.provider.name",
|
|
816
|
+
requestModel: "gen_ai.request.model",
|
|
817
|
+
responseModel: "gen_ai.response.model",
|
|
818
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
819
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
820
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
821
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
822
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
823
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
824
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
825
|
+
totalOutputTokens: "raindrop.usage.output_tokens.total",
|
|
826
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
827
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
828
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
829
|
+
};
|
|
830
|
+
var MODEL_PROVIDER_NAMES = [
|
|
831
|
+
["google.vertex", "google-vertex"],
|
|
832
|
+
["vertex.anthropic", "google-vertex"],
|
|
833
|
+
["amazon-bedrock", "amazon-bedrock"],
|
|
834
|
+
["bedrock", "amazon-bedrock"],
|
|
835
|
+
["anthropic", "anthropic"],
|
|
836
|
+
["openai", "openai"],
|
|
837
|
+
["google", "google"],
|
|
838
|
+
["azure", "azure"],
|
|
839
|
+
["openrouter", "openrouter"]
|
|
840
|
+
];
|
|
841
|
+
function canonicalModelProvider(provider) {
|
|
842
|
+
var _a;
|
|
843
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
844
|
+
if (normalizedProvider === "gateway") return "vercel";
|
|
845
|
+
const match = MODEL_PROVIDER_NAMES.find(
|
|
846
|
+
([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
|
|
847
|
+
);
|
|
848
|
+
return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
|
|
849
|
+
}
|
|
850
|
+
function tokenCount(value) {
|
|
851
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
852
|
+
}
|
|
853
|
+
function exclusiveTokens({
|
|
854
|
+
explicit,
|
|
855
|
+
total,
|
|
856
|
+
parts,
|
|
857
|
+
semantics
|
|
858
|
+
}) {
|
|
859
|
+
if (explicit !== void 0) return explicit;
|
|
860
|
+
if (total === void 0) return void 0;
|
|
861
|
+
if (semantics === "exclusive") return total;
|
|
862
|
+
const observedParts = parts.filter((part) => part !== void 0 && part > 0);
|
|
863
|
+
if (semantics === void 0 && observedParts.length > 0) return void 0;
|
|
864
|
+
const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
|
|
865
|
+
return exclusive >= 0 ? exclusive : void 0;
|
|
866
|
+
}
|
|
867
|
+
function buildModelUsageAttributes(usage) {
|
|
868
|
+
const inputTokens = tokenCount(usage.inputTokens);
|
|
869
|
+
const outputTokens = tokenCount(usage.outputTokens);
|
|
870
|
+
const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
|
|
871
|
+
const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
|
|
872
|
+
const reasoningTokens = tokenCount(usage.reasoningTokens);
|
|
873
|
+
const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
|
|
874
|
+
const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
|
|
875
|
+
const nonCachedInputTokens = exclusiveTokens({
|
|
876
|
+
explicit: explicitNonCachedInputTokens,
|
|
877
|
+
total: inputTokens,
|
|
878
|
+
parts: [cacheReadInputTokens, cacheWriteInputTokens],
|
|
879
|
+
semantics: usage.inputTokenSemantics
|
|
880
|
+
});
|
|
881
|
+
const nonReasoningOutputTokens = exclusiveTokens({
|
|
882
|
+
explicit: explicitNonReasoningOutputTokens,
|
|
883
|
+
total: outputTokens,
|
|
884
|
+
parts: [reasoningTokens],
|
|
885
|
+
semantics: usage.outputTokenSemantics
|
|
886
|
+
});
|
|
887
|
+
const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
|
|
888
|
+
// backend consumes this complete raindrop.* set as one atomic billing-pool contract.
|
|
889
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
|
|
890
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
|
|
891
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
|
|
892
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
|
|
893
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
|
|
894
|
+
] : [];
|
|
895
|
+
return [
|
|
896
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
|
|
897
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
|
|
898
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
|
|
899
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
|
|
900
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
|
|
901
|
+
...exclusivePoolAttributes
|
|
902
|
+
].filter((attribute) => attribute !== void 0);
|
|
903
|
+
}
|
|
904
|
+
var STRING_ALIASES = {
|
|
905
|
+
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
906
|
+
};
|
|
907
|
+
var NUMBER_ALIASES = {
|
|
908
|
+
[MODEL_USAGE_ATTRIBUTES.inputTokens]: [
|
|
909
|
+
"gen_ai.usage.prompt_tokens",
|
|
910
|
+
"ai.usage.prompt_tokens",
|
|
911
|
+
"ai.usage.promptTokens",
|
|
912
|
+
"ai.usage.input_tokens",
|
|
913
|
+
"ai.usage.inputTokens"
|
|
914
|
+
],
|
|
915
|
+
[MODEL_USAGE_ATTRIBUTES.outputTokens]: [
|
|
916
|
+
"gen_ai.usage.completion_tokens",
|
|
917
|
+
"ai.usage.completion_tokens",
|
|
918
|
+
"ai.usage.completionTokens",
|
|
919
|
+
"ai.usage.output_tokens",
|
|
920
|
+
"ai.usage.outputTokens"
|
|
921
|
+
],
|
|
922
|
+
[MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
|
|
923
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
924
|
+
"ai.usage.reasoningTokens",
|
|
925
|
+
"ai.usage.thoughts_tokens"
|
|
926
|
+
],
|
|
927
|
+
[MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
|
|
928
|
+
"gen_ai.usage.cache_read_tokens",
|
|
929
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
930
|
+
"ai.usage.cachedInputTokens",
|
|
931
|
+
"ai.usage.cached_tokens",
|
|
932
|
+
"ai.usage.cache_read_tokens",
|
|
933
|
+
"ai.usage.cache_read_input_tokens",
|
|
934
|
+
"ai.usage.cacheReadInputTokens"
|
|
935
|
+
],
|
|
936
|
+
[MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
|
|
937
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
938
|
+
"gen_ai.usage.cache_creation.input_tokens",
|
|
939
|
+
"ai.usage.cacheWriteInputTokens",
|
|
940
|
+
"ai.usage.cache_creation_input_tokens",
|
|
941
|
+
"ai.usage.cacheCreationInputTokens"
|
|
942
|
+
]
|
|
943
|
+
};
|
|
944
|
+
function hasAttribute(attributes, key) {
|
|
945
|
+
return attributes.some((attribute) => attribute.key === key);
|
|
946
|
+
}
|
|
947
|
+
function findStringAttribute(attributes, keys) {
|
|
948
|
+
return attributes.find(
|
|
949
|
+
(attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
function findNumberAttribute(attributes, keys) {
|
|
953
|
+
return attributes.find((attribute) => {
|
|
954
|
+
if (!keys.includes(attribute.key)) return false;
|
|
955
|
+
if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
|
|
956
|
+
return true;
|
|
957
|
+
}
|
|
958
|
+
const intValue = attribute.value.intValue;
|
|
959
|
+
return integerValue(intValue) !== void 0;
|
|
960
|
+
});
|
|
961
|
+
}
|
|
962
|
+
function integerValue(value) {
|
|
963
|
+
if (typeof value === "number") {
|
|
964
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
965
|
+
}
|
|
966
|
+
if (typeof value !== "string") return void 0;
|
|
967
|
+
const parsed = Number(value);
|
|
968
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
969
|
+
}
|
|
970
|
+
function appendAlias(attributes, target, source) {
|
|
971
|
+
if (!source || hasAttribute(attributes, target)) return attributes;
|
|
972
|
+
return [...attributes, { key: target, value: { ...source.value } }];
|
|
973
|
+
}
|
|
974
|
+
function appendProviderAlias(attributes) {
|
|
975
|
+
if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
|
|
976
|
+
const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
|
|
977
|
+
if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
|
|
978
|
+
const attribute = attrString(
|
|
979
|
+
MODEL_USAGE_ATTRIBUTES.providerName,
|
|
980
|
+
canonicalModelProvider(source.value.stringValue)
|
|
981
|
+
);
|
|
982
|
+
return attribute ? [...attributes, attribute] : attributes;
|
|
983
|
+
}
|
|
984
|
+
function normalizeModelUsageSpan(span) {
|
|
985
|
+
const original = span.attributes;
|
|
986
|
+
if (!original || original.length === 0) return span;
|
|
987
|
+
const responseModel = findStringAttribute(original, [
|
|
988
|
+
MODEL_USAGE_ATTRIBUTES.responseModel,
|
|
989
|
+
"ai.response.model"
|
|
990
|
+
]);
|
|
991
|
+
if (!responseModel) return span;
|
|
992
|
+
let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
|
|
993
|
+
attributes = appendProviderAlias(attributes);
|
|
994
|
+
for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
|
|
995
|
+
attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
|
|
996
|
+
}
|
|
997
|
+
for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
|
|
998
|
+
attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
|
|
999
|
+
}
|
|
1000
|
+
return attributes === original ? span : { ...span, attributes };
|
|
1001
|
+
}
|
|
800
1002
|
var DEFAULT_SECRET_KEY_NAMES = [
|
|
801
1003
|
"apikey",
|
|
802
1004
|
"apisecret",
|
|
@@ -997,6 +1199,10 @@ var TraceShipper = class {
|
|
|
997
1199
|
return null;
|
|
998
1200
|
}
|
|
999
1201
|
}
|
|
1202
|
+
try {
|
|
1203
|
+
current = normalizeModelUsageSpan(current);
|
|
1204
|
+
} catch (e) {
|
|
1205
|
+
}
|
|
1000
1206
|
if (!this.disableDefaultRedaction) {
|
|
1001
1207
|
current = defaultTransformSpan(current);
|
|
1002
1208
|
}
|
|
@@ -1242,7 +1448,7 @@ installTracingSuppressionHook();
|
|
|
1242
1448
|
// package.json
|
|
1243
1449
|
var package_default = {
|
|
1244
1450
|
name: "@raindrop-ai/pi-agent",
|
|
1245
|
-
version: "0.1.
|
|
1451
|
+
version: "0.1.1",
|
|
1246
1452
|
description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
|
|
1247
1453
|
type: "module",
|
|
1248
1454
|
license: "MIT",
|
|
@@ -1397,9 +1603,22 @@ function extractTokenUsage(message) {
|
|
|
1397
1603
|
return {
|
|
1398
1604
|
input: usage.input,
|
|
1399
1605
|
output: usage.output,
|
|
1400
|
-
|
|
1606
|
+
cacheRead: typeof usage.cacheRead === "number" ? usage.cacheRead : 0,
|
|
1607
|
+
cacheWrite: typeof usage.cacheWrite === "number" ? usage.cacheWrite : 0
|
|
1401
1608
|
};
|
|
1402
1609
|
}
|
|
1610
|
+
function modelSpendSpanAttributes(input) {
|
|
1611
|
+
const providerAttr = input.provider ? attrString("gen_ai.provider.name", canonicalModelProvider(input.provider)) : void 0;
|
|
1612
|
+
const usageAttrs = input.usage ? buildModelUsageAttributes({
|
|
1613
|
+
inputTokens: input.usage.input,
|
|
1614
|
+
outputTokens: input.usage.output,
|
|
1615
|
+
cacheReadInputTokens: input.usage.cacheRead,
|
|
1616
|
+
cacheWriteInputTokens: input.usage.cacheWrite,
|
|
1617
|
+
reasoningTokens: 0,
|
|
1618
|
+
inputTokenSemantics: "exclusive"
|
|
1619
|
+
}) : [];
|
|
1620
|
+
return providerAttr ? [providerAttr, ...usageAttrs] : usageAttrs;
|
|
1621
|
+
}
|
|
1403
1622
|
function extractAssistantText(message) {
|
|
1404
1623
|
if (!("role" in message) || message.role !== "assistant") return void 0;
|
|
1405
1624
|
if (!Array.isArray(message.content)) return void 0;
|
|
@@ -1541,6 +1760,9 @@ function getUsername() {
|
|
|
1541
1760
|
}
|
|
1542
1761
|
|
|
1543
1762
|
// src/internal/subscriber.ts
|
|
1763
|
+
function pushAttr(attrs, attr) {
|
|
1764
|
+
if (attr) attrs.push(attr);
|
|
1765
|
+
}
|
|
1544
1766
|
function resolveEventId(source) {
|
|
1545
1767
|
if (typeof source !== "function") return randomUUID();
|
|
1546
1768
|
try {
|
|
@@ -1658,41 +1880,30 @@ function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, opt
|
|
|
1658
1880
|
if (usage) {
|
|
1659
1881
|
currentRun.totalInputTokens += usage.input;
|
|
1660
1882
|
currentRun.totalOutputTokens += usage.output;
|
|
1661
|
-
if (usage.cacheRead) currentRun.totalCacheReadTokens += usage.cacheRead;
|
|
1883
|
+
if (usage.cacheRead > 0) currentRun.totalCacheReadTokens += usage.cacheRead;
|
|
1662
1884
|
}
|
|
1663
1885
|
if (!traceShipper || !currentRun.currentTurnSpan) return;
|
|
1664
1886
|
const rawProvider = provider;
|
|
1665
1887
|
const rawModelId = bareModel;
|
|
1666
1888
|
const stopReason = "stopReason" in message && typeof message.stopReason === "string" ? message.stopReason : void 0;
|
|
1667
|
-
const llmAttrs = [
|
|
1668
|
-
|
|
1669
|
-
];
|
|
1889
|
+
const llmAttrs = [];
|
|
1890
|
+
pushAttr(llmAttrs, attrString("ai.operationId", "generateText"));
|
|
1670
1891
|
if (rawProvider) {
|
|
1671
|
-
llmAttrs
|
|
1892
|
+
pushAttr(llmAttrs, attrString("gen_ai.system", rawProvider));
|
|
1672
1893
|
}
|
|
1673
1894
|
if (rawModelId) {
|
|
1674
|
-
llmAttrs.
|
|
1675
|
-
|
|
1676
|
-
attrString("gen_ai.request.model", rawModelId)
|
|
1677
|
-
);
|
|
1678
|
-
}
|
|
1679
|
-
if (usage) {
|
|
1680
|
-
llmAttrs.push(
|
|
1681
|
-
attrInt("gen_ai.usage.input_tokens", usage.input),
|
|
1682
|
-
attrInt("gen_ai.usage.output_tokens", usage.output)
|
|
1683
|
-
);
|
|
1684
|
-
if (usage.cacheRead) {
|
|
1685
|
-
llmAttrs.push(attrInt("gen_ai.usage.cache_read_tokens", usage.cacheRead));
|
|
1686
|
-
}
|
|
1895
|
+
pushAttr(llmAttrs, attrString("gen_ai.response.model", rawModelId));
|
|
1896
|
+
pushAttr(llmAttrs, attrString("gen_ai.request.model", rawModelId));
|
|
1687
1897
|
}
|
|
1898
|
+
llmAttrs.push(...modelSpendSpanAttributes({ provider: rawProvider, usage }));
|
|
1688
1899
|
if (assistantText) {
|
|
1689
|
-
llmAttrs
|
|
1900
|
+
pushAttr(llmAttrs, attrString("ai.response.text", truncate(assistantText)));
|
|
1690
1901
|
}
|
|
1691
1902
|
if (currentRun.currentInput) {
|
|
1692
|
-
llmAttrs
|
|
1903
|
+
pushAttr(llmAttrs, attrString("ai.prompt", truncate(currentRun.currentInput)));
|
|
1693
1904
|
}
|
|
1694
1905
|
if (stopReason) {
|
|
1695
|
-
llmAttrs
|
|
1906
|
+
pushAttr(llmAttrs, attrString("ai.stop_reason", stopReason));
|
|
1696
1907
|
}
|
|
1697
1908
|
const llmSpan = traceShipper.startSpan({
|
|
1698
1909
|
name: model != null ? model : "llm",
|
|
@@ -1794,9 +2005,9 @@ function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, opt
|
|
|
1794
2005
|
if (!traceShipper || !toolSpan) return;
|
|
1795
2006
|
const endAttrs = [];
|
|
1796
2007
|
const argsStr = truncate(safeStringify(args));
|
|
1797
|
-
if (argsStr) endAttrs
|
|
2008
|
+
if (argsStr) pushAttr(endAttrs, attrString("ai.toolCall.args", argsStr));
|
|
1798
2009
|
const resultStr = truncate(safeStringify(result));
|
|
1799
|
-
if (resultStr) endAttrs
|
|
2010
|
+
if (resultStr) pushAttr(endAttrs, attrString("ai.toolCall.result", resultStr));
|
|
1800
2011
|
traceShipper.endSpan(toolSpan, {
|
|
1801
2012
|
attributes: endAttrs,
|
|
1802
2013
|
...isError ? { error: `Tool "${toolName}" failed` } : {}
|
|
@@ -1823,29 +2034,28 @@ function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, opt
|
|
|
1823
2034
|
}
|
|
1824
2035
|
const outputText = capText2(run.outputParts.join(""));
|
|
1825
2036
|
if (traceShipper && run.rootSpan) {
|
|
1826
|
-
const rootAttrs = [
|
|
1827
|
-
|
|
1828
|
-
];
|
|
2037
|
+
const rootAttrs = [];
|
|
2038
|
+
pushAttr(rootAttrs, attrString("ai.operationId", "generateText"));
|
|
1829
2039
|
if (run.lastModel) {
|
|
1830
2040
|
run.rootSpan.name = run.lastProvider ? `${run.lastProvider}/${run.lastModel}` : run.lastModel;
|
|
1831
|
-
rootAttrs
|
|
2041
|
+
pushAttr(rootAttrs, attrString("gen_ai.response.model", run.lastModel));
|
|
1832
2042
|
}
|
|
1833
2043
|
if (run.currentInput) {
|
|
1834
|
-
rootAttrs
|
|
2044
|
+
pushAttr(rootAttrs, attrString("ai.prompt", truncate(run.currentInput)));
|
|
1835
2045
|
}
|
|
1836
2046
|
if (outputText) {
|
|
1837
|
-
rootAttrs
|
|
2047
|
+
pushAttr(rootAttrs, attrString("ai.response.text", truncate(outputText)));
|
|
1838
2048
|
}
|
|
1839
2049
|
if (run.totalInputTokens > 0) {
|
|
1840
|
-
rootAttrs
|
|
2050
|
+
pushAttr(rootAttrs, attrInt("gen_ai.usage.input_tokens", run.totalInputTokens));
|
|
1841
2051
|
}
|
|
1842
2052
|
if (run.totalOutputTokens > 0) {
|
|
1843
|
-
rootAttrs
|
|
2053
|
+
pushAttr(rootAttrs, attrInt("gen_ai.usage.output_tokens", run.totalOutputTokens));
|
|
1844
2054
|
}
|
|
1845
2055
|
if (run.totalCacheReadTokens > 0) {
|
|
1846
|
-
rootAttrs
|
|
2056
|
+
pushAttr(rootAttrs, attrInt("gen_ai.usage.cache_read_tokens", run.totalCacheReadTokens));
|
|
1847
2057
|
}
|
|
1848
|
-
rootAttrs
|
|
2058
|
+
pushAttr(rootAttrs, attrInt("ai.total_turns", run.turnNumber));
|
|
1849
2059
|
traceShipper.endSpan(run.rootSpan, { attributes: rootAttrs });
|
|
1850
2060
|
}
|
|
1851
2061
|
if (eventShipper) {
|
package/dist/index.js
CHANGED
|
@@ -13,13 +13,17 @@ import {
|
|
|
13
13
|
getHostname,
|
|
14
14
|
getUsername,
|
|
15
15
|
libraryVersion,
|
|
16
|
+
modelSpendSpanAttributes,
|
|
16
17
|
randomUUID,
|
|
17
18
|
resolveLocalDebuggerBaseUrl,
|
|
18
19
|
safeStringify,
|
|
19
20
|
truncate
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-GTKXT2J5.js";
|
|
21
22
|
|
|
22
23
|
// src/internal/subscriber.ts
|
|
24
|
+
function pushAttr(attrs, attr) {
|
|
25
|
+
if (attr) attrs.push(attr);
|
|
26
|
+
}
|
|
23
27
|
function resolveEventId(source) {
|
|
24
28
|
if (typeof source !== "function") return randomUUID();
|
|
25
29
|
try {
|
|
@@ -137,41 +141,30 @@ function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, opt
|
|
|
137
141
|
if (usage) {
|
|
138
142
|
currentRun.totalInputTokens += usage.input;
|
|
139
143
|
currentRun.totalOutputTokens += usage.output;
|
|
140
|
-
if (usage.cacheRead) currentRun.totalCacheReadTokens += usage.cacheRead;
|
|
144
|
+
if (usage.cacheRead > 0) currentRun.totalCacheReadTokens += usage.cacheRead;
|
|
141
145
|
}
|
|
142
146
|
if (!traceShipper || !currentRun.currentTurnSpan) return;
|
|
143
147
|
const rawProvider = provider;
|
|
144
148
|
const rawModelId = bareModel;
|
|
145
149
|
const stopReason = "stopReason" in message && typeof message.stopReason === "string" ? message.stopReason : void 0;
|
|
146
|
-
const llmAttrs = [
|
|
147
|
-
|
|
148
|
-
];
|
|
150
|
+
const llmAttrs = [];
|
|
151
|
+
pushAttr(llmAttrs, attrString("ai.operationId", "generateText"));
|
|
149
152
|
if (rawProvider) {
|
|
150
|
-
llmAttrs
|
|
153
|
+
pushAttr(llmAttrs, attrString("gen_ai.system", rawProvider));
|
|
151
154
|
}
|
|
152
155
|
if (rawModelId) {
|
|
153
|
-
llmAttrs.
|
|
154
|
-
|
|
155
|
-
attrString("gen_ai.request.model", rawModelId)
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
if (usage) {
|
|
159
|
-
llmAttrs.push(
|
|
160
|
-
attrInt("gen_ai.usage.input_tokens", usage.input),
|
|
161
|
-
attrInt("gen_ai.usage.output_tokens", usage.output)
|
|
162
|
-
);
|
|
163
|
-
if (usage.cacheRead) {
|
|
164
|
-
llmAttrs.push(attrInt("gen_ai.usage.cache_read_tokens", usage.cacheRead));
|
|
165
|
-
}
|
|
156
|
+
pushAttr(llmAttrs, attrString("gen_ai.response.model", rawModelId));
|
|
157
|
+
pushAttr(llmAttrs, attrString("gen_ai.request.model", rawModelId));
|
|
166
158
|
}
|
|
159
|
+
llmAttrs.push(...modelSpendSpanAttributes({ provider: rawProvider, usage }));
|
|
167
160
|
if (assistantText) {
|
|
168
|
-
llmAttrs
|
|
161
|
+
pushAttr(llmAttrs, attrString("ai.response.text", truncate(assistantText)));
|
|
169
162
|
}
|
|
170
163
|
if (currentRun.currentInput) {
|
|
171
|
-
llmAttrs
|
|
164
|
+
pushAttr(llmAttrs, attrString("ai.prompt", truncate(currentRun.currentInput)));
|
|
172
165
|
}
|
|
173
166
|
if (stopReason) {
|
|
174
|
-
llmAttrs
|
|
167
|
+
pushAttr(llmAttrs, attrString("ai.stop_reason", stopReason));
|
|
175
168
|
}
|
|
176
169
|
const llmSpan = traceShipper.startSpan({
|
|
177
170
|
name: model != null ? model : "llm",
|
|
@@ -273,9 +266,9 @@ function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, opt
|
|
|
273
266
|
if (!traceShipper || !toolSpan) return;
|
|
274
267
|
const endAttrs = [];
|
|
275
268
|
const argsStr = truncate(safeStringify(args));
|
|
276
|
-
if (argsStr) endAttrs
|
|
269
|
+
if (argsStr) pushAttr(endAttrs, attrString("ai.toolCall.args", argsStr));
|
|
277
270
|
const resultStr = truncate(safeStringify(result));
|
|
278
|
-
if (resultStr) endAttrs
|
|
271
|
+
if (resultStr) pushAttr(endAttrs, attrString("ai.toolCall.result", resultStr));
|
|
279
272
|
traceShipper.endSpan(toolSpan, {
|
|
280
273
|
attributes: endAttrs,
|
|
281
274
|
...isError ? { error: `Tool "${toolName}" failed` } : {}
|
|
@@ -302,29 +295,28 @@ function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, opt
|
|
|
302
295
|
}
|
|
303
296
|
const outputText = capText(run.outputParts.join(""));
|
|
304
297
|
if (traceShipper && run.rootSpan) {
|
|
305
|
-
const rootAttrs = [
|
|
306
|
-
|
|
307
|
-
];
|
|
298
|
+
const rootAttrs = [];
|
|
299
|
+
pushAttr(rootAttrs, attrString("ai.operationId", "generateText"));
|
|
308
300
|
if (run.lastModel) {
|
|
309
301
|
run.rootSpan.name = run.lastProvider ? `${run.lastProvider}/${run.lastModel}` : run.lastModel;
|
|
310
|
-
rootAttrs
|
|
302
|
+
pushAttr(rootAttrs, attrString("gen_ai.response.model", run.lastModel));
|
|
311
303
|
}
|
|
312
304
|
if (run.currentInput) {
|
|
313
|
-
rootAttrs
|
|
305
|
+
pushAttr(rootAttrs, attrString("ai.prompt", truncate(run.currentInput)));
|
|
314
306
|
}
|
|
315
307
|
if (outputText) {
|
|
316
|
-
rootAttrs
|
|
308
|
+
pushAttr(rootAttrs, attrString("ai.response.text", truncate(outputText)));
|
|
317
309
|
}
|
|
318
310
|
if (run.totalInputTokens > 0) {
|
|
319
|
-
rootAttrs
|
|
311
|
+
pushAttr(rootAttrs, attrInt("gen_ai.usage.input_tokens", run.totalInputTokens));
|
|
320
312
|
}
|
|
321
313
|
if (run.totalOutputTokens > 0) {
|
|
322
|
-
rootAttrs
|
|
314
|
+
pushAttr(rootAttrs, attrInt("gen_ai.usage.output_tokens", run.totalOutputTokens));
|
|
323
315
|
}
|
|
324
316
|
if (run.totalCacheReadTokens > 0) {
|
|
325
|
-
rootAttrs
|
|
317
|
+
pushAttr(rootAttrs, attrInt("gen_ai.usage.cache_read_tokens", run.totalCacheReadTokens));
|
|
326
318
|
}
|
|
327
|
-
rootAttrs
|
|
319
|
+
pushAttr(rootAttrs, attrInt("ai.total_turns", run.turnNumber));
|
|
328
320
|
traceShipper.endSpan(run.rootSpan, { attributes: rootAttrs });
|
|
329
321
|
}
|
|
330
322
|
if (eventShipper) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raindrop-ai/pi-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Raindrop observability for Pi Agent — automatic tracing via subscriber or pi-coding-agent extension",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"tsup": "^8.5.1",
|
|
55
55
|
"typescript": "^5.7.3",
|
|
56
56
|
"vitest": "^2.1.9",
|
|
57
|
-
"@raindrop-ai/core": "0.
|
|
57
|
+
"@raindrop-ai/core": "0.2.0"
|
|
58
58
|
},
|
|
59
59
|
"tsup": {
|
|
60
60
|
"entry": [
|