Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
ba2a3e2
feat(core): import durable session restart infrastructure
deepagent-ai Aug 3, 2026
51b4472
docs(core): expand durable session migration plan
deepagent-ai Aug 3, 2026
d92d892
docs(core): pause durable session migration
deepagent-ai Aug 3, 2026
3037f16
fix(deepagent-code): harden subagent task lifecycle
deepagent-ai Aug 3, 2026
2d42c38
feat(deepagent-code): implement subagent control plane L0–L10
deepagent-ai Aug 3, 2026
081962d
fix(deepagent-code): production-grade L10 executor wiring
deepagent-ai Aug 3, 2026
5f03c8c
fix(deepagent-code): production-grade subagent control plane L0-L10 r…
deepagent-ai Aug 4, 2026
632adb4
fix(deepagent-code): adversarial review gap fixes — P0/P1/P2 from rev…
deepagent-ai Aug 4, 2026
feeab4b
fix(deepagent-code): real-LLM test bundle + DET-ADM-01 FK+metadata fixes
deepagent-ai Aug 4, 2026
8f4e318
fix(deepagent-code): adversarial review P0/P1 fixes — subagent contro…
deepagent-ai Aug 4, 2026
80f229f
fix(deepagent-code): adversarial review P0/P1/P2 fixes — phases A-D
deepagent-ai Aug 4, 2026
edf9ccd
fix(deepagent-code): BUG-001-405 researcher write-type misclassificat…
deepagent-ai Aug 4, 2026
b6d66ed
fix(deepagent-code): wave-2 adversarial fixes P0-8/9/10 P1-1/6/8/11
deepagent-ai Aug 4, 2026
4b8b81a
fix(deepagent-code): harden durable subagent lifecycle
deepagent-ai Aug 4, 2026
1742109
fix(deepagent-code): project durable run identity into child sessions
deepagent-ai Aug 4, 2026
24faae7
docs(deepagent-code): finalize control-plane audit evidence
deepagent-ai Aug 4, 2026
ba46c24
fix(deepagent-code): isolate durable executor topology locks
deepagent-ai Aug 4, 2026
b2c1220
fix(deepagent-code): recover from cold code intelligence indexes
deepagent-ai Aug 4, 2026
3ead99b
test(deepagent-code): assert Fix-C dirty-path truncation in ensureSes…
deepagent-ai Aug 5, 2026
1ec84ee
fix(deepagent-code): close durable control-plane release blockers
deepagent-ai Aug 5, 2026
5e75efc
fix(deepagent-code): stop continuation repetition and preserve cache …
deepagent-ai Aug 5, 2026
af5d22f
fix(deepagent-code): harden live LLM continuation validation
deepagent-ai Aug 5, 2026
b3af05c
fix(storage): unify private data root
deepagent-ai Jul 31, 2026
56f4763
chore: merge codex/merge-upstream-durable into context-federation-har…
deepagent-ai Aug 5, 2026
a53bd98
chore: merge codex/fix-desktop-build-oom into context-federation-hard…
deepagent-ai Aug 5, 2026
f4ebb4e
fix(core): restore missing closing brackets in database-migration test
deepagent-ai Aug 5, 2026
f5f021a
chore: regenerate bun.lock after three-branch integration merge
deepagent-ai Aug 5, 2026
2357242
fix(core): disable models fetch in LocationServiceMap test to prevent…
deepagent-ai Aug 5, 2026
7b3f755
fix: close validation and prompt admission races
deepagent-ai Aug 6, 2026
02d8111
fix: harden provider startup and live task validation
deepagent-ai Aug 6, 2026
af0bf41
fix(deepagent-code): enforce WSL2 validation boundary
deepagent-ai Aug 6, 2026
0dbd3f0
fix(app): enforce durable prompt intent admission
deepagent-ai Aug 6, 2026
da90e22
fix(app): fence prompt admission against session revert
deepagent-ai Aug 6, 2026
4655215
test(deepagent-code): add prompt intent real LLM coverage
deepagent-ai Aug 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions design/real-llm-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## 0. 权威状态与硬合同

截至 2026-07-31,聚合 runner 注册 55 条命令,其中 48 条调用真实模型;headless 矩阵为 48 条命令、43 条真实模型 suite,进一步跳过 EVAL 和安装后为 46 条命令、42 条真实模型 suite。数字由 `script/run-live-llm-all.ts` 动态注册表决定,文档数字发生漂移时以注册表和 `validateSuiteManifest()` 为准。
截至 2026-08-06,聚合 runner 注册 58 条命令,其中 51 条调用真实模型;headless 矩阵为 51 条命令、46 条真实模型 suite,进一步跳过 EVAL 和安装后为 49 条命令、45 条真实模型 suite。数字由 `script/run-live-llm-all.ts` 动态注册表决定,文档数字发生漂移时以注册表和 `validateSuiteManifest()` 为准。

