@kafca/agentdock 0.1.45 → 0.1.47

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 (106) hide show
  1. package/README.md +11 -0
  2. package/dist/renderer/assets/{Badge-BIojwD6s.js → Badge-BYREM3t3.js} +1 -1
  3. package/dist/renderer/assets/Chat-Dtb5X7sB.js +2 -0
  4. package/dist/renderer/assets/{ChatMarkdown-DqszsPB_.js → ChatMarkdown-_slLloCh.js} +1 -1
  5. package/dist/renderer/assets/Config-pHichs7H.js +21 -0
  6. package/dist/renderer/assets/CronList-CJQMeCjz.js +1 -0
  7. package/dist/renderer/assets/Dashboard-CY77Imde.js +26 -0
  8. package/dist/renderer/assets/{EmptyState-BqCx1oWr.js → EmptyState-DCqmct2y.js} +1 -1
  9. package/dist/renderer/assets/{KnowledgeDetail-BwK8Gpfa.js → KnowledgeDetail-DFrxa-pv.js} +1 -1
  10. package/dist/renderer/assets/KnowledgeHome-DL-vAfrH.js +11 -0
  11. package/dist/renderer/assets/Logs-jw9Uv590.js +1 -0
  12. package/dist/renderer/assets/{Modal-D2U4r2V0.js → Modal-ChSm7tk6.js} +1 -1
  13. package/dist/renderer/assets/MonitorList-DrEwyS71.js +1 -0
  14. package/dist/renderer/assets/{Page-urf5GcT_.js → Page-DhD-zgMU.js} +1 -1
  15. package/dist/renderer/assets/ProjectDetail-BVSjpfpL.js +11 -0
  16. package/dist/renderer/assets/ProjectList-CHGbTJjk.js +1 -0
  17. package/dist/renderer/assets/{Select-CAscWpy5.js → Select-rHs9CSam.js} +1 -1
  18. package/dist/renderer/assets/SessionChat-CDc2FNMA.js +1 -0
  19. package/dist/renderer/assets/SessionList-Mr1uAnRW.js +1 -0
  20. package/dist/renderer/assets/ThreadChat-Detu5UfN.js +23 -0
  21. package/dist/renderer/assets/Workspace-MRRg8ndJ.js +19 -0
  22. package/dist/renderer/assets/{arrow-left-7HrNuS-V.js → arrow-left-BU2NB2LA.js} +1 -1
  23. package/dist/renderer/assets/{book-open-BDoAu82s.js → book-open-D-TGvWwa.js} +1 -1
  24. package/dist/renderer/assets/bot-IYNh8tH5.js +6 -0
  25. package/dist/renderer/assets/{check-DGlyq4xX.js → check-CCZ0JO_S.js} +1 -1
  26. package/dist/renderer/assets/{chevron-down-Bb_3EHq9.js → chevron-down-00bRZi15.js} +1 -1
  27. package/dist/renderer/assets/{circle-DIpqZnYw.js → circle-CpQ8x4k_.js} +1 -1
  28. package/dist/renderer/assets/{desktop-Ci1fnRDR.js → desktop-D0k2aGSj.js} +1 -1
  29. package/dist/renderer/assets/{desktop-Do_UrC-o.js → desktop-JQkhNOF4.js} +1 -1
  30. package/dist/renderer/assets/{funnel-Bbf0ERLP.js → funnel-UbcrCBCp.js} +1 -1
  31. package/dist/renderer/assets/{heart-CGqU-qfw.js → heart-DvLsV7tL.js} +1 -1
  32. package/dist/renderer/assets/{index-Df-Trovt.js → index-B2L4G-b_.js} +1 -1
  33. package/dist/renderer/assets/index-CO4fGqmv.css +11 -0
  34. package/dist/renderer/assets/{index-DwhTjLA1.js → index-dy-g2Bh4.js} +3 -3
  35. package/dist/renderer/assets/{pencil-CHiy1MvK.js → pencil-qBYOgW5M.js} +1 -1
  36. package/dist/renderer/assets/{play-CGYnmC4Q.js → play-Dn6b4AGj.js} +1 -1
  37. package/dist/renderer/assets/{plus-B_Q5-Oj7.js → plus-CaApUwEm.js} +1 -1
  38. package/dist/renderer/assets/projects-BwF5RlNV.js +1 -0
  39. package/dist/renderer/assets/save-CN6yvTfD.js +11 -0
  40. package/dist/renderer/assets/{search-D8Dkhsyq.js → search-Dn2MxYiO.js} +1 -1
  41. package/dist/renderer/assets/{server-Cd96R7WL.js → server-DpcVLHeh.js} +1 -1
  42. package/dist/renderer/assets/{session-utils-BNUbQBfF.js → session-utils-DnD2Q_y1.js} +1 -1
  43. package/dist/renderer/assets/{sessions-BACfV8s1.js → sessions-eK5D4FLt.js} +1 -1
  44. package/dist/renderer/assets/{shield-check-Cnn-yQUA.js → shield-check-DSSJkacw.js} +1 -1
  45. package/dist/renderer/assets/{trash-2-oWCxwQ9D.js → trash-2-DmYJlEvO.js} +1 -1
  46. package/dist/renderer/assets/user-Cvf_uiyQ.js +6 -0
  47. package/dist/renderer/assets/{wifi-off-DHxnNkdY.js → wifi-off-CCTloj-V.js} +1 -1
  48. package/dist/renderer/index.html +2 -2
  49. package/dist-electron/services/local-ai-core/src/acp/local-core-acp-session-coordinator.js +2 -1
  50. package/dist-electron/services/local-ai-core/src/agents/pi/launch.js +1 -1
  51. package/dist-electron/services/local-ai-core/src/agents/shared/launch-utils.js +22 -0
  52. package/dist-electron/services/local-ai-core/src/channel/lark/inbound.js +55 -1
  53. package/dist-electron/services/local-ai-core/src/channel/lark/local-core-lark-gateway.js +132 -348
  54. package/dist-electron/services/local-ai-core/src/channel/shared/base-channel-gateway.js +303 -0
  55. package/dist-electron/services/local-ai-core/src/channel/weixin/local-core-weixin-gateway.js +131 -382
  56. package/dist-electron/services/local-ai-core/src/runtime/agent-runtime-detector.js +2 -1
  57. package/dist-electron/services/local-ai-core/src/runtime/channel-service.js +150 -0
  58. package/dist-electron/services/local-ai-core/src/runtime/env-utils.js +12 -0
  59. package/dist-electron/services/local-ai-core/src/runtime/external-service.js +234 -0
  60. package/dist-electron/services/local-ai-core/src/runtime/handlers/automation-handler.js +34 -0
  61. package/dist-electron/services/local-ai-core/src/runtime/handlers/capabilities-handler.js +12 -0
  62. package/dist-electron/services/local-ai-core/src/runtime/handlers/channel-handler.js +65 -0
  63. package/dist-electron/services/local-ai-core/src/runtime/handlers/external-handler.js +17 -0
  64. package/dist-electron/services/local-ai-core/src/runtime/handlers/knowledge-handler.js +65 -0
  65. package/dist-electron/services/local-ai-core/src/runtime/handlers/openai-handler.js +496 -0
  66. package/dist-electron/services/local-ai-core/src/runtime/handlers/provider-handler.js +24 -0
  67. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtime-handler.js +68 -0
  68. package/dist-electron/services/local-ai-core/src/runtime/handlers/runtimes-handler.js +37 -0
  69. package/dist-electron/services/local-ai-core/src/runtime/handlers/scheduler-handler.js +34 -0
  70. package/dist-electron/services/local-ai-core/src/runtime/handlers/security-handler.js +49 -0
  71. package/dist-electron/services/local-ai-core/src/runtime/handlers/task-handler.js +27 -0
  72. package/dist-electron/services/local-ai-core/src/runtime/handlers/thread-handler.js +42 -0
  73. package/dist-electron/services/local-ai-core/src/runtime/handlers/workspace-handler.js +29 -0
  74. package/dist-electron/services/local-ai-core/src/runtime/local-core-controller.js +40 -592
  75. package/dist-electron/services/local-ai-core/src/runtime/server-helpers.js +96 -0
  76. package/dist-electron/services/local-ai-core/src/runtime/server.js +107 -1084
  77. package/dist-electron/services/local-ai-core/src/runtime/standalone.js +13 -1
  78. package/dist-electron/src/pages/Projects/project-provider-config.js +75 -0
  79. package/dist-electron/tests/contracts/architecture-docs.test.js +1 -0
  80. package/dist-electron/tests/electron/agent-runtime-detector.test.js +18 -0
  81. package/dist-electron/tests/electron/knowledge-skill-script.test.js +15 -5
  82. package/dist-electron/tests/electron/lac-cli.test.js +591 -688
  83. package/dist-electron/tests/electron/plugin-kernel.test.js +47 -31
  84. package/dist-electron/tests/electron/project-provider-config.test.js +71 -0
  85. package/dist-electron/tests/electron/workspace-task-store.test.js +19 -9
  86. package/dist-electron/tests/integration/lark-gateway.test.js +80 -0
  87. package/dist-electron/tests/integration/local-core-cors.test.js +22 -0
  88. package/package.json +1 -1
  89. package/dist/renderer/assets/Chat-wjBR3XEX.js +0 -2
  90. package/dist/renderer/assets/Config-BDCHs5A2.js +0 -21
  91. package/dist/renderer/assets/CronList-CEWQYTov.js +0 -1
  92. package/dist/renderer/assets/Dashboard-DrWftfk3.js +0 -26
  93. package/dist/renderer/assets/KnowledgeHome-hhDTZMDO.js +0 -11
  94. package/dist/renderer/assets/Logs-C9xPEhFT.js +0 -1
  95. package/dist/renderer/assets/MonitorList-CayKbfwJ.js +0 -1
  96. package/dist/renderer/assets/ProjectDetail-B1GyAr7a.js +0 -11
  97. package/dist/renderer/assets/ProjectList-BoipQypE.js +0 -1
  98. package/dist/renderer/assets/SessionChat-BAVy5221.js +0 -1
  99. package/dist/renderer/assets/SessionList-BZpuMvh0.js +0 -1
  100. package/dist/renderer/assets/ThreadChat-JX7m9biG.js +0 -23
  101. package/dist/renderer/assets/Workspace-CFW8otjU.js +0 -14
  102. package/dist/renderer/assets/index-RaTga2BC.css +0 -11
  103. package/dist/renderer/assets/plug-Mexu4gyV.js +0 -6
  104. package/dist/renderer/assets/projects-C6bbkC-O.js +0 -1
  105. package/dist/renderer/assets/save-CJ_QFPw0.js +0 -6
  106. package/dist/renderer/assets/user-BzE9BwsY.js +0 -11
