File size: 3,741 Bytes
68d7816 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | import { createDecorator } from '#/_base/di/instantiation';
import { LifecycleScope } from '#/app/scopes';
import { ScopeActivation, registerScopedService } from '#/_base/di/scope';
import { IEventService } from '#/app/event/event';
import { ITelemetryService } from '#/app/telemetry/telemetry';
import { IAgentScopeContext } from '#/agent/scopeContext/scopeContext';
import { promptMetadataTextFromContentParts } from '#/agent/prompt/promptMetadataText';
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 {
IAgentLoopService,
type PromptLaunchResult,
type PromptPayload,
type SteerPayload,
} from './loop';
export interface IAgentPromptChannel {
readonly _serviceBrand: undefined;
submit(payload: PromptPayload): Promise<PromptLaunchResult | undefined>;
submitSteer(payload: SteerPayload): Promise<PromptLaunchResult | undefined>;
}
export const IAgentPromptChannel = createDecorator<IAgentPromptChannel>('agentPromptService');
export class AgentPromptChannel implements IAgentPromptChannel {
declare readonly _serviceBrand: undefined;
constructor(
@IAgentLoopService private readonly loop: IAgentLoopService,
@IAgentScopeContext private readonly scopeContext: IAgentScopeContext,
@ISessionMetadata private readonly metadata: ISessionMetadata,
@IEventService private readonly eventService: IEventService,
@ISessionContext private readonly sessionContext: ISessionContext,
@ITelemetryService private readonly telemetry: ITelemetryService,
) {}
async submit(payload: PromptPayload): Promise<PromptLaunchResult | undefined> {
await this.updateMetadata(promptMetadataTextFromContentParts(payload.input));
const status = this.loop.snapshot();
const { id } = this.loop.submit({
message: { role: 'user', content: [...payload.input] },
meta: { promptId: payload.promptId, origin: { kind: 'user' }, tracked: true },
});
if (status.state === 'running' || status.paused || status.queue.length > 0) return undefined;
return launchResult(this.loop, id);
}
async submitSteer(payload: SteerPayload): Promise<PromptLaunchResult | undefined> {
this.telemetry.track2('input_steer', { parts: payload.input.length });
await this.updateMetadata(promptMetadataTextFromContentParts(payload.input));
const status = this.loop.snapshot();
const { id } = this.loop.submit(
{
message: { role: 'user', content: [...payload.input] },
meta: { origin: { kind: 'user' }, tracked: true },
},
{ steerIfActive: true },
);
if (status.state === 'running' && status.activePromptId === undefined) return undefined;
return launchResult(this.loop, id);
}
private async updateMetadata(text: string | undefined): Promise<void> {
if (this.scopeContext.agentId !== MAIN_AGENT_ID) return;
await applyPromptMetadataUpdate(
{
metadata: this.metadata,
eventService: this.eventService,
sessionId: this.sessionContext.sessionId,
},
text,
);
}
}
async function launchResult(
loop: IAgentLoopService,
id: string,
): Promise<PromptLaunchResult | undefined> {
const turn = await loop.promptHandle(id)?.launched;
if (turn === undefined) return undefined;
await turn.ready.catch(() => undefined);
return turn.id === undefined ? undefined : { turn_id: turn.id };
}
registerScopedService(
LifecycleScope.Agent,
IAgentPromptChannel,
AgentPromptChannel,
ScopeActivation.OnDemand,
'prompt',
);
|