@contextrail/code-review-agent 0.1.1-alpha.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.
- package/LICENSE +26 -0
- package/MODEL_RECOMMENDATIONS.md +178 -0
- package/README.md +177 -0
- package/dist/config/defaults.d.ts +72 -0
- package/dist/config/defaults.js +113 -0
- package/dist/config/index.d.ts +34 -0
- package/dist/config/index.js +89 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +603 -0
- package/dist/llm/factory.d.ts +21 -0
- package/dist/llm/factory.js +50 -0
- package/dist/llm/index.d.ts +3 -0
- package/dist/llm/index.js +2 -0
- package/dist/llm/service.d.ts +38 -0
- package/dist/llm/service.js +191 -0
- package/dist/llm/types.d.ts +119 -0
- package/dist/llm/types.js +1 -0
- package/dist/logging/logger.d.ts +9 -0
- package/dist/logging/logger.js +52 -0
- package/dist/mcp/client.d.ts +429 -0
- package/dist/mcp/client.js +173 -0
- package/dist/mcp/mcp-tools.d.ts +292 -0
- package/dist/mcp/mcp-tools.js +40 -0
- package/dist/mcp/token-validation.d.ts +31 -0
- package/dist/mcp/token-validation.js +57 -0
- package/dist/mcp/tools-provider.d.ts +18 -0
- package/dist/mcp/tools-provider.js +24 -0
- package/dist/observability/index.d.ts +2 -0
- package/dist/observability/index.js +1 -0
- package/dist/observability/metrics.d.ts +48 -0
- package/dist/observability/metrics.js +86 -0
- package/dist/orchestrator/agentic-orchestrator.d.ts +29 -0
- package/dist/orchestrator/agentic-orchestrator.js +136 -0
- package/dist/orchestrator/prompts.d.ts +25 -0
- package/dist/orchestrator/prompts.js +98 -0
- package/dist/orchestrator/validation.d.ts +2 -0
- package/dist/orchestrator/validation.js +7 -0
- package/dist/orchestrator/writer.d.ts +4 -0
- package/dist/orchestrator/writer.js +17 -0
- package/dist/output/aggregator.d.ts +30 -0
- package/dist/output/aggregator.js +132 -0
- package/dist/output/prompts.d.ts +32 -0
- package/dist/output/prompts.js +153 -0
- package/dist/output/schema.d.ts +1515 -0
- package/dist/output/schema.js +224 -0
- package/dist/output/writer.d.ts +31 -0
- package/dist/output/writer.js +120 -0
- package/dist/review-inputs/chunking.d.ts +29 -0
- package/dist/review-inputs/chunking.js +113 -0
- package/dist/review-inputs/diff-summary.d.ts +52 -0
- package/dist/review-inputs/diff-summary.js +83 -0
- package/dist/review-inputs/file-patterns.d.ts +40 -0
- package/dist/review-inputs/file-patterns.js +182 -0
- package/dist/review-inputs/filtering.d.ts +31 -0
- package/dist/review-inputs/filtering.js +53 -0
- package/dist/review-inputs/git-diff-provider.d.ts +2 -0
- package/dist/review-inputs/git-diff-provider.js +42 -0
- package/dist/review-inputs/index.d.ts +46 -0
- package/dist/review-inputs/index.js +122 -0
- package/dist/review-inputs/path-validation.d.ts +10 -0
- package/dist/review-inputs/path-validation.js +37 -0
- package/dist/review-inputs/surrounding-context.d.ts +35 -0
- package/dist/review-inputs/surrounding-context.js +180 -0
- package/dist/review-inputs/triage.d.ts +57 -0
- package/dist/review-inputs/triage.js +81 -0
- package/dist/reviewers/executor.d.ts +41 -0
- package/dist/reviewers/executor.js +357 -0
- package/dist/reviewers/findings-merge.d.ts +9 -0
- package/dist/reviewers/findings-merge.js +131 -0
- package/dist/reviewers/iteration.d.ts +17 -0
- package/dist/reviewers/iteration.js +95 -0
- package/dist/reviewers/persistence.d.ts +17 -0
- package/dist/reviewers/persistence.js +55 -0
- package/dist/reviewers/progress-tracker.d.ts +115 -0
- package/dist/reviewers/progress-tracker.js +194 -0
- package/dist/reviewers/prompt.d.ts +42 -0
- package/dist/reviewers/prompt.js +246 -0
- package/dist/reviewers/tool-call-tracker.d.ts +18 -0
- package/dist/reviewers/tool-call-tracker.js +40 -0
- package/dist/reviewers/types.d.ts +12 -0
- package/dist/reviewers/types.js +1 -0
- package/dist/reviewers/validation-rules.d.ts +27 -0
- package/dist/reviewers/validation-rules.js +189 -0
- package/package.json +79 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ModelMessage } from 'ai';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
import type { LlmCallResult, LlmCallConfig, ModelProvider, ToolsProvider, LlmObservabilityHooks } from './types.js';
|
|
4
|
+
import type { Logger } from '../logging/logger.js';
|
|
5
|
+
/**
|
|
6
|
+
* LLM Service abstraction layer.
|
|
7
|
+
* Provides a predictable contract for LLM calls with built-in observability.
|
|
8
|
+
*/
|
|
9
|
+
export declare class LlmService {
|
|
10
|
+
private modelProvider;
|
|
11
|
+
private toolsProvider?;
|
|
12
|
+
private hooks?;
|
|
13
|
+
private logger?;
|
|
14
|
+
constructor(config: {
|
|
15
|
+
modelProvider: ModelProvider;
|
|
16
|
+
toolsProvider?: ToolsProvider;
|
|
17
|
+
hooks?: LlmObservabilityHooks;
|
|
18
|
+
logger?: Logger;
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Execute an LLM call with structured output.
|
|
22
|
+
*
|
|
23
|
+
* @param messages - Conversation messages
|
|
24
|
+
* @param schema - Zod schema for structured output
|
|
25
|
+
* @param config - LLM call configuration
|
|
26
|
+
* @returns Structured output with usage metrics and metadata
|
|
27
|
+
*/
|
|
28
|
+
generateStructuredOutput<T extends z.ZodType>(messages: ModelMessage[], schema: T, config: LlmCallConfig): Promise<LlmCallResult<z.infer<T>>>;
|
|
29
|
+
/**
|
|
30
|
+
* Create a new LLM service instance with updated configuration.
|
|
31
|
+
* Useful for creating service instances with different tools or hooks.
|
|
32
|
+
*/
|
|
33
|
+
withConfig(config: {
|
|
34
|
+
toolsProvider?: ToolsProvider;
|
|
35
|
+
hooks?: LlmObservabilityHooks;
|
|
36
|
+
logger?: Logger;
|
|
37
|
+
}): LlmService;
|
|
38
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { generateText, Output, stepCountIs } from 'ai';
|
|
2
|
+
import { DEFAULT_TEMPERATURE } from '../config/defaults.js';
|
|
3
|
+
/**
|
|
4
|
+
* LLM Service abstraction layer.
|
|
5
|
+
* Provides a predictable contract for LLM calls with built-in observability.
|
|
6
|
+
*/
|
|
7
|
+
export class LlmService {
|
|
8
|
+
modelProvider;
|
|
9
|
+
toolsProvider;
|
|
10
|
+
hooks;
|
|
11
|
+
logger;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.modelProvider = config.modelProvider;
|
|
14
|
+
this.toolsProvider = config.toolsProvider;
|
|
15
|
+
this.hooks = config.hooks;
|
|
16
|
+
this.logger = config.logger;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Execute an LLM call with structured output.
|
|
20
|
+
*
|
|
21
|
+
* @param messages - Conversation messages
|
|
22
|
+
* @param schema - Zod schema for structured output
|
|
23
|
+
* @param config - LLM call configuration
|
|
24
|
+
* @returns Structured output with usage metrics and metadata
|
|
25
|
+
*/
|
|
26
|
+
async generateStructuredOutput(messages, schema, config) {
|
|
27
|
+
const { model, maxSteps = 10, metadata, temperature = DEFAULT_TEMPERATURE, topK, topP, toolChoice, activeTools,
|
|
28
|
+
// maxTokens and timeout are available in config but handled by provider/OpenRouter
|
|
29
|
+
// They're included for future extensibility and documentation
|
|
30
|
+
} = config;
|
|
31
|
+
// Get tools if provider is available
|
|
32
|
+
let tools = this.toolsProvider?.();
|
|
33
|
+
// Filter tools if activeTools is specified
|
|
34
|
+
if (tools && activeTools && activeTools.length > 0) {
|
|
35
|
+
// Filter tool set to only include specified tools
|
|
36
|
+
const filteredTools = {};
|
|
37
|
+
for (const toolName of activeTools) {
|
|
38
|
+
if (tools && toolName in tools) {
|
|
39
|
+
filteredTools[toolName] = tools[toolName];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const filteredKeys = Object.keys(filteredTools);
|
|
43
|
+
if (filteredKeys.length > 0) {
|
|
44
|
+
// Type assertion needed because we're filtering the tool set
|
|
45
|
+
tools = filteredTools;
|
|
46
|
+
this.logger?.debug(`[LLM] Filtered tools to: ${filteredKeys.join(', ')}`);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// No matching tools found, disable tools
|
|
50
|
+
tools = undefined;
|
|
51
|
+
this.logger?.warn(`[LLM] No matching tools found for activeTools: ${activeTools.join(', ')}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Call observability hook
|
|
55
|
+
this.hooks?.onCallStart?.(metadata);
|
|
56
|
+
const debugParams = [`model: ${model}`, `temperature: ${temperature}`];
|
|
57
|
+
if (topK !== undefined)
|
|
58
|
+
debugParams.push(`topK: ${topK}`);
|
|
59
|
+
if (topP !== undefined)
|
|
60
|
+
debugParams.push(`topP: ${topP}`);
|
|
61
|
+
if (toolChoice) {
|
|
62
|
+
debugParams.push(`toolChoice: ${typeof toolChoice === 'string' ? toolChoice : toolChoice.toolName}`);
|
|
63
|
+
}
|
|
64
|
+
this.logger?.debug(`[LLM] Starting call: ${metadata.operation} (${debugParams.join(', ')})`);
|
|
65
|
+
try {
|
|
66
|
+
// Build generateText options with reliability settings for structured output
|
|
67
|
+
// Lower temperature (0-0.3) improves consistency and reliability for structured output
|
|
68
|
+
const outputConfig = Output.object({ schema });
|
|
69
|
+
// Debug: Log schema info (for Azure compatibility debugging)
|
|
70
|
+
// Note: The AI SDK converts Zod to JSON Schema internally and sends it to the provider
|
|
71
|
+
// Azure's validator may be strict about optional fields in the JSON Schema
|
|
72
|
+
this.logger?.debug(`[LLM] Using structured output schema for ${metadata.operation}`);
|
|
73
|
+
this.logger?.debug(`[LLM] Schema type: ${schema._def?.typeName ?? 'unknown'}`);
|
|
74
|
+
const generateOptions = {
|
|
75
|
+
model: this.modelProvider(model),
|
|
76
|
+
messages,
|
|
77
|
+
output: outputConfig,
|
|
78
|
+
stopWhen: stepCountIs(maxSteps),
|
|
79
|
+
temperature, // Lower temperature for more reliable structured output
|
|
80
|
+
...(tools ? { tools } : {}), // Only include tools if they exist
|
|
81
|
+
};
|
|
82
|
+
// Add optional sampling parameters (alternative/complement to temperature)
|
|
83
|
+
if (topK !== undefined) {
|
|
84
|
+
generateOptions.topK = topK;
|
|
85
|
+
}
|
|
86
|
+
if (topP !== undefined) {
|
|
87
|
+
generateOptions.topP = topP;
|
|
88
|
+
}
|
|
89
|
+
// Add tool choice if specified
|
|
90
|
+
if (toolChoice) {
|
|
91
|
+
if (toolChoice === 'auto' || toolChoice === 'none' || toolChoice === 'required') {
|
|
92
|
+
generateOptions.toolChoice = toolChoice;
|
|
93
|
+
}
|
|
94
|
+
else if (toolChoice.type === 'tool') {
|
|
95
|
+
generateOptions.toolChoice = { type: 'tool', toolName: toolChoice.toolName };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const result = await generateText(generateOptions);
|
|
99
|
+
if (!result.output) {
|
|
100
|
+
// Enhanced debug logging to understand what the model actually returned
|
|
101
|
+
this.logger?.debug(`[LLM] No structured output received for ${metadata.operation}`);
|
|
102
|
+
this.logger?.debug(`[LLM] Model: ${model}, Operation: ${metadata.operation}`);
|
|
103
|
+
this.logger?.debug(`[LLM] Finish reason: ${result.finishReason ?? 'unknown'}`);
|
|
104
|
+
this.logger?.debug(`[LLM] Raw text response:`, result.text ?? '(no text)');
|
|
105
|
+
this.logger?.debug(`[LLM] Token usage:`, result.usage);
|
|
106
|
+
this.logger?.debug(`[LLM] Tool calls made:`, result.toolCalls?.length ?? 0);
|
|
107
|
+
if (result.toolCalls && result.toolCalls.length > 0) {
|
|
108
|
+
this.logger?.debug(`[LLM] Tool calls details:`, result.toolCalls.map((call) => ({
|
|
109
|
+
toolName: call.toolName,
|
|
110
|
+
input: call.input,
|
|
111
|
+
})));
|
|
112
|
+
}
|
|
113
|
+
// Log schema description if available
|
|
114
|
+
const schemaDescription = schema.description ?? 'No description';
|
|
115
|
+
this.logger?.debug(`[LLM] Expected schema description: ${schemaDescription}`);
|
|
116
|
+
this.logger?.debug(`[LLM] Full result object (sanitized):`, {
|
|
117
|
+
hasOutput: !!result.output,
|
|
118
|
+
hasText: !!result.text,
|
|
119
|
+
finishReason: result.finishReason,
|
|
120
|
+
usage: result.usage,
|
|
121
|
+
toolCallsCount: result.toolCalls?.length ?? 0,
|
|
122
|
+
warnings: result.warnings ?? [],
|
|
123
|
+
});
|
|
124
|
+
throw new Error(`[LLM] Failed to generate structured output for ${metadata.operation}`);
|
|
125
|
+
}
|
|
126
|
+
// Parse and validate output
|
|
127
|
+
// Note: result.output should exist here due to check above, but TypeScript needs assertion
|
|
128
|
+
if (!result.output) {
|
|
129
|
+
// This should never happen due to check above, but handle defensively
|
|
130
|
+
throw new Error(`[LLM] Structured output validation failed: output is null/undefined`);
|
|
131
|
+
}
|
|
132
|
+
const parsed = schema.parse(result.output);
|
|
133
|
+
// Extract token usage
|
|
134
|
+
const usage = result.usage
|
|
135
|
+
? {
|
|
136
|
+
promptTokens: result.usage.inputTokens ?? 0,
|
|
137
|
+
completionTokens: result.usage.outputTokens ?? 0,
|
|
138
|
+
totalTokens: result.usage.totalTokens ??
|
|
139
|
+
(result.usage.inputTokens ?? 0) + (result.usage.outputTokens ?? 0),
|
|
140
|
+
}
|
|
141
|
+
: undefined;
|
|
142
|
+
// Extract tool calls
|
|
143
|
+
const toolCalls = Array.isArray(result.toolCalls)
|
|
144
|
+
? result.toolCalls.map((call) => ({
|
|
145
|
+
toolName: call.toolName,
|
|
146
|
+
input: call.input,
|
|
147
|
+
}))
|
|
148
|
+
: undefined;
|
|
149
|
+
// Call observability hooks
|
|
150
|
+
this.hooks?.onCallComplete?.(metadata, usage);
|
|
151
|
+
if (toolCalls) {
|
|
152
|
+
for (const call of toolCalls) {
|
|
153
|
+
this.hooks?.onToolCall?.(metadata, call.toolName, call.input);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
this.logger?.debug(`[LLM] Completed call: ${metadata.operation} (tokens: ${usage?.totalTokens ?? 'unknown'})`);
|
|
157
|
+
return {
|
|
158
|
+
output: parsed,
|
|
159
|
+
usage,
|
|
160
|
+
toolCalls,
|
|
161
|
+
metadata,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
165
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
166
|
+
// Enhanced error logging for debugging
|
|
167
|
+
if (error && typeof error === 'object' && 'text' in error) {
|
|
168
|
+
const errorText = error.text;
|
|
169
|
+
this.logger?.error(`[LLM] Model returned empty or invalid response for ${metadata.operation}`);
|
|
170
|
+
this.logger?.error(`[LLM] Model: ${model}`);
|
|
171
|
+
this.logger?.error(`[LLM] Response text: ${errorText || '(empty)'}`);
|
|
172
|
+
this.logger?.error(`[LLM] This may indicate the model doesn't support structured output well. Consider trying a different model.`);
|
|
173
|
+
}
|
|
174
|
+
this.hooks?.onCallError?.(metadata, err);
|
|
175
|
+
this.logger?.error(`[LLM] Call failed: ${metadata.operation}`, err);
|
|
176
|
+
throw err;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Create a new LLM service instance with updated configuration.
|
|
181
|
+
* Useful for creating service instances with different tools or hooks.
|
|
182
|
+
*/
|
|
183
|
+
withConfig(config) {
|
|
184
|
+
return new LlmService({
|
|
185
|
+
modelProvider: this.modelProvider,
|
|
186
|
+
toolsProvider: config.toolsProvider ?? this.toolsProvider,
|
|
187
|
+
hooks: config.hooks ?? this.hooks,
|
|
188
|
+
logger: config.logger ?? this.logger,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import type { LanguageModel, ToolSet } from 'ai';
|
|
2
|
+
/**
|
|
3
|
+
* Token usage metrics for a single LLM call.
|
|
4
|
+
*/
|
|
5
|
+
export type TokenUsage = {
|
|
6
|
+
promptTokens: number;
|
|
7
|
+
completionTokens: number;
|
|
8
|
+
totalTokens: number;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Metadata for an LLM call operation.
|
|
12
|
+
*/
|
|
13
|
+
export type LlmCallMetadata = {
|
|
14
|
+
operation: string;
|
|
15
|
+
model: string;
|
|
16
|
+
iteration?: number;
|
|
17
|
+
reviewer?: string;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Result from an LLM call with structured output.
|
|
22
|
+
*/
|
|
23
|
+
export type LlmCallResult<T> = {
|
|
24
|
+
output: T;
|
|
25
|
+
usage?: TokenUsage;
|
|
26
|
+
toolCalls?: Array<{
|
|
27
|
+
toolName: string;
|
|
28
|
+
input?: unknown;
|
|
29
|
+
}>;
|
|
30
|
+
metadata: LlmCallMetadata;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Tool choice strategy for tool calling.
|
|
34
|
+
*/
|
|
35
|
+
export type ToolChoice = 'auto' | 'none' | 'required' | {
|
|
36
|
+
type: 'tool';
|
|
37
|
+
toolName: string;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Configuration for an LLM call.
|
|
41
|
+
*/
|
|
42
|
+
export type LlmCallConfig = {
|
|
43
|
+
model: string;
|
|
44
|
+
maxSteps?: number;
|
|
45
|
+
metadata: LlmCallMetadata;
|
|
46
|
+
/**
|
|
47
|
+
* Temperature for generation (0-2).
|
|
48
|
+
* Lower values (0-0.3) make output more deterministic and reliable for structured output.
|
|
49
|
+
* Default: 0.2 for structured output reliability.
|
|
50
|
+
*/
|
|
51
|
+
temperature?: number;
|
|
52
|
+
/**
|
|
53
|
+
* Top-K sampling: consider only top K most likely tokens.
|
|
54
|
+
* Lower values (1-10) make output more deterministic.
|
|
55
|
+
* Use with topP for nucleus sampling, or alone as alternative to temperature.
|
|
56
|
+
*/
|
|
57
|
+
topK?: number;
|
|
58
|
+
/**
|
|
59
|
+
* Top-P (nucleus) sampling: consider tokens with cumulative probability up to P.
|
|
60
|
+
* Lower values (0.1-0.5) make output more deterministic.
|
|
61
|
+
* Often used with temperature for fine-grained control.
|
|
62
|
+
*/
|
|
63
|
+
topP?: number;
|
|
64
|
+
/**
|
|
65
|
+
* Tool choice strategy.
|
|
66
|
+
* - 'auto': Model decides (default)
|
|
67
|
+
* - 'required': Force tool use (useful when tools are needed for structured output)
|
|
68
|
+
* - 'none': Don't use tools
|
|
69
|
+
* - { type: 'tool', toolName: string }: Force specific tool
|
|
70
|
+
*/
|
|
71
|
+
toolChoice?: ToolChoice;
|
|
72
|
+
/**
|
|
73
|
+
* Limit which tools are available for this call.
|
|
74
|
+
* If not set, all tools from toolsProvider are available.
|
|
75
|
+
* Useful for restricting tool scope or debugging.
|
|
76
|
+
*/
|
|
77
|
+
activeTools?: string[];
|
|
78
|
+
/**
|
|
79
|
+
* Maximum tokens to generate.
|
|
80
|
+
* If not set, uses model default. For structured output, ensure this is high enough.
|
|
81
|
+
*/
|
|
82
|
+
maxTokens?: number;
|
|
83
|
+
/**
|
|
84
|
+
* Request timeout in milliseconds.
|
|
85
|
+
* Default: 120000 (2 minutes) for reliability.
|
|
86
|
+
*/
|
|
87
|
+
timeout?: number;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Model provider factory function.
|
|
91
|
+
* Takes a model name and returns a LanguageModel instance.
|
|
92
|
+
*/
|
|
93
|
+
export type ModelProvider = (modelName: string) => LanguageModel;
|
|
94
|
+
/**
|
|
95
|
+
* Tools provider factory function.
|
|
96
|
+
* Returns a ToolSet for the LLM call.
|
|
97
|
+
*/
|
|
98
|
+
export type ToolsProvider = () => ToolSet | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Observability hooks for LLM calls.
|
|
101
|
+
*/
|
|
102
|
+
export type LlmObservabilityHooks = {
|
|
103
|
+
/**
|
|
104
|
+
* Called before an LLM call starts.
|
|
105
|
+
*/
|
|
106
|
+
onCallStart?: (metadata: LlmCallMetadata) => void;
|
|
107
|
+
/**
|
|
108
|
+
* Called after an LLM call completes successfully.
|
|
109
|
+
*/
|
|
110
|
+
onCallComplete?: (metadata: LlmCallMetadata, usage?: TokenUsage) => void;
|
|
111
|
+
/**
|
|
112
|
+
* Called when an LLM call fails.
|
|
113
|
+
*/
|
|
114
|
+
onCallError?: (metadata: LlmCallMetadata, error: Error) => void;
|
|
115
|
+
/**
|
|
116
|
+
* Called when tool calls are made during an LLM call.
|
|
117
|
+
*/
|
|
118
|
+
onToolCall?: (metadata: LlmCallMetadata, toolName: string, input?: unknown) => void;
|
|
119
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent';
|
|
2
|
+
export type Logger = {
|
|
3
|
+
debug: (...args: unknown[]) => void;
|
|
4
|
+
info: (...args: unknown[]) => void;
|
|
5
|
+
warn: (...args: unknown[]) => void;
|
|
6
|
+
error: (...args: unknown[]) => void;
|
|
7
|
+
};
|
|
8
|
+
export declare const parseLogLevel: (value?: string) => LogLevel;
|
|
9
|
+
export declare const createLogger: (level: LogLevel) => Logger;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const LEVEL_ORDER = {
|
|
2
|
+
debug: 10,
|
|
3
|
+
info: 20,
|
|
4
|
+
warn: 30,
|
|
5
|
+
error: 40,
|
|
6
|
+
silent: 50,
|
|
7
|
+
};
|
|
8
|
+
export const parseLogLevel = (value) => {
|
|
9
|
+
if (!value) {
|
|
10
|
+
return 'info';
|
|
11
|
+
}
|
|
12
|
+
const normalized = value.trim().toLowerCase();
|
|
13
|
+
if (normalized === 'true') {
|
|
14
|
+
return 'debug';
|
|
15
|
+
}
|
|
16
|
+
if (normalized === 'false') {
|
|
17
|
+
return 'info';
|
|
18
|
+
}
|
|
19
|
+
if (normalized === 'debug' || normalized === 'info' || normalized === 'warn' || normalized === 'error') {
|
|
20
|
+
return normalized;
|
|
21
|
+
}
|
|
22
|
+
if (normalized === 'silent') {
|
|
23
|
+
return 'silent';
|
|
24
|
+
}
|
|
25
|
+
return 'info';
|
|
26
|
+
};
|
|
27
|
+
export const createLogger = (level) => {
|
|
28
|
+
const threshold = LEVEL_ORDER[level];
|
|
29
|
+
const shouldLog = (messageLevel) => LEVEL_ORDER[messageLevel] >= threshold;
|
|
30
|
+
return {
|
|
31
|
+
debug: (...args) => {
|
|
32
|
+
if (shouldLog('debug')) {
|
|
33
|
+
console.debug(...args);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
info: (...args) => {
|
|
37
|
+
if (shouldLog('info')) {
|
|
38
|
+
console.info(...args);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
warn: (...args) => {
|
|
42
|
+
if (shouldLog('warn')) {
|
|
43
|
+
console.warn(...args);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
error: (...args) => {
|
|
47
|
+
if (shouldLog('error')) {
|
|
48
|
+
console.error(...args);
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
};
|