agentworkshop 0.7.3 → 0.7.4

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 (127) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/_nuxt/B9Yie5HN.js +2 -0
  3. package/.output/public/_nuxt/CN7Zh8GQ.js +1 -0
  4. package/.output/public/_nuxt/CdSgfcYR.js +1 -0
  5. package/.output/public/_nuxt/CdfAP_IH2.js +1 -0
  6. package/.output/public/_nuxt/ChnfyQHz.js +1 -0
  7. package/.output/public/_nuxt/{BkKYf8xY.js → CyygA0q4.js} +4 -4
  8. package/.output/public/_nuxt/{Bz40vyZS.js → DFnGFEav.js} +7 -7
  9. package/.output/public/_nuxt/Xaf_HIR3.js +1 -0
  10. package/.output/public/_nuxt/ZugRk0CM2.js +4 -0
  11. package/.output/public/_nuxt/builds/latest.json +1 -1
  12. package/.output/public/_nuxt/builds/meta/55c10854-ee0e-4be4-924b-a1b0e100fe11.json +1 -0
  13. package/.output/public/_nuxt/{default.iGJy9dP-.css → default.D17kXlD6.css} +1 -1
  14. package/.output/public/_nuxt/monitor.CmwpEUCI.css +1 -0
  15. package/.output/public/_nuxt/yIKY_V1P.js +1 -0
  16. package/.output/server/chunks/_/nitro.mjs +1131 -920
  17. package/.output/server/chunks/_/nitro.mjs.map +1 -1
  18. package/.output/server/chunks/build/{TownView-BkHxMiwZ.mjs → TownView-Bl8Gkcxi.mjs} +3 -3
  19. package/.output/server/chunks/build/{TownView-BkHxMiwZ.mjs.map → TownView-Bl8Gkcxi.mjs.map} +1 -1
  20. package/.output/server/chunks/build/{_id_-Bna1_JuB.mjs → _id_-CWLFGZjV.mjs} +2 -2
  21. package/.output/server/chunks/build/{_id_-Bna1_JuB.mjs.map → _id_-CWLFGZjV.mjs.map} +1 -1
  22. package/.output/server/chunks/build/_id_-GnRJPykX.mjs +1 -1
  23. package/.output/server/chunks/build/{_wsId_-CzLDGT_V.mjs → _wsId_-BhQMjyHG.mjs} +3 -4
  24. package/.output/server/chunks/build/{_wsId_-CzLDGT_V.mjs.map → _wsId_-BhQMjyHG.mjs.map} +1 -1
  25. package/.output/server/chunks/build/{daq-CmeM4u5u.mjs → daq-BOgpn9sl.mjs} +4 -5
  26. package/.output/server/chunks/build/daq-BOgpn9sl.mjs.map +1 -0
  27. package/.output/server/chunks/build/dcw-BTM5YU-B.mjs +1 -1
  28. package/.output/server/chunks/build/{default-Dt6xLdpd.mjs → default-CKJWhkot.mjs} +60 -17
  29. package/.output/server/chunks/build/{default-Dt6xLdpd.mjs.map → default-CKJWhkot.mjs.map} +1 -1
  30. package/.output/server/chunks/build/{logs-CUQt1z7D.mjs → logs-Dyk0I2I9.mjs} +3 -4
  31. package/.output/server/chunks/build/logs-Dyk0I2I9.mjs.map +1 -0
  32. package/.output/server/chunks/build/{monitor-yNoV98rf.mjs → monitor-KW8WLOJd.mjs} +34 -33
  33. package/.output/server/chunks/build/{monitor-yNoV98rf.mjs.map → monitor-KW8WLOJd.mjs.map} +1 -1
  34. package/.output/server/chunks/build/{town-BN4vQPb8.mjs → town-_4tEEEVW.mjs} +3 -4
  35. package/.output/server/chunks/build/town-_4tEEEVW.mjs.map +1 -0
  36. package/.output/server/chunks/build/useDaqStream-hwkhJHFU.mjs +1 -1
  37. package/.output/server/chunks/build/useDcwStream-Bdew_yrr.mjs +1 -1
  38. package/.output/server/chunks/build/{useWorkshopWs-xcdeiSmJ.mjs → useWorkshopWs-B3j5wIAK.mjs} +177 -3
  39. package/.output/server/chunks/build/useWorkshopWs-B3j5wIAK.mjs.map +1 -0
  40. package/.output/server/chunks/build/{workshop-CLhwe5eo.mjs → workshop-k0XZTFKg.mjs} +2 -3
  41. package/.output/server/chunks/build/workshop-k0XZTFKg.mjs.map +1 -0
  42. package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
  43. package/.output/server/chunks/routes/api/workshop/channels.post.mjs +1 -1
  44. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +32 -0
  45. package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs.map +1 -0
  46. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +56 -0
  47. package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs.map +1 -0
  48. package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
  49. package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
  50. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
  51. package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
  52. package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
  53. package/.output/server/chunks/routes/renderer.mjs +2 -2
  54. package/.output/server/chunks/virtual/entry.mjs +17 -11
  55. package/.output/server/chunks/virtual/precomputed.mjs +1 -1
  56. package/.output/server/package.json +1 -1
  57. package/README.md +435 -434
  58. package/app/components/AppHeader.vue +138 -0
  59. package/app/composables/workshop/useWorkshopWs.ts +4 -0
  60. package/app/pages/monitor.vue +17 -1
  61. package/app/stores/workshop/hitl.ts +80 -0
  62. package/bin/aw.mjs +0 -0
  63. package/cli/commands/tui.mjs +19 -0
  64. package/config.yml +134 -134
  65. package/docs/tui.md +43 -0
  66. package/i18n/locales/en.ts +3 -0
  67. package/i18n/locales/zh-CN.ts +3 -0
  68. package/package.json +140 -144
  69. package/scripts/_spike-pitui.mjs +116 -0
  70. package/scripts/e2e-hitl-live.mjs +323 -0
  71. package/scripts/e2e-line-live.mjs +144 -0
  72. package/scripts/test-hitl-registry.ts +112 -0
  73. package/scripts/test-tui-commands.mjs +131 -0
  74. package/scripts/test-tui-reducers.mjs +72 -0
  75. package/scripts/tsconfig.json +14 -0
  76. package/scripts/tui-smoke.mjs +91 -0
  77. package/server/api/workshop/hitl/pending.get.ts +28 -0
  78. package/server/api/workshop/hitl/respond.post.ts +67 -0
  79. package/server/api/workshop/ws.ts +30 -1
  80. package/server/data/daqs.json +39 -17
  81. package/server/data/dcw-lines.json +14 -0
  82. package/server/data/dcw-products.json +35 -0
  83. package/server/data/dcw-recipes.json +140 -0
  84. package/server/data/dcw-rollback.json +111 -1
  85. package/server/data/dcw-runs.json +135 -90
  86. package/server/data/dcw-writes.json +120 -0
  87. package/server/data/dcws.json +400 -275
  88. package/server/data/line-runs.json +11 -1
  89. package/server/plugins/workshop.ts +7 -0
  90. package/server/services/workshop/agents/harness-terminal.ts +92 -25
  91. package/server/services/workshop/agents/hitl-registry.ts +181 -0
  92. package/server/services/workshop/agents/tool-approvals.ts +15 -0
  93. package/server/services/workshop/scene-events.ts +19 -9
  94. package/shared/workshop-protocol.ts +37 -0
  95. package/tui/README.md +65 -0
  96. package/tui/aw-tui.mjs +356 -0
  97. package/tui/commands/index.mjs +250 -0
  98. package/tui/components/chat-log.mjs +42 -0
  99. package/tui/components/hitl-card.mjs +36 -0
  100. package/tui/components/monitor-pane.mjs +39 -0
  101. package/tui/components/root.mjs +53 -0
  102. package/tui/components/status-bar.mjs +29 -0
  103. package/tui/lib/api.mjs +82 -0
  104. package/tui/lib/config.mjs +58 -0
  105. package/tui/lib/reducers.mjs +218 -0
  106. package/tui/lib/state.mjs +80 -0
  107. package/tui/lib/virtual-terminal.mjs +48 -0
  108. package/tui/lib/ws.mjs +124 -0
  109. package/tui/theme.mjs +38 -0
  110. package/.output/public/_nuxt/B7V9IfTL.js +0 -1
  111. package/.output/public/_nuxt/BE5QyG5J2.js +0 -1
  112. package/.output/public/_nuxt/BuKI8z-5.js +0 -1
  113. package/.output/public/_nuxt/D0C5Q0di.js +0 -1
  114. package/.output/public/_nuxt/DC-QMEk1.js +0 -2
  115. package/.output/public/_nuxt/DEkQ0qQ02.js +0 -1
  116. package/.output/public/_nuxt/builds/meta/c6c01cdd-762e-4fb8-86e7-753c5185b856.json +0 -1
  117. package/.output/public/_nuxt/dt2tKE95.js +0 -4
  118. package/.output/public/_nuxt/i_MKObHo.js +0 -1
  119. package/.output/public/_nuxt/monitor.41fCD6TB.css +0 -1
  120. package/.output/public/_nuxt/tpDMVY5w.js +0 -1
  121. package/.output/server/chunks/build/connection-Dc0fn6yd.mjs +0 -120
  122. package/.output/server/chunks/build/connection-Dc0fn6yd.mjs.map +0 -1
  123. package/.output/server/chunks/build/daq-CmeM4u5u.mjs.map +0 -1
  124. package/.output/server/chunks/build/logs-CUQt1z7D.mjs.map +0 -1
  125. package/.output/server/chunks/build/town-BN4vQPb8.mjs.map +0 -1
  126. package/.output/server/chunks/build/useWorkshopWs-xcdeiSmJ.mjs.map +0 -1
  127. package/.output/server/chunks/build/workshop-CLhwe5eo.mjs.map +0 -1
