praxis-agent 0.43.1 → 0.45.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/README.md +45 -13
- package/dist/application/session-service.js +84 -4
- package/dist/application/top-level-agent-manager.d.ts +7 -0
- package/dist/application/top-level-agent-manager.js +21 -3
- package/dist/cli/controls.js +4 -0
- package/dist/cli/interactive.js +3 -1
- package/dist/cli/protocol.d.ts +5 -0
- package/dist/cli/protocol.js +45 -0
- package/dist/cli/provider-auth-command.d.ts +32 -0
- package/dist/cli/provider-auth-command.js +249 -0
- package/dist/cli/tui/quiet-frame.js +4 -4
- package/dist/cli/tui/transcript-viewport.js +3 -3
- package/dist/cli/workspace-trust-prompt.js +2 -2
- package/dist/cli-runtime.d.ts +34 -1
- package/dist/cli-runtime.js +587 -184
- package/dist/maintenance/doctor.js +100 -22
- package/dist/persistence/provider-credential-vault.d.ts +72 -0
- package/dist/persistence/provider-credential-vault.js +498 -0
- package/dist/providers/codex-oauth.d.ts +104 -0
- package/dist/providers/codex-oauth.js +770 -0
- package/dist/providers/codex-subscription.d.ts +33 -0
- package/dist/providers/codex-subscription.js +849 -0
- package/dist/providers/provider-auth.d.ts +71 -0
- package/dist/providers/provider-auth.js +149 -0
- package/dist/providers/provider-registry.d.ts +52 -0
- package/dist/providers/provider-registry.js +187 -0
- package/dist/providers/provider-settings.d.ts +38 -0
- package/dist/providers/provider-settings.js +334 -0
- package/dist/security/workspace-trust.d.ts +4 -3
- package/dist/security/workspace-trust.js +35 -1
- package/package.json +6 -3
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { ProviderTarget } from './provider-settings.js';
|
|
2
|
+
interface ProviderCredentialKey {
|
|
3
|
+
providerId: string;
|
|
4
|
+
profileId: string;
|
|
5
|
+
}
|
|
6
|
+
type ProviderCredentialRecord = {
|
|
7
|
+
type: 'api-key';
|
|
8
|
+
secret: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'oauth';
|
|
11
|
+
accessToken: string;
|
|
12
|
+
refreshToken: string;
|
|
13
|
+
expiresAt: number;
|
|
14
|
+
accountId?: string;
|
|
15
|
+
};
|
|
16
|
+
export interface ProviderCredentialReader {
|
|
17
|
+
read(key: ProviderCredentialKey): Promise<ProviderCredentialRecord | undefined>;
|
|
18
|
+
}
|
|
19
|
+
export type ProviderAuthenticationErrorCode = 'missing_credential' | 'invalid_credential' | 'command_failed';
|
|
20
|
+
export declare class ProviderAuthenticationError extends Error {
|
|
21
|
+
readonly code: ProviderAuthenticationErrorCode;
|
|
22
|
+
constructor(code: ProviderAuthenticationErrorCode, message: string);
|
|
23
|
+
}
|
|
24
|
+
export type ProviderCredentialSourceMetadata = {
|
|
25
|
+
source: 'explicit';
|
|
26
|
+
} | {
|
|
27
|
+
source: 'legacy-env';
|
|
28
|
+
name: 'PRAXIS_API_KEY';
|
|
29
|
+
} | {
|
|
30
|
+
source: 'env';
|
|
31
|
+
name: string;
|
|
32
|
+
} | {
|
|
33
|
+
source: 'command';
|
|
34
|
+
command: readonly string[];
|
|
35
|
+
} | {
|
|
36
|
+
source: 'vault';
|
|
37
|
+
providerId: string;
|
|
38
|
+
profileId: string;
|
|
39
|
+
};
|
|
40
|
+
export type ResolvedApiKeyCredential = {
|
|
41
|
+
type: 'api-key';
|
|
42
|
+
secret: string;
|
|
43
|
+
source: ProviderCredentialSourceMetadata;
|
|
44
|
+
};
|
|
45
|
+
export type ResolvedOAuthCredential = {
|
|
46
|
+
type: 'oauth';
|
|
47
|
+
accessToken: string;
|
|
48
|
+
refreshToken: string;
|
|
49
|
+
expiresAt: number;
|
|
50
|
+
accountId?: string;
|
|
51
|
+
source: ProviderCredentialSourceMetadata;
|
|
52
|
+
};
|
|
53
|
+
export type ResolvedProviderCredential = ResolvedApiKeyCredential | ResolvedOAuthCredential;
|
|
54
|
+
export interface ProviderCommandResult {
|
|
55
|
+
stdout: string;
|
|
56
|
+
exitCode: number;
|
|
57
|
+
}
|
|
58
|
+
export type ProviderCommandRunner = (argv: readonly string[], options: {
|
|
59
|
+
timeoutMs: number;
|
|
60
|
+
maxOutputBytes: number;
|
|
61
|
+
}) => Promise<ProviderCommandResult>;
|
|
62
|
+
export interface ResolveProviderCredentialOptions {
|
|
63
|
+
target: ProviderTarget;
|
|
64
|
+
environment?: Readonly<Record<string, string | undefined>>;
|
|
65
|
+
vault: ProviderCredentialReader;
|
|
66
|
+
apiKey?: string;
|
|
67
|
+
commandRunner?: ProviderCommandRunner;
|
|
68
|
+
}
|
|
69
|
+
export declare function resolveProviderCredential(options: ResolveProviderCredentialOptions): Promise<ResolvedProviderCredential>;
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=provider-auth.d.ts.map
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
export class ProviderAuthenticationError extends Error {
|
|
4
|
+
code;
|
|
5
|
+
constructor(code, message) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = 'ProviderAuthenticationError';
|
|
8
|
+
this.code = code;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
const COMMAND_TIMEOUT_MS = 10_000;
|
|
13
|
+
const MAX_COMMAND_OUTPUT = 64 * 1024;
|
|
14
|
+
function missing(message) {
|
|
15
|
+
throw new ProviderAuthenticationError('missing_credential', `Provider authentication failed: ${message}`);
|
|
16
|
+
}
|
|
17
|
+
function secretValue(value, label) {
|
|
18
|
+
if (typeof value !== 'string' || value.trim().length === 0)
|
|
19
|
+
missing(`${label} is missing or blank`);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
const defaultCommandRunner = async (argv, options) => {
|
|
23
|
+
const executable = argv[0];
|
|
24
|
+
if (executable === undefined || executable.length === 0)
|
|
25
|
+
missing('credential command is empty');
|
|
26
|
+
try {
|
|
27
|
+
const result = await execFileAsync(executable, argv.slice(1), {
|
|
28
|
+
shell: false,
|
|
29
|
+
timeout: options.timeoutMs,
|
|
30
|
+
maxBuffer: options.maxOutputBytes,
|
|
31
|
+
});
|
|
32
|
+
return { stdout: result.stdout, exitCode: 0 };
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
const stdout = typeof error.stdout === 'string'
|
|
36
|
+
? error.stdout
|
|
37
|
+
: '';
|
|
38
|
+
const exitCode = typeof error.code === 'number'
|
|
39
|
+
? error.code
|
|
40
|
+
: 1;
|
|
41
|
+
return { stdout, exitCode };
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
function keyFor(target, profileId = target.profileId) {
|
|
45
|
+
return { providerId: target.providerId, profileId };
|
|
46
|
+
}
|
|
47
|
+
async function vaultApiKey(target, vault, profileId) {
|
|
48
|
+
let record;
|
|
49
|
+
try {
|
|
50
|
+
record = await vault.read(keyFor(target, profileId));
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
missing(`vault credential for ${target.providerId}/${profileId} is unavailable`);
|
|
54
|
+
}
|
|
55
|
+
if (!record || record.type !== 'api-key')
|
|
56
|
+
missing(`vault API key for ${target.providerId}/${profileId} is unavailable`);
|
|
57
|
+
return {
|
|
58
|
+
type: 'api-key',
|
|
59
|
+
secret: record.secret,
|
|
60
|
+
source: { source: 'vault', providerId: target.providerId, profileId },
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export async function resolveProviderCredential(options) {
|
|
64
|
+
const { target } = options;
|
|
65
|
+
const environment = options.environment ?? process.env;
|
|
66
|
+
const explicitProvided = options.apiKey !== undefined;
|
|
67
|
+
const legacyProvided = environment.PRAXIS_API_KEY !== undefined;
|
|
68
|
+
if (target.protocol === 'codex-subscription') {
|
|
69
|
+
if (explicitProvided || legacyProvided)
|
|
70
|
+
missing('Codex subscription does not accept API keys');
|
|
71
|
+
if (target.credential.source !== 'vault')
|
|
72
|
+
missing('Codex subscription requires a vault OAuth credential');
|
|
73
|
+
const profileId = target.credential.profile ?? target.profileId;
|
|
74
|
+
if (profileId !== target.profileId)
|
|
75
|
+
missing('Codex subscription vault profile must match the selected profile');
|
|
76
|
+
let record;
|
|
77
|
+
try {
|
|
78
|
+
record = await options.vault.read(keyFor(target, target.profileId));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
missing(`vault credential for ${target.providerId}/${target.profileId} is unavailable`);
|
|
82
|
+
}
|
|
83
|
+
if (!record || record.type !== 'oauth')
|
|
84
|
+
missing(`vault OAuth credential for ${target.providerId}/${target.profileId} is unavailable`);
|
|
85
|
+
return {
|
|
86
|
+
type: 'oauth',
|
|
87
|
+
accessToken: record.accessToken,
|
|
88
|
+
refreshToken: record.refreshToken,
|
|
89
|
+
expiresAt: record.expiresAt,
|
|
90
|
+
...(record.accountId === undefined
|
|
91
|
+
? {}
|
|
92
|
+
: { accountId: record.accountId }),
|
|
93
|
+
source: {
|
|
94
|
+
source: 'vault',
|
|
95
|
+
providerId: target.providerId,
|
|
96
|
+
profileId: target.profileId,
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (explicitProvided) {
|
|
101
|
+
return {
|
|
102
|
+
type: 'api-key',
|
|
103
|
+
secret: secretValue(options.apiKey, 'explicit API key'),
|
|
104
|
+
source: { source: 'explicit' },
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
if (legacyProvided) {
|
|
108
|
+
return {
|
|
109
|
+
type: 'api-key',
|
|
110
|
+
secret: secretValue(environment.PRAXIS_API_KEY, 'PRAXIS_API_KEY'),
|
|
111
|
+
source: { source: 'legacy-env', name: 'PRAXIS_API_KEY' },
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const source = target.credential;
|
|
115
|
+
if (source.source === 'env') {
|
|
116
|
+
return {
|
|
117
|
+
type: 'api-key',
|
|
118
|
+
secret: secretValue(environment[source.name], source.name),
|
|
119
|
+
source: { source: 'env', name: source.name },
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
if (source.source === 'command') {
|
|
123
|
+
const runner = options.commandRunner ?? defaultCommandRunner;
|
|
124
|
+
let result;
|
|
125
|
+
try {
|
|
126
|
+
result = await runner(source.command, {
|
|
127
|
+
timeoutMs: COMMAND_TIMEOUT_MS,
|
|
128
|
+
maxOutputBytes: MAX_COMMAND_OUTPUT,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
missing('credential command failed');
|
|
133
|
+
}
|
|
134
|
+
if (result.exitCode !== 0)
|
|
135
|
+
missing('credential command exited unsuccessfully');
|
|
136
|
+
const output = secretValue(result.stdout, 'credential command output').trim();
|
|
137
|
+
if (output.length > MAX_COMMAND_OUTPUT)
|
|
138
|
+
missing('credential command output exceeds 64 KiB');
|
|
139
|
+
if (/\r?\n/u.test(output))
|
|
140
|
+
missing('credential command must return exactly one secret');
|
|
141
|
+
return {
|
|
142
|
+
type: 'api-key',
|
|
143
|
+
secret: output,
|
|
144
|
+
source: { source: 'command', command: source.command },
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return vaultApiKey(target, options.vault, source.profile ?? target.profileId);
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=provider-auth.js.map
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ModelProvider, ModelThinkingConfig } from '../core/runtime.js';
|
|
2
|
+
import { type CodexOAuthVault } from './codex-oauth.js';
|
|
3
|
+
import { type ProviderTarget } from './provider-settings.js';
|
|
4
|
+
import type { ProviderCredentialSourceMetadata, ProviderCredentialReader, ResolvedProviderCredential } from './provider-auth.js';
|
|
5
|
+
import { parseProviderEnvironment, type ContextEnvironment } from './environment.js';
|
|
6
|
+
import { type AnthropicPromptCachePolicy } from './anthropic-prompt-cache.js';
|
|
7
|
+
export type ProviderRegistryErrorCode = 'unsupported_provider';
|
|
8
|
+
export declare class ProviderRegistryError extends Error {
|
|
9
|
+
readonly code: ProviderRegistryErrorCode;
|
|
10
|
+
constructor(code: ProviderRegistryErrorCode, message: string);
|
|
11
|
+
}
|
|
12
|
+
export interface ProviderRegistryOptions {
|
|
13
|
+
target: ProviderTarget;
|
|
14
|
+
credential: ResolvedProviderCredential;
|
|
15
|
+
context?: ContextEnvironment;
|
|
16
|
+
anthropicThinking?: ModelThinkingConfig;
|
|
17
|
+
openAiThinking?: ModelThinkingConfig;
|
|
18
|
+
codexThinking?: ModelThinkingConfig;
|
|
19
|
+
anthropicPromptCacheResolver?: (target: {
|
|
20
|
+
baseUrl: string;
|
|
21
|
+
model: string;
|
|
22
|
+
}) => AnthropicPromptCachePolicy;
|
|
23
|
+
fetchImplementation?: typeof fetch;
|
|
24
|
+
providerEnvironment?: ReturnType<typeof parseProviderEnvironment>;
|
|
25
|
+
vault?: CodexOAuthVault;
|
|
26
|
+
}
|
|
27
|
+
export interface ResolveProviderRegistryOptions {
|
|
28
|
+
configRoot: string;
|
|
29
|
+
cwd: string;
|
|
30
|
+
environment?: Readonly<Record<string, string | undefined>>;
|
|
31
|
+
provider?: string;
|
|
32
|
+
profile?: string;
|
|
33
|
+
model?: string;
|
|
34
|
+
includeSettings?: boolean;
|
|
35
|
+
includeProjectSettings?: boolean;
|
|
36
|
+
apiKey?: string;
|
|
37
|
+
context?: ContextEnvironment;
|
|
38
|
+
anthropicThinking?: ModelThinkingConfig;
|
|
39
|
+
openAiThinking?: ModelThinkingConfig;
|
|
40
|
+
codexThinking?: ModelThinkingConfig;
|
|
41
|
+
vault: ProviderCredentialReader & CodexOAuthVault;
|
|
42
|
+
fetchImplementation?: typeof fetch;
|
|
43
|
+
}
|
|
44
|
+
export type ProviderRegistrySourceMetadata = ProviderCredentialSourceMetadata;
|
|
45
|
+
export interface ProviderRegistry {
|
|
46
|
+
readonly target: ProviderTarget;
|
|
47
|
+
readonly credentialSource: ProviderRegistrySourceMetadata;
|
|
48
|
+
create(modelId?: string): ModelProvider;
|
|
49
|
+
}
|
|
50
|
+
export declare function resolveProviderRegistry(options: ResolveProviderRegistryOptions): Promise<ProviderRegistry>;
|
|
51
|
+
export declare function createProviderRegistry(options: ProviderRegistryOptions): ProviderRegistry;
|
|
52
|
+
//# sourceMappingURL=provider-registry.d.ts.map
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { AnthropicCompatibleProvider } from './anthropic-compatible.js';
|
|
2
|
+
import { OpenAICompatibleProvider } from './openai-compatible.js';
|
|
3
|
+
import { CodexSubscriptionProvider } from './codex-subscription.js';
|
|
4
|
+
import { DeadlineModelProvider } from './deadline-provider.js';
|
|
5
|
+
import { CodexOAuthCredentialManager, } from './codex-oauth.js';
|
|
6
|
+
import { resolveProviderTarget, } from './provider-settings.js';
|
|
7
|
+
import { ProviderAuthenticationError, resolveProviderCredential, } from './provider-auth.js';
|
|
8
|
+
import { parseContextEnvironment, parseProviderEnvironment, } from './environment.js';
|
|
9
|
+
import { createAnthropicPromptCachePolicyResolver, } from './anthropic-prompt-cache.js';
|
|
10
|
+
export class ProviderRegistryError extends Error {
|
|
11
|
+
code;
|
|
12
|
+
constructor(code, message) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = 'ProviderRegistryError';
|
|
15
|
+
this.code = code;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export async function resolveProviderRegistry(options) {
|
|
19
|
+
const environment = options.environment ?? process.env;
|
|
20
|
+
const target = await resolveProviderTarget({
|
|
21
|
+
configRoot: options.configRoot,
|
|
22
|
+
cwd: options.cwd,
|
|
23
|
+
environment,
|
|
24
|
+
...(options.provider === undefined ? {} : { provider: options.provider }),
|
|
25
|
+
...(options.profile === undefined ? {} : { profile: options.profile }),
|
|
26
|
+
...(options.model === undefined ? {} : { model: options.model }),
|
|
27
|
+
...(options.includeSettings === undefined
|
|
28
|
+
? {}
|
|
29
|
+
: { includeSettings: options.includeSettings }),
|
|
30
|
+
...(options.includeProjectSettings === undefined
|
|
31
|
+
? {}
|
|
32
|
+
: { includeProjectSettings: options.includeProjectSettings }),
|
|
33
|
+
});
|
|
34
|
+
const credential = await resolveProviderCredential({
|
|
35
|
+
target,
|
|
36
|
+
environment,
|
|
37
|
+
vault: options.vault,
|
|
38
|
+
...(options.apiKey === undefined ? {} : { apiKey: options.apiKey }),
|
|
39
|
+
});
|
|
40
|
+
const context = options.context ?? parseContextEnvironment(environment);
|
|
41
|
+
const controlsEnvironment = {
|
|
42
|
+
...environment,
|
|
43
|
+
PRAXIS_PROVIDER: target.protocol === 'anthropic-messages' ? 'anthropic' : 'openai',
|
|
44
|
+
PRAXIS_BASE_URL: target.baseUrl,
|
|
45
|
+
};
|
|
46
|
+
const providerEnvironment = parseProviderEnvironment(controlsEnvironment);
|
|
47
|
+
const promptCacheResolver = target.protocol === 'anthropic-messages'
|
|
48
|
+
? createAnthropicPromptCachePolicyResolver(controlsEnvironment)
|
|
49
|
+
: undefined;
|
|
50
|
+
return createProviderRegistry({
|
|
51
|
+
target,
|
|
52
|
+
credential,
|
|
53
|
+
context,
|
|
54
|
+
...(options.anthropicThinking === undefined
|
|
55
|
+
? {}
|
|
56
|
+
: { anthropicThinking: options.anthropicThinking }),
|
|
57
|
+
...(options.openAiThinking === undefined
|
|
58
|
+
? {}
|
|
59
|
+
: { openAiThinking: options.openAiThinking }),
|
|
60
|
+
...(options.codexThinking === undefined
|
|
61
|
+
? {}
|
|
62
|
+
: { codexThinking: options.codexThinking }),
|
|
63
|
+
...(promptCacheResolver === undefined
|
|
64
|
+
? {}
|
|
65
|
+
: { anthropicPromptCacheResolver: promptCacheResolver }),
|
|
66
|
+
...(options.fetchImplementation === undefined
|
|
67
|
+
? {}
|
|
68
|
+
: { fetchImplementation: options.fetchImplementation }),
|
|
69
|
+
providerEnvironment,
|
|
70
|
+
vault: options.vault,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export function createProviderRegistry(options) {
|
|
74
|
+
return new NativeProviderRegistry(options);
|
|
75
|
+
}
|
|
76
|
+
class NativeProviderRegistry {
|
|
77
|
+
options;
|
|
78
|
+
target;
|
|
79
|
+
credentialSource;
|
|
80
|
+
codexManager;
|
|
81
|
+
constructor(options) {
|
|
82
|
+
this.options = options;
|
|
83
|
+
this.target = options.target;
|
|
84
|
+
this.credentialSource = options.credential.source;
|
|
85
|
+
if (options.target.protocol === 'codex-subscription') {
|
|
86
|
+
if (options.credential.type !== 'oauth') {
|
|
87
|
+
throw new ProviderAuthenticationError('invalid_credential', 'Provider authentication failed: Codex subscription requires an OAuth credential');
|
|
88
|
+
}
|
|
89
|
+
if (!options.vault) {
|
|
90
|
+
throw new ProviderAuthenticationError('invalid_credential', 'Provider authentication failed: Codex subscription requires a credential vault');
|
|
91
|
+
}
|
|
92
|
+
this.codexManager = new CodexOAuthCredentialManager(options.vault, options.target.profileId, options.fetchImplementation === undefined
|
|
93
|
+
? {}
|
|
94
|
+
: { fetchImplementation: options.fetchImplementation });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
create(modelId = this.target.modelId) {
|
|
98
|
+
const target = { ...this.target, modelId };
|
|
99
|
+
if (target.protocol === 'codex-subscription') {
|
|
100
|
+
if (!this.codexManager)
|
|
101
|
+
throw new ProviderAuthenticationError('invalid_credential', 'Provider authentication failed: Codex subscription credentials are unavailable');
|
|
102
|
+
return this.withDeadline(new CodexSubscriptionProvider({
|
|
103
|
+
model: target.modelId,
|
|
104
|
+
access: this.codexManager.access.bind(this.codexManager),
|
|
105
|
+
...(this.options.fetchImplementation === undefined
|
|
106
|
+
? {}
|
|
107
|
+
: { fetchImplementation: this.options.fetchImplementation }),
|
|
108
|
+
...(this.options.codexThinking === undefined
|
|
109
|
+
? {}
|
|
110
|
+
: { thinking: this.options.codexThinking }),
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
113
|
+
if (target.protocol === 'openai-compatible') {
|
|
114
|
+
if (this.options.credential.type !== 'api-key') {
|
|
115
|
+
throw new ProviderAuthenticationError('invalid_credential', 'Provider authentication failed: an API key is required');
|
|
116
|
+
}
|
|
117
|
+
return this.withDeadline(new OpenAICompatibleProvider({
|
|
118
|
+
baseUrl: target.baseUrl,
|
|
119
|
+
model: target.modelId,
|
|
120
|
+
apiKey: this.options.credential.secret,
|
|
121
|
+
...(this.options.context?.contextWindowTokens === undefined
|
|
122
|
+
? {}
|
|
123
|
+
: {
|
|
124
|
+
contextWindowTokens: this.options.context.contextWindowTokens,
|
|
125
|
+
}),
|
|
126
|
+
...(this.options.openAiThinking === undefined
|
|
127
|
+
? {}
|
|
128
|
+
: { thinking: this.options.openAiThinking }),
|
|
129
|
+
...(this.options.fetchImplementation === undefined
|
|
130
|
+
? {}
|
|
131
|
+
: { fetchImplementation: this.options.fetchImplementation }),
|
|
132
|
+
}));
|
|
133
|
+
}
|
|
134
|
+
if (target.protocol === 'anthropic-messages') {
|
|
135
|
+
if (this.options.credential.type !== 'api-key') {
|
|
136
|
+
throw new ProviderAuthenticationError('invalid_credential', 'Provider authentication failed: an API key is required');
|
|
137
|
+
}
|
|
138
|
+
return this.withDeadline(new AnthropicCompatibleProvider({
|
|
139
|
+
baseUrl: target.baseUrl,
|
|
140
|
+
model: target.modelId,
|
|
141
|
+
apiKey: this.options.credential.secret,
|
|
142
|
+
...(this.options.context?.contextWindowTokens === undefined
|
|
143
|
+
? {}
|
|
144
|
+
: {
|
|
145
|
+
contextWindowTokens: this.options.context.contextWindowTokens,
|
|
146
|
+
}),
|
|
147
|
+
...(this.options.anthropicThinking === undefined
|
|
148
|
+
? {}
|
|
149
|
+
: {
|
|
150
|
+
thinking: this.options.anthropicThinking,
|
|
151
|
+
}),
|
|
152
|
+
...(this.options.anthropicPromptCacheResolver === undefined
|
|
153
|
+
? {}
|
|
154
|
+
: {
|
|
155
|
+
promptCaching: this.options.anthropicPromptCacheResolver({
|
|
156
|
+
baseUrl: target.baseUrl,
|
|
157
|
+
model: target.modelId,
|
|
158
|
+
}),
|
|
159
|
+
}),
|
|
160
|
+
...(this.options.providerEnvironment?.maxOutputTokens === undefined
|
|
161
|
+
? {}
|
|
162
|
+
: {
|
|
163
|
+
maxOutputTokens: this.options.providerEnvironment.maxOutputTokens,
|
|
164
|
+
}),
|
|
165
|
+
...(this.options.providerEnvironment?.anthropicVersion === undefined
|
|
166
|
+
? {}
|
|
167
|
+
: {
|
|
168
|
+
anthropicVersion: this.options.providerEnvironment.anthropicVersion,
|
|
169
|
+
}),
|
|
170
|
+
...(this.options.providerEnvironment?.webSearch === undefined
|
|
171
|
+
? {}
|
|
172
|
+
: { webSearch: this.options.providerEnvironment.webSearch }),
|
|
173
|
+
...(this.options.fetchImplementation === undefined
|
|
174
|
+
? {}
|
|
175
|
+
: { fetchImplementation: this.options.fetchImplementation }),
|
|
176
|
+
}));
|
|
177
|
+
}
|
|
178
|
+
throw new ProviderRegistryError('unsupported_provider', `Unsupported provider protocol: ${target.protocol}`);
|
|
179
|
+
}
|
|
180
|
+
withDeadline(provider) {
|
|
181
|
+
const deadlineMs = this.options.providerEnvironment?.deadlineMs;
|
|
182
|
+
return deadlineMs === undefined
|
|
183
|
+
? provider
|
|
184
|
+
: new DeadlineModelProvider({ provider, deadlineMs });
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=provider-registry.js.map
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export type ProviderProtocol = 'openai-compatible' | 'anthropic-messages' | 'codex-subscription';
|
|
2
|
+
export type CredentialSource = {
|
|
3
|
+
source: 'env';
|
|
4
|
+
name: string;
|
|
5
|
+
} | {
|
|
6
|
+
source: 'command';
|
|
7
|
+
command: readonly [string, ...string[]];
|
|
8
|
+
} | {
|
|
9
|
+
source: 'vault';
|
|
10
|
+
profile?: string;
|
|
11
|
+
};
|
|
12
|
+
export interface ProviderTarget {
|
|
13
|
+
providerId: string;
|
|
14
|
+
profileId: string;
|
|
15
|
+
modelId: string;
|
|
16
|
+
protocol: ProviderProtocol;
|
|
17
|
+
baseUrl: string;
|
|
18
|
+
credential: CredentialSource;
|
|
19
|
+
billingMode: 'api' | 'subscription';
|
|
20
|
+
experimental: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface ResolveProviderTargetOptions {
|
|
23
|
+
configRoot: string;
|
|
24
|
+
cwd: string;
|
|
25
|
+
environment?: Readonly<Record<string, string | undefined>>;
|
|
26
|
+
model?: string;
|
|
27
|
+
provider?: string;
|
|
28
|
+
profile?: string;
|
|
29
|
+
includeSettings?: boolean;
|
|
30
|
+
includeProjectSettings?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export type ProviderSettingsErrorCode = 'invalid_settings' | 'model_required' | 'unknown_provider' | 'unknown_profile';
|
|
33
|
+
export declare class ProviderSettingsError extends Error {
|
|
34
|
+
readonly code: ProviderSettingsErrorCode;
|
|
35
|
+
constructor(code: ProviderSettingsErrorCode, message: string);
|
|
36
|
+
}
|
|
37
|
+
export declare function resolveProviderTarget(options: ResolveProviderTargetOptions): Promise<ProviderTarget>;
|
|
38
|
+
//# sourceMappingURL=provider-settings.d.ts.map
|