@compilr-dev/agents 0.0.1
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/README.md +1277 -0
- package/dist/agent.d.ts +1272 -0
- package/dist/agent.js +1912 -0
- package/dist/anchors/builtin.d.ts +24 -0
- package/dist/anchors/builtin.js +61 -0
- package/dist/anchors/index.d.ts +6 -0
- package/dist/anchors/index.js +5 -0
- package/dist/anchors/manager.d.ts +115 -0
- package/dist/anchors/manager.js +412 -0
- package/dist/anchors/types.d.ts +168 -0
- package/dist/anchors/types.js +10 -0
- package/dist/context/index.d.ts +12 -0
- package/dist/context/index.js +10 -0
- package/dist/context/manager.d.ts +224 -0
- package/dist/context/manager.js +770 -0
- package/dist/context/types.d.ts +377 -0
- package/dist/context/types.js +7 -0
- package/dist/costs/index.d.ts +8 -0
- package/dist/costs/index.js +7 -0
- package/dist/costs/tracker.d.ts +121 -0
- package/dist/costs/tracker.js +295 -0
- package/dist/costs/types.d.ts +157 -0
- package/dist/costs/types.js +8 -0
- package/dist/errors.d.ts +178 -0
- package/dist/errors.js +249 -0
- package/dist/guardrails/builtin.d.ts +27 -0
- package/dist/guardrails/builtin.js +223 -0
- package/dist/guardrails/index.d.ts +6 -0
- package/dist/guardrails/index.js +5 -0
- package/dist/guardrails/manager.d.ts +117 -0
- package/dist/guardrails/manager.js +288 -0
- package/dist/guardrails/types.d.ts +159 -0
- package/dist/guardrails/types.js +7 -0
- package/dist/hooks/index.d.ts +31 -0
- package/dist/hooks/index.js +29 -0
- package/dist/hooks/manager.d.ts +147 -0
- package/dist/hooks/manager.js +600 -0
- package/dist/hooks/types.d.ts +368 -0
- package/dist/hooks/types.js +12 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +73 -0
- package/dist/mcp/client.d.ts +93 -0
- package/dist/mcp/client.js +287 -0
- package/dist/mcp/errors.d.ts +60 -0
- package/dist/mcp/errors.js +78 -0
- package/dist/mcp/index.d.ts +43 -0
- package/dist/mcp/index.js +45 -0
- package/dist/mcp/manager.d.ts +120 -0
- package/dist/mcp/manager.js +276 -0
- package/dist/mcp/tools.d.ts +54 -0
- package/dist/mcp/tools.js +99 -0
- package/dist/mcp/types.d.ts +150 -0
- package/dist/mcp/types.js +40 -0
- package/dist/memory/index.d.ts +8 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/loader.d.ts +114 -0
- package/dist/memory/loader.js +463 -0
- package/dist/memory/types.d.ts +182 -0
- package/dist/memory/types.js +8 -0
- package/dist/messages/index.d.ts +82 -0
- package/dist/messages/index.js +155 -0
- package/dist/permissions/index.d.ts +5 -0
- package/dist/permissions/index.js +4 -0
- package/dist/permissions/manager.d.ts +125 -0
- package/dist/permissions/manager.js +379 -0
- package/dist/permissions/types.d.ts +162 -0
- package/dist/permissions/types.js +7 -0
- package/dist/providers/claude.d.ts +90 -0
- package/dist/providers/claude.js +348 -0
- package/dist/providers/index.d.ts +8 -0
- package/dist/providers/index.js +11 -0
- package/dist/providers/mock.d.ts +133 -0
- package/dist/providers/mock.js +204 -0
- package/dist/providers/types.d.ts +168 -0
- package/dist/providers/types.js +4 -0
- package/dist/rate-limit/index.d.ts +45 -0
- package/dist/rate-limit/index.js +47 -0
- package/dist/rate-limit/limiter.d.ts +104 -0
- package/dist/rate-limit/limiter.js +326 -0
- package/dist/rate-limit/provider-wrapper.d.ts +112 -0
- package/dist/rate-limit/provider-wrapper.js +201 -0
- package/dist/rate-limit/retry.d.ts +108 -0
- package/dist/rate-limit/retry.js +287 -0
- package/dist/rate-limit/types.d.ts +181 -0
- package/dist/rate-limit/types.js +22 -0
- package/dist/rehearsal/file-analyzer.d.ts +22 -0
- package/dist/rehearsal/file-analyzer.js +351 -0
- package/dist/rehearsal/git-analyzer.d.ts +22 -0
- package/dist/rehearsal/git-analyzer.js +472 -0
- package/dist/rehearsal/index.d.ts +35 -0
- package/dist/rehearsal/index.js +36 -0
- package/dist/rehearsal/manager.d.ts +100 -0
- package/dist/rehearsal/manager.js +290 -0
- package/dist/rehearsal/types.d.ts +235 -0
- package/dist/rehearsal/types.js +8 -0
- package/dist/skills/index.d.ts +160 -0
- package/dist/skills/index.js +282 -0
- package/dist/state/agent-state.d.ts +41 -0
- package/dist/state/agent-state.js +88 -0
- package/dist/state/checkpointer.d.ts +110 -0
- package/dist/state/checkpointer.js +362 -0
- package/dist/state/errors.d.ts +66 -0
- package/dist/state/errors.js +88 -0
- package/dist/state/index.d.ts +35 -0
- package/dist/state/index.js +37 -0
- package/dist/state/serializer.d.ts +55 -0
- package/dist/state/serializer.js +172 -0
- package/dist/state/types.d.ts +312 -0
- package/dist/state/types.js +14 -0
- package/dist/tools/builtin/bash-output.d.ts +61 -0
- package/dist/tools/builtin/bash-output.js +90 -0
- package/dist/tools/builtin/bash.d.ts +150 -0
- package/dist/tools/builtin/bash.js +354 -0
- package/dist/tools/builtin/edit.d.ts +50 -0
- package/dist/tools/builtin/edit.js +215 -0
- package/dist/tools/builtin/glob.d.ts +62 -0
- package/dist/tools/builtin/glob.js +244 -0
- package/dist/tools/builtin/grep.d.ts +74 -0
- package/dist/tools/builtin/grep.js +363 -0
- package/dist/tools/builtin/index.d.ts +44 -0
- package/dist/tools/builtin/index.js +69 -0
- package/dist/tools/builtin/kill-shell.d.ts +44 -0
- package/dist/tools/builtin/kill-shell.js +80 -0
- package/dist/tools/builtin/read-file.d.ts +57 -0
- package/dist/tools/builtin/read-file.js +184 -0
- package/dist/tools/builtin/shell-manager.d.ts +176 -0
- package/dist/tools/builtin/shell-manager.js +337 -0
- package/dist/tools/builtin/task.d.ts +202 -0
- package/dist/tools/builtin/task.js +350 -0
- package/dist/tools/builtin/todo.d.ts +207 -0
- package/dist/tools/builtin/todo.js +453 -0
- package/dist/tools/builtin/utils.d.ts +27 -0
- package/dist/tools/builtin/utils.js +70 -0
- package/dist/tools/builtin/web-fetch.d.ts +96 -0
- package/dist/tools/builtin/web-fetch.js +290 -0
- package/dist/tools/builtin/write-file.d.ts +54 -0
- package/dist/tools/builtin/write-file.js +147 -0
- package/dist/tools/define.d.ts +60 -0
- package/dist/tools/define.js +65 -0
- package/dist/tools/index.d.ts +10 -0
- package/dist/tools/index.js +37 -0
- package/dist/tools/registry.d.ts +79 -0
- package/dist/tools/registry.js +151 -0
- package/dist/tools/types.d.ts +59 -0
- package/dist/tools/types.js +4 -0
- package/dist/tracing/hooks.d.ts +58 -0
- package/dist/tracing/hooks.js +377 -0
- package/dist/tracing/index.d.ts +51 -0
- package/dist/tracing/index.js +55 -0
- package/dist/tracing/logging.d.ts +78 -0
- package/dist/tracing/logging.js +310 -0
- package/dist/tracing/manager.d.ts +160 -0
- package/dist/tracing/manager.js +468 -0
- package/dist/tracing/otel.d.ts +102 -0
- package/dist/tracing/otel.js +246 -0
- package/dist/tracing/types.d.ts +346 -0
- package/dist/tracing/types.js +38 -0
- package/dist/utils/index.d.ts +23 -0
- package/dist/utils/index.js +44 -0
- package/package.json +79 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Memory Types
|
|
3
|
+
*
|
|
4
|
+
* Types for project-level instruction loading from markdown files.
|
|
5
|
+
* Supports various LLM-specific naming conventions (CLAUDE.md, GEMINI.md, etc.)
|
|
6
|
+
* as well as generic names (PROJECT.md, INSTRUCTIONS.md, AI.md).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* LLM provider name for memory file discovery.
|
|
10
|
+
*
|
|
11
|
+
* Common values: 'claude', 'gemini', 'openai', 'gpt', 'copilot', 'cursor', 'codeium', 'anthropic'
|
|
12
|
+
*
|
|
13
|
+
* Can be any string to support custom providers - patterns will be generated
|
|
14
|
+
* automatically (e.g., 'myai' -> MYAI.md, .myai.md, .myai/instructions.md)
|
|
15
|
+
*/
|
|
16
|
+
export type LLMProviderName = string;
|
|
17
|
+
/**
|
|
18
|
+
* A loaded memory file with its content and metadata
|
|
19
|
+
*/
|
|
20
|
+
export interface MemoryFile {
|
|
21
|
+
/** Absolute path to the file */
|
|
22
|
+
path: string;
|
|
23
|
+
/** File content */
|
|
24
|
+
content: string;
|
|
25
|
+
/** Relative path from the search root */
|
|
26
|
+
relativePath: string;
|
|
27
|
+
/** The pattern that matched this file */
|
|
28
|
+
matchedPattern: string;
|
|
29
|
+
/** File size in bytes */
|
|
30
|
+
size: number;
|
|
31
|
+
/** Last modified timestamp */
|
|
32
|
+
modifiedAt: Date;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Result of loading project memory
|
|
36
|
+
*/
|
|
37
|
+
export interface ProjectMemory {
|
|
38
|
+
/** All loaded memory files */
|
|
39
|
+
files: MemoryFile[];
|
|
40
|
+
/** Combined content from all files */
|
|
41
|
+
content: string;
|
|
42
|
+
/** The root directory where search started */
|
|
43
|
+
rootDir: string;
|
|
44
|
+
/** Total token estimate (rough: chars / 4) */
|
|
45
|
+
estimatedTokens: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* File pattern configuration for discovery
|
|
49
|
+
*/
|
|
50
|
+
export interface FilePattern {
|
|
51
|
+
/** Glob pattern or exact filename */
|
|
52
|
+
pattern: string;
|
|
53
|
+
/** Priority (lower = higher priority, loaded first) */
|
|
54
|
+
priority: number;
|
|
55
|
+
/** Description of what this pattern matches */
|
|
56
|
+
description?: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Strategy for combining multiple memory files
|
|
60
|
+
*/
|
|
61
|
+
export type CombineStrategy = 'concat' | 'priority' | 'dedupe';
|
|
62
|
+
/**
|
|
63
|
+
* Options for ProjectMemoryLoader
|
|
64
|
+
*/
|
|
65
|
+
export interface ProjectMemoryOptions {
|
|
66
|
+
/**
|
|
67
|
+
* LLM provider name(s) to search for
|
|
68
|
+
* E.g., 'claude' will search for CLAUDE.md, .claude.md, .claude/instructions.md
|
|
69
|
+
* Can be a single provider or array for multi-provider support
|
|
70
|
+
* @default 'claude'
|
|
71
|
+
*/
|
|
72
|
+
providers?: LLMProviderName | LLMProviderName[];
|
|
73
|
+
/**
|
|
74
|
+
* Whether to include generic memory files (PROJECT.md, INSTRUCTIONS.md, AI.md)
|
|
75
|
+
* @default true
|
|
76
|
+
*/
|
|
77
|
+
includeGeneric?: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Additional custom file patterns to search for
|
|
80
|
+
*/
|
|
81
|
+
customPatterns?: FilePattern[];
|
|
82
|
+
/**
|
|
83
|
+
* Whether to search parent directories up to the root
|
|
84
|
+
* @default true
|
|
85
|
+
*/
|
|
86
|
+
searchParents?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Maximum number of parent directories to traverse
|
|
89
|
+
* @default 10
|
|
90
|
+
*/
|
|
91
|
+
maxParentDepth?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Stop searching parents when finding a git root (.git directory)
|
|
94
|
+
* @default true
|
|
95
|
+
*/
|
|
96
|
+
stopAtGitRoot?: boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Strategy for combining multiple memory files
|
|
99
|
+
* @default 'concat'
|
|
100
|
+
*/
|
|
101
|
+
combineStrategy?: CombineStrategy;
|
|
102
|
+
/**
|
|
103
|
+
* Separator to use between files when combining
|
|
104
|
+
* @default '\n\n---\n\n'
|
|
105
|
+
*/
|
|
106
|
+
separator?: string;
|
|
107
|
+
/**
|
|
108
|
+
* Maximum total content size in characters
|
|
109
|
+
* Files are loaded in priority order until limit is reached
|
|
110
|
+
* @default 100000 (100KB)
|
|
111
|
+
*/
|
|
112
|
+
maxContentSize?: number;
|
|
113
|
+
/**
|
|
114
|
+
* Whether to include file path headers in combined content
|
|
115
|
+
* @default true
|
|
116
|
+
*/
|
|
117
|
+
includeHeaders?: boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Header format template. Use {path} for file path, {relativePath} for relative path
|
|
120
|
+
* @default '# From: {relativePath}\n\n'
|
|
121
|
+
*/
|
|
122
|
+
headerFormat?: string;
|
|
123
|
+
/**
|
|
124
|
+
* File encoding
|
|
125
|
+
* @default 'utf-8'
|
|
126
|
+
*/
|
|
127
|
+
encoding?: BufferEncoding;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Event types for ProjectMemoryLoader
|
|
131
|
+
*/
|
|
132
|
+
export type ProjectMemoryEventType = 'memory:search_start' | 'memory:file_found' | 'memory:file_loaded' | 'memory:file_skipped' | 'memory:search_complete' | 'memory:error';
|
|
133
|
+
/**
|
|
134
|
+
* Events emitted during memory loading
|
|
135
|
+
*/
|
|
136
|
+
export type ProjectMemoryEvent = {
|
|
137
|
+
type: 'memory:search_start';
|
|
138
|
+
rootDir: string;
|
|
139
|
+
patterns: string[];
|
|
140
|
+
} | {
|
|
141
|
+
type: 'memory:file_found';
|
|
142
|
+
path: string;
|
|
143
|
+
pattern: string;
|
|
144
|
+
} | {
|
|
145
|
+
type: 'memory:file_loaded';
|
|
146
|
+
file: MemoryFile;
|
|
147
|
+
} | {
|
|
148
|
+
type: 'memory:file_skipped';
|
|
149
|
+
path: string;
|
|
150
|
+
reason: string;
|
|
151
|
+
} | {
|
|
152
|
+
type: 'memory:search_complete';
|
|
153
|
+
memory: ProjectMemory;
|
|
154
|
+
} | {
|
|
155
|
+
type: 'memory:error';
|
|
156
|
+
error: Error;
|
|
157
|
+
path?: string;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Event handler for project memory events
|
|
161
|
+
*/
|
|
162
|
+
export type ProjectMemoryEventHandler = (event: ProjectMemoryEvent) => void;
|
|
163
|
+
/**
|
|
164
|
+
* Result of checking for memory files without loading content
|
|
165
|
+
*/
|
|
166
|
+
export interface MemoryDiscoveryResult {
|
|
167
|
+
/** Paths to discovered memory files */
|
|
168
|
+
paths: string[];
|
|
169
|
+
/** Whether any memory files were found */
|
|
170
|
+
found: boolean;
|
|
171
|
+
/** The patterns that matched */
|
|
172
|
+
matchedPatterns: string[];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Built-in provider patterns
|
|
176
|
+
*/
|
|
177
|
+
export interface ProviderPatterns {
|
|
178
|
+
/** Provider name */
|
|
179
|
+
provider: LLMProviderName;
|
|
180
|
+
/** File patterns for this provider (ordered by priority) */
|
|
181
|
+
patterns: FilePattern[];
|
|
182
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project Memory Types
|
|
3
|
+
*
|
|
4
|
+
* Types for project-level instruction loading from markdown files.
|
|
5
|
+
* Supports various LLM-specific naming conventions (CLAUDE.md, GEMINI.md, etc.)
|
|
6
|
+
* as well as generic names (PROJECT.md, INSTRUCTIONS.md, AI.md).
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message utilities
|
|
3
|
+
*/
|
|
4
|
+
import type { Message, ContentBlock, TextBlock, ToolUseBlock, ToolResultBlock } from '../providers/types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Create a user message
|
|
7
|
+
*/
|
|
8
|
+
export declare function userMessage(content: string): Message;
|
|
9
|
+
/**
|
|
10
|
+
* Create an assistant message
|
|
11
|
+
*/
|
|
12
|
+
export declare function assistantMessage(content: string | ContentBlock[]): Message;
|
|
13
|
+
/**
|
|
14
|
+
* Create a system message
|
|
15
|
+
*/
|
|
16
|
+
export declare function systemMessage(content: string): Message;
|
|
17
|
+
/**
|
|
18
|
+
* Create a text content block
|
|
19
|
+
*/
|
|
20
|
+
export declare function textBlock(text: string): TextBlock;
|
|
21
|
+
/**
|
|
22
|
+
* Create a tool use content block
|
|
23
|
+
*/
|
|
24
|
+
export declare function toolUseBlock(id: string, name: string, input: Record<string, unknown>): ToolUseBlock;
|
|
25
|
+
/**
|
|
26
|
+
* Create a tool result content block
|
|
27
|
+
*/
|
|
28
|
+
export declare function toolResultBlock(toolUseId: string, content: string, isError?: boolean): ToolResultBlock;
|
|
29
|
+
/**
|
|
30
|
+
* Extract text content from a message
|
|
31
|
+
*/
|
|
32
|
+
export declare function getTextContent(message: Message): string;
|
|
33
|
+
/**
|
|
34
|
+
* Extract tool uses from a message
|
|
35
|
+
*/
|
|
36
|
+
export declare function getToolUses(message: Message): ToolUseBlock[];
|
|
37
|
+
/**
|
|
38
|
+
* Check if a message contains tool uses
|
|
39
|
+
*/
|
|
40
|
+
export declare function hasToolUses(message: Message): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Extract tool results from a message
|
|
43
|
+
*/
|
|
44
|
+
export declare function getToolResults(message: Message): ToolResultBlock[];
|
|
45
|
+
/**
|
|
46
|
+
* Validation result for tool use/result pairing
|
|
47
|
+
*/
|
|
48
|
+
export interface ToolPairingValidation {
|
|
49
|
+
valid: boolean;
|
|
50
|
+
errors: string[];
|
|
51
|
+
orphanedResults: string[];
|
|
52
|
+
missingResults: string[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Validate that tool_result blocks have matching tool_use blocks.
|
|
56
|
+
* This prevents API errors like "Tool result block missing corresponding tool_use block"
|
|
57
|
+
*
|
|
58
|
+
* @param messages - Array of messages to validate
|
|
59
|
+
* @returns Validation result with details about any mismatches
|
|
60
|
+
*/
|
|
61
|
+
export declare function validateToolUseResultPairing(messages: Message[]): ToolPairingValidation;
|
|
62
|
+
/**
|
|
63
|
+
* Ensure a message has content field (even if empty).
|
|
64
|
+
* Some APIs (like xAI) require content to be present even when tool_calls exist.
|
|
65
|
+
*
|
|
66
|
+
* This function handles messages from external sources that might not strictly
|
|
67
|
+
* conform to our Message type (e.g., API responses with missing content).
|
|
68
|
+
*
|
|
69
|
+
* @param message - Message to normalize (may have missing content from external APIs)
|
|
70
|
+
* @returns Message with guaranteed content field
|
|
71
|
+
*/
|
|
72
|
+
export declare function ensureMessageContent(message: Message | {
|
|
73
|
+
role: string;
|
|
74
|
+
content?: string | ContentBlock[] | null;
|
|
75
|
+
}): Message;
|
|
76
|
+
/**
|
|
77
|
+
* Normalize all messages to ensure content fields are present.
|
|
78
|
+
*
|
|
79
|
+
* @param messages - Array of messages to normalize
|
|
80
|
+
* @returns Normalized messages
|
|
81
|
+
*/
|
|
82
|
+
export declare function normalizeMessages(messages: Message[]): Message[];
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create a user message
|
|
6
|
+
*/
|
|
7
|
+
export function userMessage(content) {
|
|
8
|
+
return { role: 'user', content };
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create an assistant message
|
|
12
|
+
*/
|
|
13
|
+
export function assistantMessage(content) {
|
|
14
|
+
return { role: 'assistant', content };
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a system message
|
|
18
|
+
*/
|
|
19
|
+
export function systemMessage(content) {
|
|
20
|
+
return { role: 'system', content };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a text content block
|
|
24
|
+
*/
|
|
25
|
+
export function textBlock(text) {
|
|
26
|
+
return { type: 'text', text };
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Create a tool use content block
|
|
30
|
+
*/
|
|
31
|
+
export function toolUseBlock(id, name, input) {
|
|
32
|
+
return { type: 'tool_use', id, name, input };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Create a tool result content block
|
|
36
|
+
*/
|
|
37
|
+
export function toolResultBlock(toolUseId, content, isError = false) {
|
|
38
|
+
return { type: 'tool_result', toolUseId, content, isError };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Extract text content from a message
|
|
42
|
+
*/
|
|
43
|
+
export function getTextContent(message) {
|
|
44
|
+
if (typeof message.content === 'string') {
|
|
45
|
+
return message.content;
|
|
46
|
+
}
|
|
47
|
+
return message.content
|
|
48
|
+
.filter((block) => block.type === 'text')
|
|
49
|
+
.map((block) => block.text)
|
|
50
|
+
.join('');
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Extract tool uses from a message
|
|
54
|
+
*/
|
|
55
|
+
export function getToolUses(message) {
|
|
56
|
+
if (typeof message.content === 'string') {
|
|
57
|
+
return [];
|
|
58
|
+
}
|
|
59
|
+
return message.content.filter((block) => block.type === 'tool_use');
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Check if a message contains tool uses
|
|
63
|
+
*/
|
|
64
|
+
export function hasToolUses(message) {
|
|
65
|
+
return getToolUses(message).length > 0;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Extract tool results from a message
|
|
69
|
+
*/
|
|
70
|
+
export function getToolResults(message) {
|
|
71
|
+
if (typeof message.content === 'string') {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
return message.content.filter((block) => block.type === 'tool_result');
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Validate that tool_result blocks have matching tool_use blocks.
|
|
78
|
+
* This prevents API errors like "Tool result block missing corresponding tool_use block"
|
|
79
|
+
*
|
|
80
|
+
* @param messages - Array of messages to validate
|
|
81
|
+
* @returns Validation result with details about any mismatches
|
|
82
|
+
*/
|
|
83
|
+
export function validateToolUseResultPairing(messages) {
|
|
84
|
+
const toolUseIds = new Set();
|
|
85
|
+
const toolResultIds = new Set();
|
|
86
|
+
const errors = [];
|
|
87
|
+
// Collect all tool_use IDs and tool_result IDs
|
|
88
|
+
for (const message of messages) {
|
|
89
|
+
if (typeof message.content === 'string')
|
|
90
|
+
continue;
|
|
91
|
+
for (const block of message.content) {
|
|
92
|
+
if (block.type === 'tool_use') {
|
|
93
|
+
if (toolUseIds.has(block.id)) {
|
|
94
|
+
errors.push(`Duplicate tool_use ID: ${block.id}`);
|
|
95
|
+
}
|
|
96
|
+
toolUseIds.add(block.id);
|
|
97
|
+
}
|
|
98
|
+
else if (block.type === 'tool_result') {
|
|
99
|
+
if (toolResultIds.has(block.toolUseId)) {
|
|
100
|
+
errors.push(`Duplicate tool_result for ID: ${block.toolUseId}`);
|
|
101
|
+
}
|
|
102
|
+
toolResultIds.add(block.toolUseId);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Find orphaned results (results without matching use)
|
|
107
|
+
const orphanedResults = [];
|
|
108
|
+
for (const resultId of toolResultIds) {
|
|
109
|
+
if (!toolUseIds.has(resultId)) {
|
|
110
|
+
orphanedResults.push(resultId);
|
|
111
|
+
errors.push(`Tool result '${resultId}' has no matching tool_use block`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Find missing results (uses without matching result) - only for completed conversations
|
|
115
|
+
const missingResults = [];
|
|
116
|
+
for (const useId of toolUseIds) {
|
|
117
|
+
if (!toolResultIds.has(useId)) {
|
|
118
|
+
missingResults.push(useId);
|
|
119
|
+
// Note: This is not always an error - the last tool_use may not have a result yet
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
valid: errors.length === 0,
|
|
124
|
+
errors,
|
|
125
|
+
orphanedResults,
|
|
126
|
+
missingResults,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Ensure a message has content field (even if empty).
|
|
131
|
+
* Some APIs (like xAI) require content to be present even when tool_calls exist.
|
|
132
|
+
*
|
|
133
|
+
* This function handles messages from external sources that might not strictly
|
|
134
|
+
* conform to our Message type (e.g., API responses with missing content).
|
|
135
|
+
*
|
|
136
|
+
* @param message - Message to normalize (may have missing content from external APIs)
|
|
137
|
+
* @returns Message with guaranteed content field
|
|
138
|
+
*/
|
|
139
|
+
export function ensureMessageContent(message) {
|
|
140
|
+
// Check for undefined/null from external sources
|
|
141
|
+
const rawContent = message.content;
|
|
142
|
+
if (rawContent === undefined || rawContent === null) {
|
|
143
|
+
return { role: message.role, content: '' };
|
|
144
|
+
}
|
|
145
|
+
return message;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Normalize all messages to ensure content fields are present.
|
|
149
|
+
*
|
|
150
|
+
* @param messages - Array of messages to normalize
|
|
151
|
+
* @returns Normalized messages
|
|
152
|
+
*/
|
|
153
|
+
export function normalizeMessages(messages) {
|
|
154
|
+
return messages.map(ensureMessageContent);
|
|
155
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permissions module - Tool-level permission management
|
|
3
|
+
*/
|
|
4
|
+
export { PermissionManager } from './manager.js';
|
|
5
|
+
export type { PermissionLevel, ToolPermission, PermissionRequest, PermissionCheckResult, PermissionHandler, PreviewGenerator, PermissionManagerOptions, PermissionEventType, PermissionEvent, PermissionEventHandler, } from './types.js';
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PermissionManager - Manages tool-level permissions
|
|
3
|
+
*
|
|
4
|
+
* Provides fine-grained control over which tools can execute and when
|
|
5
|
+
* user approval is required.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* const permissions = new PermissionManager({
|
|
10
|
+
* defaultLevel: 'always',
|
|
11
|
+
* rules: [
|
|
12
|
+
* { toolName: 'bash', level: 'once', description: 'Shell commands' },
|
|
13
|
+
* { toolName: 'write_file', level: 'session', description: 'File writes' },
|
|
14
|
+
* { toolName: 'delete_*', level: 'deny', description: 'Delete operations' },
|
|
15
|
+
* ],
|
|
16
|
+
* onPermissionRequest: async (request) => {
|
|
17
|
+
* return await askUser(`Allow ${request.toolName}?`);
|
|
18
|
+
* },
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import type { PermissionLevel, ToolPermission, PermissionCheckResult, PermissionManagerOptions, PermissionEventHandler } from './types.js';
|
|
23
|
+
/**
|
|
24
|
+
* PermissionManager handles tool-level permission checks
|
|
25
|
+
*/
|
|
26
|
+
export declare class PermissionManager {
|
|
27
|
+
private readonly enabled;
|
|
28
|
+
private readonly defaultLevel;
|
|
29
|
+
private readonly rules;
|
|
30
|
+
private readonly wildcardRules;
|
|
31
|
+
private readonly handler?;
|
|
32
|
+
private readonly previewGenerator;
|
|
33
|
+
private readonly eventHandlers;
|
|
34
|
+
/**
|
|
35
|
+
* Track session-level permissions that have been granted
|
|
36
|
+
*/
|
|
37
|
+
private readonly sessionGrants;
|
|
38
|
+
constructor(options?: PermissionManagerOptions);
|
|
39
|
+
/**
|
|
40
|
+
* Add a permission rule
|
|
41
|
+
*/
|
|
42
|
+
addRule(rule: ToolPermission): this;
|
|
43
|
+
/**
|
|
44
|
+
* Remove a permission rule by tool name
|
|
45
|
+
*/
|
|
46
|
+
removeRule(toolName: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Get a permission rule by tool name
|
|
49
|
+
*/
|
|
50
|
+
getRule(toolName: string): ToolPermission | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Get all permission rules
|
|
53
|
+
*/
|
|
54
|
+
getAllRules(): ToolPermission[];
|
|
55
|
+
/**
|
|
56
|
+
* Check if a tool has permission to execute
|
|
57
|
+
*
|
|
58
|
+
* @param toolName - Name of the tool
|
|
59
|
+
* @param input - Tool input arguments
|
|
60
|
+
* @returns Permission check result
|
|
61
|
+
*/
|
|
62
|
+
check(toolName: string, input: Record<string, unknown>): Promise<PermissionCheckResult>;
|
|
63
|
+
/**
|
|
64
|
+
* Check and handle permission, returning whether to proceed
|
|
65
|
+
*
|
|
66
|
+
* Convenience method that combines check() with handling
|
|
67
|
+
*/
|
|
68
|
+
checkAndProceed(toolName: string, input: Record<string, unknown>): Promise<{
|
|
69
|
+
proceed: boolean;
|
|
70
|
+
result: PermissionCheckResult;
|
|
71
|
+
}>;
|
|
72
|
+
/**
|
|
73
|
+
* Ask the user for permission
|
|
74
|
+
*/
|
|
75
|
+
private askPermission;
|
|
76
|
+
/**
|
|
77
|
+
* Grant session-level permission for a tool
|
|
78
|
+
*
|
|
79
|
+
* This allows the tool to execute for the remainder of the session
|
|
80
|
+
* without asking again.
|
|
81
|
+
*/
|
|
82
|
+
grantSession(toolName: string): void;
|
|
83
|
+
/**
|
|
84
|
+
* Revoke session-level permission for a tool
|
|
85
|
+
*/
|
|
86
|
+
revokeSession(toolName: string): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Clear all session-level permissions
|
|
89
|
+
*/
|
|
90
|
+
clearSessionGrants(): void;
|
|
91
|
+
/**
|
|
92
|
+
* Get all tools with session-level permission
|
|
93
|
+
*/
|
|
94
|
+
getSessionGrants(): string[];
|
|
95
|
+
/**
|
|
96
|
+
* Check if a tool has session-level permission
|
|
97
|
+
*/
|
|
98
|
+
hasSessionGrant(toolName: string): boolean;
|
|
99
|
+
/**
|
|
100
|
+
* Set the permission level for a tool
|
|
101
|
+
*
|
|
102
|
+
* Convenience method for adding/updating a rule
|
|
103
|
+
*/
|
|
104
|
+
setLevel(toolName: string, level: PermissionLevel, description?: string): this;
|
|
105
|
+
/**
|
|
106
|
+
* Get the effective permission level for a tool
|
|
107
|
+
*/
|
|
108
|
+
getLevel(toolName: string): PermissionLevel;
|
|
109
|
+
/**
|
|
110
|
+
* Register an event handler
|
|
111
|
+
*/
|
|
112
|
+
onEvent(handler: PermissionEventHandler): () => void;
|
|
113
|
+
/**
|
|
114
|
+
* Emit an event
|
|
115
|
+
*/
|
|
116
|
+
private emit;
|
|
117
|
+
/**
|
|
118
|
+
* Get the number of rules
|
|
119
|
+
*/
|
|
120
|
+
get size(): number;
|
|
121
|
+
/**
|
|
122
|
+
* Check if permissions are enabled
|
|
123
|
+
*/
|
|
124
|
+
get isEnabled(): boolean;
|
|
125
|
+
}
|