@dsh-enhanced/assistant-delivery 0.1.6 → 0.1.12

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.
Files changed (59) hide show
  1. package/README.md +106 -7
  2. package/cordis.patch.yml +1 -0
  3. package/lib/agent-runtime.d.ts +23 -2
  4. package/lib/agent-runtime.d.ts.map +1 -1
  5. package/lib/agent-runtime.js +317 -2
  6. package/lib/agent-runtime.js.map +1 -1
  7. package/lib/canonical.d.ts +11 -1
  8. package/lib/canonical.d.ts.map +1 -1
  9. package/lib/canonical.js +107 -0
  10. package/lib/canonical.js.map +1 -1
  11. package/lib/coordinator.d.ts +3 -1
  12. package/lib/coordinator.d.ts.map +1 -1
  13. package/lib/coordinator.js +49 -21
  14. package/lib/coordinator.js.map +1 -1
  15. package/lib/feedback-command.d.ts +60 -0
  16. package/lib/feedback-command.d.ts.map +1 -0
  17. package/lib/feedback-command.js +338 -0
  18. package/lib/feedback-command.js.map +1 -0
  19. package/lib/index.d.ts +4 -3
  20. package/lib/index.d.ts.map +1 -1
  21. package/lib/index.js +4 -3
  22. package/lib/index.js.map +1 -1
  23. package/lib/learning-command.d.ts +40 -0
  24. package/lib/learning-command.d.ts.map +1 -0
  25. package/lib/learning-command.js +57 -0
  26. package/lib/learning-command.js.map +1 -0
  27. package/lib/service.d.ts +149 -6
  28. package/lib/service.d.ts.map +1 -1
  29. package/lib/service.js +1945 -34
  30. package/lib/service.js.map +1 -1
  31. package/lib/session-commands.d.ts +14 -0
  32. package/lib/session-commands.d.ts.map +1 -1
  33. package/lib/session-commands.js +30 -0
  34. package/lib/session-commands.js.map +1 -1
  35. package/lib/sqlite.d.ts +1 -1
  36. package/lib/sqlite.d.ts.map +1 -1
  37. package/lib/sqlite.js +648 -20
  38. package/lib/sqlite.js.map +1 -1
  39. package/lib/store.d.ts +375 -3
  40. package/lib/store.d.ts.map +1 -1
  41. package/lib/store.js +2956 -74
  42. package/lib/store.js.map +1 -1
  43. package/lib/types.d.ts +407 -0
  44. package/lib/types.d.ts.map +1 -1
  45. package/lib/types.js +9 -1
  46. package/lib/types.js.map +1 -1
  47. package/lib/version.d.ts +1 -1
  48. package/lib/version.d.ts.map +1 -1
  49. package/lib/version.js +1 -1
  50. package/lib/version.js.map +1 -1
  51. package/lib/workflow-auto-producer.d.ts +37 -0
  52. package/lib/workflow-auto-producer.d.ts.map +1 -0
  53. package/lib/workflow-auto-producer.js +58 -0
  54. package/lib/workflow-auto-producer.js.map +1 -0
  55. package/lib/workflow-command.d.ts +16 -0
  56. package/lib/workflow-command.d.ts.map +1 -0
  57. package/lib/workflow-command.js +52 -0
  58. package/lib/workflow-command.js.map +1 -0
  59. package/package.json +23 -3
@@ -8,8 +8,11 @@ import { effectiveApprovalPolicy, setApprovalPolicy, } from '@deepseek-ai/dsh-us
8
8
  import { approvalReviewerOf, setApprovalReviewer, waitForApprovalReviewerSessionEventReady, } from '@dsh-enhanced/assistant-policy';
9
9
  import { resolveLlmRouteCapability } from '@dsh-enhanced/llm-route-capabilities';
10
10
  import { externalPrincipalId } from './canonical.js';
