@frenchtoastman/oh-my-groundcontrol 0.0.19 → 0.0.21
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/cli/index.js +7 -1
- package/dist/config/schema.d.ts +11 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/langfuse-body/index.d.ts +39 -0
- package/dist/hooks/langfuse-common.d.ts +15 -0
- package/dist/hooks/langfuse-headers/index.d.ts +31 -0
- package/dist/hooks/langfuse-tracing/index.d.ts +39 -0
- package/dist/index.js +78 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -13772,6 +13772,11 @@ var HashlineEditConfigSchema = exports_external.object({
|
|
|
13772
13772
|
var DoubleConfirmationConfigSchema = exports_external.object({
|
|
13773
13773
|
enabled: exports_external.boolean().default(false)
|
|
13774
13774
|
});
|
|
13775
|
+
var LangfuseTracingConfigSchema = exports_external.object({
|
|
13776
|
+
enabled: exports_external.boolean().default(false),
|
|
13777
|
+
traceUserId: exports_external.string().default("opencode"),
|
|
13778
|
+
customMetadata: exports_external.record(exports_external.string(), exports_external.unknown()).default({})
|
|
13779
|
+
});
|
|
13775
13780
|
var PluginConfigSchema = exports_external.object({
|
|
13776
13781
|
preset: exports_external.string().optional(),
|
|
13777
13782
|
scoringEngineVersion: exports_external.enum(["v1", "v2-shadow", "v2"]).optional(),
|
|
@@ -13786,7 +13791,8 @@ var PluginConfigSchema = exports_external.object({
|
|
|
13786
13791
|
allowedProviders: exports_external.array(exports_external.string()).optional(),
|
|
13787
13792
|
sessionExport: SessionExportConfigSchema.optional(),
|
|
13788
13793
|
hashline_edit: HashlineEditConfigSchema.optional(),
|
|
13789
|
-
double_confirmation: DoubleConfirmationConfigSchema.optional()
|
|
13794
|
+
double_confirmation: DoubleConfirmationConfigSchema.optional(),
|
|
13795
|
+
langfuse_tracing: LangfuseTracingConfigSchema.optional()
|
|
13790
13796
|
});
|
|
13791
13797
|
// src/config/agent-mcps.ts
|
|
13792
13798
|
var DEFAULT_AGENT_MCPS = {
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -165,6 +165,12 @@ export declare const DoubleConfirmationConfigSchema: z.ZodObject<{
|
|
|
165
165
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
166
166
|
}, z.core.$strip>;
|
|
167
167
|
export type DoubleConfirmationConfig = z.infer<typeof DoubleConfirmationConfigSchema>;
|
|
168
|
+
export declare const LangfuseTracingConfigSchema: z.ZodObject<{
|
|
169
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
170
|
+
traceUserId: z.ZodDefault<z.ZodString>;
|
|
171
|
+
customMetadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
172
|
+
}, z.core.$strip>;
|
|
173
|
+
export type LangfuseTracingConfig = z.infer<typeof LangfuseTracingConfigSchema>;
|
|
168
174
|
export declare const PluginConfigSchema: z.ZodObject<{
|
|
169
175
|
preset: z.ZodOptional<z.ZodString>;
|
|
170
176
|
scoringEngineVersion: z.ZodOptional<z.ZodEnum<{
|
|
@@ -298,6 +304,11 @@ export declare const PluginConfigSchema: z.ZodObject<{
|
|
|
298
304
|
double_confirmation: z.ZodOptional<z.ZodObject<{
|
|
299
305
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
300
306
|
}, z.core.$strip>>;
|
|
307
|
+
langfuse_tracing: z.ZodOptional<z.ZodObject<{
|
|
308
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
309
|
+
traceUserId: z.ZodDefault<z.ZodString>;
|
|
310
|
+
customMetadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
311
|
+
}, z.core.$strip>>;
|
|
301
312
|
}, z.core.$strip>;
|
|
302
313
|
export type PluginConfig = z.infer<typeof PluginConfigSchema>;
|
|
303
314
|
export type { AgentName } from './constants';
|
package/dist/hooks/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { createDoubleConfirmationHook } from './double-confirmation';
|
|
|
6
6
|
export { createEditErrorRecoveryHook } from './edit-error-recovery';
|
|
7
7
|
export { createHashlineReadEnhancerHook } from './hashline-read-enhancer';
|
|
8
8
|
export { createJsonErrorRecoveryHook } from './json-error-recovery';
|
|
9
|
+
export { createLangfuseTracingHook } from './langfuse-tracing';
|
|
9
10
|
export { createPhaseReminderHook } from './phase-reminder';
|
|
10
11
|
export { createPostReadNudgeHook } from './post-read-nudge';
|
|
11
12
|
export { createQuestionRouterHook } from './question-router';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { LangfuseBodyConfig } from '../../config/schema';
|
|
2
|
+
interface ChatParamsInput {
|
|
3
|
+
sessionID: string;
|
|
4
|
+
agent: string;
|
|
5
|
+
model: {
|
|
6
|
+
id: string;
|
|
7
|
+
providerID: string;
|
|
8
|
+
};
|
|
9
|
+
provider: {
|
|
10
|
+
source: string;
|
|
11
|
+
info: unknown;
|
|
12
|
+
options: Record<string, unknown>;
|
|
13
|
+
};
|
|
14
|
+
message: unknown;
|
|
15
|
+
}
|
|
16
|
+
interface ChatParamsOutput {
|
|
17
|
+
temperature?: number;
|
|
18
|
+
topP?: number;
|
|
19
|
+
topK?: number;
|
|
20
|
+
options: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates the Langfuse body injection hook.
|
|
24
|
+
*
|
|
25
|
+
* Injects metadata into the LLM request body via `chat.params`
|
|
26
|
+
* → `output.options.metadata`, which flows through the Vercel AI
|
|
27
|
+
* SDK's `providerOptions` into the HTTP request body.
|
|
28
|
+
*
|
|
29
|
+
* LiteLLM proxy reads body-level `metadata` and forwards recognised
|
|
30
|
+
* keys (tags, session_id, trace_user_id, trace_name,
|
|
31
|
+
* generation_name) to Langfuse for trace enrichment.
|
|
32
|
+
*
|
|
33
|
+
* Ships disabled by default — enable via
|
|
34
|
+
* config.langfuse_body.enabled.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createLangfuseBodyHook(config?: Partial<LangfuseBodyConfig>): {
|
|
37
|
+
'chat.params': (input: ChatParamsInput, output: ChatParamsOutput) => Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Langfuse utilities for agent-to-task mapping and tag derivation.
|
|
3
|
+
*/
|
|
4
|
+
export declare const AGENT_TASK_MAP: Record<string, string>;
|
|
5
|
+
/**
|
|
6
|
+
* Derive the task type for an agent.
|
|
7
|
+
* Returns undefined for empty agent.
|
|
8
|
+
* Falls back to 'general' for unknown agents.
|
|
9
|
+
*/
|
|
10
|
+
export declare function deriveTask(agent: string): string | undefined;
|
|
11
|
+
/**
|
|
12
|
+
* Derive Langfuse tags for an agent.
|
|
13
|
+
* Returns ['opencode', agentName, taskType], filtering out empty values.
|
|
14
|
+
*/
|
|
15
|
+
export declare function deriveTags(agent: string): string[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { LangfuseHeadersConfig } from '../../config/schema';
|
|
2
|
+
interface ChatHeadersInput {
|
|
3
|
+
sessionID: string;
|
|
4
|
+
agent: string;
|
|
5
|
+
model: {
|
|
6
|
+
id: string;
|
|
7
|
+
providerID: string;
|
|
8
|
+
};
|
|
9
|
+
provider: {
|
|
10
|
+
source: string;
|
|
11
|
+
info: unknown;
|
|
12
|
+
options: Record<string, unknown>;
|
|
13
|
+
};
|
|
14
|
+
message: unknown;
|
|
15
|
+
}
|
|
16
|
+
interface ChatHeadersOutput {
|
|
17
|
+
headers: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Creates the Langfuse trace enrichment headers hook.
|
|
21
|
+
*
|
|
22
|
+
* Injects dynamic `X-OC-*` HTTP headers into every LLM API request,
|
|
23
|
+
* providing rich OpenCode context for Langfuse trace enrichment and
|
|
24
|
+
* training data tagging.
|
|
25
|
+
*
|
|
26
|
+
* Ships disabled by default — enable via config.langfuse_headers.enabled.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createLangfuseHeadersHook(config?: Partial<LangfuseHeadersConfig>): {
|
|
29
|
+
'chat.headers': (input: ChatHeadersInput, output: ChatHeadersOutput) => Promise<void>;
|
|
30
|
+
};
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { LangfuseTracingConfig } from '../../config/schema';
|
|
2
|
+
interface ChatParamsInput {
|
|
3
|
+
sessionID: string;
|
|
4
|
+
agent: string;
|
|
5
|
+
model: {
|
|
6
|
+
id: string;
|
|
7
|
+
providerID: string;
|
|
8
|
+
};
|
|
9
|
+
provider: {
|
|
10
|
+
source: string;
|
|
11
|
+
info: unknown;
|
|
12
|
+
options: Record<string, unknown>;
|
|
13
|
+
};
|
|
14
|
+
message: unknown;
|
|
15
|
+
}
|
|
16
|
+
interface ChatParamsOutput {
|
|
17
|
+
temperature?: number;
|
|
18
|
+
topP?: number;
|
|
19
|
+
topK?: number;
|
|
20
|
+
options: Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates the Langfuse tracing hook.
|
|
24
|
+
*
|
|
25
|
+
* Injects metadata into the LLM request body via `chat.params`
|
|
26
|
+
* → `output.options.metadata`, which flows through the Vercel AI
|
|
27
|
+
* SDK's `providerOptions` into the HTTP request body.
|
|
28
|
+
*
|
|
29
|
+
* LiteLLM proxy reads body-level `metadata` and forwards recognised
|
|
30
|
+
* keys (tags, session_id, trace_user_id, trace_name,
|
|
31
|
+
* generation_name) to Langfuse for trace enrichment.
|
|
32
|
+
*
|
|
33
|
+
* Ships disabled by default — enable via
|
|
34
|
+
* config.langfuse_tracing.enabled.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createLangfuseTracingHook(config?: Partial<LangfuseTracingConfig>): {
|
|
37
|
+
'chat.params': (input: ChatParamsInput, output: ChatParamsOutput) => Promise<void>;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
package/dist/index.js
CHANGED
|
@@ -17104,6 +17104,11 @@ var HashlineEditConfigSchema = exports_external.object({
|
|
|
17104
17104
|
var DoubleConfirmationConfigSchema = exports_external.object({
|
|
17105
17105
|
enabled: exports_external.boolean().default(false)
|
|
17106
17106
|
});
|
|
17107
|
+
var LangfuseTracingConfigSchema = exports_external.object({
|
|
17108
|
+
enabled: exports_external.boolean().default(false),
|
|
17109
|
+
traceUserId: exports_external.string().default("opencode"),
|
|
17110
|
+
customMetadata: exports_external.record(exports_external.string(), exports_external.unknown()).default({})
|
|
17111
|
+
});
|
|
17107
17112
|
var PluginConfigSchema = exports_external.object({
|
|
17108
17113
|
preset: exports_external.string().optional(),
|
|
17109
17114
|
scoringEngineVersion: exports_external.enum(["v1", "v2-shadow", "v2"]).optional(),
|
|
@@ -17118,7 +17123,8 @@ var PluginConfigSchema = exports_external.object({
|
|
|
17118
17123
|
allowedProviders: exports_external.array(exports_external.string()).optional(),
|
|
17119
17124
|
sessionExport: SessionExportConfigSchema.optional(),
|
|
17120
17125
|
hashline_edit: HashlineEditConfigSchema.optional(),
|
|
17121
|
-
double_confirmation: DoubleConfirmationConfigSchema.optional()
|
|
17126
|
+
double_confirmation: DoubleConfirmationConfigSchema.optional(),
|
|
17127
|
+
langfuse_tracing: LangfuseTracingConfigSchema.optional()
|
|
17122
17128
|
});
|
|
17123
17129
|
|
|
17124
17130
|
// src/config/loader.ts
|
|
@@ -23144,6 +23150,75 @@ ${JSON_ERROR_REMINDER}`;
|
|
|
23144
23150
|
}
|
|
23145
23151
|
};
|
|
23146
23152
|
}
|
|
23153
|
+
// src/hooks/langfuse-common.ts
|
|
23154
|
+
var AGENT_TASK_MAP = {
|
|
23155
|
+
orchestrator: "planning",
|
|
23156
|
+
explorer: "research",
|
|
23157
|
+
fixer: "coding",
|
|
23158
|
+
designer: "design",
|
|
23159
|
+
librarian: "research",
|
|
23160
|
+
oracle: "analysis",
|
|
23161
|
+
verification: "verification",
|
|
23162
|
+
"pre-flight": "planning",
|
|
23163
|
+
contractor: "planning",
|
|
23164
|
+
groundcontrol: "planning"
|
|
23165
|
+
};
|
|
23166
|
+
function deriveTask(agent) {
|
|
23167
|
+
if (!agent)
|
|
23168
|
+
return;
|
|
23169
|
+
return AGENT_TASK_MAP[agent] ?? "general";
|
|
23170
|
+
}
|
|
23171
|
+
function deriveTags(agent) {
|
|
23172
|
+
const tags = ["opencode"];
|
|
23173
|
+
if (agent)
|
|
23174
|
+
tags.push(agent);
|
|
23175
|
+
const task = deriveTask(agent);
|
|
23176
|
+
if (task)
|
|
23177
|
+
tags.push(task);
|
|
23178
|
+
return tags;
|
|
23179
|
+
}
|
|
23180
|
+
|
|
23181
|
+
// src/hooks/langfuse-tracing/index.ts
|
|
23182
|
+
function createLangfuseTracingHook(config2) {
|
|
23183
|
+
const enabled = config2?.enabled ?? false;
|
|
23184
|
+
const traceUserId = config2?.traceUserId ?? "opencode";
|
|
23185
|
+
const customMetadata = config2?.customMetadata ?? {};
|
|
23186
|
+
const pluginVersion = getCachedVersion() ?? "unknown";
|
|
23187
|
+
return {
|
|
23188
|
+
"chat.params": async (input, output) => {
|
|
23189
|
+
if (!enabled)
|
|
23190
|
+
return;
|
|
23191
|
+
try {
|
|
23192
|
+
const tags = deriveTags(input.agent);
|
|
23193
|
+
const task = deriveTask(input.agent);
|
|
23194
|
+
const metadata = {
|
|
23195
|
+
...output.options.metadata ?? {},
|
|
23196
|
+
tags,
|
|
23197
|
+
session_id: input.sessionID || undefined,
|
|
23198
|
+
trace_user_id: traceUserId || undefined,
|
|
23199
|
+
trace_name: input.agent || undefined,
|
|
23200
|
+
generation_name: task || undefined,
|
|
23201
|
+
model: input.model?.id || undefined,
|
|
23202
|
+
provider: input.model?.providerID || undefined,
|
|
23203
|
+
plugin_version: pluginVersion || undefined
|
|
23204
|
+
};
|
|
23205
|
+
for (const [key, value] of Object.entries(customMetadata)) {
|
|
23206
|
+
if (value !== undefined && value !== null) {
|
|
23207
|
+
metadata[key] = value;
|
|
23208
|
+
}
|
|
23209
|
+
}
|
|
23210
|
+
for (const key of Object.keys(metadata)) {
|
|
23211
|
+
if (metadata[key] === undefined) {
|
|
23212
|
+
delete metadata[key];
|
|
23213
|
+
}
|
|
23214
|
+
}
|
|
23215
|
+
output.options.metadata = metadata;
|
|
23216
|
+
} catch (err) {
|
|
23217
|
+
log("[langfuse-tracing] Error injecting metadata:", err);
|
|
23218
|
+
}
|
|
23219
|
+
}
|
|
23220
|
+
};
|
|
23221
|
+
}
|
|
23147
23222
|
// src/hooks/phase-reminder/index.ts
|
|
23148
23223
|
var PHASE_REMINDER = `<reminder>Recall Workflow Rules:
|
|
23149
23224
|
Before acting: <think> \u2014 analyze what you see, what's been accomplished, what still needs to be done.
|
|
@@ -39359,6 +39434,7 @@ var OhMyGroundControl = async (ctx) => {
|
|
|
39359
39434
|
const hashlineReadEnhancerHook = createHashlineReadEnhancerHook(config3.hashline_edit);
|
|
39360
39435
|
const editErrorRecoveryHook = createEditErrorRecoveryHook();
|
|
39361
39436
|
const doubleConfirmationHook = createDoubleConfirmationHook(config3.double_confirmation);
|
|
39437
|
+
const langfuseTracingHook = createLangfuseTracingHook(config3.langfuse_tracing);
|
|
39362
39438
|
const hashlineEditEnabled = config3.hashline_edit?.enabled !== false;
|
|
39363
39439
|
const hashlineEditTool = hashlineEditEnabled ? createHashlineEditTool() : undefined;
|
|
39364
39440
|
return {
|
|
@@ -39463,6 +39539,7 @@ var OhMyGroundControl = async (ctx) => {
|
|
|
39463
39539
|
"experimental.chat.messages.transform": phaseReminderHook["experimental.chat.messages.transform"],
|
|
39464
39540
|
"chat.message": questionRouterHook["chat.message"],
|
|
39465
39541
|
"command.execute.before": analyzeCommandHook["command.execute.before"],
|
|
39542
|
+
"chat.params": langfuseTracingHook["chat.params"],
|
|
39466
39543
|
"tool.execute.after": async (input, output) => {
|
|
39467
39544
|
await delegateTaskRetryHook["tool.execute.after"](input, output);
|
|
39468
39545
|
await jsonErrorRecoveryHook["tool.execute.after"](input, output);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frenchtoastman/oh-my-groundcontrol",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"description": "An OpenCode plugin for multi-agent orchestration for structured planning with NASA-style guardrails.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|