@raindrop-ai/opencode-plugin 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/dist/{chunk-4DAI6CYK.js → chunk-ZG47FVK7.js} +460 -3
- package/dist/index.cjs +534 -28
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +107 -27
- package/dist/{index.d-vgBcEZbX.d.cts → self-diagnostics-CLW6h4zB.d.cts} +60 -1
- package/dist/{index.d-vgBcEZbX.d.ts → self-diagnostics-CLW6h4zB.d.ts} +60 -1
- package/dist/v2.cjs +527 -14
- package/dist/v2.d.cts +10 -2
- package/dist/v2.d.ts +10 -2
- package/dist/v2.js +81 -13
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
default: () => plugin
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var import_plugin = require("@opencode-ai/plugin");
|
|
26
27
|
|
|
27
28
|
// ../core/dist/chunk-BYBMRLZM.js
|
|
28
29
|
var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
|
|
@@ -86,7 +87,7 @@ function evalScopeAttributes() {
|
|
|
86
87
|
return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
// ../core/dist/chunk-
|
|
90
|
+
// ../core/dist/chunk-I6TVJQEC.js
|
|
90
91
|
var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
|
|
91
92
|
function state() {
|
|
92
93
|
const holder = globalThis;
|
|
@@ -2095,6 +2096,151 @@ var TraceShipper = class {
|
|
|
2095
2096
|
}
|
|
2096
2097
|
}
|
|
2097
2098
|
};
|
|
2099
|
+
var PROMPT_TOOLS_ATTRIBUTE = "ai.prompt.tools";
|
|
2100
|
+
function isRecord(value) {
|
|
2101
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2102
|
+
}
|
|
2103
|
+
var JSON_SCHEMA_KEYS = [
|
|
2104
|
+
"type",
|
|
2105
|
+
"properties",
|
|
2106
|
+
"$schema",
|
|
2107
|
+
"$ref",
|
|
2108
|
+
"anyOf",
|
|
2109
|
+
"oneOf",
|
|
2110
|
+
"allOf",
|
|
2111
|
+
"enum",
|
|
2112
|
+
"const",
|
|
2113
|
+
"items",
|
|
2114
|
+
"additionalProperties",
|
|
2115
|
+
"required"
|
|
2116
|
+
];
|
|
2117
|
+
function isJsonSchema(value) {
|
|
2118
|
+
if (!isRecord(value)) return false;
|
|
2119
|
+
if (typeof value["~standard"] === "object") return false;
|
|
2120
|
+
if (isRecord(value._def) || isRecord(value._zod)) return false;
|
|
2121
|
+
if (Object.keys(value).length === 0) return true;
|
|
2122
|
+
return JSON_SCHEMA_KEYS.some((key) => key in value);
|
|
2123
|
+
}
|
|
2124
|
+
function toJsonSchema(value, options) {
|
|
2125
|
+
if (value === void 0 || value === null) return void 0;
|
|
2126
|
+
if (isJsonSchema(value)) return value;
|
|
2127
|
+
if (isRecord(value) && isJsonSchema(value.jsonSchema)) return value.jsonSchema;
|
|
2128
|
+
if (isRecord(value) && isJsonSchema(value.json)) return value.json;
|
|
2129
|
+
if (options == null ? void 0 : options.schema) {
|
|
2130
|
+
try {
|
|
2131
|
+
return options.schema(value);
|
|
2132
|
+
} catch (e) {
|
|
2133
|
+
return void 0;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
return void 0;
|
|
2137
|
+
}
|
|
2138
|
+
function pickString(value) {
|
|
2139
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
2140
|
+
}
|
|
2141
|
+
function functionTool(name, description, schema, options) {
|
|
2142
|
+
const tool2 = { type: "function", name };
|
|
2143
|
+
const desc = pickString(description);
|
|
2144
|
+
if (desc !== void 0) tool2.description = desc;
|
|
2145
|
+
const inputSchema = toJsonSchema(schema, options);
|
|
2146
|
+
if (inputSchema !== void 0) tool2.inputSchema = inputSchema;
|
|
2147
|
+
return tool2;
|
|
2148
|
+
}
|
|
2149
|
+
function normalizeToolDeclaration(tool2, options, fallbackName) {
|
|
2150
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
|
2151
|
+
if (!isRecord(tool2)) return void 0;
|
|
2152
|
+
if (tool2.type === "provider-defined" || tool2.type === "provider") {
|
|
2153
|
+
const name2 = (_b = (_a = pickString(tool2.name)) != null ? _a : pickString(tool2.id)) != null ? _b : fallbackName;
|
|
2154
|
+
if (name2 === void 0) return void 0;
|
|
2155
|
+
const declaration = { type: "provider-defined", name: name2 };
|
|
2156
|
+
const id = pickString(tool2.id);
|
|
2157
|
+
if (id !== void 0) declaration.id = id;
|
|
2158
|
+
if (isRecord(tool2.args)) declaration.args = tool2.args;
|
|
2159
|
+
return declaration;
|
|
2160
|
+
}
|
|
2161
|
+
if (isRecord(tool2.toolSpec)) {
|
|
2162
|
+
const spec = tool2.toolSpec;
|
|
2163
|
+
const name2 = (_c = pickString(spec.name)) != null ? _c : fallbackName;
|
|
2164
|
+
if (name2 === void 0) return void 0;
|
|
2165
|
+
return functionTool(name2, spec.description, spec.inputSchema, options);
|
|
2166
|
+
}
|
|
2167
|
+
if (isRecord(tool2.function)) {
|
|
2168
|
+
const fn = tool2.function;
|
|
2169
|
+
const name2 = (_d = pickString(fn.name)) != null ? _d : fallbackName;
|
|
2170
|
+
if (name2 === void 0) return void 0;
|
|
2171
|
+
return functionTool(name2, fn.description, (_e = fn.parameters) != null ? _e : fn.input_schema, options);
|
|
2172
|
+
}
|
|
2173
|
+
const name = (_g = (_f = pickString(tool2.name)) != null ? _f : pickString(tool2.id)) != null ? _g : fallbackName;
|
|
2174
|
+
if (name === void 0) return void 0;
|
|
2175
|
+
const type = pickString(tool2.type);
|
|
2176
|
+
if (type !== void 0 && type !== "function" && type !== "dynamic" && type !== "custom") {
|
|
2177
|
+
if (!("input_schema" in tool2) && !("inputSchema" in tool2) && !("parameters" in tool2)) {
|
|
2178
|
+
return { type: "provider-defined", id: type, name };
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return functionTool(
|
|
2182
|
+
name,
|
|
2183
|
+
tool2.description,
|
|
2184
|
+
(_j = (_i = (_h = tool2.inputSchema) != null ? _h : tool2.input_schema) != null ? _i : tool2.parameters) != null ? _j : tool2.schema,
|
|
2185
|
+
options
|
|
2186
|
+
);
|
|
2187
|
+
}
|
|
2188
|
+
var NOT_A_GEMINI_GROUP_KEYS = ["name", "id", "type", "function", "toolSpec", "cachePoint"];
|
|
2189
|
+
function isGeminiToolGroup(tool2) {
|
|
2190
|
+
if (Array.isArray(tool2.functionDeclarations)) return true;
|
|
2191
|
+
const keys = Object.keys(tool2);
|
|
2192
|
+
if (keys.length === 0 || NOT_A_GEMINI_GROUP_KEYS.some((key) => key in tool2)) return false;
|
|
2193
|
+
return keys.every((key) => isRecord(tool2[key]));
|
|
2194
|
+
}
|
|
2195
|
+
function expandGeminiTool(tool2, options) {
|
|
2196
|
+
const declarations = [];
|
|
2197
|
+
for (const [key, value] of Object.entries(tool2)) {
|
|
2198
|
+
if (key === "functionDeclarations" && Array.isArray(value)) {
|
|
2199
|
+
for (const declaration of value) {
|
|
2200
|
+
const normalized = normalizeToolDeclaration(declaration, options);
|
|
2201
|
+
if (normalized) declarations.push(normalized);
|
|
2202
|
+
}
|
|
2203
|
+
} else if (isRecord(value)) {
|
|
2204
|
+
declarations.push({ type: "provider-defined", id: key, name: key, args: value });
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
2207
|
+
return declarations;
|
|
2208
|
+
}
|
|
2209
|
+
function normalizeToolDeclarations(tools, options) {
|
|
2210
|
+
if (tools === void 0 || tools === null) return void 0;
|
|
2211
|
+
if (Array.isArray(tools)) {
|
|
2212
|
+
return tools.flatMap((tool2) => {
|
|
2213
|
+
if (isRecord(tool2) && isGeminiToolGroup(tool2)) {
|
|
2214
|
+
return expandGeminiTool(tool2, options);
|
|
2215
|
+
}
|
|
2216
|
+
const declaration = normalizeToolDeclaration(tool2, options);
|
|
2217
|
+
return declaration ? [declaration] : [];
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
if (!isRecord(tools)) return void 0;
|
|
2221
|
+
return Object.entries(tools).flatMap(([key, tool2]) => {
|
|
2222
|
+
const declaration = normalizeToolDeclaration(tool2, options, key);
|
|
2223
|
+
return declaration ? [declaration] : [];
|
|
2224
|
+
});
|
|
2225
|
+
}
|
|
2226
|
+
function promptToolsAttribute(tools) {
|
|
2227
|
+
const values = promptToolsAttributeValue(tools);
|
|
2228
|
+
if (values === void 0) return void 0;
|
|
2229
|
+
return {
|
|
2230
|
+
key: PROMPT_TOOLS_ATTRIBUTE,
|
|
2231
|
+
value: { arrayValue: { values: values.map((stringValue) => ({ stringValue })) } }
|
|
2232
|
+
};
|
|
2233
|
+
}
|
|
2234
|
+
function promptToolsAttributeValue(tools) {
|
|
2235
|
+
if (tools === void 0) return void 0;
|
|
2236
|
+
return tools.map((tool2) => {
|
|
2237
|
+
try {
|
|
2238
|
+
return JSON.stringify(tool2);
|
|
2239
|
+
} catch (e) {
|
|
2240
|
+
return JSON.stringify({ type: tool2.type, name: tool2.name });
|
|
2241
|
+
}
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2098
2244
|
|
|
2099
2245
|
// ../core/dist/index.node.js
|
|
2100
2246
|
var import_async_hooks = require("async_hooks");
|
|
@@ -2308,8 +2454,41 @@ function loadConfig(projectDirectory) {
|
|
|
2308
2454
|
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_h = merged.capture_system_prompt) != null ? _h : false,
|
|
2309
2455
|
eventMetadata,
|
|
2310
2456
|
localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url),
|
|
2311
|
-
appGit: mapAppGit(merged.app_git)
|
|
2457
|
+
appGit: mapAppGit(merged.app_git),
|
|
2458
|
+
selfDiagnostics: mapSelfDiagnostics(merged.self_diagnostics),
|
|
2459
|
+
tools: Array.isArray(merged.tools) ? merged.tools : void 0
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
function isRecord2(value) {
|
|
2463
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2464
|
+
}
|
|
2465
|
+
function mapSelfDiagnostics(value) {
|
|
2466
|
+
const env = process.env["RAINDROP_SELF_DIAGNOSTICS"];
|
|
2467
|
+
const record = isRecord2(value) ? value : {};
|
|
2468
|
+
const enabled = env !== void 0 ? env === "true" : typeof record["enabled"] === "boolean" ? record["enabled"] : void 0;
|
|
2469
|
+
const signals = mapSelfDiagnosticsSignals(record["signals"]);
|
|
2470
|
+
const options = {
|
|
2471
|
+
...enabled !== void 0 ? { enabled } : {},
|
|
2472
|
+
...signals ? { signals } : {},
|
|
2473
|
+
...typeof record["guidance"] === "string" ? { guidance: record["guidance"] } : {},
|
|
2474
|
+
...typeof record["tool_name"] === "string" ? { toolName: record["tool_name"] } : {}
|
|
2312
2475
|
};
|
|
2476
|
+
return Object.keys(options).length > 0 ? options : void 0;
|
|
2477
|
+
}
|
|
2478
|
+
function mapSelfDiagnosticsSignals(value) {
|
|
2479
|
+
if (!isRecord2(value)) return void 0;
|
|
2480
|
+
const out = {};
|
|
2481
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
2482
|
+
if (!isRecord2(entry)) continue;
|
|
2483
|
+
const definition = entry;
|
|
2484
|
+
if (typeof definition["description"] !== "string") continue;
|
|
2485
|
+
const sentiment = definition["sentiment"];
|
|
2486
|
+
out[key] = {
|
|
2487
|
+
description: definition["description"],
|
|
2488
|
+
...sentiment === "POSITIVE" || sentiment === "NEGATIVE" ? { sentiment } : {}
|
|
2489
|
+
};
|
|
2490
|
+
}
|
|
2491
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
2313
2492
|
}
|
|
2314
2493
|
function mapAppGit(value) {
|
|
2315
2494
|
if (value === false) return false;
|
|
@@ -2337,7 +2516,7 @@ function resolveLocalWorkshopUrl(fileValue) {
|
|
|
2337
2516
|
// package.json
|
|
2338
2517
|
var package_default = {
|
|
2339
2518
|
name: "@raindrop-ai/opencode-plugin",
|
|
2340
|
-
version: "0.
|
|
2519
|
+
version: "0.3.1",
|
|
2341
2520
|
description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
|
|
2342
2521
|
type: "module",
|
|
2343
2522
|
main: "dist/index.js",
|
|
@@ -2426,6 +2605,167 @@ var package_default = {
|
|
|
2426
2605
|
var PLUGIN_NAME = package_default.name;
|
|
2427
2606
|
var PLUGIN_VERSION = package_default.version;
|
|
2428
2607
|
|
|
2608
|
+
// src/self-diagnostics.ts
|
|
2609
|
+
var SELF_DIAGNOSTICS_TOOL_NAME_DEFAULT = "__raindrop_report";
|
|
2610
|
+
var SELF_DIAGNOSTICS_SIGNALS_DEFAULT = {
|
|
2611
|
+
missing_context: {
|
|
2612
|
+
description: "You cannot complete the task because critical information, credentials, or access is missing and the user cannot provide it. Do NOT report this for normal clarifying questions \u2014 only when you are blocked.",
|
|
2613
|
+
sentiment: "NEGATIVE"
|
|
2614
|
+
},
|
|
2615
|
+
repeatedly_broken_tool: {
|
|
2616
|
+
description: "A tool has failed or not returned the expected response on multiple distinct attempts in this conversation, preventing task completion. A single tool error is NOT enough \u2014 the tool must be persistently broken or aberrantly behaving across retries.",
|
|
2617
|
+
sentiment: "NEGATIVE"
|
|
2618
|
+
},
|
|
2619
|
+
capability_gap: {
|
|
2620
|
+
description: "The task requires a tool, permission, or capability that you do not have. For example, the user asks you to perform an action but no suitable tool exists, or you lack the necessary access. Do NOT report this if you simply need more information from the user \u2014 only when the gap is in your own capabilities.",
|
|
2621
|
+
sentiment: "NEGATIVE"
|
|
2622
|
+
},
|
|
2623
|
+
complete_task_failure: {
|
|
2624
|
+
description: "You were unable to accomplish what the user asked despite making genuine attempts. This might be things like, you genuinely do not have the capabilities the user is asking for. You have tried but run into a persistent bug in the environment etc. This is NOT a refusal or policy block \u2014 you tried and failed to deliver the result.",
|
|
2625
|
+
sentiment: "NEGATIVE"
|
|
2626
|
+
}
|
|
2627
|
+
};
|
|
2628
|
+
var SELF_DIAGNOSTICS_TOOL_PREAMBLE = "You have a diagnostic tool for flagging serious failures for developer review. Only call this when you hit a significant, unrecoverable problem \u2014 not for minor hiccups or routine clarifications. If you can still help the user, do that instead of calling this tool. This tool is invisible to the user \u2014 never mention it or its output.";
|
|
2629
|
+
var SELF_DIAGNOSTICS_NOTEWORTHY_SIGNAL_KEY = "noteworthy";
|
|
2630
|
+
function normalizeString(value) {
|
|
2631
|
+
if (typeof value !== "string") return void 0;
|
|
2632
|
+
const trimmed = value.trim();
|
|
2633
|
+
return trimmed || void 0;
|
|
2634
|
+
}
|
|
2635
|
+
function normalizeSelfDiagnosticsSignals(signals) {
|
|
2636
|
+
if (!signals) return SELF_DIAGNOSTICS_SIGNALS_DEFAULT;
|
|
2637
|
+
const normalizedEntries = Object.entries(signals).map(([key, value]) => {
|
|
2638
|
+
var _a;
|
|
2639
|
+
const signalKey = key.trim();
|
|
2640
|
+
if (!signalKey || !value || typeof value !== "object") return void 0;
|
|
2641
|
+
const description = (_a = value.description) == null ? void 0 : _a.trim();
|
|
2642
|
+
if (!description) return void 0;
|
|
2643
|
+
const sentiment = value.sentiment;
|
|
2644
|
+
return [
|
|
2645
|
+
signalKey,
|
|
2646
|
+
{
|
|
2647
|
+
description,
|
|
2648
|
+
...sentiment === "POSITIVE" || sentiment === "NEGATIVE" ? { sentiment } : {}
|
|
2649
|
+
}
|
|
2650
|
+
];
|
|
2651
|
+
}).filter(
|
|
2652
|
+
(entry) => entry !== void 0
|
|
2653
|
+
);
|
|
2654
|
+
if (normalizedEntries.length === 0) return SELF_DIAGNOSTICS_SIGNALS_DEFAULT;
|
|
2655
|
+
return Object.fromEntries(normalizedEntries);
|
|
2656
|
+
}
|
|
2657
|
+
function normalizeSelfDiagnosticsConfig(options) {
|
|
2658
|
+
var _a, _b;
|
|
2659
|
+
if (!(options == null ? void 0 : options.enabled)) return void 0;
|
|
2660
|
+
const signalDefinitions = normalizeSelfDiagnosticsSignals(options.signals);
|
|
2661
|
+
const signalKeys = Object.keys(signalDefinitions);
|
|
2662
|
+
const signalDescriptions = {};
|
|
2663
|
+
const signalSentiments = {};
|
|
2664
|
+
for (const signalKey of signalKeys) {
|
|
2665
|
+
const definition = signalDefinitions[signalKey];
|
|
2666
|
+
if (!definition) continue;
|
|
2667
|
+
signalDescriptions[signalKey] = definition.description;
|
|
2668
|
+
signalSentiments[signalKey] = definition.sentiment;
|
|
2669
|
+
}
|
|
2670
|
+
const customGuidance = ((_a = options.guidance) == null ? void 0 : _a.trim()) || "";
|
|
2671
|
+
const toolName = ((_b = options.toolName) == null ? void 0 : _b.trim()) || SELF_DIAGNOSTICS_TOOL_NAME_DEFAULT;
|
|
2672
|
+
const signalList = signalKeys.map((signalKey) => {
|
|
2673
|
+
const sentiment = signalSentiments[signalKey];
|
|
2674
|
+
const sentimentTag = sentiment ? ` [${sentiment.toLowerCase()}]` : "";
|
|
2675
|
+
return `- ${signalKey}: ${signalDescriptions[signalKey]}${sentimentTag}`;
|
|
2676
|
+
}).join("\n");
|
|
2677
|
+
const guidanceBlock = customGuidance ? `
|
|
2678
|
+
Additional guidance: ${customGuidance}
|
|
2679
|
+
` : "";
|
|
2680
|
+
const toolDescription = `${SELF_DIAGNOSTICS_TOOL_PREAMBLE}
|
|
2681
|
+
|
|
2682
|
+
When to call:
|
|
2683
|
+
- You are blocked from completing the task due to missing information or access that the user cannot provide.
|
|
2684
|
+
- A tool is persistently failing across multiple attempts, not just a single transient error.
|
|
2685
|
+
- The task requires a tool, permission, or capability you do not have.
|
|
2686
|
+
- You genuinely cannot deliver what the user asked for despite trying.
|
|
2687
|
+
|
|
2688
|
+
When NOT to call:
|
|
2689
|
+
- Normal clarifying questions or back-and-forth with the user.
|
|
2690
|
+
- A single tool error that you can recover from or retry.
|
|
2691
|
+
- You successfully completed the task, even if it was difficult.
|
|
2692
|
+
- Policy refusals or content filtering \u2014 those are working as intended.
|
|
2693
|
+
|
|
2694
|
+
Rules:
|
|
2695
|
+
1. Pick the single best category.
|
|
2696
|
+
2. Do not fabricate issues. Only report what is evident from the conversation.
|
|
2697
|
+
3. Err on the side of NOT calling this tool. When in doubt, help the user instead.
|
|
2698
|
+
${guidanceBlock}
|
|
2699
|
+
Categories:
|
|
2700
|
+
` + signalList;
|
|
2701
|
+
return {
|
|
2702
|
+
toolName,
|
|
2703
|
+
toolDescription,
|
|
2704
|
+
signalKeys,
|
|
2705
|
+
signalKeySet: new Set(signalKeys),
|
|
2706
|
+
signalDescriptions,
|
|
2707
|
+
signalSentiments
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
var SELF_DIAGNOSTICS_ACK = '{"acknowledged":true}';
|
|
2711
|
+
function isRecord3(value) {
|
|
2712
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2713
|
+
}
|
|
2714
|
+
async function trackSelfDiagnosticsSignal(toolInput, config, eventShipper, eventId, debug) {
|
|
2715
|
+
var _a, _b;
|
|
2716
|
+
try {
|
|
2717
|
+
const input = isRecord3(toolInput) ? toolInput : void 0;
|
|
2718
|
+
const fallbackCategory = (_a = config.signalKeys[0]) != null ? _a : "unknown";
|
|
2719
|
+
const categoryCandidate = normalizeString(input == null ? void 0 : input["category"]);
|
|
2720
|
+
const category = categoryCandidate && config.signalKeySet.has(categoryCandidate) ? categoryCandidate : fallbackCategory;
|
|
2721
|
+
const detail = (_b = normalizeString(input == null ? void 0 : input["detail"])) != null ? _b : "";
|
|
2722
|
+
if (!eventId) {
|
|
2723
|
+
if (debug) {
|
|
2724
|
+
console.warn(
|
|
2725
|
+
"[raindrop-ai/opencode-plugin] self diagnostics signal skipped: no open event for this session."
|
|
2726
|
+
);
|
|
2727
|
+
}
|
|
2728
|
+
return;
|
|
2729
|
+
}
|
|
2730
|
+
if (category === SELF_DIAGNOSTICS_NOTEWORTHY_SIGNAL_KEY) {
|
|
2731
|
+
await eventShipper.trackSignal({
|
|
2732
|
+
eventId,
|
|
2733
|
+
name: "self diagnostics - noteworthy",
|
|
2734
|
+
type: "agent_internal",
|
|
2735
|
+
properties: {
|
|
2736
|
+
source: "agent_flag_event_tool",
|
|
2737
|
+
reason: detail,
|
|
2738
|
+
severity: "medium",
|
|
2739
|
+
sdk: "opencode-plugin",
|
|
2740
|
+
sdk_version: PLUGIN_VERSION
|
|
2741
|
+
}
|
|
2742
|
+
});
|
|
2743
|
+
return;
|
|
2744
|
+
}
|
|
2745
|
+
await eventShipper.trackSignal({
|
|
2746
|
+
eventId,
|
|
2747
|
+
name: `self diagnostics - ${category}`,
|
|
2748
|
+
type: "agent",
|
|
2749
|
+
sentiment: config.signalSentiments[category],
|
|
2750
|
+
properties: {
|
|
2751
|
+
source: "agent_reporting_tool",
|
|
2752
|
+
category,
|
|
2753
|
+
signal_description: config.signalDescriptions[category],
|
|
2754
|
+
sdk: "opencode-plugin",
|
|
2755
|
+
sdk_version: PLUGIN_VERSION,
|
|
2756
|
+
...detail ? { detail } : {}
|
|
2757
|
+
}
|
|
2758
|
+
});
|
|
2759
|
+
} catch (err) {
|
|
2760
|
+
if (debug) {
|
|
2761
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2762
|
+
console.warn(
|
|
2763
|
+
`[raindrop-ai/opencode-plugin] selfDiagnostics signal dispatch failed: ${message}`
|
|
2764
|
+
);
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
|
|
2429
2769
|
// src/shipper.ts
|
|
2430
2770
|
var EventShipper3 = class extends EventShipper2 {
|
|
2431
2771
|
constructor(opts) {
|
|
@@ -2461,6 +2801,100 @@ var TraceShipper3 = class extends TraceShipper2 {
|
|
|
2461
2801
|
}
|
|
2462
2802
|
};
|
|
2463
2803
|
|
|
2804
|
+
// src/tool-catalog.ts
|
|
2805
|
+
var PROMPT_TOOLS_SOURCE_ATTRIBUTE = "ai.prompt.tools.source";
|
|
2806
|
+
var OPENCODE_TOOL_LIST_SOURCE = "opencode.tool.list";
|
|
2807
|
+
var TOOL_CATALOG_TIMEOUT_MS = 2e3;
|
|
2808
|
+
function isRecord4(value) {
|
|
2809
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2810
|
+
}
|
|
2811
|
+
function catalogItems(raw) {
|
|
2812
|
+
var _a;
|
|
2813
|
+
const list = Array.isArray(raw) ? raw : isRecord4(raw) && Array.isArray(raw.data) ? raw.data : void 0;
|
|
2814
|
+
if (!list) return void 0;
|
|
2815
|
+
const items = [];
|
|
2816
|
+
for (const item of list) {
|
|
2817
|
+
if (!isRecord4(item)) continue;
|
|
2818
|
+
const name = typeof item.id === "string" ? item.id : typeof item.name === "string" ? item.name : void 0;
|
|
2819
|
+
if (!name) continue;
|
|
2820
|
+
const schema = (_a = item.parameters) != null ? _a : item.input;
|
|
2821
|
+
items.push({
|
|
2822
|
+
type: "function",
|
|
2823
|
+
name,
|
|
2824
|
+
...typeof item.description === "string" ? { description: item.description } : {},
|
|
2825
|
+
...isJsonSchema(schema) ? { inputSchema: schema } : {}
|
|
2826
|
+
});
|
|
2827
|
+
}
|
|
2828
|
+
return items;
|
|
2829
|
+
}
|
|
2830
|
+
function withTimeout(promise, ms) {
|
|
2831
|
+
return new Promise((resolve2) => {
|
|
2832
|
+
const timer = setTimeout(() => resolve2(void 0), ms);
|
|
2833
|
+
if (typeof timer === "object" && "unref" in timer) timer.unref();
|
|
2834
|
+
promise.then(
|
|
2835
|
+
(value) => {
|
|
2836
|
+
clearTimeout(timer);
|
|
2837
|
+
resolve2(value);
|
|
2838
|
+
},
|
|
2839
|
+
() => {
|
|
2840
|
+
clearTimeout(timer);
|
|
2841
|
+
resolve2(void 0);
|
|
2842
|
+
}
|
|
2843
|
+
);
|
|
2844
|
+
});
|
|
2845
|
+
}
|
|
2846
|
+
function createToolCatalog(options = {}) {
|
|
2847
|
+
var _a, _b;
|
|
2848
|
+
const override = options.override !== void 0 ? { tools: (_a = normalizeToolDeclarations(options.override)) != null ? _a : [] } : void 0;
|
|
2849
|
+
const timeoutMs = (_b = options.timeoutMs) != null ? _b : TOOL_CATALOG_TIMEOUT_MS;
|
|
2850
|
+
const cache = /* @__PURE__ */ new Map();
|
|
2851
|
+
async function lookup(query) {
|
|
2852
|
+
const fetch2 = options.fetch;
|
|
2853
|
+
if (!fetch2) return void 0;
|
|
2854
|
+
let raw;
|
|
2855
|
+
try {
|
|
2856
|
+
raw = await withTimeout(Promise.resolve().then(() => fetch2(query)), timeoutMs);
|
|
2857
|
+
} catch (error) {
|
|
2858
|
+
if (options.debug) console.log(`[raindrop-ai/opencode-plugin] tool catalog lookup failed: ${String(error)}`);
|
|
2859
|
+
return void 0;
|
|
2860
|
+
}
|
|
2861
|
+
const tools = normalizeToolDeclarations(catalogItems(raw));
|
|
2862
|
+
if (!tools) {
|
|
2863
|
+
if (options.debug) console.log("[raindrop-ai/opencode-plugin] tool catalog lookup returned no tool list");
|
|
2864
|
+
return void 0;
|
|
2865
|
+
}
|
|
2866
|
+
return { tools, source: OPENCODE_TOOL_LIST_SOURCE };
|
|
2867
|
+
}
|
|
2868
|
+
return {
|
|
2869
|
+
resolve(sessionID, query) {
|
|
2870
|
+
if (override) return Promise.resolve(override);
|
|
2871
|
+
if (!options.fetch) return Promise.resolve(void 0);
|
|
2872
|
+
let perSession = cache.get(sessionID);
|
|
2873
|
+
if (!perSession) {
|
|
2874
|
+
perSession = /* @__PURE__ */ new Map();
|
|
2875
|
+
cache.set(sessionID, perSession);
|
|
2876
|
+
}
|
|
2877
|
+
const key = `${query.provider}\0${query.model}`;
|
|
2878
|
+
let pending = perSession.get(key);
|
|
2879
|
+
if (!pending) {
|
|
2880
|
+
pending = lookup(query).catch(() => void 0);
|
|
2881
|
+
perSession.set(key, pending);
|
|
2882
|
+
}
|
|
2883
|
+
return pending;
|
|
2884
|
+
},
|
|
2885
|
+
forget(sessionID) {
|
|
2886
|
+
cache.delete(sessionID);
|
|
2887
|
+
}
|
|
2888
|
+
};
|
|
2889
|
+
}
|
|
2890
|
+
function promptToolsAttributes(resolved) {
|
|
2891
|
+
if (!resolved) return [];
|
|
2892
|
+
return [
|
|
2893
|
+
promptToolsAttribute(resolved.tools),
|
|
2894
|
+
resolved.source !== void 0 ? attrString(PROMPT_TOOLS_SOURCE_ATTRIBUTE, resolved.source) : void 0
|
|
2895
|
+
];
|
|
2896
|
+
}
|
|
2897
|
+
|
|
2464
2898
|
// src/tracing.ts
|
|
2465
2899
|
var import_node_os2 = require("os");
|
|
2466
2900
|
|
|
@@ -2697,7 +3131,7 @@ function markTaskCallFinished(sessionID, callID) {
|
|
|
2697
3131
|
running.delete(callID);
|
|
2698
3132
|
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
2699
3133
|
}
|
|
2700
|
-
function endPendingToolSpanWithError(state2, callID,
|
|
3134
|
+
function endPendingToolSpanWithError(state2, callID, tool2, toolCallArgs, errorMessage, traceShipper) {
|
|
2701
3135
|
const startInfo = state2.toolSpanStarts.get(callID);
|
|
2702
3136
|
if (!startInfo) return false;
|
|
2703
3137
|
state2.toolSpanStarts.delete(callID);
|
|
@@ -2719,7 +3153,7 @@ function endPendingToolSpanWithError(state2, callID, tool, toolCallArgs, errorMe
|
|
|
2719
3153
|
startTimeUnixNano: startInfo.startTimeUnixNano,
|
|
2720
3154
|
attributes: [
|
|
2721
3155
|
attrString("ai.operationId", "ai.toolCall"),
|
|
2722
|
-
attrString("ai.toolCall.name",
|
|
3156
|
+
attrString("ai.toolCall.name", tool2),
|
|
2723
3157
|
attrString("ai.toolCall.id", callID)
|
|
2724
3158
|
]
|
|
2725
3159
|
});
|
|
@@ -2756,7 +3190,7 @@ function getHostname() {
|
|
|
2756
3190
|
return h;
|
|
2757
3191
|
}
|
|
2758
3192
|
}
|
|
2759
|
-
function
|
|
3193
|
+
function createTracing(config, worktree, directory, eventShipper, traceShipper, toolCatalog) {
|
|
2760
3194
|
function log(msg, data) {
|
|
2761
3195
|
if (!config.debug) return;
|
|
2762
3196
|
const prefix = `[raindrop-ai/opencode-plugin] [info] ${msg}`;
|
|
@@ -2782,7 +3216,15 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2782
3216
|
callKey,
|
|
2783
3217
|
log
|
|
2784
3218
|
});
|
|
2785
|
-
|
|
3219
|
+
const hooks = {
|
|
3220
|
+
// Fires before each model call with the model already resolved: start the
|
|
3221
|
+
// catalog lookup now so the span attributes rarely wait on it later.
|
|
3222
|
+
"chat.params": async (input) => {
|
|
3223
|
+
void (toolCatalog == null ? void 0 : toolCatalog.resolve(input.sessionID, {
|
|
3224
|
+
provider: input.model.providerID,
|
|
3225
|
+
model: input.model.id
|
|
3226
|
+
}));
|
|
3227
|
+
},
|
|
2786
3228
|
// ------------------------------------------------------------------
|
|
2787
3229
|
// event — session lifecycle + streaming parts
|
|
2788
3230
|
// ------------------------------------------------------------------
|
|
@@ -2827,14 +3269,14 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2827
3269
|
if (partObj["type"] === "text" && typeof partObj["text"] === "string") {
|
|
2828
3270
|
state2.outputParts.set(messageId, capText2(partObj["text"]));
|
|
2829
3271
|
} else if (partObj["type"] === "tool" && messageId) {
|
|
2830
|
-
const
|
|
3272
|
+
const tool2 = partObj["tool"];
|
|
2831
3273
|
const callID = partObj["callID"];
|
|
2832
3274
|
const partState = partObj["state"];
|
|
2833
3275
|
if (callID == null || callID === "")
|
|
2834
3276
|
throw new Error("message.part.updated: part.callID is required for tool part");
|
|
2835
3277
|
if (partState == null || typeof partState !== "object")
|
|
2836
3278
|
throw new Error("message.part.updated: part.state is required for tool part");
|
|
2837
|
-
if (
|
|
3279
|
+
if (tool2 === "task") {
|
|
2838
3280
|
const metadata = partState["metadata"];
|
|
2839
3281
|
const childSessionId = metadata != null && typeof metadata === "object" ? metadata["sessionId"] : void 0;
|
|
2840
3282
|
if (childSessionId != null && childSessionId !== "") {
|
|
@@ -2859,11 +3301,11 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2859
3301
|
if (endPendingToolSpanWithError(
|
|
2860
3302
|
state2,
|
|
2861
3303
|
callID,
|
|
2862
|
-
|
|
3304
|
+
tool2,
|
|
2863
3305
|
toolCallArgs,
|
|
2864
3306
|
errorMessage,
|
|
2865
3307
|
traceShipper
|
|
2866
|
-
) &&
|
|
3308
|
+
) && tool2 === "task") {
|
|
2867
3309
|
markTaskCallFinished(partSessionID, callID);
|
|
2868
3310
|
}
|
|
2869
3311
|
}
|
|
@@ -2907,6 +3349,9 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2907
3349
|
"message.updated: providerID and modelID are required non-empty strings"
|
|
2908
3350
|
);
|
|
2909
3351
|
const modelName = `${providerID}/${modelID}`;
|
|
3352
|
+
const promptTools = promptToolsAttributes(
|
|
3353
|
+
await (toolCatalog == null ? void 0 : toolCatalog.resolve(String(msgSessionID), { provider: providerID, model: modelID }))
|
|
3354
|
+
);
|
|
2910
3355
|
const finishReason = info2["finish"];
|
|
2911
3356
|
const outputText = state2.outputParts.get(messageId);
|
|
2912
3357
|
const reasoningText = state2.reasoningParts.get(messageId);
|
|
@@ -2932,7 +3377,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
2932
3377
|
const llmAttrs = [
|
|
2933
3378
|
attrString("ai.operationId", "generateText"),
|
|
2934
3379
|
attrString("ai.response.text", responseText),
|
|
2935
|
-
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
3380
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj }),
|
|
3381
|
+
...promptTools
|
|
2936
3382
|
];
|
|
2937
3383
|
if (state2.currentSystemPrompt) {
|
|
2938
3384
|
llmAttrs.push(
|
|
@@ -2968,7 +3414,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
2968
3414
|
buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
|
|
2969
3415
|
),
|
|
2970
3416
|
attrString("ai.response.text", turnOutputText),
|
|
2971
|
-
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
3417
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj }),
|
|
3418
|
+
...promptTools
|
|
2972
3419
|
];
|
|
2973
3420
|
if (state2.currentSystemPrompt) {
|
|
2974
3421
|
llmAttrs.push(
|
|
@@ -3013,7 +3460,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
3013
3460
|
buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
|
|
3014
3461
|
),
|
|
3015
3462
|
attrString("ai.response.text", turnOutputText),
|
|
3016
|
-
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
3463
|
+
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj }),
|
|
3464
|
+
...promptTools
|
|
3017
3465
|
];
|
|
3018
3466
|
if (isCompaction) {
|
|
3019
3467
|
rootAttrs.push(attrString("is_compaction", "true"));
|
|
@@ -3079,6 +3527,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
3079
3527
|
if (state2.parentId) {
|
|
3080
3528
|
cleanupSessionParentMap(String(sessionID));
|
|
3081
3529
|
sessions.delete(String(sessionID));
|
|
3530
|
+
toolCatalog == null ? void 0 : toolCatalog.forget(String(sessionID));
|
|
3082
3531
|
} else {
|
|
3083
3532
|
}
|
|
3084
3533
|
} else if (event.type === "session.deleted") {
|
|
@@ -3095,6 +3544,7 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
3095
3544
|
cleanupSessionParentMap(String(sessionID));
|
|
3096
3545
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
3097
3546
|
sessions.delete(String(sessionID));
|
|
3547
|
+
toolCatalog == null ? void 0 : toolCatalog.forget(String(sessionID));
|
|
3098
3548
|
} else if (event.type === "session.error") {
|
|
3099
3549
|
const errorSessionID = (_h = props["sessionID"]) != null ? _h : sessionID;
|
|
3100
3550
|
if (errorSessionID === void 0 || errorSessionID === "")
|
|
@@ -3120,6 +3570,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3120
3570
|
cleanupSessionParentMap(String(errorSessionID));
|
|
3121
3571
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
3122
3572
|
sessions.delete(String(errorSessionID));
|
|
3573
|
+
toolCatalog == null ? void 0 : toolCatalog.forget(String(errorSessionID));
|
|
3123
3574
|
}
|
|
3124
3575
|
} catch (err) {
|
|
3125
3576
|
rateLimitedErrorLog(
|
|
@@ -3240,20 +3691,20 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3240
3691
|
"tool.execute.before": async (toolInput, _output) => {
|
|
3241
3692
|
var _a, _b, _c;
|
|
3242
3693
|
try {
|
|
3243
|
-
const { tool, sessionID, callID } = toolInput;
|
|
3694
|
+
const { tool: tool2, sessionID, callID } = toolInput;
|
|
3244
3695
|
const state2 = sessions.get(sessionID);
|
|
3245
3696
|
if (!state2 || !state2.currentEventId) return;
|
|
3246
3697
|
const spanParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : (_a = state2.currentRootSpan) == null ? void 0 : _a.ids;
|
|
3247
3698
|
if (!spanParent) return;
|
|
3248
3699
|
const startTimeUnixNano = nowUnixNanoString();
|
|
3249
|
-
if (
|
|
3700
|
+
if (tool2 === "task") {
|
|
3250
3701
|
const liveTaskSpan = traceShipper.startSpan({
|
|
3251
3702
|
name: "ai.toolCall",
|
|
3252
3703
|
parent: spanParent,
|
|
3253
3704
|
eventId: state2.currentEventId,
|
|
3254
3705
|
attributes: [
|
|
3255
3706
|
attrString("ai.operationId", "ai.toolCall"),
|
|
3256
|
-
attrString("ai.toolCall.name",
|
|
3707
|
+
attrString("ai.toolCall.name", tool2),
|
|
3257
3708
|
attrString("ai.toolCall.id", callID)
|
|
3258
3709
|
]
|
|
3259
3710
|
});
|
|
@@ -3278,7 +3729,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3278
3729
|
startTimeUnixNano,
|
|
3279
3730
|
parent: spanParent,
|
|
3280
3731
|
eventId: state2.currentEventId,
|
|
3281
|
-
name:
|
|
3732
|
+
name: tool2,
|
|
3282
3733
|
liveSpan: liveTaskSpan
|
|
3283
3734
|
});
|
|
3284
3735
|
} else {
|
|
@@ -3286,7 +3737,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3286
3737
|
startTimeUnixNano,
|
|
3287
3738
|
parent: spanParent,
|
|
3288
3739
|
eventId: state2.currentEventId,
|
|
3289
|
-
name:
|
|
3740
|
+
name: tool2
|
|
3290
3741
|
});
|
|
3291
3742
|
}
|
|
3292
3743
|
} catch (err) {
|
|
@@ -3301,7 +3752,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3301
3752
|
// ------------------------------------------------------------------
|
|
3302
3753
|
"tool.execute.after": async (toolInput, result) => {
|
|
3303
3754
|
try {
|
|
3304
|
-
const { tool, sessionID, callID, args } = toolInput;
|
|
3755
|
+
const { tool: tool2, sessionID, callID, args } = toolInput;
|
|
3305
3756
|
const state2 = sessions.get(sessionID);
|
|
3306
3757
|
if (!state2 || !state2.currentEventId) return;
|
|
3307
3758
|
if (args === void 0 || args === null)
|
|
@@ -3311,7 +3762,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3311
3762
|
state2.toolSpanStarts.delete(callID);
|
|
3312
3763
|
const resultMetadata = result.metadata;
|
|
3313
3764
|
const childSessionId = resultMetadata == null ? void 0 : resultMetadata["sessionId"];
|
|
3314
|
-
if (
|
|
3765
|
+
if (tool2 === "task" && childSessionId) {
|
|
3315
3766
|
mapChildSessionToParent.set(childSessionId, { parentId: sessionID });
|
|
3316
3767
|
attachChildSessionToParentTask(childSessionId, sessionID, callID, "tool.execute.after");
|
|
3317
3768
|
}
|
|
@@ -3336,7 +3787,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3336
3787
|
endTimeUnixNano,
|
|
3337
3788
|
attributes: [
|
|
3338
3789
|
attrString("ai.operationId", "ai.toolCall"),
|
|
3339
|
-
attrString("ai.toolCall.name",
|
|
3790
|
+
attrString("ai.toolCall.name", tool2),
|
|
3340
3791
|
attrString("ai.toolCall.id", callID),
|
|
3341
3792
|
attrString("ai.toolCall.args", toolCallArgs),
|
|
3342
3793
|
attrString("ai.toolCall.result", toolResult)
|
|
@@ -3344,7 +3795,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3344
3795
|
});
|
|
3345
3796
|
}
|
|
3346
3797
|
}
|
|
3347
|
-
if (
|
|
3798
|
+
if (tool2 === "task") {
|
|
3348
3799
|
markTaskCallFinished(sessionID, callID);
|
|
3349
3800
|
}
|
|
3350
3801
|
} catch (err) {
|
|
@@ -3397,16 +3848,24 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3397
3848
|
}
|
|
3398
3849
|
}
|
|
3399
3850
|
};
|
|
3851
|
+
return {
|
|
3852
|
+
hooks,
|
|
3853
|
+
currentEventId(sessionID) {
|
|
3854
|
+
var _a;
|
|
3855
|
+
return (_a = sessions.get(sessionID)) == null ? void 0 : _a.currentEventId;
|
|
3856
|
+
}
|
|
3857
|
+
};
|
|
3400
3858
|
}
|
|
3401
3859
|
|
|
3402
3860
|
// src/index.ts
|
|
3403
|
-
function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
|
|
3861
|
+
function createRaindropHandle(eventShipper, traceShipper, appGitContext, currentEventId) {
|
|
3404
3862
|
return {
|
|
3405
3863
|
users: {
|
|
3406
3864
|
async identify(users) {
|
|
3407
3865
|
await eventShipper.identify(users);
|
|
3408
3866
|
}
|
|
3409
3867
|
},
|
|
3868
|
+
currentEventId,
|
|
3410
3869
|
async flush() {
|
|
3411
3870
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
3412
3871
|
},
|
|
@@ -3423,7 +3882,7 @@ function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
|
|
|
3423
3882
|
};
|
|
3424
3883
|
}
|
|
3425
3884
|
async function plugin(input, opts = {}) {
|
|
3426
|
-
var _a, _b, _c;
|
|
3885
|
+
var _a, _b, _c, _d, _e;
|
|
3427
3886
|
const config = loadConfig(input.directory);
|
|
3428
3887
|
function appLog(level, message) {
|
|
3429
3888
|
console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
|
|
@@ -3467,12 +3926,59 @@ async function plugin(input, opts = {}) {
|
|
|
3467
3926
|
appGitContext
|
|
3468
3927
|
});
|
|
3469
3928
|
const worktree = (_c = input.worktree) != null ? _c : input.directory;
|
|
3470
|
-
const
|
|
3929
|
+
const toolCatalog = createToolCatalog({
|
|
3930
|
+
override: (_d = opts.tools) != null ? _d : config.tools,
|
|
3931
|
+
fetch: (query) => input.client.tool.list({ query }),
|
|
3932
|
+
debug: config.debug
|
|
3933
|
+
});
|
|
3934
|
+
const tracing = createTracing(
|
|
3471
3935
|
config,
|
|
3472
3936
|
worktree,
|
|
3473
3937
|
input.directory,
|
|
3474
3938
|
eventShipper,
|
|
3475
|
-
traceShipper
|
|
3939
|
+
traceShipper,
|
|
3940
|
+
toolCatalog
|
|
3941
|
+
);
|
|
3942
|
+
const hooks = tracing.hooks;
|
|
3943
|
+
const selfDiagnostics = normalizeSelfDiagnosticsConfig(
|
|
3944
|
+
(_e = opts.selfDiagnostics) != null ? _e : config.selfDiagnostics
|
|
3476
3945
|
);
|
|
3477
|
-
|
|
3946
|
+
if (selfDiagnostics && !config.writeKey.trim()) {
|
|
3947
|
+
appLog(
|
|
3948
|
+
"warn",
|
|
3949
|
+
`selfDiagnostics enabled but RAINDROP_WRITE_KEY is not set \u2014 the ${selfDiagnostics.toolName} tool is not registered (signals require the cloud destination).`
|
|
3950
|
+
);
|
|
3951
|
+
}
|
|
3952
|
+
const [firstSignalKey, ...restSignalKeys] = config.writeKey.trim() && selfDiagnostics ? selfDiagnostics.signalKeys : [];
|
|
3953
|
+
if (selfDiagnostics && firstSignalKey !== void 0) {
|
|
3954
|
+
const cfg = selfDiagnostics;
|
|
3955
|
+
hooks.tool = {
|
|
3956
|
+
[cfg.toolName]: (0, import_plugin.tool)({
|
|
3957
|
+
description: cfg.toolDescription,
|
|
3958
|
+
args: {
|
|
3959
|
+
category: import_plugin.tool.schema.enum([firstSignalKey, ...restSignalKeys]),
|
|
3960
|
+
detail: import_plugin.tool.schema.string()
|
|
3961
|
+
},
|
|
3962
|
+
async execute(args, ctx) {
|
|
3963
|
+
await trackSelfDiagnosticsSignal(
|
|
3964
|
+
args,
|
|
3965
|
+
cfg,
|
|
3966
|
+
eventShipper,
|
|
3967
|
+
tracing.currentEventId(ctx.sessionID),
|
|
3968
|
+
config.debug
|
|
3969
|
+
);
|
|
3970
|
+
return SELF_DIAGNOSTICS_ACK;
|
|
3971
|
+
}
|
|
3972
|
+
})
|
|
3973
|
+
};
|
|
3974
|
+
}
|
|
3975
|
+
return {
|
|
3976
|
+
...hooks,
|
|
3977
|
+
raindrop: createRaindropHandle(
|
|
3978
|
+
eventShipper,
|
|
3979
|
+
traceShipper,
|
|
3980
|
+
appGitContext,
|
|
3981
|
+
tracing.currentEventId
|
|
3982
|
+
)
|
|
3983
|
+
};
|
|
3478
3984
|
}
|