@raindrop-ai/opencode-plugin 0.0.5 → 0.0.7
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 +164 -96
- package/dist/index.js +164 -96
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -29,7 +29,7 @@ var import_node_fs = require("fs");
|
|
|
29
29
|
var import_node_os = require("os");
|
|
30
30
|
var import_node_path = require("path");
|
|
31
31
|
function loadConfig(projectDirectory) {
|
|
32
|
-
var _a, _b, _c, _d, _e, _f;
|
|
32
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
33
33
|
let merged = {};
|
|
34
34
|
const configPaths = [
|
|
35
35
|
(0, import_node_path.join)((0, import_node_os.homedir)(), ".config", "opencode", "raindrop.json"),
|
|
@@ -45,15 +45,93 @@ function loadConfig(projectDirectory) {
|
|
|
45
45
|
} catch (e) {
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
|
+
let eventMetadata;
|
|
49
|
+
const envMeta = process.env["RAINDROP_EVENT_METADATA"];
|
|
50
|
+
if (envMeta) {
|
|
51
|
+
try {
|
|
52
|
+
eventMetadata = JSON.parse(envMeta);
|
|
53
|
+
} catch (e) {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
48
56
|
return {
|
|
49
57
|
writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
|
|
50
58
|
endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
|
|
51
59
|
eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
|
|
52
|
-
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false
|
|
60
|
+
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false,
|
|
61
|
+
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_g = merged.capture_system_prompt) != null ? _g : false,
|
|
62
|
+
eventMetadata
|
|
53
63
|
};
|
|
54
64
|
}
|
|
55
65
|
|
|
56
|
-
//
|
|
66
|
+
// package.json
|
|
67
|
+
var package_default = {
|
|
68
|
+
name: "@raindrop-ai/opencode-plugin",
|
|
69
|
+
version: "0.0.7",
|
|
70
|
+
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
71
|
+
type: "module",
|
|
72
|
+
main: "dist/index.cjs",
|
|
73
|
+
module: "dist/index.js",
|
|
74
|
+
types: "dist/index.d.ts",
|
|
75
|
+
exports: {
|
|
76
|
+
".": {
|
|
77
|
+
types: "./dist/index.d.ts",
|
|
78
|
+
import: "./dist/index.js",
|
|
79
|
+
require: "./dist/index.cjs"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
sideEffects: false,
|
|
83
|
+
files: [
|
|
84
|
+
"dist/**"
|
|
85
|
+
],
|
|
86
|
+
scripts: {
|
|
87
|
+
build: "tsup",
|
|
88
|
+
dev: "tsup --watch",
|
|
89
|
+
clean: "rm -rf dist",
|
|
90
|
+
test: "cd tests && pnpm test"
|
|
91
|
+
},
|
|
92
|
+
peerDependencies: {
|
|
93
|
+
"@opencode-ai/plugin": ">=1.3.0",
|
|
94
|
+
"@opencode-ai/sdk": ">=1.3.0"
|
|
95
|
+
},
|
|
96
|
+
peerDependenciesMeta: {
|
|
97
|
+
"@opencode-ai/sdk": {
|
|
98
|
+
optional: true
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
devDependencies: {
|
|
102
|
+
"@raindrop-ai/core": "workspace:*",
|
|
103
|
+
"@opencode-ai/plugin": "^1.3.3",
|
|
104
|
+
"@opencode-ai/sdk": "^1.3.3",
|
|
105
|
+
"@types/node": "^20.11.17",
|
|
106
|
+
tsup: "^8.4.0",
|
|
107
|
+
typescript: "^5.3.3"
|
|
108
|
+
},
|
|
109
|
+
tsup: {
|
|
110
|
+
entry: [
|
|
111
|
+
"src/index.ts"
|
|
112
|
+
],
|
|
113
|
+
format: [
|
|
114
|
+
"cjs",
|
|
115
|
+
"esm"
|
|
116
|
+
],
|
|
117
|
+
dts: {
|
|
118
|
+
resolve: true
|
|
119
|
+
},
|
|
120
|
+
clean: true,
|
|
121
|
+
noExternal: [
|
|
122
|
+
"@raindrop-ai/core"
|
|
123
|
+
]
|
|
124
|
+
},
|
|
125
|
+
publishConfig: {
|
|
126
|
+
access: "public"
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// src/package-info.ts
|
|
131
|
+
var PLUGIN_NAME = package_default.name;
|
|
132
|
+
var PLUGIN_VERSION = package_default.version;
|
|
133
|
+
|
|
134
|
+
// ../core/dist/chunk-H6VSZSLN.js
|
|
57
135
|
function getCrypto() {
|
|
58
136
|
const c = globalThis.crypto;
|
|
59
137
|
return c;
|
|
@@ -298,6 +376,7 @@ var EventShipper = class {
|
|
|
298
376
|
console.log(`${this.prefix} queue patch`, {
|
|
299
377
|
eventId,
|
|
300
378
|
userId: patch.userId,
|
|
379
|
+
convoId: patch.convoId,
|
|
301
380
|
eventName: patch.eventName,
|
|
302
381
|
hasInput: typeof patch.input === "string" && patch.input.length > 0,
|
|
303
382
|
hasOutput: typeof patch.output === "string" && patch.output.length > 0,
|
|
@@ -426,16 +505,18 @@ var EventShipper = class {
|
|
|
426
505
|
return;
|
|
427
506
|
}
|
|
428
507
|
const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
|
|
508
|
+
const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
|
|
509
|
+
const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
|
|
429
510
|
const payload = {
|
|
430
511
|
event_id: eventId,
|
|
431
512
|
user_id: userId,
|
|
432
513
|
event: eventName,
|
|
433
|
-
timestamp: (
|
|
514
|
+
timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
|
|
434
515
|
ai_data: {
|
|
435
516
|
input: accumulated.input,
|
|
436
517
|
output: accumulated.output,
|
|
437
518
|
model: accumulated.model,
|
|
438
|
-
convo_id:
|
|
519
|
+
convo_id: convoId
|
|
439
520
|
},
|
|
440
521
|
properties: {
|
|
441
522
|
...restProperties,
|
|
@@ -443,7 +524,7 @@ var EventShipper = class {
|
|
|
443
524
|
$context: this.context
|
|
444
525
|
},
|
|
445
526
|
attachments: accumulated.attachments,
|
|
446
|
-
is_pending:
|
|
527
|
+
is_pending: isPending
|
|
447
528
|
};
|
|
448
529
|
const url = `${this.baseUrl}events/track_partial`;
|
|
449
530
|
if (this.debug) {
|
|
@@ -451,7 +532,8 @@ var EventShipper = class {
|
|
|
451
532
|
eventId,
|
|
452
533
|
eventName,
|
|
453
534
|
userId,
|
|
454
|
-
|
|
535
|
+
convoId,
|
|
536
|
+
isPending,
|
|
455
537
|
inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
|
|
456
538
|
outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
|
|
457
539
|
attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
|
|
@@ -483,7 +565,6 @@ var EventShipper = class {
|
|
|
483
565
|
} finally {
|
|
484
566
|
this.inFlight.delete(p);
|
|
485
567
|
}
|
|
486
|
-
const isPending = payload.is_pending;
|
|
487
568
|
if (!isPending) {
|
|
488
569
|
this.sticky.delete(eventId);
|
|
489
570
|
}
|
|
@@ -636,69 +717,9 @@ var TraceShipper = class {
|
|
|
636
717
|
}
|
|
637
718
|
};
|
|
638
719
|
|
|
639
|
-
//
|
|
640
|
-
var
|
|
641
|
-
|
|
642
|
-
version: "0.0.5",
|
|
643
|
-
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
644
|
-
type: "module",
|
|
645
|
-
main: "dist/index.cjs",
|
|
646
|
-
module: "dist/index.js",
|
|
647
|
-
types: "dist/index.d.ts",
|
|
648
|
-
exports: {
|
|
649
|
-
".": {
|
|
650
|
-
types: "./dist/index.d.ts",
|
|
651
|
-
import: "./dist/index.js",
|
|
652
|
-
require: "./dist/index.cjs"
|
|
653
|
-
}
|
|
654
|
-
},
|
|
655
|
-
sideEffects: false,
|
|
656
|
-
files: [
|
|
657
|
-
"dist/**"
|
|
658
|
-
],
|
|
659
|
-
scripts: {
|
|
660
|
-
build: "tsup",
|
|
661
|
-
dev: "tsup --watch",
|
|
662
|
-
clean: "rm -rf dist",
|
|
663
|
-
test: "cd tests && yarn test"
|
|
664
|
-
},
|
|
665
|
-
peerDependencies: {
|
|
666
|
-
"@opencode-ai/plugin": ">=1.2.0",
|
|
667
|
-
"@opencode-ai/sdk": ">=1.2.0"
|
|
668
|
-
},
|
|
669
|
-
peerDependenciesMeta: {
|
|
670
|
-
"@opencode-ai/sdk": {
|
|
671
|
-
optional: true
|
|
672
|
-
}
|
|
673
|
-
},
|
|
674
|
-
devDependencies: {
|
|
675
|
-
"@raindrop-ai/core": "*",
|
|
676
|
-
"@opencode-ai/plugin": "^1.2.0",
|
|
677
|
-
"@opencode-ai/sdk": "^1.2.0",
|
|
678
|
-
"@types/node": "^20.11.17",
|
|
679
|
-
tsup: "^8.4.0",
|
|
680
|
-
typescript: "^5.3.3"
|
|
681
|
-
},
|
|
682
|
-
tsup: {
|
|
683
|
-
entry: [
|
|
684
|
-
"src/index.ts"
|
|
685
|
-
],
|
|
686
|
-
format: [
|
|
687
|
-
"cjs",
|
|
688
|
-
"esm"
|
|
689
|
-
],
|
|
690
|
-
dts: {
|
|
691
|
-
resolve: true
|
|
692
|
-
},
|
|
693
|
-
clean: true,
|
|
694
|
-
noExternal: [
|
|
695
|
-
"@raindrop-ai/core"
|
|
696
|
-
]
|
|
697
|
-
},
|
|
698
|
-
publishConfig: {
|
|
699
|
-
access: "public"
|
|
700
|
-
}
|
|
701
|
-
};
|
|
720
|
+
// ../core/dist/index.node.js
|
|
721
|
+
var import_async_hooks = require("async_hooks");
|
|
722
|
+
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
|
|
702
723
|
|
|
703
724
|
// src/shipper.ts
|
|
704
725
|
var EventShipper2 = class extends EventShipper {
|
|
@@ -707,8 +728,8 @@ var EventShipper2 = class extends EventShipper {
|
|
|
707
728
|
super({
|
|
708
729
|
...opts,
|
|
709
730
|
sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
|
|
710
|
-
libraryName: (_b = opts.libraryName) != null ? _b :
|
|
711
|
-
libraryVersion: (_c = opts.libraryVersion) != null ? _c :
|
|
731
|
+
libraryName: (_b = opts.libraryName) != null ? _b : PLUGIN_NAME,
|
|
732
|
+
libraryVersion: (_c = opts.libraryVersion) != null ? _c : PLUGIN_VERSION,
|
|
712
733
|
defaultEventName: (_d = opts.defaultEventName) != null ? _d : "opencode_session"
|
|
713
734
|
});
|
|
714
735
|
}
|
|
@@ -720,7 +741,7 @@ var TraceShipper2 = class extends TraceShipper {
|
|
|
720
741
|
...opts,
|
|
721
742
|
sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
|
|
722
743
|
serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.opencode-plugin",
|
|
723
|
-
serviceVersion: (_c = opts.serviceVersion) != null ? _c :
|
|
744
|
+
serviceVersion: (_c = opts.serviceVersion) != null ? _c : PLUGIN_VERSION
|
|
724
745
|
});
|
|
725
746
|
}
|
|
726
747
|
enqueue(span) {
|
|
@@ -820,8 +841,6 @@ var pendingChildSessionsByCallKey = /* @__PURE__ */ new Map();
|
|
|
820
841
|
function createSessionState(sessionId) {
|
|
821
842
|
return {
|
|
822
843
|
sessionId,
|
|
823
|
-
turnNumber: 0,
|
|
824
|
-
toolCount: 0,
|
|
825
844
|
currentInput: "",
|
|
826
845
|
outputParts: /* @__PURE__ */ new Map(),
|
|
827
846
|
reasoningParts: /* @__PURE__ */ new Map(),
|
|
@@ -875,7 +894,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
875
894
|
// event — session lifecycle + streaming parts
|
|
876
895
|
// ------------------------------------------------------------------
|
|
877
896
|
event: async ({ event }) => {
|
|
878
|
-
var _a, _b, _c, _d, _e;
|
|
897
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
879
898
|
try {
|
|
880
899
|
const props = event.properties;
|
|
881
900
|
const info = props["info"];
|
|
@@ -1010,6 +1029,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1010
1029
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1011
1030
|
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1012
1031
|
}
|
|
1032
|
+
if (state.currentSystemPrompt) {
|
|
1033
|
+
llmAttrs.push(
|
|
1034
|
+
attrString("gen_ai.prompt.0.role", "system"),
|
|
1035
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
1036
|
+
);
|
|
1037
|
+
}
|
|
1013
1038
|
const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
|
|
1014
1039
|
const llmSpan = traceShipper.startSpan({
|
|
1015
1040
|
name: modelName,
|
|
@@ -1039,6 +1064,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1039
1064
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1040
1065
|
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1041
1066
|
}
|
|
1067
|
+
if (state.currentSystemPrompt) {
|
|
1068
|
+
llmAttrs.push(
|
|
1069
|
+
attrString("gen_ai.prompt.0.role", "system"),
|
|
1070
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
1071
|
+
);
|
|
1072
|
+
}
|
|
1042
1073
|
if (!state.parentTaskSpanIds) {
|
|
1043
1074
|
traceShipper.endSpan(rootSpan, {
|
|
1044
1075
|
error: "Missing strict parent task for child session"
|
|
@@ -1079,6 +1110,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1079
1110
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1080
1111
|
rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1081
1112
|
}
|
|
1113
|
+
if (state.currentSystemPrompt) {
|
|
1114
|
+
rootAttrs.push(
|
|
1115
|
+
attrString("gen_ai.prompt.0.role", "system"),
|
|
1116
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1082
1119
|
traceShipper.endSpan(rootSpan, {
|
|
1083
1120
|
attributes: rootAttrs,
|
|
1084
1121
|
error: errorForSpan
|
|
@@ -1093,12 +1130,11 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1093
1130
|
}
|
|
1094
1131
|
if (!state.parentId) {
|
|
1095
1132
|
await eventShipper.finish(state.currentEventId, {
|
|
1096
|
-
userId: state.sessionId,
|
|
1133
|
+
userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
|
|
1097
1134
|
model: modelName,
|
|
1098
1135
|
output: outputText,
|
|
1099
1136
|
properties: {
|
|
1100
|
-
|
|
1101
|
-
tool_count: state.toolCount
|
|
1137
|
+
plugin_version: PLUGIN_VERSION
|
|
1102
1138
|
}
|
|
1103
1139
|
});
|
|
1104
1140
|
}
|
|
@@ -1136,7 +1172,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1136
1172
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
1137
1173
|
sessions.delete(String(sessionID));
|
|
1138
1174
|
} else if (event.type === "session.error") {
|
|
1139
|
-
const errorSessionID = (
|
|
1175
|
+
const errorSessionID = (_e = props["sessionID"]) != null ? _e : sessionID;
|
|
1140
1176
|
if (errorSessionID === void 0 || errorSessionID === "")
|
|
1141
1177
|
throw new Error("session.error: missing sessionID");
|
|
1142
1178
|
const state = sessions.get(String(errorSessionID));
|
|
@@ -1144,7 +1180,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1144
1180
|
const errorObj = props["error"];
|
|
1145
1181
|
if (errorObj == null) throw new Error("session.error: missing error object");
|
|
1146
1182
|
const errorName = errorObj.name;
|
|
1147
|
-
const errorMessage = (
|
|
1183
|
+
const errorMessage = (_g = (_f = errorObj.data) == null ? void 0 : _f.message) != null ? _g : errorObj.name;
|
|
1148
1184
|
if (errorName == null && errorMessage == null)
|
|
1149
1185
|
throw new Error("session.error: error object must have name or data.message");
|
|
1150
1186
|
const errorStr = `${errorMessage != null ? errorMessage : errorName}
|
|
@@ -1171,6 +1207,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1171
1207
|
// chat.message — user sent a message; start a new turn with a fresh event ID
|
|
1172
1208
|
// ------------------------------------------------------------------
|
|
1173
1209
|
"chat.message": async (messageInput, output) => {
|
|
1210
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1174
1211
|
try {
|
|
1175
1212
|
const { sessionID } = messageInput;
|
|
1176
1213
|
let state = sessions.get(sessionID);
|
|
@@ -1183,15 +1220,24 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1183
1220
|
traceShipper.endSpan(state.currentRootSpan);
|
|
1184
1221
|
state.currentRootSpan = void 0;
|
|
1185
1222
|
}
|
|
1186
|
-
state.turnNumber++;
|
|
1187
1223
|
if (output == null) throw new Error("chat.message: output is required");
|
|
1188
1224
|
const parts = output.parts;
|
|
1189
1225
|
if (parts == null) throw new Error("chat.message: output.parts is required");
|
|
1190
1226
|
const textParts = [];
|
|
1191
1227
|
const newAttachments = [];
|
|
1228
|
+
const baseMeta = { ...config.eventMetadata };
|
|
1229
|
+
const promptMeta = {};
|
|
1192
1230
|
for (const part of parts) {
|
|
1193
1231
|
if (part["type"] === "text" && typeof part["text"] === "string") {
|
|
1194
1232
|
textParts.push(part["text"]);
|
|
1233
|
+
const meta = part["metadata"];
|
|
1234
|
+
if (meta != null && typeof meta === "object") {
|
|
1235
|
+
const m = meta;
|
|
1236
|
+
if (typeof m["userId"] === "string") promptMeta.userId = m["userId"];
|
|
1237
|
+
if (typeof m["eventName"] === "string") promptMeta.eventName = m["eventName"];
|
|
1238
|
+
if (m["properties"] != null && typeof m["properties"] === "object")
|
|
1239
|
+
promptMeta.properties = m["properties"];
|
|
1240
|
+
}
|
|
1195
1241
|
} else if (part["type"] === "file") {
|
|
1196
1242
|
const mimeType = part["mediaType"];
|
|
1197
1243
|
const filename = part["filename"];
|
|
@@ -1203,6 +1249,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1203
1249
|
}
|
|
1204
1250
|
}
|
|
1205
1251
|
}
|
|
1252
|
+
state.eventMetadata = {
|
|
1253
|
+
...baseMeta,
|
|
1254
|
+
...promptMeta,
|
|
1255
|
+
properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
|
|
1256
|
+
};
|
|
1206
1257
|
const userText = textParts.join("\n");
|
|
1207
1258
|
state.currentInput = userText;
|
|
1208
1259
|
if (state.parentId) {
|
|
@@ -1238,9 +1289,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1238
1289
|
});
|
|
1239
1290
|
await eventShipper.patch(state.currentEventId, {
|
|
1240
1291
|
isPending: true,
|
|
1241
|
-
userId: state.sessionId,
|
|
1292
|
+
userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
|
|
1242
1293
|
convoId: state.sessionId,
|
|
1243
|
-
eventName: config.eventName,
|
|
1294
|
+
eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
|
|
1244
1295
|
input: userText,
|
|
1245
1296
|
...newAttachments.length > 0 ? { attachments: newAttachments } : {},
|
|
1246
1297
|
properties: {
|
|
@@ -1248,8 +1299,8 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1248
1299
|
directory,
|
|
1249
1300
|
hostname,
|
|
1250
1301
|
os,
|
|
1251
|
-
|
|
1252
|
-
|
|
1302
|
+
plugin_version: PLUGIN_VERSION,
|
|
1303
|
+
...(_g = state.eventMetadata) == null ? void 0 : _g.properties
|
|
1253
1304
|
}
|
|
1254
1305
|
});
|
|
1255
1306
|
} catch (err) {
|
|
@@ -1260,7 +1311,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1260
1311
|
// For child sessions, tool spans are parented directly to the parent task span.
|
|
1261
1312
|
// ------------------------------------------------------------------
|
|
1262
1313
|
"tool.execute.before": async (toolInput, _output) => {
|
|
1263
|
-
var _a;
|
|
1314
|
+
var _a, _b, _c;
|
|
1264
1315
|
try {
|
|
1265
1316
|
const { tool, sessionID, callID } = toolInput;
|
|
1266
1317
|
const state = sessions.get(sessionID);
|
|
@@ -1284,7 +1335,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1284
1335
|
ids: liveTaskSpan.ids,
|
|
1285
1336
|
eventContext: {
|
|
1286
1337
|
eventId: state.currentEventId,
|
|
1287
|
-
userId: state.sessionId,
|
|
1338
|
+
userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
|
|
1288
1339
|
convoId: state.sessionId
|
|
1289
1340
|
}
|
|
1290
1341
|
};
|
|
@@ -1325,7 +1376,6 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1325
1376
|
const { tool, sessionID, callID, args } = toolInput;
|
|
1326
1377
|
const state = sessions.get(sessionID);
|
|
1327
1378
|
if (!state || !state.currentEventId) return;
|
|
1328
|
-
state.toolCount++;
|
|
1329
1379
|
if (args === void 0 || args === null)
|
|
1330
1380
|
throw new Error("tool.execute.after: args is required");
|
|
1331
1381
|
const toolCallArgs = typeof args === "string" ? args : JSON.stringify(args);
|
|
@@ -1379,17 +1429,34 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1379
1429
|
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
1380
1430
|
}
|
|
1381
1431
|
}
|
|
1382
|
-
if (!state.parentId) {
|
|
1383
|
-
await eventShipper.patch(state.currentEventId, {
|
|
1384
|
-
userId: state.sessionId,
|
|
1385
|
-
properties: { tool_count: state.toolCount }
|
|
1386
|
-
});
|
|
1387
|
-
}
|
|
1388
1432
|
} catch (err) {
|
|
1389
1433
|
console.log(
|
|
1390
1434
|
`[raindrop-ai/opencode-plugin] [error] Error in tool.execute.after hook: ${err instanceof Error ? err.message : String(err)}`
|
|
1391
1435
|
);
|
|
1392
1436
|
}
|
|
1437
|
+
},
|
|
1438
|
+
// ------------------------------------------------------------------
|
|
1439
|
+
// experimental.chat.system.transform — capture system prompt (read-only)
|
|
1440
|
+
// ------------------------------------------------------------------
|
|
1441
|
+
"experimental.chat.system.transform": async (input, output) => {
|
|
1442
|
+
try {
|
|
1443
|
+
if (!config.captureSystemPrompt) return;
|
|
1444
|
+
const sessionID = input.sessionID;
|
|
1445
|
+
if (!sessionID) return;
|
|
1446
|
+
let state = sessions.get(sessionID);
|
|
1447
|
+
if (!state) {
|
|
1448
|
+
state = createSessionState(sessionID);
|
|
1449
|
+
sessions.set(sessionID, state);
|
|
1450
|
+
}
|
|
1451
|
+
const MAX_SYSTEM_PROMPT_LENGTH = 32768;
|
|
1452
|
+
const TRUNCATION_MARKER = "\n...[truncated]";
|
|
1453
|
+
const joined = output.system.join("\n\n");
|
|
1454
|
+
state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER.length) + TRUNCATION_MARKER : joined;
|
|
1455
|
+
} catch (err) {
|
|
1456
|
+
console.log(
|
|
1457
|
+
`[raindrop-ai/opencode-plugin] [error] Error in experimental.chat.system.transform hook: ${err instanceof Error ? err.message : String(err)}`
|
|
1458
|
+
);
|
|
1459
|
+
}
|
|
1393
1460
|
}
|
|
1394
1461
|
};
|
|
1395
1462
|
}
|
|
@@ -1401,6 +1468,7 @@ async function plugin(input) {
|
|
|
1401
1468
|
function appLog(level, message) {
|
|
1402
1469
|
console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
|
|
1403
1470
|
}
|
|
1471
|
+
appLog("info", `Loading ${PLUGIN_NAME} v${PLUGIN_VERSION}`);
|
|
1404
1472
|
if (!config.writeKey) {
|
|
1405
1473
|
appLog(
|
|
1406
1474
|
"warn",
|
package/dist/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { existsSync, readFileSync } from "fs";
|
|
|
10
10
|
import { homedir } from "os";
|
|
11
11
|
import { join } from "path";
|
|
12
12
|
function loadConfig(projectDirectory) {
|
|
13
|
-
var _a, _b, _c, _d, _e, _f;
|
|
13
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
14
14
|
let merged = {};
|
|
15
15
|
const configPaths = [
|
|
16
16
|
join(homedir(), ".config", "opencode", "raindrop.json"),
|
|
@@ -26,15 +26,93 @@ function loadConfig(projectDirectory) {
|
|
|
26
26
|
} catch (e) {
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
+
let eventMetadata;
|
|
30
|
+
const envMeta = process.env["RAINDROP_EVENT_METADATA"];
|
|
31
|
+
if (envMeta) {
|
|
32
|
+
try {
|
|
33
|
+
eventMetadata = JSON.parse(envMeta);
|
|
34
|
+
} catch (e) {
|
|
35
|
+
}
|
|
36
|
+
}
|
|
29
37
|
return {
|
|
30
38
|
writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
|
|
31
39
|
endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
|
|
32
40
|
eventName: (_e = merged.event_name) != null ? _e : "opencode_session",
|
|
33
|
-
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false
|
|
41
|
+
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false,
|
|
42
|
+
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_g = merged.capture_system_prompt) != null ? _g : false,
|
|
43
|
+
eventMetadata
|
|
34
44
|
};
|
|
35
45
|
}
|
|
36
46
|
|
|
37
|
-
//
|
|
47
|
+
// package.json
|
|
48
|
+
var package_default = {
|
|
49
|
+
name: "@raindrop-ai/opencode-plugin",
|
|
50
|
+
version: "0.0.7",
|
|
51
|
+
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
52
|
+
type: "module",
|
|
53
|
+
main: "dist/index.cjs",
|
|
54
|
+
module: "dist/index.js",
|
|
55
|
+
types: "dist/index.d.ts",
|
|
56
|
+
exports: {
|
|
57
|
+
".": {
|
|
58
|
+
types: "./dist/index.d.ts",
|
|
59
|
+
import: "./dist/index.js",
|
|
60
|
+
require: "./dist/index.cjs"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
sideEffects: false,
|
|
64
|
+
files: [
|
|
65
|
+
"dist/**"
|
|
66
|
+
],
|
|
67
|
+
scripts: {
|
|
68
|
+
build: "tsup",
|
|
69
|
+
dev: "tsup --watch",
|
|
70
|
+
clean: "rm -rf dist",
|
|
71
|
+
test: "cd tests && pnpm test"
|
|
72
|
+
},
|
|
73
|
+
peerDependencies: {
|
|
74
|
+
"@opencode-ai/plugin": ">=1.3.0",
|
|
75
|
+
"@opencode-ai/sdk": ">=1.3.0"
|
|
76
|
+
},
|
|
77
|
+
peerDependenciesMeta: {
|
|
78
|
+
"@opencode-ai/sdk": {
|
|
79
|
+
optional: true
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
devDependencies: {
|
|
83
|
+
"@raindrop-ai/core": "workspace:*",
|
|
84
|
+
"@opencode-ai/plugin": "^1.3.3",
|
|
85
|
+
"@opencode-ai/sdk": "^1.3.3",
|
|
86
|
+
"@types/node": "^20.11.17",
|
|
87
|
+
tsup: "^8.4.0",
|
|
88
|
+
typescript: "^5.3.3"
|
|
89
|
+
},
|
|
90
|
+
tsup: {
|
|
91
|
+
entry: [
|
|
92
|
+
"src/index.ts"
|
|
93
|
+
],
|
|
94
|
+
format: [
|
|
95
|
+
"cjs",
|
|
96
|
+
"esm"
|
|
97
|
+
],
|
|
98
|
+
dts: {
|
|
99
|
+
resolve: true
|
|
100
|
+
},
|
|
101
|
+
clean: true,
|
|
102
|
+
noExternal: [
|
|
103
|
+
"@raindrop-ai/core"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
publishConfig: {
|
|
107
|
+
access: "public"
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// src/package-info.ts
|
|
112
|
+
var PLUGIN_NAME = package_default.name;
|
|
113
|
+
var PLUGIN_VERSION = package_default.version;
|
|
114
|
+
|
|
115
|
+
// ../core/dist/chunk-H6VSZSLN.js
|
|
38
116
|
function getCrypto() {
|
|
39
117
|
const c = globalThis.crypto;
|
|
40
118
|
return c;
|
|
@@ -279,6 +357,7 @@ var EventShipper = class {
|
|
|
279
357
|
console.log(`${this.prefix} queue patch`, {
|
|
280
358
|
eventId,
|
|
281
359
|
userId: patch.userId,
|
|
360
|
+
convoId: patch.convoId,
|
|
282
361
|
eventName: patch.eventName,
|
|
283
362
|
hasInput: typeof patch.input === "string" && patch.input.length > 0,
|
|
284
363
|
hasOutput: typeof patch.output === "string" && patch.output.length > 0,
|
|
@@ -407,16 +486,18 @@ var EventShipper = class {
|
|
|
407
486
|
return;
|
|
408
487
|
}
|
|
409
488
|
const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
|
|
489
|
+
const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
|
|
490
|
+
const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
|
|
410
491
|
const payload = {
|
|
411
492
|
event_id: eventId,
|
|
412
493
|
user_id: userId,
|
|
413
494
|
event: eventName,
|
|
414
|
-
timestamp: (
|
|
495
|
+
timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
|
|
415
496
|
ai_data: {
|
|
416
497
|
input: accumulated.input,
|
|
417
498
|
output: accumulated.output,
|
|
418
499
|
model: accumulated.model,
|
|
419
|
-
convo_id:
|
|
500
|
+
convo_id: convoId
|
|
420
501
|
},
|
|
421
502
|
properties: {
|
|
422
503
|
...restProperties,
|
|
@@ -424,7 +505,7 @@ var EventShipper = class {
|
|
|
424
505
|
$context: this.context
|
|
425
506
|
},
|
|
426
507
|
attachments: accumulated.attachments,
|
|
427
|
-
is_pending:
|
|
508
|
+
is_pending: isPending
|
|
428
509
|
};
|
|
429
510
|
const url = `${this.baseUrl}events/track_partial`;
|
|
430
511
|
if (this.debug) {
|
|
@@ -432,7 +513,8 @@ var EventShipper = class {
|
|
|
432
513
|
eventId,
|
|
433
514
|
eventName,
|
|
434
515
|
userId,
|
|
435
|
-
|
|
516
|
+
convoId,
|
|
517
|
+
isPending,
|
|
436
518
|
inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
|
|
437
519
|
outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
|
|
438
520
|
attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
|
|
@@ -464,7 +546,6 @@ var EventShipper = class {
|
|
|
464
546
|
} finally {
|
|
465
547
|
this.inFlight.delete(p);
|
|
466
548
|
}
|
|
467
|
-
const isPending = payload.is_pending;
|
|
468
549
|
if (!isPending) {
|
|
469
550
|
this.sticky.delete(eventId);
|
|
470
551
|
}
|
|
@@ -617,69 +698,9 @@ var TraceShipper = class {
|
|
|
617
698
|
}
|
|
618
699
|
};
|
|
619
700
|
|
|
620
|
-
//
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
version: "0.0.5",
|
|
624
|
-
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
625
|
-
type: "module",
|
|
626
|
-
main: "dist/index.cjs",
|
|
627
|
-
module: "dist/index.js",
|
|
628
|
-
types: "dist/index.d.ts",
|
|
629
|
-
exports: {
|
|
630
|
-
".": {
|
|
631
|
-
types: "./dist/index.d.ts",
|
|
632
|
-
import: "./dist/index.js",
|
|
633
|
-
require: "./dist/index.cjs"
|
|
634
|
-
}
|
|
635
|
-
},
|
|
636
|
-
sideEffects: false,
|
|
637
|
-
files: [
|
|
638
|
-
"dist/**"
|
|
639
|
-
],
|
|
640
|
-
scripts: {
|
|
641
|
-
build: "tsup",
|
|
642
|
-
dev: "tsup --watch",
|
|
643
|
-
clean: "rm -rf dist",
|
|
644
|
-
test: "cd tests && yarn test"
|
|
645
|
-
},
|
|
646
|
-
peerDependencies: {
|
|
647
|
-
"@opencode-ai/plugin": ">=1.2.0",
|
|
648
|
-
"@opencode-ai/sdk": ">=1.2.0"
|
|
649
|
-
},
|
|
650
|
-
peerDependenciesMeta: {
|
|
651
|
-
"@opencode-ai/sdk": {
|
|
652
|
-
optional: true
|
|
653
|
-
}
|
|
654
|
-
},
|
|
655
|
-
devDependencies: {
|
|
656
|
-
"@raindrop-ai/core": "*",
|
|
657
|
-
"@opencode-ai/plugin": "^1.2.0",
|
|
658
|
-
"@opencode-ai/sdk": "^1.2.0",
|
|
659
|
-
"@types/node": "^20.11.17",
|
|
660
|
-
tsup: "^8.4.0",
|
|
661
|
-
typescript: "^5.3.3"
|
|
662
|
-
},
|
|
663
|
-
tsup: {
|
|
664
|
-
entry: [
|
|
665
|
-
"src/index.ts"
|
|
666
|
-
],
|
|
667
|
-
format: [
|
|
668
|
-
"cjs",
|
|
669
|
-
"esm"
|
|
670
|
-
],
|
|
671
|
-
dts: {
|
|
672
|
-
resolve: true
|
|
673
|
-
},
|
|
674
|
-
clean: true,
|
|
675
|
-
noExternal: [
|
|
676
|
-
"@raindrop-ai/core"
|
|
677
|
-
]
|
|
678
|
-
},
|
|
679
|
-
publishConfig: {
|
|
680
|
-
access: "public"
|
|
681
|
-
}
|
|
682
|
-
};
|
|
701
|
+
// ../core/dist/index.node.js
|
|
702
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
703
|
+
globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
|
|
683
704
|
|
|
684
705
|
// src/shipper.ts
|
|
685
706
|
var EventShipper2 = class extends EventShipper {
|
|
@@ -688,8 +709,8 @@ var EventShipper2 = class extends EventShipper {
|
|
|
688
709
|
super({
|
|
689
710
|
...opts,
|
|
690
711
|
sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
|
|
691
|
-
libraryName: (_b = opts.libraryName) != null ? _b :
|
|
692
|
-
libraryVersion: (_c = opts.libraryVersion) != null ? _c :
|
|
712
|
+
libraryName: (_b = opts.libraryName) != null ? _b : PLUGIN_NAME,
|
|
713
|
+
libraryVersion: (_c = opts.libraryVersion) != null ? _c : PLUGIN_VERSION,
|
|
693
714
|
defaultEventName: (_d = opts.defaultEventName) != null ? _d : "opencode_session"
|
|
694
715
|
});
|
|
695
716
|
}
|
|
@@ -701,7 +722,7 @@ var TraceShipper2 = class extends TraceShipper {
|
|
|
701
722
|
...opts,
|
|
702
723
|
sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
|
|
703
724
|
serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.opencode-plugin",
|
|
704
|
-
serviceVersion: (_c = opts.serviceVersion) != null ? _c :
|
|
725
|
+
serviceVersion: (_c = opts.serviceVersion) != null ? _c : PLUGIN_VERSION
|
|
705
726
|
});
|
|
706
727
|
}
|
|
707
728
|
enqueue(span) {
|
|
@@ -801,8 +822,6 @@ var pendingChildSessionsByCallKey = /* @__PURE__ */ new Map();
|
|
|
801
822
|
function createSessionState(sessionId) {
|
|
802
823
|
return {
|
|
803
824
|
sessionId,
|
|
804
|
-
turnNumber: 0,
|
|
805
|
-
toolCount: 0,
|
|
806
825
|
currentInput: "",
|
|
807
826
|
outputParts: /* @__PURE__ */ new Map(),
|
|
808
827
|
reasoningParts: /* @__PURE__ */ new Map(),
|
|
@@ -856,7 +875,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
856
875
|
// event — session lifecycle + streaming parts
|
|
857
876
|
// ------------------------------------------------------------------
|
|
858
877
|
event: async ({ event }) => {
|
|
859
|
-
var _a, _b, _c, _d, _e;
|
|
878
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
860
879
|
try {
|
|
861
880
|
const props = event.properties;
|
|
862
881
|
const info = props["info"];
|
|
@@ -991,6 +1010,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
991
1010
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
992
1011
|
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
993
1012
|
}
|
|
1013
|
+
if (state.currentSystemPrompt) {
|
|
1014
|
+
llmAttrs.push(
|
|
1015
|
+
attrString("gen_ai.prompt.0.role", "system"),
|
|
1016
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
1017
|
+
);
|
|
1018
|
+
}
|
|
994
1019
|
const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
|
|
995
1020
|
const llmSpan = traceShipper.startSpan({
|
|
996
1021
|
name: modelName,
|
|
@@ -1020,6 +1045,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1020
1045
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1021
1046
|
llmAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1022
1047
|
}
|
|
1048
|
+
if (state.currentSystemPrompt) {
|
|
1049
|
+
llmAttrs.push(
|
|
1050
|
+
attrString("gen_ai.prompt.0.role", "system"),
|
|
1051
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
1052
|
+
);
|
|
1053
|
+
}
|
|
1023
1054
|
if (!state.parentTaskSpanIds) {
|
|
1024
1055
|
traceShipper.endSpan(rootSpan, {
|
|
1025
1056
|
error: "Missing strict parent task for child session"
|
|
@@ -1060,6 +1091,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1060
1091
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1061
1092
|
rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1062
1093
|
}
|
|
1094
|
+
if (state.currentSystemPrompt) {
|
|
1095
|
+
rootAttrs.push(
|
|
1096
|
+
attrString("gen_ai.prompt.0.role", "system"),
|
|
1097
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
1098
|
+
);
|
|
1099
|
+
}
|
|
1063
1100
|
traceShipper.endSpan(rootSpan, {
|
|
1064
1101
|
attributes: rootAttrs,
|
|
1065
1102
|
error: errorForSpan
|
|
@@ -1074,12 +1111,11 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1074
1111
|
}
|
|
1075
1112
|
if (!state.parentId) {
|
|
1076
1113
|
await eventShipper.finish(state.currentEventId, {
|
|
1077
|
-
userId: state.sessionId,
|
|
1114
|
+
userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
|
|
1078
1115
|
model: modelName,
|
|
1079
1116
|
output: outputText,
|
|
1080
1117
|
properties: {
|
|
1081
|
-
|
|
1082
|
-
tool_count: state.toolCount
|
|
1118
|
+
plugin_version: PLUGIN_VERSION
|
|
1083
1119
|
}
|
|
1084
1120
|
});
|
|
1085
1121
|
}
|
|
@@ -1117,7 +1153,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1117
1153
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
1118
1154
|
sessions.delete(String(sessionID));
|
|
1119
1155
|
} else if (event.type === "session.error") {
|
|
1120
|
-
const errorSessionID = (
|
|
1156
|
+
const errorSessionID = (_e = props["sessionID"]) != null ? _e : sessionID;
|
|
1121
1157
|
if (errorSessionID === void 0 || errorSessionID === "")
|
|
1122
1158
|
throw new Error("session.error: missing sessionID");
|
|
1123
1159
|
const state = sessions.get(String(errorSessionID));
|
|
@@ -1125,7 +1161,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1125
1161
|
const errorObj = props["error"];
|
|
1126
1162
|
if (errorObj == null) throw new Error("session.error: missing error object");
|
|
1127
1163
|
const errorName = errorObj.name;
|
|
1128
|
-
const errorMessage = (
|
|
1164
|
+
const errorMessage = (_g = (_f = errorObj.data) == null ? void 0 : _f.message) != null ? _g : errorObj.name;
|
|
1129
1165
|
if (errorName == null && errorMessage == null)
|
|
1130
1166
|
throw new Error("session.error: error object must have name or data.message");
|
|
1131
1167
|
const errorStr = `${errorMessage != null ? errorMessage : errorName}
|
|
@@ -1152,6 +1188,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1152
1188
|
// chat.message — user sent a message; start a new turn with a fresh event ID
|
|
1153
1189
|
// ------------------------------------------------------------------
|
|
1154
1190
|
"chat.message": async (messageInput, output) => {
|
|
1191
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1155
1192
|
try {
|
|
1156
1193
|
const { sessionID } = messageInput;
|
|
1157
1194
|
let state = sessions.get(sessionID);
|
|
@@ -1164,15 +1201,24 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1164
1201
|
traceShipper.endSpan(state.currentRootSpan);
|
|
1165
1202
|
state.currentRootSpan = void 0;
|
|
1166
1203
|
}
|
|
1167
|
-
state.turnNumber++;
|
|
1168
1204
|
if (output == null) throw new Error("chat.message: output is required");
|
|
1169
1205
|
const parts = output.parts;
|
|
1170
1206
|
if (parts == null) throw new Error("chat.message: output.parts is required");
|
|
1171
1207
|
const textParts = [];
|
|
1172
1208
|
const newAttachments = [];
|
|
1209
|
+
const baseMeta = { ...config.eventMetadata };
|
|
1210
|
+
const promptMeta = {};
|
|
1173
1211
|
for (const part of parts) {
|
|
1174
1212
|
if (part["type"] === "text" && typeof part["text"] === "string") {
|
|
1175
1213
|
textParts.push(part["text"]);
|
|
1214
|
+
const meta = part["metadata"];
|
|
1215
|
+
if (meta != null && typeof meta === "object") {
|
|
1216
|
+
const m = meta;
|
|
1217
|
+
if (typeof m["userId"] === "string") promptMeta.userId = m["userId"];
|
|
1218
|
+
if (typeof m["eventName"] === "string") promptMeta.eventName = m["eventName"];
|
|
1219
|
+
if (m["properties"] != null && typeof m["properties"] === "object")
|
|
1220
|
+
promptMeta.properties = m["properties"];
|
|
1221
|
+
}
|
|
1176
1222
|
} else if (part["type"] === "file") {
|
|
1177
1223
|
const mimeType = part["mediaType"];
|
|
1178
1224
|
const filename = part["filename"];
|
|
@@ -1184,6 +1230,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1184
1230
|
}
|
|
1185
1231
|
}
|
|
1186
1232
|
}
|
|
1233
|
+
state.eventMetadata = {
|
|
1234
|
+
...baseMeta,
|
|
1235
|
+
...promptMeta,
|
|
1236
|
+
properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
|
|
1237
|
+
};
|
|
1187
1238
|
const userText = textParts.join("\n");
|
|
1188
1239
|
state.currentInput = userText;
|
|
1189
1240
|
if (state.parentId) {
|
|
@@ -1219,9 +1270,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1219
1270
|
});
|
|
1220
1271
|
await eventShipper.patch(state.currentEventId, {
|
|
1221
1272
|
isPending: true,
|
|
1222
|
-
userId: state.sessionId,
|
|
1273
|
+
userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
|
|
1223
1274
|
convoId: state.sessionId,
|
|
1224
|
-
eventName: config.eventName,
|
|
1275
|
+
eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
|
|
1225
1276
|
input: userText,
|
|
1226
1277
|
...newAttachments.length > 0 ? { attachments: newAttachments } : {},
|
|
1227
1278
|
properties: {
|
|
@@ -1229,8 +1280,8 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1229
1280
|
directory,
|
|
1230
1281
|
hostname,
|
|
1231
1282
|
os,
|
|
1232
|
-
|
|
1233
|
-
|
|
1283
|
+
plugin_version: PLUGIN_VERSION,
|
|
1284
|
+
...(_g = state.eventMetadata) == null ? void 0 : _g.properties
|
|
1234
1285
|
}
|
|
1235
1286
|
});
|
|
1236
1287
|
} catch (err) {
|
|
@@ -1241,7 +1292,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1241
1292
|
// For child sessions, tool spans are parented directly to the parent task span.
|
|
1242
1293
|
// ------------------------------------------------------------------
|
|
1243
1294
|
"tool.execute.before": async (toolInput, _output) => {
|
|
1244
|
-
var _a;
|
|
1295
|
+
var _a, _b, _c;
|
|
1245
1296
|
try {
|
|
1246
1297
|
const { tool, sessionID, callID } = toolInput;
|
|
1247
1298
|
const state = sessions.get(sessionID);
|
|
@@ -1265,7 +1316,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1265
1316
|
ids: liveTaskSpan.ids,
|
|
1266
1317
|
eventContext: {
|
|
1267
1318
|
eventId: state.currentEventId,
|
|
1268
|
-
userId: state.sessionId,
|
|
1319
|
+
userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
|
|
1269
1320
|
convoId: state.sessionId
|
|
1270
1321
|
}
|
|
1271
1322
|
};
|
|
@@ -1306,7 +1357,6 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1306
1357
|
const { tool, sessionID, callID, args } = toolInput;
|
|
1307
1358
|
const state = sessions.get(sessionID);
|
|
1308
1359
|
if (!state || !state.currentEventId) return;
|
|
1309
|
-
state.toolCount++;
|
|
1310
1360
|
if (args === void 0 || args === null)
|
|
1311
1361
|
throw new Error("tool.execute.after: args is required");
|
|
1312
1362
|
const toolCallArgs = typeof args === "string" ? args : JSON.stringify(args);
|
|
@@ -1360,17 +1410,34 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1360
1410
|
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
1361
1411
|
}
|
|
1362
1412
|
}
|
|
1363
|
-
if (!state.parentId) {
|
|
1364
|
-
await eventShipper.patch(state.currentEventId, {
|
|
1365
|
-
userId: state.sessionId,
|
|
1366
|
-
properties: { tool_count: state.toolCount }
|
|
1367
|
-
});
|
|
1368
|
-
}
|
|
1369
1413
|
} catch (err) {
|
|
1370
1414
|
console.log(
|
|
1371
1415
|
`[raindrop-ai/opencode-plugin] [error] Error in tool.execute.after hook: ${err instanceof Error ? err.message : String(err)}`
|
|
1372
1416
|
);
|
|
1373
1417
|
}
|
|
1418
|
+
},
|
|
1419
|
+
// ------------------------------------------------------------------
|
|
1420
|
+
// experimental.chat.system.transform — capture system prompt (read-only)
|
|
1421
|
+
// ------------------------------------------------------------------
|
|
1422
|
+
"experimental.chat.system.transform": async (input, output) => {
|
|
1423
|
+
try {
|
|
1424
|
+
if (!config.captureSystemPrompt) return;
|
|
1425
|
+
const sessionID = input.sessionID;
|
|
1426
|
+
if (!sessionID) return;
|
|
1427
|
+
let state = sessions.get(sessionID);
|
|
1428
|
+
if (!state) {
|
|
1429
|
+
state = createSessionState(sessionID);
|
|
1430
|
+
sessions.set(sessionID, state);
|
|
1431
|
+
}
|
|
1432
|
+
const MAX_SYSTEM_PROMPT_LENGTH = 32768;
|
|
1433
|
+
const TRUNCATION_MARKER = "\n...[truncated]";
|
|
1434
|
+
const joined = output.system.join("\n\n");
|
|
1435
|
+
state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER.length) + TRUNCATION_MARKER : joined;
|
|
1436
|
+
} catch (err) {
|
|
1437
|
+
console.log(
|
|
1438
|
+
`[raindrop-ai/opencode-plugin] [error] Error in experimental.chat.system.transform hook: ${err instanceof Error ? err.message : String(err)}`
|
|
1439
|
+
);
|
|
1440
|
+
}
|
|
1374
1441
|
}
|
|
1375
1442
|
};
|
|
1376
1443
|
}
|
|
@@ -1382,6 +1449,7 @@ async function plugin(input) {
|
|
|
1382
1449
|
function appLog(level, message) {
|
|
1383
1450
|
console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
|
|
1384
1451
|
}
|
|
1452
|
+
appLog("info", `Loading ${PLUGIN_NAME} v${PLUGIN_VERSION}`);
|
|
1385
1453
|
if (!config.writeKey) {
|
|
1386
1454
|
appLog(
|
|
1387
1455
|
"warn",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raindrop-ai/opencode-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Raindrop observability plugin for OpenCode — automatic session/event/span tracing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"build": "tsup",
|
|
22
22
|
"dev": "tsup --watch",
|
|
23
23
|
"clean": "rm -rf dist",
|
|
24
|
-
"test": "cd tests &&
|
|
24
|
+
"test": "cd tests && pnpm test"
|
|
25
25
|
},
|
|
26
26
|
"peerDependencies": {
|
|
27
|
-
"@opencode-ai/plugin": ">=1.
|
|
28
|
-
"@opencode-ai/sdk": ">=1.
|
|
27
|
+
"@opencode-ai/plugin": ">=1.3.0",
|
|
28
|
+
"@opencode-ai/sdk": ">=1.3.0"
|
|
29
29
|
},
|
|
30
30
|
"peerDependenciesMeta": {
|
|
31
31
|
"@opencode-ai/sdk": {
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@raindrop-ai/core": "
|
|
37
|
-
"@opencode-ai/plugin": "^1.
|
|
38
|
-
"@opencode-ai/sdk": "^1.
|
|
36
|
+
"@raindrop-ai/core": "workspace:*",
|
|
37
|
+
"@opencode-ai/plugin": "^1.3.3",
|
|
38
|
+
"@opencode-ai/sdk": "^1.3.3",
|
|
39
39
|
"@types/node": "^20.11.17",
|
|
40
40
|
"tsup": "^8.4.0",
|
|
41
41
|
"typescript": "^5.3.3"
|