@raindrop-ai/opencode-plugin 0.1.1 → 0.1.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/index.cjs +233 -38
- package/dist/index.js +233 -45
- package/package.json +2 -2
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-3V4MIA75.js
|
|
28
28
|
function getCrypto() {
|
|
29
29
|
const c = globalThis.crypto;
|
|
30
30
|
return c;
|
|
@@ -82,6 +82,20 @@ function base64Encode(bytes) {
|
|
|
82
82
|
function generateId() {
|
|
83
83
|
return randomUUID();
|
|
84
84
|
}
|
|
85
|
+
var HANDOFF_ATTRIBUTE_SUFFIXES = {
|
|
86
|
+
mode: "raindrop.handoff.mode",
|
|
87
|
+
childEventId: "raindrop.handoff.childEventId",
|
|
88
|
+
parentEventId: "raindrop.handoff.parentEventId",
|
|
89
|
+
parentSpanId: "raindrop.handoff.parentSpanId",
|
|
90
|
+
name: "raindrop.handoff.name",
|
|
91
|
+
terminal: "raindrop.handoff.terminal",
|
|
92
|
+
agentRole: "raindrop.agent.role"
|
|
93
|
+
};
|
|
94
|
+
var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
|
|
95
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
96
|
+
var BAGGAGE_HEADER = "baggage";
|
|
97
|
+
var HANDOFF_HEADER = "x-raindrop-handoff";
|
|
98
|
+
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.`;
|
|
85
99
|
function runWithTracingSuppressed(fn) {
|
|
86
100
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
87
101
|
if (typeof hook !== "function") return fn();
|
|
@@ -279,6 +293,11 @@ function attrInt(key, value) {
|
|
|
279
293
|
if (!Number.isFinite(value)) return void 0;
|
|
280
294
|
return { key, value: { intValue: String(Math.trunc(value)) } };
|
|
281
295
|
}
|
|
296
|
+
function attrDouble(key, value) {
|
|
297
|
+
if (value === void 0) return void 0;
|
|
298
|
+
if (!Number.isFinite(value)) return void 0;
|
|
299
|
+
return { key, value: { doubleValue: value } };
|
|
300
|
+
}
|
|
282
301
|
function buildOtlpSpan(args) {
|
|
283
302
|
const attrs = args.attributes.filter((x) => x !== void 0);
|
|
284
303
|
const span = {
|
|
@@ -800,6 +819,163 @@ var EventShipper = class {
|
|
|
800
819
|
}
|
|
801
820
|
}
|
|
802
821
|
};
|
|
822
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
823
|
+
usageSource: "raindrop.usage.source",
|
|
824
|
+
providerName: "gen_ai.provider.name",
|
|
825
|
+
requestModel: "gen_ai.request.model",
|
|
826
|
+
responseModel: "gen_ai.response.model",
|
|
827
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
828
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
829
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
830
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
831
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
832
|
+
providerReportedCost: "gen_ai.usage.provider_reported_cost",
|
|
833
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
834
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
835
|
+
totalOutputTokens: "raindrop.usage.output_tokens.total",
|
|
836
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
837
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
838
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
839
|
+
};
|
|
840
|
+
var MODEL_PROVIDER_NAMES = [
|
|
841
|
+
["google.vertex.anthropic", "google-vertex"],
|
|
842
|
+
["google.vertex_ai", "google-vertex"],
|
|
843
|
+
["google.vertex", "google-vertex"],
|
|
844
|
+
["gcp.vertex_ai", "google-vertex"],
|
|
845
|
+
["gcp.gemini", "google"],
|
|
846
|
+
["google_vertexai", "google-vertex"],
|
|
847
|
+
["vertex.anthropic", "google-vertex"],
|
|
848
|
+
["amazon-bedrock", "amazon-bedrock"],
|
|
849
|
+
["aws.bedrock", "amazon-bedrock"],
|
|
850
|
+
["bedrock", "amazon-bedrock"],
|
|
851
|
+
["anthropic", "anthropic"],
|
|
852
|
+
["openai", "openai"],
|
|
853
|
+
["google", "google"],
|
|
854
|
+
["az.ai.openai", "azure"],
|
|
855
|
+
["azure", "azure"],
|
|
856
|
+
["openrouter", "openrouter"]
|
|
857
|
+
];
|
|
858
|
+
function canonicalModelProvider(provider) {
|
|
859
|
+
var _a;
|
|
860
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
861
|
+
if (normalizedProvider === "gateway") return "vercel";
|
|
862
|
+
const match = MODEL_PROVIDER_NAMES.find(
|
|
863
|
+
([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
|
|
864
|
+
);
|
|
865
|
+
return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
|
|
866
|
+
}
|
|
867
|
+
function tokenCount(value) {
|
|
868
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
869
|
+
}
|
|
870
|
+
function buildRawModelUsageAttributes(usage) {
|
|
871
|
+
const providerReportedCost = typeof usage.providerReportedCost === "number" && Number.isFinite(usage.providerReportedCost) && usage.providerReportedCost >= 0 ? usage.providerReportedCost : void 0;
|
|
872
|
+
return [
|
|
873
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, tokenCount(usage.inputTokens)),
|
|
874
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, tokenCount(usage.outputTokens)),
|
|
875
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, tokenCount(usage.reasoningTokens)),
|
|
876
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, tokenCount(usage.cacheReadInputTokens)),
|
|
877
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, tokenCount(usage.cacheWriteInputTokens)),
|
|
878
|
+
attrDouble(MODEL_USAGE_ATTRIBUTES.providerReportedCost, providerReportedCost)
|
|
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
|
+
}
|
|
803
979
|
var DEFAULT_SECRET_KEY_NAMES = [
|
|
804
980
|
"apikey",
|
|
805
981
|
"apisecret",
|
|
@@ -1000,6 +1176,10 @@ var TraceShipper = class {
|
|
|
1000
1176
|
return null;
|
|
1001
1177
|
}
|
|
1002
1178
|
}
|
|
1179
|
+
try {
|
|
1180
|
+
current = normalizeModelUsageSpan(current);
|
|
1181
|
+
} catch (e) {
|
|
1182
|
+
}
|
|
1003
1183
|
if (!this.disableDefaultRedaction) {
|
|
1004
1184
|
current = defaultTransformSpan(current);
|
|
1005
1185
|
}
|
|
@@ -1296,7 +1476,7 @@ function resolveLocalWorkshopUrl(fileValue) {
|
|
|
1296
1476
|
// package.json
|
|
1297
1477
|
var package_default = {
|
|
1298
1478
|
name: "@raindrop-ai/opencode-plugin",
|
|
1299
|
-
version: "0.1.
|
|
1479
|
+
version: "0.1.3",
|
|
1300
1480
|
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
1301
1481
|
type: "module",
|
|
1302
1482
|
main: "dist/index.js",
|
|
@@ -1401,6 +1581,9 @@ var TraceShipper2 = class extends TraceShipper {
|
|
|
1401
1581
|
}
|
|
1402
1582
|
};
|
|
1403
1583
|
|
|
1584
|
+
// src/tracing.ts
|
|
1585
|
+
var import_node_os2 = require("os");
|
|
1586
|
+
|
|
1404
1587
|
// src/bounded.ts
|
|
1405
1588
|
var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
|
|
1406
1589
|
var MAX_TEXT_FIELD_CHARS = 1e6;
|
|
@@ -1481,6 +1664,47 @@ function boundedStringify(value, limit = MAX_TEXT_FIELD_CHARS) {
|
|
|
1481
1664
|
}
|
|
1482
1665
|
}
|
|
1483
1666
|
|
|
1667
|
+
// src/model-spend.ts
|
|
1668
|
+
function parseOpenCodeAssistantTokens(tokens) {
|
|
1669
|
+
const input = tokens["input"];
|
|
1670
|
+
const output = tokens["output"];
|
|
1671
|
+
if (typeof input !== "number" || typeof output !== "number") return void 0;
|
|
1672
|
+
const reasoning = tokens["reasoning"];
|
|
1673
|
+
const cache = tokens["cache"];
|
|
1674
|
+
const cacheObj = cache && typeof cache === "object" && cache !== null ? cache : void 0;
|
|
1675
|
+
return {
|
|
1676
|
+
input,
|
|
1677
|
+
output,
|
|
1678
|
+
reasoning: typeof reasoning === "number" ? reasoning : 0,
|
|
1679
|
+
cacheRead: typeof (cacheObj == null ? void 0 : cacheObj["read"]) === "number" ? cacheObj["read"] : 0,
|
|
1680
|
+
cacheWrite: typeof (cacheObj == null ? void 0 : cacheObj["write"]) === "number" ? cacheObj["write"] : 0
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
function modelSpendSpanAttributes(input) {
|
|
1684
|
+
const providerAttr = attrString("gen_ai.provider.name", canonicalModelProvider(input.providerID));
|
|
1685
|
+
const usageAttrs = buildRawModelUsageAttributes({
|
|
1686
|
+
inputTokens: input.tokens.input,
|
|
1687
|
+
outputTokens: input.tokens.output,
|
|
1688
|
+
reasoningTokens: input.tokens.reasoning,
|
|
1689
|
+
cacheReadInputTokens: input.tokens.cacheRead,
|
|
1690
|
+
cacheWriteInputTokens: input.tokens.cacheWrite
|
|
1691
|
+
});
|
|
1692
|
+
return providerAttr ? [providerAttr, ...usageAttrs] : usageAttrs;
|
|
1693
|
+
}
|
|
1694
|
+
function buildLlmGenAiAttributes(input) {
|
|
1695
|
+
const parsed = parseOpenCodeAssistantTokens(input.tokens);
|
|
1696
|
+
if (!parsed) return [];
|
|
1697
|
+
return [
|
|
1698
|
+
// OpenCode has already normalized both token axes. Provenance lets Dawn
|
|
1699
|
+
// select that contract without the SDK or customer declaring semantics.
|
|
1700
|
+
attrString(MODEL_USAGE_ATTRIBUTES.usageSource, "opencode"),
|
|
1701
|
+
attrString("gen_ai.system", input.providerID),
|
|
1702
|
+
attrString("gen_ai.request.model", input.modelID),
|
|
1703
|
+
attrString("gen_ai.response.model", input.modelID),
|
|
1704
|
+
...modelSpendSpanAttributes({ providerID: input.providerID, tokens: parsed })
|
|
1705
|
+
].filter((attribute) => attribute !== void 0);
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1484
1708
|
// src/tracing-linkage-helpers.ts
|
|
1485
1709
|
function createSessionParentMapHelpers({
|
|
1486
1710
|
sessions: sessions2,
|
|
@@ -1645,7 +1869,7 @@ function getHostname() {
|
|
|
1645
1869
|
try {
|
|
1646
1870
|
const bunGlobal = globalThis;
|
|
1647
1871
|
if ((_a = bunGlobal.Bun) == null ? void 0 : _a.hostname) return bunGlobal.Bun.hostname;
|
|
1648
|
-
return
|
|
1872
|
+
return (0, import_node_os2.hostname)();
|
|
1649
1873
|
} catch (e) {
|
|
1650
1874
|
const h = process.env["HOSTNAME"];
|
|
1651
1875
|
if (h === void 0 || h === "") throw new Error("HOSTNAME env is not set");
|
|
@@ -1794,7 +2018,6 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1794
2018
|
const tokensObj = tokens;
|
|
1795
2019
|
const inputTokens = tokensObj["input"];
|
|
1796
2020
|
const outputTokens = tokensObj["output"];
|
|
1797
|
-
const reasoningTokens = tokensObj["reasoning"];
|
|
1798
2021
|
if (typeof inputTokens !== "number" || typeof outputTokens !== "number")
|
|
1799
2022
|
throw new Error("message.updated: tokens.input and tokens.output must be numbers");
|
|
1800
2023
|
const providerID = info2["providerID"];
|
|
@@ -1812,13 +2035,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1812
2035
|
state.turnOutputParts.push(outputText);
|
|
1813
2036
|
}
|
|
1814
2037
|
state.turnOutputTokens += outputTokens;
|
|
1815
|
-
|
|
1816
|
-
if (outputText === void 0 && !(isToolCallsCompletion && hasIntermediateReasoning))
|
|
1817
|
-
return;
|
|
1818
|
-
if (isToolCallsCompletion && !hasIntermediateReasoning) {
|
|
1819
|
-
await traceShipper.flush();
|
|
1820
|
-
return;
|
|
1821
|
-
}
|
|
2038
|
+
if (outputText === void 0 && !isToolCallsCompletion) return;
|
|
1822
2039
|
const msgError = info2["error"];
|
|
1823
2040
|
const errorForSpan = msgError ? (() => {
|
|
1824
2041
|
var _a2, _b2;
|
|
@@ -1831,20 +2048,12 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1831
2048
|
type: ${name != null ? name : "UnknownError"}`;
|
|
1832
2049
|
})() : void 0;
|
|
1833
2050
|
if (isToolCallsCompletion) {
|
|
1834
|
-
|
|
1835
|
-
throw new Error("message.updated: reasoningParts missing for tool-call continuation");
|
|
2051
|
+
const responseText = reasoningText !== void 0 && reasoningText.trim().length > 0 ? reasoningText.trim() : outputText !== void 0 && outputText.trim().length > 0 ? outputText.trim() : "";
|
|
1836
2052
|
const llmAttrs = [
|
|
1837
2053
|
attrString("ai.operationId", "generateText"),
|
|
1838
|
-
attrString("ai.response.text",
|
|
1839
|
-
|
|
1840
|
-
attrString("gen_ai.request.model", modelID),
|
|
1841
|
-
attrString("gen_ai.response.model", modelID),
|
|
1842
|
-
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1843
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
2054
|
+
attrString("ai.response.text", responseText),
|
|
2055
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
1844
2056
|
];
|
|
1845
|
-
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1846
|
-
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1847
|
-
}
|
|
1848
2057
|
if (state.currentSystemPrompt) {
|
|
1849
2058
|
llmAttrs.push(
|
|
1850
2059
|
attrString("gen_ai.prompt.0.role", "system"),
|
|
@@ -1879,15 +2088,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1879
2088
|
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1880
2089
|
),
|
|
1881
2090
|
attrString("ai.response.text", turnOutputText),
|
|
1882
|
-
|
|
1883
|
-
attrString("gen_ai.request.model", modelID),
|
|
1884
|
-
attrString("gen_ai.response.model", modelID),
|
|
1885
|
-
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1886
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
2091
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
1887
2092
|
];
|
|
1888
|
-
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1889
|
-
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1890
|
-
}
|
|
1891
2093
|
if (state.currentSystemPrompt) {
|
|
1892
2094
|
llmAttrs.push(
|
|
1893
2095
|
attrString("gen_ai.prompt.0.role", "system"),
|
|
@@ -1931,19 +2133,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1931
2133
|
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1932
2134
|
),
|
|
1933
2135
|
attrString("ai.response.text", turnOutputText),
|
|
1934
|
-
|
|
1935
|
-
attrString("gen_ai.request.model", modelID),
|
|
1936
|
-
attrString("gen_ai.response.model", modelID),
|
|
1937
|
-
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1938
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
2136
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
1939
2137
|
];
|
|
1940
2138
|
if (isCompaction) {
|
|
1941
2139
|
rootAttrs.push(attrString("is_compaction", "true"));
|
|
1942
2140
|
}
|
|
1943
2141
|
rootAttrs.push(attrString("message_id", messageId));
|
|
1944
|
-
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1945
|
-
rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1946
|
-
}
|
|
1947
2142
|
if (state.currentSystemPrompt) {
|
|
1948
2143
|
rootAttrs.push(
|
|
1949
2144
|
attrString("gen_ai.prompt.0.role", "system"),
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
// ../core/dist/chunk-QTUH3BHZ.js
|
|
1
|
+
// ../core/dist/chunk-3V4MIA75.js
|
|
9
2
|
function getCrypto() {
|
|
10
3
|
const c = globalThis.crypto;
|
|
11
4
|
return c;
|
|
@@ -63,6 +56,20 @@ function base64Encode(bytes) {
|
|
|
63
56
|
function generateId() {
|
|
64
57
|
return randomUUID();
|
|
65
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.`;
|
|
66
73
|
function runWithTracingSuppressed(fn) {
|
|
67
74
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
68
75
|
if (typeof hook !== "function") return fn();
|
|
@@ -260,6 +267,11 @@ function attrInt(key, value) {
|
|
|
260
267
|
if (!Number.isFinite(value)) return void 0;
|
|
261
268
|
return { key, value: { intValue: String(Math.trunc(value)) } };
|
|
262
269
|
}
|
|
270
|
+
function attrDouble(key, value) {
|
|
271
|
+
if (value === void 0) return void 0;
|
|
272
|
+
if (!Number.isFinite(value)) return void 0;
|
|
273
|
+
return { key, value: { doubleValue: value } };
|
|
274
|
+
}
|
|
263
275
|
function buildOtlpSpan(args) {
|
|
264
276
|
const attrs = args.attributes.filter((x) => x !== void 0);
|
|
265
277
|
const span = {
|
|
@@ -781,6 +793,163 @@ var EventShipper = class {
|
|
|
781
793
|
}
|
|
782
794
|
}
|
|
783
795
|
};
|
|
796
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
797
|
+
usageSource: "raindrop.usage.source",
|
|
798
|
+
providerName: "gen_ai.provider.name",
|
|
799
|
+
requestModel: "gen_ai.request.model",
|
|
800
|
+
responseModel: "gen_ai.response.model",
|
|
801
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
802
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
803
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
804
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
805
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
806
|
+
providerReportedCost: "gen_ai.usage.provider_reported_cost",
|
|
807
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
808
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
809
|
+
totalOutputTokens: "raindrop.usage.output_tokens.total",
|
|
810
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
811
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
812
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
813
|
+
};
|
|
814
|
+
var MODEL_PROVIDER_NAMES = [
|
|
815
|
+
["google.vertex.anthropic", "google-vertex"],
|
|
816
|
+
["google.vertex_ai", "google-vertex"],
|
|
817
|
+
["google.vertex", "google-vertex"],
|
|
818
|
+
["gcp.vertex_ai", "google-vertex"],
|
|
819
|
+
["gcp.gemini", "google"],
|
|
820
|
+
["google_vertexai", "google-vertex"],
|
|
821
|
+
["vertex.anthropic", "google-vertex"],
|
|
822
|
+
["amazon-bedrock", "amazon-bedrock"],
|
|
823
|
+
["aws.bedrock", "amazon-bedrock"],
|
|
824
|
+
["bedrock", "amazon-bedrock"],
|
|
825
|
+
["anthropic", "anthropic"],
|
|
826
|
+
["openai", "openai"],
|
|
827
|
+
["google", "google"],
|
|
828
|
+
["az.ai.openai", "azure"],
|
|
829
|
+
["azure", "azure"],
|
|
830
|
+
["openrouter", "openrouter"]
|
|
831
|
+
];
|
|
832
|
+
function canonicalModelProvider(provider) {
|
|
833
|
+
var _a;
|
|
834
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
835
|
+
if (normalizedProvider === "gateway") return "vercel";
|
|
836
|
+
const match = MODEL_PROVIDER_NAMES.find(
|
|
837
|
+
([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
|
|
838
|
+
);
|
|
839
|
+
return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
|
|
840
|
+
}
|
|
841
|
+
function tokenCount(value) {
|
|
842
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
843
|
+
}
|
|
844
|
+
function buildRawModelUsageAttributes(usage) {
|
|
845
|
+
const providerReportedCost = typeof usage.providerReportedCost === "number" && Number.isFinite(usage.providerReportedCost) && usage.providerReportedCost >= 0 ? usage.providerReportedCost : void 0;
|
|
846
|
+
return [
|
|
847
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, tokenCount(usage.inputTokens)),
|
|
848
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, tokenCount(usage.outputTokens)),
|
|
849
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, tokenCount(usage.reasoningTokens)),
|
|
850
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, tokenCount(usage.cacheReadInputTokens)),
|
|
851
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, tokenCount(usage.cacheWriteInputTokens)),
|
|
852
|
+
attrDouble(MODEL_USAGE_ATTRIBUTES.providerReportedCost, providerReportedCost)
|
|
853
|
+
].filter((attribute) => attribute !== void 0);
|
|
854
|
+
}
|
|
855
|
+
var STRING_ALIASES = {
|
|
856
|
+
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
857
|
+
};
|
|
858
|
+
var NUMBER_ALIASES = {
|
|
859
|
+
[MODEL_USAGE_ATTRIBUTES.inputTokens]: [
|
|
860
|
+
"gen_ai.usage.prompt_tokens",
|
|
861
|
+
"ai.usage.prompt_tokens",
|
|
862
|
+
"ai.usage.promptTokens",
|
|
863
|
+
"ai.usage.input_tokens",
|
|
864
|
+
"ai.usage.inputTokens"
|
|
865
|
+
],
|
|
866
|
+
[MODEL_USAGE_ATTRIBUTES.outputTokens]: [
|
|
867
|
+
"gen_ai.usage.completion_tokens",
|
|
868
|
+
"ai.usage.completion_tokens",
|
|
869
|
+
"ai.usage.completionTokens",
|
|
870
|
+
"ai.usage.output_tokens",
|
|
871
|
+
"ai.usage.outputTokens"
|
|
872
|
+
],
|
|
873
|
+
[MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
|
|
874
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
875
|
+
"ai.usage.reasoningTokens",
|
|
876
|
+
"ai.usage.thoughts_tokens"
|
|
877
|
+
],
|
|
878
|
+
[MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
|
|
879
|
+
"gen_ai.usage.cache_read_tokens",
|
|
880
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
881
|
+
"ai.usage.cachedInputTokens",
|
|
882
|
+
"ai.usage.cached_tokens",
|
|
883
|
+
"ai.usage.cache_read_tokens",
|
|
884
|
+
"ai.usage.cache_read_input_tokens",
|
|
885
|
+
"ai.usage.cacheReadInputTokens"
|
|
886
|
+
],
|
|
887
|
+
[MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
|
|
888
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
889
|
+
"gen_ai.usage.cache_creation.input_tokens",
|
|
890
|
+
"ai.usage.cacheWriteInputTokens",
|
|
891
|
+
"ai.usage.cache_creation_input_tokens",
|
|
892
|
+
"ai.usage.cacheCreationInputTokens"
|
|
893
|
+
]
|
|
894
|
+
};
|
|
895
|
+
function hasAttribute(attributes, key) {
|
|
896
|
+
return attributes.some((attribute) => attribute.key === key);
|
|
897
|
+
}
|
|
898
|
+
function findStringAttribute(attributes, keys) {
|
|
899
|
+
return attributes.find(
|
|
900
|
+
(attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
|
|
901
|
+
);
|
|
902
|
+
}
|
|
903
|
+
function findNumberAttribute(attributes, keys) {
|
|
904
|
+
return attributes.find((attribute) => {
|
|
905
|
+
if (!keys.includes(attribute.key)) return false;
|
|
906
|
+
if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
|
|
907
|
+
return true;
|
|
908
|
+
}
|
|
909
|
+
const intValue = attribute.value.intValue;
|
|
910
|
+
return integerValue(intValue) !== void 0;
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
function integerValue(value) {
|
|
914
|
+
if (typeof value === "number") {
|
|
915
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
916
|
+
}
|
|
917
|
+
if (typeof value !== "string") return void 0;
|
|
918
|
+
const parsed = Number(value);
|
|
919
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
920
|
+
}
|
|
921
|
+
function appendAlias(attributes, target, source) {
|
|
922
|
+
if (!source || hasAttribute(attributes, target)) return attributes;
|
|
923
|
+
return [...attributes, { key: target, value: { ...source.value } }];
|
|
924
|
+
}
|
|
925
|
+
function appendProviderAlias(attributes) {
|
|
926
|
+
if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
|
|
927
|
+
const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
|
|
928
|
+
if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
|
|
929
|
+
const attribute = attrString(
|
|
930
|
+
MODEL_USAGE_ATTRIBUTES.providerName,
|
|
931
|
+
canonicalModelProvider(source.value.stringValue)
|
|
932
|
+
);
|
|
933
|
+
return attribute ? [...attributes, attribute] : attributes;
|
|
934
|
+
}
|
|
935
|
+
function normalizeModelUsageSpan(span) {
|
|
936
|
+
const original = span.attributes;
|
|
937
|
+
if (!original || original.length === 0) return span;
|
|
938
|
+
const responseModel = findStringAttribute(original, [
|
|
939
|
+
MODEL_USAGE_ATTRIBUTES.responseModel,
|
|
940
|
+
"ai.response.model"
|
|
941
|
+
]);
|
|
942
|
+
if (!responseModel) return span;
|
|
943
|
+
let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
|
|
944
|
+
attributes = appendProviderAlias(attributes);
|
|
945
|
+
for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
|
|
946
|
+
attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
|
|
947
|
+
}
|
|
948
|
+
for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
|
|
949
|
+
attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
|
|
950
|
+
}
|
|
951
|
+
return attributes === original ? span : { ...span, attributes };
|
|
952
|
+
}
|
|
784
953
|
var DEFAULT_SECRET_KEY_NAMES = [
|
|
785
954
|
"apikey",
|
|
786
955
|
"apisecret",
|
|
@@ -981,6 +1150,10 @@ var TraceShipper = class {
|
|
|
981
1150
|
return null;
|
|
982
1151
|
}
|
|
983
1152
|
}
|
|
1153
|
+
try {
|
|
1154
|
+
current = normalizeModelUsageSpan(current);
|
|
1155
|
+
} catch (e) {
|
|
1156
|
+
}
|
|
984
1157
|
if (!this.disableDefaultRedaction) {
|
|
985
1158
|
current = defaultTransformSpan(current);
|
|
986
1159
|
}
|
|
@@ -1277,7 +1450,7 @@ function resolveLocalWorkshopUrl(fileValue) {
|
|
|
1277
1450
|
// package.json
|
|
1278
1451
|
var package_default = {
|
|
1279
1452
|
name: "@raindrop-ai/opencode-plugin",
|
|
1280
|
-
version: "0.1.
|
|
1453
|
+
version: "0.1.3",
|
|
1281
1454
|
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
1282
1455
|
type: "module",
|
|
1283
1456
|
main: "dist/index.js",
|
|
@@ -1382,6 +1555,9 @@ var TraceShipper2 = class extends TraceShipper {
|
|
|
1382
1555
|
}
|
|
1383
1556
|
};
|
|
1384
1557
|
|
|
1558
|
+
// src/tracing.ts
|
|
1559
|
+
import { hostname as osHostname } from "os";
|
|
1560
|
+
|
|
1385
1561
|
// src/bounded.ts
|
|
1386
1562
|
var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
|
|
1387
1563
|
var MAX_TEXT_FIELD_CHARS = 1e6;
|
|
@@ -1462,6 +1638,47 @@ function boundedStringify(value, limit = MAX_TEXT_FIELD_CHARS) {
|
|
|
1462
1638
|
}
|
|
1463
1639
|
}
|
|
1464
1640
|
|
|
1641
|
+
// src/model-spend.ts
|
|
1642
|
+
function parseOpenCodeAssistantTokens(tokens) {
|
|
1643
|
+
const input = tokens["input"];
|
|
1644
|
+
const output = tokens["output"];
|
|
1645
|
+
if (typeof input !== "number" || typeof output !== "number") return void 0;
|
|
1646
|
+
const reasoning = tokens["reasoning"];
|
|
1647
|
+
const cache = tokens["cache"];
|
|
1648
|
+
const cacheObj = cache && typeof cache === "object" && cache !== null ? cache : void 0;
|
|
1649
|
+
return {
|
|
1650
|
+
input,
|
|
1651
|
+
output,
|
|
1652
|
+
reasoning: typeof reasoning === "number" ? reasoning : 0,
|
|
1653
|
+
cacheRead: typeof (cacheObj == null ? void 0 : cacheObj["read"]) === "number" ? cacheObj["read"] : 0,
|
|
1654
|
+
cacheWrite: typeof (cacheObj == null ? void 0 : cacheObj["write"]) === "number" ? cacheObj["write"] : 0
|
|
1655
|
+
};
|
|
1656
|
+
}
|
|
1657
|
+
function modelSpendSpanAttributes(input) {
|
|
1658
|
+
const providerAttr = attrString("gen_ai.provider.name", canonicalModelProvider(input.providerID));
|
|
1659
|
+
const usageAttrs = buildRawModelUsageAttributes({
|
|
1660
|
+
inputTokens: input.tokens.input,
|
|
1661
|
+
outputTokens: input.tokens.output,
|
|
1662
|
+
reasoningTokens: input.tokens.reasoning,
|
|
1663
|
+
cacheReadInputTokens: input.tokens.cacheRead,
|
|
1664
|
+
cacheWriteInputTokens: input.tokens.cacheWrite
|
|
1665
|
+
});
|
|
1666
|
+
return providerAttr ? [providerAttr, ...usageAttrs] : usageAttrs;
|
|
1667
|
+
}
|
|
1668
|
+
function buildLlmGenAiAttributes(input) {
|
|
1669
|
+
const parsed = parseOpenCodeAssistantTokens(input.tokens);
|
|
1670
|
+
if (!parsed) return [];
|
|
1671
|
+
return [
|
|
1672
|
+
// OpenCode has already normalized both token axes. Provenance lets Dawn
|
|
1673
|
+
// select that contract without the SDK or customer declaring semantics.
|
|
1674
|
+
attrString(MODEL_USAGE_ATTRIBUTES.usageSource, "opencode"),
|
|
1675
|
+
attrString("gen_ai.system", input.providerID),
|
|
1676
|
+
attrString("gen_ai.request.model", input.modelID),
|
|
1677
|
+
attrString("gen_ai.response.model", input.modelID),
|
|
1678
|
+
...modelSpendSpanAttributes({ providerID: input.providerID, tokens: parsed })
|
|
1679
|
+
].filter((attribute) => attribute !== void 0);
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1465
1682
|
// src/tracing-linkage-helpers.ts
|
|
1466
1683
|
function createSessionParentMapHelpers({
|
|
1467
1684
|
sessions: sessions2,
|
|
@@ -1626,7 +1843,7 @@ function getHostname() {
|
|
|
1626
1843
|
try {
|
|
1627
1844
|
const bunGlobal = globalThis;
|
|
1628
1845
|
if ((_a = bunGlobal.Bun) == null ? void 0 : _a.hostname) return bunGlobal.Bun.hostname;
|
|
1629
|
-
return
|
|
1846
|
+
return osHostname();
|
|
1630
1847
|
} catch (e) {
|
|
1631
1848
|
const h = process.env["HOSTNAME"];
|
|
1632
1849
|
if (h === void 0 || h === "") throw new Error("HOSTNAME env is not set");
|
|
@@ -1775,7 +1992,6 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1775
1992
|
const tokensObj = tokens;
|
|
1776
1993
|
const inputTokens = tokensObj["input"];
|
|
1777
1994
|
const outputTokens = tokensObj["output"];
|
|
1778
|
-
const reasoningTokens = tokensObj["reasoning"];
|
|
1779
1995
|
if (typeof inputTokens !== "number" || typeof outputTokens !== "number")
|
|
1780
1996
|
throw new Error("message.updated: tokens.input and tokens.output must be numbers");
|
|
1781
1997
|
const providerID = info2["providerID"];
|
|
@@ -1793,13 +2009,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1793
2009
|
state.turnOutputParts.push(outputText);
|
|
1794
2010
|
}
|
|
1795
2011
|
state.turnOutputTokens += outputTokens;
|
|
1796
|
-
|
|
1797
|
-
if (outputText === void 0 && !(isToolCallsCompletion && hasIntermediateReasoning))
|
|
1798
|
-
return;
|
|
1799
|
-
if (isToolCallsCompletion && !hasIntermediateReasoning) {
|
|
1800
|
-
await traceShipper.flush();
|
|
1801
|
-
return;
|
|
1802
|
-
}
|
|
2012
|
+
if (outputText === void 0 && !isToolCallsCompletion) return;
|
|
1803
2013
|
const msgError = info2["error"];
|
|
1804
2014
|
const errorForSpan = msgError ? (() => {
|
|
1805
2015
|
var _a2, _b2;
|
|
@@ -1812,20 +2022,12 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
1812
2022
|
type: ${name != null ? name : "UnknownError"}`;
|
|
1813
2023
|
})() : void 0;
|
|
1814
2024
|
if (isToolCallsCompletion) {
|
|
1815
|
-
|
|
1816
|
-
throw new Error("message.updated: reasoningParts missing for tool-call continuation");
|
|
2025
|
+
const responseText = reasoningText !== void 0 && reasoningText.trim().length > 0 ? reasoningText.trim() : outputText !== void 0 && outputText.trim().length > 0 ? outputText.trim() : "";
|
|
1817
2026
|
const llmAttrs = [
|
|
1818
2027
|
attrString("ai.operationId", "generateText"),
|
|
1819
|
-
attrString("ai.response.text",
|
|
1820
|
-
|
|
1821
|
-
attrString("gen_ai.request.model", modelID),
|
|
1822
|
-
attrString("gen_ai.response.model", modelID),
|
|
1823
|
-
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1824
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
2028
|
+
attrString("ai.response.text", responseText),
|
|
2029
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
1825
2030
|
];
|
|
1826
|
-
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1827
|
-
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1828
|
-
}
|
|
1829
2031
|
if (state.currentSystemPrompt) {
|
|
1830
2032
|
llmAttrs.push(
|
|
1831
2033
|
attrString("gen_ai.prompt.0.role", "system"),
|
|
@@ -1860,15 +2062,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1860
2062
|
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1861
2063
|
),
|
|
1862
2064
|
attrString("ai.response.text", turnOutputText),
|
|
1863
|
-
|
|
1864
|
-
attrString("gen_ai.request.model", modelID),
|
|
1865
|
-
attrString("gen_ai.response.model", modelID),
|
|
1866
|
-
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1867
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
2065
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
1868
2066
|
];
|
|
1869
|
-
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1870
|
-
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1871
|
-
}
|
|
1872
2067
|
if (state.currentSystemPrompt) {
|
|
1873
2068
|
llmAttrs.push(
|
|
1874
2069
|
attrString("gen_ai.prompt.0.role", "system"),
|
|
@@ -1912,19 +2107,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1912
2107
|
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
1913
2108
|
),
|
|
1914
2109
|
attrString("ai.response.text", turnOutputText),
|
|
1915
|
-
|
|
1916
|
-
attrString("gen_ai.request.model", modelID),
|
|
1917
|
-
attrString("gen_ai.response.model", modelID),
|
|
1918
|
-
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1919
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
2110
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
1920
2111
|
];
|
|
1921
2112
|
if (isCompaction) {
|
|
1922
2113
|
rootAttrs.push(attrString("is_compaction", "true"));
|
|
1923
2114
|
}
|
|
1924
2115
|
rootAttrs.push(attrString("message_id", messageId));
|
|
1925
|
-
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1926
|
-
rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1927
|
-
}
|
|
1928
2116
|
if (state.currentSystemPrompt) {
|
|
1929
2117
|
rootAttrs.push(
|
|
1930
2118
|
attrString("gen_ai.prompt.0.role", "system"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raindrop-ai/opencode-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Raindrop observability plugin for OpenCode — automatic session/event/span tracing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@types/node": "^20.11.17",
|
|
38
38
|
"tsup": "^8.4.0",
|
|
39
39
|
"typescript": "^5.3.3",
|
|
40
|
-
"@raindrop-ai/core": "0.1
|
|
40
|
+
"@raindrop-ai/core": "0.2.1"
|
|
41
41
|
},
|
|
42
42
|
"tsup": {
|
|
43
43
|
"entry": [
|