commit
1ba0976baf
28
CHANGELOG.md
28
CHANGELOG.md
@ -6,6 +6,34 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
||||||
|
|
||||||
|
## [0.25.0] - 2026-02-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Terraform/AWS ピース: IaC 開発用の完全なピースとファセット一式を追加。plan → implement → 並列3レビュー(architect/QA/security)→ supervise → complete の15ムーブメント構成(EN/JA)
|
||||||
|
- GitProvider 抽象化: Git/GitHub 操作を `GitProvider` インターフェースに統一し、将来の複数 Git プロバイダー対応の基盤を構築 (#375)
|
||||||
|
- プロジェクト設定で submodule の自動取得をサポート: `submodules: all` または `submodules: [path1, path2]` で指定可能に (#387)
|
||||||
|
- `takt add` で GitHub Issue 作成時にラベルをインタラクティブに選択可能に (#377, #111)
|
||||||
|
- deep-research ピースにデータ保存・レポート出力機能を追加(dig/analyze ムーブメントに Write・Bash ツール許可、supervise に research-report 出力契約)
|
||||||
|
- GitHub Discussions・Discord・X への一斉アナウンス GitHub Actions ワークフローを追加
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- default ピースをテスト先行開発構成に変更: plan の後に `write_tests` ムーブメントを追加し、テストを先に書いてから実装する流れに。並列レビューに testing-review を追加(3→4 レビュアー)。レポートファイル名をセマンティック命名に統一(`00-plan.md` → `plan.md` 等)
|
||||||
|
- sync with root をピースエンジン経由からプロバイダー抽象化を利用した単発エージェント呼び出しに簡素化。コンフリクト解決プロンプトをテンプレートファイル化(EN/JA 分離)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- lineEditor でサロゲートペア(絵文字等)のカーソル位置がずれる問題を修正。Ctrl+J による改行挿入を追加
|
||||||
|
- `--task` オプションでの直接実行時に tasks.yaml へ不要な記録がされる問題を修正
|
||||||
|
- `--task` でワークツリー作成時は tasks.yaml に記録するよう修正(`takt list` でのブランチ管理に必要)
|
||||||
|
- E2E テスト config-priority の不安定性を修正 (#388)
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
|
||||||
|
- GitProvider 抽象化に伴うテスト追加(github-provider, taskGit)と既存テストのインポート更新
|
||||||
|
- CLAUDE.md 更新
|
||||||
|
|
||||||
## [0.24.0] - 2026-02-24
|
## [0.24.0] - 2026-02-24
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -6,6 +6,34 @@
|
|||||||
|
|
||||||
フォーマットは [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) に基づいています。
|
フォーマットは [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) に基づいています。
|
||||||
|
|
||||||
|
## [0.25.0] - 2026-02-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Terraform/AWS ピース: IaC 開発用の完全なピースとファセット一式を追加。plan → implement → 並列3レビュー(architect/QA/security)→ supervise → complete の15ムーブメント構成(EN/JA)
|
||||||
|
- GitProvider 抽象化: Git/GitHub 操作を `GitProvider` インターフェースに統一し、将来の複数 Git プロバイダー対応の基盤を構築 (#375)
|
||||||
|
- プロジェクト設定で submodule の自動取得をサポート: `submodules: all` または `submodules: [path1, path2]` で指定可能に (#387)
|
||||||
|
- `takt add` で GitHub Issue 作成時にラベルをインタラクティブに選択可能に (#377, #111)
|
||||||
|
- deep-research ピースにデータ保存・レポート出力機能を追加(dig/analyze ムーブメントに Write・Bash ツール許可、supervise に research-report 出力契約)
|
||||||
|
- GitHub Discussions・Discord・X への一斉アナウンス GitHub Actions ワークフローを追加
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- default ピースをテスト先行開発構成に変更: plan の後に `write_tests` ムーブメントを追加し、テストを先に書いてから実装する流れに。並列レビューに testing-review を追加(3→4 レビュアー)。レポートファイル名をセマンティック命名に統一(`00-plan.md` → `plan.md` 等)
|
||||||
|
- sync with root をピースエンジン経由からプロバイダー抽象化を利用した単発エージェント呼び出しに簡素化。コンフリクト解決プロンプトをテンプレートファイル化(EN/JA 分離)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- lineEditor でサロゲートペア(絵文字等)のカーソル位置がずれる問題を修正。Ctrl+J による改行挿入を追加
|
||||||
|
- `--task` オプションでの直接実行時に tasks.yaml へ不要な記録がされる問題を修正
|
||||||
|
- `--task` でワークツリー作成時は tasks.yaml に記録するよう修正(`takt list` でのブランチ管理に必要)
|
||||||
|
- E2E テスト config-priority の不安定性を修正 (#388)
|
||||||
|
|
||||||
|
### Internal
|
||||||
|
|
||||||
|
- GitProvider 抽象化に伴うテスト追加(github-provider, taskGit)と既存テストのインポート更新
|
||||||
|
- CLAUDE.md 更新
|
||||||
|
|
||||||
## [0.24.0] - 2026-02-24
|
## [0.24.0] - 2026-02-24
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@ -43,6 +43,7 @@ export interface CreateTestRepoOptions {
|
|||||||
function getGitHubUser(): string {
|
function getGitHubUser(): string {
|
||||||
const user = execFileSync('gh', ['api', 'user', '--jq', '.login'], {
|
const user = execFileSync('gh', ['api', 'user', '--jq', '.login'], {
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
|
stdio: 'pipe',
|
||||||
}).trim();
|
}).trim();
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
||||||
import { dirname, join, resolve } from 'node:path';
|
import { dirname, join, resolve } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { mkdirSync, writeFileSync } from 'node:fs';
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||||
|
import { parse as parseYaml } from 'yaml';
|
||||||
import { createIsolatedEnv, updateIsolatedConfig, type IsolatedEnv } from '../helpers/isolated-env';
|
import { createIsolatedEnv, updateIsolatedConfig, type IsolatedEnv } from '../helpers/isolated-env';
|
||||||
import { createTestRepo, type TestRepo } from '../helpers/test-repo';
|
import { createTestRepo, type TestRepo } from '../helpers/test-repo';
|
||||||
import { runTakt } from '../helpers/takt-runner';
|
import { runTakt } from '../helpers/takt-runner';
|
||||||
@ -9,6 +10,17 @@ import { runTakt } from '../helpers/takt-runner';
|
|||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
|
function readFirstTask(repoPath: string): Record<string, unknown> {
|
||||||
|
const tasksPath = join(repoPath, '.takt', 'tasks.yaml');
|
||||||
|
const raw = readFileSync(tasksPath, 'utf-8');
|
||||||
|
const parsed = parseYaml(raw) as { tasks?: Array<Record<string, unknown>> } | null;
|
||||||
|
const first = parsed?.tasks?.[0];
|
||||||
|
if (!first) {
|
||||||
|
throw new Error(`No task record found in ${tasksPath}`);
|
||||||
|
}
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
// E2E更新時は docs/testing/e2e.md も更新すること
|
// E2E更新時は docs/testing/e2e.md も更新すること
|
||||||
describe('E2E: Config priority (piece / autoPr)', () => {
|
describe('E2E: Config priority (piece / autoPr)', () => {
|
||||||
let isolatedEnv: IsolatedEnv;
|
let isolatedEnv: IsolatedEnv;
|
||||||
@ -67,7 +79,7 @@ describe('E2E: Config priority (piece / autoPr)', () => {
|
|||||||
const piecePath = resolve(__dirname, '../fixtures/pieces/mock-single-step.yaml');
|
const piecePath = resolve(__dirname, '../fixtures/pieces/mock-single-step.yaml');
|
||||||
const scenarioPath = resolve(__dirname, '../fixtures/scenarios/execute-done.json');
|
const scenarioPath = resolve(__dirname, '../fixtures/scenarios/execute-done.json');
|
||||||
|
|
||||||
const result = runTakt({
|
runTakt({
|
||||||
args: [
|
args: [
|
||||||
'--task', 'Auto PR default behavior',
|
'--task', 'Auto PR default behavior',
|
||||||
'--piece', piecePath,
|
'--piece', piecePath,
|
||||||
@ -82,10 +94,8 @@ describe('E2E: Config priority (piece / autoPr)', () => {
|
|||||||
timeout: 240_000,
|
timeout: 240_000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// auto_pr=true の場合は PR 作成フローに入り、テスト環境では gh 未認証のため失敗する
|
const task = readFirstTask(testRepo.path);
|
||||||
const output = result.stdout + result.stderr;
|
expect(task['auto_pr']).toBe(true);
|
||||||
expect(result.exitCode).toBe(1);
|
|
||||||
expect(output).toContain('PR creation failed:');
|
|
||||||
}, 240_000);
|
}, 240_000);
|
||||||
|
|
||||||
it('should use auto_pr from config when set', () => {
|
it('should use auto_pr from config when set', () => {
|
||||||
@ -108,9 +118,9 @@ describe('E2E: Config priority (piece / autoPr)', () => {
|
|||||||
timeout: 240_000,
|
timeout: 240_000,
|
||||||
});
|
});
|
||||||
|
|
||||||
const output = result.stdout + result.stderr;
|
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(output).not.toContain('PR creation failed:');
|
const task = readFirstTask(testRepo.path);
|
||||||
|
expect(task['auto_pr']).toBe(false);
|
||||||
}, 240_000);
|
}, 240_000);
|
||||||
|
|
||||||
it('should prioritize env auto_pr over config', () => {
|
it('should prioritize env auto_pr over config', () => {
|
||||||
@ -118,7 +128,7 @@ describe('E2E: Config priority (piece / autoPr)', () => {
|
|||||||
const scenarioPath = resolve(__dirname, '../fixtures/scenarios/execute-done.json');
|
const scenarioPath = resolve(__dirname, '../fixtures/scenarios/execute-done.json');
|
||||||
updateIsolatedConfig(isolatedEnv.taktDir, { auto_pr: false });
|
updateIsolatedConfig(isolatedEnv.taktDir, { auto_pr: false });
|
||||||
|
|
||||||
const result = runTakt({
|
runTakt({
|
||||||
args: [
|
args: [
|
||||||
'--task', 'Auto PR from env override',
|
'--task', 'Auto PR from env override',
|
||||||
'--piece', piecePath,
|
'--piece', piecePath,
|
||||||
@ -134,9 +144,7 @@ describe('E2E: Config priority (piece / autoPr)', () => {
|
|||||||
timeout: 240_000,
|
timeout: 240_000,
|
||||||
});
|
});
|
||||||
|
|
||||||
// env override により auto_pr=true が優先され、PR 作成フローに入る
|
const task = readFirstTask(testRepo.path);
|
||||||
const output = result.stdout + result.stderr;
|
expect(task['auto_pr']).toBe(true);
|
||||||
expect(result.exitCode).toBe(1);
|
|
||||||
expect(output).toContain('PR creation failed:');
|
|
||||||
}, 240_000);
|
}, 240_000);
|
||||||
});
|
});
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "takt",
|
"name": "takt",
|
||||||
"version": "0.24.0",
|
"version": "0.25.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "takt",
|
"name": "takt",
|
||||||
"version": "0.24.0",
|
"version": "0.25.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.47",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.47",
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "takt",
|
"name": "takt",
|
||||||
"version": "0.24.0",
|
"version": "0.25.0",
|
||||||
"description": "TAKT: TAKT Agent Koordination Topology - AI Agent Piece Orchestration",
|
"description": "TAKT: TAKT Agent Koordination Topology - AI Agent Piece Orchestration",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
|||||||
@ -115,6 +115,7 @@ vi.mock('../infra/config/global/globalConfig.js', async (importOriginal) => {
|
|||||||
...original,
|
...original,
|
||||||
loadGlobalConfig: vi.fn().mockReturnValue({
|
loadGlobalConfig: vi.fn().mockReturnValue({
|
||||||
language: 'en',
|
language: 'en',
|
||||||
|
provider: 'mock',
|
||||||
enableBuiltinPieces: true,
|
enableBuiltinPieces: true,
|
||||||
disabledBuiltins: [],
|
disabledBuiltins: [],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -96,6 +96,7 @@ vi.mock('../infra/config/global/globalConfig.js', async (importOriginal) => {
|
|||||||
...original,
|
...original,
|
||||||
loadGlobalConfig: vi.fn().mockReturnValue({
|
loadGlobalConfig: vi.fn().mockReturnValue({
|
||||||
language: 'en',
|
language: 'en',
|
||||||
|
provider: 'mock',
|
||||||
enableBuiltinPieces: true,
|
enableBuiltinPieces: true,
|
||||||
disabledBuiltins: [],
|
disabledBuiltins: [],
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -57,7 +57,7 @@ describe('OptionsBuilder.buildBaseOptions', () => {
|
|||||||
expect(options.permissionMode).toBe('full');
|
expect(options.permissionMode).toBe('full');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('uses default profile when provider_profiles are not provided', () => {
|
it('uses readonly when provider is not configured', () => {
|
||||||
const step = createMovement();
|
const step = createMovement();
|
||||||
const builder = createBuilder(step, {
|
const builder = createBuilder(step, {
|
||||||
provider: undefined,
|
provider: undefined,
|
||||||
@ -65,7 +65,7 @@ describe('OptionsBuilder.buildBaseOptions', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const options = builder.buildBaseOptions(step);
|
const options = builder.buildBaseOptions(step);
|
||||||
expect(options.permissionMode).toBe('edit');
|
expect(options.permissionMode).toBe('readonly');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('merges provider options with precedence: global < movement < project', () => {
|
it('merges provider options with precedence: global < movement < project', () => {
|
||||||
|
|||||||
@ -34,9 +34,12 @@ export class AgentRunner {
|
|||||||
{ provider: options?.stepProvider },
|
{ provider: options?.stepProvider },
|
||||||
{ provider: config.provider },
|
{ provider: config.provider },
|
||||||
{ provider: agentConfig?.provider },
|
{ provider: agentConfig?.provider },
|
||||||
]).provider ?? 'claude';
|
]).provider;
|
||||||
|
if (!resolvedProvider) {
|
||||||
|
throw new Error('No provider configured. Set "provider" in ~/.takt/config.yaml');
|
||||||
|
}
|
||||||
|
|
||||||
const configModel = (config.provider ?? 'claude') === resolvedProvider
|
const configModel = config.provider === resolvedProvider
|
||||||
? config.model
|
? config.model
|
||||||
: undefined;
|
: undefined;
|
||||||
const resolvedModel = resolveProviderModelCandidates([
|
const resolvedModel = resolveProviderModelCandidates([
|
||||||
|
|||||||
@ -64,7 +64,7 @@ export class OptionsBuilder {
|
|||||||
model: this.engineOptions.model,
|
model: this.engineOptions.model,
|
||||||
personaProviders: this.engineOptions.personaProviders,
|
personaProviders: this.engineOptions.personaProviders,
|
||||||
});
|
});
|
||||||
const resolvedProvider = resolved.provider ?? this.engineOptions.provider ?? 'claude';
|
const resolvedProvider = resolved.provider ?? this.engineOptions.provider;
|
||||||
const resolvedModel = resolved.model ?? this.engineOptions.model;
|
const resolvedModel = resolved.model ?? this.engineOptions.model;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -30,12 +30,7 @@ export const DEFAULT_PROVIDER_PERMISSION_PROFILES: ProviderPermissionProfiles =
|
|||||||
*/
|
*/
|
||||||
export function resolveMovementPermissionMode(input: ResolvePermissionModeInput): PermissionMode {
|
export function resolveMovementPermissionMode(input: ResolvePermissionModeInput): PermissionMode {
|
||||||
if (!input.provider) {
|
if (!input.provider) {
|
||||||
if (input.requiredPermissionMode) {
|
return input.requiredPermissionMode ?? 'readonly';
|
||||||
return input.requiredPermissionMode;
|
|
||||||
}
|
|
||||||
throw new Error(
|
|
||||||
`Unable to resolve permission mode for movement "${input.movementName}": provider is required when movement.required_permission_mode is omitted.`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectProfile = input.projectProviderProfiles?.[input.provider];
|
const projectProfile = input.projectProviderProfiles?.[input.provider];
|
||||||
|
|||||||
@ -340,6 +340,9 @@ export async function executePiece(
|
|||||||
const shouldNotifyPieceComplete = shouldNotify && notificationSoundEvents?.pieceComplete !== false;
|
const shouldNotifyPieceComplete = shouldNotify && notificationSoundEvents?.pieceComplete !== false;
|
||||||
const shouldNotifyPieceAbort = shouldNotify && notificationSoundEvents?.pieceAbort !== false;
|
const shouldNotifyPieceAbort = shouldNotify && notificationSoundEvents?.pieceAbort !== false;
|
||||||
const currentProvider = globalConfig.provider;
|
const currentProvider = globalConfig.provider;
|
||||||
|
if (!currentProvider) {
|
||||||
|
throw new Error('No provider configured. Set "provider" in ~/.takt/config.yaml');
|
||||||
|
}
|
||||||
const effectivePieceConfig: PieceConfig = {
|
const effectivePieceConfig: PieceConfig = {
|
||||||
...pieceConfig,
|
...pieceConfig,
|
||||||
runtime: resolveRuntimeConfig(globalConfig.runtime, pieceConfig.runtime),
|
runtime: resolveRuntimeConfig(globalConfig.runtime, pieceConfig.runtime),
|
||||||
@ -555,7 +558,7 @@ export async function executePiece(
|
|||||||
model: options.model,
|
model: options.model,
|
||||||
personaProviders: options.personaProviders,
|
personaProviders: options.personaProviders,
|
||||||
});
|
});
|
||||||
const movementProvider = resolved.provider ?? 'claude';
|
const movementProvider = resolved.provider ?? options.provider ?? currentProvider;
|
||||||
const resolvedModel = resolved.model;
|
const resolvedModel = resolved.model;
|
||||||
const movementModel = resolvedModel ?? '(default)';
|
const movementModel = resolvedModel ?? '(default)';
|
||||||
currentMovementProvider = movementProvider;
|
currentMovementProvider = movementProvider;
|
||||||
|
|||||||
@ -70,7 +70,10 @@ export async function syncBranchWithRoot(
|
|||||||
const prompt = loadTemplate('sync_conflict_resolver_message', lang, { originalInstruction });
|
const prompt = loadTemplate('sync_conflict_resolver_message', lang, { originalInstruction });
|
||||||
|
|
||||||
const config = resolveConfigValues(projectDir, ['provider', 'model']);
|
const config = resolveConfigValues(projectDir, ['provider', 'model']);
|
||||||
const providerType = (config.provider ?? 'claude') as ProviderType;
|
if (!config.provider) {
|
||||||
|
throw new Error('No provider configured. Set "provider" in ~/.takt/config.yaml');
|
||||||
|
}
|
||||||
|
const providerType = config.provider as ProviderType;
|
||||||
const provider = getProvider(providerType);
|
const provider = getProvider(providerType);
|
||||||
const agent = provider.setup({ name: 'conflict-resolver', systemPrompt });
|
const agent = provider.setup({ name: 'conflict-resolver', systemPrompt });
|
||||||
|
|
||||||
|
|||||||
@ -64,7 +64,6 @@ const RESOLUTION_REGISTRY: Partial<{ [K in ConfigParameterKey]: ResolutionRule<K
|
|||||||
piece: { layers: ['local', 'global'], defaultValue: 'default' },
|
piece: { layers: ['local', 'global'], defaultValue: 'default' },
|
||||||
provider: {
|
provider: {
|
||||||
layers: ['local', 'piece', 'global'],
|
layers: ['local', 'piece', 'global'],
|
||||||
defaultValue: 'claude',
|
|
||||||
pieceValue: (pieceContext) => pieceContext?.provider,
|
pieceValue: (pieceContext) => pieceContext?.provider,
|
||||||
},
|
},
|
||||||
model: {
|
model: {
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import type { PersistedGlobalConfig } from '../../core/models/persisted-global-config.js';
|
import type { PersistedGlobalConfig } from '../../core/models/persisted-global-config.js';
|
||||||
|
|
||||||
export interface LoadedConfig extends Omit<PersistedGlobalConfig, 'provider' | 'verbose'> {
|
export interface LoadedConfig extends Omit<PersistedGlobalConfig, 'verbose'> {
|
||||||
piece: string;
|
piece: string;
|
||||||
provider: NonNullable<PersistedGlobalConfig['provider']>;
|
|
||||||
verbose: boolean;
|
verbose: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -67,7 +67,10 @@ export class TaskSummarizer {
|
|||||||
log.info('Task name romanized', { original: taskName, slug });
|
log.info('Task name romanized', { original: taskName, slug });
|
||||||
return slug || 'task';
|
return slug || 'task';
|
||||||
}
|
}
|
||||||
const providerType = (globalConfig.provider as ProviderType) ?? 'claude';
|
if (!globalConfig.provider) {
|
||||||
|
throw new Error('No provider configured. Set "provider" in ~/.takt/config.yaml');
|
||||||
|
}
|
||||||
|
const providerType = globalConfig.provider as ProviderType;
|
||||||
const model = options.model ?? globalConfig.model;
|
const model = options.model ?? globalConfig.model;
|
||||||
|
|
||||||
const provider = getProvider(providerType);
|
const provider = getProvider(providerType);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user