Download packages/agent-core-v2/src/features/skill/skillService.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 9.95 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/features/skill/skillService.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/agent-core-v2/src/features/skill/skillService.ts
-
curl -L -o skillService.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/features/skill/skillService.ts
9.95 kB
| import { randomUUID } from 'node:crypto'; | |
| import { createDecorator } from '#/_base/di/instantiation'; | |
| import type { | |
| BundledSkillActivation, | |
| PromptOrigin, | |
| SkillActivationOrigin, | |
| } from '#/agent/contextMemory/types'; | |
| import { IAgentLoopService, type PromptLaunchResult, type Turn } from '#/agent/loop/loop'; | |
| import { promptMetadataTextFromContentParts } from '#/agent/prompt/promptMetadataText'; | |
| import { IAgentScopeContext } from '#/agent/scopeContext/scopeContext'; | |
| import { IEventService } from '#/app/event/event'; | |
| import { ITelemetryService } from '#/app/telemetry/telemetry'; | |
| import { ErrorCodes, Error2 } from '#/errors'; | |
| import type { ContentPart } from '#human/llm/message'; | |
| import { MAIN_AGENT_ID } from '#/session/agentLifecycle/agentLifecycle'; | |
| import { ISessionContext } from '#/session/sessionContext/sessionContext'; | |
| import { ISessionMetadata } from '#/session/sessionMetadata/sessionMetadata'; | |
| import { applyPromptMetadataUpdate } from '#/session/sessionMetadata/promptMetadata'; | |
| import { IEventDispatcher } from '#/state/eventDispatcher'; | |
| import { isUserActivatableSkillType, type SkillDefinition } from './catalog/types'; | |
| import { promptMetadataTextFromSkill, renderUserSlashSkillPrompt } from './prompt'; | |
| import { ISessionSkillCatalog } from './session/skillCatalog'; | |
| import type { | |
| PromptSkillActivation, | |
| PromptWithSkillsInput, | |
| PromptWithSkillsResult, | |
| SkillActivationInput, | |
| } from './skill'; | |
| import { SkillActivated } from './skillOps'; | |
| export interface IAgentSkillService { | |
| readonly _serviceBrand: undefined; | |
| activate(input: SkillActivationInput): Promise<PromptLaunchResult>; | |
| promptWithSkills(input: PromptWithSkillsInput): Promise<PromptWithSkillsResult>; | |
| recordModelToolActivation(origin: SkillActivationOrigin): void; | |
| } | |
| export const IAgentSkillService = createDecorator<IAgentSkillService>('agentSkillService'); | |
| export class AgentSkillService implements IAgentSkillService { | |
| declare readonly _serviceBrand: undefined; | |
| constructor( | |
| private readonly catalog: ISessionSkillCatalog, | |
| private readonly loop: IAgentLoopService, | |
| private readonly metadata: ISessionMetadata, | |
| private readonly eventService: IEventService, | |
| private readonly sessionContext: ISessionContext, | |
| private readonly telemetry: ITelemetryService, | |
| private readonly dispatcher: IEventDispatcher, | |
| private readonly scopeContext: IAgentScopeContext, | |
| ) {} | |
| async activate(input: SkillActivationInput): Promise<PromptLaunchResult> { | |
| const catalog = this.catalog; | |
| await catalog.ready; | |
| const skill = catalog.catalog.getSkill(input.name); | |
| if (skill === undefined) { | |
| throw new Error2(ErrorCodes.SKILL_NOT_FOUND, `Skill "${input.name}" was not found`); | |
| } | |
| if (!isUserActivatableSkillType(skill.metadata.type)) { | |
| throw new Error2( | |
| ErrorCodes.SKILL_TYPE_UNSUPPORTED, | |
| `Skill "${skill.name}" cannot be activated by the user`, | |
| ); | |
| } | |
| const skillArgs = input.args ?? ''; | |
| const skillContent = this.renderSkillPrompt(skill, skillArgs); | |
| const content: ContentPart[] = [ | |
| { | |
| type: 'text', | |
| text: renderUserSlashSkillPrompt({ | |
| skillName: skill.name, | |
| skillArgs, | |
| skillContent, | |
| skillSource: skill.source, | |
| skillDir: skill.dir, | |
| }), | |
| }, | |
| ...(input.content ?? []), | |
| ]; | |
| const turn = await this.recordActivation( | |
| { | |
| kind: 'skill_activation', | |
| activationId: randomUUID(), | |
| skillName: skill.name, | |
| trigger: 'user-slash', | |
| skillType: skill.metadata.type, | |
| skillPath: skill.path, | |
| skillSource: skill.source, | |
| skillArgs: input.args, | |
| attachments: input.attachments, | |
| clientMetadata: input.clientMetadata, | |
| }, | |
| content, | |
| ); | |
| if (turn === undefined) { | |
| throw new Error2( | |
| ErrorCodes.TURN_AGENT_BUSY, | |
| 'Cannot activate skill while another turn is active', | |
| ); | |
| } | |
| await turn.ready.catch(() => undefined); | |
| if (turn.id === undefined) { | |
| throw new Error2(ErrorCodes.INTERNAL, 'Skill activation turn ended before it started'); | |
| } | |
| if (this.scopeContext.agentContext.agentId === MAIN_AGENT_ID) { | |
| await applyPromptMetadataUpdate( | |
| { | |
| metadata: this.metadata, | |
| eventService: this.eventService, | |
| sessionId: this.sessionContext.sessionId, | |
| }, | |
| promptMetadataTextFromSkill(input), | |
| ); | |
| } | |
| return { turn_id: turn.id }; | |
| } | |
| async promptWithSkills(input: PromptWithSkillsInput): Promise<PromptWithSkillsResult> { | |
| if (input.input.length === 0) { | |
| throw new Error2(ErrorCodes.REQUEST_INVALID, 'promptWithSkills requires a non-empty prompt'); | |
| } | |
| if (input.skills.length === 0) { | |
| throw new Error2( | |
| ErrorCodes.REQUEST_INVALID, | |
| 'promptWithSkills requires at least one skill', | |
| ); | |
| } | |
| const catalog = this.catalog; | |
| await catalog.ready; | |
| const prepared = input.skills.map((skill) => this.prepareBundled(skill)); | |
| if (this.scopeContext.agentContext.agentId === MAIN_AGENT_ID) { | |
| await applyPromptMetadataUpdate( | |
| { | |
| metadata: this.metadata, | |
| eventService: this.eventService, | |
| sessionId: this.sessionContext.sessionId, | |
| }, | |
| promptMetadataTextFromContentParts(input.input, input.clientMetadata), | |
| ); | |
| } | |
| for (const activation of prepared) { | |
| void this.recordActivation(activation.origin); | |
| } | |
| const status = this.loop.snapshot(); | |
| const { id } = this.loop.submit({ | |
| message: { | |
| role: 'user', | |
| content: [...prepared.map((activation) => activation.part), ...input.input], | |
| }, | |
| meta: { | |
| origin: { | |
| kind: 'user', | |
| skillActivations: prepared.map((activation) => activation.entry), | |
| clientMetadata: input.clientMetadata, | |
| attachments: input.attachments, | |
| } as PromptOrigin, | |
| tracked: true, | |
| }, | |
| }); | |
| const handle = this.loop.promptHandle(id)!; | |
| if (status.state === 'running' || status.paused || status.queue.length > 0) { | |
| return { prompt_id: id, created_at: handle.createdAt, state: 'queued' }; | |
| } | |
| await Promise.race([handle.launched, handle.completion]); | |
| const turn = await handle.launched; | |
| if (turn === undefined && handle.state !== 'blocked') { | |
| throw new Error2(ErrorCodes.INTERNAL, 'promptWithSkills failed to launch a turn'); | |
| } | |
| if (turn !== undefined) await turn.ready.catch(() => undefined); | |
| return { | |
| turn_id: turn?.id, | |
| prompt_id: id, | |
| created_at: handle.createdAt, | |
| state: handle.state === 'blocked' ? 'blocked' : 'running', | |
| }; | |
| } | |
| recordModelToolActivation(origin: SkillActivationOrigin): void { | |
| void this.recordActivation(origin); | |
| } | |
| private prepareBundled(input: PromptSkillActivation): { | |
| readonly origin: SkillActivationOrigin; | |
| readonly part: ContentPart; | |
| readonly entry: BundledSkillActivation; | |
| } { | |
| const catalog = this.catalog; | |
| const skill = catalog.catalog.getSkill(input.name); | |
| if (skill === undefined) { | |
| throw new Error2(ErrorCodes.SKILL_NOT_FOUND, `Skill "${input.name}" was not found`); | |
| } | |
| if (!isUserActivatableSkillType(skill.metadata.type)) { | |
| throw new Error2( | |
| ErrorCodes.SKILL_TYPE_UNSUPPORTED, | |
| `Skill "${skill.name}" cannot be activated by the user`, | |
| ); | |
| } | |
| const skillArgs = input.args ?? ''; | |
| const skillContent = this.renderSkillPrompt(skill, skillArgs); | |
| const origin: SkillActivationOrigin = { | |
| kind: 'skill_activation', | |
| activationId: randomUUID(), | |
| skillName: skill.name, | |
| trigger: 'user-slash', | |
| skillType: skill.metadata.type, | |
| skillPath: skill.path, | |
| skillSource: skill.source, | |
| skillArgs: input.args, | |
| }; | |
| return { | |
| origin, | |
| part: { | |
| type: 'text', | |
| text: renderUserSlashSkillPrompt({ | |
| skillName: skill.name, | |
| skillArgs, | |
| skillContent, | |
| skillSource: skill.source, | |
| skillDir: skill.dir, | |
| }), | |
| }, | |
| entry: { | |
| activationId: origin.activationId, | |
| skillName: origin.skillName, | |
| skillArgs: origin.skillArgs, | |
| skillType: origin.skillType, | |
| skillPath: origin.skillPath, | |
| skillSource: origin.skillSource, | |
| }, | |
| }; | |
| } | |
| private async recordActivation( | |
| origin: SkillActivationOrigin, | |
| input?: readonly ContentPart[], | |
| ): Promise<Turn | undefined> { | |
| await this.dispatcher.dispatch( | |
| new SkillActivated({ | |
| agentId: this.scopeContext.agentContext.agentId, | |
| activationId: origin.activationId, | |
| skillName: origin.skillName, | |
| trigger: origin.trigger, | |
| skillArgs: origin.skillArgs, | |
| skillPath: origin.skillPath, | |
| skillSource: origin.skillSource, | |
| }), | |
| ); | |
| this.publishActivation(origin); | |
| if (input === undefined) return undefined; | |
| const steer = this.loop.snapshot().state === 'running'; | |
| const { id } = this.loop.submit( | |
| { | |
| message: { role: 'user', content: [...input] }, | |
| meta: { origin, tracked: !steer }, | |
| }, | |
| { steerIfActive: steer }, | |
| ); | |
| return this.loop.promptHandle(id)!.launched; | |
| } | |
| private renderSkillPrompt(skill: SkillDefinition, rawArgs: string): string { | |
| return this.catalog.catalog.renderSkillPrompt(skill, rawArgs, { | |
| sessionId: this.sessionContext.sessionId, | |
| }); | |
| } | |
| private publishActivation(origin: SkillActivationOrigin): void { | |
| this.telemetry.track2('skill_invoked', { | |
| skill_name: origin.skillName, | |
| trigger: origin.trigger, | |
| }); | |
| if (origin.skillType === 'flow') { | |
| this.telemetry.track2('flow_invoked', { | |
| flow_name: origin.skillName, | |
| }); | |
| } | |
| } | |
| } | |