@nocobase/app-plugin-agents 1.0.0-beta.29 → 2.0.0-beta.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.
- package/CHANGELOG.md +49 -0
- package/README.md +2 -19
- package/dist/client/api/client.d.ts +2 -2
- package/dist/client/api/client.d.ts.map +1 -1
- package/dist/client/api/client.js +2 -2
- package/dist/client/api/client.js.map +1 -1
- package/dist/client/api/runners.d.ts +2 -2
- package/dist/client/api/runners.d.ts.map +1 -1
- package/dist/client/api/runners.js +5 -2
- package/dist/client/api/runners.js.map +1 -1
- package/dist/client/chat/api.d.ts +1 -1
- package/dist/client/chat/api.d.ts.map +1 -1
- package/dist/client/chat/api.js +6 -2
- package/dist/client/chat/api.js.map +1 -1
- package/dist/client/chat/controller.d.ts +7 -5
- package/dist/client/chat/controller.d.ts.map +1 -1
- package/dist/client/chat/controller.js +186 -65
- package/dist/client/chat/controller.js.map +1 -1
- package/dist/client/chat/submissions.d.ts +2 -0
- package/dist/client/chat/submissions.d.ts.map +1 -1
- package/dist/client/chat/submissions.js +1 -0
- package/dist/client/chat/submissions.js.map +1 -1
- package/dist/client/chat/use-chat.d.ts.map +1 -1
- package/dist/client/chat/use-chat.js +2 -4
- package/dist/client/chat/use-chat.js.map +1 -1
- package/dist/client/components/ag-tag-tones.d.ts +7 -0
- package/dist/client/components/ag-tag-tones.d.ts.map +1 -0
- package/dist/client/components/ag-tag-tones.js +14 -0
- package/dist/client/components/ag-tag-tones.js.map +1 -0
- package/dist/client/components/ag-tag.d.ts +2 -1
- package/dist/client/components/ag-tag.d.ts.map +1 -1
- package/dist/client/components/ag-tag.js +1 -13
- package/dist/client/components/ag-tag.js.map +1 -1
- package/dist/client/components/quota-status.d.ts +2 -1
- package/dist/client/components/quota-status.d.ts.map +1 -1
- package/dist/client/components/quota-status.js +2 -2
- package/dist/client/components/quota-status.js.map +1 -1
- package/dist/client/components/ui/pagination.d.ts +6 -0
- package/dist/client/components/ui/pagination.d.ts.map +1 -0
- package/dist/client/components/ui/pagination.js +13 -0
- package/dist/client/components/ui/pagination.js.map +1 -0
- package/dist/client/hooks/use-notify.d.ts.map +1 -1
- package/dist/client/hooks/use-notify.js +4 -0
- package/dist/client/hooks/use-notify.js.map +1 -1
- package/dist/client/locales/de-DE.d.ts.map +1 -1
- package/dist/client/locales/de-DE.js +26 -10
- package/dist/client/locales/de-DE.js.map +1 -1
- package/dist/client/locales/en-US.d.ts +11 -0
- package/dist/client/locales/en-US.d.ts.map +1 -1
- package/dist/client/locales/en-US.js +21 -10
- package/dist/client/locales/en-US.js.map +1 -1
- package/dist/client/locales/es-ES.d.ts.map +1 -1
- package/dist/client/locales/es-ES.js +26 -10
- package/dist/client/locales/es-ES.js.map +1 -1
- package/dist/client/locales/fr-FR.d.ts.map +1 -1
- package/dist/client/locales/fr-FR.js +26 -10
- package/dist/client/locales/fr-FR.js.map +1 -1
- package/dist/client/locales/id-ID.d.ts.map +1 -1
- package/dist/client/locales/id-ID.js +26 -10
- package/dist/client/locales/id-ID.js.map +1 -1
- package/dist/client/locales/ja-JP.d.ts.map +1 -1
- package/dist/client/locales/ja-JP.js +26 -10
- package/dist/client/locales/ja-JP.js.map +1 -1
- package/dist/client/locales/pt-BR.d.ts.map +1 -1
- package/dist/client/locales/pt-BR.js +26 -10
- package/dist/client/locales/pt-BR.js.map +1 -1
- package/dist/client/locales/runtimes.en-US.d.ts +5 -0
- package/dist/client/locales/runtimes.en-US.d.ts.map +1 -1
- package/dist/client/locales/runtimes.en-US.js +5 -0
- package/dist/client/locales/runtimes.en-US.js.map +1 -1
- package/dist/client/locales/runtimes.zh-CN.d.ts.map +1 -1
- package/dist/client/locales/runtimes.zh-CN.js +5 -0
- package/dist/client/locales/runtimes.zh-CN.js.map +1 -1
- package/dist/client/locales/vi-VN.d.ts.map +1 -1
- package/dist/client/locales/vi-VN.js +26 -10
- package/dist/client/locales/vi-VN.js.map +1 -1
- package/dist/client/locales/zh-CN.d.ts.map +1 -1
- package/dist/client/locales/zh-CN.js +21 -10
- package/dist/client/locales/zh-CN.js.map +1 -1
- package/dist/client/locales/zh-TW.d.ts.map +1 -1
- package/dist/client/locales/zh-TW.js +26 -10
- package/dist/client/locales/zh-TW.js.map +1 -1
- package/dist/client/model-suggestion.d.ts +2 -0
- package/dist/client/model-suggestion.d.ts.map +1 -1
- package/dist/client/model-suggestion.js +27 -2
- package/dist/client/model-suggestion.js.map +1 -1
- package/dist/client/pages/agents/agent-dialog.d.ts.map +1 -1
- package/dist/client/pages/agents/agent-dialog.js +6 -7
- package/dist/client/pages/agents/agent-dialog.js.map +1 -1
- package/dist/client/pages/agents/available-models-drawer.d.ts.map +1 -1
- package/dist/client/pages/agents/available-models-drawer.js +2 -1
- package/dist/client/pages/agents/available-models-drawer.js.map +1 -1
- package/dist/client/pages/agents/good-at-templates.d.ts +8 -0
- package/dist/client/pages/agents/good-at-templates.d.ts.map +1 -0
- package/dist/client/pages/agents/good-at-templates.js +29 -0
- package/dist/client/pages/agents/good-at-templates.js.map +1 -0
- package/dist/client/pages/runtimes/runner-cells.d.ts.map +1 -1
- package/dist/client/pages/runtimes/runner-cells.js +3 -1
- package/dist/client/pages/runtimes/runner-cells.js.map +1 -1
- package/dist/client/pages/runtimes/runner-pagination.d.ts +15 -0
- package/dist/client/pages/runtimes/runner-pagination.d.ts.map +1 -0
- package/dist/client/pages/runtimes/runner-pagination.js +9 -0
- package/dist/client/pages/runtimes/runner-pagination.js.map +1 -0
- package/dist/client/pages/runtimes/runner-runs.d.ts +3 -2
- package/dist/client/pages/runtimes/runner-runs.d.ts.map +1 -1
- package/dist/client/pages/runtimes/runner-runs.js +38 -15
- package/dist/client/pages/runtimes/runner-runs.js.map +1 -1
- package/dist/client/pages/runtimes/runner-sheet.js +1 -1
- package/dist/client/pages/runtimes/runner-sheet.js.map +1 -1
- package/dist/client/pages/runtimes/runner-workspaces.d.ts.map +1 -1
- package/dist/client/pages/runtimes/runner-workspaces.js +7 -3
- package/dist/client/pages/runtimes/runner-workspaces.js.map +1 -1
- package/dist/client/runs/refresh-run.d.ts +4 -0
- package/dist/client/runs/refresh-run.d.ts.map +1 -0
- package/dist/client/runs/refresh-run.js +8 -0
- package/dist/client/runs/refresh-run.js.map +1 -0
- package/dist/client/runs/run-hooks.d.ts.map +1 -1
- package/dist/client/runs/run-hooks.js +2 -1
- package/dist/client/runs/run-hooks.js.map +1 -1
- package/dist/database/migrations/.manifest.json +8 -0
- package/dist/database/migrations/202611010003_ag_runner_run_history_index.d.ts +4 -0
- package/dist/database/migrations/202611010003_ag_runner_run_history_index.d.ts.map +1 -0
- package/dist/database/migrations/202611010003_ag_runner_run_history_index.js +17 -0
- package/dist/database/migrations/202611010003_ag_runner_run_history_index.js.map +1 -0
- package/dist/database/migrations/202611070001_ag_conversation_project.d.ts +4 -0
- package/dist/database/migrations/202611070001_ag_conversation_project.d.ts.map +1 -0
- package/dist/database/migrations/202611070001_ag_conversation_project.js +17 -0
- package/dist/database/migrations/202611070001_ag_conversation_project.js.map +1 -0
- package/dist/package.json +4 -6
- package/dist/server/composition.d.ts +0 -17
- package/dist/server/composition.d.ts.map +1 -1
- package/dist/server/composition.js +7 -20
- package/dist/server/composition.js.map +1 -1
- package/dist/server/core/conversations/conversation.service.d.ts.map +1 -1
- package/dist/server/core/conversations/conversation.service.js +160 -19
- package/dist/server/core/conversations/conversation.service.js.map +1 -1
- package/dist/server/core/conversations/conversation.store.d.ts +1 -0
- package/dist/server/core/conversations/conversation.store.d.ts.map +1 -1
- package/dist/server/core/conversations/conversation.store.js.map +1 -1
- package/dist/server/core/conversations/index.d.ts +1 -1
- package/dist/server/core/conversations/index.d.ts.map +1 -1
- package/dist/server/core/conversations/index.js.map +1 -1
- package/dist/server/core/conversations/ports.d.ts +14 -0
- package/dist/server/core/conversations/ports.d.ts.map +1 -1
- package/dist/server/core/runs/claim.d.ts +7 -1
- package/dist/server/core/runs/claim.d.ts.map +1 -1
- package/dist/server/core/runs/claim.js +69 -17
- package/dist/server/core/runs/claim.js.map +1 -1
- package/dist/server/core/runs/ports.d.ts +2 -0
- package/dist/server/core/runs/ports.d.ts.map +1 -1
- package/dist/server/core/runs/ports.js.map +1 -1
- package/dist/server/core/runs/run.service.d.ts +5 -0
- package/dist/server/core/runs/run.service.d.ts.map +1 -1
- package/dist/server/core/runs/run.service.js +22 -0
- package/dist/server/core/runs/run.service.js.map +1 -1
- package/dist/server/core/runs/run.store.d.ts +1 -1
- package/dist/server/core/runs/run.store.d.ts.map +1 -1
- package/dist/server/core/runs/run.store.js +1 -1
- package/dist/server/core/runs/run.store.js.map +1 -1
- package/dist/server/core/runs/runner-view.d.ts +8 -4
- package/dist/server/core/runs/runner-view.d.ts.map +1 -1
- package/dist/server/core/runs/runner-view.js +89 -32
- package/dist/server/core/runs/runner-view.js.map +1 -1
- package/dist/server/locales/de-DE.d.ts.map +1 -1
- package/dist/server/locales/de-DE.js +5 -0
- package/dist/server/locales/de-DE.js.map +1 -1
- package/dist/server/locales/en-US.d.ts +7 -1
- package/dist/server/locales/en-US.d.ts.map +1 -1
- package/dist/server/locales/en-US.js +5 -0
- package/dist/server/locales/en-US.js.map +1 -1
- package/dist/server/locales/es-ES.d.ts.map +1 -1
- package/dist/server/locales/es-ES.js +5 -0
- package/dist/server/locales/es-ES.js.map +1 -1
- package/dist/server/locales/fr-FR.d.ts.map +1 -1
- package/dist/server/locales/fr-FR.js +5 -0
- package/dist/server/locales/fr-FR.js.map +1 -1
- package/dist/server/locales/id-ID.d.ts.map +1 -1
- package/dist/server/locales/id-ID.js +5 -0
- package/dist/server/locales/id-ID.js.map +1 -1
- package/dist/server/locales/ja-JP.d.ts.map +1 -1
- package/dist/server/locales/ja-JP.js +5 -0
- package/dist/server/locales/ja-JP.js.map +1 -1
- package/dist/server/locales/pt-BR.d.ts.map +1 -1
- package/dist/server/locales/pt-BR.js +5 -0
- package/dist/server/locales/pt-BR.js.map +1 -1
- package/dist/server/locales/vi-VN.d.ts.map +1 -1
- package/dist/server/locales/vi-VN.js +5 -0
- package/dist/server/locales/vi-VN.js.map +1 -1
- package/dist/server/locales/zh-CN.d.ts +2 -2
- package/dist/server/locales/zh-CN.d.ts.map +1 -1
- package/dist/server/locales/zh-CN.js +5 -0
- package/dist/server/locales/zh-CN.js.map +1 -1
- package/dist/server/locales/zh-TW.d.ts.map +1 -1
- package/dist/server/locales/zh-TW.js +5 -0
- package/dist/server/locales/zh-TW.js.map +1 -1
- package/dist/server/online/agent/native/backend.d.ts.map +1 -1
- package/dist/server/online/agent/native/backend.js +2 -0
- package/dist/server/online/agent/native/backend.js.map +1 -1
- package/dist/server/online/agent/native/session.d.ts.map +1 -1
- package/dist/server/online/agent/native/session.js +3 -1
- package/dist/server/online/agent/native/session.js.map +1 -1
- package/dist/server/online/agent/runner/backend.d.ts.map +1 -1
- package/dist/server/online/agent/runner/backend.js +4 -1
- package/dist/server/online/agent/runner/backend.js.map +1 -1
- package/dist/server/online/agent/runner/projection.d.ts +1 -1
- package/dist/server/online/agent/runner/projection.d.ts.map +1 -1
- package/dist/server/online/agent/runner/projection.js +33 -3
- package/dist/server/online/agent/runner/projection.js.map +1 -1
- package/dist/server/online/agent/service.d.ts.map +1 -1
- package/dist/server/online/agent/service.js +3 -0
- package/dist/server/online/agent/service.js.map +1 -1
- package/dist/server/online/agent/types.d.ts +3 -0
- package/dist/server/online/agent/types.d.ts.map +1 -1
- package/dist/server/providers/agents.d.ts +5 -9
- package/dist/server/providers/agents.d.ts.map +1 -1
- package/dist/server/providers/agents.js +9 -13
- package/dist/server/providers/agents.js.map +1 -1
- package/dist/server/routes/chat.d.ts.map +1 -1
- package/dist/server/routes/chat.js +37 -0
- package/dist/server/routes/chat.js.map +1 -1
- package/dist/server/routes/runners/admin.d.ts.map +1 -1
- package/dist/server/routes/runners/admin.js +16 -7
- package/dist/server/routes/runners/admin.js.map +1 -1
- package/dist/server/routes/runners/runner.d.ts.map +1 -1
- package/dist/server/routes/runners/runner.js +6 -4
- package/dist/server/routes/runners/runner.js.map +1 -1
- package/dist/server/routes/schemas.d.ts +7 -1
- package/dist/server/routes/schemas.d.ts.map +1 -1
- package/dist/server/routes/schemas.js +41 -1
- package/dist/server/routes/schemas.js.map +1 -1
- package/dist/server/tokens.d.ts +1 -2
- package/dist/server/tokens.d.ts.map +1 -1
- package/dist/server/tokens.js.map +1 -1
- package/dist/shared/conversations.d.ts +16 -0
- package/dist/shared/conversations.d.ts.map +1 -1
- package/dist/shared/conversations.js.map +1 -1
- package/dist/shared/runners.d.ts +18 -2
- package/dist/shared/runners.d.ts.map +1 -1
- package/dist/shared/runners.js +20 -0
- package/dist/shared/runners.js.map +1 -1
- package/dist/shared/ui-message.d.ts +2 -0
- package/dist/shared/ui-message.d.ts.map +1 -1
- package/dist/shared/ui-message.js +1 -0
- package/dist/shared/ui-message.js.map +1 -1
- package/docs/ui-message-clients.md +5 -1
- package/docs/ui-messages.md +3 -1
- package/docs/vectors-migration.md +91 -0
- package/package.json +8 -10
- package/skills/nocobase-app-plugin-agents/SKILL.md +1 -1
- package/skills/nocobase-app-plugin-agents/references/extension-points.md +0 -1
- package/skills/nocobase-app-plugin-agents/references/model-services.md +3 -3
- package/skills/nocobase-app-plugin-agents/references/online-agent.md +6 -0
- package/skills/nocobase-app-plugin-agents/references/setup-and-config.md +0 -4
- package/skills/nocobase-app-plugin-agents/references/verification-and-troubleshooting.md +0 -2
- package/dist/server/vectors/index.d.ts +0 -7
- package/dist/server/vectors/index.d.ts.map +0 -1
- package/dist/server/vectors/index.js +0 -6
- package/dist/server/vectors/index.js.map +0 -1
- package/dist/server/vectors/naming.d.ts +0 -6
- package/dist/server/vectors/naming.d.ts.map +0 -1
- package/dist/server/vectors/naming.js +0 -15
- package/dist/server/vectors/naming.js.map +0 -1
- package/dist/server/vectors/pgvector.d.ts +0 -26
- package/dist/server/vectors/pgvector.d.ts.map +0 -1
- package/dist/server/vectors/pgvector.js +0 -346
- package/dist/server/vectors/pgvector.js.map +0 -1
- package/dist/server/vectors/sqlite-vec.d.ts +0 -14
- package/dist/server/vectors/sqlite-vec.d.ts.map +0 -1
- package/dist/server/vectors/sqlite-vec.js +0 -286
- package/dist/server/vectors/sqlite-vec.js.map +0 -1
- package/dist/server/vectors/types.d.ts +0 -256
- package/dist/server/vectors/types.d.ts.map +0 -1
- package/dist/server/vectors/types.js +0 -2
- package/dist/server/vectors/types.js.map +0 -1
- package/dist/server/vectors/vectors.d.ts +0 -34
- package/dist/server/vectors/vectors.d.ts.map +0 -1
- package/dist/server/vectors/vectors.js +0 -866
- package/dist/server/vectors/vectors.js.map +0 -1
|
@@ -31,9 +31,7 @@ export class ChatController {
|
|
|
31
31
|
histories = new Map();
|
|
32
32
|
loads = new Map();
|
|
33
33
|
refreshAgain = new Set();
|
|
34
|
-
|
|
35
|
-
resuming = new Map();
|
|
36
|
-
recoveryErrors = new Map();
|
|
34
|
+
recoveries = new Map();
|
|
37
35
|
admissions = new Map();
|
|
38
36
|
watches = new Map();
|
|
39
37
|
messageVersions = new Map();
|
|
@@ -47,6 +45,7 @@ export class ChatController {
|
|
|
47
45
|
disposed = false;
|
|
48
46
|
generation = 0;
|
|
49
47
|
detailVersions = new Map();
|
|
48
|
+
receiptVersions = new Map();
|
|
50
49
|
commandVersions = new Map();
|
|
51
50
|
constructor(api) {
|
|
52
51
|
this.api = api;
|
|
@@ -69,7 +68,22 @@ export class ChatController {
|
|
|
69
68
|
const admission = this.admissions.get(id);
|
|
70
69
|
if (!this.disposed && admission?.clientId === clientId)
|
|
71
70
|
admission.gate.resolve();
|
|
72
|
-
}, (options) => this.resendAccepted(id, options))
|
|
71
|
+
}, (options) => this.resendAccepted(id, options), () => {
|
|
72
|
+
const active = this.lifetime(), recovery = this.recoveries.get(id);
|
|
73
|
+
return (available) => {
|
|
74
|
+
if (!active() ||
|
|
75
|
+
this.chats.get(id) !== chat ||
|
|
76
|
+
!recovery ||
|
|
77
|
+
this.recoveries.get(id) !== recovery)
|
|
78
|
+
return;
|
|
79
|
+
recovery.phase = available ? 'live' : 'history';
|
|
80
|
+
recovery.error = undefined;
|
|
81
|
+
// Reads started before reconnection must not replace its replay or revive old errors.
|
|
82
|
+
this.nextDetailVersion(id);
|
|
83
|
+
this.invalidateHistoryReads(id);
|
|
84
|
+
this.publish();
|
|
85
|
+
};
|
|
86
|
+
}),
|
|
73
87
|
onFinish: () => {
|
|
74
88
|
if (!this.disposed && this.chats.get(id) === chat)
|
|
75
89
|
this.scheduleRefresh(id);
|
|
@@ -180,15 +194,18 @@ export class ChatController {
|
|
|
180
194
|
this.publish();
|
|
181
195
|
}
|
|
182
196
|
historyLifetime(id) {
|
|
183
|
-
const active = this.lifetime(), epoch = this.historyEpochs.get(id) ?? 0;
|
|
184
|
-
return () => active() &&
|
|
197
|
+
const active = this.lifetime(), epoch = this.historyEpochs.get(id) ?? 0, command = this.commandVersions.get(id);
|
|
198
|
+
return () => active() &&
|
|
199
|
+
(this.historyEpochs.get(id) ?? 0) === epoch &&
|
|
200
|
+
this.commandVersions.get(id) === command;
|
|
185
201
|
}
|
|
186
|
-
invalidateHistoryReads(id) {
|
|
202
|
+
invalidateHistoryReads(id, discardDeferred = false) {
|
|
187
203
|
this.historyEpochs.set(id, (this.historyEpochs.get(id) ?? 0) + 1);
|
|
188
204
|
this.loads.delete(id);
|
|
189
205
|
this.refreshAgain.delete(id);
|
|
190
206
|
this.revisionQueue.delete(id);
|
|
191
|
-
|
|
207
|
+
if (discardDeferred)
|
|
208
|
+
this.deferredReads.delete(id);
|
|
192
209
|
for (const key of this.messageVersions.keys())
|
|
193
210
|
if (key.startsWith(`${id}:`))
|
|
194
211
|
this.messageVersions.delete(key);
|
|
@@ -221,8 +238,8 @@ export class ChatController {
|
|
|
221
238
|
if (previous?.executionId === event.executionId ||
|
|
222
239
|
(previous && previous.lastSeq > event.lastSeq))
|
|
223
240
|
return false;
|
|
224
|
-
this.invalidateHistoryReads(id);
|
|
225
|
-
this.
|
|
241
|
+
this.invalidateHistoryReads(id, true);
|
|
242
|
+
this.recoveries.delete(id);
|
|
226
243
|
this.replacements.set(id, event);
|
|
227
244
|
this.dispatch(id, { type: 'replaceHistory', ...event });
|
|
228
245
|
this.historyMeta(id).loadedThrough = Math.max(this.historyMeta(id).loadedThrough, event.lastSeq);
|
|
@@ -664,14 +681,16 @@ export class ChatController {
|
|
|
664
681
|
async sendInput(id, input) {
|
|
665
682
|
if (this.disposed)
|
|
666
683
|
throw new CancelledError({ silent: true });
|
|
667
|
-
|
|
684
|
+
let chat = this.chat(id);
|
|
668
685
|
if (chat.status === 'submitted' || chat.status === 'streaming')
|
|
669
686
|
throw new Error('This conversation is already receiving a response.');
|
|
670
687
|
if (this.resendRequests.has(id))
|
|
671
688
|
throw new Error('This conversation is busy.');
|
|
672
689
|
const admitted = deferred();
|
|
673
690
|
this.admissions.set(id, { clientId: input.clientId, gate: admitted });
|
|
674
|
-
this.
|
|
691
|
+
this.recoveries.delete(id);
|
|
692
|
+
// A new turn owns its callbacks, including when the previous transport finishes late.
|
|
693
|
+
chat = this.renewChat(id, chat.messages);
|
|
675
694
|
const active = this.lifetime();
|
|
676
695
|
const sending = chat.sendMessage({
|
|
677
696
|
id: input.clientId,
|
|
@@ -697,6 +716,7 @@ export class ChatController {
|
|
|
697
716
|
}, {
|
|
698
717
|
body: {
|
|
699
718
|
...(input.agentId ? { agentId: input.agentId } : {}),
|
|
719
|
+
...(input.effort !== undefined ? { effort: input.effort } : {}),
|
|
700
720
|
...(input.context ? { context: input.context } : {}),
|
|
701
721
|
...(input.attachmentIds?.length
|
|
702
722
|
? { attachmentIds: input.attachmentIds }
|
|
@@ -727,42 +747,82 @@ export class ChatController {
|
|
|
727
747
|
}
|
|
728
748
|
state(id) {
|
|
729
749
|
const chat = this.chats.get(id);
|
|
750
|
+
const recovery = this.recoveries.get(id);
|
|
751
|
+
const recovering = recovery?.phase === 'recovering';
|
|
752
|
+
const error = recovering ? undefined : (chat?.error ?? recovery?.error);
|
|
730
753
|
return chat
|
|
731
754
|
? {
|
|
732
755
|
status: chat.status,
|
|
733
|
-
error
|
|
756
|
+
error,
|
|
757
|
+
recovery: recovering
|
|
758
|
+
? 'recovering'
|
|
759
|
+
: error
|
|
760
|
+
? 'interrupted'
|
|
761
|
+
: recovery?.phase === 'history'
|
|
762
|
+
? 'history'
|
|
763
|
+
: undefined,
|
|
734
764
|
}
|
|
735
765
|
: undefined;
|
|
736
766
|
}
|
|
767
|
+
recoveryKey(id, detail) {
|
|
768
|
+
return (detail.run?.id ??
|
|
769
|
+
detail.execution?.messageId ??
|
|
770
|
+
(detail.execution?.status === 'running'
|
|
771
|
+
? this.recoveries.get(id)?.key
|
|
772
|
+
: undefined) ??
|
|
773
|
+
[...this.chat(id).messages].reverse().find((m) => m.role === 'user')
|
|
774
|
+
?.id ??
|
|
775
|
+
'');
|
|
776
|
+
}
|
|
737
777
|
receive(id, known) {
|
|
738
|
-
if (this.disposed
|
|
778
|
+
if (this.disposed)
|
|
739
779
|
return;
|
|
740
780
|
const detail = known ??
|
|
741
781
|
agentsQueryClient().getQueryData(chatKeys.conversation(id));
|
|
742
|
-
if (!detail
|
|
743
|
-
|
|
744
|
-
this.resumed.add(id);
|
|
745
|
-
if (detail?.execution?.status === 'idle' ||
|
|
746
|
-
detail?.execution?.waitingApproval)
|
|
782
|
+
if (!detail ||
|
|
783
|
+
this.recoveries.get(id)?.key === this.recoveryKey(id, detail))
|
|
747
784
|
return;
|
|
748
|
-
void this.resume(id);
|
|
785
|
+
void this.resume(id, detail);
|
|
749
786
|
}
|
|
750
|
-
async resume(id) {
|
|
787
|
+
async resume(id, known) {
|
|
751
788
|
if (this.disposed)
|
|
752
789
|
return;
|
|
753
|
-
const
|
|
754
|
-
|
|
755
|
-
|
|
790
|
+
const detail = known ??
|
|
791
|
+
agentsQueryClient().getQueryData(chatKeys.conversation(id));
|
|
792
|
+
if (!detail)
|
|
793
|
+
return;
|
|
794
|
+
if (!chatIsRunning(detail) || detail.execution?.waitingApproval) {
|
|
795
|
+
const chat = this.chats.get(id);
|
|
796
|
+
if (chat?.status !== 'submitted' && chat?.status !== 'streaming')
|
|
797
|
+
await this.loadHistory(id);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
800
|
+
const key = this.recoveryKey(id, detail);
|
|
801
|
+
const pending = this.recoveries.get(id);
|
|
756
802
|
let chat = this.chat(id);
|
|
757
|
-
if (chat.status === 'submitted' || chat.status === 'streaming')
|
|
803
|
+
if (chat.status === 'submitted' || chat.status === 'streaming') {
|
|
804
|
+
if (!pending || pending.key !== key)
|
|
805
|
+
this.recoveries.set(id, { key, phase: 'live' });
|
|
758
806
|
return;
|
|
807
|
+
}
|
|
808
|
+
if (pending?.key === key) {
|
|
809
|
+
if (pending.task)
|
|
810
|
+
return pending.task;
|
|
811
|
+
if (pending.phase === 'history')
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
759
814
|
const active = this.lifetime();
|
|
760
815
|
const replacement = this.replacements.get(id);
|
|
761
|
-
const
|
|
816
|
+
const command = this.commandVersions.get(id);
|
|
817
|
+
const recovery = { key, phase: 'recovering' };
|
|
818
|
+
this.recoveries.set(id, recovery);
|
|
819
|
+
this.publish();
|
|
820
|
+
const current = () => active() &&
|
|
821
|
+
this.commandVersions.get(id) === command &&
|
|
822
|
+
this.recoveries.get(id) === recovery &&
|
|
762
823
|
this.replacements.get(id) === replacement &&
|
|
763
|
-
this.chats.get(id) === chat
|
|
764
|
-
|
|
765
|
-
chat.status !== 'streaming';
|
|
824
|
+
this.chats.get(id) === chat;
|
|
825
|
+
const canResume = () => current() && chat.status !== 'submitted' && chat.status !== 'streaming';
|
|
766
826
|
const task = (async () => {
|
|
767
827
|
let interrupted;
|
|
768
828
|
try {
|
|
@@ -770,6 +830,8 @@ export class ChatController {
|
|
|
770
830
|
// A new input can begin while the recovery snapshot is still being read.
|
|
771
831
|
if (!canResume())
|
|
772
832
|
return;
|
|
833
|
+
if (this.history(id).error)
|
|
834
|
+
throw this.history(id).error;
|
|
773
835
|
if (chat.error) {
|
|
774
836
|
const previous = chat;
|
|
775
837
|
interrupted = [...previous.messages]
|
|
@@ -790,36 +852,57 @@ export class ChatController {
|
|
|
790
852
|
if (!active())
|
|
791
853
|
return;
|
|
792
854
|
}
|
|
793
|
-
this.recoveryErrors.delete(id);
|
|
794
855
|
chat.clearError();
|
|
795
856
|
const response = [...chat.messages]
|
|
796
857
|
.reverse()
|
|
797
858
|
.find((message) => message.role === 'assistant');
|
|
798
|
-
if (response
|
|
859
|
+
if (response &&
|
|
860
|
+
(response === interrupted ||
|
|
861
|
+
!key ||
|
|
862
|
+
response.metadata?.executionId === key ||
|
|
863
|
+
response.id === detail.execution?.messageId)) {
|
|
864
|
+
interrupted ??= response;
|
|
799
865
|
chat.messages = mergeUIMessages(chat.messages, [], response.id);
|
|
866
|
+
}
|
|
800
867
|
await chat.resumeStream();
|
|
801
|
-
if (
|
|
868
|
+
if (current()) {
|
|
869
|
+
if (chat.error) {
|
|
870
|
+
recovery.phase = 'interrupted';
|
|
871
|
+
recovery.error = chat.error;
|
|
872
|
+
}
|
|
802
873
|
await this.refresh(id);
|
|
874
|
+
}
|
|
803
875
|
}
|
|
804
876
|
catch (error) {
|
|
805
|
-
if (
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
877
|
+
if (current()) {
|
|
878
|
+
if (chat.error) {
|
|
879
|
+
recovery.phase = 'interrupted';
|
|
880
|
+
recovery.error = chat.error;
|
|
881
|
+
}
|
|
882
|
+
else {
|
|
883
|
+
// A failed history read is not evidence that the transport failed.
|
|
884
|
+
this.historyMeta(id).error = error;
|
|
885
|
+
if (recovery.phase === 'recovering')
|
|
886
|
+
recovery.phase = 'live';
|
|
887
|
+
}
|
|
888
|
+
}
|
|
809
889
|
}
|
|
810
890
|
finally {
|
|
811
|
-
if (
|
|
891
|
+
if (current()) {
|
|
812
892
|
const display = interrupted;
|
|
813
893
|
if (display &&
|
|
814
894
|
canResume() &&
|
|
815
895
|
!chat.messages.some((message) => message.id === display.id))
|
|
816
896
|
chat.messages = mergeUIMessages(chat.messages, [display]);
|
|
817
|
-
|
|
897
|
+
recovery.task = undefined;
|
|
898
|
+
if (recovery.phase === 'recovering' &&
|
|
899
|
+
(chat.status === 'submitted' || chat.status === 'streaming'))
|
|
900
|
+
recovery.phase = 'live';
|
|
818
901
|
this.publish();
|
|
819
902
|
}
|
|
820
903
|
}
|
|
821
904
|
})();
|
|
822
|
-
|
|
905
|
+
recovery.task = task;
|
|
823
906
|
return task;
|
|
824
907
|
}
|
|
825
908
|
async approve(id, input) {
|
|
@@ -867,7 +950,13 @@ export class ChatController {
|
|
|
867
950
|
async refresh(id) {
|
|
868
951
|
if (this.disposed)
|
|
869
952
|
return;
|
|
870
|
-
const
|
|
953
|
+
const lifetime = this.lifetime(), commandVersion = this.commandVersions.get(id), active = () => lifetime() && this.commandVersions.get(id) === commandVersion, ordered = this.detailRequest(id);
|
|
954
|
+
const submittedOwner = this.chat(id);
|
|
955
|
+
const submittedInput = submittedOwner.status === 'submitted' && !this.admissions.has(id)
|
|
956
|
+
? [...submittedOwner.messages]
|
|
957
|
+
.reverse()
|
|
958
|
+
.find((message) => message.role === 'user' && message.metadata?.seq !== undefined)
|
|
959
|
+
: undefined;
|
|
871
960
|
const detail = await this.api.conversation(id);
|
|
872
961
|
if (!active())
|
|
873
962
|
return;
|
|
@@ -878,7 +967,7 @@ export class ChatController {
|
|
|
878
967
|
// A newer detail query must not discard this refresh's message catch-up.
|
|
879
968
|
// loadHistory coalesces overlapping reads independently of detail ordering.
|
|
880
969
|
await this.loadHistory(id, false, true);
|
|
881
|
-
if (!active()
|
|
970
|
+
if (!active())
|
|
882
971
|
return;
|
|
883
972
|
const history = this.history(id);
|
|
884
973
|
if (history.error)
|
|
@@ -903,14 +992,29 @@ export class ChatController {
|
|
|
903
992
|
if (!active() || !ordered())
|
|
904
993
|
return;
|
|
905
994
|
const owner = this.chat(id), receiving = owner.messages.at(-1);
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
(
|
|
909
|
-
|
|
910
|
-
|
|
995
|
+
const lastUser = [...owner.messages]
|
|
996
|
+
.reverse()
|
|
997
|
+
.find((message) => message.role === 'user');
|
|
998
|
+
const executionId = submittedInput?.metadata?.executionId ?? this.recoveries.get(id)?.key;
|
|
999
|
+
const submittedTerminal = owner === submittedOwner &&
|
|
1000
|
+
owner.status === 'submitted' &&
|
|
1001
|
+
submittedInput &&
|
|
1002
|
+
lastUser?.id === submittedInput.id &&
|
|
1003
|
+
detail.execution?.status === 'idle' &&
|
|
1004
|
+
[...saved, ...owner.messages].some((message) => message.role !== 'user' &&
|
|
911
1005
|
message.metadata?.seq !== undefined &&
|
|
912
|
-
message.metadata
|
|
913
|
-
message.metadata.
|
|
1006
|
+
message.metadata.seq > submittedInput.metadata.seq &&
|
|
1007
|
+
((executionId && message.metadata.executionId === executionId) ||
|
|
1008
|
+
message.id === detail.execution?.messageId));
|
|
1009
|
+
if (submittedTerminal ||
|
|
1010
|
+
(owner.status === 'streaming' &&
|
|
1011
|
+
receiving?.role === 'assistant' &&
|
|
1012
|
+
(detail.execution?.status === 'idle' ||
|
|
1013
|
+
detail.execution?.waitingApproval) &&
|
|
1014
|
+
saved.some((message) => message.id === receiving.id &&
|
|
1015
|
+
message.metadata?.seq !== undefined &&
|
|
1016
|
+
message.metadata?.executionId === receiving.metadata?.executionId &&
|
|
1017
|
+
message.metadata.revision >= (detail.execution?.revision ?? 0)))) {
|
|
914
1018
|
// Durable completion can release a lost subscriber; this never calls business Stop.
|
|
915
1019
|
await owner.stop();
|
|
916
1020
|
if (!active() || !ordered())
|
|
@@ -919,20 +1023,13 @@ export class ChatController {
|
|
|
919
1023
|
}
|
|
920
1024
|
if (!active() || !ordered())
|
|
921
1025
|
return;
|
|
922
|
-
this.remember(detail);
|
|
1026
|
+
this.remember(detail, false);
|
|
923
1027
|
const chat = this.chat(id);
|
|
924
1028
|
if (detail.execution?.status === 'idle') {
|
|
925
|
-
this.
|
|
926
|
-
if (chat.error
|
|
927
|
-
saved.some((message) => message.id === chat.messages.at(-1)?.id &&
|
|
928
|
-
message.metadata?.seq !== undefined))
|
|
1029
|
+
this.recoveries.delete(id);
|
|
1030
|
+
if (chat.error)
|
|
929
1031
|
this.renewChat(id, chat.messages);
|
|
930
1032
|
}
|
|
931
|
-
else if (detail.execution?.status === 'running' &&
|
|
932
|
-
!detail.execution.waitingApproval &&
|
|
933
|
-
chat.status !== 'submitted' &&
|
|
934
|
-
chat.status !== 'streaming')
|
|
935
|
-
this.recoveryErrors.set(id, new Error('Execution remains active; reconcile saved history or resume its stream.'));
|
|
936
1033
|
this.publish();
|
|
937
1034
|
}
|
|
938
1035
|
scheduleRefresh(id) {
|
|
@@ -945,14 +1042,16 @@ export class ChatController {
|
|
|
945
1042
|
void this.refresh(id).catch(() => { });
|
|
946
1043
|
});
|
|
947
1044
|
}
|
|
948
|
-
observeDetail(detail) {
|
|
1045
|
+
observeDetail(detail, refresh = true) {
|
|
949
1046
|
if (detail.execution?.status === 'running')
|
|
950
1047
|
this.receive(detail.id, detail);
|
|
951
1048
|
if (!chatIsRunning(detail)) {
|
|
952
|
-
if (
|
|
1049
|
+
if (refresh &&
|
|
1050
|
+
(this.chats.get(detail.id)?.status === 'streaming' ||
|
|
1051
|
+
this.chats.get(detail.id)?.status === 'submitted'))
|
|
953
1052
|
this.scheduleRefresh(detail.id);
|
|
954
1053
|
this.stopRequests.delete(detail.id);
|
|
955
|
-
this.
|
|
1054
|
+
this.recoveries.delete(detail.id);
|
|
956
1055
|
this.publish();
|
|
957
1056
|
}
|
|
958
1057
|
}
|
|
@@ -987,16 +1086,38 @@ export class ChatController {
|
|
|
987
1086
|
const active = this.lifetime(), version = this.nextDetailVersion(id);
|
|
988
1087
|
return () => active() && this.detailVersions.get(id) === version;
|
|
989
1088
|
}
|
|
990
|
-
remember(detail) {
|
|
1089
|
+
remember(detail, refresh = true) {
|
|
991
1090
|
this.nextDetailVersion(detail.id);
|
|
992
|
-
this.observeDetail(detail);
|
|
1091
|
+
this.observeDetail(detail, refresh);
|
|
993
1092
|
agentsQueryClient().setQueryData(chatKeys.conversation(detail.id), detail);
|
|
994
1093
|
void agentsQueryClient().invalidateQueries({ queryKey: chatKeys.lists });
|
|
995
1094
|
}
|
|
1095
|
+
async markRead(id) {
|
|
1096
|
+
const active = this.lifetime(), commandVersion = this.commandVersions.get(id), receiptVersion = (this.receiptVersions.get(id) ?? 0) + 1;
|
|
1097
|
+
// Detail reads must not suppress the read transition needed by a viewed conversation.
|
|
1098
|
+
this.receiptVersions.set(id, receiptVersion);
|
|
1099
|
+
this.nextDetailVersion(id);
|
|
1100
|
+
const detail = await this.api.markRead(id);
|
|
1101
|
+
if (active() &&
|
|
1102
|
+
this.commandVersions.get(id) === commandVersion &&
|
|
1103
|
+
this.receiptVersions.get(id) === receiptVersion) {
|
|
1104
|
+
// Read receipts do not change execution or invalidate pending history.
|
|
1105
|
+
this.nextDetailVersion(id);
|
|
1106
|
+
agentsQueryClient().setQueryData(chatKeys.conversation(id), detail);
|
|
1107
|
+
void agentsQueryClient().invalidateQueries({ queryKey: chatKeys.lists });
|
|
1108
|
+
}
|
|
1109
|
+
return detail;
|
|
1110
|
+
}
|
|
996
1111
|
async command(id, request, detail) {
|
|
997
1112
|
const active = this.lifetime(), version = (this.commandVersions.get(id) ?? 0) + 1;
|
|
998
1113
|
this.commandVersions.set(id, version);
|
|
999
1114
|
this.nextDetailVersion(id);
|
|
1115
|
+
this.invalidateHistoryReads(id);
|
|
1116
|
+
const recovery = this.recoveries.get(id);
|
|
1117
|
+
if (recovery?.phase === 'history')
|
|
1118
|
+
this.recoveries.set(id, { key: recovery.key, phase: 'history' });
|
|
1119
|
+
else
|
|
1120
|
+
this.recoveries.delete(id);
|
|
1000
1121
|
await agentsQueryClient().cancelQueries({
|
|
1001
1122
|
queryKey: chatKeys.conversation(id),
|
|
1002
1123
|
exact: true,
|
|
@@ -1047,10 +1168,10 @@ export class ChatController {
|
|
|
1047
1168
|
this.loads.clear();
|
|
1048
1169
|
this.refreshAgain.clear();
|
|
1049
1170
|
this.commandVersions.clear();
|
|
1171
|
+
this.receiptVersions.clear();
|
|
1050
1172
|
this.stopRequests.clear();
|
|
1051
1173
|
this.approvalRequests.clear();
|
|
1052
|
-
this.
|
|
1053
|
-
this.resumed.clear();
|
|
1174
|
+
this.recoveries.clear();
|
|
1054
1175
|
this.submissions.invalidate();
|
|
1055
1176
|
agentsQueryClient().removeQueries({ queryKey: chatKeys.all });
|
|
1056
1177
|
}
|