Download packages/agent-core-v2/src/session/sessionActivity/sessionActivityService.ts from SaylorTwift/kimi-code: direct link, hf CLI and curl.
- Browser
- Download file 10.2 kB
-
https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/session/sessionActivity/sessionActivityService.ts
- Command line
-
hf download hf://SaylorTwift/kimi-code/packages/agent-core-v2/src/session/sessionActivity/sessionActivityService.ts
-
curl -L -o sessionActivityService.ts https://huggingface.co/SaylorTwift/kimi-code/resolve/main/packages/agent-core-v2/src/session/sessionActivity/sessionActivityService.ts
10.2 kB
| import { Disposable, DisposableStore, toDisposable, type IDisposable } from '#/_base/di/lifecycle'; | |
| import { LifecycleScope } from '#/app/scopes'; | |
| import { | |
| ScopeActivation, | |
| registerScopedService, | |
| type IAgentScopeHandle, | |
| } from '#/_base/di/scope'; | |
| import { Emitter, type Event } from '#/_base/event'; | |
| import { defineState } from '#/state/state'; | |
| import { IEventBus } from '#/app/event/eventBus'; | |
| import { IEventDispatcher } from '#/state/eventDispatcher'; | |
| import { IAgentLoopService } from '#/agent/loop/loop'; | |
| import { TurnStarted, type TurnEndReason } from '#/agent/loop/turnEvents'; | |
| import { TurnEnded, turnKey } from '#/agent/loop/turnOps'; | |
| import { IAgentTaskService } from '#/agent/task/task'; | |
| import { TaskStarted, TaskTerminatedNotice } from '#/agent/task/taskOps'; | |
| import { IAgentFullCompactionService } from '#/agent/fullCompaction/fullCompaction'; | |
| import { | |
| CompactionCancelled, | |
| CompactionCompleted, | |
| CompactionStarted, | |
| } from '#/agent/fullCompaction/compactionOps'; | |
| import { IAgentStateService } from '#/agent/state/agentState'; | |
| import { IAgentLifecycleService, MAIN_AGENT_ID } from '#/session/agentLifecycle/agentLifecycle'; | |
| import { | |
| INTERACTION_TAG_SESSION_ID, | |
| type Interaction, | |
| } from '#/human/interaction/interaction'; | |
| import { interactions } from '#/human/interaction/facade'; | |
| import { ISessionContext } from '#/session/sessionContext/sessionContext'; | |
| import { ISessionStateService } from '#/session/state/sessionState'; | |
| import { | |
| ISessionActivityView, | |
| type SessionActivityCause, | |
| type SessionActivityChangedEvent, | |
| type SessionActivityState, | |
| type SessionPendingInteraction, | |
| type SessionTurnOutcome, | |
| } from './sessionActivity'; | |
| interface AgentWorkFold { | |
| turnActive: boolean; | |
| background: ReadonlySet<string>; | |
| compacting: boolean; | |
| lastTurnReason?: SessionTurnOutcome; | |
| } | |
| export const sessionActivityFoldsKey = defineState<Map<string, AgentWorkFold>>( | |
| 'sessionActivity.folds', | |
| () => new Map(), | |
| ); | |
| export const sessionActivityCurrentKey = defineState<SessionActivityState>('sessionActivity.current', () => ({ | |
| busy: false, | |
| mainTurnActive: false, | |
| pendingInteraction: 'none', | |
| lastTurnReason: undefined, | |
| })); | |
| export class SessionActivityView extends Disposable implements ISessionActivityView { | |
| declare readonly _serviceBrand: undefined; | |
| private readonly _onDidChange = this._register(new Emitter<SessionActivityChangedEvent>()); | |
| readonly onDidChange: Event<SessionActivityChangedEvent> = this._onDidChange.event; | |
| private readonly agentSubscriptions = new Map<string, IDisposable>(); | |
| constructor( | |
| private readonly states: ISessionStateService, | |
| private readonly agents: IAgentLifecycleService, | |
| private readonly ctx: ISessionContext, | |
| ) { | |
| super(); | |
| this.states.contributeState(sessionActivityFoldsKey); | |
| this.states.contributeState(sessionActivityCurrentKey); | |
| for (const agent of this.agents.list()) { | |
| const handle = this.agents.handleOf(agent.agentId); | |
| if (handle !== undefined) this.attachAgent(handle); | |
| } | |
| this.current = this.aggregate(); | |
| this._register( | |
| this.agents.onDidCreateScope(({ handle }) => { | |
| this.attachAgent(handle); | |
| this.recompute('agent_lifecycle'); | |
| }), | |
| ); | |
| this._register( | |
| this.agents.onDidClose((agent) => { | |
| this.agentSubscriptions.get(agent.agentId)?.dispose(); | |
| this.agentSubscriptions.delete(agent.agentId); | |
| if (this.folds.delete(agent.agentId)) this.recompute('agent_lifecycle'); | |
| }), | |
| ); | |
| this._register( | |
| toDisposable( | |
| interactions.onDidChangePending(() => this.recompute('interaction')), | |
| ), | |
| ); | |
| this._register( | |
| toDisposable(() => { | |
| for (const subscription of this.agentSubscriptions.values()) subscription.dispose(); | |
| this.agentSubscriptions.clear(); | |
| }), | |
| ); | |
| } | |
| private get folds(): Map<string, AgentWorkFold> { | |
| return this.states.get(sessionActivityFoldsKey); | |
| } | |
| private get current(): SessionActivityState { | |
| return this.states.get(sessionActivityCurrentKey); | |
| } | |
| private set current(value: SessionActivityState) { | |
| this.states.set(sessionActivityCurrentKey, value); | |
| } | |
| state(): SessionActivityState { | |
| return this.current; | |
| } | |
| private attachAgent(handle: IAgentScopeHandle): void { | |
| if (this.folds.has(handle.id)) return; | |
| this.folds.set(handle.id, seedFold(handle)); | |
| const bus = handle.accessor.get(IEventBus) as IEventBus | undefined; | |
| if (bus === undefined) return; | |
| const subscriptions = new DisposableStore(); | |
| subscriptions.add( | |
| bus.subscribe(TurnStarted, () => | |
| this.patchFold(handle.id, (fold) => ({ | |
| ...fold, | |
| turnActive: true, | |
| lastTurnReason: handle.id === MAIN_AGENT_ID ? undefined : fold.lastTurnReason, | |
| })), | |
| ), | |
| ); | |
| subscriptions.add( | |
| bus.subscribe(TurnEnded, (event) => | |
| this.patchFold(handle.id, (fold) => ({ | |
| ...fold, | |
| turnActive: false, | |
| lastTurnReason: handle.id === MAIN_AGENT_ID ? mapTurnReason(event.reason) : fold.lastTurnReason, | |
| })), | |
| ), | |
| ); | |
| subscriptions.add( | |
| bus.subscribe(TaskStarted, (event) => | |
| this.patchFold(handle.id, (fold) => ({ | |
| ...fold, | |
| background: new Set(fold.background).add(event.info.taskId), | |
| })), | |
| ), | |
| ); | |
| subscriptions.add( | |
| bus.subscribe(TaskTerminatedNotice, (event) => | |
| this.patchFold(handle.id, (fold) => { | |
| if (!fold.background.has(event.info.taskId)) return fold; | |
| const background = new Set(fold.background); | |
| background.delete(event.info.taskId); | |
| return { ...fold, background }; | |
| }), | |
| ), | |
| ); | |
| subscriptions.add( | |
| bus.subscribe(CompactionStarted, () => | |
| this.patchFold(handle.id, (fold) => ({ ...fold, compacting: true })), | |
| ), | |
| ); | |
| subscriptions.add( | |
| bus.subscribe(CompactionCompleted, () => | |
| this.patchFold(handle.id, (fold) => ({ ...fold, compacting: false })), | |
| ), | |
| ); | |
| subscriptions.add( | |
| bus.subscribe(CompactionCancelled, () => | |
| this.patchFold(handle.id, (fold) => ({ ...fold, compacting: false })), | |
| ), | |
| ); | |
| const dispatcher = handle.accessor.get(IEventDispatcher) as IEventDispatcher | undefined; | |
| if (dispatcher !== undefined) { | |
| subscriptions.add( | |
| dispatcher.hooks.onDidRestore.register('sessionActivity', async (_ctx, next) => { | |
| this.folds.set(handle.id, seedFold(handle)); | |
| this.recompute('agent_lifecycle'); | |
| await next(); | |
| }), | |
| ); | |
| } | |
| this.agentSubscriptions.set(handle.id, subscriptions); | |
| } | |
| private patchFold(agentId: string, patch: (fold: AgentWorkFold) => AgentWorkFold): void { | |
| const previous = this.folds.get(agentId); | |
| if (previous === undefined) return; | |
| const next = patch(previous); | |
| this.folds.set(agentId, next); | |
| let cause: SessionActivityCause | undefined; | |
| if (!previous.turnActive && next.turnActive) cause = 'turn_started'; | |
| else if (previous.turnActive && !next.turnActive) cause = 'turn_ended'; | |
| else if (previous.background.size !== next.background.size || previous.compacting !== next.compacting) { | |
| cause = 'background'; | |
| } | |
| else if (agentId === MAIN_AGENT_ID && previous.lastTurnReason !== next.lastTurnReason) { | |
| cause = 'turn_ended'; | |
| } | |
| if (cause !== undefined) this.recompute(cause); | |
| } | |
| private recompute(cause: SessionActivityCause): void { | |
| const next = this.aggregate(); | |
| if (activityEquals(this.current, next)) return; | |
| this.current = next; | |
| this._onDidChange.fire({ state: next, cause }); | |
| } | |
| private aggregate(): SessionActivityState { | |
| let busy = false; | |
| for (const fold of this.folds.values()) { | |
| if (fold.turnActive || fold.background.size > 0 || fold.compacting) { | |
| busy = true; | |
| break; | |
| } | |
| } | |
| return { | |
| busy, | |
| mainTurnActive: this.folds.get(MAIN_AGENT_ID)?.turnActive ?? false, | |
| pendingInteraction: resolvePendingInteraction( | |
| interactions.findAll({ | |
| resolved: false, | |
| tags: { [INTERACTION_TAG_SESSION_ID]: this.ctx.sessionId }, | |
| }), | |
| ), | |
| lastTurnReason: this.folds.get(MAIN_AGENT_ID)?.lastTurnReason, | |
| }; | |
| } | |
| } | |
| function seedFold(handle: IAgentScopeHandle): AgentWorkFold { | |
| const loop = handle.accessor.get(IAgentLoopService) as IAgentLoopService | undefined; | |
| const tasks = handle.accessor.get(IAgentTaskService) as IAgentTaskService | undefined; | |
| const compaction = handle.accessor.get(IAgentFullCompactionService) as | |
| | IAgentFullCompactionService | |
| | undefined; | |
| const states = handle.accessor.get(IAgentStateService) as IAgentStateService | undefined; | |
| const lastEnded = | |
| handle.id === MAIN_AGENT_ID && states?.has(turnKey) === true | |
| ? states.get(turnKey).lastEnded | |
| : undefined; | |
| return { | |
| turnActive: loop?.snapshot().state === 'running', | |
| background: new Set(tasks?.list(true).map((task) => task.taskId) ?? []), | |
| compacting: (compaction?.compacting ?? null) !== null, | |
| lastTurnReason: | |
| loop?.snapshot().state === 'running' ? undefined : mapTurnReason(lastEnded?.reason), | |
| }; | |
| } | |
| function mapTurnReason(reason: TurnEndReason | undefined): SessionTurnOutcome | undefined { | |
| if (reason === undefined) return undefined; | |
| return reason === 'completed' ? 'completed' : reason === 'cancelled' ? 'cancelled' : 'failed'; | |
| } | |
| function resolvePendingInteraction(pending: readonly Interaction[]): SessionPendingInteraction { | |
| if (pending.some((interaction) => interaction.kind === 'approval')) return 'approval'; | |
| if (pending.some((interaction) => interaction.kind === 'question')) return 'question'; | |
| return 'none'; | |
| } | |
| function activityEquals(a: SessionActivityState, b: SessionActivityState): boolean { | |
| return ( | |
| a.busy === b.busy && | |
| a.mainTurnActive === b.mainTurnActive && | |
| a.pendingInteraction === b.pendingInteraction && | |
| a.lastTurnReason === b.lastTurnReason | |
| ); | |
| } | |
| registerScopedService( | |
| LifecycleScope.Session, | |
| ISessionActivityView, | |
| SessionActivityView, | |
| ScopeActivation.OnScopeCreated, | |
| 'sessionActivity', | |
| ); | |