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.
- package/.output/nitro.json +1 -1
- package/.output/public/_nuxt/B9Yie5HN.js +2 -0
- package/.output/public/_nuxt/CN7Zh8GQ.js +1 -0
- package/.output/public/_nuxt/CdSgfcYR.js +1 -0
- package/.output/public/_nuxt/CdfAP_IH2.js +1 -0
- package/.output/public/_nuxt/ChnfyQHz.js +1 -0
- package/.output/public/_nuxt/{BkKYf8xY.js → CyygA0q4.js} +4 -4
- package/.output/public/_nuxt/{Bz40vyZS.js → DFnGFEav.js} +7 -7
- package/.output/public/_nuxt/Xaf_HIR3.js +1 -0
- package/.output/public/_nuxt/ZugRk0CM2.js +4 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/55c10854-ee0e-4be4-924b-a1b0e100fe11.json +1 -0
- package/.output/public/_nuxt/{default.iGJy9dP-.css → default.D17kXlD6.css} +1 -1
- package/.output/public/_nuxt/monitor.CmwpEUCI.css +1 -0
- package/.output/public/_nuxt/yIKY_V1P.js +1 -0
- package/.output/server/chunks/_/nitro.mjs +1131 -920
- package/.output/server/chunks/_/nitro.mjs.map +1 -1
- package/.output/server/chunks/build/{TownView-BkHxMiwZ.mjs → TownView-Bl8Gkcxi.mjs} +3 -3
- package/.output/server/chunks/build/{TownView-BkHxMiwZ.mjs.map → TownView-Bl8Gkcxi.mjs.map} +1 -1
- package/.output/server/chunks/build/{_id_-Bna1_JuB.mjs → _id_-CWLFGZjV.mjs} +2 -2
- package/.output/server/chunks/build/{_id_-Bna1_JuB.mjs.map → _id_-CWLFGZjV.mjs.map} +1 -1
- package/.output/server/chunks/build/_id_-GnRJPykX.mjs +1 -1
- package/.output/server/chunks/build/{_wsId_-CzLDGT_V.mjs → _wsId_-BhQMjyHG.mjs} +3 -4
- package/.output/server/chunks/build/{_wsId_-CzLDGT_V.mjs.map → _wsId_-BhQMjyHG.mjs.map} +1 -1
- package/.output/server/chunks/build/{daq-CmeM4u5u.mjs → daq-BOgpn9sl.mjs} +4 -5
- package/.output/server/chunks/build/daq-BOgpn9sl.mjs.map +1 -0
- package/.output/server/chunks/build/dcw-BTM5YU-B.mjs +1 -1
- package/.output/server/chunks/build/{default-Dt6xLdpd.mjs → default-CKJWhkot.mjs} +60 -17
- package/.output/server/chunks/build/{default-Dt6xLdpd.mjs.map → default-CKJWhkot.mjs.map} +1 -1
- package/.output/server/chunks/build/{logs-CUQt1z7D.mjs → logs-Dyk0I2I9.mjs} +3 -4
- package/.output/server/chunks/build/logs-Dyk0I2I9.mjs.map +1 -0
- package/.output/server/chunks/build/{monitor-yNoV98rf.mjs → monitor-KW8WLOJd.mjs} +34 -33
- package/.output/server/chunks/build/{monitor-yNoV98rf.mjs.map → monitor-KW8WLOJd.mjs.map} +1 -1
- package/.output/server/chunks/build/{town-BN4vQPb8.mjs → town-_4tEEEVW.mjs} +3 -4
- package/.output/server/chunks/build/town-_4tEEEVW.mjs.map +1 -0
- package/.output/server/chunks/build/useDaqStream-hwkhJHFU.mjs +1 -1
- package/.output/server/chunks/build/useDcwStream-Bdew_yrr.mjs +1 -1
- package/.output/server/chunks/build/{useWorkshopWs-xcdeiSmJ.mjs → useWorkshopWs-B3j5wIAK.mjs} +177 -3
- package/.output/server/chunks/build/useWorkshopWs-B3j5wIAK.mjs.map +1 -0
- package/.output/server/chunks/build/{workshop-CLhwe5eo.mjs → workshop-k0XZTFKg.mjs} +2 -3
- package/.output/server/chunks/build/workshop-k0XZTFKg.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/channel-templates/_id/instantiate.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/channels.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs +32 -0
- package/.output/server/chunks/routes/api/workshop/hitl/pending.get.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs +56 -0
- package/.output/server/chunks/routes/api/workshop/hitl/respond.post.mjs.map +1 -0
- package/.output/server/chunks/routes/api/workshop/plugins/_name/disable.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/plugins/_name/enable.post.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.delete.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/scene/layouts/_channelId_.put.mjs +1 -1
- package/.output/server/chunks/routes/api/workshop/workspaces/_id/channel-templates/_tplId_.post.mjs +1 -1
- package/.output/server/chunks/routes/renderer.mjs +2 -2
- package/.output/server/chunks/virtual/entry.mjs +17 -11
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/package.json +1 -1
- package/README.md +435 -434
- package/app/components/AppHeader.vue +138 -0
- package/app/composables/workshop/useWorkshopWs.ts +4 -0
- package/app/pages/monitor.vue +17 -1
- package/app/stores/workshop/hitl.ts +80 -0
- package/bin/aw.mjs +0 -0
- package/cli/commands/tui.mjs +19 -0
- package/config.yml +134 -134
- package/docs/tui.md +43 -0
- package/i18n/locales/en.ts +3 -0
- package/i18n/locales/zh-CN.ts +3 -0
- package/package.json +140 -144
- package/scripts/_spike-pitui.mjs +116 -0
- package/scripts/e2e-hitl-live.mjs +323 -0
- package/scripts/e2e-line-live.mjs +144 -0
- package/scripts/test-hitl-registry.ts +112 -0
- package/scripts/test-tui-commands.mjs +131 -0
- package/scripts/test-tui-reducers.mjs +72 -0
- package/scripts/tsconfig.json +14 -0
- package/scripts/tui-smoke.mjs +91 -0
- package/server/api/workshop/hitl/pending.get.ts +28 -0
- package/server/api/workshop/hitl/respond.post.ts +67 -0
- package/server/api/workshop/ws.ts +30 -1
- package/server/data/daqs.json +39 -17
- package/server/data/dcw-lines.json +14 -0
- package/server/data/dcw-products.json +35 -0
- package/server/data/dcw-recipes.json +140 -0
- package/server/data/dcw-rollback.json +111 -1
- package/server/data/dcw-runs.json +135 -90
- package/server/data/dcw-writes.json +120 -0
- package/server/data/dcws.json +400 -275
- package/server/data/line-runs.json +11 -1
- package/server/plugins/workshop.ts +7 -0
- package/server/services/workshop/agents/harness-terminal.ts +92 -25
- package/server/services/workshop/agents/hitl-registry.ts +181 -0
- package/server/services/workshop/agents/tool-approvals.ts +15 -0
- package/server/services/workshop/scene-events.ts +19 -9
- package/shared/workshop-protocol.ts +37 -0
- package/tui/README.md +65 -0
- package/tui/aw-tui.mjs +356 -0
- package/tui/commands/index.mjs +250 -0
- package/tui/components/chat-log.mjs +42 -0
- package/tui/components/hitl-card.mjs +36 -0
- package/tui/components/monitor-pane.mjs +39 -0
- package/tui/components/root.mjs +53 -0
- package/tui/components/status-bar.mjs +29 -0
- package/tui/lib/api.mjs +82 -0
- package/tui/lib/config.mjs +58 -0
- package/tui/lib/reducers.mjs +218 -0
- package/tui/lib/state.mjs +80 -0
- package/tui/lib/virtual-terminal.mjs +48 -0
- package/tui/lib/ws.mjs +124 -0
- package/tui/theme.mjs +38 -0
- package/.output/public/_nuxt/B7V9IfTL.js +0 -1
- package/.output/public/_nuxt/BE5QyG5J2.js +0 -1
- package/.output/public/_nuxt/BuKI8z-5.js +0 -1
- package/.output/public/_nuxt/D0C5Q0di.js +0 -1
- package/.output/public/_nuxt/DC-QMEk1.js +0 -2
- package/.output/public/_nuxt/DEkQ0qQ02.js +0 -1
- package/.output/public/_nuxt/builds/meta/c6c01cdd-762e-4fb8-86e7-753c5185b856.json +0 -1
- package/.output/public/_nuxt/dt2tKE95.js +0 -4
- package/.output/public/_nuxt/i_MKObHo.js +0 -1
- package/.output/public/_nuxt/monitor.41fCD6TB.css +0 -1
- package/.output/public/_nuxt/tpDMVY5w.js +0 -1
- package/.output/server/chunks/build/connection-Dc0fn6yd.mjs +0 -120
- package/.output/server/chunks/build/connection-Dc0fn6yd.mjs.map +0 -1
- package/.output/server/chunks/build/daq-CmeM4u5u.mjs.map +0 -1
- package/.output/server/chunks/build/logs-CUQt1z7D.mjs.map +0 -1
- package/.output/server/chunks/build/town-BN4vQPb8.mjs.map +0 -1
- package/.output/server/chunks/build/useWorkshopWs-xcdeiSmJ.mjs.map +0 -1
- 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) // 推进重连续传游标
|
package/app/pages/monitor.vue
CHANGED
|
@@ -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)
|
|
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.
|
|
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 断言) |
|
package/i18n/locales/en.ts
CHANGED
|
@@ -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}',
|
package/i18n/locales/zh-CN.ts
CHANGED
|
@@ -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}',
|