@getverbal/cli 0.4.3 → 0.6.0

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.
Files changed (249) hide show
  1. package/dist/agent-hooks/claude.d.ts +10 -0
  2. package/dist/agent-hooks/claude.d.ts.map +1 -0
  3. package/dist/agent-hooks/claude.js +218 -0
  4. package/dist/agent-hooks/claude.js.map +1 -0
  5. package/dist/agent-hooks/cli.d.ts +2 -0
  6. package/dist/agent-hooks/cli.d.ts.map +1 -0
  7. package/dist/agent-hooks/cli.js +271 -0
  8. package/dist/agent-hooks/cli.js.map +1 -0
  9. package/dist/agent-hooks/codex.d.ts +9 -0
  10. package/dist/agent-hooks/codex.d.ts.map +1 -0
  11. package/dist/agent-hooks/codex.js +349 -0
  12. package/dist/agent-hooks/codex.js.map +1 -0
  13. package/dist/agent-hooks/config.d.ts +32 -0
  14. package/dist/agent-hooks/config.d.ts.map +1 -0
  15. package/dist/agent-hooks/config.js +176 -0
  16. package/dist/agent-hooks/config.js.map +1 -0
  17. package/dist/agent-hooks/ingest.d.ts +4 -0
  18. package/dist/agent-hooks/ingest.d.ts.map +1 -0
  19. package/dist/agent-hooks/ingest.js +22 -0
  20. package/dist/agent-hooks/ingest.js.map +1 -0
  21. package/dist/agent-hooks/launchagent.d.ts +7 -0
  22. package/dist/agent-hooks/launchagent.d.ts.map +1 -0
  23. package/dist/agent-hooks/launchagent.js +51 -0
  24. package/dist/agent-hooks/launchagent.js.map +1 -0
  25. package/dist/agent-hooks/runtime-context.d.ts +20 -0
  26. package/dist/agent-hooks/runtime-context.d.ts.map +1 -0
  27. package/dist/agent-hooks/runtime-context.js +90 -0
  28. package/dist/agent-hooks/runtime-context.js.map +1 -0
  29. package/dist/agent-hooks/state.d.ts +26 -0
  30. package/dist/agent-hooks/state.d.ts.map +1 -0
  31. package/dist/agent-hooks/state.js +67 -0
  32. package/dist/agent-hooks/state.js.map +1 -0
  33. package/dist/agent-hooks/tokscale.d.ts +70 -0
  34. package/dist/agent-hooks/tokscale.d.ts.map +1 -0
  35. package/dist/agent-hooks/tokscale.js +142 -0
  36. package/dist/agent-hooks/tokscale.js.map +1 -0
  37. package/dist/agent-hooks/tool-extraction.d.ts +7 -0
  38. package/dist/agent-hooks/tool-extraction.d.ts.map +1 -0
  39. package/dist/agent-hooks/tool-extraction.js +100 -0
  40. package/dist/agent-hooks/tool-extraction.js.map +1 -0
  41. package/dist/agent-hooks/trace.d.ts +17 -0
  42. package/dist/agent-hooks/trace.d.ts.map +1 -0
  43. package/dist/agent-hooks/trace.js +25 -0
  44. package/dist/agent-hooks/trace.js.map +1 -0
  45. package/dist/auth/browser-auth.d.ts +6 -0
  46. package/dist/auth/browser-auth.d.ts.map +1 -0
  47. package/dist/auth/browser-auth.js +202 -0
  48. package/dist/auth/browser-auth.js.map +1 -0
  49. package/dist/auth/credentials.d.ts +6 -0
  50. package/dist/auth/credentials.d.ts.map +1 -0
  51. package/dist/auth/credentials.js +78 -0
  52. package/dist/auth/credentials.js.map +1 -0
  53. package/dist/cli.d.ts +3 -0
  54. package/dist/cli.d.ts.map +1 -0
  55. package/dist/cli.js +1513 -440
  56. package/dist/cli.js.map +1 -0
  57. package/dist/commands/dashboard.d.ts +2 -0
  58. package/dist/commands/dashboard.d.ts.map +1 -0
  59. package/dist/commands/dashboard.js +19 -0
  60. package/dist/commands/dashboard.js.map +1 -0
  61. package/dist/commands/hooks.d.ts +2 -0
  62. package/dist/commands/hooks.d.ts.map +1 -0
  63. package/dist/commands/hooks.js +6 -0
  64. package/dist/commands/hooks.js.map +1 -0
  65. package/dist/commands/import.d.ts +2 -0
  66. package/dist/commands/import.d.ts.map +1 -0
  67. package/dist/commands/import.js +129 -0
  68. package/dist/commands/import.js.map +1 -0
  69. package/dist/commands/init.d.ts +2 -0
  70. package/dist/commands/init.d.ts.map +1 -0
  71. package/dist/commands/init.js +262 -0
  72. package/dist/commands/init.js.map +1 -0
  73. package/dist/commands/logout.d.ts +2 -0
  74. package/dist/commands/logout.d.ts.map +1 -0
  75. package/dist/commands/logout.js +17 -0
  76. package/dist/commands/logout.js.map +1 -0
  77. package/dist/commands/mcp-serve.d.ts +2 -0
  78. package/dist/commands/mcp-serve.d.ts.map +1 -0
  79. package/dist/commands/mcp-serve.js +7 -0
  80. package/dist/commands/mcp-serve.js.map +1 -0
  81. package/dist/commands/status.d.ts +2 -0
  82. package/dist/commands/status.d.ts.map +1 -0
  83. package/dist/commands/status.js +43 -0
  84. package/dist/commands/status.js.map +1 -0
  85. package/dist/commands/uninstall.d.ts +2 -0
  86. package/dist/commands/uninstall.d.ts.map +1 -0
  87. package/dist/commands/uninstall.js +43 -0
  88. package/dist/commands/uninstall.js.map +1 -0
  89. package/dist/commands/update.d.ts +2 -0
  90. package/dist/commands/update.d.ts.map +1 -0
  91. package/dist/commands/update.js +58 -0
  92. package/dist/commands/update.js.map +1 -0
  93. package/dist/configure/claude-code.d.ts +7 -0
  94. package/dist/configure/claude-code.d.ts.map +1 -0
  95. package/dist/configure/claude-code.js +11 -0
  96. package/dist/configure/claude-code.js.map +1 -0
  97. package/dist/configure/claude-desktop.d.ts +8 -0
  98. package/dist/configure/claude-desktop.d.ts.map +1 -0
  99. package/dist/configure/claude-desktop.js +28 -0
  100. package/dist/configure/claude-desktop.js.map +1 -0
  101. package/dist/configure/codex.d.ts +7 -0
  102. package/dist/configure/codex.d.ts.map +1 -0
  103. package/dist/configure/codex.js +12 -0
  104. package/dist/configure/codex.js.map +1 -0
  105. package/dist/configure/cursor.d.ts +7 -0
  106. package/dist/configure/cursor.d.ts.map +1 -0
  107. package/dist/configure/cursor.js +12 -0
  108. package/dist/configure/cursor.js.map +1 -0
  109. package/dist/configure/index.d.ts +34 -0
  110. package/dist/configure/index.d.ts.map +1 -0
  111. package/dist/configure/index.js +153 -0
  112. package/dist/configure/index.js.map +1 -0
  113. package/dist/detect/claude-code.d.ts +3 -0
  114. package/dist/detect/claude-code.d.ts.map +1 -0
  115. package/dist/detect/claude-code.js +82 -0
  116. package/dist/detect/claude-code.js.map +1 -0
  117. package/dist/detect/claude-desktop.d.ts +3 -0
  118. package/dist/detect/claude-desktop.d.ts.map +1 -0
  119. package/dist/detect/claude-desktop.js +89 -0
  120. package/dist/detect/claude-desktop.js.map +1 -0
  121. package/dist/detect/codex.d.ts +3 -0
  122. package/dist/detect/codex.d.ts.map +1 -0
  123. package/dist/detect/codex.js +64 -0
  124. package/dist/detect/codex.js.map +1 -0
  125. package/dist/detect/cursor.d.ts +3 -0
  126. package/dist/detect/cursor.d.ts.map +1 -0
  127. package/dist/detect/cursor.js +81 -0
  128. package/dist/detect/cursor.js.map +1 -0
  129. package/dist/detect/index.d.ts +3 -0
  130. package/dist/detect/index.d.ts.map +1 -0
  131. package/dist/detect/index.js +28 -0
  132. package/dist/detect/index.js.map +1 -0
  133. package/dist/import/file-upload.d.ts +10 -0
  134. package/dist/import/file-upload.d.ts.map +1 -0
  135. package/dist/import/file-upload.js +37 -0
  136. package/dist/import/file-upload.js.map +1 -0
  137. package/dist/import/index.d.ts +11 -0
  138. package/dist/import/index.d.ts.map +1 -0
  139. package/dist/import/index.js +51 -0
  140. package/dist/import/index.js.map +1 -0
  141. package/dist/mcp/exports.d.ts +13 -0
  142. package/dist/mcp/exports.d.ts.map +1 -0
  143. package/dist/mcp/exports.js +13 -0
  144. package/dist/mcp/exports.js.map +1 -0
  145. package/dist/mcp/git-context.d.ts +17 -0
  146. package/dist/mcp/git-context.d.ts.map +1 -0
  147. package/dist/mcp/git-context.js +72 -0
  148. package/dist/mcp/git-context.js.map +1 -0
  149. package/dist/mcp/hooks/anthropic.d.ts +31 -0
  150. package/dist/mcp/hooks/anthropic.d.ts.map +1 -0
  151. package/dist/mcp/hooks/anthropic.js +137 -0
  152. package/dist/mcp/hooks/anthropic.js.map +1 -0
  153. package/dist/mcp/hooks/google.d.ts +53 -0
  154. package/dist/mcp/hooks/google.d.ts.map +1 -0
  155. package/dist/mcp/hooks/google.js +161 -0
  156. package/dist/mcp/hooks/google.js.map +1 -0
  157. package/dist/mcp/hooks/index.d.ts +9 -0
  158. package/dist/mcp/hooks/index.d.ts.map +1 -0
  159. package/dist/mcp/hooks/index.js +7 -0
  160. package/dist/mcp/hooks/index.js.map +1 -0
  161. package/dist/mcp/hooks/openai.d.ts +59 -0
  162. package/dist/mcp/hooks/openai.d.ts.map +1 -0
  163. package/dist/mcp/hooks/openai.js +158 -0
  164. package/dist/mcp/hooks/openai.js.map +1 -0
  165. package/dist/mcp/hooks/types.d.ts +8 -0
  166. package/dist/mcp/hooks/types.d.ts.map +1 -0
  167. package/dist/mcp/hooks/types.js +5 -0
  168. package/dist/mcp/hooks/types.js.map +1 -0
  169. package/dist/mcp/ingestor.d.ts +23 -0
  170. package/dist/mcp/ingestor.d.ts.map +1 -0
  171. package/dist/mcp/ingestor.js +310 -0
  172. package/dist/mcp/ingestor.js.map +1 -0
  173. package/dist/mcp/pricing.d.ts +19 -0
  174. package/dist/mcp/pricing.d.ts.map +1 -0
  175. package/dist/mcp/pricing.js +130 -0
  176. package/dist/mcp/pricing.js.map +1 -0
  177. package/dist/mcp/server.d.ts +10 -0
  178. package/dist/mcp/server.d.ts.map +1 -0
  179. package/dist/mcp/server.js +689 -0
  180. package/dist/mcp/server.js.map +1 -0
  181. package/dist/mcp/session-tracker.d.ts +52 -0
  182. package/dist/mcp/session-tracker.d.ts.map +1 -0
  183. package/dist/mcp/session-tracker.js +186 -0
  184. package/dist/mcp/session-tracker.js.map +1 -0
  185. package/dist/mcp/tools/analyze-spending-trend.d.ts +10 -0
  186. package/dist/mcp/tools/analyze-spending-trend.d.ts.map +1 -0
  187. package/dist/mcp/tools/analyze-spending-trend.js +126 -0
  188. package/dist/mcp/tools/analyze-spending-trend.js.map +1 -0
  189. package/dist/mcp/tools/get-budget-status.d.ts +9 -0
  190. package/dist/mcp/tools/get-budget-status.d.ts.map +1 -0
  191. package/dist/mcp/tools/get-budget-status.js +59 -0
  192. package/dist/mcp/tools/get-budget-status.js.map +1 -0
  193. package/dist/mcp/tools/get-cost-breakdown.d.ts +10 -0
  194. package/dist/mcp/tools/get-cost-breakdown.d.ts.map +1 -0
  195. package/dist/mcp/tools/get-cost-breakdown.js +52 -0
  196. package/dist/mcp/tools/get-cost-breakdown.js.map +1 -0
  197. package/dist/mcp/tools/get-model-efficiency.d.ts +9 -0
  198. package/dist/mcp/tools/get-model-efficiency.d.ts.map +1 -0
  199. package/dist/mcp/tools/get-model-efficiency.js +137 -0
  200. package/dist/mcp/tools/get-model-efficiency.js.map +1 -0
  201. package/dist/mcp/tools/get-recent-prompts.d.ts +13 -0
  202. package/dist/mcp/tools/get-recent-prompts.d.ts.map +1 -0
  203. package/dist/mcp/tools/get-recent-prompts.js +56 -0
  204. package/dist/mcp/tools/get-recent-prompts.js.map +1 -0
  205. package/dist/mcp/tools/get-roi-metrics.d.ts +9 -0
  206. package/dist/mcp/tools/get-roi-metrics.d.ts.map +1 -0
  207. package/dist/mcp/tools/get-roi-metrics.js +84 -0
  208. package/dist/mcp/tools/get-roi-metrics.js.map +1 -0
  209. package/dist/mcp/tools/get-usage-summary.d.ts +10 -0
  210. package/dist/mcp/tools/get-usage-summary.d.ts.map +1 -0
  211. package/dist/mcp/tools/get-usage-summary.js +47 -0
  212. package/dist/mcp/tools/get-usage-summary.js.map +1 -0
  213. package/dist/mcp/tools/index.d.ts +221 -0
  214. package/dist/mcp/tools/index.d.ts.map +1 -0
  215. package/dist/mcp/tools/index.js +161 -0
  216. package/dist/mcp/tools/index.js.map +1 -0
  217. package/dist/mcp/tools/list-projects.d.ts +6 -0
  218. package/dist/mcp/tools/list-projects.d.ts.map +1 -0
  219. package/dist/mcp/tools/list-projects.js +43 -0
  220. package/dist/mcp/tools/list-projects.js.map +1 -0
  221. package/dist/mcp/tools/optimize-prompt.d.ts +44 -0
  222. package/dist/mcp/tools/optimize-prompt.d.ts.map +1 -0
  223. package/dist/mcp/tools/optimize-prompt.js +95 -0
  224. package/dist/mcp/tools/optimize-prompt.js.map +1 -0
  225. package/dist/mcp/types.d.ts +118 -0
  226. package/dist/mcp/types.d.ts.map +1 -0
  227. package/dist/mcp/types.js +5 -0
  228. package/dist/mcp/types.js.map +1 -0
  229. package/dist/types.d.ts +18 -0
  230. package/dist/types.d.ts.map +1 -0
  231. package/dist/types.js +2 -0
  232. package/dist/types.js.map +1 -0
  233. package/dist/update-check/check.d.ts +6 -0
  234. package/dist/update-check/check.d.ts.map +1 -0
  235. package/dist/update-check/check.js +64 -0
  236. package/dist/update-check/check.js.map +1 -0
  237. package/dist/update-check/notify.d.ts +6 -0
  238. package/dist/update-check/notify.d.ts.map +1 -0
  239. package/dist/update-check/notify.js +40 -0
  240. package/dist/update-check/notify.js.map +1 -0
  241. package/dist/verify.d.ts +7 -0
  242. package/dist/verify.d.ts.map +1 -0
  243. package/dist/verify.js +40 -0
  244. package/dist/verify.js.map +1 -0
  245. package/dist/version.d.ts +9 -0
  246. package/dist/version.d.ts.map +1 -0
  247. package/dist/version.js +21 -0
  248. package/dist/version.js.map +1 -0
  249. package/package.json +10 -5
