Add capability-probed structured outputs and a prototype/instance creation graph.

Probe API profiles for json_schema/tools, flatten worker artifacts onto a strict schema, and let users spawn or revise graph nodes instead of a one-shot DAG.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-31 01:57:22 +08:00
co-authored by Cursor
parent 872f742d3e
commit bd5d88abfa
65 changed files with 7625 additions and 942 deletions
+14 -4
View File
@@ -72,9 +72,16 @@ export function buildContextTrace(params: {
};
}
/** 编排检查点:不随「只留最新 N 条」丢掉,否则开场白阶段无法回看/回退到流程编排 */
export function isPinnedContextTraceCaller(caller: string | undefined): boolean {
const id = (caller ?? "").trim();
return id === "worker:design-flow" || id.endsWith(":design-flow");
}
/**
* 只保留「带 contextTrace 的消息」中最新 keepLatest 条的全文;
* 更早的消息删除 contextTrace 字段(消息本身保留)。
* design-flow 痕迹钉住不删(keep=0 仍全部清除)。
*/
export function pruneContextTraces<T extends { contextTrace?: LlmContextTrace }>(
messages: T[],
@@ -88,12 +95,15 @@ export function pruneContextTraces<T extends { contextTrace?: LlmContextTrace }>
return rest as T;
});
}
const withTraceIdx: number[] = [];
const droppableIdx: number[] = [];
for (let i = 0; i < messages.length; i++) {
if (messages[i].contextTrace) withTraceIdx.push(i);
const trace = messages[i].contextTrace;
if (!trace) continue;
if (isPinnedContextTraceCaller(trace.caller)) continue;
droppableIdx.push(i);
}
if (withTraceIdx.length <= keep) return messages;
const drop = new Set(withTraceIdx.slice(0, withTraceIdx.length - keep));
if (droppableIdx.length <= keep) return messages;
const drop = new Set(droppableIdx.slice(0, droppableIdx.length - keep));
return messages.map((m, i) => {
if (!drop.has(i) || !m.contextTrace) return m;
const { contextTrace: _drop, ...rest } = m as T & { contextTrace?: LlmContextTrace };
+30 -1
View File
@@ -60,6 +60,13 @@ export type WaitingReason =
kind: "next_intent";
afterWorkerId?: string;
afterUnitId?: string;
}
| {
/**
* DAG 已在:按依赖层级点选节点。依赖未齐的不能点;
* 可反复能力以 role=prototype 槽位呈现;点原型增殖 instance 再进去。
*/
kind: "pick_creation_step";
};
/** 与 src/skills/types 对齐的最小 skill 索引字段,避免 runtime 强依赖 skills 模块 */
@@ -232,6 +239,26 @@ export type RuntimeEvent =
type: "user_rejected_next_step";
payload: { decisionId: string; reason?: string };
}
| {
/** 回到流程编排:在已验收步骤上追加/改排节点(不整局重开) */
type: "user_requested_flow_replan";
payload: { reason?: string };
}
| {
/** DAG 图上点选一条已就绪的步骤,进入 design-step */
type: "user_picked_creation_step";
payload: { stepId: string };
}
| {
/** 验收后 / 总管误调 design-step:停在分层图上等用户点选 */
type: "creation_step_pick_awaited";
payload?: Record<string, never>;
}
| {
/** 离开当前技能步,回到分层图点选(误点增殖节点时用) */
type: "user_left_creation_step";
payload?: Record<string, never>;
}
| {
type: "worker_started";
payload: {
@@ -331,10 +358,12 @@ export type PhaseEffect =
| { type: "resume_worker" }
| { type: "run_programmatic_review"; artifactId: string }
| { type: "emit_message"; message: string }
/** 根据流程与用户下一步意向,提案下一节点并进入确认 */
/** 根据流程与用户下一步意向,提案下一节点或停在分层图上等点选 */
| { type: "propose_next_creation_step" }
/** 选定开场白:落库、关 DAG、标记创作收口 */
| { type: "seal_creation_opening" }
/** 再编排:解开开场收口、把 DAG 改回 open */
| { type: "unseal_creation_opening" }
/** 游玩:按运行规格开一轮(旁观 → 主世界层 → 转述) */
| { type: "run_play_turn" }
/** 游玩:跑管线里的下一个执行单元;队空则等下一条用户输入 */