mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
feat(web): merge compact status and summary cards
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/compact/command-compact/README.md
|
||||
README.md: a32a6aeb9957f0fd5f8cff58b1edbb9bc29a4e3d
|
||||
README.zh.md: c678f522115d9b0fd414b2f290b3cb54ce690722
|
||||
README.md: 54f341e39447a423964b7d7435cfb638857eda6e
|
||||
README.zh.md: d4a122b8a19cdf907212ad019b2528ae52d03886
|
||||
|
||||
@@ -12,7 +12,7 @@ Human-facing `/compact` control over [`ctx.compact`](../compact/README.md). The
|
||||
| `/compact` with no compactable history | `No compactable history yet.` — no marker or surface mutation is written. |
|
||||
| `/compact <anything>` | `Usage: /compact (no arguments)` — the command takes no arguments and calls no compaction backend. |
|
||||
|
||||
The command is backend-independent: it depends only on `compactNow(agent, signal)`. The invoking agent is the exact target, and the dispatching UI's cancellation signal is forwarded through the seam. Every resolved invocation records the executor-owned log-only pair `command/run` / `command/done`; neither event joins model history.
|
||||
The command is backend-independent: it depends only on `compactNow(agent, signal)`. The invoking agent is the exact target, and the dispatching UI's cancellation signal is forwarded through the seam. Every resolved invocation records the executor-owned log-only pair `command/run` / `command/done`; neither event joins model history. On success, `command/done.sourceEventSeq` names the transaction's `compact/summary` event so a presentation can fold the command lifecycle into its checkpoint without parsing result text or assuming adjacent rows.
|
||||
|
||||
Expected `ManualCompactionError` codes become stable direct errors:
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
| `/compact`,但没有可压缩历史 | `No compactable history yet.`:不会写入标记,也不会变更 surface。 |
|
||||
| `/compact <anything>` | `Usage: /compact (no arguments)`:该命令不接受参数,也不会调用压缩后端。 |
|
||||
|
||||
该命令与后端无关,只依赖 `compactNow(agent, signal)`。调用该命令的 agent(智能体)就是操作的确切目标,发起分发的 UI 会通过 seam 转发取消信号。每次完成的调用都会记录执行器所属的纯日志事件对 `command/run` / `command/done`;两者都不进入模型历史。
|
||||
该命令与后端无关,只依赖 `compactNow(agent, signal)`。调用该命令的 agent(智能体)就是操作的确切目标,发起分发的 UI 会通过 seam 转发取消信号。每次完成的调用都会记录执行器所属的纯日志事件对 `command/run` / `command/done`;两者都不进入模型历史。成功时,`command/done.sourceEventSeq` 会指明该事务的 `compact/summary` 事件,让呈现层无须解析结果文本或假定两行相邻,即可将命令生命周期归并到对应检查点中。
|
||||
|
||||
预期的 `ManualCompactionError` 代码会成为稳定的直接错误:
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ async function executeCompact(
|
||||
return {
|
||||
kind: 'success',
|
||||
text: `Compacted ${result.shadowedSeqs.length} history items (~${result.shadowedTokenCount} tokens).`,
|
||||
sourceEventSeq: result.summarySeq,
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
if (invocation.signal.aborted) return { kind: 'error', text: 'Compaction cancelled.' }
|
||||
|
||||
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import Loader from '@cordisjs/plugin-loader'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import CommandService from '@deepseek-ai/dsh-commands'
|
||||
import CommandService, { type CommandResult } from '@deepseek-ai/dsh-commands'
|
||||
import {
|
||||
CompactService,
|
||||
ManualCompactionError,
|
||||
@@ -15,9 +15,9 @@ import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
import * as commandCompact from '@deepseek-ai/dsh-command-compact'
|
||||
|
||||
const RESULT: CompactionResult = {
|
||||
startSeq: 10,
|
||||
summarySeq: 11,
|
||||
endSeq: 13,
|
||||
startSeq: 1,
|
||||
summarySeq: 2,
|
||||
endSeq: 3,
|
||||
summary: [{ type: 'text', text: 'summary' }],
|
||||
shadowedRange: { start: 1, end: 7 },
|
||||
shadowedSeqs: [1, 3, 7],
|
||||
@@ -49,10 +49,24 @@ class StubCompactService extends CompactService {
|
||||
this.calls.push({ agent, signal })
|
||||
if (this.operation !== undefined) return this.operation()
|
||||
return this.failure === undefined
|
||||
? Promise.resolve(this.result)
|
||||
? Promise.resolve(this.result === null ? null : this.appendResult(agent, this.result))
|
||||
// oxlint-disable-next-line typescript/prefer-promise-reject-errors -- exercise arbitrary backend rejection values.
|
||||
: Promise.reject(this.failure)
|
||||
}
|
||||
|
||||
private appendResult(agent: ManualCompactAgentContext, result: CompactionResult): CompactionResult {
|
||||
agent.session.append('compact/start', { turn: null })
|
||||
agent.session.append('compact/summary', {
|
||||
summary: result.summary,
|
||||
shadowedRange: result.shadowedRange,
|
||||
shadowedSeqs: result.shadowedSeqs,
|
||||
shadowedTokenCount: result.shadowedTokenCount,
|
||||
provider: 'command-test',
|
||||
model: 'command-test',
|
||||
})
|
||||
agent.session.append('compact/end', { turn: null })
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
interface Harness {
|
||||
@@ -91,9 +105,11 @@ async function run(
|
||||
function expectLastLifecycle(
|
||||
test: Harness,
|
||||
args: string,
|
||||
outcome: { readonly kind: 'success' | 'error'; readonly text?: string },
|
||||
outcome: CommandResult,
|
||||
): string {
|
||||
const lifecycle = test.agent.session.events.slice(-2)
|
||||
const lifecycle = test.agent.session.events
|
||||
.filter(event => event.type === 'command/run' || event.type === 'command/done')
|
||||
.slice(-2)
|
||||
const runEvent = lifecycle[0]
|
||||
const doneEvent = lifecycle[1]
|
||||
if (runEvent?.type !== 'command/run' || doneEvent?.type !== 'command/done') {
|
||||
@@ -149,6 +165,7 @@ describe('/compact human command', () => {
|
||||
expect(execution.result).toEqual({
|
||||
kind: 'success',
|
||||
text: 'Compacted 3 history items (~42 tokens).',
|
||||
sourceEventSeq: RESULT.summarySeq,
|
||||
})
|
||||
expect(execution.commandId).toBe(expectLastLifecycle(test, '', execution.result))
|
||||
expect(test.compact.calls).toEqual([{ agent: test.agent, signal: controller.signal }])
|
||||
|
||||
@@ -21,7 +21,7 @@ import { Session, SessionId } from '@deepseek-ai/dsh-session'
|
||||
const RESULT: CompactionResult = {
|
||||
startSeq: 1,
|
||||
summarySeq: 2,
|
||||
endSeq: 4,
|
||||
endSeq: 3,
|
||||
summary: [{ type: 'text', text: 'loader summary' }],
|
||||
shadowedRange: { start: 3, end: 8 },
|
||||
shadowedSeqs: [3, 5, 8],
|
||||
@@ -42,9 +42,19 @@ class LoaderCompactService extends CompactService {
|
||||
}
|
||||
|
||||
override compactNow(
|
||||
_agent: ManualCompactAgentContext,
|
||||
agent: ManualCompactAgentContext,
|
||||
_signal: AbortSignal,
|
||||
): Promise<CompactionResult | null> {
|
||||
agent.session.append('compact/start', { turn: null })
|
||||
agent.session.append('compact/summary', {
|
||||
summary: RESULT.summary,
|
||||
shadowedRange: RESULT.shadowedRange,
|
||||
shadowedSeqs: RESULT.shadowedSeqs,
|
||||
shadowedTokenCount: RESULT.shadowedTokenCount,
|
||||
provider: 'loader-test',
|
||||
model: 'loader-test',
|
||||
})
|
||||
agent.session.append('compact/end', { turn: null })
|
||||
return Promise.resolve(RESULT)
|
||||
}
|
||||
}
|
||||
@@ -108,6 +118,7 @@ describe('command-compact real Loader composition', () => {
|
||||
expect(execution.result).toEqual({
|
||||
kind: 'success',
|
||||
text: 'Compacted 3 history items (~99 tokens).',
|
||||
sourceEventSeq: RESULT.summarySeq,
|
||||
})
|
||||
expect(session.events.map(event => ({ type: event.type, data: event.data }))).toEqual([
|
||||
{
|
||||
@@ -119,12 +130,32 @@ describe('command-compact real Loader composition', () => {
|
||||
source: { kind: 'user' },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'compact/start',
|
||||
data: { turn: null },
|
||||
},
|
||||
{
|
||||
type: 'compact/summary',
|
||||
data: {
|
||||
summary: RESULT.summary,
|
||||
shadowedRange: RESULT.shadowedRange,
|
||||
shadowedSeqs: RESULT.shadowedSeqs,
|
||||
shadowedTokenCount: RESULT.shadowedTokenCount,
|
||||
provider: 'loader-test',
|
||||
model: 'loader-test',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'compact/end',
|
||||
data: { turn: null },
|
||||
},
|
||||
{
|
||||
type: 'command/done',
|
||||
data: {
|
||||
commandId: execution.commandId,
|
||||
kind: 'success',
|
||||
text: 'Compacted 3 history items (~99 tokens).',
|
||||
sourceEventSeq: RESULT.summarySeq,
|
||||
},
|
||||
},
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user