@@ -1,7 +1,10 @@
1
1
  <script setup lang="ts">
2
2
  import type { MenuProps, SelectProps } from 'ant-design-vue'
3
+ import type { AepHitlItem } from '#shared/workshop-protocol'
3
4
  import { useUserStore } from '@/app/stores/workshop/user'
4
5
  import { useWsConnectionStore } from '@/app/stores/workshop/connection'
6
+ import { useHitlStore } from '@/app/stores/workshop/hitl'
7
+ import { useWorkshopWs } from '@/app/composables/workshop/useWorkshopWs'
5
8
 
6
9
  const { t, locale, locales, setLocale } = useI18n()
7
10
  const store = useAppStore()
@@ -10,6 +13,26 @@ const trail = useRouteTrailStore()
10
13
  const userStore = useUserStore()
11
14
  const { metaFor } = useRouteMeta()
12
15
 
16
+ // ── HITL 全局待办(omp ask 对话框 + dcw 审批统一徽标;页头保底建连 ——
17
+ // hitl 全员直推帧只达已连 peer,不建连的页面收不到提醒;快照兜底刷新前待办) ──
18
+ const hitl = useHitlStore()
19
+ const wsSession = useWorkshopWs()
20
+ const ensureHitlLive = () => {
21
+ if (userStore.isLoggedIn) wsSession.ensureConnected()
22
+ }
23
+ watch(() => userStore.token, (t2) => {
24
+ if (t2) {
25
+ ensureHitlLive()
26
+ void hitl.loadSnapshot()
27
+ }
28
+ else hitl.clear()
29
+ }, { immediate: true })
30
+ const hitlKindLabel = (kind: AepHitlItem['kind']) =>
31
+ kind === 'omp-dialog' ? t('appHeader.hitlKindOmp') : t('appHeader.hitlKindDcw')
32
+ const hitlGo = (item: AepHitlItem) => {
33
+ navigateTo({ path: '/monitor', query: { agentId: item.agentId, channelId: item.channelId } })
34
+ }
35
+
13
36
  const localeOptions = computed(() =>
14
37
  (locales.value as Array<{ code: string, name: string }>).map(l => ({
15
38
  label: l.name,
@@ -205,6 +228,40 @@ const onAvatarMenu: MenuProps['onClick'] = async ({ key }) => {
205
228
 
206
229
  <!-- 右侧:功能集群 -->
207
230
  <div class="header-right">
231
+ <!-- HITL 待办铃标(有待办才出现;点击下拉 → 进入对应 agent 终端处理) -->
232
+ <ClientOnly>
233
+ <a-dropdown
234
+ v-if="hitl.count > 0"
235
+ placement="bottomRight"
236
+ >
237
+ <button
238
+ class="icon-btn hitl-bell"
239
+ :title="t('appHeader.hitlBadge')"
240
+ >
241
+ <span class="i-tabler-bell-ringing" />
242
+ <span class="hitl-count">{{ hitl.count }}</span>
243
+ </button>
244
+ <template #overlay>
245
+ <div class="hitl-menu">
246
+ <div class="hitl-menu-title">
247
+ {{ t('appHeader.hitlBadge') }} · {{ hitl.count }}
248
+ </div>
249
+ <button
250
+ v-for="item in hitl.items"
251
+ :key="`${item.kind}:${item.id}`"
252
+ class="hitl-item"
253
+ @click="hitlGo(item)"
254
+ >
255
+ <span class="hitl-item-top">
256
+ <span class="hitl-item-agent">{{ item.agentName }}</span>
257
+ <span class="hitl-item-kind">{{ hitlKindLabel(item.kind) }}</span>
258
+ </span>
259
+ <span class="hitl-item-title">{{ item.title }}</span>
260
+ </button>
261
+ </div>
262
+ </template>
263
+ </a-dropdown>
264
+ </ClientOnly>
208
265
  <!-- 实时连接状态点(WS 会话全局单例;未用过 WS 的会话不显示) -->
209
266
  <span
210
267
  v-if="wsVisible"
@@ -660,6 +717,87 @@ const onAvatarMenu: MenuProps['onClick'] = async ({ key }) => {
660
717
  50% { opacity: 0.45; }
661
718
  }
662
719
 
720
+ /* ── HITL 待办铃标(琥珀警示;角标数字极简,无装饰堆砌) ── */
721
+ .hitl-bell {
722
+ position: relative;
723
+ color: var(--tone-warning-dot, #d4a017);
724
+ }
725
+ .hitl-count {
726
+ position: absolute;
727
+ top: 2px;
728
+ right: 2px;
729
+ min-width: 15px;
730
+ height: 15px;
731
+ padding: 0 4px;
732
+ font-family: var(--font-mono);
733
+ font-size: 9.5px;
734
+ font-weight: 700;
735
+ line-height: 15px;
736
+ color: var(--on-accent, #fff);
737
+ text-align: center;
738
+ background: var(--tone-danger-dot, #e05252);
739
+ border-radius: 8px;
740
+ }
741
+ .hitl-menu {
742
+ min-width: 260px;
743
+ max-width: 340px;
744
+ padding: 6px;
745
+ background: var(--paper, #fff);
746
+ border: 1px solid var(--line);
747
+ border-radius: var(--radius-panel-sm, 10px);
748
+ box-shadow: 0 10px 32px rgba(0, 0, 0, 0.14);
749
+ }
750
+ .hitl-menu-title {
751
+ padding: 6px 10px;
752
+ font-size: 11px;
753
+ font-weight: 600;
754
+ letter-spacing: 0.08em;
755
+ color: var(--ink-faint);
756
+ border-bottom: 1px solid var(--line);
757
+ }
758
+ .hitl-item {
759
+ display: flex;
760
+ flex-direction: column;
761
+ gap: 3px;
762
+ width: 100%;
763
+ margin-top: 4px;
764
+ padding: 8px 10px;
765
+ text-align: left;
766
+ cursor: pointer;
767
+ background: transparent;
768
+ border: 1px solid transparent;
769
+ border-radius: var(--radius-panel-sm, 8px);
770
+ transition: background var(--transition-fast), border-color var(--transition-fast);
771
+ }
772
+ .hitl-item:hover {
773
+ background: var(--paper-deep);
774
+ border-color: var(--line);
775
+ }
776
+ .hitl-item-top {
777
+ display: flex;
778
+ gap: 8px;
779
+ align-items: baseline;
780
+ justify-content: space-between;
781
+ }
782
+ .hitl-item-agent {
783
+ font-size: 12.5px;
784
+ font-weight: 600;
785
+ color: var(--ink);
786
+ }
787
+ .hitl-item-kind {
788
+ font-family: var(--font-mono);
789
+ font-size: 9.5px;
790
+ letter-spacing: 0.1em;
791
+ color: var(--tone-warning-dot, #d4a017);
792
+ }
793
+ .hitl-item-title {
794
+ overflow: hidden;
795
+ font-size: 12px;
796
+ color: var(--ink-soft);
797
+ text-overflow: ellipsis;
798
+ white-space: nowrap;
799
+ }
800
+
663
801
  @media (prefers-reduced-motion: reduce) {
664
802
  .plotter-line.run {
665
803
  animation: none;
@@ -8,6 +8,7 @@ import { useUserStore } from '../../stores/workshop/user'
8
8
  import { WorkshopWsSession, useWsConnectionStore } from '../../stores/workshop/connection'
9
9
  import { useEventsStore } from '../../stores/workshop/events'
10
10
  import { useEntitiesStore } from '../../stores/workshop/entities'
11
+ import { useHitlStore } from '../../stores/workshop/hitl'
11
12
  import { useTownBus } from './useTownBus'
12
13
  import type { AepEnvelope, AepSnapshot } from '#shared/workshop-protocol'
13
14
 
@@ -16,6 +17,7 @@ export function useWorkshopWs() {
16
17
  const userStore = useUserStore()
17
18
  const events = useEventsStore()
18
19
  const entities = useEntitiesStore()
20
+ const hitl = useHitlStore()
19
21
  const townBus = useTownBus()
20
22
 
21
23
  // 模块级单例:多组件共享一条连接
@@ -48,6 +50,8 @@ export function useWorkshopWs() {
48
50
  events.ingest(e)
49
51
  entities.applyEvent(e)
50
52
  }
53
+ // HITL 全局待办(频道帧 + channelId='' 全员直推各到一次,store 内 kind+id 幂等)
54
+ if (e.type === 'hitl.request' || e.type === 'hitl.resolved') hitl.applyEnvelope(e)
51
55
  if (typeof e.seq === 'number' && e.seq > 0 && e.channelId) {
52
56
  conn.cursors[e.channelId] = e.seq
53
57
  s.updateCursor(e.channelId, e.seq) // 推进重连续传游标
@@ -67,6 +67,7 @@ interface MonitorSnapshot {
67
67
  interface ApiEnvelope<T> { code: number | string, message: string, data: T | null }
68
68
 
69
69
  const { t } = useI18n()
70
+ const route = useRoute()
70
71
  const userStore = useUserStore()
71
72
  const isAdmin = computed(() => userStore.isAdmin)
72
73
 
@@ -112,7 +113,9 @@ watch(() => userStore.token, () => {
112
113
  })
113
114
 
114
115
  onMounted(() => {
115
- if (userStore.token) void poll()
116
+ if (userStore.token) {
117
+ void poll().then(() => openFromQuery())
118
+ }
116
119
  applyTimer()
117
120
  })
118
121
  onBeforeUnmount(() => {
@@ -169,6 +172,19 @@ const openTerminal = (pid: number, name: string | null, role: string | null): vo
169
172
  terminalOpen.value = true
170
173
  }
171
174
 
175
+ // HITL 徽标跳转定位:?agentId=&channelId= → 自动打开该 agent 的终端面板(omp 未
176
+ // spawn 时无进程行,保持关闭;用后即清 query,刷新/再进不重复弹开)
177
+ const openFromQuery = (): void => {
178
+ const agentId = route.query.agentId
179
+ if (typeof agentId !== 'string' || !agentId) return
180
+ const channelId = typeof route.query.channelId === 'string' ? route.query.channelId : ''
181
+ const proc = snapshot.value?.processes.find(p => p.agentId === agentId && (!channelId || p.channelId === channelId))
182
+ if (proc?.pid) {
183
+ openTerminal(proc.pid, proc.name, proc.role)
184
+ void navigateTo({ path: '/monitor' }, { replace: true })
185
+ }
186
+ }
187
+
172
188
  // ===== 展示辅助 =====
173
189
  const shortId = (id: string | null | undefined): string => (id && id.length > 8 ? `${id.slice(0, 8)}…` : (id ?? '-'))
174
190
  const stateColor: Record<string, string> = { idle: 'success', busy: 'processing', stopped: 'error' }
@@ -0,0 +1,80 @@
1
+ /**
2
+ * HITL 全局待办 store:omp ask 对话框 + dcw 工具审批的统一待答视图。
3
+ *
4
+ * 数据源:
5
+ * - AEP hitl.request/hitl.resolved 帧(频道流 seq 帧与 channelId='' 全员直推
6
+ * 会各到一次,upsert 按 kind+id 幂等去重;徽标不依赖 channel 订阅)
7
+ * - GET /api/workshop/hitl/pending 快照(页面挂载/重连后的基线对齐)
8
+ */
9
+ import { defineStore } from 'pinia'
10
+ import type { AepEnvelope, AepHitlItem } from '#shared/workshop-protocol'
11
+ import { useUserStore } from './user'
12
+
13
+ const keyOf = (i: Pick<AepHitlItem, 'kind' | 'id'>) => `${i.kind}:${i.id}`
14
+
15
+ interface HitlPendingRes {
16
+ code: number | string
17
+ data?: { items: AepHitlItem[] }
18
+ }
19
+
20
+ export const useHitlStore = defineStore('workshop.hitl', {
21
+ state: () => ({
22
+ /** 当前待人工处理条目(kind+id 幂等) */
23
+ items: [] as AepHitlItem[],
24
+ /** 快照已加载(防重复拉取;WS 掉线重连后由 ensureBaseline 重置) */
25
+ snapshotLoaded: false,
26
+ }),
27
+ getters: {
28
+ count: state => state.items.length,
29
+ /** 按 agent 分组(徽标下拉/跳转用) */
30
+ byAgent: (state) => {
31
+ const map = new Map<string, AepHitlItem[]>()
32
+ for (const i of state.items) {
33
+ const list = map.get(i.agentId) ?? []
34
+ list.push(i)
35
+ map.set(i.agentId, list)
36
+ }
37
+ return map
38
+ },
39
+ },
40
+ actions: {
41
+ /** AEP 帧消费(hitl.request / hitl.resolved;幂等 upsert/remove) */
42
+ applyEnvelope(e: AepEnvelope): void {
43
+ if (e.type === 'hitl.request') {
44
+ const item = e.payload as AepHitlItem
45
+ const key = keyOf(item)
46
+ const idx = this.items.findIndex(i => keyOf(i) === key)
47
+ if (idx >= 0) this.items[idx] = item
48
+ else this.items.push(item)
49
+ }
50
+ else if (e.type === 'hitl.resolved') {
51
+ const r = e.payload as { kind: AepHitlItem['kind'], id: string }
52
+ this.items = this.items.filter(i => keyOf(i) !== keyOf(r))
53
+ }
54
+ },
55
+ /** 快照对齐(挂载/重连;替换式 —— 以 REST 为准收敛 WS 期间的可能漂移) */
56
+ async loadSnapshot(): Promise<void> {
57
+ if (typeof window === 'undefined') return
58
+ const token = useUserStore().token
59
+ if (!token) return
60
+ try {
61
+ const res = await $fetch<HitlPendingRes>('/api/workshop/hitl/pending', {
62
+ headers: { authorization: `Bearer ${token}` },
63
+ })
64
+ if (res.code === 0 && res.data) {
65
+ this.items = res.data.items
66
+ this.snapshotLoaded = true
67
+ }
68
+ }
69
+ catch { /* 快照失败不阻塞实时帧 */ }
70
+ },
71
+ /** WS 断线重连后重新对齐 */
72
+ invalidate(): void {
73
+ this.snapshotLoaded = false
74
+ },
75
+ clear(): void {
76
+ this.items = []
77
+ this.snapshotLoaded = false
78
+ },
79
+ },
80
+ })
package/bin/aw.mjs CHANGED
File without changes
@@ -0,0 +1,19 @@
1
+ // ============================================================
2
+ // 指令:tui —— 终端工作台(与 AgentTeam 交互作业;实现在 tui/)。
3
+ // 用法:aw tui [--url http://127.0.0.1:3000] [--token ut-*] [--channel <名>]
4
+ // ============================================================
5
+
6
+ export const meta = {
7
+ name: 'tui',
8
+ aliases: ['tui'],
9
+ group: '交互',
10
+ summary: '终端工作台 TUI:频道管理/发任务/实时监控/HITL 作答',
11
+ usage: 'aw tui [--url <baseUrl>] [--token <ut-*>] [--channel <名>]',
12
+ needsProject: false,
13
+ }
14
+
15
+ export async function run(argv) {
16
+ const { main } = await import('../../tui/aw-tui.mjs')
17
+ await main(argv)
18
+ return 0
19
+ }
package/config.yml CHANGED
@@ -1,134 +1,134 @@
1
- # ============================================================
2
- # AgentWorkShop 运行配置 —— 单一事实来源(Single Source of Truth)
3
- # ------------------------------------------------------------
4
- # 本文件由 nuxt.config.ts(构建/开发期)与 scripts/start.mjs(生产启动期)
5
- # 读取并解析,驱动整个运行时。修改后重启对应模式即可生效:
6
- # 开发:pnpm dev -> 读取 server.dev
7
- # 生产:pnpm start -> 读取 server.prod
8
- # ============================================================
9
-
10
- app:
11
- name: AgentWorkShop
12
- title: AgentWorkShop
13
- version: 0.7.3
14
- description: 基于 Nuxt 4 的配置驱动运行范式
15
-
16
- # 运行模式(dev/prod 实际由启动命令决定,此处仅作运行时展示)
17
- mode: dev
18
-
19
- # ------------------------------------------------------------
20
- # 服务端口:dev 与 prod 可分别自定义
21
- # ------------------------------------------------------------
22
- server:
23
- host: 0.0.0.0
24
- dev:
25
- port: 3000
26
- prod:
27
- port: 3001
28
-
29
- # 后端 API(前端 axios 基址 + 服务端行为均由本段驱动)
30
- api:
31
- baseURL: /api
32
- timeout: 15000
33
- pageSize: 20 # 服务端默认分页大小
34
- maxPageSize: 100 # 服务端分页大小上限
35
-
36
- # 国际化
37
- i18n:
38
- defaultLocale: zh-CN
39
- locales:
40
- - code: zh-CN
41
- name: 简体中文
42
- - code: en
43
- name: English
44
-
45
- # 主题
46
- theme:
47
- # Agent Harness · Digital Twin 控制室色板:品牌绿(交互/确认/DAQ)+ 数据青,见 TownView.vue --hud-*
48
- primaryColor: "#35e0a0"
49
- mode: light # light | dark
50
-
51
- # 安全配置
52
- # 数据采集基础设施(数采 DAQ;地址与 docker-compose.yml 默认一致)
53
- # startInfrastructure: never=启动探测,不通且有 Docker 则自动 docker compose 拉起;
54
- # always=仅 Docker 拉起;never=只直连。连接失败降级并警告,可前端一键重连。
55
- daq:
56
- startInfrastructure: auto
57
- mqtt:
58
- host: 127.0.0.1
59
- port: 1883
60
- timescale:
61
- host: 127.0.0.1
62
- port: 5432
63
- user: postgres
64
- password: awshop
65
- database: awshop
66
- # 对象存储(图像帧;MinIO,S3 兼容)。不可达时自动降级本地磁盘 data/daq-objects/,采集不中断。
67
- objectstore:
68
- host: 127.0.0.1
69
- port: 9000
70
- accessKey: awshop
71
- secretKey: awshop-secret
72
- bucket: daq
73
-
74
- security:
75
- # Session cookie 加密密钥(nuxt-auth-utils 使用)
76
- # 生产环境必须修改为强随机值;可用环境变量 NUXT_SESSION_PASSWORD 覆盖
77
- sessionPassword: awshop-dev-secret-change-me-0123456789
78
- # HITL 审批超时窗 ms(超时默认拒绝;env HITL_TIMEOUT_MS 兼容)
79
- # hitl_timeout_ms: 180000
80
-
81
- # ------------------------------------------------------------
82
- # 以下运行语义组:全部键均可被 env AW_<键>(点转下划线)或历史别名覆盖,
83
- # 优先级 config.yml < data/runtime-settings.json < 环境变量。缺省即用默认。
84
- # ------------------------------------------------------------
85
-
86
- # Agent 记忆系统(env AW_MEMORY_*)
87
- memory:
88
- primer_tokens: 300 # 记忆引子 token 预算(AW_MEMORY_PRIMER_TOKENS)
89
- inject_total: 500 # 单次注入总硬顶(AW_MEMORY_INJECT_TOTAL)
90
- maintenance_ms: 21600000 # 维护调度周期(AW_MEMORY_MAINTENANCE_MS)
91
- expire_days: 180 # 情景记忆保留天数(AW_MEMORY_EXPIRE_DAYS)
92
- expire_session_days: 14 # 会话记忆保留天数(AW_MEMORY_EXPIRE_SESSION_DAYS)
93
- cap: 500 # 条目驱逐上限(AW_MEMORY_CAP)
94
- reflect_trigger: 8 # 空闲反思触发阈值(AW_MEMORY_REFLECT_TRIGGER)
95
- embed_base_url: '' # OpenAI 兼容 /embeddings 基址(AW_MEMORY_EMBED_BASE_URL;空=纯 FTS)
96
- embed_model: '' # 向量模型名(AW_MEMORY_EMBED_MODEL)
97
- embed_api_key: '' # Bearer 密钥(AW_MEMORY_EMBED_API_KEY)
98
-
99
- # omp Agent Harness(env AW_OMP_COMPACT_*)
100
- omp:
101
- compact_enabled: true # 上下文自动压缩总开关(AW_OMP_COMPACT_ENABLED=0 可关)
102
- compact_threshold: 0.7 # 触发压缩的上下文占用比例(AW_OMP_COMPACT_THRESHOLD)
103
- compact_min_interval_ms: 300000 # 两次压缩最小间隔(AW_OMP_COMPACT_MIN_INTERVAL_MS)
104
- compact_wait_ms: 120000 # 等待压缩完成超时(AW_OMP_COMPACT_WAIT_MS)
105
-
106
- # 数控写控制(env DCW_ROLLBACK_*)
107
- dcw:
108
- rollback_cooldown_ms: 300000 # 回退后同向重写冷却(DCW_ROLLBACK_COOLDOWN_MS)
109
- rollback_min_window_ms: 120000 # 判定最小观察窗(DCW_ROLLBACK_MIN_WINDOW_MS)
110
- rollback_baseline_ms: 600000 # 基线回看窗(DCW_ROLLBACK_BASELINE_MS)
111
- rollback_stale_ms: 1800000 # open 记录接管阈值(DCW_ROLLBACK_STALE_MS)
112
-
113
- # 车间运行(env WORKSHOP_IDLE_*)
114
- workshop:
115
- idle_sweep_ms: 30000 # 空闲 agent 扫描周期(WORKSHOP_IDLE_SWEEP_MS)
116
- idle_grace_ms: 120000 # 空闲卸载宽限(WORKSHOP_IDLE_GRACE_MS)
117
-
118
- # 数据备份(env BACKUP_*)
119
- backup:
120
- disabled: false # BACKUP_DISABLED=1 关闭
121
- interval_hours: 24 # 备份间隔(BACKUP_INTERVAL_HOURS)
122
- keep: 7 # 保留份数(BACKUP_KEEP)
123
-
124
- # 数据保留清理(env RETENTION_DISABLED / AW_EVENTS_RETENTION_D 等)
125
- retention:
126
- disabled: false # RETENTION_DISABLED=1 / AW_RETENTION_DISABLED=1 关闭
127
- events_days: 7 # WS 事件流保留天数(AW_EVENTS_RETENTION_D)
128
- messages_days: 30 # Channel 消息(AW_MESSAGES_RETENTION_D)
129
- audit_days: 90 # 审计日志(AW_AUDIT_RETENTION_D)
130
- approval_days: 180 # 审批历史(AW_APPROVAL_RETENTION_D)
131
-
132
- # 服务端日志(env AWSHOP_LOG_LEVEL)
133
- log:
134
- level: info # debug | info | warn | error
1
+ # ============================================================
2
+ # AgentWorkShop 运行配置 —— 单一事实来源(Single Source of Truth)
3
+ # ------------------------------------------------------------
4
+ # 本文件由 nuxt.config.ts(构建/开发期)与 scripts/start.mjs(生产启动期)
5
+ # 读取并解析,驱动整个运行时。修改后重启对应模式即可生效:
6
+ # 开发:pnpm dev -> 读取 server.dev
7
+ # 生产:pnpm start -> 读取 server.prod
8
+ # ============================================================
9
+
10
+ app:
11
+ name: AgentWorkShop
12
+ title: AgentWorkShop
13
+ version: 0.7.4
14
+ description: 基于 Nuxt 4 的配置驱动运行范式
15
+
16
+ # 运行模式(dev/prod 实际由启动命令决定,此处仅作运行时展示)
17
+ mode: dev
18
+
19
+ # ------------------------------------------------------------
20
+ # 服务端口:dev 与 prod 可分别自定义
21
+ # ------------------------------------------------------------
22
+ server:
23
+ host: 0.0.0.0
24
+ dev:
25
+ port: 3000
26
+ prod:
27
+ port: 3001
28
+
29
+ # 后端 API(前端 axios 基址 + 服务端行为均由本段驱动)
30
+ api:
31
+ baseURL: /api
32
+ timeout: 15000
33
+ pageSize: 20 # 服务端默认分页大小
34
+ maxPageSize: 100 # 服务端分页大小上限
35
+
36
+ # 国际化
37
+ i18n:
38
+ defaultLocale: zh-CN
39
+ locales:
40
+ - code: zh-CN
41
+ name: 简体中文
42
+ - code: en
43
+ name: English
44
+
45
+ # 主题
46
+ theme:
47
+ # Agent Harness · Digital Twin 控制室色板:品牌绿(交互/确认/DAQ)+ 数据青,见 TownView.vue --hud-*
48
+ primaryColor: "#35e0a0"
49
+ mode: light # light | dark
50
+
51
+ # 安全配置
52
+ # 数据采集基础设施(数采 DAQ;地址与 docker-compose.yml 默认一致)
53
+ # startInfrastructure: never=启动探测,不通且有 Docker 则自动 docker compose 拉起;
54
+ # always=仅 Docker 拉起;never=只直连。连接失败降级并警告,可前端一键重连。
55
+ daq:
56
+ startInfrastructure: auto
57
+ mqtt:
58
+ host: 127.0.0.1
59
+ port: 1883
60
+ timescale:
61
+ host: 127.0.0.1
62
+ port: 5432
63
+ user: postgres
64
+ password: awshop
65
+ database: awshop
66
+ # 对象存储(图像帧;MinIO,S3 兼容)。不可达时自动降级本地磁盘 data/daq-objects/,采集不中断。
67
+ objectstore:
68
+ host: 127.0.0.1
69
+ port: 9000
70
+ accessKey: awshop
71
+ secretKey: awshop-secret
72
+ bucket: daq
73
+
74
+ security:
75
+ # Session cookie 加密密钥(nuxt-auth-utils 使用)
76
+ # 生产环境必须修改为强随机值;可用环境变量 NUXT_SESSION_PASSWORD 覆盖
77
+ sessionPassword: awshop-dev-secret-change-me-0123456789
78
+ # HITL 审批超时窗 ms(超时默认拒绝;env HITL_TIMEOUT_MS 兼容)
79
+ # hitl_timeout_ms: 180000
80
+
81
+ # ------------------------------------------------------------
82
+ # 以下运行语义组:全部键均可被 env AW_<键>(点转下划线)或历史别名覆盖,
83
+ # 优先级 config.yml < data/runtime-settings.json < 环境变量。缺省即用默认。
84
+ # ------------------------------------------------------------
85
+
86
+ # Agent 记忆系统(env AW_MEMORY_*)
87
+ memory:
88
+ primer_tokens: 300 # 记忆引子 token 预算(AW_MEMORY_PRIMER_TOKENS)
89
+ inject_total: 500 # 单次注入总硬顶(AW_MEMORY_INJECT_TOTAL)
90
+ maintenance_ms: 21600000 # 维护调度周期(AW_MEMORY_MAINTENANCE_MS)
91
+ expire_days: 180 # 情景记忆保留天数(AW_MEMORY_EXPIRE_DAYS)
92
+ expire_session_days: 14 # 会话记忆保留天数(AW_MEMORY_EXPIRE_SESSION_DAYS)
93
+ cap: 500 # 条目驱逐上限(AW_MEMORY_CAP)
94
+ reflect_trigger: 8 # 空闲反思触发阈值(AW_MEMORY_REFLECT_TRIGGER)
95
+ embed_base_url: '' # OpenAI 兼容 /embeddings 基址(AW_MEMORY_EMBED_BASE_URL;空=纯 FTS)
96
+ embed_model: '' # 向量模型名(AW_MEMORY_EMBED_MODEL)
97
+ embed_api_key: '' # Bearer 密钥(AW_MEMORY_EMBED_API_KEY)
98
+
99
+ # omp Agent Harness(env AW_OMP_COMPACT_*)
100
+ omp:
101
+ compact_enabled: true # 上下文自动压缩总开关(AW_OMP_COMPACT_ENABLED=0 可关)
102
+ compact_threshold: 0.7 # 触发压缩的上下文占用比例(AW_OMP_COMPACT_THRESHOLD)
103
+ compact_min_interval_ms: 300000 # 两次压缩最小间隔(AW_OMP_COMPACT_MIN_INTERVAL_MS)
104
+ compact_wait_ms: 120000 # 等待压缩完成超时(AW_OMP_COMPACT_WAIT_MS)
105
+
106
+ # 数控写控制(env DCW_ROLLBACK_*)
107
+ dcw:
108
+ rollback_cooldown_ms: 300000 # 回退后同向重写冷却(DCW_ROLLBACK_COOLDOWN_MS)
109
+ rollback_min_window_ms: 120000 # 判定最小观察窗(DCW_ROLLBACK_MIN_WINDOW_MS)
110
+ rollback_baseline_ms: 600000 # 基线回看窗(DCW_ROLLBACK_BASELINE_MS)
111
+ rollback_stale_ms: 1800000 # open 记录接管阈值(DCW_ROLLBACK_STALE_MS)
112
+
113
+ # 车间运行(env WORKSHOP_IDLE_*)
114
+ workshop:
115
+ idle_sweep_ms: 30000 # 空闲 agent 扫描周期(WORKSHOP_IDLE_SWEEP_MS)
116
+ idle_grace_ms: 120000 # 空闲卸载宽限(WORKSHOP_IDLE_GRACE_MS)
117
+
118
+ # 数据备份(env BACKUP_*)
119
+ backup:
120
+ disabled: false # BACKUP_DISABLED=1 关闭
121
+ interval_hours: 24 # 备份间隔(BACKUP_INTERVAL_HOURS)
122
+ keep: 7 # 保留份数(BACKUP_KEEP)
123
+
124
+ # 数据保留清理(env RETENTION_DISABLED / AW_EVENTS_RETENTION_D 等)
125
+ retention:
126
+ disabled: false # RETENTION_DISABLED=1 / AW_RETENTION_DISABLED=1 关闭
127
+ events_days: 7 # WS 事件流保留天数(AW_EVENTS_RETENTION_D)
128
+ messages_days: 30 # Channel 消息(AW_MESSAGES_RETENTION_D)
129
+ audit_days: 90 # 审计日志(AW_AUDIT_RETENTION_D)
130
+ approval_days: 180 # 审批历史(AW_APPROVAL_RETENTION_D)
131
+
132
+ # 服务端日志(env AWSHOP_LOG_LEVEL)
133
+ log:
134
+ level: info # debug | info | warn | error
package/docs/tui.md ADDED
@@ -0,0 +1,43 @@
1
+ # TUI 终端工作台(`aw tui`)
2
+
3
+ 与 AgentTeam 交互作业的终端客户端。渲染层基于 `@earendil-works/pi-tui`(openclaw
4
+ 同款组件化 TUI 框架),代码在仓库 `tui/` 目录(`.mjs` 直跑,零构建);与服务端
5
+ 的关系和 WebUI 平级 —— 同一套 REST + AEP WebSocket,不引入新的服务端形态。
6
+
7
+ > 完整用法/按键/命令表见 [`tui/README.md`](../tui/README.md);本文是架构与集成说明。
8
+
9
+ ## 能力总览
10
+
11
+ - **频道管理**:`/channel new|use|add` 创建频道(可内联建 lead)、切换订阅、
12
+ 放置 Agent 实例(模板克隆或内联定义)。
13
+ - **任务下发**:普通文本发 lead(`priority=task`);`/send` immediate 直发
14
+ (忙碌时 steer 注入 omp 当前回合);`/task` 正式任务(goal/loop/pipeline)。
15
+ - **实时观察**:AEP WS 订阅(断线 `lastSeq` 续传);`/monitor <agent>` 打开
16
+ 右侧终端镜像面板(omp `rpc-ui` 会话的净化帧流)。
17
+ - **HITL 统一作答**:omp ask 对话框与 dcw 下发审批的待办在 `/hitl` 聚合,
18
+ 作答经 `POST /api/workshop/hitl/respond` 路由回 omp stdin / 审批裁决。
19
+
20
+ ## HITL 集成(服务端增量)
21
+
22
+ 服务端新增 `server/services/workshop/agents/hitl-registry.ts`(进程内待办登记处):
23
+
24
+ - 两条既有 HITL 链路统一登记:`harness-terminal.ts`(omp `extension_ui_request`,
25
+ park 语义:零订阅倒计时 `security.hitl_timeout_ms`,订阅即暂停)与
26
+ `tool-approvals.ts`(dcw 审批,180s 超时同源)。
27
+ - AEP 新帧:`hitl.request` / `hitl.resolved`(频道流 publish + 全员直推各一路,
28
+ WebUI/TUI 不依赖频道订阅即达;快照恢复走 `GET /api/workshop/hitl/pending`)。
29
+ - 统一应答:`POST /api/workshop/hitl/respond`(幂等,已落定返回 409
30
+ `ALREADY_RESOLVED`;用户 token + channel 所有权校验 + audit 留痕)。
31
+
32
+ WebUI 侧:`app/stores/workshop/hitl.ts` 消费帧 → `AppHeader` 铃标 → 点击跳
33
+ `/monitor?agentId=&channelId=` 直达该 Agent 终端作答(OmpTerminalPanel 既有
34
+ 作答界面不变)。
35
+
36
+ ## 测试
37
+
38
+ | 命令 | 覆盖 |
39
+ |---|---|
40
+ | `npx tsx scripts/test-hitl-registry.ts` | registry 登记/落定/订阅/park 暂停与超时(22 断言) |
41
+ | `node scripts/test-tui-reducers.mjs` | AEP 帧 → 会话状态归约(15 断言) |
42
+ | `node scripts/test-tui-commands.mjs` | 命令解析/分发(21 断言) |
43
+ | `node scripts/tui-smoke.mjs` | 无头 e2e:虚拟终端驱动真实 TUI ↔ 真实 dev server(12 断言) |
@@ -1850,6 +1850,9 @@ export default {
1850
1850
  kwsdot0002: 'Syncing in real time…',
1851
1851
  kwsdot0003: 'Connecting…',
1852
1852
  kwsdot0004: 'Connection lost',
1853
+ hitlBadge: 'Needs human input',
1854
+ hitlKindOmp: 'omp dialog',
1855
+ hitlKindDcw: 'write approval',
1853
1856
  },
1854
1857
  ompTerminalPanel: {
1855
1858
  k14jk3nu001: ' {p0}· 对话框已撤销({p1}){p2}',
@@ -1849,6 +1849,9 @@ export default {
1849
1849
  kwsdot0002: '实时同步中…',
1850
1850
  kwsdot0003: '连接中…',
1851
1851
  kwsdot0004: '连接已断开',
1852
+ hitlBadge: '待人工处理',
1853
+ hitlKindOmp: 'omp 对话框',
1854
+ hitlKindDcw: '下发审批',
1852
1855
  },
1853
1856
  ompTerminalPanel: {
1854
1857
  k14jk3nu001: ' {p0}· 对话框已撤销({p1}){p2}',