`qualifiedLiveRuns` 当前为空。注册、单次通过和 EXT 可达都不代表 pre-push 资格;LIVE suite 只有完成本节资格合同后才能进入该集合。

Expand Down Expand Up @@ -127,6 +127,14 @@ ${EDITOR:-vi} script/live-llm.config.local.json
| `evalRuns` | EVAL 重复次数,范围为 1–20。次数越高,费用和耗时越高。 |
| `installDependencies` | 聚合测试是否先运行依赖安装步骤。命令行 `--skip-install` 可以覆盖它。 |

旧版配置如果仍包含 `"apiKey": "..."`,必须迁移,不能同时保留两个字段:

1. 将原始 key 移入第 2 节所述的仓库外单行文件,并执行 `chmod 600`;
2. 删除 JSON 中的 `apiKey`;
3. 在同一位置写入 `"apiKeyFile": "~/.deepagent/code/tmp/live-llm-deepseek.key"`。

聚合 runner 会在任何 Provider 请求发生前拒绝旧字段,且错误信息不会回显旧 key。package 和 Desktop 的单 suite 入口同样只接受 `DEEPAGENT_CODE_LIVE_LLM_API_KEY_FILE`。

## 4. 启动聚合测试

所有聚合命令都从仓库根目录运行。
Expand Down Expand Up @@ -200,6 +208,7 @@ export DEEPAGENT_CODE_LIVE_LLM_TIMEOUT_MS="180000"
(cd packages/deepagent-code && bun run test:llm-ext:subagent-intensity)
(cd packages/deepagent-code && bun run test:llm-ext:subagent-resume)
(cd packages/deepagent-code && bun run test:llm-ext:subagent-takeover)
(cd packages/deepagent-code && bun run test:llm-ext:prompt-intent-fencing)
(cd packages/desktop && bun run test:llm-release:ui)
```

Expand Down Expand Up @@ -243,7 +252,13 @@ Git 合同分入口定义:交互式写型 `task` 使用独立 worktree,并

审批后的完整闭环由直接生产状态机测试验证:Reviewer 首次返回 `request_changes` 后,使用原 `task_id` 恢复同一个 V4 child Session 和作者 worktree,重新提交到同一 PR;再次 `pr_finalize` 后绑定新 SHA 审阅、`--no-ff` merge、Senior Reviewer 和 worktree cleanup 全部完成。默认 V4 分区规则当前没有产生独立同 wave 节点,因此 V4 wave pool 的并行性使用确定性双 runner 同步屏障证明;真实模型并行性由 `multi-agent-parallel-worktrees` 和 `expert-panel` 覆盖,不能把两类证据混写。

### 5.5 Expert Panel 与缓存边界
### 5.5 智能直达、Prompt Intent 与撤回重写

`prompt-intent-fencing` 在同一个真实 DeepSeek Session 中覆盖两条生产链。第一条先通过 intelligence prepare 得到 `route=general`,再以同一个 durable intent 提交原始输入;Oracle 要求 `session_intent` 为 `admitted/original/turn`、Session 中只有一条原始用户消息和一次真实 provider 执行。在 provider 仍为 busy 的窗口内,ACK 丢失后的 exact retry 不得增加用户消息,晚到的 rewritten 草稿必须以 `SessionPromptIntent.Conflict` 拒绝,不得排队或启动第二次执行。第二条对该消息执行生产 `SessionRevert`,要求 mutation epoch 精确递增一次,旧 intent retry 以 `SessionMutationEpoch.Stale` 拒绝,再以新 rewrite intent 完成一次真实 provider 执行;清理后的活动 transcript 只能保留一条 rewrite 用户消息,且不得残留旧回复、工具调用、权限请求或工作区改动。

该 EXT suite 只证明真实 refinement/provider 与 durable admission/revert 接线一致,不替代竞态正确性证明。并发 claim、事务原子性、ACK crash window、跨窗口相同 intent、revert 与 materialize 的交错顺序仍由 SQLite/Effect/前端 barrier 的确定性测试承担;不得用模型最终文本或单次 live 通过声称 exactly-once 状态机已经完备。

### 5.6 Expert Panel 与缓存边界

`expert-panel` 必须并行创建 correctness、security、architecture 三个 Reviewer Session。每个 Reviewer 只能成功读取自己的目标文件,必须经过独立的 structured finalizer,并由确定性 arbiter 重算最终 verdict 和 dissent。Oracle 要求每个 lens 至少有一条命中预埋代码事实且置信度为 `0.95` 的 finding;额外 finding 只要仍受目标文件、类别、证据隔离和置信度范围约束,就不应被误判为产品故障。模型对未授权路径的额外 read 尝试可以存在,但必须由权限层拒绝;任何额外成功读取或其他工具调用都应失败。

Expand Down
47 changes: 40 additions & 7 deletions packages/app/src/components/prompt-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ import { pathKey } from "@/utils/path-key"
import { base64Encode } from "@deepagent-code/core/util/encode"
import { displayName } from "@/pages/layout/helpers"

export type PromptInputControl = {
cancelPending: () => Promise<void>
}

interface PromptInputProps {
class?: string
variant?: "dock" | "new-session"
Expand All @@ -99,6 +103,8 @@ interface PromptInputProps {
onQueue?: (draft: FollowupDraft) => void
onAbort?: () => void
onSubmit?: () => void
disabled?: boolean
controlRef?: (control: PromptInputControl | undefined) => void
}

const EXAMPLES = [
Expand Down Expand Up @@ -220,14 +226,15 @@ export const PromptInput: Component<PromptInputProps> = (props) => {

const makeTextPrompt = (text: string): Prompt => [{ type: "text", content: text, start: 0, end: text.length }]

const finishDraftReview = (result: { editedGoal: string } | false) => {
const finishDraftReview = (result: { editedGoal: string } | false, restore = true) => {
const current = draftReview()
if (!current) return
setDraftReview(undefined)
const resolve = draftReviewResolve
draftReviewResolve = undefined
resolve?.(result)
if (result !== false) return
if (!restore) return

prompt.set(current.originalPrompt, current.originalCursor)
requestAnimationFrame(() => {
Expand Down Expand Up @@ -281,6 +288,13 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
if (!draftReview() && !draftPreparing()) draftPreparePrompt = undefined
}

const discardDraftPrepare = () => {
if (draftReview()) finishDraftReview(false, false)
setDraftPreparing(false)
setDraftPreview("")
draftPreparePrompt = undefined
}

// Copy the preserved partial draft into the editor so the user can edit and resubmit it. A canceled
// stream has no server-persisted draft id, so it can't be submitted as an intelligence draft directly.
const useDraftPreview = () => {
Expand Down Expand Up @@ -1295,7 +1309,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
})
})

const { abort, handleSubmit } = createPromptSubmit({
const { abort, cancelPending, handleSubmit } = createPromptSubmit({
info,
imageAttachments,
commentCount,
Expand All @@ -1320,10 +1334,24 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
onPromptPrepareStart: startDraftPrepare,
onPromptPrepareProgress: updateDraftPrepare,
onPromptPrepareEnd: stopDraftPrepare,
onPromptPrepareDiscard: discardDraftPrepare,
confirmPromptDraft,
})

const submitControl = {
cancelPending: async () => {
discardDraftPrepare()
await cancelPending()
},
}
props.controlRef?.(submitControl)
onCleanup(() => props.controlRef?.(undefined))

const handlePromptSubmit = (event: Event) => {
if (props.disabled) {
event.preventDefault()
return
}
// Read-only finished subagent: swallow the submit so no new turn is started.
if (subagentFinished()) {
event.preventDefault()
Expand All @@ -1349,6 +1377,11 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
}

const handleKeyDown = (event: KeyboardEvent) => {
if (props.disabled) {
event.preventDefault()
event.stopPropagation()
return
}
if (draftPreparing()) {
if (event.key === "Escape" || (event.ctrlKey && event.code === "KeyG")) void abort()
event.preventDefault()
Expand Down Expand Up @@ -1808,7 +1841,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<div
class="relative"
onMouseDown={(e) => {
if (draftPreparing()) return
if (draftPreparing() || props.disabled) return
const target = e.target
if (!(target instanceof HTMLElement)) return
if (
Expand All @@ -1835,8 +1868,8 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
role="textbox"
aria-multiline="true"
aria-label={placeholder()}
aria-disabled={draftPreparing()}
contenteditable={draftPreparing() ? "false" : "true"}
aria-disabled={draftPreparing() || props.disabled}
contenteditable={draftPreparing() || props.disabled ? "false" : "true"}
autocapitalize={store.mode === "normal" ? "sentences" : "off"}
autocorrect={store.mode === "normal" ? "on" : "off"}
spellcheck={store.mode === "normal"}
Expand All @@ -1857,7 +1890,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
"font-mono!": store.mode === "shell",
// Editor keeps the raw user input during preparation (the streamed draft shows in the
// panel below), so it reads normally — locked to edits, not greyed as a placeholder.
"cursor-wait": draftPreparing(),
"cursor-wait": draftPreparing() || props.disabled,
}}
style={{ "padding-bottom": space }}
/>
Expand Down Expand Up @@ -1900,7 +1933,7 @@ export const PromptInput: Component<PromptInputProps> = (props) => {
<IconButton
data-action="prompt-submit"
type="submit"
disabled={subagentFinished() || (!draftPreparing() && !working() && blank())}
disabled={props.disabled || subagentFinished() || (!draftPreparing() && !working() && blank())}
tabIndex={store.mode === "normal" ? undefined : -1}
icon={stopping() ? "stop" : store.mode === "shell" ? "arrow-undo-down" : "arrow-up"}
variant="primary"
Expand Down
Loading
Loading