@xmanrui/dsh-im 4.13.0 → 4.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -161,7 +161,20 @@ function normalizeDeliveryTargets(value, { version } = {}) {
161
161
  if (!targets || typeof targets !== 'object' || Array.isArray(targets)) return null;
162
162
  const normalizedTargets = Object.create(null);
163
163
  for (const [targetId, target] of Object.entries(targets)) {
164
- const normalized = normalizeDeliveryTarget(target, {
164
+ // Backward compatibility: some released builds persisted the target id
165
+ // inside the stored object as well. Accept a redundant targetId that
166
+ // matches the map key when loading a stored document; a mismatch stays
167
+ // invalid so a corrupted file still fails closed.
168
+ let candidate = target;
169
+ if (target && typeof target === 'object' && !Array.isArray(target)
170
+ && target.targetId !== undefined) {
171
+ if (target.targetId !== targetId) {
172
+ throw deliveryTargetError('invalid-target', 'Invalid target id');
173
+ }
174
+ const { targetId: _legacyTargetId, ...withoutLegacyId } = target;
175
+ candidate = withoutLegacyId;
176
+ }
177
+ const normalized = normalizeDeliveryTarget(candidate, {
165
178
  targetId,
166
179
  allowSessionSync: version >= CURRENT_DOCUMENT_VERSION,
167
180
  });
@@ -590,6 +590,9 @@ export class HarnessReplyTracker {
590
590
  const text = assistantMessageText(event);
591
591
  const step = Number.isSafeInteger(event.data?.step) ? event.data.step : null;
592
592
  this.#assistantText.setCanonical(step, text);
593
+ // canonical 定稿且非空时按 step 透出,供分步推送消费方使用;
594
+ // 先于 commitText 透出,保持 text 更新作为批次末尾的既有语义。
595
+ if (text) pushUpdate({ type: 'assistant-message', step, text });
593
596
  this.#commitText(this.#assistantText.text, pushUpdate);
594
597
  continue;
595
598
  }
@@ -600,7 +603,19 @@ export class HarnessReplyTracker {
600
603
  ?? nonEmptyText(event.data?.subCallId);
601
604
  if (callId) this.#toolNames.set(callId, name);
602
605
  this.#lastToolName = name;
603
- pushUpdate({ type: 'tool', name, ...(callId ? { callId } : {}) });
606
+ let argsText = null;
607
+ if (event.data?.arguments !== undefined && event.data?.arguments !== null) {
608
+ if (typeof event.data.arguments === 'string') {
609
+ argsText = event.data.arguments;
610
+ } else {
611
+ try {
612
+ argsText = JSON.stringify(event.data.arguments);
613
+ } catch {
614
+ argsText = undefined;
615
+ }
616
+ }
617
+ }
618
+ pushUpdate({ type: 'tool', name, ...(argsText ? { arguments: argsText } : {}), ...(callId ? { callId } : {}) });
604
619
  } else if (event.type === 'tool/result') {
605
620
  const callId = nonEmptyText(event.data?.message?.source?.callId)
606
621
  ?? nonEmptyText(event.data?.callId)
@@ -1562,7 +1577,11 @@ export class HarnessClient {
1562
1577
  lastPollSeq = tracker.lastSeq;
1563
1578
  if (seqAdvanced) lastProgressAt = Date.now();
1564
1579
  if (onUpdate) {
1565
- const visibleUpdates = progressMode === 'all' ? updates : updates.slice(-1);
1580
+ // latest 模式只投递一条最新进展;assistant-message 是分步推送专用更新,
1581
+ // 且 canonical 去重后可能成为批次唯一变化,绝不能冒充进度投给全部渠道。
1582
+ const visibleUpdates = progressMode === 'all'
1583
+ ? updates
1584
+ : updates.filter((update) => update.type !== 'assistant-message').slice(-1);
1566
1585
  for (const update of visibleUpdates) {
1567
1586
  try {
1568
1587
  await onUpdate(update);
@@ -373,4 +373,6 @@ export default {
373
373
  '已请求停止后台任务。': 'Requested to stop the background task.',
374
374
  '无法安全停止后台任务,请在 Harness 中查看并停止对应任务。': 'Unable to safely stop the background task. Please inspect and stop the matching task in Harness.',
375
375
  '任务失败': 'Failed',
376
+ // feishu/bridge.mjs — step push context injection
377
+ '📎 已注入会话上下文': '📎 Context injected',
376
378
  };
@@ -46,7 +46,9 @@ function artifactError(code, message) {
46
46
  }
47
47
 
48
48
  function currentTurn(agent) {
49
- const events = agent?.session?.events;
49
+ const events = typeof agent?.session?.snapshotEvents === 'function'
50
+ ? agent.session.snapshotEvents()
51
+ : agent?.session?.events;
50
52
  if (!Array.isArray(events)) return null;
51
53
  let turn = null;
52
54
  for (const event of events) {