Files
OpenOPC/opc/plugins/office_ui/frontend_src/lib/progressLog.test.ts
T
LZH-YS1998 12817a4e60 fix(office-ui): native progress parity, ui_state lock hardening, approval-card idempotency
Native agent progress panel (company mode):
- ws_handler: filter runtime bookkeeping noise (turn/status/member_inbox_updated),
  keep tool_completed as tool_call, thinking summary previews content,
  preserve raw thinking_delta fragments (no strip; skip whitespace-only)
- frontend progressLog: summarize thinking by content preview; merge thinking
  by detail only so the 'Thinking' label never splices into text
- AgentProgressBlock: add bottom "Show more (N earlier steps)" toggle

ui_state.db "database is locked" hardening:
- ws_handler: isolate engine progress/kanban/runtime-event callbacks so UI
  persistence failures never crash work items
- chat_store: busy_timeout, _retry_locked backoff, idempotent insert_message
  (INSERT OR REPLACE), create_channel read-before-write to stop poll writes
- server: flock single-instance guard for `opc ui` per OPC home

Approval card duplicate-click bug:
- EscalationPanel: disable buttons on click with Submitting state and 30s
  reconnect fallback
- ws_handler: stale-escalation branch checks real card status (new
  chat_store.get_checkpoint_message); already-resolved cards get an accurate
  "already handled (decision: X)" reply without being re-marked stale;
  dedup identical helper messages within 120s to stop reply spam

Company mode prompt:
- add soft guidance that the runtime monitors state and re-activates roles,
  so leaders need not poll work items after delegation/review

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-07 16:18:01 +08:00

117 lines
2.7 KiB
TypeScript

import assert from 'node:assert/strict'
import { appendProgressEntry } from './progressLog'
let log = appendProgressEntry([], {
timestamp: 1,
type: 'thinking',
summary: 'Thinking',
detail: '我先',
turnId: 'rt-1:1',
itemId: 'rt-1:1:thinking',
seq: 1,
})
for (const [seq, detail] of [
[2, '先联网'],
[3, '联网抓'],
[4, '抓取'],
] as const) {
log = appendProgressEntry(log, {
timestamp: seq,
type: 'thinking',
summary: 'Thinking',
detail,
turnId: 'rt-1:1',
itemId: 'rt-1:1:thinking',
seq,
})
}
assert.equal(log.length, 1)
assert.equal(log[0]?.summary, '我先联网抓取')
assert.equal(log[0]?.detail, '我先联网抓取')
// Token-sized streaming fragments keep their whitespace when merged, and
// entries without detail never splice their summary label into the text.
let spacedLog = appendProgressEntry([], {
timestamp: 100,
type: 'thinking',
summary: 'The user',
detail: 'The user',
turnId: 'rt-2:1',
itemId: 'rt-2:1:thinking',
seq: 1,
})
spacedLog = appendProgressEntry(spacedLog, {
timestamp: 101,
type: 'thinking',
summary: 'wants to',
detail: ' wants to',
turnId: 'rt-2:1',
itemId: 'rt-2:1:thinking',
seq: 2,
})
spacedLog = appendProgressEntry(spacedLog, {
timestamp: 102,
type: 'thinking',
summary: 'Thinking',
turnId: 'rt-2:1',
itemId: 'rt-2:1:thinking',
seq: 3,
})
assert.equal(spacedLog.length, 1)
assert.equal(spacedLog[0]?.detail, 'The user wants to')
assert.equal(spacedLog[0]?.summary, 'The user wants to')
const unchanged = appendProgressEntry(log, {
timestamp: 5,
type: 'thinking',
summary: 'Thinking',
detail: '重复',
turnId: 'rt-1:1',
itemId: 'rt-1:1:thinking',
seq: 4,
})
assert.equal(unchanged[0]?.detail, '我先联网抓取')
let toolLog = appendProgressEntry([], {
timestamp: 10,
type: 'tool_call',
summary: 'web_search',
detail: '{"query":"weather"}',
turnId: 'rt-1:2',
toolCallId: 'call-1',
})
toolLog = appendProgressEntry(toolLog, {
timestamp: 11,
type: 'tool_call',
summary: 'web_search',
detail: 'completed',
turnId: 'rt-1:2',
toolCallId: 'call-1',
})
assert.equal(toolLog.length, 1)
assert.equal(toolLog[0]?.detail, '{"query":"weather"}\ncompleted')
let permissionLog = appendProgressEntry([], {
timestamp: 20,
type: 'autonomy',
summary: 'shell_exec: ask',
turnId: 'rt-1:3',
permissionGroupKey: 'tool:shell_exec/python:domain:example.com',
})
permissionLog = appendProgressEntry(permissionLog, {
timestamp: 21,
type: 'autonomy',
summary: 'shell_exec: allow',
turnId: 'rt-1:3',
permissionGroupKey: 'tool:shell_exec/python:domain:example.com',
})
assert.equal(permissionLog.length, 1)
assert.equal(permissionLog[0]?.summary, 'shell_exec: allow')