gencode-ai 0.1.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/.env.example +11 -0
- package/CLAUDE.md +70 -0
- package/LICENSE +21 -0
- package/README.md +117 -0
- package/dist/agent/agent.d.ts +84 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +233 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/index.d.ts +6 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +6 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/types.d.ts +47 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +5 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/cli/components/App.d.ts +14 -0
- package/dist/cli/components/App.d.ts.map +1 -0
- package/dist/cli/components/App.js +395 -0
- package/dist/cli/components/App.js.map +1 -0
- package/dist/cli/components/CommandSuggestions.d.ts +13 -0
- package/dist/cli/components/CommandSuggestions.d.ts.map +1 -0
- package/dist/cli/components/CommandSuggestions.js +32 -0
- package/dist/cli/components/CommandSuggestions.js.map +1 -0
- package/dist/cli/components/Header.d.ts +9 -0
- package/dist/cli/components/Header.d.ts.map +1 -0
- package/dist/cli/components/Header.js +13 -0
- package/dist/cli/components/Header.js.map +1 -0
- package/dist/cli/components/Input.d.ts +13 -0
- package/dist/cli/components/Input.d.ts.map +1 -0
- package/dist/cli/components/Input.js +27 -0
- package/dist/cli/components/Input.js.map +1 -0
- package/dist/cli/components/Logo.d.ts +2 -0
- package/dist/cli/components/Logo.d.ts.map +1 -0
- package/dist/cli/components/Logo.js +8 -0
- package/dist/cli/components/Logo.js.map +1 -0
- package/dist/cli/components/Messages.d.ts +37 -0
- package/dist/cli/components/Messages.d.ts.map +1 -0
- package/dist/cli/components/Messages.js +106 -0
- package/dist/cli/components/Messages.js.map +1 -0
- package/dist/cli/components/ModelSelector.d.ts +13 -0
- package/dist/cli/components/ModelSelector.d.ts.map +1 -0
- package/dist/cli/components/ModelSelector.js +72 -0
- package/dist/cli/components/ModelSelector.js.map +1 -0
- package/dist/cli/components/Spinner.d.ts +12 -0
- package/dist/cli/components/Spinner.d.ts.map +1 -0
- package/dist/cli/components/Spinner.js +45 -0
- package/dist/cli/components/Spinner.js.map +1 -0
- package/dist/cli/components/index.d.ts +12 -0
- package/dist/cli/components/index.d.ts.map +1 -0
- package/dist/cli/components/index.js +12 -0
- package/dist/cli/components/index.js.map +1 -0
- package/dist/cli/components/theme.d.ts +31 -0
- package/dist/cli/components/theme.d.ts.map +1 -0
- package/dist/cli/components/theme.js +36 -0
- package/dist/cli/components/theme.js.map +1 -0
- package/dist/cli/index-legacy.d.ts +7 -0
- package/dist/cli/index-legacy.d.ts.map +1 -0
- package/dist/cli/index-legacy.js +431 -0
- package/dist/cli/index-legacy.js.map +1 -0
- package/dist/cli/index.d.ts +7 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +116 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/ink-cli.d.ts +7 -0
- package/dist/cli/ink-cli.d.ts.map +1 -0
- package/dist/cli/ink-cli.js +105 -0
- package/dist/cli/ink-cli.js.map +1 -0
- package/dist/cli/session-picker.d.ts +16 -0
- package/dist/cli/session-picker.d.ts.map +1 -0
- package/dist/cli/session-picker.js +280 -0
- package/dist/cli/session-picker.js.map +1 -0
- package/dist/cli/ui.d.ts +61 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +364 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/config/index.d.ts +7 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/manager.d.ts +31 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +65 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/config/types.d.ts +22 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +6 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/index.d.ts +10 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +9 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/init.d.ts +20 -0
- package/dist/memory/init.d.ts.map +1 -0
- package/dist/memory/init.js +332 -0
- package/dist/memory/init.js.map +1 -0
- package/dist/memory/manager.d.ts +85 -0
- package/dist/memory/manager.d.ts.map +1 -0
- package/dist/memory/manager.js +234 -0
- package/dist/memory/manager.js.map +1 -0
- package/dist/memory/types.d.ts +74 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +6 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/permissions/index.d.ts +7 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +6 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/permissions/manager.d.ts +32 -0
- package/dist/permissions/manager.d.ts.map +1 -0
- package/dist/permissions/manager.js +79 -0
- package/dist/permissions/manager.js.map +1 -0
- package/dist/permissions/types.d.ts +14 -0
- package/dist/permissions/types.d.ts.map +1 -0
- package/dist/permissions/types.js +17 -0
- package/dist/permissions/types.js.map +1 -0
- package/dist/providers/anthropic.d.ts +20 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +185 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/gemini.d.ts +21 -0
- package/dist/providers/gemini.d.ts.map +1 -0
- package/dist/providers/gemini.js +241 -0
- package/dist/providers/gemini.js.map +1 -0
- package/dist/providers/index.d.ts +34 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +72 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/openai.d.ts +19 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +221 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/types.d.ts +125 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +6 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/session/index.d.ts +6 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +6 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/manager.d.ts +101 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +295 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/types.d.ts +39 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +10 -0
- package/dist/session/types.js.map +1 -0
- package/dist/tools/builtin/bash.d.ts +7 -0
- package/dist/tools/builtin/bash.d.ts.map +1 -0
- package/dist/tools/builtin/bash.js +80 -0
- package/dist/tools/builtin/bash.js.map +1 -0
- package/dist/tools/builtin/edit.d.ts +7 -0
- package/dist/tools/builtin/edit.d.ts.map +1 -0
- package/dist/tools/builtin/edit.js +32 -0
- package/dist/tools/builtin/edit.js.map +1 -0
- package/dist/tools/builtin/glob.d.ts +7 -0
- package/dist/tools/builtin/glob.d.ts.map +1 -0
- package/dist/tools/builtin/glob.js +36 -0
- package/dist/tools/builtin/glob.js.map +1 -0
- package/dist/tools/builtin/grep.d.ts +7 -0
- package/dist/tools/builtin/grep.d.ts.map +1 -0
- package/dist/tools/builtin/grep.js +59 -0
- package/dist/tools/builtin/grep.js.map +1 -0
- package/dist/tools/builtin/read.d.ts +7 -0
- package/dist/tools/builtin/read.d.ts.map +1 -0
- package/dist/tools/builtin/read.js +29 -0
- package/dist/tools/builtin/read.js.map +1 -0
- package/dist/tools/builtin/write.d.ts +7 -0
- package/dist/tools/builtin/write.d.ts.map +1 -0
- package/dist/tools/builtin/write.js +24 -0
- package/dist/tools/builtin/write.js.map +1 -0
- package/dist/tools/index.d.ts +38 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +32 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/registry.d.ts +22 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +71 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/types.d.ts +62 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +126 -0
- package/dist/tools/types.js.map +1 -0
- package/docs/README.md +16 -0
- package/docs/proposals/0001-web-fetch-tool.md +293 -0
- package/docs/proposals/0002-web-search-tool.md +306 -0
- package/docs/proposals/0003-task-subagents.md +333 -0
- package/docs/proposals/0004-plan-mode.md +338 -0
- package/docs/proposals/0005-todo-system.md +299 -0
- package/docs/proposals/0006-memory-system.md +539 -0
- package/docs/proposals/0007-context-management.md +429 -0
- package/docs/proposals/0008-checkpointing.md +327 -0
- package/docs/proposals/0009-hooks-system.md +343 -0
- package/docs/proposals/0010-mcp-integration.md +382 -0
- package/docs/proposals/0011-custom-commands.md +374 -0
- package/docs/proposals/0012-ask-user-question.md +317 -0
- package/docs/proposals/0013-multi-edit-tool.md +345 -0
- package/docs/proposals/0014-lsp-tool.md +478 -0
- package/docs/proposals/0015-ls-tool.md +407 -0
- package/docs/proposals/0016-kill-shell-tool.md +455 -0
- package/docs/proposals/0017-background-tasks.md +489 -0
- package/docs/proposals/0018-parallel-tool-execution.md +415 -0
- package/docs/proposals/0019-session-enhancements.md +462 -0
- package/docs/proposals/0020-session-summarization.md +447 -0
- package/docs/proposals/0021-skills-system.md +409 -0
- package/docs/proposals/0022-plugin-system.md +467 -0
- package/docs/proposals/0023-permission-enhancements.md +470 -0
- package/docs/proposals/0024-keyboard-shortcuts.md +443 -0
- package/docs/proposals/0025-cost-tracking.md +447 -0
- package/docs/proposals/0026-git-integration.md +475 -0
- package/docs/proposals/0027-enhanced-read-tool.md +514 -0
- package/docs/proposals/0028-enhanced-bash-tool.md +511 -0
- package/docs/proposals/0029-notebook-edit-tool.md +413 -0
- package/docs/proposals/0030-plugin-marketplace.md +360 -0
- package/docs/proposals/0031-command-suggestions.md +295 -0
- package/docs/proposals/0032-ide-integrations.md +328 -0
- package/docs/proposals/0033-enterprise-deployment.md +221 -0
- package/docs/proposals/0034-sandboxing.md +273 -0
- package/docs/proposals/0035-auto-updater.md +311 -0
- package/docs/proposals/0036-enhanced-glob-tool.md +267 -0
- package/docs/proposals/0037-enhanced-grep-tool.md +360 -0
- package/docs/proposals/0038-interactive-cli-ui.md +373 -0
- package/docs/proposals/0039-streaming-enhancements.md +359 -0
- package/docs/proposals/0040-multi-provider-enhancements.md +369 -0
- package/docs/proposals/README.md +84 -0
- package/docs/proposals/TEMPLATE.md +57 -0
- package/docs/proposals/research/claude-code-research.md +307 -0
- package/examples/agent-demo.ts +115 -0
- package/examples/basic.ts +166 -0
- package/package.json +50 -0
- package/src/agent/agent.ts +276 -0
- package/src/agent/index.ts +6 -0
- package/src/agent/types.ts +62 -0
- package/src/cli/components/App.tsx +565 -0
- package/src/cli/components/CommandSuggestions.tsx +58 -0
- package/src/cli/components/Header.tsx +36 -0
- package/src/cli/components/Input.tsx +60 -0
- package/src/cli/components/Logo.tsx +16 -0
- package/src/cli/components/Messages.tsx +210 -0
- package/src/cli/components/ModelSelector.tsx +135 -0
- package/src/cli/components/Spinner.tsx +72 -0
- package/src/cli/components/index.ts +21 -0
- package/src/cli/components/theme.ts +36 -0
- package/src/cli/index.tsx +136 -0
- package/src/config/index.ts +7 -0
- package/src/config/manager.ts +77 -0
- package/src/config/types.ts +25 -0
- package/src/index.ts +86 -0
- package/src/permissions/index.ts +7 -0
- package/src/permissions/manager.ts +97 -0
- package/src/permissions/types.ts +29 -0
- package/src/providers/anthropic.ts +224 -0
- package/src/providers/gemini.ts +295 -0
- package/src/providers/index.ts +97 -0
- package/src/providers/openai.ts +261 -0
- package/src/providers/types.ts +181 -0
- package/src/session/index.ts +6 -0
- package/src/session/manager.ts +354 -0
- package/src/session/types.ts +49 -0
- package/src/tools/builtin/bash.ts +92 -0
- package/src/tools/builtin/edit.ts +37 -0
- package/src/tools/builtin/glob.ts +42 -0
- package/src/tools/builtin/grep.ts +67 -0
- package/src/tools/builtin/read.ts +34 -0
- package/src/tools/builtin/write.ts +27 -0
- package/src/tools/index.ts +36 -0
- package/src/tools/registry.ts +83 -0
- package/src/tools/types.ts +172 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Manager - Persists user settings (Claude Code style)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import * as fs from 'fs/promises';
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import * as os from 'os';
|
|
8
|
+
import type { Settings, SettingsManagerOptions } from './types.js';
|
|
9
|
+
import { DEFAULT_SETTINGS_DIR, SETTINGS_FILE_NAME } from './types.js';
|
|
10
|
+
|
|
11
|
+
export class SettingsManager {
|
|
12
|
+
private settingsDir: string;
|
|
13
|
+
private settingsPath: string;
|
|
14
|
+
private settings: Settings = {};
|
|
15
|
+
|
|
16
|
+
constructor(options: SettingsManagerOptions = {}) {
|
|
17
|
+
const dir = options.settingsDir ?? DEFAULT_SETTINGS_DIR;
|
|
18
|
+
this.settingsDir = dir.replace('~', os.homedir());
|
|
19
|
+
this.settingsPath = path.join(this.settingsDir, SETTINGS_FILE_NAME);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Ensure settings directory exists
|
|
24
|
+
*/
|
|
25
|
+
private async ensureDir(): Promise<void> {
|
|
26
|
+
try {
|
|
27
|
+
await fs.mkdir(this.settingsDir, { recursive: true });
|
|
28
|
+
} catch {
|
|
29
|
+
// Directory may already exist
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Load settings from disk
|
|
35
|
+
*/
|
|
36
|
+
async load(): Promise<Settings> {
|
|
37
|
+
try {
|
|
38
|
+
const content = await fs.readFile(this.settingsPath, 'utf-8');
|
|
39
|
+
this.settings = JSON.parse(content);
|
|
40
|
+
return this.settings;
|
|
41
|
+
} catch {
|
|
42
|
+
// File doesn't exist or is invalid
|
|
43
|
+
this.settings = {};
|
|
44
|
+
return this.settings;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Save settings to disk (merges with existing)
|
|
50
|
+
*/
|
|
51
|
+
async save(updates: Partial<Settings>): Promise<void> {
|
|
52
|
+
await this.ensureDir();
|
|
53
|
+
|
|
54
|
+
// Merge updates with existing settings
|
|
55
|
+
this.settings = { ...this.settings, ...updates };
|
|
56
|
+
|
|
57
|
+
await fs.writeFile(
|
|
58
|
+
this.settingsPath,
|
|
59
|
+
JSON.stringify(this.settings, null, 2),
|
|
60
|
+
'utf-8'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Get current settings
|
|
66
|
+
*/
|
|
67
|
+
get(): Settings {
|
|
68
|
+
return { ...this.settings };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get settings file path
|
|
73
|
+
*/
|
|
74
|
+
getPath(): string {
|
|
75
|
+
return this.settingsPath;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings Types - User settings persistence (Claude Code style)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type ProviderName = 'openai' | 'anthropic' | 'gemini';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Settings file structure (~/.gencode/settings.json)
|
|
9
|
+
* Similar to Claude Code's settings.json
|
|
10
|
+
*/
|
|
11
|
+
export interface Settings {
|
|
12
|
+
model?: string;
|
|
13
|
+
provider?: ProviderName;
|
|
14
|
+
permissions?: {
|
|
15
|
+
allow?: string[];
|
|
16
|
+
deny?: string[];
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface SettingsManagerOptions {
|
|
21
|
+
settingsDir?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const DEFAULT_SETTINGS_DIR = '~/.gencode';
|
|
25
|
+
export const SETTINGS_FILE_NAME = 'settings.json';
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recode - Multi-LLM Agent SDK
|
|
3
|
+
*
|
|
4
|
+
* A unified SDK for building AI agents with support for
|
|
5
|
+
* OpenAI, Anthropic, and Google Gemini models.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Providers
|
|
9
|
+
export {
|
|
10
|
+
// Types
|
|
11
|
+
type LLMProvider,
|
|
12
|
+
type Message,
|
|
13
|
+
type MessageRole,
|
|
14
|
+
type MessageContent,
|
|
15
|
+
type TextContent,
|
|
16
|
+
type ToolUseContent,
|
|
17
|
+
type ToolResultContent,
|
|
18
|
+
type ToolDefinition,
|
|
19
|
+
type ToolCall,
|
|
20
|
+
type ToolResult,
|
|
21
|
+
type CompletionOptions,
|
|
22
|
+
type CompletionResponse,
|
|
23
|
+
type StreamChunk,
|
|
24
|
+
type StopReason,
|
|
25
|
+
type OpenAIConfig,
|
|
26
|
+
type AnthropicConfig,
|
|
27
|
+
type GeminiConfig,
|
|
28
|
+
type ProviderConfig,
|
|
29
|
+
type ProviderName,
|
|
30
|
+
// Providers
|
|
31
|
+
OpenAIProvider,
|
|
32
|
+
AnthropicProvider,
|
|
33
|
+
GeminiProvider,
|
|
34
|
+
// Factory
|
|
35
|
+
createProvider,
|
|
36
|
+
inferProvider,
|
|
37
|
+
ModelAliases,
|
|
38
|
+
} from './providers/index.js';
|
|
39
|
+
|
|
40
|
+
// Tools
|
|
41
|
+
export {
|
|
42
|
+
type Tool,
|
|
43
|
+
type ToolContext,
|
|
44
|
+
type ToolResult as ToolExecutionResult,
|
|
45
|
+
ToolRegistry,
|
|
46
|
+
createDefaultRegistry,
|
|
47
|
+
builtinTools,
|
|
48
|
+
readTool,
|
|
49
|
+
writeTool,
|
|
50
|
+
editTool,
|
|
51
|
+
bashTool,
|
|
52
|
+
globTool,
|
|
53
|
+
grepTool,
|
|
54
|
+
} from './tools/index.js';
|
|
55
|
+
|
|
56
|
+
// Permissions
|
|
57
|
+
export {
|
|
58
|
+
type PermissionMode,
|
|
59
|
+
type PermissionRule,
|
|
60
|
+
type PermissionConfig,
|
|
61
|
+
type ConfirmCallback,
|
|
62
|
+
PermissionManager,
|
|
63
|
+
DEFAULT_PERMISSION_CONFIG,
|
|
64
|
+
} from './permissions/index.js';
|
|
65
|
+
|
|
66
|
+
// Agent
|
|
67
|
+
export {
|
|
68
|
+
type AgentConfig,
|
|
69
|
+
type AgentEvent,
|
|
70
|
+
type AgentEventText,
|
|
71
|
+
type AgentEventToolStart,
|
|
72
|
+
type AgentEventToolResult,
|
|
73
|
+
type AgentEventError,
|
|
74
|
+
type AgentEventDone,
|
|
75
|
+
Agent,
|
|
76
|
+
} from './agent/index.js';
|
|
77
|
+
|
|
78
|
+
// Session
|
|
79
|
+
export {
|
|
80
|
+
type Session,
|
|
81
|
+
type SessionMetadata,
|
|
82
|
+
type SessionListItem,
|
|
83
|
+
type SessionConfig,
|
|
84
|
+
SessionManager,
|
|
85
|
+
DEFAULT_SESSION_CONFIG,
|
|
86
|
+
} from './session/index.js';
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission Manager - Controls tool execution permissions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { PermissionConfig, PermissionMode } from './types.js';
|
|
6
|
+
import { DEFAULT_PERMISSION_CONFIG } from './types.js';
|
|
7
|
+
|
|
8
|
+
export type ConfirmCallback = (
|
|
9
|
+
tool: string,
|
|
10
|
+
input: unknown
|
|
11
|
+
) => Promise<boolean>;
|
|
12
|
+
|
|
13
|
+
export class PermissionManager {
|
|
14
|
+
private config: PermissionConfig;
|
|
15
|
+
private confirmCallback?: ConfirmCallback;
|
|
16
|
+
private approvedTools: Set<string> = new Set();
|
|
17
|
+
|
|
18
|
+
constructor(config?: Partial<PermissionConfig>) {
|
|
19
|
+
this.config = {
|
|
20
|
+
...DEFAULT_PERMISSION_CONFIG,
|
|
21
|
+
...config,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Set the confirmation callback
|
|
27
|
+
*/
|
|
28
|
+
setConfirmCallback(callback: ConfirmCallback): void {
|
|
29
|
+
this.confirmCallback = callback;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get the permission mode for a tool
|
|
34
|
+
*/
|
|
35
|
+
getModeForTool(tool: string): PermissionMode {
|
|
36
|
+
for (const rule of this.config.rules) {
|
|
37
|
+
if (typeof rule.tool === 'string') {
|
|
38
|
+
if (rule.tool === tool) {
|
|
39
|
+
return rule.mode;
|
|
40
|
+
}
|
|
41
|
+
} else if (rule.tool.test(tool)) {
|
|
42
|
+
return rule.mode;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return this.config.defaultMode;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Check if a tool can be executed
|
|
50
|
+
*/
|
|
51
|
+
async checkPermission(tool: string, input: unknown): Promise<boolean> {
|
|
52
|
+
const mode = this.getModeForTool(tool);
|
|
53
|
+
|
|
54
|
+
switch (mode) {
|
|
55
|
+
case 'auto':
|
|
56
|
+
return true;
|
|
57
|
+
|
|
58
|
+
case 'deny':
|
|
59
|
+
return false;
|
|
60
|
+
|
|
61
|
+
case 'confirm':
|
|
62
|
+
// Check if already approved this session
|
|
63
|
+
const key = `${tool}:${JSON.stringify(input)}`;
|
|
64
|
+
if (this.approvedTools.has(key)) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!this.confirmCallback) {
|
|
69
|
+
// No callback, auto-approve in non-interactive mode
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const approved = await this.confirmCallback(tool, input);
|
|
74
|
+
if (approved) {
|
|
75
|
+
this.approvedTools.add(key);
|
|
76
|
+
}
|
|
77
|
+
return approved;
|
|
78
|
+
|
|
79
|
+
default:
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Approve a tool for this session
|
|
86
|
+
*/
|
|
87
|
+
approveToolForSession(tool: string): void {
|
|
88
|
+
this.approvedTools.add(tool);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Clear all session approvals
|
|
93
|
+
*/
|
|
94
|
+
clearApprovals(): void {
|
|
95
|
+
this.approvedTools.clear();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Permission System Types
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type PermissionMode = 'auto' | 'confirm' | 'deny';
|
|
6
|
+
|
|
7
|
+
export interface PermissionRule {
|
|
8
|
+
tool: string | RegExp;
|
|
9
|
+
mode: PermissionMode;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PermissionConfig {
|
|
13
|
+
defaultMode: PermissionMode;
|
|
14
|
+
rules: PermissionRule[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const DEFAULT_PERMISSION_CONFIG: PermissionConfig = {
|
|
18
|
+
defaultMode: 'confirm',
|
|
19
|
+
rules: [
|
|
20
|
+
// Read-only tools are auto-approved
|
|
21
|
+
{ tool: 'Read', mode: 'auto' },
|
|
22
|
+
{ tool: 'Glob', mode: 'auto' },
|
|
23
|
+
{ tool: 'Grep', mode: 'auto' },
|
|
24
|
+
// Write operations require confirmation
|
|
25
|
+
{ tool: 'Write', mode: 'confirm' },
|
|
26
|
+
{ tool: 'Edit', mode: 'confirm' },
|
|
27
|
+
{ tool: 'Bash', mode: 'confirm' },
|
|
28
|
+
],
|
|
29
|
+
};
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anthropic Provider Implementation
|
|
3
|
+
* Supports Claude 3.5 Sonnet, Claude 3 Opus, Claude 3 Haiku, etc.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
7
|
+
import type {
|
|
8
|
+
LLMProvider,
|
|
9
|
+
CompletionOptions,
|
|
10
|
+
CompletionResponse,
|
|
11
|
+
StreamChunk,
|
|
12
|
+
Message,
|
|
13
|
+
MessageContent,
|
|
14
|
+
ToolDefinition,
|
|
15
|
+
StopReason,
|
|
16
|
+
AnthropicConfig,
|
|
17
|
+
ModelInfo,
|
|
18
|
+
} from './types.js';
|
|
19
|
+
|
|
20
|
+
type AnthropicMessage = Anthropic.MessageParam;
|
|
21
|
+
type AnthropicTool = Anthropic.Tool;
|
|
22
|
+
type AnthropicContent = Anthropic.ContentBlockParam;
|
|
23
|
+
|
|
24
|
+
export class AnthropicProvider implements LLMProvider {
|
|
25
|
+
readonly name = 'anthropic';
|
|
26
|
+
private client: Anthropic;
|
|
27
|
+
|
|
28
|
+
constructor(config: AnthropicConfig = {}) {
|
|
29
|
+
this.client = new Anthropic({
|
|
30
|
+
apiKey: config.apiKey ?? process.env.ANTHROPIC_API_KEY,
|
|
31
|
+
baseURL: config.baseURL,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async complete(options: CompletionOptions): Promise<CompletionResponse> {
|
|
36
|
+
const messages = this.convertMessages(options.messages);
|
|
37
|
+
const tools = options.tools ? this.convertTools(options.tools) : undefined;
|
|
38
|
+
|
|
39
|
+
const response = await this.client.messages.create({
|
|
40
|
+
model: options.model,
|
|
41
|
+
messages,
|
|
42
|
+
tools,
|
|
43
|
+
system: options.systemPrompt,
|
|
44
|
+
max_tokens: options.maxTokens ?? 4096,
|
|
45
|
+
temperature: options.temperature,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return this.convertResponse(response);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async *stream(options: CompletionOptions): AsyncGenerator<StreamChunk, void, unknown> {
|
|
52
|
+
const messages = this.convertMessages(options.messages);
|
|
53
|
+
const tools = options.tools ? this.convertTools(options.tools) : undefined;
|
|
54
|
+
|
|
55
|
+
const stream = this.client.messages.stream({
|
|
56
|
+
model: options.model,
|
|
57
|
+
messages,
|
|
58
|
+
tools,
|
|
59
|
+
system: options.systemPrompt,
|
|
60
|
+
max_tokens: options.maxTokens ?? 4096,
|
|
61
|
+
temperature: options.temperature,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const toolInputBuffers: Map<number, { id: string; name: string; input: string }> = new Map();
|
|
65
|
+
|
|
66
|
+
for await (const event of stream) {
|
|
67
|
+
if (event.type === 'content_block_start') {
|
|
68
|
+
const block = event.content_block;
|
|
69
|
+
|
|
70
|
+
if (block.type === 'tool_use') {
|
|
71
|
+
toolInputBuffers.set(event.index, {
|
|
72
|
+
id: block.id,
|
|
73
|
+
name: block.name,
|
|
74
|
+
input: '',
|
|
75
|
+
});
|
|
76
|
+
yield { type: 'tool_start', id: block.id, name: block.name };
|
|
77
|
+
}
|
|
78
|
+
} else if (event.type === 'content_block_delta') {
|
|
79
|
+
const delta = event.delta;
|
|
80
|
+
|
|
81
|
+
if (delta.type === 'text_delta') {
|
|
82
|
+
yield { type: 'text', text: delta.text };
|
|
83
|
+
} else if (delta.type === 'input_json_delta') {
|
|
84
|
+
const buffer = toolInputBuffers.get(event.index);
|
|
85
|
+
if (buffer) {
|
|
86
|
+
buffer.input += delta.partial_json;
|
|
87
|
+
yield { type: 'tool_input', id: buffer.id, input: delta.partial_json };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Get final message
|
|
94
|
+
const finalMessage = await stream.finalMessage();
|
|
95
|
+
const content = this.convertContent(finalMessage.content);
|
|
96
|
+
|
|
97
|
+
yield {
|
|
98
|
+
type: 'done',
|
|
99
|
+
response: {
|
|
100
|
+
content,
|
|
101
|
+
stopReason: this.convertStopReason(finalMessage.stop_reason),
|
|
102
|
+
usage: {
|
|
103
|
+
inputTokens: finalMessage.usage.input_tokens,
|
|
104
|
+
outputTokens: finalMessage.usage.output_tokens,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private convertMessages(messages: Message[]): AnthropicMessage[] {
|
|
111
|
+
const result: AnthropicMessage[] = [];
|
|
112
|
+
|
|
113
|
+
for (const msg of messages) {
|
|
114
|
+
// Skip system messages - handled separately
|
|
115
|
+
if (msg.role === 'system') {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (msg.role === 'user') {
|
|
120
|
+
const content = this.convertToAnthropicContent(msg.content, 'user');
|
|
121
|
+
result.push({ role: 'user', content });
|
|
122
|
+
} else if (msg.role === 'assistant') {
|
|
123
|
+
const content = this.convertToAnthropicContent(msg.content, 'assistant');
|
|
124
|
+
result.push({ role: 'assistant', content });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
private convertToAnthropicContent(
|
|
132
|
+
content: string | MessageContent[],
|
|
133
|
+
role: 'user' | 'assistant'
|
|
134
|
+
): AnthropicContent[] | string {
|
|
135
|
+
if (typeof content === 'string') {
|
|
136
|
+
return content;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const result: AnthropicContent[] = [];
|
|
140
|
+
|
|
141
|
+
for (const item of content) {
|
|
142
|
+
if (item.type === 'text') {
|
|
143
|
+
result.push({ type: 'text', text: item.text });
|
|
144
|
+
} else if (item.type === 'tool_use' && role === 'assistant') {
|
|
145
|
+
result.push({
|
|
146
|
+
type: 'tool_use',
|
|
147
|
+
id: item.id,
|
|
148
|
+
name: item.name,
|
|
149
|
+
input: item.input,
|
|
150
|
+
});
|
|
151
|
+
} else if (item.type === 'tool_result' && role === 'user') {
|
|
152
|
+
result.push({
|
|
153
|
+
type: 'tool_result',
|
|
154
|
+
tool_use_id: item.toolUseId,
|
|
155
|
+
content: item.content,
|
|
156
|
+
is_error: item.isError,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return result.length > 0 ? result : '';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
private convertTools(tools: ToolDefinition[]): AnthropicTool[] {
|
|
165
|
+
return tools.map((tool) => ({
|
|
166
|
+
name: tool.name,
|
|
167
|
+
description: tool.description,
|
|
168
|
+
input_schema: tool.parameters as Anthropic.Tool.InputSchema,
|
|
169
|
+
}));
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private convertResponse(response: Anthropic.Message): CompletionResponse {
|
|
173
|
+
return {
|
|
174
|
+
content: this.convertContent(response.content),
|
|
175
|
+
stopReason: this.convertStopReason(response.stop_reason),
|
|
176
|
+
usage: {
|
|
177
|
+
inputTokens: response.usage.input_tokens,
|
|
178
|
+
outputTokens: response.usage.output_tokens,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private convertContent(content: Anthropic.ContentBlock[]): MessageContent[] {
|
|
184
|
+
return content.map((block) => {
|
|
185
|
+
if (block.type === 'text') {
|
|
186
|
+
return { type: 'text' as const, text: block.text };
|
|
187
|
+
} else if (block.type === 'tool_use') {
|
|
188
|
+
return {
|
|
189
|
+
type: 'tool_use' as const,
|
|
190
|
+
id: block.id,
|
|
191
|
+
name: block.name,
|
|
192
|
+
input: block.input as Record<string, unknown>,
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// Fallback for unknown types
|
|
196
|
+
return { type: 'text' as const, text: '' };
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private convertStopReason(reason: Anthropic.Message['stop_reason']): StopReason {
|
|
201
|
+
switch (reason) {
|
|
202
|
+
case 'tool_use':
|
|
203
|
+
return 'tool_use';
|
|
204
|
+
case 'max_tokens':
|
|
205
|
+
return 'max_tokens';
|
|
206
|
+
case 'stop_sequence':
|
|
207
|
+
return 'stop_sequence';
|
|
208
|
+
case 'end_turn':
|
|
209
|
+
default:
|
|
210
|
+
return 'end_turn';
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
async listModels(): Promise<ModelInfo[]> {
|
|
215
|
+
const models: ModelInfo[] = [];
|
|
216
|
+
for await (const model of this.client.models.list()) {
|
|
217
|
+
models.push({
|
|
218
|
+
id: model.id,
|
|
219
|
+
name: model.display_name || model.id,
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
return models;
|
|
223
|
+
}
|
|
224
|
+
}
|