@@ -0,0 +1,496 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.OpenAiChatCompletionStreamAdapter = void 0;
4
+ exports.registerOpenAiHandler = registerOpenAiHandler;
5
+ const server_helpers_js_1 = require("../server-helpers.js");
6
+ class OpenAiChatCompletionStreamAdapter {
7
+ options;
8
+ created = Math.floor(Date.now() / 1000);
9
+ completionId;
10
+ assistantPreviewContentByHandle = new Map();
11
+ thoughtContentByHandle = new Map();
12
+ emittedMessageIds = new Set();
13
+ closed = false;
14
+ roleSent = false;
15
+ constructor(options) {
16
+ this.options = options;
17
+ this.completionId = `chatcmpl_${(0, server_helpers_js_1.sanitizeOpenAiId)(options.runId)}`;
18
+ }
19
+ start() {
20
+ this.options.response.writeHead(200, {
21
+ 'Content-Type': 'text/event-stream',
22
+ 'Cache-Control': 'no-cache, no-transform',
23
+ Connection: 'keep-alive',
24
+ });
25
+ this.sendChunk({ role: 'assistant' }, {
26
+ event: 'run_started',
27
+ kind: 'assistant',
28
+ run_id: this.options.runId,
29
+ });
30
+ this.roleSent = true;
31
+ }
32
+ handleBridgeEvent(event) {
33
+ if (this.closed || String(event.replyCtx || '') !== this.options.runId) {
34
+ return;
35
+ }
36
+ if (!this.roleSent) {
37
+ this.start();
38
+ }
39
+ if (event.type === 'typing_stop') {
40
+ this.finish('stop', { event: 'run_finished', kind: 'status' });
41
+ return;
42
+ }
43
+ if ((event.type === 'status' || event.type === 'card') && event.error) {
44
+ this.error(event.error, 'runtime_error');
45
+ return;
46
+ }
47
+ if (event.type === 'buttons' && event.bridgeKind === 'permission') {
48
+ this.error('Unexpected permission request for yolo OpenAI chat run.', 'unexpected_permission_request');
49
+ return;
50
+ }
51
+ if (event.type === 'preview_start' || event.type === 'update_message') {
52
+ this.handlePreviewEvent(event);
53
+ return;
54
+ }
55
+ if (event.type === 'reply') {
56
+ this.handleReplyEvent(event);
57
+ return;
58
+ }
59
+ if (event.type === 'status' || event.type === 'card') {
60
+ this.sendChunk({}, {
61
+ event: event.type,
62
+ kind: event.bridgeKind || 'status',
63
+ run_id: this.options.runId,
64
+ content: event.content,
65
+ ok: event.ok,
66
+ card: event.card,
67
+ });
68
+ }
69
+ }
70
+ replayMessage(input) {
71
+ if (this.closed || this.emittedMessageIds.has(input.id)) {
72
+ return;
73
+ }
74
+ this.emittedMessageIds.add(input.id);
75
+ const event = {
76
+ type: 'reply',
77
+ replyCtx: this.options.runId,
78
+ messageId: input.id,
79
+ content: input.content,
80
+ bridgeKind: input.bridgeKind,
81
+ bridgeStatus: input.bridgeStatus,
82
+ toolCall: input.toolCall,
83
+ };
84
+ this.handleReplyEvent(event);
85
+ }
86
+ finish(finishReason = 'stop', agentdock = {}) {
87
+ if (this.closed) {
88
+ return;
89
+ }
90
+ const chunk = this.baseChunk({}, {
91
+ run_id: this.options.runId,
92
+ ...agentdock,
93
+ }, finishReason);
94
+ this.options.response.write((0, server_helpers_js_1.createOpenAiSseData)(chunk));
95
+ this.options.response.write((0, server_helpers_js_1.createOpenAiDone)());
96
+ this.closed = true;
97
+ this.options.onClose();
98
+ this.options.response.end();
99
+ }
100
+ error(message, code = 'runtime_error') {
101
+ if (this.closed) {
102
+ return;
103
+ }
104
+ const chunk = this.baseChunk({}, {
105
+ run_id: this.options.runId,
106
+ event: 'error',
107
+ kind: 'status',
108
+ });
109
+ chunk.error = {
110
+ message,
111
+ type: code,
112
+ code,
113
+ };
114
+ this.options.response.write((0, server_helpers_js_1.createOpenAiSseData)(chunk));
115
+ this.options.response.write((0, server_helpers_js_1.createOpenAiDone)());
116
+ this.closed = true;
117
+ this.options.onClose();
118
+ this.options.response.end();
119
+ }
120
+ handlePreviewEvent(event) {
121
+ const content = String(event.content || '');
122
+ const handle = String(event.previewHandle || event.messageId || event.replyCtx || '');
123
+ if (!content || !handle) {
124
+ return;
125
+ }
126
+ if (event.bridgeKind === 'thought') {
127
+ const prior = this.thoughtContentByHandle.get(handle) || '';
128
+ const delta = (0, server_helpers_js_1.diffAccumulatedText)(prior, content);
129
+ this.thoughtContentByHandle.set(handle, content);
130
+ if (!delta) {
131
+ return;
132
+ }
133
+ this.sendProgressChunk(this.progressText('thinking', delta), {
134
+ event: 'thought_delta',
135
+ kind: 'thought',
136
+ run_id: this.options.runId,
137
+ thought: {
138
+ content,
139
+ delta,
140
+ preview_handle: handle,
141
+ },
142
+ });
143
+ return;
144
+ }
145
+ if (event.bridgeKind && event.bridgeKind !== 'assistant') {
146
+ return;
147
+ }
148
+ const prior = this.assistantPreviewContentByHandle.get(handle) || '';
149
+ const delta = (0, server_helpers_js_1.diffAccumulatedText)(prior, content);
150
+ this.assistantPreviewContentByHandle.set(handle, content);
151
+ if (!delta) {
152
+ return;
153
+ }
154
+ this.sendChunk({ content: delta }, {
155
+ event: 'assistant_delta',
156
+ kind: 'assistant',
157
+ run_id: this.options.runId,
158
+ preview_handle: handle,
159
+ });
160
+ }
161
+ handleReplyEvent(event) {
162
+ const content = String(event.content || '');
163
+ if (event.messageId) {
164
+ if (this.emittedMessageIds.has(event.messageId)) {
165
+ return;
166
+ }
167
+ this.emittedMessageIds.add(event.messageId);
168
+ }
169
+ if (event.bridgeKind === 'tool') {
170
+ this.sendProgressChunk(this.formatToolProgressContent(event), {
171
+ event: 'tool_update',
172
+ kind: 'tool',
173
+ run_id: this.options.runId,
174
+ message_id: event.messageId,
175
+ tool: event.toolCall || {
176
+ output: content,
177
+ },
178
+ });
179
+ return;
180
+ }
181
+ if (event.bridgeKind === 'plan') {
182
+ this.sendProgressChunk(this.progressText('plan', content), {
183
+ event: 'plan_update',
184
+ kind: 'plan',
185
+ run_id: this.options.runId,
186
+ message_id: event.messageId,
187
+ plan: {
188
+ content,
189
+ },
190
+ });
191
+ return;
192
+ }
193
+ if (event.bridgeKind === 'thought') {
194
+ this.sendProgressChunk(this.progressText('thinking', content), {
195
+ event: 'thought_message',
196
+ kind: 'thought',
197
+ run_id: this.options.runId,
198
+ message_id: event.messageId,
199
+ thought: {
200
+ content,
201
+ delta: content,
202
+ },
203
+ });
204
+ return;
205
+ }
206
+ if (event.bridgeKind === 'status' || event.bridgeKind === 'permission') {
207
+ this.sendProgressChunk(this.progressText(event.bridgeKind, content), {
208
+ event: event.bridgeKind === 'permission' ? 'permission_required' : 'status',
209
+ kind: event.bridgeKind,
210
+ run_id: this.options.runId,
211
+ message_id: event.messageId,
212
+ content,
213
+ bridge_status: event.bridgeStatus,
214
+ });
215
+ return;
216
+ }
217
+ if (content) {
218
+ this.sendChunk({ content }, {
219
+ event: 'assistant_message',
220
+ kind: 'assistant',
221
+ run_id: this.options.runId,
222
+ message_id: event.messageId,
223
+ });
224
+ }
225
+ }
226
+ sendProgressChunk(content, agentdock) {
227
+ this.sendChunk(this.options.progressMode === 'content' && content ? { content } : {}, agentdock);
228
+ }
229
+ sendChunk(delta, agentdock, finishReason = null) {
230
+ if (this.closed) {
231
+ return;
232
+ }
233
+ this.options.response.write((0, server_helpers_js_1.createOpenAiSseData)(this.baseChunk(delta, agentdock, finishReason)));
234
+ }
235
+ baseChunk(delta, agentdock, finishReason = null) {
236
+ return {
237
+ id: this.completionId,
238
+ object: 'chat.completion.chunk',
239
+ created: this.created,
240
+ model: this.options.model,
241
+ choices: [
242
+ {
243
+ index: 0,
244
+ delta,
245
+ finish_reason: finishReason,
246
+ },
247
+ ],
248
+ agentdock,
249
+ };
250
+ }
251
+ progressText(kind, content) {
252
+ return content ? `\n\n[${kind}]\n${content}` : '';
253
+ }
254
+ formatToolProgressContent(event) {
255
+ const tool = event.toolCall;
256
+ const name = tool?.name || tool?.label || 'tool';
257
+ const status = tool?.status || '';
258
+ const output = tool?.output || tool?.detail || event.content || '';
259
+ return output ? `\n\n[tool:${name}${status ? ` ${status}` : ''}]\n${output}` : '';
260
+ }
261
+ }
262
+ exports.OpenAiChatCompletionStreamAdapter = OpenAiChatCompletionStreamAdapter;
263
+ function extractMetadataValue(metadata, key) {
264
+ const value = metadata[key];
265
+ return String(value === undefined || value === null ? '' : value).trim();
266
+ }
267
+ function parseOpenAiChatCompletionRequest(input) {
268
+ const metadata = input.metadata && typeof input.metadata === 'object' && !Array.isArray(input.metadata)
269
+ ? input.metadata
270
+ : {};
271
+ const userId = extractMetadataValue(metadata, 'user_id') || String(input.user || '').trim();
272
+ const projectId = extractMetadataValue(metadata, 'project_id');
273
+ if (!userId) {
274
+ throw new Error('metadata.user_id is required.');
275
+ }
276
+ if (!projectId) {
277
+ throw new Error('metadata.project_id is required.');
278
+ }
279
+ const unsupported = [
280
+ input.tools !== undefined ? 'tools' : '',
281
+ input.tool_choice !== undefined ? 'tool_choice' : '',
282
+ input.response_format !== undefined ? 'response_format' : '',
283
+ input.audio !== undefined ? 'audio' : '',
284
+ input.logprobs !== undefined ? 'logprobs' : '',
285
+ ].filter(Boolean);
286
+ if (unsupported.length > 0) {
287
+ throw new Error(`Unsupported OpenAI chat field(s): ${unsupported.join(', ')}.`);
288
+ }
289
+ if (input.n !== undefined && Number(input.n) !== 1) {
290
+ throw new Error('Only n=1 is supported.');
291
+ }
292
+ const messages = Array.isArray(input.messages) ? input.messages : [];
293
+ if (messages.length === 0) {
294
+ throw new Error('messages must contain at least one text message.');
295
+ }
296
+ const prompt = messages
297
+ .map((message) => formatOpenAiMessage(message))
298
+ .filter(Boolean)
299
+ .join('\n\n');
300
+ if (!prompt.trim()) {
301
+ throw new Error('messages must contain text content.');
302
+ }
303
+ const progressMode = extractMetadataValue(metadata, 'agentdock_progress_mode') === 'content'
304
+ ? 'content'
305
+ : 'extension';
306
+ const model = String(input.model || extractMetadataValue(metadata, 'model') || '').trim();
307
+ const externalRun = {
308
+ user_id: userId,
309
+ external_project_id: projectId,
310
+ external_thread_id: extractMetadataValue(metadata, 'thread_id') || undefined,
311
+ display_name: extractMetadataValue(metadata, 'display_name') || undefined,
312
+ agent_type: extractMetadataValue(metadata, 'agent_type') || 'pi',
313
+ provider_id: extractMetadataValue(metadata, 'provider_id') || undefined,
314
+ model: model || undefined,
315
+ title: extractMetadataValue(metadata, 'title') || undefined,
316
+ metadata: {
317
+ ...metadata,
318
+ openai_compatible: true,
319
+ },
320
+ prompt,
321
+ permission_mode: 'bypassPermissions',
322
+ runtime_env: {
323
+ AGENTDOCK_OPENAI_COMPAT: '1',
324
+ },
325
+ };
326
+ return {
327
+ externalRun,
328
+ model: model || externalRun.agent_type || 'agentdock',
329
+ stream: Boolean(input.stream),
330
+ progressMode,
331
+ };
332
+ }
333
+ function formatOpenAiMessage(message) {
334
+ const role = String(message?.role || 'user').trim() || 'user';
335
+ const content = extractOpenAiMessageText(message?.content);
336
+ if (!content.trim()) {
337
+ return '';
338
+ }
339
+ if (role === 'user') {
340
+ return content;
341
+ }
342
+ return `[${role}]\n${content}`;
343
+ }
344
+ function extractOpenAiMessageText(content) {
345
+ if (typeof content === 'string') {
346
+ return content;
347
+ }
348
+ if (content === null || content === undefined) {
349
+ return '';
350
+ }
351
+ if (!Array.isArray(content)) {
352
+ throw new Error('Only text message content is supported.');
353
+ }
354
+ return content.map((part) => {
355
+ const type = String(part?.type || 'text');
356
+ if (type !== 'text') {
357
+ throw new Error(`Only text message parts are supported; received ${type}.`);
358
+ }
359
+ return String(part?.text || '');
360
+ }).join('');
361
+ }
362
+ function collectAssistantMessagesForRun(snapshot) {
363
+ const thread = snapshot.thread;
364
+ const startedAt = Date.parse(snapshot.task?.startedAt || snapshot.task?.createdAt || '');
365
+ if (!thread || !Number.isFinite(startedAt)) {
366
+ return [];
367
+ }
368
+ return (thread.messages || []).filter((message) => {
369
+ if (message.role !== 'assistant') {
370
+ return false;
371
+ }
372
+ const messageAt = Date.parse(message.timestamp || '');
373
+ return Number.isFinite(messageAt) && messageAt >= startedAt;
374
+ });
375
+ }
376
+ function registerOpenAiHandler(map, externalService, streamReg) {
377
+ map.set('openai.chat.completions', async (_route, req, res) => {
378
+ let parsed;
379
+ try {
380
+ parsed = parseOpenAiChatCompletionRequest(await (0, server_helpers_js_1.readJsonBody)(req));
381
+ }
382
+ catch (error) {
383
+ (0, server_helpers_js_1.openAiJsonError)(res, 400, error instanceof Error ? error.message : String(error));
384
+ return;
385
+ }
386
+ if (parsed.stream) {
387
+ await handleStreaming(externalService, streamReg, parsed, res);
388
+ return;
389
+ }
390
+ await handleNonStreaming(externalService, parsed, res);
391
+ });
392
+ }
393
+ async function handleStreaming(externalService, streamReg, parsed, res) {
394
+ try {
395
+ const created = await externalService.createRun(parsed.externalRun);
396
+ const adapter = new OpenAiChatCompletionStreamAdapter({
397
+ runId: created.run_id,
398
+ model: parsed.model,
399
+ response: res,
400
+ progressMode: parsed.progressMode,
401
+ onClose: () => {
402
+ streamReg.removeAdapter(created.run_id, adapter);
403
+ },
404
+ });
405
+ streamReg.addAdapter(created.run_id, adapter);
406
+ adapter.start();
407
+ res.on('close', () => {
408
+ streamReg.removeAdapter(created.run_id, adapter);
409
+ });
410
+ const snapshot = await externalService.getRunSnapshot(created.run_id);
411
+ replayOpenAiRunMessages(adapter, snapshot);
412
+ if ((0, server_helpers_js_1.isTerminalAgentTaskStatus)(snapshot.task?.status)) {
413
+ adapter.finish('stop', { event: 'run_finished', kind: 'status' });
414
+ }
415
+ }
416
+ catch (error) {
417
+ (0, server_helpers_js_1.openAiJsonError)(res, 500, error instanceof Error ? error.message : String(error), 'agentdock_run_error');
418
+ }
419
+ }
420
+ async function handleNonStreaming(externalService, parsed, res) {
421
+ let created;
422
+ try {
423
+ created = await externalService.createRun(parsed.externalRun);
424
+ }
425
+ catch (error) {
426
+ (0, server_helpers_js_1.openAiJsonError)(res, 500, error instanceof Error ? error.message : String(error), 'agentdock_run_error');
427
+ return;
428
+ }
429
+ const started = Date.now();
430
+ const timeoutMs = 10 * 60 * 1000;
431
+ let snapshot = await externalService.getRunSnapshot(created.run_id);
432
+ while (!(0, server_helpers_js_1.isTerminalAgentTaskStatus)(snapshot.task?.status) && Date.now() - started < timeoutMs) {
433
+ await new Promise((resolve) => setTimeout(resolve, 500));
434
+ snapshot = await externalService.getRunSnapshot(created.run_id);
435
+ }
436
+ if (!(0, server_helpers_js_1.isTerminalAgentTaskStatus)(snapshot.task?.status)) {
437
+ (0, server_helpers_js_1.openAiJsonError)(res, 504, 'OpenAI-compatible chat completion timed out waiting for the agent run.', 'run_timeout');
438
+ return;
439
+ }
440
+ if (snapshot.task?.status === 'failed') {
441
+ (0, server_helpers_js_1.openAiJsonError)(res, 500, snapshot.task.error || 'Agent run failed.', 'agentdock_run_failed');
442
+ return;
443
+ }
444
+ if (snapshot.task?.status === 'cancelled') {
445
+ (0, server_helpers_js_1.openAiJsonError)(res, 500, snapshot.task.error || 'Agent run was cancelled.', 'agentdock_run_cancelled');
446
+ return;
447
+ }
448
+ const messages = collectAssistantMessagesForRun(snapshot);
449
+ const finalContent = messages
450
+ .filter((message) => message.kind === 'final' || !message.bridgeKind || message.bridgeKind === 'assistant')
451
+ .map((message) => message.content)
452
+ .filter(Boolean)
453
+ .join('\n\n');
454
+ const response = {
455
+ id: `chatcmpl_${(0, server_helpers_js_1.sanitizeOpenAiId)(created.run_id)}`,
456
+ object: 'chat.completion',
457
+ created: Math.floor(Date.now() / 1000),
458
+ model: parsed.model,
459
+ choices: [
460
+ {
461
+ index: 0,
462
+ message: {
463
+ role: 'assistant',
464
+ content: finalContent,
465
+ },
466
+ finish_reason: 'stop',
467
+ },
468
+ ],
469
+ agentdock: {
470
+ run_id: created.run_id,
471
+ workspace_id: created.workspace_id,
472
+ thread_id: created.thread_id,
473
+ task_id: created.task_id,
474
+ events: messages
475
+ .filter((message) => message.bridgeKind && message.bridgeKind !== 'assistant')
476
+ .map((message) => ({
477
+ event: `${message.bridgeKind}_update`,
478
+ kind: message.bridgeKind,
479
+ content: message.content,
480
+ tool: message.toolCall,
481
+ })),
482
+ },
483
+ };
484
+ (0, server_helpers_js_1.rawJson)(res, 200, response);
485
+ }
486
+ function replayOpenAiRunMessages(adapter, snapshot) {
487
+ for (const message of collectAssistantMessagesForRun(snapshot)) {
488
+ adapter.replayMessage({
489
+ id: message.id,
490
+ content: message.content,
491
+ bridgeKind: message.bridgeKind,
492
+ bridgeStatus: message.bridgeStatus,
493
+ toolCall: message.toolCall,
494
+ });
495
+ }
496
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerProviderHandlers = registerProviderHandlers;
4
+ const server_helpers_js_1 = require("../server-helpers.js");
5
+ function registerProviderHandlers(map, store) {
6
+ map.set('providers.list', async (_route, _req, res) => {
7
+ (0, server_helpers_js_1.json)(res, 200, { providers: store.listModelProviders() });
8
+ });
9
+ map.set('providers.create', async (_route, req, res) => {
10
+ const body = await (0, server_helpers_js_1.readJsonBody)(req);
11
+ (0, server_helpers_js_1.json)(res, 200, await store.upsertModelProvider(body));
12
+ });
13
+ map.set('provider.update', async (route, req, res) => {
14
+ const body = await (0, server_helpers_js_1.readJsonBody)(req);
15
+ const existing = store.getModelProvider(route.providerId);
16
+ if (!existing) {
17
+ throw new Error(`Provider not found: ${route.providerId}`);
18
+ }
19
+ (0, server_helpers_js_1.json)(res, 200, store.upsertModelProvider({ ...body, id: route.providerId }));
20
+ });
21
+ map.set('provider.delete', async (route, _req, res) => {
22
+ (0, server_helpers_js_1.json)(res, 200, store.deleteModelProvider(route.providerId));
23
+ });
24
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerRuntimeHandlers = registerRuntimeHandlers;
4
+ const server_helpers_js_1 = require("../server-helpers.js");
5
+ function registerRuntimeHandlers(map, controller, errorReporter, attachSseClient) {
6
+ map.set('health', async (_route, _req, res) => {
7
+ (0, server_helpers_js_1.json)(res, 200, { name: 'local-ai-core', version: '0.1.0' });
8
+ });
9
+ map.set('runtime.status', async (_route, _req, res) => {
10
+ (0, server_helpers_js_1.json)(res, 200, await controller.getRuntimeStatus());
11
+ });
12
+ map.set('runtime.service.start', async (_route, _req, res) => {
13
+ (0, server_helpers_js_1.json)(res, 200, await controller.startService());
14
+ });
15
+ map.set('runtime.service.stop', async (_route, _req, res) => {
16
+ (0, server_helpers_js_1.json)(res, 200, await controller.stopService());
17
+ });
18
+ map.set('runtime.service.restart', async (_route, _req, res) => {
19
+ (0, server_helpers_js_1.json)(res, 200, await controller.restartService());
20
+ });
21
+ map.set('runtime.logs', async (_route, _req, res, url) => {
22
+ const limit = Number(url.searchParams.get('limit') || '200');
23
+ (0, server_helpers_js_1.json)(res, 200, controller.getLogs(limit));
24
+ });
25
+ map.set('logs.list', async (_route, _req, res, url) => {
26
+ const level = url.searchParams.get('level') || 'sys';
27
+ const limit = Number(url.searchParams.get('limit') || '200');
28
+ (0, server_helpers_js_1.json)(res, 200, {
29
+ entries: controller.getLogEntries(level, limit).map((entry) => ({
30
+ time: entry.ts,
31
+ level: entry.level,
32
+ scope: entry.scope,
33
+ message: entry.message,
34
+ meta: entry.meta,
35
+ })),
36
+ });
37
+ });
38
+ map.set('diagnostics.errors', async (_route, _req, res) => {
39
+ (0, server_helpers_js_1.json)(res, 200, { errors: await errorReporter.list() });
40
+ });
41
+ map.set('runtime.config.read', async (_route, _req, res) => {
42
+ (0, server_helpers_js_1.json)(res, 200, await controller.readConfigFile());
43
+ });
44
+ map.set('runtime.config.save-raw', async (_route, req, res) => {
45
+ const body = await (0, server_helpers_js_1.readJsonBody)(req);
46
+ (0, server_helpers_js_1.json)(res, 200, await controller.saveRawConfigFile(String(body.raw || '')));
47
+ });
48
+ map.set('runtime.config.save-structured', async (_route, req, res) => {
49
+ const body = await (0, server_helpers_js_1.readJsonBody)(req);
50
+ (0, server_helpers_js_1.json)(res, 200, await controller.saveStructuredConfigFile((body.config || {})));
51
+ });
52
+ map.set('runtime.settings.save', async (_route, req, res) => {
53
+ const body = await (0, server_helpers_js_1.readJsonBody)(req);
54
+ (0, server_helpers_js_1.json)(res, 200, await controller.saveSettings(body));
55
+ });
56
+ map.set('diagnostics.doctor', async (_route, _req, res) => {
57
+ (0, server_helpers_js_1.json)(res, 200, await controller.runDiagnosticsDoctor());
58
+ });
59
+ map.set('diagnostics.deployment', async (_route, _req, res) => {
60
+ (0, server_helpers_js_1.json)(res, 200, await controller.runDeploymentDiagnostics());
61
+ });
62
+ map.set('plugins.diagnostics', async (_route, _req, res) => {
63
+ (0, server_helpers_js_1.json)(res, 200, await controller.getPluginDiagnostics());
64
+ });
65
+ map.set('events.stream', async (_route, _req, res) => {
66
+ attachSseClient(res);
67
+ });
68
+ }
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerRuntimesHandlers = registerRuntimesHandlers;
4
+ const server_helpers_js_1 = require("../server-helpers.js");
5
+ async function runtimeDetectionResponse(runtimeDetection) {
6
+ return {
7
+ runtimes: await runtimeDetection.list(),
8
+ checking: runtimeDetection.isChecking(),
9
+ };
10
+ }
11
+ function registerRuntimesHandlers(map, runtimeDetection) {
12
+ map.set('runtime.agent-runtimes', async (_route, _req, res) => {
13
+ (0, server_helpers_js_1.json)(res, 200, await runtimeDetectionResponse(runtimeDetection));
14
+ });
15
+ map.set('runtimes.list', async (_route, _req, res) => {
16
+ (0, server_helpers_js_1.json)(res, 200, await runtimeDetectionResponse(runtimeDetection));
17
+ });
18
+ map.set('runtimes.detail', async (route, _req, res) => {
19
+ const rId = route.runtimeId;
20
+ const runtimes = await runtimeDetection.list();
21
+ const runtime = runtimes.find((entry) => entry.runtimeId === rId || entry.agentType === rId);
22
+ if (!runtime) {
23
+ (0, server_helpers_js_1.json)(res, 404, null, false, 'Runtime not found');
24
+ return;
25
+ }
26
+ (0, server_helpers_js_1.json)(res, 200, runtime);
27
+ });
28
+ map.set('runtimes.refresh', async (_route, _req, res) => {
29
+ const runtimes = await runtimeDetection.refresh();
30
+ (0, server_helpers_js_1.json)(res, 200, { runtimes, checking: runtimeDetection.isChecking() });
31
+ });
32
+ map.set('runtimes.refresh-one', async (route, _req, res) => {
33
+ const rId = route.runtimeId;
34
+ const runtimes = await runtimeDetection.refresh(rId);
35
+ (0, server_helpers_js_1.json)(res, 200, { runtimes, checking: runtimeDetection.isChecking(rId) });
36
+ });
37
+ }
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerSchedulerHandlers = registerSchedulerHandlers;
4
+ const server_helpers_js_1 = require("../server-helpers.js");
5
+ function registerSchedulerHandlers(map, scheduledJobs) {
6
+ map.set('scheduler.jobs.list', async (_route, _req, res, url) => {
7
+ const workspaceId = String(url.searchParams.get('workspace_id') || '');
8
+ (0, server_helpers_js_1.json)(res, 200, { jobs: await scheduledJobs.listJobs(workspaceId || undefined) });
9
+ });
10
+ map.set('scheduler.jobs.create', async (_route, req, res) => {
11
+ const body = await (0, server_helpers_js_1.readJsonBody)(req);
12
+ (0, server_helpers_js_1.json)(res, 200, await scheduledJobs.createJob(body));
13
+ });
14
+ map.set('scheduler.job.get', async (route, _req, res) => {
15
+ const job = scheduledJobs.getJob(route.jobId);
16
+ if (!job) {
17
+ throw new Error(`Scheduled job not found: ${route.jobId}`);
18
+ }
19
+ (0, server_helpers_js_1.json)(res, 200, job);
20
+ });
21
+ map.set('scheduler.job.runs', async (route, _req, res) => {
22
+ (0, server_helpers_js_1.json)(res, 200, { runs: await scheduledJobs.listJobRuns(route.jobId) });
23
+ });
24
+ map.set('scheduler.job.run', async (route, _req, res) => {
25
+ (0, server_helpers_js_1.json)(res, 200, await scheduledJobs.runJobNow(route.jobId));
26
+ });
27
+ map.set('scheduler.job.update', async (route, req, res) => {
28
+ const body = await (0, server_helpers_js_1.readJsonBody)(req);
29
+ (0, server_helpers_js_1.json)(res, 200, await scheduledJobs.updateJob(route.jobId, body));
30
+ });
31
+ map.set('scheduler.job.delete', async (route, _req, res) => {
32
+ (0, server_helpers_js_1.json)(res, 200, await scheduledJobs.deleteJob(route.jobId));
33
+ });
34
+ }