@@ -0,0 +1,137 @@
1
+ /**
2
+ * Anthropic SDK hook adapter using custom fetch middleware
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * import Anthropic from '@anthropic-ai/sdk';
7
+ * import { createAnthropicHook } from '@verbal/mcp-service/hooks/anthropic';
8
+ *
9
+ * const trackedFetch = createAnthropicHook(ingestor);
10
+ * const client = new Anthropic({
11
+ * apiKey: process.env.ANTHROPIC_API_KEY,
12
+ * fetch: trackedFetch,
13
+ * });
14
+ * ```
15
+ */
16
+ export function createAnthropicHook(tracker) {
17
+ return async (url, init) => {
18
+ const startTime = Date.now();
19
+ let requestBody = null;
20
+ // Capture request body for prompt extraction
21
+ if (init?.body && typeof init.body === 'string') {
22
+ try {
23
+ requestBody = JSON.parse(init.body);
24
+ }
25
+ catch {
26
+ // Ignore parse errors
27
+ }
28
+ }
29
+ // Call original fetch
30
+ const response = await fetch(url, init);
31
+ // Only track API calls to Anthropic
32
+ const urlString = typeof url === 'string' ? url : url instanceof URL ? url.href : url.url;
33
+ if (!urlString.includes('anthropic.com/v1/messages')) {
34
+ return response;
35
+ }
36
+ // Clone response to read body without consuming it
37
+ const clonedResponse = response.clone();
38
+ try {
39
+ const responseBody = await clonedResponse.json();
40
+ // Only track successful responses with usage metadata
41
+ if (response.ok && responseBody.usage) {
42
+ const promptContent = extractPromptContent(requestBody);
43
+ const responseContent = extractResponseContent(responseBody);
44
+ const usage = responseBody.usage;
45
+ await tracker.track({
46
+ event_type: 'prompt',
47
+ provider: 'anthropic',
48
+ model: responseBody.model,
49
+ tokens_in: usage.input_tokens,
50
+ tokens_out: usage.output_tokens,
51
+ total_tokens: usage.input_tokens + usage.output_tokens,
52
+ duration_ms: Date.now() - startTime,
53
+ request_id: responseBody.id,
54
+ prompt: promptContent,
55
+ response: responseContent,
56
+ });
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.warn('[AnthropicHook] Failed to track usage:', error);
61
+ }
62
+ return response;
63
+ };
64
+ }
65
+ /**
66
+ * Extract prompt content from Anthropic request body
67
+ */
68
+ function extractPromptContent(body) {
69
+ if (!body || !body.messages)
70
+ return undefined;
71
+ const messages = body.messages;
72
+ const parts = [];
73
+ // Include system prompt if present
74
+ if (typeof body.system === 'string') {
75
+ parts.push(body.system);
76
+ }
77
+ for (const msg of messages) {
78
+ if (typeof msg.content === 'string') {
79
+ parts.push(msg.content);
80
+ }
81
+ else if (Array.isArray(msg.content)) {
82
+ for (const block of msg.content) {
83
+ if (block.type === 'text' && typeof block.text === 'string') {
84
+ parts.push(block.text);
85
+ }
86
+ }
87
+ }
88
+ }
89
+ return parts.length > 0 ? parts.join('\n') : undefined;
90
+ }
91
+ /**
92
+ * Extract response content from Anthropic response body
93
+ */
94
+ function extractResponseContent(body) {
95
+ if (!body.content || !Array.isArray(body.content))
96
+ return undefined;
97
+ return body.content
98
+ .filter((block) => block.type === 'text' && block.text)
99
+ .map((block) => block.text)
100
+ .join('');
101
+ }
102
+ /**
103
+ * Hook for Anthropic streaming responses using event listeners
104
+ *
105
+ * Usage:
106
+ * ```ts
107
+ * const stream = await client.messages.stream({...});
108
+ * attachStreamHooks(stream, ingestor, promptContent);
109
+ * ```
110
+ */
111
+ export function attachAnthropicStreamHooks(stream, tracker, promptContent, startTime = Date.now()) {
112
+ stream.on('message', (message) => {
113
+ const msg = message;
114
+ if (msg.usage) {
115
+ const responseContent = msg.content
116
+ ?.filter((block) => block.type === 'text' && block.text)
117
+ .map((block) => block.text)
118
+ .join('');
119
+ tracker.track({
120
+ event_type: 'prompt',
121
+ provider: 'anthropic',
122
+ model: msg.model,
123
+ tokens_in: msg.usage.input_tokens,
124
+ tokens_out: msg.usage.output_tokens,
125
+ total_tokens: msg.usage.input_tokens + msg.usage.output_tokens,
126
+ duration_ms: Date.now() - startTime,
127
+ request_id: msg.id,
128
+ prompt: promptContent,
129
+ response: responseContent,
130
+ });
131
+ }
132
+ });
133
+ stream.on('error', (error) => {
134
+ console.error('[AnthropicStreamHook] Stream error:', error);
135
+ });
136
+ }
137
+ //# sourceMappingURL=anthropic.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anthropic.js","sourceRoot":"","sources":["../../../src/mcp/hooks/anthropic.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Google Generative AI SDK hook adapter using custom fetch middleware
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * import { GoogleGenerativeAI } from '@google/generative-ai';
7
+ * import { createGoogleHook } from '@verbal/mcp-service/hooks/google';
8
+ *
9
+ * const trackedFetch = createGoogleHook(ingestor);
10
+ * const genai = new GoogleGenerativeAI({
11
+ * apiKey: process.env.GOOGLE_API_KEY,
12
+ * fetch: trackedFetch,
13
+ * });
14
+ * ```
15
+ */
16
+ import type { HookTracker } from './types.js';
17
+ export declare function createGoogleHook(tracker: HookTracker): typeof fetch;
18
+ /**
19
+ * OpenTelemetry-based tracking for Google AI (advanced)
20
+ *
21
+ * Usage:
22
+ * ```ts
23
+ * import { trace } from '@opentelemetry/api';
24
+ * import { trackGoogleWithOTel } from '@verbal/mcp-service/hooks/google';
25
+ *
26
+ * const tracer = trace.getTracer('gemini-client');
27
+ * const result = await trackGoogleWithOTel(
28
+ * tracer,
29
+ * ingestor,
30
+ * model,
31
+ * async () => model.generateContent(prompt)
32
+ * );
33
+ * ```
34
+ */
35
+ export declare function trackGoogleWithOTel<T extends {
36
+ response: {
37
+ usageMetadata?: {
38
+ promptTokenCount?: number;
39
+ candidatesTokenCount?: number;
40
+ totalTokenCount?: number;
41
+ };
42
+ };
43
+ }>(tracer: {
44
+ startSpan(name: string): {
45
+ setAttributes(attributes: Record<string, unknown>): void;
46
+ setStatus(status: {
47
+ code: number;
48
+ }): void;
49
+ recordException(error: Error): void;
50
+ end(): void;
51
+ };
52
+ }, tracker: HookTracker, modelName: string, operation: () => Promise<T>): Promise<T>;
53
+ //# sourceMappingURL=google.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.d.ts","sourceRoot":"","sources":["../../../src/mcp/hooks/google.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,KAAK,CAwDnE;AA0DD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,SAAS;IAAE,QAAQ,EAAE;QAAE,aAAa,CAAC,EAAE;YAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;YAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;YAAC,eAAe,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAA;CAAE,EAC1K,MAAM,EAAE;IACN,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;QACvB,aAAa,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;QACzD,SAAS,CAAC,MAAM,EAAE;YAAE,IAAI,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAC;QAC1C,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;QACpC,GAAG,IAAI,IAAI,CAAC;KACb,CAAC;CACH,EACD,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAC1B,OAAO,CAAC,CAAC,CAAC,CAwCZ"}
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Google Generative AI SDK hook adapter using custom fetch middleware
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * import { GoogleGenerativeAI } from '@google/generative-ai';
7
+ * import { createGoogleHook } from '@verbal/mcp-service/hooks/google';
8
+ *
9
+ * const trackedFetch = createGoogleHook(ingestor);
10
+ * const genai = new GoogleGenerativeAI({
11
+ * apiKey: process.env.GOOGLE_API_KEY,
12
+ * fetch: trackedFetch,
13
+ * });
14
+ * ```
15
+ */
16
+ export function createGoogleHook(tracker) {
17
+ return async (url, init) => {
18
+ const startTime = Date.now();
19
+ let requestBody = null;
20
+ // Capture request body for prompt extraction
21
+ if (init?.body && typeof init.body === 'string') {
22
+ try {
23
+ requestBody = JSON.parse(init.body);
24
+ }
25
+ catch {
26
+ // Ignore parse errors
27
+ }
28
+ }
29
+ // Call original fetch
30
+ const response = await fetch(url, init);
31
+ // Only track API calls to Google AI/Vertex AI
32
+ const urlString = typeof url === 'string' ? url : url instanceof URL ? url.href : url.url;
33
+ if (!urlString.includes('generativelanguage.googleapis.com') &&
34
+ !urlString.includes('aiplatform.googleapis.com')) {
35
+ return response;
36
+ }
37
+ // Clone response to read body without consuming it
38
+ const clonedResponse = response.clone();
39
+ try {
40
+ const responseBody = await clonedResponse.json();
41
+ // Only track successful responses with usage metadata
42
+ if (response.ok && responseBody.usageMetadata) {
43
+ const promptContent = extractPromptContent(requestBody);
44
+ const responseContent = extractResponseContent(responseBody);
45
+ const usage = responseBody.usageMetadata;
46
+ await tracker.track({
47
+ event_type: 'prompt',
48
+ provider: 'google',
49
+ model: extractModelName(urlString),
50
+ tokens_in: usage.promptTokenCount,
51
+ tokens_out: usage.candidatesTokenCount,
52
+ total_tokens: usage.totalTokenCount,
53
+ duration_ms: Date.now() - startTime,
54
+ prompt: promptContent,
55
+ response: responseContent,
56
+ });
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.warn('[GoogleHook] Failed to track usage:', error);
61
+ }
62
+ return response;
63
+ };
64
+ }
65
+ /**
66
+ * Extract model name from Google AI URL
67
+ */
68
+ function extractModelName(url) {
69
+ // URL format: .../models/{model-name}:generateContent
70
+ const match = url.match(/\/models\/([^/:]+)/);
71
+ return match ? match[1] : 'unknown';
72
+ }
73
+ /**
74
+ * Extract prompt content from Google AI request body
75
+ */
76
+ function extractPromptContent(body) {
77
+ if (!body || !body.contents)
78
+ return undefined;
79
+ const contents = body.contents;
80
+ const parts = [];
81
+ for (const content of contents) {
82
+ if (content.parts && Array.isArray(content.parts)) {
83
+ for (const part of content.parts) {
84
+ if (part.text) {
85
+ parts.push(part.text);
86
+ }
87
+ }
88
+ }
89
+ }
90
+ return parts.length > 0 ? parts.join('\n') : undefined;
91
+ }
92
+ /**
93
+ * Extract response content from Google AI response body
94
+ */
95
+ function extractResponseContent(body) {
96
+ if (!body.candidates || !Array.isArray(body.candidates) || body.candidates.length === 0) {
97
+ return undefined;
98
+ }
99
+ const candidate = body.candidates[0];
100
+ if (!candidate.content?.parts)
101
+ return undefined;
102
+ return candidate.content.parts
103
+ .filter((part) => part.text)
104
+ .map((part) => part.text)
105
+ .join('');
106
+ }
107
+ /**
108
+ * OpenTelemetry-based tracking for Google AI (advanced)
109
+ *
110
+ * Usage:
111
+ * ```ts
112
+ * import { trace } from '@opentelemetry/api';
113
+ * import { trackGoogleWithOTel } from '@verbal/mcp-service/hooks/google';
114
+ *
115
+ * const tracer = trace.getTracer('gemini-client');
116
+ * const result = await trackGoogleWithOTel(
117
+ * tracer,
118
+ * ingestor,
119
+ * model,
120
+ * async () => model.generateContent(prompt)
121
+ * );
122
+ * ```
123
+ */
124
+ export async function trackGoogleWithOTel(tracer, tracker, modelName, operation) {
125
+ const span = tracer.startSpan('gemini.generateContent');
126
+ const startTime = Date.now();
127
+ try {
128
+ const result = await operation();
129
+ const usage = result.response.usageMetadata;
130
+ if (usage) {
131
+ // Add usage to OTel span
132
+ span.setAttributes({
133
+ 'ai.provider': 'google',
134
+ 'ai.model': modelName,
135
+ 'ai.prompt_tokens': usage.promptTokenCount ?? 0,
136
+ 'ai.completion_tokens': usage.candidatesTokenCount ?? 0,
137
+ 'ai.total_tokens': usage.totalTokenCount ?? 0,
138
+ });
139
+ // Track in Verbal
140
+ await tracker.track({
141
+ event_type: 'usage',
142
+ provider: 'google',
143
+ model: modelName,
144
+ tokens_in: usage.promptTokenCount,
145
+ tokens_out: usage.candidatesTokenCount,
146
+ total_tokens: usage.totalTokenCount,
147
+ duration_ms: Date.now() - startTime,
148
+ });
149
+ }
150
+ span.setStatus({ code: 0 }); // OK
151
+ span.end();
152
+ return result;
153
+ }
154
+ catch (error) {
155
+ span.recordException(error);
156
+ span.setStatus({ code: 2 }); // ERROR
157
+ span.end();
158
+ throw error;
159
+ }
160
+ }
161
+ //# sourceMappingURL=google.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"google.js","sourceRoot":"","sources":["../../../src/mcp/hooks/google.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Hook adapters for native SDK integration
3
+ */
4
+ export { createAnthropicHook, attachAnthropicStreamHooks } from './anthropic.js';
5
+ export { createOpenAIHooks, createOpenAIFetchHook } from './openai.js';
6
+ export { createGoogleHook, trackGoogleWithOTel } from './google.js';
7
+ export type { HookTracker } from './types.js';
8
+ export type { OpenAIRunHooks } from './openai.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mcp/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Hook adapters for native SDK integration
3
+ */
4
+ export { createAnthropicHook, attachAnthropicStreamHooks } from './anthropic.js';
5
+ export { createOpenAIHooks, createOpenAIFetchHook } from './openai.js';
6
+ export { createGoogleHook, trackGoogleWithOTel } from './google.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * OpenAI Agents SDK hook adapter using RunHooks
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * import { Agent } from 'openai/agents';
7
+ * import { createOpenAIHooks } from '@verbal/mcp-service/hooks/openai';
8
+ *
9
+ * const agent = new Agent({
10
+ * name: 'my-agent',
11
+ * model: 'gpt-4o',
12
+ * hooks: createOpenAIHooks(ingestor),
13
+ * });
14
+ * ```
15
+ */
16
+ import type { HookTracker } from './types.js';
17
+ export interface OpenAIRunHooks {
18
+ onLLMGeneration?: (generation: {
19
+ id: string;
20
+ model: string;
21
+ usage: {
22
+ prompt_tokens: number;
23
+ completion_tokens: number;
24
+ total_tokens: number;
25
+ };
26
+ input: string;
27
+ output: string;
28
+ agentName?: string;
29
+ runId?: string;
30
+ }) => Promise<void>;
31
+ onToolCall?: (toolCall: {
32
+ name: string;
33
+ input: unknown;
34
+ output: unknown;
35
+ durationMs: number;
36
+ }) => Promise<void>;
37
+ onRunComplete?: (run: {
38
+ id: string;
39
+ totalCost: number;
40
+ totalTokens: number;
41
+ }) => Promise<void>;
42
+ }
43
+ export declare function createOpenAIHooks(tracker: HookTracker): OpenAIRunHooks;
44
+ /**
45
+ * Custom fetch hook for standard OpenAI client (non-Agents SDK)
46
+ *
47
+ * Usage:
48
+ * ```ts
49
+ * import OpenAI from 'openai';
50
+ * import { createOpenAIFetchHook } from '@verbal/mcp-service/hooks/openai';
51
+ *
52
+ * const client = new OpenAI({
53
+ * apiKey: process.env.OPENAI_API_KEY,
54
+ * fetch: createOpenAIFetchHook(ingestor),
55
+ * });
56
+ * ```
57
+ */
58
+ export declare function createOpenAIFetchHook(tracker: HookTracker): typeof fetch;
59
+ //# sourceMappingURL=openai.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/mcp/hooks/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,cAAc;IAC7B,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE;QAC7B,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE;YAAE,aAAa,EAAE,MAAM,CAAC;YAAC,iBAAiB,EAAE,MAAM,CAAC;YAAC,YAAY,EAAE,MAAM,CAAA;SAAE,CAAC;QAClF,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QACtB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,OAAO,CAAC;QACf,MAAM,EAAE,OAAO,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;KACpB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpB,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE;QACpB,EAAE,EAAE,MAAM,CAAC;QACX,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAkDtE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,KAAK,CAsDxE"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * OpenAI Agents SDK hook adapter using RunHooks
3
+ *
4
+ * Usage:
5
+ * ```ts
6
+ * import { Agent } from 'openai/agents';
7
+ * import { createOpenAIHooks } from '@verbal/mcp-service/hooks/openai';
8
+ *
9
+ * const agent = new Agent({
10
+ * name: 'my-agent',
11
+ * model: 'gpt-4o',
12
+ * hooks: createOpenAIHooks(ingestor),
13
+ * });
14
+ * ```
15
+ */
16
+ export function createOpenAIHooks(tracker) {
17
+ return {
18
+ onLLMGeneration: async (generation) => {
19
+ await tracker.track({
20
+ event_type: 'prompt',
21
+ provider: 'openai',
22
+ model: generation.model,
23
+ tokens_in: generation.usage.prompt_tokens,
24
+ tokens_out: generation.usage.completion_tokens,
25
+ total_tokens: generation.usage.total_tokens,
26
+ request_id: generation.id,
27
+ prompt: generation.input,
28
+ response: generation.output,
29
+ metadata: {
30
+ agent_name: generation.agentName,
31
+ run_id: generation.runId,
32
+ },
33
+ });
34
+ },
35
+ onToolCall: async (toolCall) => {
36
+ // Track tool usage as non-LLM event
37
+ await tracker.track({
38
+ event_type: 'usage',
39
+ provider: 'openai',
40
+ model: 'tool-execution',
41
+ tokens_in: 0,
42
+ tokens_out: 0,
43
+ total_tokens: 0,
44
+ duration_ms: toolCall.durationMs,
45
+ metadata: {
46
+ tool_name: toolCall.name,
47
+ tool_input: toolCall.input,
48
+ tool_output: toolCall.output,
49
+ tool_provenance: {
50
+ mcp_server: process.env.VERBAL_MCP_SERVER_NAME ?? 'verbal',
51
+ skill_name: process.env.VERBAL_ACTIVE_SKILL ?? null,
52
+ invocation_chain: process.env.VERBAL_INVOCATION_CHAIN ?? null,
53
+ },
54
+ },
55
+ });
56
+ },
57
+ onRunComplete: async (run) => {
58
+ // Optional: log aggregate metrics
59
+ console.log(`[OpenAIHook] Run ${run.id} complete: ${run.totalCost} cost, ${run.totalTokens} tokens`);
60
+ },
61
+ };
62
+ }
63
+ /**
64
+ * Custom fetch hook for standard OpenAI client (non-Agents SDK)
65
+ *
66
+ * Usage:
67
+ * ```ts
68
+ * import OpenAI from 'openai';
69
+ * import { createOpenAIFetchHook } from '@verbal/mcp-service/hooks/openai';
70
+ *
71
+ * const client = new OpenAI({
72
+ * apiKey: process.env.OPENAI_API_KEY,
73
+ * fetch: createOpenAIFetchHook(ingestor),
74
+ * });
75
+ * ```
76
+ */
77
+ export function createOpenAIFetchHook(tracker) {
78
+ return async (url, init) => {
79
+ const startTime = Date.now();
80
+ let requestBody = null;
81
+ // Capture request body for prompt extraction
82
+ if (init?.body && typeof init.body === 'string') {
83
+ try {
84
+ requestBody = JSON.parse(init.body);
85
+ }
86
+ catch {
87
+ // Ignore parse errors
88
+ }
89
+ }
90
+ // Call original fetch
91
+ const response = await fetch(url, init);
92
+ // Only track API calls to OpenAI
93
+ const urlString = typeof url === 'string' ? url : url instanceof URL ? url.href : url.url;
94
+ if (!urlString.includes('openai.com/v1/')) {
95
+ return response;
96
+ }
97
+ // Clone response to read body without consuming it
98
+ const clonedResponse = response.clone();
99
+ try {
100
+ const responseBody = await clonedResponse.json();
101
+ // Track chat completions and completions
102
+ if (response.ok && responseBody.usage) {
103
+ const promptContent = extractPromptContent(requestBody);
104
+ const responseContent = extractResponseContent(responseBody);
105
+ const usage = responseBody.usage;
106
+ await tracker.track({
107
+ event_type: 'prompt',
108
+ provider: 'openai',
109
+ model: responseBody.model,
110
+ tokens_in: usage.prompt_tokens,
111
+ tokens_out: usage.completion_tokens,
112
+ total_tokens: usage.total_tokens,
113
+ duration_ms: Date.now() - startTime,
114
+ request_id: responseBody.id,
115
+ prompt: promptContent,
116
+ response: responseContent,
117
+ });
118
+ }
119
+ }
120
+ catch (error) {
121
+ console.warn('[OpenAIFetchHook] Failed to track usage:', error);
122
+ }
123
+ return response;
124
+ };
125
+ }
126
+ /**
127
+ * Extract prompt content from OpenAI request body
128
+ */
129
+ function extractPromptContent(body) {
130
+ if (!body)
131
+ return undefined;
132
+ // Chat completions
133
+ if (body.messages && Array.isArray(body.messages)) {
134
+ return body.messages
135
+ .map((msg) => msg.content)
136
+ .filter(Boolean)
137
+ .join('\n');
138
+ }
139
+ // Legacy completions
140
+ if (body.prompt) {
141
+ if (typeof body.prompt === 'string')
142
+ return body.prompt;
143
+ if (Array.isArray(body.prompt))
144
+ return body.prompt.join('\n');
145
+ }
146
+ return undefined;
147
+ }
148
+ /**
149
+ * Extract response content from OpenAI response body
150
+ */
151
+ function extractResponseContent(body) {
152
+ if (!body.choices || !Array.isArray(body.choices) || body.choices.length === 0) {
153
+ return undefined;
154
+ }
155
+ const choice = body.choices[0];
156
+ return choice.message?.content ?? choice.text;
157
+ }
158
+ //# sourceMappingURL=openai.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/mcp/hooks/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Types for SDK hook adapters
3
+ */
4
+ import type { UsageEvent } from '../types.js';
5
+ export interface HookTracker {
6
+ track(event: UsageEvent): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/mcp/hooks/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACzC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types for SDK hook adapters
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/mcp/hooks/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}