@nocobase/app-plugin-agents 1.0.0-beta.28 → 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 +56 -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 +193 -69
- 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);
|
|
@@ -448,7 +465,7 @@ export class ChatController {
|
|
|
448
465
|
}
|
|
449
466
|
const chat = this.chat(id);
|
|
450
467
|
const receiving = chat.status === 'submitted' || chat.status === 'streaming';
|
|
451
|
-
const activeId = receiving && chat.messages.at(-1)?.
|
|
468
|
+
const activeId = receiving && chat.messages.at(-1)?.role === 'assistant'
|
|
452
469
|
? chat.messages.at(-1)?.id
|
|
453
470
|
: undefined;
|
|
454
471
|
chat.messages = mergeUIMessages(chat.messages.filter((m) => !missing.has(m.id) || m.id === activeId), found, activeId);
|
|
@@ -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
|
|
782
|
+
if (!detail ||
|
|
783
|
+
this.recoveries.get(id)?.key === this.recoveryKey(id, detail))
|
|
743
784
|
return;
|
|
744
|
-
this.
|
|
745
|
-
if (detail?.execution?.status === 'idle' ||
|
|
746
|
-
detail?.execution?.waitingApproval)
|
|
747
|
-
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,15 +950,24 @@ 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
|
-
if (!active()
|
|
961
|
+
if (!active())
|
|
873
962
|
return;
|
|
874
|
-
|
|
875
|
-
|
|
963
|
+
if (ordered())
|
|
964
|
+
await this.reconcile(id, detail);
|
|
965
|
+
if (!active())
|
|
876
966
|
return;
|
|
967
|
+
// A newer detail query must not discard this refresh's message catch-up.
|
|
968
|
+
// loadHistory coalesces overlapping reads independently of detail ordering.
|
|
877
969
|
await this.loadHistory(id, false, true);
|
|
878
|
-
if (!active()
|
|
970
|
+
if (!active())
|
|
879
971
|
return;
|
|
880
972
|
const history = this.history(id);
|
|
881
973
|
if (history.error)
|
|
@@ -900,14 +992,29 @@ export class ChatController {
|
|
|
900
992
|
if (!active() || !ordered())
|
|
901
993
|
return;
|
|
902
994
|
const owner = this.chat(id), receiving = owner.messages.at(-1);
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
(
|
|
906
|
-
|
|
907
|
-
|
|
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' &&
|
|
908
1005
|
message.metadata?.seq !== undefined &&
|
|
909
|
-
message.metadata
|
|
910
|
-
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)))) {
|
|
911
1018
|
// Durable completion can release a lost subscriber; this never calls business Stop.
|
|
912
1019
|
await owner.stop();
|
|
913
1020
|
if (!active() || !ordered())
|
|
@@ -916,20 +1023,13 @@ export class ChatController {
|
|
|
916
1023
|
}
|
|
917
1024
|
if (!active() || !ordered())
|
|
918
1025
|
return;
|
|
919
|
-
this.remember(detail);
|
|
1026
|
+
this.remember(detail, false);
|
|
920
1027
|
const chat = this.chat(id);
|
|
921
1028
|
if (detail.execution?.status === 'idle') {
|
|
922
|
-
this.
|
|
923
|
-
if (chat.error
|
|
924
|
-
saved.some((message) => message.id === chat.messages.at(-1)?.id &&
|
|
925
|
-
message.metadata?.seq !== undefined))
|
|
1029
|
+
this.recoveries.delete(id);
|
|
1030
|
+
if (chat.error)
|
|
926
1031
|
this.renewChat(id, chat.messages);
|
|
927
1032
|
}
|
|
928
|
-
else if (detail.execution?.status === 'running' &&
|
|
929
|
-
!detail.execution.waitingApproval &&
|
|
930
|
-
chat.status !== 'submitted' &&
|
|
931
|
-
chat.status !== 'streaming')
|
|
932
|
-
this.recoveryErrors.set(id, new Error('Execution remains active; reconcile saved history or resume its stream.'));
|
|
933
1033
|
this.publish();
|
|
934
1034
|
}
|
|
935
1035
|
scheduleRefresh(id) {
|
|
@@ -942,14 +1042,16 @@ export class ChatController {
|
|
|
942
1042
|
void this.refresh(id).catch(() => { });
|
|
943
1043
|
});
|
|
944
1044
|
}
|
|
945
|
-
observeDetail(detail) {
|
|
1045
|
+
observeDetail(detail, refresh = true) {
|
|
946
1046
|
if (detail.execution?.status === 'running')
|
|
947
1047
|
this.receive(detail.id, detail);
|
|
948
1048
|
if (!chatIsRunning(detail)) {
|
|
949
|
-
if (
|
|
1049
|
+
if (refresh &&
|
|
1050
|
+
(this.chats.get(detail.id)?.status === 'streaming' ||
|
|
1051
|
+
this.chats.get(detail.id)?.status === 'submitted'))
|
|
950
1052
|
this.scheduleRefresh(detail.id);
|
|
951
1053
|
this.stopRequests.delete(detail.id);
|
|
952
|
-
this.
|
|
1054
|
+
this.recoveries.delete(detail.id);
|
|
953
1055
|
this.publish();
|
|
954
1056
|
}
|
|
955
1057
|
}
|
|
@@ -984,16 +1086,38 @@ export class ChatController {
|
|
|
984
1086
|
const active = this.lifetime(), version = this.nextDetailVersion(id);
|
|
985
1087
|
return () => active() && this.detailVersions.get(id) === version;
|
|
986
1088
|
}
|
|
987
|
-
remember(detail) {
|
|
1089
|
+
remember(detail, refresh = true) {
|
|
988
1090
|
this.nextDetailVersion(detail.id);
|
|
989
|
-
this.observeDetail(detail);
|
|
1091
|
+
this.observeDetail(detail, refresh);
|
|
990
1092
|
agentsQueryClient().setQueryData(chatKeys.conversation(detail.id), detail);
|
|
991
1093
|
void agentsQueryClient().invalidateQueries({ queryKey: chatKeys.lists });
|
|
992
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
|
+
}
|
|
993
1111
|
async command(id, request, detail) {
|
|
994
1112
|
const active = this.lifetime(), version = (this.commandVersions.get(id) ?? 0) + 1;
|
|
995
1113
|
this.commandVersions.set(id, version);
|
|
996
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);
|
|
997
1121
|
await agentsQueryClient().cancelQueries({
|
|
998
1122
|
queryKey: chatKeys.conversation(id),
|
|
999
1123
|
exact: true,
|
|
@@ -1044,10 +1168,10 @@ export class ChatController {
|
|
|
1044
1168
|
this.loads.clear();
|
|
1045
1169
|
this.refreshAgain.clear();
|
|
1046
1170
|
this.commandVersions.clear();
|
|
1171
|
+
this.receiptVersions.clear();
|
|
1047
1172
|
this.stopRequests.clear();
|
|
1048
1173
|
this.approvalRequests.clear();
|
|
1049
|
-
this.
|
|
1050
|
-
this.resumed.clear();
|
|
1174
|
+
this.recoveries.clear();
|
|
1051
1175
|
this.submissions.invalidate();
|
|
1052
1176
|
agentsQueryClient().removeQueries({ queryKey: chatKeys.all });
|
|
1053
1177
|
}
|