oh-my-agent-web 0.5.0 → 0.6.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.
Files changed (92) hide show
  1. package/dist/server/session/runtime.js +5 -1
  2. package/dist/server/session/turn-queue.js +101 -18
  3. package/dist/server/session/turn-send.js +4 -0
  4. package/dist/server/util/upstream-version.js +47 -8
  5. package/package.json +1 -1
  6. package/web/dist/assets/{abnfDiagram-WEYOIA3C-VUKLHHSn.js → abnfDiagram-WEYOIA3C-C0scvgfK.js} +1 -1
  7. package/web/dist/assets/{arc-BeUkaHhk.js → arc-DQWQXZ0D.js} +1 -1
  8. package/web/dist/assets/{architecture-WOLXFQ4H-B9I4s0NV.js → architecture-WOLXFQ4H-DRYAlsMA.js} +1 -1
  9. package/web/dist/assets/{architectureDiagram-ZHVYKT53-CaEkLhfq.js → architectureDiagram-ZHVYKT53-DURI6MT_.js} +1 -1
  10. package/web/dist/assets/{blockDiagram-RJAE7QA3-IR49UNE_.js → blockDiagram-RJAE7QA3-4SqX2RCZ.js} +1 -1
  11. package/web/dist/assets/{c4Diagram-XDPPPE54-B-81CloB.js → c4Diagram-XDPPPE54-CyzS6It3.js} +1 -1
  12. package/web/dist/assets/channel-sSfIOMg7.js +1 -0
  13. package/web/dist/assets/{chunk-2E7WHVMD-CaWVF7qv.js → chunk-2E7WHVMD-B-50G064.js} +1 -1
  14. package/web/dist/assets/{chunk-4EMNKR2T-BvXf2tq-.js → chunk-4EMNKR2T-DsXkPvfB.js} +1 -1
  15. package/web/dist/assets/{chunk-55XCU76K-Bz_d2e2D.js → chunk-55XCU76K-BAQkUXw9.js} +1 -1
  16. package/web/dist/assets/{chunk-7S6XSTFO-B_SPMiU8.js → chunk-7S6XSTFO-MNTmDz5n.js} +1 -1
  17. package/web/dist/assets/{chunk-AQDTSKZB-Cen-_xej.js → chunk-AQDTSKZB-DxchdDrD.js} +1 -1
  18. package/web/dist/assets/{chunk-DSNLSHJZ-DEw1kFwj.js → chunk-DSNLSHJZ-CQfLJsEG.js} +1 -1
  19. package/web/dist/assets/{chunk-HAGFOTED-BwpOOcw8.js → chunk-HAGFOTED-BaVCqyAB.js} +1 -1
  20. package/web/dist/assets/{chunk-HNE4Q36P-BjCwi2uW.js → chunk-HNE4Q36P-BachKm72.js} +1 -1
  21. package/web/dist/assets/{chunk-NQOKRVIF-WcqhWFS5.js → chunk-NQOKRVIF-D38mfZCv.js} +1 -1
  22. package/web/dist/assets/{chunk-UHW7PFBP-quDvQby8.js → chunk-UHW7PFBP-DzvEYnNC.js} +1 -1
  23. package/web/dist/assets/{chunk-VQ5W62QI-DZBwmhzq.js → chunk-VQ5W62QI-D7Rb-hYZ.js} +1 -1
  24. package/web/dist/assets/{chunk-WQQL4CDK-wYyHYuui.js → chunk-WQQL4CDK-Dt2FUoIk.js} +1 -1
  25. package/web/dist/assets/{chunk-XXDRQBXY-DfJzC7nt.js → chunk-XXDRQBXY-DasKl82Z.js} +1 -1
  26. package/web/dist/assets/{chunk-YZO67HFG-CWLraGk_.js → chunk-YZO67HFG-3YefBeUz.js} +1 -1
  27. package/web/dist/assets/{chunk-ZAUX2LTX-ChBUt_FJ.js → chunk-ZAUX2LTX-CUoEknd1.js} +1 -1
  28. package/web/dist/assets/{chunk-ZCHMQSOR-C57UFT60.js → chunk-ZCHMQSOR-Da3GBE09.js} +1 -1
  29. package/web/dist/assets/{classDiagram-v2-4MYWR3UA-Bo4i7SNY.js → classDiagram-v2-4MYWR3UA-ByZcqRlk.js} +1 -1
  30. package/web/dist/assets/{cose-bilkent-JH36ORCC-CK360NdH.js → cose-bilkent-JH36ORCC-PGAAEchc.js} +1 -1
  31. package/web/dist/assets/{cynefin-EF2NZ3EQ-DlXFjIFm.js → cynefin-EF2NZ3EQ-BBkeqM17.js} +1 -1
  32. package/web/dist/assets/{cynefinDiagram-WF24UDRP-zvZIqA1c.js → cynefinDiagram-WF24UDRP-DOEytVty.js} +1 -1
  33. package/web/dist/assets/{dagre-NK4GIZVX-CnKhCu-v.js → dagre-NK4GIZVX-Bei2BCmp.js} +1 -1
  34. package/web/dist/assets/{diagram-CBK3MWTC-3QTR8Fjx.js → diagram-CBK3MWTC-BdeyWllS.js} +1 -1
  35. package/web/dist/assets/{diagram-I5XIIV2D-D9lSd7z6.js → diagram-I5XIIV2D-BmNMrWWj.js} +1 -1
  36. package/web/dist/assets/{diagram-ODIL2UCW-DWJD6lPM.js → diagram-ODIL2UCW-D8Kz7g8s.js} +1 -1
  37. package/web/dist/assets/{diagram-PFBEJUXE-CWJmoUg4.js → diagram-PFBEJUXE-BNSD58Rk.js} +1 -1
  38. package/web/dist/assets/{diagram-RJA3I4VV-D1SZHQcQ.js → diagram-RJA3I4VV-D-1dWVjH.js} +1 -1
  39. package/web/dist/assets/{diagram-TYUNFSNR-DCCjGi1x.js → diagram-TYUNFSNR-8YHZJhel.js} +1 -1
  40. package/web/dist/assets/{dist-VOk_Iv17.js → dist-BBxVlYHc.js} +1 -1
  41. package/web/dist/assets/{ebnfDiagram-V4P3TTPT-CQLdqEiW.js → ebnfDiagram-V4P3TTPT-CtgdOqHX.js} +1 -1
  42. package/web/dist/assets/{elk-QONTBCTQ-Dp2pEp6b.js → elk-QONTBCTQ-DM5bxyWI.js} +1 -1
  43. package/web/dist/assets/{erDiagram-KYQIGQAA-BFGNoFQ-.js → erDiagram-KYQIGQAA-BkQvVdNn.js} +1 -1
  44. package/web/dist/assets/{eventmodeling-K75KTNOO-CFfAemGw.js → eventmodeling-K75KTNOO-DWnHI7Q0.js} +1 -1
  45. package/web/dist/assets/flowDiagram-IUGLLWBU-DYv3kVGg.js +1 -0
  46. package/web/dist/assets/{ganttDiagram-R7GPNTJY-vK3jPGDq.js → ganttDiagram-R7GPNTJY-hF6RKzBy.js} +1 -1
  47. package/web/dist/assets/{gitGraph-VSP46ZUC-rXBgHTdq.js → gitGraph-VSP46ZUC-Dg0BaeiY.js} +1 -1
  48. package/web/dist/assets/{gitGraphDiagram-PDYL7XHY-CBbGhago.js → gitGraphDiagram-PDYL7XHY-CEJB8ISX.js} +1 -1
  49. package/web/dist/assets/index-BLsWuXKg.js +104 -0
  50. package/web/dist/assets/index-Bph00xIt.css +1 -0
  51. package/web/dist/assets/{info-OHQRW6UA-Cd9vp-6C.js → info-OHQRW6UA-X0qorfja.js} +1 -1
  52. package/web/dist/assets/{infoDiagram-MVDRKAX5-Ce-Sg_qu.js → infoDiagram-MVDRKAX5-Ct4k2rOv.js} +1 -1
  53. package/web/dist/assets/{ishikawaDiagram-HPEHV2GE-DWlmR6BY.js → ishikawaDiagram-HPEHV2GE-JsH1yFOe.js} +1 -1
  54. package/web/dist/assets/{journeyDiagram-BOSHW7O7-DmDG97ae.js → journeyDiagram-BOSHW7O7-B0ommDDF.js} +1 -1
  55. package/web/dist/assets/{kanban-definition-FNSA4HC5-1Z4sDrgV.js → kanban-definition-FNSA4HC5-C5IHOEO9.js} +1 -1
  56. package/web/dist/assets/{line-DGM1-9KW.js → line-XIlcDZrk.js} +1 -1
  57. package/web/dist/assets/{linear-B6hyeGHu.js → linear-BXwFphKE.js} +1 -1
  58. package/web/dist/assets/{mermaid-parser.core-D1HmdkA4.js → mermaid-parser.core-9OmqIOQj.js} +3 -3
  59. package/web/dist/assets/{mermaid.core-DeUJrhO1.js → mermaid.core-B9yDV3Hs.js} +4 -4
  60. package/web/dist/assets/{mindmap-definition-6OY57UG3-C3-FByy8.js → mindmap-definition-6OY57UG3-Bc8uZ5T9.js} +1 -1
  61. package/web/dist/assets/{packet-JDAUHWVQ-BoOr7DaW.js → packet-JDAUHWVQ-9EbXSBeV.js} +1 -1
  62. package/web/dist/assets/{pegDiagram-ECIUJNBX-Bn7m75TZ.js → pegDiagram-ECIUJNBX-nYdgRfAO.js} +1 -1
  63. package/web/dist/assets/{pie-XZMESJXO-CGuMTDBp.js → pie-XZMESJXO-DNvb9i1G.js} +1 -1
  64. package/web/dist/assets/{pieDiagram-GNMPY74T-DHhaPwZe.js → pieDiagram-GNMPY74T-BUKhe6YN.js} +1 -1
  65. package/web/dist/assets/{quadrantDiagram-D57K4MC3-DxTgFHLK.js → quadrantDiagram-D57K4MC3-COMDA2G7.js} +1 -1
  66. package/web/dist/assets/{radar-ABXABTNO-BiKxmALL.js → radar-ABXABTNO-DAG-ygGV.js} +1 -1
  67. package/web/dist/assets/{railroad-I3PHUGI6-BKYufgg4.js → railroad-I3PHUGI6-CjnKFfHL.js} +1 -1
  68. package/web/dist/assets/{railroad-abnf-LNEFI6M7-DmOrjlyL.js → railroad-abnf-LNEFI6M7-DOpu4hdH.js} +1 -1
  69. package/web/dist/assets/{railroad-ebnf-DWYD2UWJ-BgMyVDd1.js → railroad-ebnf-DWYD2UWJ-B7kV2hyB.js} +1 -1
  70. package/web/dist/assets/{railroad-peg-JR7BVNR7-BN6NL8S-.js → railroad-peg-JR7BVNR7-Cy4mKxpf.js} +1 -1
  71. package/web/dist/assets/{railroadDiagram-Y72NRBL7-BsbA-9gP.js → railroadDiagram-Y72NRBL7-CJek641i.js} +1 -1
  72. package/web/dist/assets/{requirementDiagram-EQYSW5RA-HUw4YqWd.js → requirementDiagram-EQYSW5RA-DilR-z_d.js} +1 -1
  73. package/web/dist/assets/{sankeyDiagram-SY24JHO5-Dx1MOFRu.js → sankeyDiagram-SY24JHO5-mnLwPz1t.js} +1 -1
  74. package/web/dist/assets/{sequenceDiagram-BLEHNHQU-C0-Rzg3g.js → sequenceDiagram-BLEHNHQU-BdH-2WXg.js} +1 -1
  75. package/web/dist/assets/{src-CuHygcpj.js → src-DrBGN2Yi.js} +1 -1
  76. package/web/dist/assets/{stateDiagram-v2-A6IESKWZ-BnEICGtg.js → stateDiagram-v2-A6IESKWZ-Byl9Wc56.js} +1 -1
  77. package/web/dist/assets/{swimlanes-B3ENRKFQ-CwDRCHZD.js → swimlanes-B3ENRKFQ-D_Mnemnr.js} +1 -1
  78. package/web/dist/assets/swimlanesDiagram-AYQRV4AK-D6uQfcsx.js +8 -0
  79. package/web/dist/assets/{timeline-definition-JXYKGLGB-C4BVpgzc.js → timeline-definition-JXYKGLGB-D2DwVY9P.js} +1 -1
  80. package/web/dist/assets/{treeView-D4JQ5SDB-BBsvEMP3.js → treeView-D4JQ5SDB-BPseZx68.js} +1 -1
  81. package/web/dist/assets/{treemap-SAJKECNS-BYw6cxC8.js → treemap-SAJKECNS-DbkR3mjV.js} +1 -1
  82. package/web/dist/assets/{usecaseDiagram-WPOLBNNX-BkOXLgwP.js → usecaseDiagram-WPOLBNNX-ClThWCPc.js} +1 -1
  83. package/web/dist/assets/{vennDiagram-Q3Y3IDCW-Kgjk_n6B.js → vennDiagram-Q3Y3IDCW-B50-oQjz.js} +1 -1
  84. package/web/dist/assets/{wardley-7MLQ67FV-BGVObhvJ.js → wardley-7MLQ67FV-Ct_6HXw3.js} +1 -1
  85. package/web/dist/assets/{wardleyDiagram-IVAIDKWA-i97uD6tL.js → wardleyDiagram-IVAIDKWA-B7Z8k44J.js} +1 -1
  86. package/web/dist/assets/{xychartDiagram-4URNHDU4-awJi5TfJ.js → xychartDiagram-4URNHDU4-CUJ-AhMv.js} +1 -1
  87. package/web/dist/index.html +2 -2
  88. package/web/dist/assets/channel-B_mTTjGt.js +0 -1
  89. package/web/dist/assets/flowDiagram-IUGLLWBU-DmSp3cbW.js +0 -1
  90. package/web/dist/assets/index-DBOF_OJe.js +0 -104
  91. package/web/dist/assets/index-nlY_-OaR.css +0 -1
  92. package/web/dist/assets/swimlanesDiagram-AYQRV4AK-DZ_aAXmG.js +0 -8
