Download packages/agent-core-v2/src/agent/profile/profileService.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 35 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/agent/profile/profileService.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/agent-core-v2/src/agent/profile/profileService.ts
-
curl -L -o profileService.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/agent/profile/profileService.ts
35 kB
| import { Disposable } from '#/_base/di/lifecycle'; | |
| import { LifecycleScope } from '#/app/scopes'; | |
| import { ScopeActivation, registerScopedService } from '#/_base/di/scope'; | |
| import { defineState } from '#/state/state'; | |
| import { UNKNOWN_CAPABILITY, type ModelCapability } from '#/llm-adapter/contract/capability'; | |
| import { type ThinkingEffort } from '#human/llm/thinking'; | |
| import { IModelCatalog, type Model } from '#/llm-adapter/model/catalog'; | |
| import { type ModelOverrides } from '#/llm-adapter/model/model.types'; | |
| import { type ModelRequestParams, type SamplingOptions } from '#/llm-adapter/model/model-requester'; | |
| import { IProtocolAdapterRegistry } from '#/llm-adapter/protocol/protocol'; | |
| import { | |
| drivesThinkingThroughTraits, | |
| modelSupportsThinkingEffort, | |
| normalizeRequestedThinkingEffort, | |
| resolveForcedThinkingEffort, | |
| resolveThinkingEffortForModel, | |
| resolveThinkingKeep, | |
| requiresStrictThinkingValidation, | |
| type ThinkingConfig, | |
| } from '#/llm-adapter/model/thinking'; | |
| import { THINKING_SECTION } from '#/app/kosongConfig/configSection'; | |
| import { DEFAULT_AGENT_PROFILE_NAME } from '#/app/agentProfileCatalog/agentProfileCatalog'; | |
| import { IBuiltinAgentProfileLoader } from '#/app/agentProfileCatalog/builtinAgentProfileLoader'; | |
| import { ErrorCodes, Error2 } from "#/errors"; | |
| import { IAgentIdentity } from '#/app/agentIdentity/agentIdentity'; | |
| import { IBootstrapService } from '#/app/bootstrap/bootstrap'; | |
| import { IConfigService } from '#/app/config/config'; | |
| import type { LoopControl } from '#/agent/loop/configSection'; | |
| import { IAgentRuntimeService } from '#/agent/runtimeBinding/agentRuntime'; | |
| import { RuntimeWorkspaceView } from '#/runtime/runtimeWorkspaceView'; | |
| import { ISessionContext } from '#/session/sessionContext/sessionContext'; | |
| import type { ToolSource } from '#/tool/toolContract'; | |
| import { ISessionWorkspaceContext } from '#/session/workspaceContext/workspaceContext'; | |
| import { ISessionInstructionsProvider } from '#/session/sessionInstructions/instructionsProvider'; | |
| import { ISessionSkillCatalog } from '#/features/skill/session/skillCatalog'; | |
| import { ISessionAgentProfileCatalog } from '#/session/sessionAgentProfileCatalog/sessionAgentProfileCatalog'; | |
| import { ISessionToolPolicy } from '#/session/sessionToolPolicy/sessionToolPolicy'; | |
| import { ISessionToolPolicyGate } from '#/session/sessionToolPolicyGate/sessionToolPolicyGate'; | |
| import { IPluginService } from '#/app/plugin/plugin'; | |
| import type { ResolvedAgentProfile, SystemPromptContext } from '#/agent/profile/profile'; | |
| import { IAgentScopeContext } from '#/agent/scopeContext/scopeContext'; | |
| import { IAgentStateService } from '#/agent/state/agentState'; | |
| import { IAgentAgentsMdReminderService } from '#/agent/agentsMdReminder/agentsMdReminder'; | |
| import { ITelemetryService } from '#/app/telemetry/telemetry'; | |
| import { IEventDispatcher } from '#/state/eventDispatcher'; | |
| import { | |
| extractAgentsMdPathsFromSystemPrompt, | |
| prepareSystemPromptContext, | |
| type LoadedAgentsMd, | |
| } from './context'; | |
| import type { | |
| ApplyProfileOptions, | |
| BindAgentInput, | |
| ProfileBindingSnapshot, | |
| ProfileData, | |
| ProfileModelContext, | |
| ProfileServiceOptions, | |
| ProfileSetModelResult, | |
| ProfileUpdateData, | |
| } from './profile'; | |
| import { IAgentProfileService, ProfileError, ProfileErrors } from './profile'; | |
| import { TOOLS_SECTION, type ToolsConfig } from '#/agent/toolPolicy/configSection'; | |
| import { isToolActiveComposed, findInactiveToolPatterns, literalToolNames, type InactiveToolPattern } from '#/agent/toolPolicy/evaluate'; | |
| import { IAgentToolRegistryService } from '#/agent/toolRegistry/toolRegistry'; | |
| import { ISessionNotify } from '#/features/notify/sessionNotify'; | |
| import { NOTIFY_USER_TOOL_NAME } from '#/features/notify/tools/notify-user/notify-user'; | |
| import { renderAgentProfilePrompt } from '#/app/agentProfileCatalog/profile-shared'; | |
| import { getAgentToolContributions } from '#/agent/toolRegistry/toolContribution'; | |
| import { | |
| profileActiveToolsKey, | |
| ConfigUpdate, | |
| ProfileBind, | |
| profileKey, | |
| ToolsResetActiveTools, | |
| ToolsSetActiveTools, | |
| WarningIssued, | |
| type ActiveToolsState, | |
| type ConfigUpdatePayload, | |
| type ProfileModelState, | |
| } from './profileOps'; | |
| import { AgentStatusUpdated } from '#/agent/usage/usageEvents'; | |
| export type { WarningEvent } from '#/errors'; | |
| function describeInactiveToolPattern( | |
| context: string, | |
| field: string, | |
| issue: InactiveToolPattern, | |
| ): string { | |
| switch (issue.kind) { | |
| case 'unknown-tool': | |
| return `Tool pattern "${issue.pattern}" in ${context} ${field} does not match any registered or built-in tool; it will never activate anything.`; | |
| case 'wildcard-not-mcp': | |
| return `Tool pattern "${issue.pattern}" in ${context} ${field} uses wildcards, which only match MCP tools (names starting with "mcp__"); it will never activate anything.`; | |
| case 'incomplete-mcp-name': | |
| return `Tool pattern "${issue.pattern}" in ${context} ${field} matches no tool; use "${issue.pattern}__*" to match the whole MCP server.`; | |
| } | |
| } | |
| export const PLUGIN_SECTIONS_MAX_BYTES = 64 * 1024; | |
| export const profileActiveToolNamesOverlayKey = defineState<readonly string[] | undefined>( | |
| 'profile.activeToolNamesOverlay', | |
| () => undefined as readonly string[] | undefined, | |
| ); | |
| export const profileAgentsMdWarningKey = defineState<string | undefined>( | |
| 'profile.agentsMdWarning', | |
| () => undefined as string | undefined, | |
| ); | |
| export const profileEmittedThinkingEffortWarningsKey = defineState<Set<string>>( | |
| 'profile.emittedThinkingEffortWarnings', | |
| () => new Set(), | |
| ); | |
| export const profileEmittedToolPatternWarningsKey = defineState<Set<string>>( | |
| 'profile.emittedToolPatternWarnings', | |
| () => new Set(), | |
| ); | |
| export const profileEmittedPluginBudgetWarningsKey = defineState<Set<string>>( | |
| 'profile.emittedPluginBudgetWarnings', | |
| () => new Set(), | |
| ); | |
| export class AgentProfileService extends Disposable implements IAgentProfileService { | |
| declare readonly _serviceBrand: undefined; | |
| private optionsValue: ProfileServiceOptions = {}; | |
| private get activeToolNames(): ActiveToolsState { | |
| return ( | |
| this.activeToolNamesOverlay ?? | |
| (this.states.get(profileActiveToolsKey) as ActiveToolsState) | |
| ); | |
| } | |
| private activeProfile: ResolvedAgentProfile | undefined; | |
| private frozenSkillListing: string | undefined; | |
| private frozenPluginSections: string | undefined; | |
| constructor( | |
| private readonly dispatcher: IEventDispatcher, | |
| private readonly telemetry: ITelemetryService, | |
| private readonly config: IConfigService, | |
| private readonly modelCatalog: IModelCatalog, | |
| private readonly protocolAdapters: IProtocolAdapterRegistry, | |
| private readonly runtime: IAgentRuntimeService, | |
| private readonly sessionContext: ISessionContext, | |
| private readonly bootstrap: IBootstrapService, | |
| private readonly notify: ISessionNotify, | |
| private readonly workspace: ISessionWorkspaceContext, | |
| private readonly catalog: ISessionAgentProfileCatalog, | |
| private readonly skillCatalog: ISessionSkillCatalog, | |
| private readonly instructions: ISessionInstructionsProvider, | |
| private readonly sessionToolPolicy: ISessionToolPolicy, | |
| private readonly toolPolicyGate: ISessionToolPolicyGate, | |
| private readonly toolRegistry: IAgentToolRegistryService, | |
| private readonly builtinProfiles: IBuiltinAgentProfileLoader, | |
| private readonly scopeContext: IAgentScopeContext, | |
| private readonly states: IAgentStateService, | |
| private readonly plugins: IPluginService, | |
| private readonly identity: IAgentIdentity, | |
| private readonly agentsMdReminder: IAgentAgentsMdReminderService, | |
| ) { | |
| super(); | |
| this.states.contributeState(profileKey); | |
| this.states.contributeState(profileActiveToolsKey); | |
| this.states.contributeState(profileActiveToolNamesOverlayKey); | |
| this.states.contributeState(profileAgentsMdWarningKey); | |
| this.states.contributeState(profileEmittedThinkingEffortWarningsKey); | |
| this.states.contributeState(profileEmittedToolPatternWarningsKey); | |
| this.states.contributeState(profileEmittedPluginBudgetWarningsKey); | |
| this.configure({}); | |
| this._register( | |
| this.dispatcher.hooks.onDidRestore.register('profile', async (_ctx, next) => { | |
| this.syncTelemetryModelContext(this.modelAlias); | |
| await next(); | |
| }), | |
| ); | |
| this._register( | |
| this.config.onDidSectionChange(({ domain }) => { | |
| if (domain === TOOLS_SECTION) { | |
| this.publishToolPatternWarnings(); | |
| } | |
| }), | |
| ); | |
| } | |
| private get activeToolNamesOverlay(): readonly string[] | undefined { | |
| return this.states.get(profileActiveToolNamesOverlayKey); | |
| } | |
| private set activeToolNamesOverlay(value: readonly string[] | undefined) { | |
| this.states.set(profileActiveToolNamesOverlayKey, value); | |
| } | |
| private get agentsMdWarning(): string | undefined { | |
| return this.states.get(profileAgentsMdWarningKey); | |
| } | |
| private set agentsMdWarning(value: string | undefined) { | |
| this.states.set(profileAgentsMdWarningKey, value); | |
| } | |
| private get emittedThinkingEffortWarnings(): Set<string> { | |
| return this.states.get(profileEmittedThinkingEffortWarningsKey); | |
| } | |
| private get emittedToolPatternWarnings(): Set<string> { | |
| return this.states.get(profileEmittedToolPatternWarningsKey); | |
| } | |
| private get emittedPluginBudgetWarnings(): Set<string> { | |
| return this.states.get(profileEmittedPluginBudgetWarningsKey); | |
| } | |
| configure(options: ProfileServiceOptions): void { | |
| this.optionsValue = { | |
| emitStatusUpdated: options.emitStatusUpdated ?? this.optionsValue.emitStatusUpdated, | |
| }; | |
| } | |
| update(changed: ProfileUpdateData): void { | |
| const { activeToolNames, ...configChanged } = changed; | |
| if ( | |
| changed.profileName !== undefined && | |
| this.activeProfile?.name !== changed.profileName | |
| ) { | |
| this.activeProfile = undefined; | |
| } | |
| if (Object.keys(configChanged).length > 0) { | |
| void this.dispatcher.dispatch(new ConfigUpdate(this.resolveConfigPayload(configChanged))); | |
| this.afterConfigDispatch(configChanged); | |
| } | |
| if (activeToolNames !== undefined) { | |
| this.setActiveTools(activeToolNames); | |
| } | |
| } | |
| applyBindingSnapshot(snapshot: ProfileBindingSnapshot): void { | |
| this.activeProfile = undefined; | |
| this.activeToolNamesOverlay = undefined; | |
| const agentsMdPaths = | |
| snapshot.agentsMdPaths ?? extractAgentsMdPathsFromSystemPrompt(snapshot.systemPrompt); | |
| void this.dispatcher.dispatch( | |
| new ProfileBind({ | |
| agentId: this.scopeContext.agentId, | |
| modelAlias: snapshot.modelAlias, | |
| profileName: snapshot.profileName, | |
| thinkingEffort: snapshot.thinkingLevel, | |
| systemPrompt: snapshot.systemPrompt, | |
| environmentDisclosure: snapshot.environmentDisclosure, | |
| renderGeneration: snapshot.renderGeneration, | |
| agentsMdPaths, | |
| activeToolNames: snapshot.activeToolNames, | |
| disallowedTools: snapshot.disallowedTools ?? [], | |
| subagents: snapshot.subagents, | |
| }), | |
| ); | |
| this.afterConfigDispatch({ | |
| modelAlias: snapshot.modelAlias, | |
| profileName: snapshot.profileName, | |
| thinkingLevel: snapshot.thinkingLevel, | |
| systemPrompt: snapshot.systemPrompt, | |
| environmentDisclosure: snapshot.environmentDisclosure, | |
| agentsMdPaths, | |
| disallowedTools: snapshot.disallowedTools ?? [], | |
| }); | |
| this.agentsMdReminder.seedInjected(agentsMdPaths, this.sessionContext.cwd); | |
| } | |
| async bind(input: BindAgentInput): Promise<void> { | |
| await this.catalog.ready; | |
| await this.identity.resolved(); | |
| this.assertBindable(input.profile); | |
| const profile = this.catalog.get(input.profile); | |
| if (profile === undefined) { | |
| const available = this.catalog | |
| .list() | |
| .map((p) => p.name) | |
| .join(', '); | |
| throw new ProfileError( | |
| ProfileErrors.codes.PROFILE_UNKNOWN, | |
| `Unknown agent profile: "${input.profile}". Available profiles: ${available}`, | |
| { profile: input.profile, available }, | |
| ); | |
| } | |
| const alias = input.model ?? this.config.get<string>('defaultModel'); | |
| if (alias === undefined || alias === '') { | |
| throw new ProfileError( | |
| ProfileErrors.codes.MODEL_NOT_CONFIGURED, | |
| `model is required to bind profile "${input.profile}" (no default model configured)`, | |
| ); | |
| } | |
| const model = this.modelCatalog.get(alias); | |
| if (input.strictThinking === true && input.thinking !== undefined) { | |
| this.assertThinkingEffortSupported(input.thinking, model, alias); | |
| } | |
| await this.sessionToolPolicy.ready; | |
| const context = await this.buildSystemPromptContext(profile); | |
| this.assertBindable(profile.name); | |
| const currentProfileName = this.profileName; | |
| const rendered = renderAgentProfilePrompt(profile, context); | |
| this.activeProfile = profile; | |
| this.cacheAgentsMdWarning(context); | |
| const thinkingLevel = this.resolveThinkingEffort( | |
| input.thinking ?? (currentProfileName !== undefined ? this.thinkingLevel : undefined), | |
| model, | |
| ); | |
| this.activeToolNamesOverlay = undefined; | |
| await this.dispatcher.dispatch(new ProfileBind({ | |
| agentId: this.scopeContext.agentId, | |
| modelAlias: alias, | |
| profileName: profile.name, | |
| thinkingEffort: thinkingLevel, | |
| systemPrompt: rendered.text, | |
| environmentDisclosure: rendered.environment, | |
| agentsMdPaths: context.agentsMdPaths ?? [], | |
| activeToolNames: profile.tools, | |
| disallowedTools: profile.disallowedTools ?? [], | |
| subagents: profile.subagents, | |
| })); | |
| this.afterConfigDispatch({ | |
| modelAlias: alias, | |
| profileName: profile.name, | |
| thinkingLevel, | |
| systemPrompt: rendered.text, | |
| disallowedTools: profile.disallowedTools ?? [], | |
| }); | |
| this.seedAgentsMdReminder(context); | |
| this.publishAgentsMdWarning(); | |
| this.publishToolPatternWarnings(profile); | |
| } | |
| async setModel(alias: string): Promise<ProfileSetModelResult> { | |
| const model = this.modelCatalog.get(alias); | |
| if (this.profileName === undefined) { | |
| await this.bind({ profile: DEFAULT_AGENT_PROFILE_NAME, model: alias }); | |
| this.telemetry.track2('model_switch', { model: alias }); | |
| } else if (this.modelAlias !== alias) { | |
| this.update({ modelAlias: alias }); | |
| this.telemetry.track2('model_switch', { model: alias }); | |
| } | |
| return { | |
| model: alias, | |
| providerName: model.providerName, | |
| }; | |
| } | |
| setThinking(level: string): void { | |
| const previousEffort = this.thinkingLevel; | |
| this.assertThinkingEffortSupported(level, this.tryResolveRawModel(), this.modelAlias ?? ''); | |
| const normalized = normalizeRequestedThinkingEffort(level); | |
| this.update({ thinkingLevel: normalized ?? level }); | |
| const effort = this.thinkingLevel; | |
| if (effort !== previousEffort) { | |
| this.telemetry.track2('thinking_toggle', { | |
| enabled: effort !== 'off', | |
| effort, | |
| from: previousEffort, | |
| }); | |
| } | |
| } | |
| private assertThinkingEffortSupported( | |
| requested: string, | |
| model: Model | undefined, | |
| modelAlias: string, | |
| ): void { | |
| const normalized = normalizeRequestedThinkingEffort(requested); | |
| if (normalized === undefined || this.supportsThinkingEffort(normalized, model)) return; | |
| const efforts = model?.supportEfforts ?? []; | |
| const supported = efforts.length === 0 ? 'off' : ['off', ...efforts].join(', '); | |
| throw new ProfileError( | |
| ProfileErrors.codes.MODEL_CONFIG_INVALID, | |
| `Thinking effort "${requested}" is not supported by model "${modelAlias}". Supported efforts: ${supported}.`, | |
| ); | |
| } | |
| getModel(): string { | |
| return this.modelAlias ?? ''; | |
| } | |
| useProfile(profile: ResolvedAgentProfile, context: SystemPromptContext): void { | |
| this.activeProfile = profile; | |
| const rendered = renderAgentProfilePrompt(profile, context); | |
| this.update({ | |
| profileName: profile.name, | |
| systemPrompt: rendered.text, | |
| environmentDisclosure: rendered.environment, | |
| agentsMdPaths: context.agentsMdPaths ?? [], | |
| disallowedTools: profile.disallowedTools ?? [], | |
| }); | |
| this.setActiveTools(profile.tools); | |
| } | |
| async applyProfile(profile: ResolvedAgentProfile, options?: ApplyProfileOptions): Promise<void> { | |
| const context = await this.buildSystemPromptContext(profile, options); | |
| this.useProfile(profile, context); | |
| this.seedAgentsMdReminder(context); | |
| this.cacheAgentsMdWarning(context); | |
| this.publishAgentsMdWarning(); | |
| this.publishToolPatternWarnings(profile); | |
| } | |
| private seedAgentsMdReminder(context: SystemPromptContext): void { | |
| this.agentsMdReminder.seedInjected( | |
| context.agentsMdPaths ?? [], | |
| context.cwd ?? this.sessionContext.cwd, | |
| ); | |
| } | |
| getAgentsMdWarning(): string | undefined { | |
| return this.agentsMdWarning; | |
| } | |
| data(): ProfileData { | |
| const model = this.tryResolveRawModel(); | |
| return { | |
| modelAlias: this.modelAlias, | |
| modelCapabilities: model?.capabilities ?? UNKNOWN_CAPABILITY, | |
| profileName: this.profileName, | |
| thinkingLevel: this.thinkingLevel, | |
| systemPrompt: this.systemPrompt, | |
| agentsMdPaths: this.profileState.agentsMdPaths, | |
| activeToolNames: this.activeToolNames === undefined ? undefined : [...this.activeToolNames], | |
| disallowedTools: [...(this.profileState.disallowedTools ?? [])], | |
| subagents: | |
| this.profileState.subagents === undefined ? undefined : [...this.profileState.subagents], | |
| environmentDisclosure: this.profileState.environmentDisclosure, | |
| renderGeneration: this.profileState.renderGeneration, | |
| }; | |
| } | |
| getEffectiveThinkingLevel(): ThinkingEffort { | |
| return this.resolveThinkingState(this.tryResolveRawModel()).effective; | |
| } | |
| resolveModelContext(): ProfileModelContext { | |
| const modelAlias = this.model; | |
| const model = this.modelCatalog.get(modelAlias); | |
| const loopControl = this.config.get<LoopControl>('loopControl'); | |
| return { | |
| modelAlias, | |
| modelCapabilities: model.capabilities, | |
| maxOutputSize: model.maxOutputSize, | |
| alwaysThinking: model.alwaysThinking || undefined, | |
| thinkingLevel: this.resolveThinkingState(model).effective, | |
| reservedContextSize: loopControl?.reservedContextSize, | |
| compactionTriggerRatio: loopControl?.compactionTriggerRatio, | |
| compactionMaxAttempts: loopControl?.compactionMaxAttempts, | |
| }; | |
| } | |
| resolveRequestParams(): ModelRequestParams { | |
| const model = this.tryResolveRawModel(); | |
| const thinking = this.resolveThinkingState(model); | |
| const thinkingConfig = this.config.get<ThinkingConfig>(THINKING_SECTION); | |
| const overrides = this.config.get<ModelOverrides>('modelOverrides'); | |
| const sampling: SamplingOptions = { | |
| temperature: overrides?.temperature, | |
| topP: overrides?.topP, | |
| }; | |
| return { | |
| cacheKey: this.sessionContext.sessionId, | |
| sampling: | |
| sampling.temperature === undefined && sampling.topP === undefined ? undefined : sampling, | |
| thinkingEffort: thinking.effective, | |
| thinkingKeep: resolveThinkingKeep( | |
| overrides?.thinkingKeep, | |
| thinkingConfig?.keep, | |
| thinking.effective, | |
| ), | |
| }; | |
| } | |
| getModelCapabilities(): ModelCapability { | |
| return this.tryResolveRawModel()?.capabilities ?? UNKNOWN_CAPABILITY; | |
| } | |
| getModelProviderType(alias?: string): string | undefined { | |
| const effective = alias ?? this.modelAlias ?? this.config.get<string>('defaultModel'); | |
| return this.resolveModelForThinking(effective)?.providerType; | |
| } | |
| getMaxOutputSize(): number | undefined { | |
| return this.tryResolveRawModel()?.maxOutputSize; | |
| } | |
| hasModel(): boolean { | |
| return this.modelAlias !== undefined; | |
| } | |
| isRunnable(): boolean { | |
| return this.profileName !== undefined && this.hasModel(); | |
| } | |
| hasProvider(): boolean { | |
| return this.tryResolveRawModel() !== undefined; | |
| } | |
| getSystemPrompt(): string { | |
| return this.systemPrompt; | |
| } | |
| getActiveToolNames(): readonly string[] | undefined { | |
| return this.activeToolNames; | |
| } | |
| addActiveTool(name: string): void { | |
| const activeToolNames = this.activeToolNames; | |
| if (activeToolNames === undefined || activeToolNames.includes(name)) return; | |
| this.activeToolNamesOverlay = [...activeToolNames, name]; | |
| } | |
| removeActiveTool(name: string): void { | |
| const activeToolNames = this.activeToolNames; | |
| if (activeToolNames === undefined || !activeToolNames.includes(name)) return; | |
| this.activeToolNamesOverlay = activeToolNames.filter((candidate) => candidate !== name); | |
| } | |
| private resolveConfigPayload( | |
| changed: Omit<ProfileUpdateData, 'activeToolNames'>, | |
| ): ConfigUpdatePayload { | |
| const payload: ConfigUpdatePayload = { agentId: this.scopeContext.agentId }; | |
| if (changed.modelAlias !== undefined) payload.modelAlias = changed.modelAlias; | |
| if (changed.profileName !== undefined) payload.profileName = changed.profileName; | |
| if (changed.thinkingLevel !== undefined || changed.modelAlias !== undefined) { | |
| const model = this.resolveModelForThinking(changed.modelAlias ?? this.modelAlias); | |
| const requested = | |
| changed.thinkingLevel ?? (this.modelAlias === undefined ? undefined : this.thinkingLevel); | |
| payload.thinkingEffort = this.resolveThinkingEffort(requested, model); | |
| } | |
| if (changed.systemPrompt !== undefined) { | |
| payload.systemPrompt = changed.systemPrompt; | |
| if (changed.environmentDisclosure !== undefined) { | |
| payload.environmentDisclosure = changed.environmentDisclosure; | |
| } | |
| } | |
| if (changed.agentsMdPaths !== undefined) { | |
| payload.agentsMdPaths = [...changed.agentsMdPaths]; | |
| } | |
| if (changed.disallowedTools !== undefined) { | |
| payload.disallowedTools = [...changed.disallowedTools]; | |
| } | |
| return payload; | |
| } | |
| private afterConfigDispatch(changed: Omit<ProfileUpdateData, 'activeToolNames'>): void { | |
| if (changed.modelAlias !== undefined) { | |
| this.syncTelemetryModelContext(changed.modelAlias); | |
| } | |
| if (changed.modelAlias !== undefined || changed.thinkingLevel !== undefined) { | |
| this.warnAboutAnthropicThinkingEffort(); | |
| } | |
| this.emitStatusUpdated( | |
| changed.modelAlias !== undefined || changed.thinkingLevel !== undefined, | |
| ); | |
| } | |
| private syncTelemetryModelContext(modelAlias: string | undefined): void { | |
| if (modelAlias === undefined) { | |
| return; | |
| } | |
| const model = this.tryResolveRawModel(); | |
| this.telemetry.setContext({ | |
| model: modelAlias, | |
| provider_type: model?.providerType ?? model?.protocol, | |
| protocol: model?.protocol, | |
| }); | |
| } | |
| private warnAboutAnthropicThinkingEffort(): void { | |
| try { | |
| const model = this.tryResolveRawModel(); | |
| if (model?.protocol !== 'anthropic') return; | |
| const effort = this.getEffectiveThinkingLevel(); | |
| if (effort === 'on' || effort === 'off') return; | |
| let code: string; | |
| let message: string; | |
| let knownEfforts = ''; | |
| const efforts = model.supportEfforts?.filter((value) => value.length > 0); | |
| if (efforts === undefined || efforts.length === 0 || efforts.includes(effort)) return; | |
| knownEfforts = efforts.join(','); | |
| code = 'anthropic-thinking-effort-not-listed'; | |
| message = `Thinking effort "${effort}" is not listed for model "${model.name}" (known: ${efforts.join(', ')}). The configured value will be sent unchanged to the Anthropic-compatible backend.`; | |
| const key = [code, model.id, model.name, effort, knownEfforts].join('\u0000'); | |
| if (this.emittedThinkingEffortWarnings.has(key)) return; | |
| this.emittedThinkingEffortWarnings.add(key); | |
| void this.dispatcher.dispatch(new WarningIssued({ agentId: this.scopeContext.agentId, code, message })); | |
| } catch { | |
| } | |
| } | |
| private setActiveTools(names: readonly string[] | undefined): void { | |
| this.activeToolNamesOverlay = undefined; | |
| if (names === undefined) { | |
| void this.dispatcher.dispatch(new ToolsResetActiveTools({ agentId: this.scopeContext.agentId })); | |
| return; | |
| } | |
| void this.dispatcher.dispatch( | |
| new ToolsSetActiveTools({ agentId: this.scopeContext.agentId, names: [...names] }), | |
| ); | |
| } | |
| private emitStatusUpdated(includeThinkingEffort = false): void { | |
| const custom = this.optionsValue.emitStatusUpdated; | |
| if (custom !== undefined) { | |
| custom(); | |
| return; | |
| } | |
| const modelAlias = this.modelAlias; | |
| if (modelAlias === undefined) return; | |
| const capabilities = this.tryResolveRawModel()?.capabilities; | |
| const maxContextTokens = capabilities?.max_input_tokens ?? capabilities?.max_context_tokens; | |
| void this.dispatcher.dispatch( | |
| new AgentStatusUpdated({ | |
| agentId: this.scopeContext.agentId, | |
| model: modelAlias, | |
| thinkingEffort: includeThinkingEffort | |
| ? this.getEffectiveThinkingLevel() | |
| : undefined, | |
| maxContextTokens: | |
| maxContextTokens !== undefined && maxContextTokens > 0 ? maxContextTokens : undefined, | |
| }), | |
| ); | |
| } | |
| republishStatus(): void { | |
| this.emitStatusUpdated(true); | |
| } | |
| private get profileState(): ProfileModelState { | |
| return this.states.get(profileKey); | |
| } | |
| private get model(): string { | |
| const modelAlias = this.modelAlias; | |
| if (modelAlias === undefined) { | |
| throw new Error2(ErrorCodes.MODEL_NOT_CONFIGURED, 'Model not set'); | |
| } | |
| return modelAlias; | |
| } | |
| private get modelAlias(): string | undefined { | |
| return this.profileState.modelAlias; | |
| } | |
| private get profileName(): string | undefined { | |
| return this.profileState.profileName; | |
| } | |
| private get systemPrompt(): string { | |
| return this.profileState.systemPrompt; | |
| } | |
| private get thinkingLevel(): ThinkingEffort { | |
| const stored = this.profileState.thinkingLevel; | |
| if (stored === 'off' && this.alwaysThinkingModel) { | |
| return this.resolveThinkingEffort(stored, this.tryResolveRawModel()); | |
| } | |
| return stored; | |
| } | |
| private resolveThinkingState(model: Model | undefined): { | |
| readonly effective: ThinkingEffort; | |
| readonly forced: ThinkingEffort | undefined; | |
| } { | |
| const base = this.thinkingLevel; | |
| const forced = resolveForcedThinkingEffort( | |
| this.config.get<ThinkingConfig>(THINKING_SECTION)?.forcedEffort, | |
| base, | |
| drivesThinkingThroughTraits(model?.providerType), | |
| ); | |
| return { effective: forced ?? base, forced }; | |
| } | |
| private strictThinkingValidation(model: Model | undefined): boolean { | |
| if (model === undefined) return false; | |
| return requiresStrictThinkingValidation( | |
| this.protocolAdapters, | |
| model.protocol, | |
| model.providerType, | |
| ); | |
| } | |
| private resolveThinkingEffort( | |
| requested: string | undefined, | |
| model: Model | undefined, | |
| ): ThinkingEffort { | |
| return resolveThinkingEffortForModel( | |
| requested, | |
| this.config.get<ThinkingConfig>(THINKING_SECTION), | |
| model, | |
| this.strictThinkingValidation(model), | |
| ); | |
| } | |
| private supportsThinkingEffort(effort: ThinkingEffort, model: Model | undefined): boolean { | |
| return modelSupportsThinkingEffort(effort, model, this.strictThinkingValidation(model)); | |
| } | |
| private get alwaysThinkingModel(): boolean { | |
| return this.tryResolveRawModel()?.alwaysThinking === true; | |
| } | |
| private tryResolveRawModel(): Model | undefined { | |
| const alias = this.modelAlias; | |
| return this.resolveModelForThinking(alias); | |
| } | |
| private resolveModelForThinking(alias: string | undefined): Model | undefined { | |
| if (alias === undefined) return undefined; | |
| try { | |
| return this.modelCatalog.get(alias); | |
| } catch { | |
| return undefined; | |
| } | |
| } | |
| private assertBindable(requested: string): void { | |
| const current = this.profileName; | |
| if (current !== undefined && current !== requested) { | |
| throw new ProfileError( | |
| ProfileErrors.codes.PROFILE_ALREADY_BOUND, | |
| `agent is already bound to profile "${current}"; cannot switch to "${requested}" in this session`, | |
| { current, requested }, | |
| ); | |
| } | |
| } | |
| private cacheAgentsMdWarning(context: Pick<SystemPromptContext, 'agentsMdWarning'>): void { | |
| this.agentsMdWarning = context.agentsMdWarning; | |
| } | |
| private publishAgentsMdWarning(): void { | |
| const warning = this.agentsMdWarning; | |
| if (warning === undefined) return; | |
| void this.dispatcher.dispatch( | |
| new WarningIssued({ | |
| agentId: this.scopeContext.agentId, | |
| message: warning, | |
| code: 'agents-md-oversized', | |
| }), | |
| ); | |
| } | |
| private publishToolPatternWarnings(profile?: ResolvedAgentProfile): void { | |
| const known = new Set<string>(); | |
| for (const contribution of getAgentToolContributions()) known.add(contribution.options.name); | |
| for (const ref of this.toolRegistry.listReferences()) known.add(ref.name); | |
| for (const builtin of this.builtinProfiles.list()) { | |
| for (const name of literalToolNames([ | |
| ...(builtin.tools ?? []), | |
| ...(builtin.disallowedTools ?? []), | |
| ])) { | |
| known.add(name); | |
| } | |
| } | |
| const checks: { | |
| context: string; | |
| field: string; | |
| patterns: readonly string[] | undefined; | |
| }[] = []; | |
| if (profile !== undefined) { | |
| checks.push( | |
| { context: `profile "${profile.name}"`, field: 'tools', patterns: profile.tools }, | |
| { | |
| context: `profile "${profile.name}"`, | |
| field: 'disallowedTools', | |
| patterns: profile.disallowedTools, | |
| }, | |
| ); | |
| } | |
| const global = this.config.get<ToolsConfig>(TOOLS_SECTION); | |
| checks.push( | |
| { context: 'the global [tools] config', field: 'enabled', patterns: global?.enabled }, | |
| { context: 'the global [tools] config', field: 'disabled', patterns: global?.disabled }, | |
| ); | |
| for (const { context, field, patterns } of checks) { | |
| if (patterns === undefined) continue; | |
| for (const issue of findInactiveToolPatterns(patterns, (name) => known.has(name))) { | |
| const key = `${context}|${field}|${issue.pattern}`; | |
| if (this.emittedToolPatternWarnings.has(key)) continue; | |
| this.emittedToolPatternWarnings.add(key); | |
| void this.dispatcher.dispatch( | |
| new WarningIssued({ | |
| agentId: this.scopeContext.agentId, | |
| code: 'tool-pattern-no-match', | |
| message: describeInactiveToolPattern(context, field, issue), | |
| }), | |
| ); | |
| } | |
| } | |
| } | |
| private async buildSystemPromptContext( | |
| profile: ResolvedAgentProfile, | |
| options?: ApplyProfileOptions, | |
| ): Promise<SystemPromptContext> { | |
| await this.notify.ready; | |
| const preloadedAgentsMd = await this.workspaceInstructionsSnapshot(); | |
| const fsAvailable = this.runtime.isAvailable(['fs']); | |
| const lease = this.runtime.acquire(fsAvailable ? ['fs'] : []); | |
| const env = lease.runtime.environment; | |
| const view = new RuntimeWorkspaceView(lease.runtime, { | |
| workDir: this.sessionContext.cwd, | |
| additionalDirs: options?.additionalDirs ?? this.workspace.additionalDirs, | |
| }); | |
| let base: SystemPromptContext; | |
| try { | |
| base = !fsAvailable | |
| ? {} | |
| : await prepareSystemPromptContext( | |
| { fs: lease.runtime.fs!, homeDir: env.homeDir }, | |
| view.workDir, | |
| this.bootstrap.homeDir, | |
| { | |
| additionalDirs: view.additionalDirs, | |
| preloadedAgentsMd, | |
| }, | |
| ); | |
| } finally { | |
| lease.dispose(); | |
| } | |
| const skills = await this.resolveSkillListing(); | |
| const pluginSections = await this.resolvePluginSections(); | |
| return { | |
| ...base, | |
| cwd: view.workDir, | |
| osKind: env.osKind, | |
| shellName: env.shellName, | |
| shellPath: env.shellPath, | |
| skills, | |
| pluginSections, | |
| skillActive: this.isToolActiveForProfile(profile, 'Skill'), | |
| productName: (await this.identity.resolved()).displayName, | |
| replyStyleGuide: this.bootstrap.args.replyStyleGuide, | |
| notifyUserActive: | |
| this.notify.enabled && | |
| this.isToolActiveForProfile(profile, NOTIFY_USER_TOOL_NAME), | |
| }; | |
| } | |
| private async workspaceInstructionsSnapshot(): Promise<LoadedAgentsMd> { | |
| await this.instructions.ready; | |
| return { | |
| content: this.instructions.agentsMd ?? '', | |
| warning: this.instructions.agentsMdWarning, | |
| paths: this.instructions.agentsMdPaths ?? [], | |
| }; | |
| } | |
| private isToolActiveForProfile( | |
| profile: ResolvedAgentProfile, | |
| name: string, | |
| source: ToolSource = 'builtin', | |
| ): boolean { | |
| return isToolActiveComposed( | |
| { | |
| workspaceDisabledTools: this.toolPolicyGate.disabledTools, | |
| profile, | |
| global: this.config.get<ToolsConfig>(TOOLS_SECTION), | |
| sessionDisabledTools: this.sessionToolPolicy.disabledTools(), | |
| }, | |
| name, | |
| source, | |
| ); | |
| } | |
| private async resolveSkillListing(): Promise<string> { | |
| if (this.frozenSkillListing !== undefined) return this.frozenSkillListing; | |
| try { | |
| await this.skillCatalog.ready; | |
| const listing = this.skillCatalog.catalog.getModelSkillListing(); | |
| this.frozenSkillListing = listing; | |
| return listing; | |
| } catch { | |
| return ''; | |
| } | |
| } | |
| private async resolvePluginSections(): Promise<string> { | |
| if (this.frozenPluginSections !== undefined) return this.frozenPluginSections; | |
| const sections = await this.plugins.enabledSystemPrompts(); | |
| const parts: string[] = []; | |
| const skipped: string[] = []; | |
| let totalBytes = 0; | |
| for (const section of sections) { | |
| const block = `<!-- From: plugin ${section.pluginId} -->\n${section.content}`; | |
| const bytes = Buffer.byteLength(block, 'utf8'); | |
| if (totalBytes + bytes > PLUGIN_SECTIONS_MAX_BYTES) { | |
| skipped.push(section.pluginId); | |
| continue; | |
| } | |
| totalBytes += bytes; | |
| parts.push(block); | |
| } | |
| if (skipped.length > 0) { | |
| const newlySkipped = skipped.filter((id) => !this.emittedPluginBudgetWarnings.has(id)); | |
| if (newlySkipped.length > 0) { | |
| for (const id of newlySkipped) this.emittedPluginBudgetWarnings.add(id); | |
| void this.dispatcher.dispatch( | |
| new WarningIssued({ | |
| agentId: this.scopeContext.agentId, | |
| message: | |
| `Plugin system-prompt contributions from ${newlySkipped.map((id) => `"${id}"`).join(', ')} ` + | |
| `were skipped: the aggregate ${PLUGIN_SECTIONS_MAX_BYTES / 1024} KB budget is exhausted.`, | |
| code: 'plugin-sections-oversized', | |
| }), | |
| ); | |
| } | |
| } | |
| const resolved = parts.join('\n\n'); | |
| if (this.plugins.hasLoadedSnapshot()) this.frozenPluginSections = resolved; | |
| return resolved; | |
| } | |
| } | |
| registerScopedService( | |
| LifecycleScope.Agent, | |
| IAgentProfileService, | |
| AgentProfileService, | |
| ScopeActivation.OnScopeCreated, | |
| 'profile', | |
| ); | |