@raindrop-ai/opencode-plugin 0.0.7 → 0.0.8
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 +99 -8
- package/dist/index.js +99 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -66,7 +66,7 @@ function loadConfig(projectDirectory) {
|
|
|
66
66
|
// package.json
|
|
67
67
|
var package_default = {
|
|
68
68
|
name: "@raindrop-ai/opencode-plugin",
|
|
69
|
-
version: "0.0.
|
|
69
|
+
version: "0.0.8",
|
|
70
70
|
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
71
71
|
type: "module",
|
|
72
72
|
main: "dist/index.cjs",
|
|
@@ -131,7 +131,7 @@ var package_default = {
|
|
|
131
131
|
var PLUGIN_NAME = package_default.name;
|
|
132
132
|
var PLUGIN_VERSION = package_default.version;
|
|
133
133
|
|
|
134
|
-
// ../core/dist/chunk-
|
|
134
|
+
// ../core/dist/chunk-4UCYIEH4.js
|
|
135
135
|
function getCrypto() {
|
|
136
136
|
const c = globalThis.crypto;
|
|
137
137
|
return c;
|
|
@@ -570,11 +570,28 @@ var EventShipper = class {
|
|
|
570
570
|
}
|
|
571
571
|
}
|
|
572
572
|
};
|
|
573
|
+
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
574
|
+
function resolveLocalDebuggerBaseUrl(baseUrl) {
|
|
575
|
+
var _a, _b, _c;
|
|
576
|
+
const resolved = (_b = baseUrl != null ? baseUrl : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[LOCAL_DEBUGGER_ENV_VAR] : void 0) != null ? _b : null;
|
|
577
|
+
return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
|
|
578
|
+
}
|
|
579
|
+
function mirrorTraceExportToLocalDebugger(body, options = {}) {
|
|
580
|
+
var _a;
|
|
581
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
582
|
+
if (!baseUrl) return;
|
|
583
|
+
void postJson(`${baseUrl}traces`, body, {}, {
|
|
584
|
+
maxAttempts: 1,
|
|
585
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
586
|
+
sdkName: options.sdkName
|
|
587
|
+
}).catch(() => {
|
|
588
|
+
});
|
|
589
|
+
}
|
|
573
590
|
var TraceShipper = class {
|
|
574
591
|
constructor(opts) {
|
|
575
592
|
this.queue = [];
|
|
576
593
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
577
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
594
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
578
595
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
579
596
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
580
597
|
this.enabled = opts.enabled !== false;
|
|
@@ -587,6 +604,13 @@ var TraceShipper = class {
|
|
|
587
604
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
588
605
|
this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
|
|
589
606
|
this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
|
|
607
|
+
const localDebugger = typeof process !== "undefined" ? (_i = process.env) == null ? void 0 : _i.RAINDROP_LOCAL_DEBUGGER : void 0;
|
|
608
|
+
if (localDebugger) {
|
|
609
|
+
this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(localDebugger)) != null ? _j : void 0;
|
|
610
|
+
if (this.debug) {
|
|
611
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
590
614
|
}
|
|
591
615
|
isDebugEnabled() {
|
|
592
616
|
return this.debug;
|
|
@@ -603,7 +627,25 @@ var TraceShipper = class {
|
|
|
603
627
|
attrString("ai.operationId", args.operationId)
|
|
604
628
|
];
|
|
605
629
|
if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
|
|
606
|
-
|
|
630
|
+
const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
|
|
631
|
+
if (this.localDebuggerUrl) {
|
|
632
|
+
const openSpan = buildOtlpSpan({
|
|
633
|
+
ids: span.ids,
|
|
634
|
+
name: span.name,
|
|
635
|
+
startTimeUnixNano: span.startTimeUnixNano,
|
|
636
|
+
endTimeUnixNano: span.startTimeUnixNano,
|
|
637
|
+
// placeholder — will be updated on endSpan
|
|
638
|
+
attributes: span.attributes,
|
|
639
|
+
status: { code: SpanStatusCode.UNSET }
|
|
640
|
+
});
|
|
641
|
+
const body = buildExportTraceServiceRequest([openSpan], this.serviceName, this.serviceVersion);
|
|
642
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
643
|
+
baseUrl: this.localDebuggerUrl,
|
|
644
|
+
debug: false,
|
|
645
|
+
sdkName: this.sdkName
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
return span;
|
|
607
649
|
}
|
|
608
650
|
endSpan(span, extra) {
|
|
609
651
|
var _a, _b;
|
|
@@ -626,6 +668,14 @@ var TraceShipper = class {
|
|
|
626
668
|
status
|
|
627
669
|
});
|
|
628
670
|
this.enqueue(otlp);
|
|
671
|
+
if (this.localDebuggerUrl) {
|
|
672
|
+
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
673
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
674
|
+
baseUrl: this.localDebuggerUrl,
|
|
675
|
+
debug: false,
|
|
676
|
+
sdkName: this.sdkName
|
|
677
|
+
});
|
|
678
|
+
}
|
|
629
679
|
}
|
|
630
680
|
createSpan(args) {
|
|
631
681
|
var _a;
|
|
@@ -643,6 +693,14 @@ var TraceShipper = class {
|
|
|
643
693
|
status: args.status
|
|
644
694
|
});
|
|
645
695
|
this.enqueue(otlp);
|
|
696
|
+
if (this.localDebuggerUrl) {
|
|
697
|
+
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
698
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
699
|
+
baseUrl: this.localDebuggerUrl,
|
|
700
|
+
debug: false,
|
|
701
|
+
sdkName: this.sdkName
|
|
702
|
+
});
|
|
703
|
+
}
|
|
646
704
|
}
|
|
647
705
|
enqueue(span) {
|
|
648
706
|
if (!this.enabled) return;
|
|
@@ -899,7 +957,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
899
957
|
const props = event.properties;
|
|
900
958
|
const info = props["info"];
|
|
901
959
|
const sessionID = (_b = (_a = props["sessionID"]) != null ? _a : info == null ? void 0 : info["id"]) != null ? _b : props["id"];
|
|
902
|
-
const sessionEventTypes = ["session.created", "session.idle", "session.deleted", "session.error"];
|
|
960
|
+
const sessionEventTypes = ["session.created", "session.compacted", "session.idle", "session.deleted", "session.error"];
|
|
903
961
|
if (sessionEventTypes.includes(event.type) && (sessionID === void 0 || sessionID === "")) {
|
|
904
962
|
throw new Error(`event ${event.type}: missing sessionID in properties`);
|
|
905
963
|
}
|
|
@@ -914,6 +972,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
914
972
|
}
|
|
915
973
|
state.parentId = parentID;
|
|
916
974
|
if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
|
|
975
|
+
} else if (event.type === "session.compacted") {
|
|
976
|
+
const state = sessions.get(String(sessionID));
|
|
977
|
+
if (!state) return;
|
|
978
|
+
state.isCompacting = true;
|
|
917
979
|
} else if (event.type === "message.part.updated") {
|
|
918
980
|
const part = props["part"];
|
|
919
981
|
if (part == null || typeof part !== "object")
|
|
@@ -1023,6 +1085,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1023
1085
|
attrString("ai.response.text", reasoningText),
|
|
1024
1086
|
attrString("gen_ai.system", providerID),
|
|
1025
1087
|
attrString("gen_ai.request.model", modelID),
|
|
1088
|
+
attrString("gen_ai.response.model", modelID),
|
|
1026
1089
|
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1027
1090
|
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
1028
1091
|
];
|
|
@@ -1051,6 +1114,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1051
1114
|
}
|
|
1052
1115
|
if (outputText === void 0) return;
|
|
1053
1116
|
const rootSpan = state.currentRootSpan;
|
|
1117
|
+
const isCompaction = state.isCompacting === true;
|
|
1054
1118
|
if (state.parentId) {
|
|
1055
1119
|
const llmAttrs = [
|
|
1056
1120
|
attrString("ai.operationId", "generateText"),
|
|
@@ -1058,6 +1122,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1058
1122
|
attrString("ai.response.text", outputText),
|
|
1059
1123
|
attrString("gen_ai.system", providerID),
|
|
1060
1124
|
attrString("gen_ai.request.model", modelID),
|
|
1125
|
+
attrString("gen_ai.response.model", modelID),
|
|
1061
1126
|
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1062
1127
|
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
1063
1128
|
];
|
|
@@ -1097,16 +1162,20 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1097
1162
|
error: errorForSpan
|
|
1098
1163
|
});
|
|
1099
1164
|
} else {
|
|
1100
|
-
rootSpan.name = modelName;
|
|
1165
|
+
rootSpan.name = isCompaction ? "ai.compaction" : modelName;
|
|
1101
1166
|
const rootAttrs = [
|
|
1102
1167
|
attrString("ai.operationId", "generateText"),
|
|
1103
1168
|
attrString("ai.prompt", state.currentInput),
|
|
1104
1169
|
attrString("ai.response.text", outputText),
|
|
1105
1170
|
attrString("gen_ai.system", providerID),
|
|
1106
1171
|
attrString("gen_ai.request.model", modelID),
|
|
1172
|
+
attrString("gen_ai.response.model", modelID),
|
|
1107
1173
|
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1108
1174
|
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
1109
1175
|
];
|
|
1176
|
+
if (isCompaction) {
|
|
1177
|
+
rootAttrs.push(attrString("is_compaction", "true"));
|
|
1178
|
+
}
|
|
1110
1179
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1111
1180
|
rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1112
1181
|
}
|
|
@@ -1120,6 +1189,9 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1120
1189
|
attributes: rootAttrs,
|
|
1121
1190
|
error: errorForSpan
|
|
1122
1191
|
});
|
|
1192
|
+
if (isCompaction) {
|
|
1193
|
+
state.isCompacting = false;
|
|
1194
|
+
}
|
|
1123
1195
|
}
|
|
1124
1196
|
state.currentRootSpan = void 0;
|
|
1125
1197
|
const hasAssistantResponse = outputText.trim().length > 0;
|
|
@@ -1134,7 +1206,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1134
1206
|
model: modelName,
|
|
1135
1207
|
output: outputText,
|
|
1136
1208
|
properties: {
|
|
1137
|
-
plugin_version: PLUGIN_VERSION
|
|
1209
|
+
plugin_version: PLUGIN_VERSION,
|
|
1210
|
+
...isCompaction ? { is_compaction: true } : {}
|
|
1138
1211
|
}
|
|
1139
1212
|
});
|
|
1140
1213
|
}
|
|
@@ -1151,6 +1224,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1151
1224
|
if (state.currentEventId) {
|
|
1152
1225
|
state.currentEventId = void 0;
|
|
1153
1226
|
}
|
|
1227
|
+
state.isCompacting = false;
|
|
1154
1228
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
1155
1229
|
if (state.parentId) {
|
|
1156
1230
|
cleanupSessionParentMap(String(sessionID));
|
|
@@ -1278,7 +1352,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1278
1352
|
}
|
|
1279
1353
|
state.currentEventId = generateId();
|
|
1280
1354
|
state.currentRootSpan = traceShipper.startSpan({
|
|
1281
|
-
name: "ai.event",
|
|
1355
|
+
name: state.isCompacting ? "ai.compaction" : "ai.event",
|
|
1282
1356
|
eventId: state.currentEventId,
|
|
1283
1357
|
attributes: [
|
|
1284
1358
|
attrString("workspace", worktree),
|
|
@@ -1436,6 +1510,23 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1436
1510
|
}
|
|
1437
1511
|
},
|
|
1438
1512
|
// ------------------------------------------------------------------
|
|
1513
|
+
// experimental.session.compacting — fires before compaction LLM call
|
|
1514
|
+
// ------------------------------------------------------------------
|
|
1515
|
+
"experimental.session.compacting": async (input, _output) => {
|
|
1516
|
+
try {
|
|
1517
|
+
const sessionID = input.sessionID;
|
|
1518
|
+
if (!sessionID) return;
|
|
1519
|
+
const state = sessions.get(sessionID);
|
|
1520
|
+
if (state) {
|
|
1521
|
+
state.isCompacting = true;
|
|
1522
|
+
}
|
|
1523
|
+
} catch (err) {
|
|
1524
|
+
console.log(
|
|
1525
|
+
`[raindrop-ai/opencode-plugin] [error] Error in experimental.session.compacting hook: ${err instanceof Error ? err.message : String(err)}`
|
|
1526
|
+
);
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
// ------------------------------------------------------------------
|
|
1439
1530
|
// experimental.chat.system.transform — capture system prompt (read-only)
|
|
1440
1531
|
// ------------------------------------------------------------------
|
|
1441
1532
|
"experimental.chat.system.transform": async (input, output) => {
|
package/dist/index.js
CHANGED
|
@@ -47,7 +47,7 @@ function loadConfig(projectDirectory) {
|
|
|
47
47
|
// package.json
|
|
48
48
|
var package_default = {
|
|
49
49
|
name: "@raindrop-ai/opencode-plugin",
|
|
50
|
-
version: "0.0.
|
|
50
|
+
version: "0.0.8",
|
|
51
51
|
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
52
52
|
type: "module",
|
|
53
53
|
main: "dist/index.cjs",
|
|
@@ -112,7 +112,7 @@ var package_default = {
|
|
|
112
112
|
var PLUGIN_NAME = package_default.name;
|
|
113
113
|
var PLUGIN_VERSION = package_default.version;
|
|
114
114
|
|
|
115
|
-
// ../core/dist/chunk-
|
|
115
|
+
// ../core/dist/chunk-4UCYIEH4.js
|
|
116
116
|
function getCrypto() {
|
|
117
117
|
const c = globalThis.crypto;
|
|
118
118
|
return c;
|
|
@@ -551,11 +551,28 @@ var EventShipper = class {
|
|
|
551
551
|
}
|
|
552
552
|
}
|
|
553
553
|
};
|
|
554
|
+
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
555
|
+
function resolveLocalDebuggerBaseUrl(baseUrl) {
|
|
556
|
+
var _a, _b, _c;
|
|
557
|
+
const resolved = (_b = baseUrl != null ? baseUrl : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[LOCAL_DEBUGGER_ENV_VAR] : void 0) != null ? _b : null;
|
|
558
|
+
return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
|
|
559
|
+
}
|
|
560
|
+
function mirrorTraceExportToLocalDebugger(body, options = {}) {
|
|
561
|
+
var _a;
|
|
562
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
563
|
+
if (!baseUrl) return;
|
|
564
|
+
void postJson(`${baseUrl}traces`, body, {}, {
|
|
565
|
+
maxAttempts: 1,
|
|
566
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
567
|
+
sdkName: options.sdkName
|
|
568
|
+
}).catch(() => {
|
|
569
|
+
});
|
|
570
|
+
}
|
|
554
571
|
var TraceShipper = class {
|
|
555
572
|
constructor(opts) {
|
|
556
573
|
this.queue = [];
|
|
557
574
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
558
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
575
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
559
576
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
560
577
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
561
578
|
this.enabled = opts.enabled !== false;
|
|
@@ -568,6 +585,13 @@ var TraceShipper = class {
|
|
|
568
585
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
569
586
|
this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
|
|
570
587
|
this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
|
|
588
|
+
const localDebugger = typeof process !== "undefined" ? (_i = process.env) == null ? void 0 : _i.RAINDROP_LOCAL_DEBUGGER : void 0;
|
|
589
|
+
if (localDebugger) {
|
|
590
|
+
this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(localDebugger)) != null ? _j : void 0;
|
|
591
|
+
if (this.debug) {
|
|
592
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
571
595
|
}
|
|
572
596
|
isDebugEnabled() {
|
|
573
597
|
return this.debug;
|
|
@@ -584,7 +608,25 @@ var TraceShipper = class {
|
|
|
584
608
|
attrString("ai.operationId", args.operationId)
|
|
585
609
|
];
|
|
586
610
|
if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
|
|
587
|
-
|
|
611
|
+
const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
|
|
612
|
+
if (this.localDebuggerUrl) {
|
|
613
|
+
const openSpan = buildOtlpSpan({
|
|
614
|
+
ids: span.ids,
|
|
615
|
+
name: span.name,
|
|
616
|
+
startTimeUnixNano: span.startTimeUnixNano,
|
|
617
|
+
endTimeUnixNano: span.startTimeUnixNano,
|
|
618
|
+
// placeholder — will be updated on endSpan
|
|
619
|
+
attributes: span.attributes,
|
|
620
|
+
status: { code: SpanStatusCode.UNSET }
|
|
621
|
+
});
|
|
622
|
+
const body = buildExportTraceServiceRequest([openSpan], this.serviceName, this.serviceVersion);
|
|
623
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
624
|
+
baseUrl: this.localDebuggerUrl,
|
|
625
|
+
debug: false,
|
|
626
|
+
sdkName: this.sdkName
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
return span;
|
|
588
630
|
}
|
|
589
631
|
endSpan(span, extra) {
|
|
590
632
|
var _a, _b;
|
|
@@ -607,6 +649,14 @@ var TraceShipper = class {
|
|
|
607
649
|
status
|
|
608
650
|
});
|
|
609
651
|
this.enqueue(otlp);
|
|
652
|
+
if (this.localDebuggerUrl) {
|
|
653
|
+
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
654
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
655
|
+
baseUrl: this.localDebuggerUrl,
|
|
656
|
+
debug: false,
|
|
657
|
+
sdkName: this.sdkName
|
|
658
|
+
});
|
|
659
|
+
}
|
|
610
660
|
}
|
|
611
661
|
createSpan(args) {
|
|
612
662
|
var _a;
|
|
@@ -624,6 +674,14 @@ var TraceShipper = class {
|
|
|
624
674
|
status: args.status
|
|
625
675
|
});
|
|
626
676
|
this.enqueue(otlp);
|
|
677
|
+
if (this.localDebuggerUrl) {
|
|
678
|
+
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
679
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
680
|
+
baseUrl: this.localDebuggerUrl,
|
|
681
|
+
debug: false,
|
|
682
|
+
sdkName: this.sdkName
|
|
683
|
+
});
|
|
684
|
+
}
|
|
627
685
|
}
|
|
628
686
|
enqueue(span) {
|
|
629
687
|
if (!this.enabled) return;
|
|
@@ -880,7 +938,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
880
938
|
const props = event.properties;
|
|
881
939
|
const info = props["info"];
|
|
882
940
|
const sessionID = (_b = (_a = props["sessionID"]) != null ? _a : info == null ? void 0 : info["id"]) != null ? _b : props["id"];
|
|
883
|
-
const sessionEventTypes = ["session.created", "session.idle", "session.deleted", "session.error"];
|
|
941
|
+
const sessionEventTypes = ["session.created", "session.compacted", "session.idle", "session.deleted", "session.error"];
|
|
884
942
|
if (sessionEventTypes.includes(event.type) && (sessionID === void 0 || sessionID === "")) {
|
|
885
943
|
throw new Error(`event ${event.type}: missing sessionID in properties`);
|
|
886
944
|
}
|
|
@@ -895,6 +953,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
895
953
|
}
|
|
896
954
|
state.parentId = parentID;
|
|
897
955
|
if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
|
|
956
|
+
} else if (event.type === "session.compacted") {
|
|
957
|
+
const state = sessions.get(String(sessionID));
|
|
958
|
+
if (!state) return;
|
|
959
|
+
state.isCompacting = true;
|
|
898
960
|
} else if (event.type === "message.part.updated") {
|
|
899
961
|
const part = props["part"];
|
|
900
962
|
if (part == null || typeof part !== "object")
|
|
@@ -1004,6 +1066,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1004
1066
|
attrString("ai.response.text", reasoningText),
|
|
1005
1067
|
attrString("gen_ai.system", providerID),
|
|
1006
1068
|
attrString("gen_ai.request.model", modelID),
|
|
1069
|
+
attrString("gen_ai.response.model", modelID),
|
|
1007
1070
|
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1008
1071
|
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
1009
1072
|
];
|
|
@@ -1032,6 +1095,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1032
1095
|
}
|
|
1033
1096
|
if (outputText === void 0) return;
|
|
1034
1097
|
const rootSpan = state.currentRootSpan;
|
|
1098
|
+
const isCompaction = state.isCompacting === true;
|
|
1035
1099
|
if (state.parentId) {
|
|
1036
1100
|
const llmAttrs = [
|
|
1037
1101
|
attrString("ai.operationId", "generateText"),
|
|
@@ -1039,6 +1103,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1039
1103
|
attrString("ai.response.text", outputText),
|
|
1040
1104
|
attrString("gen_ai.system", providerID),
|
|
1041
1105
|
attrString("gen_ai.request.model", modelID),
|
|
1106
|
+
attrString("gen_ai.response.model", modelID),
|
|
1042
1107
|
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1043
1108
|
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
1044
1109
|
];
|
|
@@ -1078,16 +1143,20 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1078
1143
|
error: errorForSpan
|
|
1079
1144
|
});
|
|
1080
1145
|
} else {
|
|
1081
|
-
rootSpan.name = modelName;
|
|
1146
|
+
rootSpan.name = isCompaction ? "ai.compaction" : modelName;
|
|
1082
1147
|
const rootAttrs = [
|
|
1083
1148
|
attrString("ai.operationId", "generateText"),
|
|
1084
1149
|
attrString("ai.prompt", state.currentInput),
|
|
1085
1150
|
attrString("ai.response.text", outputText),
|
|
1086
1151
|
attrString("gen_ai.system", providerID),
|
|
1087
1152
|
attrString("gen_ai.request.model", modelID),
|
|
1153
|
+
attrString("gen_ai.response.model", modelID),
|
|
1088
1154
|
attrInt("gen_ai.usage.input_tokens", inputTokens),
|
|
1089
1155
|
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
1090
1156
|
];
|
|
1157
|
+
if (isCompaction) {
|
|
1158
|
+
rootAttrs.push(attrString("is_compaction", "true"));
|
|
1159
|
+
}
|
|
1091
1160
|
if (reasoningTokens != null && typeof reasoningTokens === "number" && reasoningTokens > 0) {
|
|
1092
1161
|
rootAttrs.push(attrInt("gen_ai.usage.reasoning_tokens", reasoningTokens));
|
|
1093
1162
|
}
|
|
@@ -1101,6 +1170,9 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1101
1170
|
attributes: rootAttrs,
|
|
1102
1171
|
error: errorForSpan
|
|
1103
1172
|
});
|
|
1173
|
+
if (isCompaction) {
|
|
1174
|
+
state.isCompacting = false;
|
|
1175
|
+
}
|
|
1104
1176
|
}
|
|
1105
1177
|
state.currentRootSpan = void 0;
|
|
1106
1178
|
const hasAssistantResponse = outputText.trim().length > 0;
|
|
@@ -1115,7 +1187,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1115
1187
|
model: modelName,
|
|
1116
1188
|
output: outputText,
|
|
1117
1189
|
properties: {
|
|
1118
|
-
plugin_version: PLUGIN_VERSION
|
|
1190
|
+
plugin_version: PLUGIN_VERSION,
|
|
1191
|
+
...isCompaction ? { is_compaction: true } : {}
|
|
1119
1192
|
}
|
|
1120
1193
|
});
|
|
1121
1194
|
}
|
|
@@ -1132,6 +1205,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
1132
1205
|
if (state.currentEventId) {
|
|
1133
1206
|
state.currentEventId = void 0;
|
|
1134
1207
|
}
|
|
1208
|
+
state.isCompacting = false;
|
|
1135
1209
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
1136
1210
|
if (state.parentId) {
|
|
1137
1211
|
cleanupSessionParentMap(String(sessionID));
|
|
@@ -1259,7 +1333,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1259
1333
|
}
|
|
1260
1334
|
state.currentEventId = generateId();
|
|
1261
1335
|
state.currentRootSpan = traceShipper.startSpan({
|
|
1262
|
-
name: "ai.event",
|
|
1336
|
+
name: state.isCompacting ? "ai.compaction" : "ai.event",
|
|
1263
1337
|
eventId: state.currentEventId,
|
|
1264
1338
|
attributes: [
|
|
1265
1339
|
attrString("workspace", worktree),
|
|
@@ -1417,6 +1491,23 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
1417
1491
|
}
|
|
1418
1492
|
},
|
|
1419
1493
|
// ------------------------------------------------------------------
|
|
1494
|
+
// experimental.session.compacting — fires before compaction LLM call
|
|
1495
|
+
// ------------------------------------------------------------------
|
|
1496
|
+
"experimental.session.compacting": async (input, _output) => {
|
|
1497
|
+
try {
|
|
1498
|
+
const sessionID = input.sessionID;
|
|
1499
|
+
if (!sessionID) return;
|
|
1500
|
+
const state = sessions.get(sessionID);
|
|
1501
|
+
if (state) {
|
|
1502
|
+
state.isCompacting = true;
|
|
1503
|
+
}
|
|
1504
|
+
} catch (err) {
|
|
1505
|
+
console.log(
|
|
1506
|
+
`[raindrop-ai/opencode-plugin] [error] Error in experimental.session.compacting hook: ${err instanceof Error ? err.message : String(err)}`
|
|
1507
|
+
);
|
|
1508
|
+
}
|
|
1509
|
+
},
|
|
1510
|
+
// ------------------------------------------------------------------
|
|
1420
1511
|
// experimental.chat.system.transform — capture system prompt (read-only)
|
|
1421
1512
|
// ------------------------------------------------------------------
|
|
1422
1513
|
"experimental.chat.system.transform": async (input, output) => {
|