aps-agent/server/app/echo-runtime.ts

62 lines
2.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* A1 阶段的占位引擎:把用户输入回显成一条助手消息,用来打通 HTTP / SSE 链路。
*
* 它刻意不做任何「理解」,也不调用 Provider——避免把假能力写进真实链路。
* A3.1 定义正式 AgentRuntime、A3.2 写 FakeRuntime 之后,本文件整体替换。
*/
import type { EventBus } from './events.js';
export interface EchoRunInput {
sessionId: string;
runId: string;
messageId: string;
text: string;
bus: EventBus;
signal: AbortSignal;
}
export interface EchoRunResult {
text: string;
finishReason: 'stop' | 'cancelled';
}
const CHUNK_SIZE = 6;
const CHUNK_DELAY_MS = 25;
const sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));
export async function runEcho(input: EchoRunInput): Promise<EchoRunResult> {
const { bus, signal, sessionId, runId, messageId } = input;
const replyMessageId = `${messageId}-reply`;
const reply = `(A1 占位引擎)收到:${input.text}`;
let emitted = '';
bus.publish({ sessionId, runId, type: 'run.state', data: { state: 'running' } });
for (let index = 0; index < reply.length; index += CHUNK_SIZE) {
if (signal.aborted) return finish(true);
const piece = reply.slice(index, index + CHUNK_SIZE);
emitted += piece;
bus.publish({ sessionId, runId, type: 'message.delta', data: { messageId: replyMessageId, text: piece } });
await sleep(CHUNK_DELAY_MS);
}
if (signal.aborted) return finish(true);
bus.publish({ sessionId, runId, type: 'message.completed', data: { messageId: replyMessageId, finishReason: 'stop' } });
bus.publish({ sessionId, runId, type: 'run.state', data: { state: 'idle' } });
return { text: emitted, finishReason: 'stop' };
function finish(cancelled: boolean): EchoRunResult {
// 取消路径:cancelling → 一条带 cancelled 结束原因的消息 → 回到 idle。
// 'cancelled' 这个运行状态当前不使用(A3.1 定稿再确认语义)。
bus.publish({ sessionId, runId, type: 'run.state', data: { state: 'cancelling' } });
bus.publish({
sessionId,
runId,
type: 'message.completed',
data: { messageId: replyMessageId, finishReason: cancelled ? 'cancelled' : 'stop' },
});
bus.publish({ sessionId, runId, type: 'run.state', data: { state: 'idle' } });
return { text: emitted, finishReason: 'cancelled' };
}
}