@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 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 = {
@@ -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';
@@ -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.19",
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",