11
- import { isExactDeliveryCommand, parseDeliveryCommand, permissionDispatchRecoveryCode, } from './session-commands.js';
11
+ import { feedbackSignalInput, feedbackUsage, parseFeedbackCommand, } from './feedback-command.js';
12
+ import { learningCommandUsage, parseLearningCommand, serializeLearningExport, } from './learning-command.js';
13
+ import { isExactDeliveryCommand, learningDispatchRecoveryCode, parseDeliveryCommand, permissionDispatchRecoveryCode, } from './session-commands.js';
12
14
  import { DeliveryStoreError } from './store.js';
15
+ import { parseWorkflowCommand, workflowCommandUsage, } from './workflow-command.js';
13
16
  const SAFE_NATIVE_COMMANDS = new Set(['compact']);
14
17
  class UserSessionCancellation extends Error {
15
18
  command;
@@ -1636,6 +1639,304 @@ export class DshDeliveryRuntime {
1636
1639
  this.options.replyCommand(binding, envelope.eventId, reply);
1637
1640
  return { outcome: 'processed' };
1638
1641
  }
1642
+ async runFeedbackCommand(command, binding, envelope, signal, markDispatching) {
1643
+ const parsed = parseFeedbackCommand(command.rawInput);
1644
+ if (parsed.kind === 'invalid') {
1645
+ return this.replySessionCommand(binding, envelope, {
1646
+ text: feedbackUsage,
1647
+ format: 'plain',
1648
+ }, signal, markDispatching);
1649
+ }
1650
+ if ((envelope.attachments?.length ?? 0) > 0) {
1651
+ return this.replySessionCommand(binding, envelope, {
1652
+ text: '反馈命令不接受文件、图片或其他附件;本次反馈未记录。请只发送 /feedback 文字命令。',
1653
+ format: 'plain',
1654
+ }, signal, markDispatching);
1655
+ }
1656
+ let authorized;
1657
+ try {
1658
+ authorized = this.options.isOwnerFeedbackController(binding, envelope);
1659
+ }
1660
+ catch {
1661
+ return {
1662
+ outcome: 'not-processed',
1663
+ failureCode: 'feedback-authorization-check-failed',
1664
+ retryable: true,
1665
+ };
1666
+ }
1667
+ if (!authorized) {
1668
+ return this.replySessionCommand(binding, envelope, {
1669
+ text: '当前身份不能提交反馈;本次反馈未记录。',
1670
+ format: 'plain',
1671
+ }, signal, markDispatching);
1672
+ }
1673
+ if (markDispatching === undefined) {
1674
+ return { outcome: 'not-processed', failureCode: 'dispatch-gate-unavailable', retryable: true };
1675
+ }
1676
+ signal.throwIfAborted();
1677
+ markDispatching();
1678
+ signal.throwIfAborted();
1679
+ if (parsed.kind === 'objective') {
1680
+ const objective = await this.options.dispatchObjectiveFeedback(binding, envelope, parsed.objectiveStatus);
1681
+ signal.throwIfAborted();
1682
+ if (objective === 'unknown') {
1683
+ return {
1684
+ outcome: 'not-processed',
1685
+ failureCode: 'objective-feedback-state-unknown',
1686
+ retryable: true,
1687
+ };
1688
+ }
1689
+ if (objective === 'unavailable') {
1690
+ this.options.replyCommand(binding, envelope.eventId, {
1691
+ text: '评测服务尚未启用;本次任务结果未记录。请联系管理员启用成长组件。',
1692
+ format: 'plain',
1693
+ });
1694
+ return { outcome: 'processed' };
1695
+ }
1696
+ if (objective === 'invalid-target') {
1697
+ this.options.replyCommand(binding, envelope.eventId, {
1698
+ text: '任务结果未记录。请直接回复对应的自动化或普通 Agent 任务结果消息,并发送 /feedback achieved、partial 或 not-achieved。',
1699
+ format: 'plain',
1700
+ });
1701
+ return { outcome: 'processed' };
1702
+ }
1703
+ if (objective === 'conflict') {
1704
+ this.options.replyCommand(binding, envelope.eventId, {
1705
+ text: '该次任务已经记录了不同的任务结果;为避免重复计票,本次未覆盖原记录。',
1706
+ format: 'plain',
1707
+ });
1708
+ return { outcome: 'processed' };
1709
+ }
1710
+ this.options.replyCommand(binding, envelope.eventId, {
1711
+ text: `已把该次任务结果记录为 ${parsed.objectiveStatus};同一次任务只计一票。`,
1712
+ format: 'plain',
1713
+ });
1714
+ return { outcome: 'processed' };
1715
+ }
1716
+ // The dispatch fence proves the exact Inbox/binding snapshot. Recheck the
1717
+ // mutable owner and consume an audited preference-signal authorization
1718
+ // immediately before the authoritative sink receives the batch.
1719
+ let attestation;
1720
+ try {
1721
+ attestation = this.options.authorizeOwnerPreferenceFeedback(binding, envelope, parsed.selections);
1722
+ }
1723
+ catch {
1724
+ return {
1725
+ outcome: 'not-processed',
1726
+ failureCode: 'feedback-authorization-check-failed-after-dispatch',
1727
+ retryable: false,
1728
+ };
1729
+ }
1730
+ if (attestation === undefined) {
1731
+ return {
1732
+ outcome: 'not-processed',
1733
+ failureCode: 'feedback-authorization-revoked',
1734
+ retryable: false,
1735
+ };
1736
+ }
1737
+ const events = parsed.selections.map(selection => feedbackSignalInput(binding, envelope, selection, attestation));
1738
+ const result = await this.options.dispatchPreferenceFeedback(Object.freeze(events));
1739
+ signal.throwIfAborted();
1740
+ if (result === 'unknown') {
1741
+ // The Inbox remains the durable retry envelope. Both downstream ledgers
1742
+ // are idempotent, so a crash/ambiguous local call safely replays the exact
1743
+ // feedback event rather than acknowledging a signal that may be lost.
1744
+ return {
1745
+ outcome: 'not-processed',
1746
+ failureCode: 'preference-feedback-state-unknown',
1747
+ retryable: true,
1748
+ };
1749
+ }
1750
+ if (result === 'unavailable') {
1751
+ this.options.replyCommand(binding, envelope.eventId, {
1752
+ text: '偏好学习服务尚未启用;本次偏好反馈未记录。',
1753
+ format: 'plain',
1754
+ });
1755
+ return { outcome: 'processed' };
1756
+ }
1757
+ signal.throwIfAborted();
1758
+ this.options.replyCommand(binding, envelope.eventId, {
1759
+ text: parsed.selections.length === 1
1760
+ ? '已记录偏好反馈;它不会被当成任务成败。只作用于当前工作区与 preset。'
1761
+ : '已记录偏好反馈及对应的回复长度偏好;它们不会被当成任务成败。只作用于当前工作区与 preset。',
1762
+ format: 'plain',
1763
+ });
1764
+ return { outcome: 'processed' };
1765
+ }
1766
+ async runWorkflowCommand(command, binding, envelope, signal, markDispatching) {
1767
+ const parsed = parseWorkflowCommand(command.rawInput);
1768
+ if (parsed.kind === 'help' || parsed.kind === 'invalid') {
1769
+ return this.replySessionCommand(binding, envelope, {
1770
+ text: workflowCommandUsage,
1771
+ format: 'plain',
1772
+ }, signal, markDispatching);
1773
+ }
1774
+ if ((envelope.attachments?.length ?? 0) > 0) {
1775
+ return this.replySessionCommand(binding, envelope, {
1776
+ text: '工作流学习命令不接受附件;本次未记录。请只回复一条无附件的已完成任务结果。',
1777
+ format: 'plain',
1778
+ }, signal, markDispatching);
1779
+ }
1780
+ let authorized;
1781
+ try {
1782
+ authorized = this.options.isOwnerFeedbackController(binding, envelope);
1783
+ }
1784
+ catch {
1785
+ return { outcome: 'not-processed', failureCode: 'workflow-authorization-check-failed', retryable: true };
1786
+ }
1787
+ if (!authorized) {
1788
+ return this.replySessionCommand(binding, envelope, {
1789
+ text: '当前身份不是此会话的 owner;本次工作流学习未记录。',
1790
+ format: 'plain',
1791
+ }, signal, markDispatching);
1792
+ }
1793
+ if (markDispatching === undefined) {
1794
+ return { outcome: 'not-processed', failureCode: 'dispatch-gate-unavailable', retryable: true };
1795
+ }
1796
+ signal.throwIfAborted();
1797
+ markDispatching();
1798
+ signal.throwIfAborted();
1799
+ const outcome = await this.options.dispatchWorkflowCommand(binding, envelope, parsed);
1800
+ signal.throwIfAborted();
1801
+ if (outcome === 'unknown') {
1802
+ return { outcome: 'not-processed', failureCode: 'workflow-dispatch-recovery', retryable: true };
1803
+ }
1804
+ const text = outcome === 'recorded'
1805
+ ? parsed.kind === 'save'
1806
+ ? '已记录 owner 明确授权的工作流证据;它只会生成候选与审批,当前没有自动化被启用。'
1807
+ : '已撤回这条任务对应的工作流证据;若已有实验,成长组件会按证据撤回流程回滚。'
1808
+ : outcome === 'invalid-target'
1809
+ ? '工作流证据未记录。请直接回复同一会话中一条已完成、无附件的任务结果消息。'
1810
+ : outcome === 'conflict'
1811
+ ? '该工作流命令与已持久化记录冲突;本次没有覆盖原记录。'
1812
+ : '成长组件尚未启用;本次工作流证据未记录。';
1813
+ this.options.replyCommand(binding, envelope.eventId, { text, format: 'plain' });
1814
+ return { outcome: 'processed' };
1815
+ }
1816
+ async runLearningCommand(command, binding, envelope, signal, markDispatching) {
1817
+ const parsed = parseLearningCommand(command.rawInput);
1818
+ if (parsed.kind === 'help' || parsed.kind === 'invalid') {
1819
+ return this.replySessionCommand(binding, envelope, {
1820
+ text: learningCommandUsage,
1821
+ format: 'plain',
1822
+ }, signal, markDispatching);
1823
+ }
1824
+ if (parsed.kind === 'forget-prompt') {
1825
+ return this.replySessionCommand(binding, envelope, {
1826
+ text: '尚未删除任何学习记录。若确定永久删除当前工作区与 preset 的记录,请发送 /learning forget confirm。',
1827
+ format: 'plain',
1828
+ }, signal, markDispatching);
1829
+ }
1830
+ if ((envelope.attachments?.length ?? 0) > 0) {
1831
+ return this.replySessionCommand(binding, envelope, {
1832
+ text: '学习控制命令不接受附件;本次未执行。请只发送 /learning 文字命令。',
1833
+ format: 'plain',
1834
+ }, signal, markDispatching);
1835
+ }
1836
+ let authorized;
1837
+ try {
1838
+ authorized = this.options.isOwnerFeedbackController(binding, envelope);
1839
+ }
1840
+ catch {
1841
+ return { outcome: 'not-processed', failureCode: 'learning-authorization-check-failed', retryable: true };
1842
+ }
1843
+ if (!authorized) {
1844
+ return this.replySessionCommand(binding, envelope, {
1845
+ text: '当前身份不是此会话的 owner;本次学习控制未执行。',
1846
+ format: 'plain',
1847
+ }, signal, markDispatching);
1848
+ }
1849
+ if (markDispatching === undefined) {
1850
+ return { outcome: 'not-processed', failureCode: 'dispatch-gate-unavailable', retryable: true };
1851
+ }
1852
+ signal.throwIfAborted();
1853
+ markDispatching();
1854
+ signal.throwIfAborted();
1855
+ const action = parsed.kind === 'forget-confirm'
1856
+ ? 'forget'
1857
+ : parsed.kind === 'rollback-confirm' ? 'rollback' : parsed.kind;
1858
+ const result = await this.options.dispatchLearningCommand(binding, envelope, action, parsed.kind === 'rollback-confirm' ? parsed.preferenceKey : undefined);
1859
+ signal.throwIfAborted();
1860
+ if (result === 'unknown') {
1861
+ return { outcome: 'not-processed', failureCode: learningDispatchRecoveryCode, retryable: true };
1862
+ }
1863
+ if (result === 'unavailable') {
1864
+ this.options.replyCommand(binding, envelope.eventId, {
1865
+ text: '偏好学习服务尚未启用;本次学习控制未执行。',
1866
+ format: 'plain',
1867
+ });
1868
+ return { outcome: 'processed' };
1869
+ }
1870
+ if (result === 'forbidden' || result.outcome === 'stale') {
1871
+ this.options.replyCommand(binding, envelope.eventId, {
1872
+ text: result === 'forbidden'
1873
+ ? 'owner 或会话绑定已变化;本次学习控制未执行。'
1874
+ : '已有更新的学习控制,或 owner/会话绑定已经变化;本次学习控制未执行,也未覆盖当前状态。',
1875
+ format: 'plain',
1876
+ });
1877
+ return { outcome: 'processed' };
1878
+ }
1879
+ const state = result.state;
1880
+ const statusLines = [
1881
+ `组件状态:${state.administrativelyEnabled ? '已启用' : '已禁用'}`,
1882
+ `管理员开关:${state.administrativelyEnabled ? '已开启' : '已关闭'}`,
1883
+ `收集状态:${state.collectionMode === 'paused' ? '已暂停' : '运行中'}`,
1884
+ `owner 控制:${state.collectionMode === 'paused' ? '已暂停' : '未暂停'}`,
1885
+ `- 已保存信号:${state.signals}`,
1886
+ `- 已保存假设:${state.hypotheses}`,
1887
+ `- 已保存有效偏好:${state.storedActiveOverlays}`,
1888
+ `- 当前生效偏好:${state.effectiveActiveOverlays}`,
1889
+ `- 待观察假设:${state.shadowHypotheses}`,
1890
+ ];
1891
+ const text = result.action === 'status'
1892
+ ? statusLines.join('\n')
1893
+ : result.action === 'export'
1894
+ ? serializeLearningExport(result.exportDocument)
1895
+ : result.action === 'explain'
1896
+ ? result.explanation?.length
1897
+ ? [
1898
+ '当前 owner 与 lineage 的 T1 偏好摘要(不含原始内容):',
1899
+ ...result.explanation.map(item => [
1900
+ `- key=${item.key}`,
1901
+ ` value=${item.value}`,
1902
+ ` state=${item.state}`,
1903
+ ` version=${item.version}`,
1904
+ ` supportingSignals=${item.supportingSignals}`,
1905
+ ` contradictingSignals=${item.contradictingSignals}`,
1906
+ ` evidenceMass=${item.evidenceMass}`,
1907
+ ].join('\n')),
1908
+ ].join('\n')
1909
+ : '当前 owner 与 lineage 没有 T1 偏好摘要。'
1910
+ : result.action === 'pause'
1911
+ ? [state.administrativelyEnabled
1912
+ ? '已暂停当前工作区与 preset 的偏好学习。暂停期间不收集、不激活、也不注入偏好;已有记录保留。'
1913
+ : '已记录暂停状态;偏好学习组件当前由管理员禁用,重新启用后仍会保持暂停。',
1914
+ '', ...statusLines].join('\n')
1915
+ : result.action === 'resume'
1916
+ ? [state.administrativelyEnabled
1917
+ ? '已恢复当前工作区与 preset 的偏好学习;已有的有效偏好会重新生效。'
1918
+ : '已记录恢复状态;偏好学习组件当前仍由管理员禁用,只有管理员重新启用后偏好才会生效。',
1919
+ '', ...statusLines].join('\n')
1920
+ : result.action === 'rollback'
1921
+ ? [result.rolledBack
1922
+ ? `已回滚 ${parsed.kind === 'rollback-confirm' ? parsed.preferenceKey : '指定键'} 当前激活的偏好。`
1923
+ : `${parsed.kind === 'rollback-confirm' ? parsed.preferenceKey : '指定键'} 当前没有激活偏好;未修改偏好记录。`,
1924
+ state.administrativelyEnabled
1925
+ ? `owner 收集状态:${state.collectionMode === 'paused' ? '已暂停' : '运行中'}。`
1926
+ : '管理员开关:已禁用;即使 owner 处于运行状态,偏好仍不会收集或生效。',
1927
+ '',
1928
+ ...statusLines,
1929
+ ].join('\n')
1930
+ : [
1931
+ '已永久删除当前工作区与 preset 的偏好学习记录。',
1932
+ `- 删除信号:${result.deletedSignals ?? 0}`,
1933
+ `- 删除假设:${result.deletedHypotheses ?? 0}`,
1934
+ '',
1935
+ ...statusLines,
1936
+ ].join('\n');
1937
+ this.options.replyCommand(binding, envelope.eventId, { text, format: 'plain' });
1938
+ return { outcome: 'processed' };
1939
+ }
1639
1940
  sessionHelp(native) {
1640
1941
  const lines = [
1641
1942
  '会话命令:',
@@ -1644,6 +1945,8 @@ export class DshDeliveryRuntime {
1644
1945
  '- /status(/session):查看当前 session、上下文与模型。',
1645
1946
  '- /model:查看或切换模型;上下文保留。',
1646
1947
  '- /permission:查看或切换运行权限。',
1948
+ '- /feedback:提交结构化偏好;回复自动化结果可记录 achieved/partial/not-achieved;不进入模型。',
1949
+ '- /learning:查看、导出、暂停、恢复或清除当前 scope 的偏好学习;不进入模型。',
1647
1950
  '- /help:显示当前实际可用命令。',
1648
1951
  ];
1649
1952
  const visible = native.filter(command => SAFE_NATIVE_COMMANDS.has(command.name));
@@ -1873,6 +2176,15 @@ export class DshDeliveryRuntime {
1873
2176
  }
1874
2177
  }
1875
2178
  async processControlled(binding, envelope, signal, sessionCommand, prepared, markDispatching) {
2179
+ if (sessionCommand?.name === 'feedback') {
2180
+ return await this.runFeedbackCommand(sessionCommand, binding, envelope, signal, markDispatching);
2181
+ }
2182
+ if (sessionCommand?.name === 'workflow') {
2183
+ return await this.runWorkflowCommand(sessionCommand, binding, envelope, signal, markDispatching);
2184
+ }
2185
+ if (sessionCommand?.name === 'learning') {
2186
+ return await this.runLearningCommand(sessionCommand, binding, envelope, signal, markDispatching);
2187
+ }
1876
2188
  const permissions = permissionCommand(sessionCommand);
1877
2189
  if (permissions !== undefined) {
1878
2190
  if (markDispatching === undefined) {
@@ -2070,7 +2382,10 @@ export class DshDeliveryRuntime {
2070
2382
  // Agent answers are authored as Markdown (tables, bold, inline code), so request Markdown
2071
2383
  // rendering; sending them as plain text shows the raw `|---|` and `**` syntax to the user.
2072
2384
  if (output.text !== '') {
2073
- this.options.reply(agent, envelope.eventId, { text: output.text, format: 'markdown' });
2385
+ const learning = await this.options.replyCompletedPreferenceTurn(agent, binding, envelope, { text: output.text, format: 'markdown' });
2386
+ if (learning === 'unknown') {
2387
+ this.ctx.logger.warn('assistant-delivery: completed-turn preference projection is ambiguous');
2388
+ }
2074
2389
  }
2075
2390
  publishProgress({ kind: 'completed' });
2076
2391
  return { outcome: 'processed' };