@frenchtoastman/oh-my-groundcontrol 0.0.20 → 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,9 +13772,10 @@ var HashlineEditConfigSchema = exports_external.object({
13772
13772
  var DoubleConfirmationConfigSchema = exports_external.object({
13773
13773
  enabled: exports_external.boolean().default(false)
13774
13774
  });
13775
- var LangfuseHeadersConfigSchema = exports_external.object({
13775
+ var LangfuseTracingConfigSchema = exports_external.object({
13776
13776
  enabled: exports_external.boolean().default(false),
13777
- customHeaders: exports_external.record(exports_external.string(), exports_external.string()).default({})
13777
+ traceUserId: exports_external.string().default("opencode"),
13778
+ customMetadata: exports_external.record(exports_external.string(), exports_external.unknown()).default({})
13778
13779
  });
13779
13780
  var PluginConfigSchema = exports_external.object({
13780
13781
  preset: exports_external.string().optional(),
@@ -13791,7 +13792,7 @@ var PluginConfigSchema = exports_external.object({
13791
13792
  sessionExport: SessionExportConfigSchema.optional(),
13792
13793
  hashline_edit: HashlineEditConfigSchema.optional(),
13793
13794
  double_confirmation: DoubleConfirmationConfigSchema.optional(),
13794
- langfuse_headers: LangfuseHeadersConfigSchema.optional()
13795
+ langfuse_tracing: LangfuseTracingConfigSchema.optional()
13795
13796
  });
13796
13797
  // src/config/agent-mcps.ts
13797
13798
  var DEFAULT_AGENT_MCPS = {
@@ -165,11 +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 LangfuseHeadersConfigSchema: z.ZodObject<{
168
+ export declare const LangfuseTracingConfigSchema: z.ZodObject<{
169
169
  enabled: z.ZodDefault<z.ZodBoolean>;
170
- customHeaders: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
170
+ traceUserId: z.ZodDefault<z.ZodString>;
171
+ customMetadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
171
172
  }, z.core.$strip>;
172
- export type LangfuseHeadersConfig = z.infer<typeof LangfuseHeadersConfigSchema>;
173
+ export type LangfuseTracingConfig = z.infer<typeof LangfuseTracingConfigSchema>;
173
174
  export declare const PluginConfigSchema: z.ZodObject<{
174
175
  preset: z.ZodOptional<z.ZodString>;
175
176
  scoringEngineVersion: z.ZodOptional<z.ZodEnum<{
@@ -303,9 +304,10 @@ export declare const PluginConfigSchema: z.ZodObject<{
303
304
  double_confirmation: z.ZodOptional<z.ZodObject<{
304
305
  enabled: z.ZodDefault<z.ZodBoolean>;
305
306
  }, z.core.$strip>>;
306
- langfuse_headers: z.ZodOptional<z.ZodObject<{
307
+ langfuse_tracing: z.ZodOptional<z.ZodObject<{
307
308
  enabled: z.ZodDefault<z.ZodBoolean>;
308
- customHeaders: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
309
+ traceUserId: z.ZodDefault<z.ZodString>;
310
+ customMetadata: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
309
311
  }, z.core.$strip>>;
310
312
  }, z.core.$strip>;
311
313
  export type PluginConfig = z.infer<typeof PluginConfigSchema>;
@@ -6,7 +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 { createLangfuseHeadersHook } from './langfuse-headers';
9
+ export { createLangfuseTracingHook } from './langfuse-tracing';
10
10
  export { createPhaseReminderHook } from './phase-reminder';
11
11
  export { createPostReadNudgeHook } from './post-read-nudge';
12
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,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,9 +17104,10 @@ var HashlineEditConfigSchema = exports_external.object({
17104
17104
  var DoubleConfirmationConfigSchema = exports_external.object({
17105
17105
  enabled: exports_external.boolean().default(false)
17106
17106
  });
17107
- var LangfuseHeadersConfigSchema = exports_external.object({
17107
+ var LangfuseTracingConfigSchema = exports_external.object({
17108
17108
  enabled: exports_external.boolean().default(false),
17109
- customHeaders: exports_external.record(exports_external.string(), exports_external.string()).default({})
17109
+ traceUserId: exports_external.string().default("opencode"),
17110
+ customMetadata: exports_external.record(exports_external.string(), exports_external.unknown()).default({})
17110
17111
  });
17111
17112
  var PluginConfigSchema = exports_external.object({
17112
17113
  preset: exports_external.string().optional(),
@@ -17123,7 +17124,7 @@ var PluginConfigSchema = exports_external.object({
17123
17124
  sessionExport: SessionExportConfigSchema.optional(),
17124
17125
  hashline_edit: HashlineEditConfigSchema.optional(),
17125
17126
  double_confirmation: DoubleConfirmationConfigSchema.optional(),
17126
- langfuse_headers: LangfuseHeadersConfigSchema.optional()
17127
+ langfuse_tracing: LangfuseTracingConfigSchema.optional()
17127
17128
  });
17128
17129
 
17129
17130
  // src/config/loader.ts
@@ -23149,7 +23150,7 @@ ${JSON_ERROR_REMINDER}`;
23149
23150
  }
23150
23151
  };
23151
23152
  }
23152
- // src/hooks/langfuse-headers/index.ts
23153
+ // src/hooks/langfuse-common.ts
23153
23154
  var AGENT_TASK_MAP = {
23154
23155
  orchestrator: "planning",
23155
23156
  explorer: "research",
@@ -23157,46 +23158,63 @@ var AGENT_TASK_MAP = {
23157
23158
  designer: "design",
23158
23159
  librarian: "research",
23159
23160
  oracle: "analysis",
23160
- build: "coding",
23161
23161
  verification: "verification",
23162
23162
  "pre-flight": "planning",
23163
23163
  contractor: "planning",
23164
- groundcontrol: "planning",
23165
- "power-slap-red": "coding",
23166
- "power-slap-blue": "coding",
23167
- "power-slap-green": "coding"
23164
+ groundcontrol: "planning"
23168
23165
  };
23169
- function createLangfuseHeadersHook(config2) {
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) {
23170
23183
  const enabled = config2?.enabled ?? false;
23171
- const customHeaders = config2?.customHeaders ?? {};
23184
+ const traceUserId = config2?.traceUserId ?? "opencode";
23185
+ const customMetadata = config2?.customMetadata ?? {};
23172
23186
  const pluginVersion = getCachedVersion() ?? "unknown";
23173
23187
  return {
23174
- "chat.headers": async (input, output) => {
23188
+ "chat.params": async (input, output) => {
23175
23189
  if (!enabled)
23176
23190
  return;
23177
23191
  try {
23178
- const dynamic = {
23179
- "X-OC-App": "opencode",
23180
- "X-OC-Agent": input.agent || undefined,
23181
- "X-OC-Task": input.agent && AGENT_TASK_MAP[input.agent] || (input.agent ? "general" : undefined),
23182
- "X-OC-Session-Id": input.sessionID || undefined,
23183
- "X-OC-Model": input.model?.id || undefined,
23184
- "X-OC-Provider": input.model?.providerID || undefined,
23185
- "X-OC-Plugin-Version": pluginVersion || undefined,
23186
- "X-OC-Prompt-Version": "opencode-default"
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
23187
23204
  };
23188
- for (const [key, value] of Object.entries(dynamic)) {
23189
- if (value) {
23190
- output.headers[key] = value;
23205
+ for (const [key, value] of Object.entries(customMetadata)) {
23206
+ if (value !== undefined && value !== null) {
23207
+ metadata[key] = value;
23191
23208
  }
23192
23209
  }
23193
- for (const [key, value] of Object.entries(customHeaders)) {
23194
- if (value) {
23195
- output.headers[key] = value;
23210
+ for (const key of Object.keys(metadata)) {
23211
+ if (metadata[key] === undefined) {
23212
+ delete metadata[key];
23196
23213
  }
23197
23214
  }
23215
+ output.options.metadata = metadata;
23198
23216
  } catch (err) {
23199
- log("[langfuse-headers] Error injecting headers:", err);
23217
+ log("[langfuse-tracing] Error injecting metadata:", err);
23200
23218
  }
23201
23219
  }
23202
23220
  };
@@ -39416,7 +39434,7 @@ var OhMyGroundControl = async (ctx) => {
39416
39434
  const hashlineReadEnhancerHook = createHashlineReadEnhancerHook(config3.hashline_edit);
39417
39435
  const editErrorRecoveryHook = createEditErrorRecoveryHook();
39418
39436
  const doubleConfirmationHook = createDoubleConfirmationHook(config3.double_confirmation);
39419
- const langfuseHeadersHook = createLangfuseHeadersHook(config3.langfuse_headers);
39437
+ const langfuseTracingHook = createLangfuseTracingHook(config3.langfuse_tracing);
39420
39438
  const hashlineEditEnabled = config3.hashline_edit?.enabled !== false;
39421
39439
  const hashlineEditTool = hashlineEditEnabled ? createHashlineEditTool() : undefined;
39422
39440
  return {
@@ -39521,7 +39539,7 @@ var OhMyGroundControl = async (ctx) => {
39521
39539
  "experimental.chat.messages.transform": phaseReminderHook["experimental.chat.messages.transform"],
39522
39540
  "chat.message": questionRouterHook["chat.message"],
39523
39541
  "command.execute.before": analyzeCommandHook["command.execute.before"],
39524
- "chat.headers": langfuseHeadersHook["chat.headers"],
39542
+ "chat.params": langfuseTracingHook["chat.params"],
39525
39543
  "tool.execute.after": async (input, output) => {
39526
39544
  await delegateTaskRetryHook["tool.execute.after"](input, output);
39527
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.20",
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",