编码母题 / P0 / AI 全栈与 Agent 工程 / 01
智能体流式事件协议与状态归并器
先读清题意与边界,独立尝试,再展开思路并对照可运行的参考代码。
重要程度高价值难度中等预计完成35–45 分钟
题目是什么
按 runId、sequence 和事件类型把 Agent 流式事件归并成前端状态。重复序号忽略,跳号报错,工具调用只能按合法状态转移。
输入输出示例
收到 sequence=1 后直接收到 3,应报告 gap,不能把 token 拼入错误状态。
练习起手式与验证
复制代码后补全空方法,再运行下方三组验证;复杂题所需的辅助类型与输入准备一并放在代码块中。
/*
* 题目:智能体流式事件协议与状态归并器
* 要求:按 runId、sequence 和事件类型把 Agent 流式事件归并成前端状态。
* 重复序号忽略,跳号报错,工具调用只能按合法状态转移。
* 示例:收到 sequence=1 后直接收到 3,应报告 gap,不能把 token
* 拼入错误状态。
*/
function initialAgentState(runId) {}
function reduceAgentEvent(state, event) {}
const events = [
{ runId: "r", sequence: 1, type: "run_started" },
{ runId: "r", sequence: 2, type: "token_delta", delta: "你" },
{
runId: "r",
sequence: 3,
type: "tool_started",
toolCallId: "t",
name: "search",
},
{
runId: "r",
sequence: 4,
type: "tool_completed",
toolCallId: "t",
output: [],
},
{ runId: "r", sequence: 5, type: "run_completed" },
];
const state = events.reduce(reduceAgentEvent, initialAgentState("r"));
console.log(state.status); // 预期:"completed"
console.log(state.text); // 预期:"你"
console.log(state.tools.t.status); // 预期:"completed"
/*
* 题目:智能体流式事件协议与状态归并器
* 要求:按 runId、sequence 和事件类型把 Agent 流式事件归并成前端状态。
* 重复序号忽略,跳号报错,工具调用只能按合法状态转移。
* 示例:收到 sequence=1 后直接收到 3,应报告 gap,不能把 token
* 拼入错误状态。
*/
function initialAgentState(runId) {}
function reduceAgentEvent(state, event) {}
const events = [
{ runId: "r", sequence: 1, type: "run_started" },
{ runId: "r", sequence: 2, type: "token_delta", delta: "你" },
{
runId: "r",
sequence: 3,
type: "tool_started",
toolCallId: "t",
name: "search",
},
{
runId: "r",
sequence: 4,
type: "tool_completed",
toolCallId: "t",
output: [],
},
{ runId: "r", sequence: 5, type: "run_completed" },
];
const state = events.reduce(reduceAgentEvent, initialAgentState("r"));
console.log(state.status); // 预期:"completed"
console.log(state.text); // 预期:"你"
console.log(state.tools.t.status); // 预期:"completed"解题思路
展开思路、不变量与常见边界
关键切入点:把事件作为可重放事实日志,Reducer 只接受严格连续序号并保持纯函数。
核心模型:服务端事件是事实日志,前端状态是可重放投影。只接受严格连续序号; Tool 以 id 索引并校验合法转移;终态拒绝后续新事件。Reducer 不做网络和时间副作用。 迁移:刷新后重放、断线续传、Agent 时间线和多端同步。
参考代码与验证
“关键机制”注释用于解释实现,下载链接提供未经页面注释修改的原始 JS 文件。
// 关键机制:把事件作为可重放事实日志,Reducer 只接受严格连续序号并保持纯函数。
function initialAgentState(runId) {
return {
runId,
status: "idle",
lastSequence: 0,
text: "",
tools: {},
error: null,
};
}
function reduceAgentEvent(state, event) {
if (event.runId !== state.runId) throw new Error("runId mismatch");
if (event.sequence <= state.lastSequence) return state;
if (event.sequence !== state.lastSequence + 1)
throw new Error("event sequence gap");
if (["completed", "failed"].includes(state.status))
throw new Error("event after terminal state");
const next = {
...state,
lastSequence: event.sequence,
tools: { ...state.tools },
};
if (event.type === "run_started") {
if (state.status !== "idle") throw new Error("run already started");
next.status = "running";
} else if (event.type === "token_delta") {
if (state.status !== "running") throw new Error("run not active");
next.text += event.delta;
} else if (event.type === "tool_started") {
if (next.tools[event.toolCallId]) throw new Error("duplicate tool call");
next.tools[event.toolCallId] = { status: "running", name: event.name };
} else if (event.type === "tool_completed") {
const tool = next.tools[event.toolCallId];
if (!tool || tool.status !== "running") throw new Error("tool not running");
next.tools[event.toolCallId] = {
...tool,
status: "completed",
output: event.output,
};
} else if (event.type === "run_completed") next.status = "completed";
else if (event.type === "run_failed") {
next.status = "failed";
next.error = event.error;
} else throw new Error(`unknown event: ${event.type}`);
return next;
}
// 三组以上可直接运行的验证。
const events = [
{ runId: "r", sequence: 1, type: "run_started" },
{ runId: "r", sequence: 2, type: "token_delta", delta: "你" },
{
runId: "r",
sequence: 3,
type: "tool_started",
toolCallId: "t",
name: "search",
},
{
runId: "r",
sequence: 4,
type: "tool_completed",
toolCallId: "t",
output: [],
},
{ runId: "r", sequence: 5, type: "run_completed" },
];
const state = events.reduce(reduceAgentEvent, initialAgentState("r"));
console.log(state.status); // 预期:"completed"
console.log(state.text); // 预期:"你"
console.log(state.tools.t.status); // 预期:"completed"
console.log(reduceAgentEvent(state, events[4])); // 预期:state
console.log((() => { try { (() =>
reduceAgentEvent(initialAgentState("r"), {
runId: "r",
sequence: 2,
type: "run_started",
}))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
// 关键机制:把事件作为可重放事实日志,Reducer 只接受严格连续序号并保持纯函数。
function initialAgentState(runId) {
return {
runId,
status: "idle",
lastSequence: 0,
text: "",
tools: {},
error: null,
};
}
function reduceAgentEvent(state, event) {
if (event.runId !== state.runId) throw new Error("runId mismatch");
if (event.sequence <= state.lastSequence) return state;
if (event.sequence !== state.lastSequence + 1)
throw new Error("event sequence gap");
if (["completed", "failed"].includes(state.status))
throw new Error("event after terminal state");
const next = {
...state,
lastSequence: event.sequence,
tools: { ...state.tools },
};
if (event.type === "run_started") {
if (state.status !== "idle") throw new Error("run already started");
next.status = "running";
} else if (event.type === "token_delta") {
if (state.status !== "running") throw new Error("run not active");
next.text += event.delta;
} else if (event.type === "tool_started") {
if (next.tools[event.toolCallId]) throw new Error("duplicate tool call");
next.tools[event.toolCallId] = { status: "running", name: event.name };
} else if (event.type === "tool_completed") {
const tool = next.tools[event.toolCallId];
if (!tool || tool.status !== "running") throw new Error("tool not running");
next.tools[event.toolCallId] = {
...tool,
status: "completed",
output: event.output,
};
} else if (event.type === "run_completed") next.status = "completed";
else if (event.type === "run_failed") {
next.status = "failed";
next.error = event.error;
} else throw new Error(`unknown event: ${event.type}`);
return next;
}
// 三组以上可直接运行的验证。
const events = [
{ runId: "r", sequence: 1, type: "run_started" },
{ runId: "r", sequence: 2, type: "token_delta", delta: "你" },
{
runId: "r",
sequence: 3,
type: "tool_started",
toolCallId: "t",
name: "search",
},
{
runId: "r",
sequence: 4,
type: "tool_completed",
toolCallId: "t",
output: [],
},
{ runId: "r", sequence: 5, type: "run_completed" },
];
const state = events.reduce(reduceAgentEvent, initialAgentState("r"));
console.log(state.status); // 预期:"completed"
console.log(state.text); // 预期:"你"
console.log(state.tools.t.status); // 预期:"completed"
console.log(reduceAgentEvent(state, events[4])); // 预期:state
console.log((() => { try { (() =>
reduceAgentEvent(initialAgentState("r"), {
runId: "r",
sequence: 2,
type: "run_started",
}))(); return false; } catch { return true; } })()); // 预期:true(抛出异常)
复杂度分析
时间复杂度:O(T+L)/事件。复制 T 个工具状态;token 追加可能复制已有 L 长度文本。
空间复杂度:O(T+L)/状态。下一状态保存工具表和累计文本。