@theia/ai-external-api 1.76.0-next.33
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/README.md +83 -0
- package/lib/browser/ai-external-api-frontend-contribution.d.ts +28 -0
- package/lib/browser/ai-external-api-frontend-contribution.d.ts.map +1 -0
- package/lib/browser/ai-external-api-frontend-contribution.js +88 -0
- package/lib/browser/ai-external-api-frontend-contribution.js.map +1 -0
- package/lib/browser/ai-external-api-frontend-contribution.spec.d.ts +2 -0
- package/lib/browser/ai-external-api-frontend-contribution.spec.d.ts.map +1 -0
- package/lib/browser/ai-external-api-frontend-contribution.spec.js +102 -0
- package/lib/browser/ai-external-api-frontend-contribution.spec.js.map +1 -0
- package/lib/browser/ai-external-api-frontend-module.d.ts +4 -0
- package/lib/browser/ai-external-api-frontend-module.d.ts.map +1 -0
- package/lib/browser/ai-external-api-frontend-module.js +47 -0
- package/lib/browser/ai-external-api-frontend-module.js.map +1 -0
- package/lib/browser/frontend-external-chat-session-provider.d.ts +63 -0
- package/lib/browser/frontend-external-chat-session-provider.d.ts.map +1 -0
- package/lib/browser/frontend-external-chat-session-provider.js +271 -0
- package/lib/browser/frontend-external-chat-session-provider.js.map +1 -0
- package/lib/browser/frontend-external-chat-session-provider.spec.d.ts +2 -0
- package/lib/browser/frontend-external-chat-session-provider.spec.d.ts.map +1 -0
- package/lib/browser/frontend-external-chat-session-provider.spec.js +421 -0
- package/lib/browser/frontend-external-chat-session-provider.spec.js.map +1 -0
- package/lib/browser/index.d.ts +3 -0
- package/lib/browser/index.d.ts.map +1 -0
- package/lib/browser/index.js +21 -0
- package/lib/browser/index.js.map +1 -0
- package/lib/common/external-chat-session-provider.d.ts +213 -0
- package/lib/common/external-chat-session-provider.d.ts.map +1 -0
- package/lib/common/external-chat-session-provider.js +147 -0
- package/lib/common/external-chat-session-provider.js.map +1 -0
- package/lib/common/index.d.ts +2 -0
- package/lib/common/index.d.ts.map +1 -0
- package/lib/common/index.js +20 -0
- package/lib/common/index.js.map +1 -0
- package/lib/node/ai-external-api-backend-module.d.ts +4 -0
- package/lib/node/ai-external-api-backend-module.d.ts.map +1 -0
- package/lib/node/ai-external-api-backend-module.js +38 -0
- package/lib/node/ai-external-api-backend-module.js.map +1 -0
- package/lib/node/ai-external-api-endpoint.d.ts +31 -0
- package/lib/node/ai-external-api-endpoint.d.ts.map +1 -0
- package/lib/node/ai-external-api-endpoint.js +189 -0
- package/lib/node/ai-external-api-endpoint.js.map +1 -0
- package/lib/node/ai-external-api-endpoint.spec.d.ts +2 -0
- package/lib/node/ai-external-api-endpoint.spec.d.ts.map +1 -0
- package/lib/node/ai-external-api-endpoint.spec.js +233 -0
- package/lib/node/ai-external-api-endpoint.spec.js.map +1 -0
- package/lib/node/external-chat-session-registry.d.ts +83 -0
- package/lib/node/external-chat-session-registry.d.ts.map +1 -0
- package/lib/node/external-chat-session-registry.js +266 -0
- package/lib/node/external-chat-session-registry.js.map +1 -0
- package/lib/node/external-chat-session-registry.spec.d.ts +2 -0
- package/lib/node/external-chat-session-registry.spec.d.ts.map +1 -0
- package/lib/node/external-chat-session-registry.spec.js +366 -0
- package/lib/node/external-chat-session-registry.spec.js.map +1 -0
- package/lib/node/index.d.ts +3 -0
- package/lib/node/index.d.ts.map +1 -0
- package/lib/node/index.js +21 -0
- package/lib/node/index.js.map +1 -0
- package/package.json +52 -0
- package/src/browser/ai-external-api-frontend-contribution.spec.ts +128 -0
- package/src/browser/ai-external-api-frontend-contribution.ts +90 -0
- package/src/browser/ai-external-api-frontend-module.ts +48 -0
- package/src/browser/frontend-external-chat-session-provider.spec.ts +491 -0
- package/src/browser/frontend-external-chat-session-provider.ts +277 -0
- package/src/browser/index.ts +18 -0
- package/src/common/external-chat-session-provider.ts +330 -0
- package/src/common/index.ts +17 -0
- package/src/node/ai-external-api-backend-module.ts +41 -0
- package/src/node/ai-external-api-endpoint.spec.ts +272 -0
- package/src/node/ai-external-api-endpoint.ts +195 -0
- package/src/node/external-chat-session-registry.spec.ts +413 -0
- package/src/node/external-chat-session-registry.ts +270 -0
- package/src/node/index.ts +18 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.AIExternalApiEndpoint = void 0;
|
|
19
|
+
const tslib_1 = require("tslib");
|
|
20
|
+
const inversify_1 = require("@theia/core/shared/inversify");
|
|
21
|
+
const rest_result_1 = require("@theia/external-api/lib/node/rest-result");
|
|
22
|
+
const external_chat_session_provider_1 = require("../common/external-chat-session-provider");
|
|
23
|
+
const external_chat_session_registry_1 = require("./external-chat-session-registry");
|
|
24
|
+
const SESSION_ID_PARAM = { description: 'The session id.' };
|
|
25
|
+
const SESSION_LIST_SCHEMA = {
|
|
26
|
+
type: 'object',
|
|
27
|
+
required: ['sessions'],
|
|
28
|
+
properties: {
|
|
29
|
+
sessions: { type: 'array', items: external_chat_session_provider_1.ExternalChatSessionSummary.SCHEMA, description: 'The sessions, most recently used first.' }
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const SESSION_CREATED_SCHEMA = {
|
|
33
|
+
type: 'object',
|
|
34
|
+
required: ['session'],
|
|
35
|
+
properties: {
|
|
36
|
+
session: external_chat_session_provider_1.ExternalChatSessionSummary.SCHEMA,
|
|
37
|
+
requestId: { type: 'string', description: 'Id of the request created for the initial prompt; absent when no prompt was sent.' }
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const PROMPT_ACCEPTED_SCHEMA = {
|
|
41
|
+
type: 'object',
|
|
42
|
+
required: ['sessionId', 'requestId'],
|
|
43
|
+
properties: {
|
|
44
|
+
sessionId: { type: 'string', description: 'Id of the prompted session.' },
|
|
45
|
+
requestId: { type: 'string', description: 'Id of the created request.' }
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
/**
|
|
49
|
+
* Contributes the AI session API to the external API server:
|
|
50
|
+
* - `GET /api/ai/sessions` lists all sessions (restored and persisted) with id, title, status,
|
|
51
|
+
* agent, workspace, last interaction time, and a short plain-text preview of the conversation.
|
|
52
|
+
* - `POST /api/ai/sessions` creates a session in a frontend matching the requested workspace,
|
|
53
|
+
* optionally pinning an agent and sending an initial prompt.
|
|
54
|
+
* - `GET /api/ai/sessions/events` streams the session list as server-sent events, pushing an
|
|
55
|
+
* updated list whenever sessions change.
|
|
56
|
+
* - `GET /api/ai/sessions/:id` returns a single session including its conversation reduced to
|
|
57
|
+
* plain-text messages (persisted sessions report metadata only until restored).
|
|
58
|
+
* - `POST /api/ai/sessions/:id/open` shows the session in the chat view of a connected frontend.
|
|
59
|
+
* - `POST /api/ai/sessions/:id/restore` restores a persisted session and returns its detail.
|
|
60
|
+
* - `POST /api/ai/sessions/:id/prompt` sends a prompt to the session.
|
|
61
|
+
*
|
|
62
|
+
* The endpoints are served on the external API port and are token-protected when an
|
|
63
|
+
* external API token is configured (see `@theia/external-api`).
|
|
64
|
+
*/
|
|
65
|
+
let AIExternalApiEndpoint = class AIExternalApiEndpoint {
|
|
66
|
+
constructor() {
|
|
67
|
+
this.path = external_chat_session_provider_1.AI_SESSIONS_API_PATH;
|
|
68
|
+
this.documentation = {
|
|
69
|
+
title: 'AI Chat Sessions',
|
|
70
|
+
description: 'Inspect, follow, open, prompt, and create the AI chat sessions of this Theia instance.'
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
configure(router) {
|
|
74
|
+
router.get('/', {
|
|
75
|
+
operationId: 'listChatSessions',
|
|
76
|
+
summary: 'List all AI chat sessions, most recently used first.',
|
|
77
|
+
responses: {
|
|
78
|
+
200: { description: 'The current sessions of all connected frontends.', schema: SESSION_LIST_SCHEMA }
|
|
79
|
+
}
|
|
80
|
+
}, async () => rest_result_1.RestResult.ok({ sessions: await this.registry.getSessions() }));
|
|
81
|
+
// register before '/:id' so that 'events' is not treated as a session id
|
|
82
|
+
const events = router.eventStream('/events', {
|
|
83
|
+
event: 'sessions',
|
|
84
|
+
operationId: 'streamChatSessions',
|
|
85
|
+
summary: 'Stream the session list as server-sent events.',
|
|
86
|
+
description: 'On connect, the stream immediately delivers the current session list; afterwards, the full, '
|
|
87
|
+
+ 'updated list is pushed whenever sessions change. Consume each event as a replacement, not a delta.',
|
|
88
|
+
dataSchema: SESSION_LIST_SCHEMA,
|
|
89
|
+
snapshot: async () => ({ sessions: await this.registry.getSessions() })
|
|
90
|
+
});
|
|
91
|
+
router.toDispose.push(this.registry.onDidChangeSessions(() => events.notifyChanged()));
|
|
92
|
+
router.get('/:id', {
|
|
93
|
+
operationId: 'getChatSession',
|
|
94
|
+
summary: 'Get a single session including its conversation reduced to plain-text messages.',
|
|
95
|
+
params: { id: SESSION_ID_PARAM },
|
|
96
|
+
responses: {
|
|
97
|
+
200: {
|
|
98
|
+
description: 'The session detail. Persisted sessions that are not restored carry no messages.',
|
|
99
|
+
schema: external_chat_session_provider_1.ExternalChatSessionDetail.SCHEMA
|
|
100
|
+
},
|
|
101
|
+
404: { description: 'The session is unknown to all connected frontends.' }
|
|
102
|
+
}
|
|
103
|
+
}, async ({ params }) => {
|
|
104
|
+
const session = await this.registry.getSession(params.id);
|
|
105
|
+
return session ? rest_result_1.RestResult.ok(session) : rest_result_1.RestResult.notFound();
|
|
106
|
+
});
|
|
107
|
+
router.post('/', {
|
|
108
|
+
operationId: 'createChatSession',
|
|
109
|
+
summary: 'Create a chat session in a connected frontend and optionally send an initial prompt.',
|
|
110
|
+
bodySchema: external_chat_session_provider_1.ExternalChatSessionCreateRequest.SCHEMA,
|
|
111
|
+
responses: {
|
|
112
|
+
201: { description: 'The created session and, if an initial prompt was sent, the id of the created request.', schema: SESSION_CREATED_SCHEMA },
|
|
113
|
+
400: { description: 'The requested agent is not registered.' },
|
|
114
|
+
404: { description: 'No connected frontend matches the requested workspace.' },
|
|
115
|
+
409: { description: 'The workspace is ambiguous or no agent could handle the initial prompt.' },
|
|
116
|
+
503: { description: 'No frontend is connected.' }
|
|
117
|
+
}
|
|
118
|
+
}, ({ body }) => this.createSession(body));
|
|
119
|
+
router.post('/:id/open', {
|
|
120
|
+
operationId: 'openChatSession',
|
|
121
|
+
summary: 'Show the session in the chat view of a connected frontend, restoring it first if necessary.',
|
|
122
|
+
params: { id: SESSION_ID_PARAM },
|
|
123
|
+
responses: {
|
|
124
|
+
204: { description: 'The session is shown in a frontend.' },
|
|
125
|
+
404: { description: 'The session is unknown to all connected frontends.' }
|
|
126
|
+
}
|
|
127
|
+
}, async ({ params }) => await this.registry.openSession(params.id) ? rest_result_1.RestResult.noContent() : rest_result_1.RestResult.notFound());
|
|
128
|
+
router.post('/:id/restore', {
|
|
129
|
+
operationId: 'restoreChatSession',
|
|
130
|
+
summary: 'Restore the session in a connected frontend without focusing it, and return its detail.',
|
|
131
|
+
params: { id: SESSION_ID_PARAM },
|
|
132
|
+
responses: {
|
|
133
|
+
200: { description: 'The detail of the restored session.', schema: external_chat_session_provider_1.ExternalChatSessionDetail.SCHEMA },
|
|
134
|
+
404: { description: 'The session is unknown to all connected frontends.' }
|
|
135
|
+
}
|
|
136
|
+
}, async ({ params }) => {
|
|
137
|
+
const session = await this.registry.restoreSession(params.id);
|
|
138
|
+
return session ? rest_result_1.RestResult.ok(session) : rest_result_1.RestResult.notFound();
|
|
139
|
+
});
|
|
140
|
+
router.post('/:id/prompt', {
|
|
141
|
+
operationId: 'promptChatSession',
|
|
142
|
+
summary: 'Send a prompt to the session, restoring it first if necessary.',
|
|
143
|
+
bodySchema: external_chat_session_provider_1.ExternalChatPrompt.SCHEMA,
|
|
144
|
+
params: { id: SESSION_ID_PARAM },
|
|
145
|
+
responses: {
|
|
146
|
+
202: { description: 'The prompt was submitted; follow the progress via the event stream or the read endpoints.', schema: PROMPT_ACCEPTED_SCHEMA },
|
|
147
|
+
404: { description: 'The session is unknown to all connected frontends.' },
|
|
148
|
+
409: { description: 'A request is in progress and `interrupt` was not set, or no agent is available.' }
|
|
149
|
+
}
|
|
150
|
+
}, ({ params, body }) => this.sendPrompt(params.id, body));
|
|
151
|
+
}
|
|
152
|
+
async createSession(request) {
|
|
153
|
+
const result = await this.registry.createSession(request);
|
|
154
|
+
if ('created' in result) {
|
|
155
|
+
return rest_result_1.RestResult.created(result.created);
|
|
156
|
+
}
|
|
157
|
+
switch (result.failure) {
|
|
158
|
+
case 'unknownAgent':
|
|
159
|
+
return rest_result_1.RestResult.badRequest('unknown agent');
|
|
160
|
+
case 'noAgent':
|
|
161
|
+
return rest_result_1.RestResult.conflict('no agent available');
|
|
162
|
+
case 'noFrontend':
|
|
163
|
+
return rest_result_1.RestResult.error(503, 'no frontend connected');
|
|
164
|
+
case 'workspaceNotFound':
|
|
165
|
+
return rest_result_1.RestResult.notFound('workspace not found');
|
|
166
|
+
case 'ambiguousWorkspace':
|
|
167
|
+
return rest_result_1.RestResult.conflict('ambiguous workspace');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
async sendPrompt(sessionId, prompt) {
|
|
171
|
+
const result = await this.registry.sendPrompt(sessionId, prompt);
|
|
172
|
+
if (!result) {
|
|
173
|
+
return rest_result_1.RestResult.notFound();
|
|
174
|
+
}
|
|
175
|
+
if ('sent' in result) {
|
|
176
|
+
return rest_result_1.RestResult.accepted(result.sent);
|
|
177
|
+
}
|
|
178
|
+
return rest_result_1.RestResult.conflict(result.failure === 'busy' ? 'busy' : 'no agent available');
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
exports.AIExternalApiEndpoint = AIExternalApiEndpoint;
|
|
182
|
+
tslib_1.__decorate([
|
|
183
|
+
(0, inversify_1.inject)(external_chat_session_registry_1.ExternalChatSessionRegistry),
|
|
184
|
+
tslib_1.__metadata("design:type", external_chat_session_registry_1.ExternalChatSessionRegistry)
|
|
185
|
+
], AIExternalApiEndpoint.prototype, "registry", void 0);
|
|
186
|
+
exports.AIExternalApiEndpoint = AIExternalApiEndpoint = tslib_1.__decorate([
|
|
187
|
+
(0, inversify_1.injectable)()
|
|
188
|
+
], AIExternalApiEndpoint);
|
|
189
|
+
//# sourceMappingURL=ai-external-api-endpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-external-api-endpoint.js","sourceRoot":"","sources":["../../src/node/ai-external-api-endpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-external-api-endpoint.spec.d.ts","sourceRoot":"","sources":["../../src/node/ai-external-api-endpoint.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// *****************************************************************************
|
|
3
|
+
// Copyright (C) 2026 EclipseSource GmbH.
|
|
4
|
+
//
|
|
5
|
+
// This program and the accompanying materials are made available under the
|
|
6
|
+
// terms of the Eclipse Public License v. 2.0 which is available at
|
|
7
|
+
// http://www.eclipse.org/legal/epl-2.0.
|
|
8
|
+
//
|
|
9
|
+
// This Source Code may also be made available under the following Secondary
|
|
10
|
+
// Licenses when the conditions for such availability set forth in the Eclipse
|
|
11
|
+
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
12
|
+
// with the GNU Classpath Exception which is available at
|
|
13
|
+
// https://www.gnu.org/software/classpath/license.html.
|
|
14
|
+
//
|
|
15
|
+
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0
|
|
16
|
+
// *****************************************************************************
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
const core_1 = require("@theia/core");
|
|
19
|
+
const express = require("@theia/core/shared/express");
|
|
20
|
+
const external_api_test_support_1 = require("@theia/external-api/lib/node/test/external-api-test-support");
|
|
21
|
+
const chai_1 = require("chai");
|
|
22
|
+
const ai_external_api_endpoint_1 = require("./ai-external-api-endpoint");
|
|
23
|
+
describe('AIExternalApiEndpoint', () => {
|
|
24
|
+
const sessions = [
|
|
25
|
+
{
|
|
26
|
+
id: '1', title: 'session', status: 'running', lastInteraction: 100, workspace: 'file:///test/workspace',
|
|
27
|
+
preview: 'fix the build\nSure.', agentId: 'coder', agentName: 'Coder', restored: true
|
|
28
|
+
}
|
|
29
|
+
];
|
|
30
|
+
let server;
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
server?.close();
|
|
33
|
+
server?.closeAllConnections();
|
|
34
|
+
server = undefined;
|
|
35
|
+
});
|
|
36
|
+
async function serve(registry = {}) {
|
|
37
|
+
const sessionsChanged = new core_1.Emitter();
|
|
38
|
+
const endpoint = external_api_test_support_1.ExternalApiTestSupport.inject(new ai_external_api_endpoint_1.AIExternalApiEndpoint(), {
|
|
39
|
+
registry: {
|
|
40
|
+
getSessions: async () => sessions,
|
|
41
|
+
getSession: async (id) => sessions.find(candidate => candidate.id === id),
|
|
42
|
+
openSession: async (id) => sessions.some(candidate => candidate.id === id),
|
|
43
|
+
restoreSession: async (id) => sessions.find(candidate => candidate.id === id),
|
|
44
|
+
sendPrompt: async (id) => sessions.some(candidate => candidate.id === id)
|
|
45
|
+
? { sent: { sessionId: id, requestId: 'r1' } }
|
|
46
|
+
: undefined,
|
|
47
|
+
createSession: async () => ({ created: { session: sessions[0], requestId: 'r1' } }),
|
|
48
|
+
onDidChangeSessions: sessionsChanged.event,
|
|
49
|
+
...registry
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
const app = express();
|
|
53
|
+
const router = external_api_test_support_1.ExternalApiTestSupport.mountContribution(app, endpoint);
|
|
54
|
+
const listening = new Promise(resolve => {
|
|
55
|
+
server = app.listen(0, '127.0.0.1', () => resolve());
|
|
56
|
+
});
|
|
57
|
+
await listening;
|
|
58
|
+
return { url: `http://127.0.0.1:${server.address().port}${endpoint.path}`, router, sessionsChanged };
|
|
59
|
+
}
|
|
60
|
+
function eventData(event) {
|
|
61
|
+
const data = event?.split('\n').find(line => line.startsWith('data: '));
|
|
62
|
+
(0, chai_1.expect)(data, `expected a data line in event: ${event}`).to.not.equal(undefined);
|
|
63
|
+
return JSON.parse(data.substring('data: '.length));
|
|
64
|
+
}
|
|
65
|
+
it('lists sessions', async () => {
|
|
66
|
+
const { url } = await serve();
|
|
67
|
+
const response = await fetch(url);
|
|
68
|
+
(0, chai_1.expect)(response.status).to.equal(200);
|
|
69
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ sessions });
|
|
70
|
+
});
|
|
71
|
+
it('returns a single session', async () => {
|
|
72
|
+
const { url } = await serve();
|
|
73
|
+
const response = await fetch(`${url}/1`);
|
|
74
|
+
(0, chai_1.expect)(response.status).to.equal(200);
|
|
75
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal(sessions[0]);
|
|
76
|
+
});
|
|
77
|
+
it('returns 404 for unknown sessions', async () => {
|
|
78
|
+
const { url } = await serve();
|
|
79
|
+
const response = await fetch(`${url}/missing`);
|
|
80
|
+
(0, chai_1.expect)(response.status).to.equal(404);
|
|
81
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'not found' });
|
|
82
|
+
});
|
|
83
|
+
it('returns 500 when gathering session data fails', async () => {
|
|
84
|
+
const { url } = await serve({ getSessions: async () => { throw new Error('boom'); } });
|
|
85
|
+
const response = await fetch(url);
|
|
86
|
+
(0, chai_1.expect)(response.status).to.equal(500);
|
|
87
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'internal error' });
|
|
88
|
+
});
|
|
89
|
+
describe('open and restore', () => {
|
|
90
|
+
it('opens a session', async () => {
|
|
91
|
+
const opened = [];
|
|
92
|
+
const { url } = await serve({ openSession: async (id) => { opened.push(id); return true; } });
|
|
93
|
+
const response = await fetch(`${url}/1/open`, { method: 'POST' });
|
|
94
|
+
(0, chai_1.expect)(response.status).to.equal(204);
|
|
95
|
+
(0, chai_1.expect)(opened).to.deep.equal(['1']);
|
|
96
|
+
});
|
|
97
|
+
it('returns 404 when opening an unknown session', async () => {
|
|
98
|
+
const { url } = await serve();
|
|
99
|
+
const response = await fetch(`${url}/missing/open`, { method: 'POST' });
|
|
100
|
+
(0, chai_1.expect)(response.status).to.equal(404);
|
|
101
|
+
});
|
|
102
|
+
it('restores a session and returns its detail', async () => {
|
|
103
|
+
const { url } = await serve();
|
|
104
|
+
const response = await fetch(`${url}/1/restore`, { method: 'POST' });
|
|
105
|
+
(0, chai_1.expect)(response.status).to.equal(200);
|
|
106
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal(sessions[0]);
|
|
107
|
+
});
|
|
108
|
+
it('returns 404 when restoring an unknown session', async () => {
|
|
109
|
+
const { url } = await serve();
|
|
110
|
+
const response = await fetch(`${url}/missing/restore`, { method: 'POST' });
|
|
111
|
+
(0, chai_1.expect)(response.status).to.equal(404);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
describe('create and prompt', () => {
|
|
115
|
+
function post(url, body) {
|
|
116
|
+
return fetch(url, {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
headers: { 'content-type': 'application/json' },
|
|
119
|
+
body: typeof body === 'string' ? body : JSON.stringify(body)
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
it('creates a session', async () => {
|
|
123
|
+
const { url } = await serve();
|
|
124
|
+
const response = await post(url, { workspace: 'file:///test/workspace', agentId: 'coder', prompt: 'fix the build' });
|
|
125
|
+
(0, chai_1.expect)(response.status).to.equal(201);
|
|
126
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ session: sessions[0], requestId: 'r1' });
|
|
127
|
+
});
|
|
128
|
+
it('rejects an invalid creation request with the validation errors as details', async () => {
|
|
129
|
+
const { url } = await serve();
|
|
130
|
+
const response = await post(url, { focus: 'yes' });
|
|
131
|
+
(0, chai_1.expect)(response.status).to.equal(400);
|
|
132
|
+
const body = await response.json();
|
|
133
|
+
(0, chai_1.expect)(body.error).to.equal('invalid request');
|
|
134
|
+
(0, chai_1.expect)(body.details).to.have.length(1);
|
|
135
|
+
(0, chai_1.expect)(body.details[0]).to.contain('focus');
|
|
136
|
+
});
|
|
137
|
+
it('rejects a creation request with a blank workspace', async () => {
|
|
138
|
+
const { url } = await serve();
|
|
139
|
+
const response = await post(url, { workspace: ' ' });
|
|
140
|
+
(0, chai_1.expect)(response.status).to.equal(400);
|
|
141
|
+
const error = await response.json();
|
|
142
|
+
(0, chai_1.expect)(error.error).to.equal('invalid request');
|
|
143
|
+
(0, chai_1.expect)(error.details[0]).to.contain('workspace');
|
|
144
|
+
});
|
|
145
|
+
it('rejects an unknown agent', async () => {
|
|
146
|
+
const { url } = await serve({ createSession: async () => ({ failure: 'unknownAgent' }) });
|
|
147
|
+
const response = await post(url, { agentId: 'ghost' });
|
|
148
|
+
(0, chai_1.expect)(response.status).to.equal(400);
|
|
149
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'unknown agent' });
|
|
150
|
+
});
|
|
151
|
+
it('rejects an unknown workspace', async () => {
|
|
152
|
+
const { url } = await serve({ createSession: async () => ({ failure: 'workspaceNotFound' }) });
|
|
153
|
+
const response = await post(url, { workspace: 'file:///other' });
|
|
154
|
+
(0, chai_1.expect)(response.status).to.equal(404);
|
|
155
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'workspace not found' });
|
|
156
|
+
});
|
|
157
|
+
it('rejects a creation request when no frontend is connected', async () => {
|
|
158
|
+
const { url } = await serve({ createSession: async () => ({ failure: 'noFrontend' }) });
|
|
159
|
+
const response = await post(url, {});
|
|
160
|
+
(0, chai_1.expect)(response.status).to.equal(503);
|
|
161
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'no frontend connected' });
|
|
162
|
+
});
|
|
163
|
+
it('rejects an ambiguous workspace', async () => {
|
|
164
|
+
const { url } = await serve({ createSession: async () => ({ failure: 'ambiguousWorkspace' }) });
|
|
165
|
+
const response = await post(url, {});
|
|
166
|
+
(0, chai_1.expect)(response.status).to.equal(409);
|
|
167
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'ambiguous workspace' });
|
|
168
|
+
});
|
|
169
|
+
it('sends a prompt to a session', async () => {
|
|
170
|
+
const { url } = await serve();
|
|
171
|
+
const response = await post(`${url}/1/prompt`, { text: 'continue' });
|
|
172
|
+
(0, chai_1.expect)(response.status).to.equal(202);
|
|
173
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ sessionId: '1', requestId: 'r1' });
|
|
174
|
+
});
|
|
175
|
+
it('returns 404 when prompting an unknown session', async () => {
|
|
176
|
+
const { url } = await serve();
|
|
177
|
+
const response = await post(`${url}/missing/prompt`, { text: 'continue' });
|
|
178
|
+
(0, chai_1.expect)(response.status).to.equal(404);
|
|
179
|
+
});
|
|
180
|
+
it('returns 409 when the session is busy', async () => {
|
|
181
|
+
const { url } = await serve({ sendPrompt: async () => ({ failure: 'busy' }) });
|
|
182
|
+
const response = await post(`${url}/1/prompt`, { text: 'continue' });
|
|
183
|
+
(0, chai_1.expect)(response.status).to.equal(409);
|
|
184
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'busy' });
|
|
185
|
+
});
|
|
186
|
+
it('returns 409 when no agent is available', async () => {
|
|
187
|
+
const { url } = await serve({ sendPrompt: async () => ({ failure: 'noAgent' }) });
|
|
188
|
+
const response = await post(`${url}/1/prompt`, { text: 'continue' });
|
|
189
|
+
(0, chai_1.expect)(response.status).to.equal(409);
|
|
190
|
+
(0, chai_1.expect)(await response.json()).to.deep.equal({ error: 'no agent available' });
|
|
191
|
+
});
|
|
192
|
+
it('rejects a prompt without text', async () => {
|
|
193
|
+
const { url } = await serve();
|
|
194
|
+
const response = await post(`${url}/1/prompt`, { text: ' ' });
|
|
195
|
+
(0, chai_1.expect)(response.status).to.equal(400);
|
|
196
|
+
const error = await response.json();
|
|
197
|
+
(0, chai_1.expect)(error.error).to.equal('invalid request');
|
|
198
|
+
(0, chai_1.expect)(error.details[0]).to.contain('text');
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
describe('events', () => {
|
|
202
|
+
it('streams the current sessions on connect', async () => {
|
|
203
|
+
const { url } = await serve();
|
|
204
|
+
const response = await fetch(`${url}/events`);
|
|
205
|
+
(0, chai_1.expect)(response.status).to.equal(200);
|
|
206
|
+
(0, chai_1.expect)(response.headers.get('content-type')).to.equal('text/event-stream');
|
|
207
|
+
const events = external_api_test_support_1.ExternalApiTestSupport.sseReader(response);
|
|
208
|
+
const first = await events.next();
|
|
209
|
+
(0, chai_1.expect)(first).to.contain('event: sessions');
|
|
210
|
+
(0, chai_1.expect)(eventData(first)).to.deep.equal({ sessions });
|
|
211
|
+
await events.cancel();
|
|
212
|
+
});
|
|
213
|
+
it('pushes an updated list when sessions change', async () => {
|
|
214
|
+
const { url, sessionsChanged } = await serve();
|
|
215
|
+
const response = await fetch(`${url}/events`);
|
|
216
|
+
const events = external_api_test_support_1.ExternalApiTestSupport.sseReader(response);
|
|
217
|
+
await events.next();
|
|
218
|
+
sessionsChanged.fire();
|
|
219
|
+
const update = await events.next();
|
|
220
|
+
(0, chai_1.expect)(eventData(update)).to.deep.equal({ sessions });
|
|
221
|
+
await events.cancel();
|
|
222
|
+
});
|
|
223
|
+
it('closes event streams when the routing is rebuilt', async () => {
|
|
224
|
+
const { url, router } = await serve();
|
|
225
|
+
const response = await fetch(`${url}/events`);
|
|
226
|
+
const events = external_api_test_support_1.ExternalApiTestSupport.sseReader(response);
|
|
227
|
+
await events.next();
|
|
228
|
+
router.dispose();
|
|
229
|
+
(0, chai_1.expect)(await events.next()).to.equal(undefined);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
//# sourceMappingURL=ai-external-api-endpoint.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-external-api-endpoint.spec.js","sourceRoot":"","sources":["../../src/node/ai-external-api-endpoint.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Emitter, Event } from '@theia/core';
|
|
2
|
+
import { ILogger } from '@theia/core/lib/common/logger';
|
|
3
|
+
import { ExternalChatPrompt, ExternalChatPromptResult, ExternalChatSessionCreateRequest, ExternalChatSessionCreateResult, ExternalChatSessionDetail, ExternalChatSessionProvider, ExternalChatSessionSummary } from '../common/external-chat-session-provider';
|
|
4
|
+
/**
|
|
5
|
+
* Aggregates the {@link ExternalChatSessionProvider}s of all connected frontends.
|
|
6
|
+
*
|
|
7
|
+
* Providers register when a frontend connects and are removed when its connection closes.
|
|
8
|
+
* Queries fan out to all providers; a failing or unresponsive provider is logged and skipped
|
|
9
|
+
* so that a broken, busy, or disconnecting frontend does not break the external API. Sessions
|
|
10
|
+
* reported by more than one provider (e.g. a session restored in several frontends) are
|
|
11
|
+
* deduplicated, preferring restored over persisted-only, in-progress over finished, and more
|
|
12
|
+
* recent over older reports. Session actions (open, restore) are routed to the preferred
|
|
13
|
+
* provider in the same order.
|
|
14
|
+
*/
|
|
15
|
+
export declare class ExternalChatSessionRegistry {
|
|
16
|
+
/**
|
|
17
|
+
* Timeout in milliseconds after which an unresponsive provider is skipped in the query
|
|
18
|
+
* fan-outs. Only the read-only queries are bounded: an action call may legitimately take
|
|
19
|
+
* longer, and abandoning it could send it twice.
|
|
20
|
+
*/
|
|
21
|
+
protected readonly queryTimeout = 10000;
|
|
22
|
+
protected readonly logger: ILogger;
|
|
23
|
+
protected readonly providers: Set<ExternalChatSessionProvider>;
|
|
24
|
+
protected readonly onDidChangeSessionsEmitter: Emitter<void>;
|
|
25
|
+
/** Fired when the set of connected frontends changes or a frontend reports a session change. */
|
|
26
|
+
readonly onDidChangeSessions: Event<void>;
|
|
27
|
+
addProvider(provider: ExternalChatSessionProvider): void;
|
|
28
|
+
removeProvider(provider: ExternalChatSessionProvider): void;
|
|
29
|
+
/** Announces that the sessions visible through this registry changed, see {@link onDidChangeSessions}. */
|
|
30
|
+
notifySessionsChanged(): void;
|
|
31
|
+
getSessions(): Promise<ExternalChatSessionSummary[]>;
|
|
32
|
+
/**
|
|
33
|
+
* Returns the detail of the session from the preferred frontend that knows it, or
|
|
34
|
+
* `undefined` if no connected frontend knows it. The frontends are ranked by their session
|
|
35
|
+
* summaries, so that only the preferred frontend has to report the conversation.
|
|
36
|
+
*/
|
|
37
|
+
getSession(sessionId: string): Promise<ExternalChatSessionDetail | undefined>;
|
|
38
|
+
/**
|
|
39
|
+
* Opens the session in the preferred frontend that knows it, restoring it if necessary.
|
|
40
|
+
* Returns `false` if no connected frontend knows the session.
|
|
41
|
+
*/
|
|
42
|
+
openSession(sessionId: string): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Restores the session in the preferred frontend that knows it and returns its detail.
|
|
45
|
+
* Returns `undefined` if no connected frontend knows the session.
|
|
46
|
+
*/
|
|
47
|
+
restoreSession(sessionId: string): Promise<ExternalChatSessionDetail | undefined>;
|
|
48
|
+
/**
|
|
49
|
+
* Sends the prompt to the given session in the preferred frontend that knows it.
|
|
50
|
+
* The first definitive answer wins: in particular, a `busy` rejection by the preferred
|
|
51
|
+
* frontend is not retried against less preferred copies of the session.
|
|
52
|
+
* Returns `undefined` if no connected frontend knows the session.
|
|
53
|
+
*/
|
|
54
|
+
sendPrompt(sessionId: string, prompt: ExternalChatPrompt): Promise<ExternalChatPromptResult | undefined>;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a session in a frontend matching the requested workspace. Without a requested
|
|
57
|
+
* workspace, the session is created in the only connected frontend, and if the connected
|
|
58
|
+
* frontends have different workspaces open, the request is rejected as ambiguous.
|
|
59
|
+
* Rejected with `noFrontend` when no frontend is connected or none responds.
|
|
60
|
+
*/
|
|
61
|
+
createSession(request: ExternalChatSessionCreateRequest): Promise<ExternalChatSessionCreateResult>;
|
|
62
|
+
/** Returns the providers whose workspace matches the given one, or all providers if none is given. */
|
|
63
|
+
protected getProvidersForWorkspace(workspace: string | undefined): Promise<{
|
|
64
|
+
provider: ExternalChatSessionProvider;
|
|
65
|
+
workspace?: string;
|
|
66
|
+
}[]>;
|
|
67
|
+
/**
|
|
68
|
+
* Normalizes a workspace URI for comparison: URIs that denote the same workspace but differ
|
|
69
|
+
* in their path encoding or in a trailing separator normalize to the same string.
|
|
70
|
+
*/
|
|
71
|
+
protected normalizeWorkspace(workspace: string): string;
|
|
72
|
+
/** Returns the providers that know the given session, most preferred report first. */
|
|
73
|
+
protected getProvidersFor(sessionId: string): Promise<ExternalChatSessionProvider[]>;
|
|
74
|
+
protected queryProviders<T>(query: (provider: ExternalChatSessionProvider) => Promise<T | undefined>): Promise<T[]>;
|
|
75
|
+
/**
|
|
76
|
+
* Rejects when the query does not answer within {@link queryTimeout}. Theia's RPC has no
|
|
77
|
+
* request timeout of its own, so an unresponsive frontend would otherwise stall the
|
|
78
|
+
* external API request that fans out to it indefinitely.
|
|
79
|
+
*/
|
|
80
|
+
protected withQueryTimeout<T>(query: Promise<T>, description: string): Promise<T>;
|
|
81
|
+
protected prefer(candidate: ExternalChatSessionSummary, existing: ExternalChatSessionSummary): boolean;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=external-chat-session-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-chat-session-registry.d.ts","sourceRoot":"","sources":["../../src/node/external-chat-session-registry.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAO,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,+BAA+B,CAAC;AAExD,OAAO,EACH,kBAAkB,EAAE,wBAAwB,EAAE,gCAAgC,EAAE,+BAA+B,EAC/G,yBAAyB,EAAE,2BAA2B,EAAE,0BAA0B,EACrF,MAAM,0CAA0C,CAAC;AAElD;;;;;;;;;;GAUG;AACH,qBACa,2BAA2B;IAEpC;;;;OAIG;IACH,SAAS,CAAC,QAAQ,CAAC,YAAY,SAAU;IAGzC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAEnC,SAAS,CAAC,QAAQ,CAAC,SAAS,mCAA0C;IAEtE,SAAS,CAAC,QAAQ,CAAC,0BAA0B,gBAAuB;IACpE,gGAAgG;IAChG,QAAQ,CAAC,mBAAmB,EAAE,KAAK,CAAC,IAAI,CAAC,CAAyC;IAElF,WAAW,CAAC,QAAQ,EAAE,2BAA2B,GAAG,IAAI;IAKxD,cAAc,CAAC,QAAQ,EAAE,2BAA2B,GAAG,IAAI;IAM3D,0GAA0G;IAC1G,qBAAqB,IAAI,IAAI;IAIvB,WAAW,IAAI,OAAO,CAAC,0BAA0B,EAAE,CAAC;IAa1D;;;;OAIG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC;IAcnF;;;OAGG;IACG,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAatD;;;OAGG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,yBAAyB,GAAG,SAAS,CAAC;IAcvF;;;;;OAKG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,wBAAwB,GAAG,SAAS,CAAC;IAc9G;;;;;OAKG;IACG,aAAa,CAAC,OAAO,EAAE,gCAAgC,GAAG,OAAO,CAAC,+BAA+B,CAAC;IAqBxG,sGAAsG;cACtF,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,2BAA2B,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAiBjJ;;;OAGG;IACH,SAAS,CAAC,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAMvD,sFAAsF;cACtE,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,2BAA2B,EAAE,CAAC;cAiB1E,cAAc,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,2BAA2B,KAAK,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAezH;;;;OAIG;IACH,SAAS,CAAC,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAQjF,SAAS,CAAC,MAAM,CAAC,SAAS,EAAE,0BAA0B,EAAE,QAAQ,EAAE,0BAA0B,GAAG,OAAO;CAUzG"}
|