mirror of
https://github.com/cline/cline.git
synced 2026-09-12 00:50:27 +08:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
642824c5cc |
@@ -27,6 +27,8 @@ export type DelegatedAgentConnectionConfig = Pick<
|
||||
| "providerConfig"
|
||||
| "knownModels"
|
||||
| "thinking"
|
||||
| "reasoningEffort"
|
||||
| "thinkingBudgetTokens"
|
||||
>;
|
||||
|
||||
export interface DelegatedAgentRuntimeConfig
|
||||
@@ -69,6 +71,7 @@ export interface BuildDelegatedAgentConfigOptions {
|
||||
) => Promise<ToolApprovalResult> | ToolApprovalResult;
|
||||
role?: string;
|
||||
cwd?: string;
|
||||
connectionConfig?: DelegatedAgentConnectionConfig;
|
||||
}
|
||||
|
||||
export function createDelegatedAgentConfigProvider(
|
||||
@@ -87,6 +90,8 @@ export function createDelegatedAgentConfigProvider(
|
||||
providerConfig: runtimeConfig.providerConfig,
|
||||
knownModels: runtimeConfig.knownModels,
|
||||
thinking: runtimeConfig.thinking,
|
||||
reasoningEffort: runtimeConfig.reasoningEffort,
|
||||
thinkingBudgetTokens: runtimeConfig.thinkingBudgetTokens,
|
||||
}),
|
||||
updateConnectionDefaults: (overrides) => {
|
||||
runtimeConfig = {
|
||||
@@ -107,7 +112,8 @@ export function buildDelegatedAgentConfig(
|
||||
: buildSubAgentSystemPrompt(options.prompt, runtimeConfig);
|
||||
|
||||
return {
|
||||
...options.configProvider.getConnectionConfig(),
|
||||
...(options.connectionConfig ??
|
||||
options.configProvider.getConnectionConfig()),
|
||||
systemPrompt,
|
||||
tools: options.tools,
|
||||
maxIterations: options.maxIterations ?? runtimeConfig.maxIterations,
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
import type { ProviderListItem, ProviderModel } from "@cline/shared";
|
||||
import { resolveProviderConfig } from "../../../services/llms/provider-defaults";
|
||||
import {
|
||||
getLocalProviderModels,
|
||||
listLocalProviders,
|
||||
refreshProviderModelsFromSource,
|
||||
} from "../../../services/providers/local-provider-service";
|
||||
import type { ProviderSettingsManager } from "../../../services/storage/provider-settings-manager";
|
||||
import type {
|
||||
DelegatedAgentConfigProvider,
|
||||
DelegatedAgentConnectionConfig,
|
||||
} from "./delegated-agent";
|
||||
import type {
|
||||
TeamConnectionConfigRequest,
|
||||
TeamModelCatalogResult,
|
||||
TeamModelConfigProvider,
|
||||
TeamModelListItem,
|
||||
TeamProviderListItem,
|
||||
} from "./team-tools";
|
||||
|
||||
function toTeamModel(model: ProviderModel): TeamModelListItem {
|
||||
return {
|
||||
id: model.id,
|
||||
name: model.name,
|
||||
supportsAttachments: model.supportsAttachments,
|
||||
supportsVision: model.supportsVision,
|
||||
supportsReasoning: model.supportsReasoning,
|
||||
};
|
||||
}
|
||||
|
||||
function toTeamProvider(provider: ProviderListItem): TeamProviderListItem {
|
||||
return {
|
||||
id: provider.id,
|
||||
name: provider.name,
|
||||
enabled: provider.enabled,
|
||||
defaultModelId: provider.defaultModelId,
|
||||
models: provider.models,
|
||||
modelList: provider.modelList?.map(toTeamModel),
|
||||
};
|
||||
}
|
||||
|
||||
export function createLocalTeamModelConfigProvider(options: {
|
||||
manager: ProviderSettingsManager;
|
||||
fallbackConfigProvider: DelegatedAgentConfigProvider;
|
||||
}): TeamModelConfigProvider {
|
||||
return {
|
||||
async listModels(input): Promise<TeamModelCatalogResult> {
|
||||
const providerId = input.providerId?.trim();
|
||||
if (input.refresh) {
|
||||
if (providerId) {
|
||||
await refreshProviderModelsFromSource(
|
||||
options.manager,
|
||||
providerId,
|
||||
).catch(() => undefined);
|
||||
} else {
|
||||
const catalog = await listLocalProviders(options.manager);
|
||||
await Promise.all(
|
||||
catalog.providers
|
||||
.filter((provider) => provider.enabled)
|
||||
.map((provider) =>
|
||||
refreshProviderModelsFromSource(
|
||||
options.manager,
|
||||
provider.id,
|
||||
).catch(() => undefined),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const includeDisabled = input.includeDisabledProviders ?? true;
|
||||
const catalog = await listLocalProviders(options.manager);
|
||||
let providers = catalog.providers;
|
||||
if (providerId) {
|
||||
providers = providers.filter((provider) => provider.id === providerId);
|
||||
}
|
||||
if (!includeDisabled) {
|
||||
providers = providers.filter((provider) => provider.enabled);
|
||||
}
|
||||
|
||||
return {
|
||||
providers: providers.map(toTeamProvider),
|
||||
settingsPath: catalog.settingsPath,
|
||||
};
|
||||
},
|
||||
|
||||
async resolveConnectionConfig(
|
||||
request: TeamConnectionConfigRequest,
|
||||
): Promise<DelegatedAgentConnectionConfig> {
|
||||
const fallback = options.fallbackConfigProvider.getConnectionConfig();
|
||||
const providerId = request.providerId?.trim() || fallback.providerId;
|
||||
const modelId = request.modelId?.trim() || fallback.modelId;
|
||||
|
||||
if (providerId === fallback.providerId) {
|
||||
return {
|
||||
...fallback,
|
||||
modelId,
|
||||
...(request.thinking !== undefined
|
||||
? { thinking: request.thinking }
|
||||
: {}),
|
||||
...(request.reasoningEffort
|
||||
? { reasoningEffort: request.reasoningEffort }
|
||||
: {}),
|
||||
};
|
||||
}
|
||||
|
||||
const persistedConfig = options.manager.getProviderConfig(providerId, {
|
||||
includeKnownModels: false,
|
||||
});
|
||||
const resolved = await resolveProviderConfig(
|
||||
providerId,
|
||||
{
|
||||
loadLatestOnInit: false,
|
||||
loadPrivateOnAuth: false,
|
||||
failOnError: false,
|
||||
},
|
||||
persistedConfig,
|
||||
);
|
||||
const settings = options.manager.getProviderSettings(providerId);
|
||||
const knownModels =
|
||||
resolved?.knownModels ??
|
||||
(await getLocalProviderModels(providerId, persistedConfig)
|
||||
.then(({ models }) =>
|
||||
Object.fromEntries(
|
||||
models.map((model) => [
|
||||
model.id,
|
||||
{
|
||||
id: model.id,
|
||||
name: model.name,
|
||||
},
|
||||
]),
|
||||
),
|
||||
)
|
||||
.catch(() => undefined));
|
||||
|
||||
return {
|
||||
providerId,
|
||||
modelId,
|
||||
apiKey: persistedConfig?.apiKey ?? settings?.apiKey,
|
||||
baseUrl: persistedConfig?.baseUrl ?? resolved?.baseUrl,
|
||||
headers: persistedConfig?.headers ?? settings?.headers,
|
||||
providerConfig: persistedConfig,
|
||||
knownModels,
|
||||
thinking:
|
||||
request.thinking ?? persistedConfig?.thinking ?? fallback.thinking,
|
||||
reasoningEffort:
|
||||
request.reasoningEffort ??
|
||||
persistedConfig?.reasoningEffort ??
|
||||
fallback.reasoningEffort,
|
||||
thinkingBudgetTokens:
|
||||
persistedConfig?.thinkingBudgetTokens ??
|
||||
fallback.thinkingBudgetTokens,
|
||||
};
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -152,7 +152,10 @@ describe("AgentTeamsRuntime teammate lifecycle events", () => {
|
||||
role: undefined,
|
||||
teammate: {
|
||||
rolePrompt: "Write concise Python-focused haiku",
|
||||
providerId: "anthropic",
|
||||
modelId: "claude-sonnet-4-5-20250929",
|
||||
thinking: undefined,
|
||||
reasoningEffort: undefined,
|
||||
maxIterations: 7,
|
||||
runtimeAgentId: "teammate-1",
|
||||
conversationId: "conv-1",
|
||||
|
||||
@@ -889,7 +889,10 @@ export class AgentTeamsRuntime {
|
||||
role: config.role,
|
||||
teammate: {
|
||||
rolePrompt: config.systemPrompt,
|
||||
providerId: config.providerId,
|
||||
modelId: config.modelId,
|
||||
thinking: config.thinking,
|
||||
reasoningEffort: config.reasoningEffort,
|
||||
maxIterations: config.maxIterations,
|
||||
runtimeAgentId: agent.getAgentId(),
|
||||
conversationId: agent.getConversationId(),
|
||||
|
||||
@@ -7,6 +7,7 @@ export {
|
||||
type DelegatedAgentKind,
|
||||
type DelegatedAgentRuntimeConfig,
|
||||
} from "./delegated-agent";
|
||||
export { createLocalTeamModelConfigProvider } from "./model-config-provider";
|
||||
|
||||
// =============================================================================
|
||||
// Spawn Agent Tool
|
||||
@@ -50,5 +51,10 @@ export {
|
||||
createAgentTeamsTools,
|
||||
reviveTeamStateDates,
|
||||
sanitizeTeamName,
|
||||
type TeamConnectionConfigRequest,
|
||||
type TeamModelCatalogResult,
|
||||
type TeamModelConfigProvider,
|
||||
type TeamModelListItem,
|
||||
type TeamProviderListItem,
|
||||
type TeamTeammateRuntimeConfig,
|
||||
} from "./team-tools";
|
||||
|
||||
@@ -136,9 +136,12 @@ describe("createAgentTeamsTools schema surface", () => {
|
||||
onLeadToolsUnlocked,
|
||||
});
|
||||
|
||||
expect(tools.map((tool) => tool.name)).toEqual(["team_spawn_teammate"]);
|
||||
expect(tools.map((tool) => tool.name)).toEqual([
|
||||
"team_spawn_teammate",
|
||||
"team_list_models",
|
||||
]);
|
||||
|
||||
const spawn = tools[0];
|
||||
const spawn = tools.find((tool) => tool.name === "team_spawn_teammate");
|
||||
await expect(
|
||||
spawn?.execute(
|
||||
{
|
||||
@@ -509,6 +512,112 @@ describe("createAgentTeamsTools runtime behavior", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("applies optional provider/model/reasoning overrides when spawning teammates", async () => {
|
||||
const spawnTeammate = vi.fn();
|
||||
const runtime = {
|
||||
getMemberRole: vi.fn(() => "lead"),
|
||||
isTeammateActive: vi.fn(() => false),
|
||||
spawnTeammate,
|
||||
} as unknown as AgentTeamsRuntime;
|
||||
const modelConfigProvider = {
|
||||
listModels: vi.fn(),
|
||||
resolveConnectionConfig: vi.fn(async () => ({
|
||||
providerId: "openai-native",
|
||||
modelId: "gpt-5.3-codex",
|
||||
apiKey: "openai-key",
|
||||
thinking: true,
|
||||
reasoningEffort: "high" as const,
|
||||
})),
|
||||
};
|
||||
|
||||
const tools = createAgentTeamsTools({
|
||||
runtime,
|
||||
requesterId: "lead",
|
||||
teammateConfigProvider: makeTeammateConfigProvider(),
|
||||
modelConfigProvider,
|
||||
createBaseTools: () => [],
|
||||
includeManagementTools: false,
|
||||
});
|
||||
const spawnTool = tools.find((tool) => tool.name === "team_spawn_teammate");
|
||||
|
||||
await spawnTool?.execute(
|
||||
{
|
||||
agentId: "coder",
|
||||
rolePrompt: "Implement focused edits.",
|
||||
providerId: "openai-native",
|
||||
modelId: "gpt-5.3-codex",
|
||||
thinking: true,
|
||||
reasoningEffort: "high",
|
||||
maxIterations: 9,
|
||||
},
|
||||
{ agentId: "lead", conversationId: "conv-1", iteration: 1 },
|
||||
);
|
||||
|
||||
expect(modelConfigProvider.resolveConnectionConfig).toHaveBeenCalledWith({
|
||||
providerId: "openai-native",
|
||||
modelId: "gpt-5.3-codex",
|
||||
thinking: true,
|
||||
reasoningEffort: "high",
|
||||
});
|
||||
expect(spawnTeammate).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
agentId: "coder",
|
||||
config: expect.objectContaining({
|
||||
providerId: "openai-native",
|
||||
modelId: "gpt-5.3-codex",
|
||||
apiKey: "openai-key",
|
||||
thinking: true,
|
||||
reasoningEffort: "high",
|
||||
maxIterations: 9,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("lists teammate models through the injected model config provider", async () => {
|
||||
const runtime = new AgentTeamsRuntime({ teamName: "test-team" });
|
||||
const modelConfigProvider = {
|
||||
listModels: vi.fn(async () => ({
|
||||
providers: [
|
||||
{
|
||||
id: "cline",
|
||||
name: "Cline",
|
||||
enabled: true,
|
||||
defaultModelId: "anthropic/claude-sonnet-4.6",
|
||||
models: 1,
|
||||
modelList: [
|
||||
{ id: "anthropic/claude-sonnet-4.6", supportsReasoning: true },
|
||||
],
|
||||
},
|
||||
],
|
||||
settingsPath: "/tmp/providers.json",
|
||||
})),
|
||||
resolveConnectionConfig: vi.fn(),
|
||||
};
|
||||
const tools = createAgentTeamsTools({
|
||||
runtime,
|
||||
requesterId: "lead",
|
||||
teammateConfigProvider: makeTeammateConfigProvider(),
|
||||
modelConfigProvider,
|
||||
});
|
||||
const listModels = tools.find((tool) => tool.name === "team_list_models");
|
||||
|
||||
await expect(
|
||||
listModels?.execute(
|
||||
{ providerId: "cline", refresh: true },
|
||||
{ agentId: "lead", conversationId: "conv-1", iteration: 1 },
|
||||
),
|
||||
).resolves.toMatchObject({
|
||||
providers: [
|
||||
{ id: "cline", modelList: [{ id: "anthropic/claude-sonnet-4.6" }] },
|
||||
],
|
||||
});
|
||||
expect(modelConfigProvider.listModels).toHaveBeenCalledWith({
|
||||
providerId: "cline",
|
||||
refresh: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("injects workspace metadata into cline teammate system prompt", async () => {
|
||||
const spawnTeammate = vi.fn();
|
||||
const runtime = {
|
||||
|
||||
@@ -26,6 +26,8 @@ import {
|
||||
type TeamFinalizeOutcomeInput,
|
||||
TeamFinalizeOutcomeInputSchema,
|
||||
TeamFinalizeOutcomeToolResultSchema,
|
||||
type TeamListModelsInput,
|
||||
TeamListModelsInputSchema,
|
||||
type TeamListOutcomesInput,
|
||||
TeamListOutcomesInputSchema,
|
||||
type TeamListRunsInput,
|
||||
@@ -74,6 +76,7 @@ import {
|
||||
import {
|
||||
buildDelegatedAgentConfig,
|
||||
type DelegatedAgentConfigProvider,
|
||||
type DelegatedAgentConnectionConfig,
|
||||
type DelegatedAgentRuntimeConfig,
|
||||
} from "./delegated-agent";
|
||||
import type { AgentTeamsRuntime } from "./multi-agent";
|
||||
@@ -163,10 +166,47 @@ function assertAwaitedRunSucceeded(run: TeamRunRecord): void {
|
||||
|
||||
export type TeamTeammateRuntimeConfig = DelegatedAgentRuntimeConfig;
|
||||
|
||||
export interface TeamModelListItem {
|
||||
id: string;
|
||||
name?: string;
|
||||
supportsAttachments?: boolean;
|
||||
supportsVision?: boolean;
|
||||
supportsReasoning?: boolean;
|
||||
}
|
||||
|
||||
export interface TeamProviderListItem {
|
||||
id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
defaultModelId?: string;
|
||||
models?: number | null;
|
||||
modelList?: TeamModelListItem[];
|
||||
}
|
||||
|
||||
export interface TeamModelCatalogResult {
|
||||
providers: TeamProviderListItem[];
|
||||
settingsPath?: string;
|
||||
}
|
||||
|
||||
export interface TeamConnectionConfigRequest {
|
||||
providerId?: string;
|
||||
modelId?: string;
|
||||
thinking?: boolean;
|
||||
reasoningEffort?: DelegatedAgentConnectionConfig["reasoningEffort"];
|
||||
}
|
||||
|
||||
export interface TeamModelConfigProvider {
|
||||
listModels(input: TeamListModelsInput): Promise<TeamModelCatalogResult>;
|
||||
resolveConnectionConfig(
|
||||
input: TeamConnectionConfigRequest,
|
||||
): Promise<DelegatedAgentConnectionConfig>;
|
||||
}
|
||||
|
||||
export interface CreateAgentTeamsToolsOptions {
|
||||
runtime: AgentTeamsRuntime;
|
||||
requesterId: string;
|
||||
teammateConfigProvider: DelegatedAgentConfigProvider;
|
||||
modelConfigProvider?: TeamModelConfigProvider;
|
||||
createBaseTools?: () => AgentTool[];
|
||||
allowSpawn?: boolean;
|
||||
includeSpawnTool?: boolean;
|
||||
@@ -177,6 +217,7 @@ export interface CreateAgentTeamsToolsOptions {
|
||||
export interface BootstrapAgentTeamsOptions {
|
||||
runtime: AgentTeamsRuntime;
|
||||
teammateConfigProvider: DelegatedAgentConfigProvider;
|
||||
modelConfigProvider?: TeamModelConfigProvider;
|
||||
createBaseTools?: () => AgentTool[];
|
||||
leadAgentId?: string;
|
||||
restoredTeammates?: TeamTeammateSpec[];
|
||||
@@ -194,6 +235,7 @@ export interface BootstrapAgentTeamsResult {
|
||||
|
||||
export const TEAM_TOOL_NAMES = [
|
||||
"team_spawn_teammate",
|
||||
"team_list_models",
|
||||
"team_shutdown_teammate",
|
||||
"team_status",
|
||||
"team_task",
|
||||
@@ -218,7 +260,7 @@ function spawnTeamTeammate(
|
||||
requesterId: string;
|
||||
spec: TeamTeammateSpec;
|
||||
},
|
||||
): void {
|
||||
): Promise<void> | void {
|
||||
const teammateTools: AgentTool[] = [];
|
||||
if (options.createBaseTools) {
|
||||
teammateTools.push(...options.createBaseTools());
|
||||
@@ -228,22 +270,47 @@ function spawnTeamTeammate(
|
||||
runtime: options.runtime,
|
||||
requesterId: options.spec.agentId,
|
||||
teammateConfigProvider: options.teammateConfigProvider,
|
||||
modelConfigProvider: options.modelConfigProvider,
|
||||
createBaseTools: options.createBaseTools,
|
||||
allowSpawn: false,
|
||||
}),
|
||||
);
|
||||
options.runtime.spawnTeammate({
|
||||
agentId: options.spec.agentId,
|
||||
config: buildDelegatedAgentConfig({
|
||||
kind: "teammate",
|
||||
prompt: options.spec.rolePrompt,
|
||||
role: options.spec.rolePrompt,
|
||||
configProvider: options.teammateConfigProvider,
|
||||
tools: teammateTools,
|
||||
maxIterations: options.spec.maxIterations,
|
||||
cwd: options.teammateConfigProvider.getRuntimeConfig().cwd,
|
||||
}),
|
||||
});
|
||||
const spawn = async () => {
|
||||
const connectionConfig = options.modelConfigProvider
|
||||
? await options.modelConfigProvider.resolveConnectionConfig({
|
||||
providerId: options.spec.providerId,
|
||||
modelId: options.spec.modelId,
|
||||
thinking: options.spec.thinking,
|
||||
reasoningEffort: options.spec.reasoningEffort,
|
||||
})
|
||||
: {
|
||||
...options.teammateConfigProvider.getConnectionConfig(),
|
||||
...(options.spec.providerId
|
||||
? { providerId: options.spec.providerId }
|
||||
: {}),
|
||||
...(options.spec.modelId ? { modelId: options.spec.modelId } : {}),
|
||||
...(options.spec.thinking !== undefined
|
||||
? { thinking: options.spec.thinking }
|
||||
: {}),
|
||||
...(options.spec.reasoningEffort
|
||||
? { reasoningEffort: options.spec.reasoningEffort }
|
||||
: {}),
|
||||
};
|
||||
options.runtime.spawnTeammate({
|
||||
agentId: options.spec.agentId,
|
||||
config: buildDelegatedAgentConfig({
|
||||
kind: "teammate",
|
||||
prompt: options.spec.rolePrompt,
|
||||
role: options.spec.rolePrompt,
|
||||
configProvider: options.teammateConfigProvider,
|
||||
connectionConfig,
|
||||
tools: teammateTools,
|
||||
maxIterations: options.spec.maxIterations,
|
||||
cwd: options.teammateConfigProvider.getRuntimeConfig().cwd,
|
||||
}),
|
||||
});
|
||||
};
|
||||
return spawn();
|
||||
}
|
||||
|
||||
export function bootstrapAgentTeams(
|
||||
@@ -256,6 +323,7 @@ export function bootstrapAgentTeams(
|
||||
runtime: options.runtime,
|
||||
requesterId: leadAgentId,
|
||||
teammateConfigProvider: options.teammateConfigProvider,
|
||||
modelConfigProvider: options.modelConfigProvider,
|
||||
createBaseTools: options.createBaseTools,
|
||||
allowSpawn: true,
|
||||
includeSpawnTool: options.includeLeadSpawnTool,
|
||||
@@ -268,10 +336,11 @@ export function bootstrapAgentTeams(
|
||||
if (options.runtime.isTeammateActive(spec.agentId)) {
|
||||
continue;
|
||||
}
|
||||
spawnTeamTeammate({
|
||||
void spawnTeamTeammate({
|
||||
runtime: options.runtime,
|
||||
requesterId: leadAgentId,
|
||||
teammateConfigProvider: options.teammateConfigProvider,
|
||||
modelConfigProvider: options.modelConfigProvider,
|
||||
createBaseTools: options.createBaseTools,
|
||||
spec,
|
||||
});
|
||||
@@ -313,11 +382,17 @@ export function createAgentTeamsTools(
|
||||
const spec: TeamTeammateSpec = {
|
||||
agentId: validatedInput.agentId,
|
||||
rolePrompt: validatedInput.rolePrompt,
|
||||
providerId: validatedInput.providerId,
|
||||
modelId: validatedInput.modelId,
|
||||
thinking: validatedInput.thinking,
|
||||
reasoningEffort: validatedInput.reasoningEffort,
|
||||
maxIterations: validatedInput.maxIterations,
|
||||
};
|
||||
spawnTeamTeammate({
|
||||
await spawnTeamTeammate({
|
||||
runtime: options.runtime,
|
||||
requesterId: options.requesterId,
|
||||
teammateConfigProvider: options.teammateConfigProvider,
|
||||
modelConfigProvider: options.modelConfigProvider,
|
||||
createBaseTools: options.createBaseTools,
|
||||
spec,
|
||||
});
|
||||
@@ -340,6 +415,52 @@ export function createAgentTeamsTools(
|
||||
);
|
||||
}
|
||||
|
||||
tools.push(
|
||||
createTool<TeamListModelsInput, TeamModelCatalogResult>({
|
||||
name: "team_list_models",
|
||||
description:
|
||||
"List providers and models available for spawning teammates. Use providerId to filter; refresh=true may query provider model sources.",
|
||||
inputSchema: zodToJsonSchema(TeamListModelsInputSchema),
|
||||
execute: async (input) => {
|
||||
const validatedInput = validateWithZod(
|
||||
TeamListModelsInputSchema,
|
||||
input,
|
||||
);
|
||||
if (options.modelConfigProvider) {
|
||||
return options.modelConfigProvider.listModels(validatedInput);
|
||||
}
|
||||
|
||||
const runtimeConfig = options.teammateConfigProvider.getRuntimeConfig();
|
||||
const connectionConfig =
|
||||
options.teammateConfigProvider.getConnectionConfig();
|
||||
const modelIds = Object.keys(connectionConfig.knownModels ?? {});
|
||||
const modelList = modelIds.length
|
||||
? modelIds.map((id) => ({
|
||||
id,
|
||||
name: connectionConfig.knownModels?.[id]?.name ?? id,
|
||||
}))
|
||||
: [
|
||||
{
|
||||
id: connectionConfig.modelId,
|
||||
name: connectionConfig.modelId,
|
||||
},
|
||||
];
|
||||
return {
|
||||
providers: [
|
||||
{
|
||||
id: connectionConfig.providerId,
|
||||
name: connectionConfig.providerId,
|
||||
enabled: true,
|
||||
defaultModelId: runtimeConfig.modelId,
|
||||
models: modelList.length,
|
||||
modelList,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
}) as AgentTool,
|
||||
);
|
||||
|
||||
if (!includeManagementTools) {
|
||||
return tools;
|
||||
}
|
||||
|
||||
@@ -295,6 +295,7 @@ export {
|
||||
createAgentTeamsTools,
|
||||
createDelegatedAgent,
|
||||
createDelegatedAgentConfigProvider,
|
||||
createLocalTeamModelConfigProvider,
|
||||
createSpawnAgentTool,
|
||||
type DelegatedAgentConfigProvider,
|
||||
type DelegatedAgentConnectionConfig,
|
||||
@@ -305,8 +306,13 @@ export {
|
||||
type SubAgentEndContext,
|
||||
type SubAgentStartContext,
|
||||
type TaskResult,
|
||||
type TeamConnectionConfigRequest,
|
||||
type TeamEvent,
|
||||
type TeamMemberConfig,
|
||||
type TeamModelCatalogResult,
|
||||
type TeamModelConfigProvider,
|
||||
type TeamModelListItem,
|
||||
type TeamProviderListItem,
|
||||
type TeamTeammateRuntimeConfig,
|
||||
toTeamProgressLifecycleEvent,
|
||||
} from "./extensions/tools/team";
|
||||
|
||||
@@ -30,12 +30,14 @@ import {
|
||||
AgentTeamsRuntime,
|
||||
bootstrapAgentTeams,
|
||||
createDelegatedAgentConfigProvider,
|
||||
createLocalTeamModelConfigProvider,
|
||||
type TeamEvent,
|
||||
} from "../../extensions/tools/team";
|
||||
import {
|
||||
filterDisabledTools,
|
||||
resolveDisabledToolNames,
|
||||
} from "../../services/global-settings";
|
||||
import { ProviderSettingsManager } from "../../services/storage/provider-settings-manager";
|
||||
import { createLocalTeamStore } from "../../services/storage/team-store";
|
||||
import type { CoreAgentMode, CoreSessionConfig } from "../../types/config";
|
||||
import type {
|
||||
@@ -423,6 +425,12 @@ export class DefaultRuntimeBuilder implements RuntimeBuilder {
|
||||
telemetry: input.telemetry ?? config.telemetry,
|
||||
workspaceMetadata: config.workspaceMetadata,
|
||||
});
|
||||
const teamModelConfigProvider = normalized.enableAgentTeams
|
||||
? createLocalTeamModelConfigProvider({
|
||||
manager: new ProviderSettingsManager(),
|
||||
fallbackConfigProvider: delegatedAgentConfigProvider,
|
||||
})
|
||||
: undefined;
|
||||
if (!this.teamRuntimeEntries.has(registryKey)) {
|
||||
this.teamRuntimeEntries.set(registryKey, {
|
||||
delegatedAgentConfigProvider,
|
||||
@@ -456,7 +464,10 @@ export class DefaultRuntimeBuilder implements RuntimeBuilder {
|
||||
const spec: TeamTeammateSpec = {
|
||||
agentId: event.agentId,
|
||||
rolePrompt: event.teammate.rolePrompt,
|
||||
providerId: event.teammate.providerId,
|
||||
modelId: event.teammate.modelId,
|
||||
thinking: event.teammate.thinking,
|
||||
reasoningEffort: event.teammate.reasoningEffort,
|
||||
maxIterations: event.teammate.maxIterations,
|
||||
};
|
||||
teammateSpecs.set(spec.agentId, spec);
|
||||
@@ -496,6 +507,7 @@ export class DefaultRuntimeBuilder implements RuntimeBuilder {
|
||||
restoredTeammates: restoredTeammateSpecs,
|
||||
includeLeadSpawnTool: true,
|
||||
includeLeadManagementTools: true,
|
||||
modelConfigProvider: teamModelConfigProvider,
|
||||
onLeadToolsUnlocked: (teamTools) => {
|
||||
pendingLeadTeamTools = teamTools;
|
||||
leadAgentInstance?.addTools(teamTools);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
import { z } from "zod";
|
||||
|
||||
const TeamReasoningEffortSchema = z.enum(["low", "medium", "high", "xhigh"]);
|
||||
|
||||
export const DEFAULT_OUTCOME_REQUIRED_SECTIONS = [
|
||||
"current_state",
|
||||
"boundary_analysis",
|
||||
@@ -48,7 +50,10 @@ const TeamMemberSnapshotSchema = z.object({
|
||||
export const TeamTeammateSpecSchema = z.object({
|
||||
agentId: z.string(),
|
||||
rolePrompt: z.string(),
|
||||
providerId: z.string().optional(),
|
||||
modelId: z.string().optional(),
|
||||
thinking: z.boolean().optional(),
|
||||
reasoningEffort: TeamReasoningEffortSchema.optional(),
|
||||
maxIterations: z.number().optional(),
|
||||
});
|
||||
|
||||
@@ -66,9 +71,36 @@ export const TeamSpawnTeammateInputSchema = z
|
||||
.string()
|
||||
.min(1)
|
||||
.describe("System prompt describing teammate role"),
|
||||
providerId: nullableOptional(z.string().min(1)).describe(
|
||||
"Optional provider ID for this teammate; defaults to the lead provider",
|
||||
),
|
||||
modelId: nullableOptional(z.string().min(1)).describe(
|
||||
"Optional model ID for this teammate; defaults to the lead model",
|
||||
),
|
||||
thinking: nullableOptional(z.boolean()).describe(
|
||||
"Optional reasoning/thinking toggle for capable models",
|
||||
),
|
||||
reasoningEffort: nullableOptional(TeamReasoningEffortSchema).describe(
|
||||
"Optional reasoning effort for capable models",
|
||||
),
|
||||
maxIterations: nullableOptional(z.number().positive()).describe(
|
||||
"Optional max loop iterations for this teammate",
|
||||
),
|
||||
})
|
||||
.strict();
|
||||
|
||||
export const TeamListModelsInputSchema = z.object({
|
||||
providerId: nullableOptional(z.string().min(1)).describe(
|
||||
"Optional provider ID to filter models; omit to list all known providers",
|
||||
),
|
||||
includeDisabledProviders: nullableOptional(z.boolean()).describe(
|
||||
"Include providers without saved settings; defaults to true",
|
||||
),
|
||||
refresh: nullableOptional(z.boolean()).describe(
|
||||
"Try refreshing model data from provider source before listing; defaults to false",
|
||||
),
|
||||
});
|
||||
|
||||
export const TeamShutdownTeammateInputSchema = z.object({
|
||||
agentId: z.string().min(1).describe("Teammate identifier"),
|
||||
reason: nullableOptional(z.string().min(1)).describe(
|
||||
@@ -237,6 +269,7 @@ export const TeamListOutcomesInputSchema = z.object({});
|
||||
export type TeamSpawnTeammateInput = z.infer<
|
||||
typeof TeamSpawnTeammateInputSchema
|
||||
>;
|
||||
export type TeamListModelsInput = z.infer<typeof TeamListModelsInputSchema>;
|
||||
export type TeamShutdownTeammateInput = z.infer<
|
||||
typeof TeamShutdownTeammateInputSchema
|
||||
>;
|
||||
|
||||
@@ -71,7 +71,10 @@ export interface TeamMemberSnapshot {
|
||||
|
||||
export interface TeammateLifecycleSpec {
|
||||
rolePrompt: string;
|
||||
providerId?: string;
|
||||
modelId?: string;
|
||||
thinking?: boolean;
|
||||
reasoningEffort?: "low" | "medium" | "high" | "xhigh";
|
||||
maxIterations?: number;
|
||||
runtimeAgentId?: string;
|
||||
conversationId?: string;
|
||||
|
||||
Reference in New Issue
Block a user