@@ -151,7 +151,7 @@ export function createRuntime(options) {
151
151
  statsOf: async (id) => (await engine.sessionStats?.(id)) ?? null,
152
152
  onChanged: pushSnapshot,
153
153
  });
154
- const { queue, busy } = createTurnPlumbing({
154
+ const { queue, busy, flushSteer } = createTurnPlumbing({
155
155
  state,
156
156
  engine,
157
157
  nextId,
@@ -163,6 +163,8 @@ export function createRuntime(options) {
163
163
  },
164
164
  notice: (text, level) => notice(text, level),
165
165
  pushSnapshot,
166
+ // 插队注入前要确认「这一轮真的还在跑」(见 turn-queue 的 flushSteer)
167
+ isTurnRunning: (conversationId) => turns.has(conversationId),
166
168
  });
167
169
  const finishTurn = createRuntimeTurnFinisher({
168
170
  state,
@@ -232,6 +234,8 @@ export function createRuntime(options) {
232
234
  refreshThinking: (id) => models.refreshThinking(id),
233
235
  clientView,
234
236
  touchConversation,
237
+ // 挂着的插队:一到「一步结束」就真插进去
238
+ steerAtBoundary: (conversationId) => flushSteer(conversationId),
235
239
  uploadStore: options.uploadStore,
236
240
  });
237
241
  /**
@@ -12,13 +12,24 @@ export function createTurnQueue() {
12
12
  return null;
13
13
  return entries.splice(index, 1)[0] ?? null;
14
14
  },
15
- /** 取消一条(按 id);返回是否真的删掉了 */
15
+ /** 取消一条(按 id);返回被删掉的那条(没有就 null)—— 调用方靠 mode 决定提示语 */
16
16
  remove(id) {
17
17
  const index = entries.findIndex((entry) => entry.id === id);
18
18
  if (index < 0)
19
- return false;
20
- entries.splice(index, 1);
21
- return true;
19
+ return null;
20
+ return entries.splice(index, 1)[0] ?? null;
21
+ },
22
+ /**
23
+ * 取走某会话队首的「插队」那一项(没有就 null)。
24
+ *
25
+ * 只在**注入时机到了**才调:插队先挂在队列里 → 界面上就是一条可撤回的待发行 →
26
+ * 到 step 边界(或兑底超时)才用 streamingBehavior:"steer" 真正插进去。
27
+ */
28
+ takeSteer(conversationId) {
29
+ const index = entries.findIndex((entry) => entry.conversationId === conversationId && entry.mode === "steer");
30
+ if (index < 0)
31
+ return null;
32
+ return entries.splice(index, 1)[0] ?? null;
22
33
  },
23
34
  /** 删掉某个会话的全部排队项(会话被删时用) */
24
35
  removeConversation(conversationId) {
@@ -31,7 +42,7 @@ export function createTurnQueue() {
31
42
  };
32
43
  }
33
44
  function toViews(entries) {
34
- return entries.map(({ id, conversationId, text }) => ({ id, conversationId, text }));
45
+ return entries.map(({ id, conversationId, text, mode }) => ({ id, conversationId, text, mode }));
35
46
  }
36
47
  export function createBusyHandler(deps) {
37
48
  return async (mode, text, promptText, _images, attachments) => {
@@ -39,15 +50,16 @@ export function createBusyHandler(deps) {
39
50
  if (!conversationId)
40
51
  return { ok: false, error: { code: "session.none", message: "先打开一个会话" } };
41
52
  if (mode === "queue") {
42
- const depth = deps.queue(conversationId, text, attachments);
53
+ const depth = deps.queue(conversationId, text, attachments, "queue");
43
54
  deps.notice(`已排队(第 ${depth} 条):这一轮结束后自动发送`, "info");
44
55
  deps.pushSnapshot();
45
56
  return { ok: true };
46
57
  }
47
58
  if (mode === "steer") {
48
- await deps.steer(conversationId, promptText);
49
- deps.appendUser(conversationId, text, true);
50
- deps.notice("已插队:插进当前这一轮", "info");
59
+ // 先挂到队列(界面上是「插队」待发行,可撤回 / 取消),到 step 边界再真注入。
60
+ // 不在这里直接 steer:一旦交给引擎就再也拿不回来了,没有可撤回的窗口。
61
+ deps.queue(conversationId, text, attachments, "steer");
62
+ deps.notice("已插队:等当前这一步结束插进去(还没插进去,可以撤回)", "info");
51
63
  deps.pushSnapshot();
52
64
  return { ok: true };
53
65
  }
@@ -62,11 +74,12 @@ export function createQueueController(options) {
62
74
  options.onChanged();
63
75
  };
64
76
  return {
65
- push(conversationId, text, attachments) {
77
+ push(conversationId, text, attachments, mode) {
66
78
  const views = options.turnQueue.push({
67
79
  id: options.nextId("q"),
68
80
  conversationId,
69
81
  text,
82
+ mode,
70
83
  ...(attachments ? { attachments } : {}),
71
84
  });
72
85
  sync();
@@ -77,10 +90,26 @@ export function createQueueController(options) {
77
90
  sync();
78
91
  return next;
79
92
  },
93
+ /** 取走一条挂着的插队(注入时才调) */
94
+ takeSteer(conversationId) {
95
+ const next = options.turnQueue.takeSteer(conversationId);
96
+ if (next)
97
+ sync();
98
+ return next;
99
+ },
100
+ /** 这个会话还挂着插队吗(一次只插一条,插完看还有没有下一条) */
101
+ hasSteer(conversationId) {
102
+ return options.turnQueue
103
+ .views()
104
+ .some((item) => item.conversationId === conversationId && item.mode === "steer");
105
+ },
106
+ /** 取消一条待发(排队或插队都行);返回被删掉那条的 kind,界面靠它说准话 */
80
107
  cancel(queueId) {
81
108
  const removed = options.turnQueue.remove(queueId);
109
+ if (!removed)
110
+ return null;
82
111
  sync();
83
- return removed;
112
+ return removed.mode;
84
113
  },
85
114
  };
86
115
  }
@@ -92,20 +121,74 @@ export function createTurnPlumbing(options) {
92
121
  nextId: options.nextId,
93
122
  onChanged: options.pushSnapshot,
94
123
  });
124
+ /** 每个会话一个兑底计时器:插队挂着太久就不等边界了 */
125
+ const steerTimers = new Map();
126
+ /**
127
+ * 把挂着的「插队」真正插进当前回合。
128
+ *
129
+ * 调用时机只有三种(都是宿主的判断,不靠用户再点一次):
130
+ * 1. 当前回合到了 step 边界(一条工具调用 / 一次模型调用收尾)—— 这也正是引擎自己插队的时机;
131
+ * 2. 兑底超时(记在 STEER_HOLD_MS)—— 免得遇到长时间无边界的一轮,插队默默退化成排队;
132
+ * 3. 这一轮已经结束(收尾时排空队列会把它当成下一轮发,不会丢)。
133
+ */
134
+ const flushSteer = (conversationId) => {
135
+ clearSteerTimer(conversationId);
136
+ // 回合已经结束了:不注入(否则消息落了盘、模型却收不到)—— 留给收尾排空当下一轮发
137
+ if (options.isTurnRunning && !options.isTurnRunning(conversationId))
138
+ return;
139
+ const held = queue.takeSteer(conversationId);
140
+ if (!held)
141
+ return;
142
+ // 先进消息流再注入:界面与对话记录的顺序与旧行为一致(插队就在当前这一轮里)
143
+ options.appendUser(held.conversationId, held.text, true);
144
+ options.pushSnapshot();
145
+ void options.engine
146
+ .sendMessage(held.conversationId, held.text, () => { }, { streamingBehavior: "steer" })
147
+ .catch(() => undefined);
148
+ options.notice("已插队:插进当前这一轮", "info");
149
+ // 还挂着别的话继续等下一个边界(一次只插一条,和队列语义一致)
150
+ if (queue.hasSteer(conversationId))
151
+ scheduleSteerFlush(conversationId);
152
+ };
153
+ const clearSteerTimer = (conversationId) => {
154
+ const timer = steerTimers.get(conversationId);
155
+ if (!timer)
156
+ return;
157
+ clearTimeout(timer);
158
+ steerTimers.delete(conversationId);
159
+ };
160
+ /** 兑底:挂着超过 STEER_HOLD_MS 还没遇到 step 边界就直接插(不退化成排队) */
161
+ const scheduleSteerFlush = (conversationId) => {
162
+ if (steerTimers.has(conversationId))
163
+ return;
164
+ const timer = setTimeout(() => {
165
+ steerTimers.delete(conversationId);
166
+ flushSteer(conversationId);
167
+ }, STEER_HOLD_MS);
168
+ timer.unref?.();
169
+ steerTimers.set(conversationId, timer);
170
+ };
95
171
  const busy = createBusyHandler({
96
172
  activeId: () => options.state.activeId,
97
- steer: (id, prompt) => options.engine.sendMessage(id, prompt, () => { }, { streamingBehavior: "steer" }),
98
- queue: (id, text, attachments) => queue.push(id, text, attachments),
173
+ queue: (id, text, attachments, mode) => {
174
+ const depth = queue.push(id, text, attachments, mode);
175
+ if (mode === "steer")
176
+ scheduleSteerFlush(id);
177
+ return depth;
178
+ },
99
179
  appendUser: options.appendUser,
100
180
  notice: options.notice,
101
181
  pushSnapshot: options.pushSnapshot,
102
182
  });
103
- return { queue, busy };
183
+ return { queue, busy, flushSteer };
104
184
  }
105
- /** 取消一条排队消息的对外动作(runtime 里只留一行) */
185
+ /** 插队挂在宿主上的最长时长:超过它就不再等 step 边界(否则插队会退化成排队) */
186
+ export const STEER_HOLD_MS = 3000;
187
+ /** 取消一条待发消息的对外动作(runtime 里只留一行) */
106
188
  export function cancelQueuedWith(queue, queueId, notice) {
107
- if (!queue.cancel(queueId))
108
- return { ok: false, error: { code: "queue.not_found", message: "这条排队消息已经不在了" } };
109
- notice("已取消排队", "info");
189
+ const kind = queue.cancel(queueId);
190
+ if (!kind)
191
+ return { ok: false, error: { code: "queue.not_found", message: "这条待发消息已经不在了(可能已插进去/已发出)" } };
192
+ notice(kind === "steer" ? "已取消插队:不会插进去了" : "已取消排队", "info");
110
193
  return { ok: true };
111
194
  }
@@ -83,6 +83,10 @@ export function createTurnSender(deps) {
83
83
  deps.pushSnapshot();
84
84
  await deps.engine.sendMessage(conv, resolved.promptText, (event) => {
85
85
  applyEngineEvent(deps.turnContext, { conversationId: conv, messageId: assistantMessage.id, event });
86
+ // 插队挂着的时候:一到「一步结束」就插进去(tool_end / 一次模型调用收尾)
87
+ if (event.type === "tool_end" || (event.type === "usage" && event.final === true)) {
88
+ deps.steerAtBoundary?.(conv);
89
+ }
86
90
  }, resolved.images.length > 0 ? { images: resolved.images } : undefined);
87
91
  return { ok: true };
88
92
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 上游(GitHub)最新版本号:新会话抬头的 `web v0.1.0` 靠它决定「要不要标红提醒有新版」。
2
+ * 上游(GitHub / npm)最新版本号:新会话抬头的 `web v0.1.0` 靠它决定「要不要标红提醒有新版」。
3
3
  *
4
4
  * 为什么是查上游而不是读本地两份 package.json:抬头那行是在说「我在跑哪个版本」,
5
5
  * 只有跟**已发布的版本**比,才知道「该不该提醒你去更新」。
@@ -16,8 +16,24 @@
16
16
  export const REPO_URL = "https://github.com/duzhenxun/oh-my-agent-web";
17
17
  /** 拿版本号的分支:跟 `main` 上的 package.json 对齐(发版就是改那里) */
18
18
  export const REPO_BRANCH = "main";
19
- /** 只要一个版本号,不必走 GitHub API(匿名 API 有速率限制,raw 没有) */
20
- export const VERSION_URL = `https://raw.githubusercontent.com/duzhenxun/oh-my-agent-web/${REPO_BRANCH}/package.json`;
19
+ /** 包名:npm registry / 升级命令都用它 */
20
+ export const PACKAGE_NAME = "oh-my-agent-web";
21
+ /**
22
+ * 查「最新已发布版本」的几个地址,按顺序试,第一个拿到值就算数:
23
+ *
24
+ * 1. **npm registry**:抬头那个「↑ 有新版」点下去装的就是 `@latest`(npm 上的包),
25
+ * 所以「有没有新版可以装」必须以它为准;反之若 main 上有个还没发版的 bump,
26
+ * 按 main 提示反而会让人白跑一趟安装。
27
+ * 2. **GitHub main 的 package.json**:registry 不通(内网/镜像/公司代理只放行 git)时的兜底。
28
+ *
29
+ * 两个都失败 → null = 不知道,界面不标红(绝不因为查不到就把人唬去找新版)。
30
+ */
31
+ export const VERSION_SOURCES = [
32
+ `https://registry.npmjs.org/${PACKAGE_NAME}/latest`,
33
+ `https://raw.githubusercontent.com/duzhenxun/${PACKAGE_NAME}/${REPO_BRANCH}/package.json`,
34
+ ];
35
+ /** 只查第一源(兼容老代码/测试里的显式 url 语义) */
36
+ export const VERSION_URL = VERSION_SOURCES[0];
21
37
  /** 一次请求最多等这么久:等不到就当没网 */
22
38
  export const FETCH_TIMEOUT_MS = 4000;
23
39
  /** 成功结果的保鲜期:6 小时(发版是低频事件,没必要频繁打人家的 CDN) */
@@ -69,19 +85,42 @@ export function isOutdated(latest, current) {
69
85
  return false; // 读不到本机版本时不给结论
70
86
  return compareVersions(latest, current) > 0;
71
87
  }
72
- /** 真去拉一次(不带缓存):任何异常都咽掉,返回 null */
88
+ /** 真去拉一次(不带缓存):任何异常都咽掉,返回 null
89
+ *
90
+ * 传了 `url` 就只查那一个(测试/调试用);不传则按 `VERSION_SOURCES` 依次试。
91
+ */
73
92
  export async function fetchLatestVersion(options = {}) {
74
- const fetchImpl = options.fetchImpl ?? globalThis.fetch;
93
+ const sources = options.url ? [options.url] : [...VERSION_SOURCES];
94
+ for (const url of sources) {
95
+ const found = await fetchVersionFrom(url, options.fetchImpl, options.timeoutMs);
96
+ if (found)
97
+ return found;
98
+ }
99
+ return null;
100
+ }
101
+ /** 从单个地址拉版本号:超时/非 2xx/解析不出 → null(换下一个源继续试) */
102
+ async function fetchVersionFrom(url, fetchImplOption, timeoutMs) {
103
+ const fetchImpl = fetchImplOption ?? globalThis.fetch;
75
104
  if (!fetchImpl)
76
105
  return null;
77
106
  const controller = new AbortController();
78
- const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? FETCH_TIMEOUT_MS);
107
+ const timer = setTimeout(() => controller.abort(), timeoutMs ?? FETCH_TIMEOUT_MS);
79
108
  timer.unref?.();
80
109
  try {
81
- const response = await fetchImpl(options.url ?? VERSION_URL, { signal: controller.signal });
110
+ const response = await fetchImpl(url, { signal: controller.signal });
82
111
  if (!response.ok)
83
112
  return null;
84
- return parseVersion(await response.text());
113
+ const text = await response.text();
114
+ // registry 返回的是完整 JSON:能 parse 就用字段,坏掉的(注释/尾逗号)退回正则抠
115
+ try {
116
+ const parsed = JSON.parse(text);
117
+ if (typeof parsed.version === "string" && parsed.version.trim() !== "")
118
+ return parsed.version.trim();
119
+ }
120
+ catch {
121
+ // 不是 JSON(package.json 原文)→ 往下走正则
122
+ }
123
+ return parseVersion(text);
85
124
  }
86
125
  catch {
87
126
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-agent-web",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "bin": {
5
5
  "oh-my-agent-web": "dist/server/cli.js",
6
6
  "omaw": "dist/server/cli.js",
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-D1HmdkA4.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CuHygcpj.js";import"./chunk-DSNLSHJZ-DEw1kFwj.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-CaWVF7qv.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-DeUJrhO1.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
1
+ import{m as e,t}from"./mermaid-parser.core-9OmqIOQj.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-DrBGN2Yi.js";import"./chunk-DSNLSHJZ-CQfLJsEG.js";import{n as i,r as a,t as o}from"./chunk-2E7WHVMD-B-50G064.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-B9yDV3Hs.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
@@ -1 +1 @@
1
- import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-VOk_Iv17.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i){if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
1
+ import{n as e,t}from"./path-fybaL0A-.js";import{a as n,c as r,d as i,f as a,i as o,l as s,m as c,n as l,o as u,p as d,r as f,u as p}from"./dist-BBxVlYHc.js";function m(e){return e.innerRadius}function h(e){return e.outerRadius}function g(e){return e.startAngle}function _(e){return e.endAngle}function v(e){return e&&e.padAngle}function y(e,t,n,r,i,a,o,s){var c=n-e,l=r-t,u=o-i,d=s-a,f=d*c-u*l;if(!(f*f<1e-12))return f=(u*(t-a)-d*(e-i))/f,[e+f*c,t+f*l]}function b(e,t,n,r,i,a,o){var c=e-n,l=t-r,u=(o?a:-a)/d(c*c+l*l),f=u*l,p=-u*c,m=e+f,h=t+p,g=n+f,_=r+p,v=(m+g)/2,y=(h+_)/2,b=g-m,x=_-h,S=b*b+x*x,C=i-a,w=m*_-g*h,T=(x<0?-1:1)*d(s(0,C*C*S-w*w)),E=(w*x-b*T)/S,D=(-w*b-x*T)/S,O=(w*x+b*T)/S,k=(-w*b+x*T)/S,A=E-v,j=D-y,M=O-v,N=k-y;return A*A+j*j>M*M+N*N&&(E=O,D=k),{cx:E,cy:D,x01:-f,y01:-p,x11:E*(i/C-1),y11:D*(i/C-1)}}function x(){var s=m,x=h,S=e(0),C=null,w=g,T=_,E=v,D=null,O=t(k);function k(){var e,t,m=+s.apply(this,arguments),h=+x.apply(this,arguments),g=w.apply(this,arguments)-r,_=T.apply(this,arguments)-r,v=l(_-g),k=_>g;if(D||=e=O(),h<m&&(t=h,h=m,m=t),!(h>1e-12))D.moveTo(0,0);else if(v>c-1e-12)D.moveTo(h*u(g),h*a(g)),D.arc(0,0,h,g,_,!k),m>1e-12&&(D.moveTo(m*u(_),m*a(_)),D.arc(0,0,m,_,g,k));else{var A=g,j=_,M=g,N=_,P=v,F=v,I=E.apply(this,arguments)/2,L=I>1e-12&&(C?+C.apply(this,arguments):d(m*m+h*h)),R=p(l(h-m)/2,+S.apply(this,arguments)),z=R,B=R,V,H;if(L>1e-12){var U=o(L/m*a(I)),W=o(L/h*a(I));(P-=U*2)>1e-12?(U*=k?1:-1,M+=U,N-=U):(P=0,M=N=(g+_)/2),(F-=W*2)>1e-12?(W*=k?1:-1,A+=W,j-=W):(F=0,A=j=(g+_)/2)}var G=h*u(A),K=h*a(A),q=m*u(N),J=m*a(N);if(R>1e-12){var Y=h*u(j),X=h*a(j),Z=m*u(M),Q=m*a(M),$;if(v<i){if($=y(G,K,Z,Q,Y,X,q,J)){var ee=G-$[0],te=K-$[1],ne=Y-$[0],re=X-$[1],ie=1/a(f((ee*ne+te*re)/(d(ee*ee+te*te)*d(ne*ne+re*re)))/2),ae=d($[0]*$[0]+$[1]*$[1]);z=p(R,(m-ae)/(ie-1)),B=p(R,(h-ae)/(ie+1))}else z=B=0}}F>1e-12?B>1e-12?(V=b(Z,Q,G,K,h,B,k),H=b(Y,X,q,J,h,B,k),D.moveTo(V.cx+V.x01,V.cy+V.y01),B<R?D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,B,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,h,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),!k),D.arc(H.cx,H.cy,B,n(H.y11,H.x11),n(H.y01,H.x01),!k))):(D.moveTo(G,K),D.arc(0,0,h,A,j,!k)):D.moveTo(G,K),!(m>1e-12)||!(P>1e-12)?D.lineTo(q,J):z>1e-12?(V=b(q,J,Y,X,m,-z,k),H=b(G,K,Z,Q,m,-z,k),D.lineTo(V.cx+V.x01,V.cy+V.y01),z<R?D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(H.y01,H.x01),!k):(D.arc(V.cx,V.cy,z,n(V.y01,V.x01),n(V.y11,V.x11),!k),D.arc(0,0,m,n(V.cy+V.y11,V.cx+V.x11),n(H.cy+H.y11,H.cx+H.x11),k),D.arc(H.cx,H.cy,z,n(H.y11,H.x11),n(H.y01,H.x01),!k))):D.arc(0,0,m,N,M,k)}if(D.closePath(),e)return D=null,e+``||null}return k.centroid=function(){var e=(+s.apply(this,arguments)+ +x.apply(this,arguments))/2,t=(+w.apply(this,arguments)+ +T.apply(this,arguments))/2-i/2;return[u(t)*e,a(t)*e]},k.innerRadius=function(t){return arguments.length?(s=typeof t==`function`?t:e(+t),k):s},k.outerRadius=function(t){return arguments.length?(x=typeof t==`function`?t:e(+t),k):x},k.cornerRadius=function(t){return arguments.length?(S=typeof t==`function`?t:e(+t),k):S},k.padRadius=function(t){return arguments.length?(C=t==null?null:typeof t==`function`?t:e(+t),k):C},k.startAngle=function(t){return arguments.length?(w=typeof t==`function`?t:e(+t),k):w},k.endAngle=function(t){return arguments.length?(T=typeof t==`function`?t:e(+t),k):T},k.padAngle=function(t){return arguments.length?(E=typeof t==`function`?t:e(+t),k):E},k.context=function(e){return arguments.length?(D=e??null,k):D},k}export{x as t};
@@ -1 +1 @@
1
- import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-D1HmdkA4.js";
1
+ import"./chunk-NGNAAXSQ-C2Wy9Xmz.js";export{M as createArchitectureServices}from"./mermaid-parser.core-9OmqIOQj.js";