@pellux/goodvibes-sdk 0.18.41 → 0.18.43
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/dist/_internal/daemon/runtime-route-types.d.ts +7 -0
- package/dist/_internal/daemon/runtime-route-types.d.ts.map +1 -1
- package/dist/_internal/daemon/runtime-session-routes.d.ts.map +1 -1
- package/dist/_internal/daemon/runtime-session-routes.js +43 -0
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts +94 -0
- package/dist/_internal/platform/companion/companion-chat-manager.d.ts.map +1 -0
- package/dist/_internal/platform/companion/companion-chat-manager.js +291 -0
- package/dist/_internal/platform/companion/companion-chat-route-types.d.ts +31 -0
- package/dist/_internal/platform/companion/companion-chat-route-types.d.ts.map +1 -0
- package/dist/_internal/platform/companion/companion-chat-route-types.js +6 -0
- package/dist/_internal/platform/companion/companion-chat-routes.d.ts +23 -0
- package/dist/_internal/platform/companion/companion-chat-routes.d.ts.map +1 -0
- package/dist/_internal/platform/companion/companion-chat-routes.js +133 -0
- package/dist/_internal/platform/companion/companion-chat-types.d.ts +108 -0
- package/dist/_internal/platform/companion/companion-chat-types.d.ts.map +1 -0
- package/dist/_internal/platform/companion/companion-chat-types.js +11 -0
- package/dist/_internal/platform/companion/index.d.ts +6 -0
- package/dist/_internal/platform/companion/index.d.ts.map +1 -0
- package/dist/_internal/platform/companion/index.js +2 -0
- package/dist/_internal/platform/control-plane/conversation-message.d.ts +29 -0
- package/dist/_internal/platform/control-plane/conversation-message.d.ts.map +1 -0
- package/dist/_internal/platform/control-plane/conversation-message.js +9 -0
- package/dist/_internal/platform/control-plane/index.d.ts +1 -0
- package/dist/_internal/platform/control-plane/index.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/session-broker.d.ts +45 -0
- package/dist/_internal/platform/control-plane/session-broker.d.ts.map +1 -1
- package/dist/_internal/platform/control-plane/session-broker.js +197 -5
- package/dist/_internal/platform/control-plane/session-types.d.ts +16 -0
- package/dist/_internal/platform/control-plane/session-types.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade-composition.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade-composition.js +7 -0
- package/dist/_internal/platform/daemon/facade.d.ts +2 -0
- package/dist/_internal/platform/daemon/facade.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/facade.js +17 -0
- package/dist/_internal/platform/daemon/http/router.d.ts +7 -0
- package/dist/_internal/platform/daemon/http/router.d.ts.map +1 -1
- package/dist/_internal/platform/daemon/http/router.js +34 -0
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts +7 -0
- package/dist/_internal/platform/daemon/http/runtime-route-types.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/tasks/adapters/agent-adapter.d.ts +25 -0
- package/dist/_internal/platform/runtime/tasks/adapters/agent-adapter.d.ts.map +1 -1
- package/dist/_internal/platform/runtime/tasks/adapters/agent-adapter.js +85 -0
- package/dist/_internal/platform/version.js +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DaemonApiRouteHandlers } from './context.js';
|
|
2
|
+
import type { ConversationMessageEnvelope } from '../platform/control-plane/conversation-message.js';
|
|
2
3
|
export type JsonBody = Record<string, unknown>;
|
|
3
4
|
export type AutomationSurfaceKind = string;
|
|
4
5
|
export interface SharedSessionRoutingIntent {
|
|
@@ -234,6 +235,12 @@ export interface DaemonRuntimeRouteContext {
|
|
|
234
235
|
readonly runtimeDispatch: {
|
|
235
236
|
transitionRuntimeTask(taskId: string, status: string, patch: Record<string, unknown>, source: string): void;
|
|
236
237
|
} | null;
|
|
238
|
+
/**
|
|
239
|
+
* Publish a conversation follow-up event scoped to a specific session.
|
|
240
|
+
* Used by Problem-2 message routing: kind='message' submits skip agent spawn
|
|
241
|
+
* and instead broadcast a ConversationMessageEnvelope to TUI surface subscribers.
|
|
242
|
+
*/
|
|
243
|
+
readonly publishConversationFollowup: (sessionId: string, envelope: Omit<ConversationMessageEnvelope, 'sessionId'>) => void;
|
|
237
244
|
}
|
|
238
245
|
export type DaemonRuntimeRouteHandlerMap = Pick<DaemonApiRouteHandlers, 'createSharedSession' | 'getAutomationJobs' | 'postAutomationJob' | 'getAutomationRuns' | 'getAutomationRun' | 'getAutomationHeartbeat' | 'postAutomationHeartbeat' | 'automationRunAction' | 'patchAutomationJob' | 'deleteAutomationJob' | 'setAutomationJobEnabled' | 'runAutomationJobNow' | 'postTask' | 'getSharedSession' | 'closeSharedSession' | 'reopenSharedSession' | 'getSharedSessionMessages' | 'getSharedSessionInputs' | 'postSharedSessionMessage' | 'postSharedSessionSteer' | 'postSharedSessionFollowUp' | 'cancelSharedSessionInput' | 'getRuntimeTask' | 'runtimeTaskAction' | 'getTaskStatus' | 'getSchedules' | 'postSchedule' | 'deleteSchedule' | 'setScheduleEnabled' | 'runScheduleNow'>;
|
|
239
246
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-route-types.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/runtime-route-types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime-route-types.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/runtime-route-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-session-routes.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/runtime-session-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime-session-routes.d.ts","sourceRoot":"","sources":["../../../src/_internal/daemon/runtime-session-routes.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAEV,yBAAyB,EAI1B,MAAM,0BAA0B,CAAC;AAMlC,wBAAgB,uCAAuC,CACrD,OAAO,EAAE,yBAAyB,GACjC,IAAI,CACL,sBAAsB,EACpB,qBAAqB,GACrB,UAAU,GACV,kBAAkB,GAClB,oBAAoB,GACpB,qBAAqB,GACrB,0BAA0B,GAC1B,wBAAwB,GACxB,0BAA0B,GAC1B,wBAAwB,GACxB,2BAA2B,GAC3B,0BAA0B,GAC1B,gBAAgB,GAChB,mBAAmB,GACnB,eAAe,CAClB,CAiBA"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Synced from packages/daemon-sdk/src/runtime-session-routes.ts
|
|
2
|
+
// Extracted from legacy source: src/daemon/http/runtime-session-routes.ts
|
|
3
|
+
import { randomUUID } from 'node:crypto';
|
|
1
4
|
export function createDaemonRuntimeSessionRouteHandlers(context) {
|
|
2
5
|
return {
|
|
3
6
|
createSharedSession: async (request) => handleCreateSharedSession(context, request),
|
|
@@ -193,15 +196,55 @@ async function handlePostSharedSessionMessage(context, sessionId, req) {
|
|
|
193
196
|
const body = await context.parseJsonBody(req);
|
|
194
197
|
if (body instanceof Response)
|
|
195
198
|
return body;
|
|
199
|
+
// Validate kind field — only 'task' (default) and 'message' are accepted
|
|
200
|
+
const kind = body.kind === undefined ? 'task' : body.kind;
|
|
201
|
+
if (kind !== 'task' && kind !== 'message') {
|
|
202
|
+
return Response.json({ error: `Invalid kind '${String(kind)}'. Accepted values: 'task' | 'message'`, code: 'INVALID_KIND' }, { status: 400 });
|
|
203
|
+
}
|
|
196
204
|
const message = readSharedSessionMessageBody(body);
|
|
197
205
|
if (!message) {
|
|
198
206
|
return Response.json({ error: 'Missing shared session message body' }, { status: 400 });
|
|
199
207
|
}
|
|
208
|
+
// Problem 2: kind='message' — route as companion follow-up, never spawn an agent
|
|
209
|
+
if (kind === 'message') {
|
|
210
|
+
return handleCompanionMessageRouting(context, sessionId, message, body, req);
|
|
211
|
+
}
|
|
200
212
|
const submission = await context.sessionBroker.submitMessage(buildSharedSessionMessageInput(sessionId, body, message));
|
|
201
213
|
return await respondToSessionSubmission(context, req, submission, message, `/api/sessions/${sessionId}/messages`, 'DaemonServer.handlePostSharedSessionMessage', {
|
|
202
214
|
context: `shared-session:${submission.session.id}`,
|
|
203
215
|
});
|
|
204
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Problem 2: companion message routing.
|
|
219
|
+
*
|
|
220
|
+
* A companion follow-up message is injected directly into the operator's
|
|
221
|
+
* live conversation context via the control-plane event bus. No agent is
|
|
222
|
+
* spawned; the TUI operator decides whether to respond.
|
|
223
|
+
*
|
|
224
|
+
* The message is routed as a control-plane event to the operator's live
|
|
225
|
+
* conversation; no input record is created and no agent is spawned.
|
|
226
|
+
* A `conversation.followup.companion` event is published scoped to the target
|
|
227
|
+
* session's TUI-surface subscribers, carrying a ConversationMessageEnvelope.
|
|
228
|
+
*/
|
|
229
|
+
function handleCompanionMessageRouting(context, sessionId, messageText, _body, req) {
|
|
230
|
+
const session = context.sessionBroker.getSession(sessionId);
|
|
231
|
+
if (!session) {
|
|
232
|
+
return Response.json({ error: 'Unknown shared session', code: 'SESSION_NOT_FOUND' }, { status: 404 });
|
|
233
|
+
}
|
|
234
|
+
if (session.status === 'closed') {
|
|
235
|
+
return Response.json({ error: 'Session is closed', code: 'SESSION_CLOSED' }, { status: 409 });
|
|
236
|
+
}
|
|
237
|
+
const messageId = randomUUID();
|
|
238
|
+
const timestamp = Date.now();
|
|
239
|
+
// Publish the follow-up event scoped to this session's TUI surface subscriber
|
|
240
|
+
context.publishConversationFollowup(sessionId, {
|
|
241
|
+
messageId,
|
|
242
|
+
body: messageText,
|
|
243
|
+
source: 'companion-followup',
|
|
244
|
+
timestamp,
|
|
245
|
+
});
|
|
246
|
+
return context.recordApiResponse(req, `/api/sessions/${sessionId}/messages`, Response.json({ messageId, routedTo: 'conversation' }, { status: 202 }));
|
|
247
|
+
}
|
|
205
248
|
async function handlePostSharedSessionSteer(context, sessionId, req) {
|
|
206
249
|
const body = await context.parseJsonBody(req);
|
|
207
250
|
if (body instanceof Response)
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* companion-chat-manager.ts
|
|
3
|
+
*
|
|
4
|
+
* In-memory manager for companion-app chat-mode sessions.
|
|
5
|
+
*
|
|
6
|
+
* Design:
|
|
7
|
+
* - Each session owns a ConversationManager (isolated message history).
|
|
8
|
+
* - When a user message is posted, the manager appends it to the conversation
|
|
9
|
+
* and runs a lightweight LLM turn using the provider registry.
|
|
10
|
+
* - Streaming chunks are fanned out via ControlPlaneGateway.publishEvent
|
|
11
|
+
* with a per-session clientId filter, so they only reach the subscriber
|
|
12
|
+
* for that specific session — never the global TUI event feed.
|
|
13
|
+
* - A GC sweep closes sessions that have been idle beyond the TTL.
|
|
14
|
+
*
|
|
15
|
+
* TODO (follow-up): persist sessions across daemon restart.
|
|
16
|
+
* TODO (follow-up): rate-limiting per session / per client.
|
|
17
|
+
* TODO (follow-up): tool-call execution requires ToolRegistry injection;
|
|
18
|
+
* currently tools are passed through the Orchestrator which needs the
|
|
19
|
+
* full TUI context. For v1, we provide a no-op tool registry so tool
|
|
20
|
+
* calls degrade gracefully. Proper tool support requires the daemon to
|
|
21
|
+
* inject its ToolRegistry into CompanionChatManager.
|
|
22
|
+
*/
|
|
23
|
+
import type { CompanionChatMessage, CompanionChatSession, CreateCompanionChatSessionInput } from './companion-chat-types.js';
|
|
24
|
+
export interface CompanionProviderMessage {
|
|
25
|
+
readonly role: 'user' | 'assistant';
|
|
26
|
+
readonly content: string;
|
|
27
|
+
}
|
|
28
|
+
export interface CompanionProviderChunk {
|
|
29
|
+
readonly type: 'text_delta' | 'tool_call' | 'tool_result' | 'done' | 'error';
|
|
30
|
+
readonly delta?: string;
|
|
31
|
+
readonly toolCallId?: string;
|
|
32
|
+
readonly toolName?: string;
|
|
33
|
+
readonly toolInput?: unknown;
|
|
34
|
+
readonly result?: unknown;
|
|
35
|
+
readonly isError?: boolean;
|
|
36
|
+
readonly error?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface CompanionLLMProvider {
|
|
39
|
+
/** Stream a single-turn conversation. Yields chunks. */
|
|
40
|
+
chatStream(messages: CompanionProviderMessage[], options: {
|
|
41
|
+
readonly systemPrompt?: string | null;
|
|
42
|
+
readonly model?: string | null;
|
|
43
|
+
readonly provider?: string | null;
|
|
44
|
+
readonly abortSignal?: AbortSignal;
|
|
45
|
+
}): AsyncIterable<CompanionProviderChunk>;
|
|
46
|
+
}
|
|
47
|
+
export interface CompanionChatEventPublisher {
|
|
48
|
+
publishEvent(event: string, payload: unknown, filter?: {
|
|
49
|
+
clientId?: string;
|
|
50
|
+
}): void;
|
|
51
|
+
}
|
|
52
|
+
export interface CompanionChatManagerConfig {
|
|
53
|
+
readonly provider: CompanionLLMProvider;
|
|
54
|
+
readonly eventPublisher: CompanionChatEventPublisher;
|
|
55
|
+
/** Override for tests */
|
|
56
|
+
readonly idleActiveMs?: number;
|
|
57
|
+
/** Override for tests */
|
|
58
|
+
readonly idleEmptyMs?: number;
|
|
59
|
+
/** Override for tests */
|
|
60
|
+
readonly gcIntervalMs?: number;
|
|
61
|
+
}
|
|
62
|
+
export declare class CompanionChatManager {
|
|
63
|
+
private readonly sessions;
|
|
64
|
+
private readonly provider;
|
|
65
|
+
private readonly eventPublisher;
|
|
66
|
+
private readonly idleActiveMs;
|
|
67
|
+
private readonly idleEmptyMs;
|
|
68
|
+
private gcTimer;
|
|
69
|
+
constructor(config: CompanionChatManagerConfig);
|
|
70
|
+
createSession(input?: CreateCompanionChatSessionInput): CompanionChatSession;
|
|
71
|
+
getSession(sessionId: string): CompanionChatSession | null;
|
|
72
|
+
getMessages(sessionId: string): CompanionChatMessage[];
|
|
73
|
+
/**
|
|
74
|
+
* Register the SSE clientId for this session so events are routed only to
|
|
75
|
+
* the correct subscriber. Replaces any previous registration (single subscriber
|
|
76
|
+
* per session in v1 — the last SSE connection wins).
|
|
77
|
+
*/
|
|
78
|
+
registerSubscriber(sessionId: string, clientId: string): void;
|
|
79
|
+
/**
|
|
80
|
+
* Close a session cleanly. Aborts any in-flight turn. Returns the session
|
|
81
|
+
* snapshot, or null if not found.
|
|
82
|
+
*/
|
|
83
|
+
closeSession(sessionId: string): CompanionChatSession | null;
|
|
84
|
+
/**
|
|
85
|
+
* Post a user message and start an async LLM turn. Returns the messageId.
|
|
86
|
+
* Throws if the session is closed.
|
|
87
|
+
*/
|
|
88
|
+
postMessage(sessionId: string, content: string): Promise<string>;
|
|
89
|
+
dispose(): void;
|
|
90
|
+
private _runTurn;
|
|
91
|
+
_gcSweep(): void;
|
|
92
|
+
private _updateMeta;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=companion-chat-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companion-chat-manager.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/companion/companion-chat-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* companion-chat-manager.ts
|
|
3
|
+
*
|
|
4
|
+
* In-memory manager for companion-app chat-mode sessions.
|
|
5
|
+
*
|
|
6
|
+
* Design:
|
|
7
|
+
* - Each session owns a ConversationManager (isolated message history).
|
|
8
|
+
* - When a user message is posted, the manager appends it to the conversation
|
|
9
|
+
* and runs a lightweight LLM turn using the provider registry.
|
|
10
|
+
* - Streaming chunks are fanned out via ControlPlaneGateway.publishEvent
|
|
11
|
+
* with a per-session clientId filter, so they only reach the subscriber
|
|
12
|
+
* for that specific session — never the global TUI event feed.
|
|
13
|
+
* - A GC sweep closes sessions that have been idle beyond the TTL.
|
|
14
|
+
*
|
|
15
|
+
* TODO (follow-up): persist sessions across daemon restart.
|
|
16
|
+
* TODO (follow-up): rate-limiting per session / per client.
|
|
17
|
+
* TODO (follow-up): tool-call execution requires ToolRegistry injection;
|
|
18
|
+
* currently tools are passed through the Orchestrator which needs the
|
|
19
|
+
* full TUI context. For v1, we provide a no-op tool registry so tool
|
|
20
|
+
* calls degrade gracefully. Proper tool support requires the daemon to
|
|
21
|
+
* inject its ToolRegistry into CompanionChatManager.
|
|
22
|
+
*/
|
|
23
|
+
import { randomUUID } from 'node:crypto';
|
|
24
|
+
import { ConversationManager } from '../core/conversation.js';
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Idle GC constants (customisable for tests)
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
const DEFAULT_IDLE_ACTIVE_MS = 30 * 60 * 1_000; // 30 minutes with messages
|
|
29
|
+
const DEFAULT_IDLE_EMPTY_MS = 5 * 60 * 1_000; // 5 minutes empty session
|
|
30
|
+
const GC_INTERVAL_MS = 60 * 1_000; // sweep every minute
|
|
31
|
+
export class CompanionChatManager {
|
|
32
|
+
sessions = new Map();
|
|
33
|
+
provider;
|
|
34
|
+
eventPublisher;
|
|
35
|
+
idleActiveMs;
|
|
36
|
+
idleEmptyMs;
|
|
37
|
+
gcTimer = null;
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.provider = config.provider;
|
|
40
|
+
this.eventPublisher = config.eventPublisher;
|
|
41
|
+
this.idleActiveMs = config.idleActiveMs ?? DEFAULT_IDLE_ACTIVE_MS;
|
|
42
|
+
this.idleEmptyMs = config.idleEmptyMs ?? DEFAULT_IDLE_EMPTY_MS;
|
|
43
|
+
const gcIntervalMs = config.gcIntervalMs ?? GC_INTERVAL_MS;
|
|
44
|
+
this.gcTimer = setInterval(() => this._gcSweep(), gcIntervalMs);
|
|
45
|
+
// Don't block node process on this timer
|
|
46
|
+
this.gcTimer.unref?.();
|
|
47
|
+
}
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Session lifecycle
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
createSession(input = {}) {
|
|
52
|
+
const id = randomUUID();
|
|
53
|
+
const now = Date.now();
|
|
54
|
+
const meta = {
|
|
55
|
+
id,
|
|
56
|
+
kind: 'companion-chat',
|
|
57
|
+
title: input.title ?? 'Chat',
|
|
58
|
+
model: input.model ?? null,
|
|
59
|
+
provider: input.provider ?? null,
|
|
60
|
+
systemPrompt: input.systemPrompt ?? null,
|
|
61
|
+
status: 'active',
|
|
62
|
+
createdAt: now,
|
|
63
|
+
updatedAt: now,
|
|
64
|
+
closedAt: null,
|
|
65
|
+
messageCount: 0,
|
|
66
|
+
};
|
|
67
|
+
const conversation = new ConversationManager();
|
|
68
|
+
this.sessions.set(id, {
|
|
69
|
+
meta,
|
|
70
|
+
conversation,
|
|
71
|
+
messages: [],
|
|
72
|
+
abortController: new AbortController(),
|
|
73
|
+
lastActivityAt: now,
|
|
74
|
+
subscriberClientId: null,
|
|
75
|
+
});
|
|
76
|
+
return meta;
|
|
77
|
+
}
|
|
78
|
+
getSession(sessionId) {
|
|
79
|
+
return this.sessions.get(sessionId)?.meta ?? null;
|
|
80
|
+
}
|
|
81
|
+
getMessages(sessionId) {
|
|
82
|
+
return this.sessions.get(sessionId)?.messages ?? [];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Register the SSE clientId for this session so events are routed only to
|
|
86
|
+
* the correct subscriber. Replaces any previous registration (single subscriber
|
|
87
|
+
* per session in v1 — the last SSE connection wins).
|
|
88
|
+
*/
|
|
89
|
+
registerSubscriber(sessionId, clientId) {
|
|
90
|
+
const session = this.sessions.get(sessionId);
|
|
91
|
+
if (session) {
|
|
92
|
+
session.subscriberClientId = clientId;
|
|
93
|
+
session.lastActivityAt = Date.now();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Close a session cleanly. Aborts any in-flight turn. Returns the session
|
|
98
|
+
* snapshot, or null if not found.
|
|
99
|
+
*/
|
|
100
|
+
closeSession(sessionId) {
|
|
101
|
+
const session = this.sessions.get(sessionId);
|
|
102
|
+
if (!session)
|
|
103
|
+
return null;
|
|
104
|
+
if (session.meta.status === 'closed')
|
|
105
|
+
return session.meta;
|
|
106
|
+
session.abortController.abort();
|
|
107
|
+
const now = Date.now();
|
|
108
|
+
const updated = this._updateMeta(session, { status: 'closed', closedAt: now, updatedAt: now });
|
|
109
|
+
return updated;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Post a user message and start an async LLM turn. Returns the messageId.
|
|
113
|
+
* Throws if the session is closed.
|
|
114
|
+
*/
|
|
115
|
+
async postMessage(sessionId, content) {
|
|
116
|
+
const session = this.sessions.get(sessionId);
|
|
117
|
+
if (!session) {
|
|
118
|
+
throw Object.assign(new Error(`Session not found: ${sessionId}`), { code: 'SESSION_NOT_FOUND', status: 404 });
|
|
119
|
+
}
|
|
120
|
+
if (session.meta.status === 'closed') {
|
|
121
|
+
throw Object.assign(new Error(`Session is closed: ${sessionId}`), { code: 'SESSION_CLOSED', status: 409 });
|
|
122
|
+
}
|
|
123
|
+
const messageId = randomUUID();
|
|
124
|
+
const now = Date.now();
|
|
125
|
+
const userMsg = {
|
|
126
|
+
id: messageId,
|
|
127
|
+
sessionId,
|
|
128
|
+
role: 'user',
|
|
129
|
+
content,
|
|
130
|
+
createdAt: now,
|
|
131
|
+
};
|
|
132
|
+
session.messages.push(userMsg);
|
|
133
|
+
session.conversation.addUserMessage(content);
|
|
134
|
+
session.lastActivityAt = now;
|
|
135
|
+
this._updateMeta(session, {
|
|
136
|
+
messageCount: session.messages.length,
|
|
137
|
+
updatedAt: now,
|
|
138
|
+
});
|
|
139
|
+
// Fire-and-forget: run the turn without blocking the HTTP response
|
|
140
|
+
void this._runTurn(session, messageId);
|
|
141
|
+
return messageId;
|
|
142
|
+
}
|
|
143
|
+
dispose() {
|
|
144
|
+
if (this.gcTimer) {
|
|
145
|
+
clearInterval(this.gcTimer);
|
|
146
|
+
this.gcTimer = null;
|
|
147
|
+
}
|
|
148
|
+
// Abort all in-flight turns
|
|
149
|
+
for (const session of this.sessions.values()) {
|
|
150
|
+
session.abortController.abort();
|
|
151
|
+
}
|
|
152
|
+
this.sessions.clear();
|
|
153
|
+
}
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Turn execution
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
async _runTurn(session, userMessageId) {
|
|
158
|
+
const turnId = randomUUID();
|
|
159
|
+
const sessionId = session.meta.id;
|
|
160
|
+
const abortSignal = session.abortController.signal;
|
|
161
|
+
const publish = (event) => {
|
|
162
|
+
this.eventPublisher.publishEvent(`companion-chat.${event.type}`, event, session.subscriberClientId ? { clientId: session.subscriberClientId } : undefined);
|
|
163
|
+
};
|
|
164
|
+
// Build user-message envelope for turn.started
|
|
165
|
+
const userMsg = session.messages.find((m) => m.id === userMessageId);
|
|
166
|
+
const startEnvelope = {
|
|
167
|
+
sessionId,
|
|
168
|
+
messageId: userMessageId,
|
|
169
|
+
body: userMsg?.content ?? '',
|
|
170
|
+
source: 'companion-chat-user',
|
|
171
|
+
timestamp: userMsg?.createdAt ?? Date.now(),
|
|
172
|
+
};
|
|
173
|
+
publish({ type: 'turn.started', sessionId, messageId: userMessageId, turnId, envelope: startEnvelope });
|
|
174
|
+
let assistantContent = '';
|
|
175
|
+
const assistantMessageId = randomUUID();
|
|
176
|
+
try {
|
|
177
|
+
const messages = session.conversation.getMessagesForLLM();
|
|
178
|
+
// Convert ProviderMessage[] to our minimal interface
|
|
179
|
+
const chatMessages = messages.map((m) => ({
|
|
180
|
+
role: m.role === 'user' ? 'user' : 'assistant',
|
|
181
|
+
content: typeof m.content === 'string' ? m.content : JSON.stringify(m.content),
|
|
182
|
+
}));
|
|
183
|
+
const stream = this.provider.chatStream(chatMessages, {
|
|
184
|
+
systemPrompt: session.meta.systemPrompt,
|
|
185
|
+
model: session.meta.model,
|
|
186
|
+
provider: session.meta.provider,
|
|
187
|
+
abortSignal,
|
|
188
|
+
});
|
|
189
|
+
for await (const chunk of stream) {
|
|
190
|
+
if (abortSignal.aborted)
|
|
191
|
+
break;
|
|
192
|
+
switch (chunk.type) {
|
|
193
|
+
case 'text_delta': {
|
|
194
|
+
const delta = chunk.delta ?? '';
|
|
195
|
+
assistantContent += delta;
|
|
196
|
+
publish({ type: 'turn.delta', sessionId, turnId, delta });
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
case 'tool_call': {
|
|
200
|
+
publish({
|
|
201
|
+
type: 'turn.tool_call',
|
|
202
|
+
sessionId,
|
|
203
|
+
turnId,
|
|
204
|
+
toolCallId: chunk.toolCallId ?? '',
|
|
205
|
+
toolName: chunk.toolName ?? '',
|
|
206
|
+
toolInput: chunk.toolInput ?? null,
|
|
207
|
+
});
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
case 'tool_result': {
|
|
211
|
+
publish({
|
|
212
|
+
type: 'turn.tool_result',
|
|
213
|
+
sessionId,
|
|
214
|
+
turnId,
|
|
215
|
+
toolCallId: chunk.toolCallId ?? '',
|
|
216
|
+
toolName: chunk.toolName ?? '',
|
|
217
|
+
result: chunk.result ?? null,
|
|
218
|
+
isError: chunk.isError ?? false,
|
|
219
|
+
});
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
case 'error': {
|
|
223
|
+
throw new Error(chunk.error ?? 'Provider streaming error');
|
|
224
|
+
}
|
|
225
|
+
case 'done':
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Append assistant reply to conversation
|
|
230
|
+
if (assistantContent) {
|
|
231
|
+
session.conversation.addAssistantMessage(assistantContent);
|
|
232
|
+
}
|
|
233
|
+
const now = Date.now();
|
|
234
|
+
const assistantMsg = {
|
|
235
|
+
id: assistantMessageId,
|
|
236
|
+
sessionId,
|
|
237
|
+
role: 'assistant',
|
|
238
|
+
content: assistantContent,
|
|
239
|
+
createdAt: now,
|
|
240
|
+
};
|
|
241
|
+
session.messages.push(assistantMsg);
|
|
242
|
+
session.lastActivityAt = now;
|
|
243
|
+
this._updateMeta(session, { messageCount: session.messages.length, updatedAt: now });
|
|
244
|
+
const completedEnvelope = {
|
|
245
|
+
sessionId,
|
|
246
|
+
messageId: assistantMessageId,
|
|
247
|
+
body: assistantContent,
|
|
248
|
+
source: 'companion-chat-assistant',
|
|
249
|
+
timestamp: now,
|
|
250
|
+
};
|
|
251
|
+
publish({ type: 'turn.completed', sessionId, turnId, assistantMessageId, envelope: completedEnvelope });
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
if (!abortSignal.aborted) {
|
|
255
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
256
|
+
publish({ type: 'turn.error', sessionId, turnId, error: errorMessage });
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
// GC sweep
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
_gcSweep() {
|
|
264
|
+
const now = Date.now();
|
|
265
|
+
for (const [id, session] of this.sessions) {
|
|
266
|
+
if (session.meta.status === 'closed') {
|
|
267
|
+
// Remove already-closed sessions after a short grace period (5 min)
|
|
268
|
+
if (now - (session.meta.closedAt ?? now) > 5 * 60_000) {
|
|
269
|
+
this.sessions.delete(id);
|
|
270
|
+
}
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const idleMs = now - session.lastActivityAt;
|
|
274
|
+
const isEmpty = session.messages.length === 0;
|
|
275
|
+
const ttl = isEmpty ? this.idleEmptyMs : this.idleActiveMs;
|
|
276
|
+
if (idleMs >= ttl) {
|
|
277
|
+
// Close via GC
|
|
278
|
+
session.abortController.abort();
|
|
279
|
+
this._updateMeta(session, { status: 'closed', closedAt: now, updatedAt: now });
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// ---------------------------------------------------------------------------
|
|
284
|
+
// Internal helpers
|
|
285
|
+
// ---------------------------------------------------------------------------
|
|
286
|
+
_updateMeta(session, patch) {
|
|
287
|
+
const updated = { ...session.meta, ...patch };
|
|
288
|
+
session.meta = updated;
|
|
289
|
+
return updated;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* companion-chat-route-types.ts
|
|
3
|
+
*
|
|
4
|
+
* Context interface injected into companion chat route handlers.
|
|
5
|
+
*/
|
|
6
|
+
import type { CompanionChatManager } from './companion-chat-manager.js';
|
|
7
|
+
export interface CompanionChatRouteContext {
|
|
8
|
+
/**
|
|
9
|
+
* The chat session manager. Caller injects a real instance;
|
|
10
|
+
* tests inject a mock or real instance with a mock provider.
|
|
11
|
+
*/
|
|
12
|
+
readonly chatManager: CompanionChatManager;
|
|
13
|
+
/** Parse JSON body from request. Returns Response on parse error. */
|
|
14
|
+
readonly parseJsonBody: (req: Request) => Promise<{
|
|
15
|
+
[k: string]: unknown;
|
|
16
|
+
} | Response>;
|
|
17
|
+
/** Parse optional JSON body. Returns null if body is absent. */
|
|
18
|
+
readonly parseOptionalJsonBody: (req: Request) => Promise<{
|
|
19
|
+
[k: string]: unknown;
|
|
20
|
+
} | null | Response>;
|
|
21
|
+
/**
|
|
22
|
+
* Open an SSE event stream scoped to a session.
|
|
23
|
+
* Callers must call chatManager.registerSubscriber(sessionId, clientId)
|
|
24
|
+
* before returning the Response so that event routing is set up.
|
|
25
|
+
*
|
|
26
|
+
* The returned function accepts (event, payload, id?) and is how the
|
|
27
|
+
* gateway fan-out will push events to this specific subscriber.
|
|
28
|
+
*/
|
|
29
|
+
readonly openSessionEventStream: (req: Request, sessionId: string) => Response;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=companion-chat-route-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companion-chat-route-types.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/companion/companion-chat-route-types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAExE,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,oBAAoB,CAAC;IAC3C,qEAAqE;IACrE,QAAQ,CAAC,aAAa,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;QAAE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,QAAQ,CAAC,CAAC;IACvF,gEAAgE;IAChE,QAAQ,CAAC,qBAAqB,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC;QAAE,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,IAAI,GAAG,QAAQ,CAAC,CAAC;IACtG;;;;;;;OAOG;IACH,QAAQ,CAAC,sBAAsB,EAAE,CAC/B,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,MAAM,KACd,QAAQ,CAAC;CACf"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* companion-chat-routes.ts
|
|
3
|
+
*
|
|
4
|
+
* HTTP route handlers for the companion-app chat-mode API.
|
|
5
|
+
*
|
|
6
|
+
* Routes:
|
|
7
|
+
* POST /api/companion/chat/sessions
|
|
8
|
+
* GET /api/companion/chat/sessions/:sessionId
|
|
9
|
+
* DELETE /api/companion/chat/sessions/:sessionId
|
|
10
|
+
* POST /api/companion/chat/sessions/:sessionId/messages
|
|
11
|
+
* GET /api/companion/chat/sessions/:sessionId/events (SSE)
|
|
12
|
+
*
|
|
13
|
+
* All routes require the existing daemon bearer-token auth (enforced by the
|
|
14
|
+
* caller — DaemonHttpRouter.handleRequest already validates auth before
|
|
15
|
+
* dispatching to API routes).
|
|
16
|
+
*/
|
|
17
|
+
import type { CompanionChatRouteContext } from './companion-chat-route-types.js';
|
|
18
|
+
/**
|
|
19
|
+
* Try to handle a companion chat route. Returns null if the path/method
|
|
20
|
+
* does not match, so the caller can fall through to other route groups.
|
|
21
|
+
*/
|
|
22
|
+
export declare function dispatchCompanionChatRoutes(req: Request, context: CompanionChatRouteContext): Promise<Response | null>;
|
|
23
|
+
//# sourceMappingURL=companion-chat-routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"companion-chat-routes.d.ts","sourceRoot":"","sources":["../../../../src/_internal/platform/companion/companion-chat-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAC;AAMjF;;;GAGG;AACH,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,OAAO,EACZ,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAsC1B"}
|