crewly 1.4.31 → 1.4.32

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 (70) hide show
  1. package/dist/backend/backend/src/constants.d.ts +1 -1
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +2 -2
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/controllers/cloud/cloud-google-auth.controller.js +6 -6
  6. package/dist/backend/backend/src/controllers/cloud/cloud-google-auth.controller.js.map +1 -1
  7. package/dist/backend/backend/src/controllers/monitoring/extension-logs.controller.d.ts +23 -0
  8. package/dist/backend/backend/src/controllers/monitoring/extension-logs.controller.d.ts.map +1 -0
  9. package/dist/backend/backend/src/controllers/monitoring/extension-logs.controller.js +48 -0
  10. package/dist/backend/backend/src/controllers/monitoring/extension-logs.controller.js.map +1 -0
  11. package/dist/backend/backend/src/controllers/monitoring/monitoring.routes.d.ts.map +1 -1
  12. package/dist/backend/backend/src/controllers/monitoring/monitoring.routes.js +6 -0
  13. package/dist/backend/backend/src/controllers/monitoring/monitoring.routes.js.map +1 -1
  14. package/dist/backend/backend/src/controllers/monitoring/pty-status.controller.d.ts +45 -0
  15. package/dist/backend/backend/src/controllers/monitoring/pty-status.controller.d.ts.map +1 -0
  16. package/dist/backend/backend/src/controllers/monitoring/pty-status.controller.js +72 -0
  17. package/dist/backend/backend/src/controllers/monitoring/pty-status.controller.js.map +1 -0
  18. package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
  19. package/dist/backend/backend/src/services/agent/agent-registration.service.js +23 -1
  20. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  21. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts +85 -3
  22. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.d.ts.map +1 -1
  23. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js +309 -8
  24. package/dist/backend/backend/src/services/agent/crewly-agent/agent-runner.service.js.map +1 -1
  25. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts +86 -0
  26. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.d.ts.map +1 -0
  27. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js +147 -0
  28. package/dist/backend/backend/src/services/agent/crewly-agent/agent-worker.js.map +1 -0
  29. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts +122 -17
  30. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.d.ts.map +1 -1
  31. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js +580 -46
  32. package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.js.map +1 -1
  33. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-log-buffer.d.ts +41 -3
  34. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-log-buffer.d.ts.map +1 -1
  35. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-log-buffer.js +116 -3
  36. package/dist/backend/backend/src/services/agent/crewly-agent/in-process-log-buffer.js.map +1 -1
  37. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts +17 -0
  38. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.d.ts.map +1 -1
  39. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js +44 -3
  40. package/dist/backend/backend/src/services/agent/crewly-agent/rate-limiter.js.map +1 -1
  41. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.d.ts.map +1 -1
  42. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js +134 -39
  43. package/dist/backend/backend/src/services/agent/crewly-agent/tool-registry.js.map +1 -1
  44. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +26 -2
  45. package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
  46. package/dist/backend/backend/src/services/agent/crewly-agent/types.js +12 -2
  47. package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
  48. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +2 -2
  49. package/dist/backend/backend/src/services/cloud/cloud-client.service.js +2 -2
  50. package/dist/backend/backend/src/services/core/env.config.js +1 -1
  51. package/dist/backend/backend/src/services/session/session-backend.interface.d.ts +9 -0
  52. package/dist/backend/backend/src/services/session/session-backend.interface.d.ts.map +1 -1
  53. package/dist/backend/backend/src/services/session/session-backend.interface.js.map +1 -1
  54. package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
  55. package/dist/backend/backend/src/websocket/terminal.gateway.js +17 -5
  56. package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
  57. package/dist/cli/backend/src/constants.d.ts +1 -1
  58. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  59. package/dist/cli/backend/src/constants.js +2 -2
  60. package/dist/cli/backend/src/constants.js.map +1 -1
  61. package/dist/cli/cli/src/commands/service.d.ts +4 -0
  62. package/dist/cli/cli/src/commands/service.d.ts.map +1 -1
  63. package/dist/cli/cli/src/commands/service.js +248 -2
  64. package/dist/cli/cli/src/commands/service.js.map +1 -1
  65. package/dist/cli/cli/src/index.js +5 -1
  66. package/dist/cli/cli/src/index.js.map +1 -1
  67. package/frontend/dist/assets/{index-c10b16b7.js → index-411a5785.js} +338 -337
  68. package/frontend/dist/assets/{index-2b76b01d.css → index-63a5cc28.css} +1 -1
  69. package/frontend/dist/index.html +2 -2
  70. package/package.json +1 -1
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Agent Worker Process
3
+ *
4
+ * Standalone Node.js child process that wraps AgentRunnerService for
5
+ * isolated agent execution. Communicates with the parent process via
6
+ * IPC messages (Node.js child_process.fork() protocol).
7
+ *
8
+ * This enables hot-reload of agent code without restarting the main
9
+ * backend process, and crash isolation so a worker failure doesn't
10
+ * bring down the server.
11
+ *
12
+ * @module services/agent/crewly-agent/agent-worker
13
+ */
14
+ import type { CrewlyAgentConfig, AgentRunResult } from './types.js';
15
+ /**
16
+ * Messages sent from the parent process to this worker.
17
+ */
18
+ export type ParentMessage = {
19
+ type: 'init';
20
+ config: CrewlyAgentConfig;
21
+ } | {
22
+ type: 'run';
23
+ message: string;
24
+ conversationId?: string;
25
+ metadata?: Record<string, string>;
26
+ } | {
27
+ type: 'abort';
28
+ } | {
29
+ type: 'get-state';
30
+ } | {
31
+ type: 'shutdown';
32
+ };
33
+ /**
34
+ * Messages sent from this worker to the parent process.
35
+ */
36
+ export type WorkerMessage = {
37
+ type: 'ready';
38
+ } | {
39
+ type: 'result';
40
+ data: AgentRunResult;
41
+ } | {
42
+ type: 'error';
43
+ error: string;
44
+ code?: string;
45
+ } | {
46
+ type: 'log';
47
+ level: 'debug' | 'info' | 'warn' | 'error';
48
+ message: string;
49
+ } | {
50
+ type: 'stream';
51
+ event: 'text';
52
+ data: {
53
+ chunk: string;
54
+ };
55
+ } | {
56
+ type: 'stream';
57
+ event: 'toolStart';
58
+ data: {
59
+ toolName: string;
60
+ args: Record<string, unknown>;
61
+ };
62
+ } | {
63
+ type: 'stream';
64
+ event: 'toolFinish';
65
+ data: {
66
+ toolName: string;
67
+ args: Record<string, unknown>;
68
+ result: unknown;
69
+ durationMs: number;
70
+ };
71
+ } | {
72
+ type: 'stream';
73
+ event: 'stepFinish';
74
+ data: {
75
+ stepIndex: number;
76
+ hasToolCalls: boolean;
77
+ };
78
+ } | {
79
+ type: 'state';
80
+ data: {
81
+ historyLength: number;
82
+ isProcessing: boolean;
83
+ isInitialized: boolean;
84
+ };
85
+ };
86
+ //# sourceMappingURL=agent-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/agent-worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EAEf,MAAM,YAAY,CAAC;AAIpB;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC5F;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEzB;;GAEG;AACH,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,cAAc,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5E;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAC1D;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAA;CAAE,GACjG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GACvI;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,GAC3F;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,aAAa,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,OAAO,CAAA;KAAE,CAAA;CAAE,CAAC"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Agent Worker Process
3
+ *
4
+ * Standalone Node.js child process that wraps AgentRunnerService for
5
+ * isolated agent execution. Communicates with the parent process via
6
+ * IPC messages (Node.js child_process.fork() protocol).
7
+ *
8
+ * This enables hot-reload of agent code without restarting the main
9
+ * backend process, and crash isolation so a worker failure doesn't
10
+ * bring down the server.
11
+ *
12
+ * @module services/agent/crewly-agent/agent-worker
13
+ */
14
+ import { AgentRunnerService } from './agent-runner.service.js';
15
+ // ===== Worker State =====
16
+ let runner = null;
17
+ /**
18
+ * Send a typed message to the parent process.
19
+ *
20
+ * @param msg - Worker message to send
21
+ */
22
+ function send(msg) {
23
+ if (process.send) {
24
+ process.send(msg);
25
+ }
26
+ }
27
+ /**
28
+ * Build streaming callbacks that forward events to the parent via IPC.
29
+ *
30
+ * @returns StreamingEventCallbacks that emit IPC messages
31
+ */
32
+ function buildStreamingCallbacks() {
33
+ return {
34
+ onTextChunk: (chunk) => {
35
+ send({ type: 'stream', event: 'text', data: { chunk } });
36
+ },
37
+ onToolCallStart: (toolName, args) => {
38
+ send({ type: 'stream', event: 'toolStart', data: { toolName, args } });
39
+ },
40
+ onToolCallFinish: (toolName, args, result, durationMs) => {
41
+ send({ type: 'stream', event: 'toolFinish', data: { toolName, args, result, durationMs } });
42
+ },
43
+ onStepFinish: (stepIndex, hasToolCalls) => {
44
+ send({ type: 'stream', event: 'stepFinish', data: { stepIndex, hasToolCalls } });
45
+ },
46
+ };
47
+ }
48
+ /** AbortController for the currently executing run */
49
+ let currentAbort = null;
50
+ /**
51
+ * Handle incoming messages from the parent process.
52
+ *
53
+ * @param msg - Parent message received via IPC
54
+ */
55
+ async function handleMessage(msg) {
56
+ switch (msg.type) {
57
+ case 'init': {
58
+ try {
59
+ runner = new AgentRunnerService(msg.config);
60
+ await runner.initialize();
61
+ send({ type: 'ready' });
62
+ send({ type: 'log', level: 'info', message: `Worker initialized (${msg.config.model.provider}/${msg.config.model.modelId})` });
63
+ }
64
+ catch (err) {
65
+ const errMsg = err instanceof Error ? err.message : String(err);
66
+ send({ type: 'error', error: `Init failed: ${errMsg}`, code: 'INIT_FAILED' });
67
+ runner = null;
68
+ }
69
+ break;
70
+ }
71
+ case 'run': {
72
+ if (!runner || !runner.isInitialized()) {
73
+ send({ type: 'error', error: 'Worker not initialized', code: 'NOT_INITIALIZED' });
74
+ return;
75
+ }
76
+ currentAbort = new AbortController();
77
+ const streamingCallbacks = buildStreamingCallbacks();
78
+ try {
79
+ const result = await runner.run(msg.message, msg.conversationId, msg.metadata, {
80
+ abortSignal: currentAbort.signal,
81
+ streaming: streamingCallbacks,
82
+ });
83
+ currentAbort = null;
84
+ send({ type: 'result', data: result });
85
+ }
86
+ catch (err) {
87
+ currentAbort = null;
88
+ const errMsg = err instanceof Error ? err.message : String(err);
89
+ send({ type: 'error', error: errMsg, code: 'RUN_FAILED' });
90
+ }
91
+ break;
92
+ }
93
+ case 'abort': {
94
+ if (currentAbort) {
95
+ currentAbort.abort();
96
+ currentAbort = null;
97
+ send({ type: 'log', level: 'warn', message: 'Run aborted by parent' });
98
+ }
99
+ if (runner) {
100
+ runner.abortCurrentRun();
101
+ }
102
+ break;
103
+ }
104
+ case 'get-state': {
105
+ send({
106
+ type: 'state',
107
+ data: {
108
+ historyLength: runner ? runner.getHistoryLength() : 0,
109
+ isProcessing: runner ? runner.isProcessing() : false,
110
+ isInitialized: runner ? runner.isInitialized() : false,
111
+ },
112
+ });
113
+ break;
114
+ }
115
+ case 'shutdown': {
116
+ send({ type: 'log', level: 'info', message: 'Worker shutting down' });
117
+ if (runner) {
118
+ await runner.shutdown();
119
+ runner = null;
120
+ }
121
+ // Give IPC a moment to flush, then exit
122
+ setTimeout(() => process.exit(0), 100);
123
+ break;
124
+ }
125
+ }
126
+ }
127
+ // ===== Process Setup =====
128
+ // Listen for IPC messages from parent
129
+ process.on('message', (msg) => {
130
+ handleMessage(msg).catch((err) => {
131
+ const errMsg = err instanceof Error ? err.message : String(err);
132
+ send({ type: 'error', error: `Unhandled worker error: ${errMsg}`, code: 'UNHANDLED' });
133
+ });
134
+ });
135
+ // Handle uncaught exceptions — report to parent before crashing
136
+ process.on('uncaughtException', (err) => {
137
+ send({ type: 'error', error: `Worker crash (uncaughtException): ${err.message}`, code: 'CRASH' });
138
+ setTimeout(() => process.exit(1), 100);
139
+ });
140
+ process.on('unhandledRejection', (reason) => {
141
+ const msg = reason instanceof Error ? reason.message : String(reason);
142
+ send({ type: 'error', error: `Worker crash (unhandledRejection): ${msg}`, code: 'CRASH' });
143
+ setTimeout(() => process.exit(1), 100);
144
+ });
145
+ // Signal ready to receive init
146
+ send({ type: 'log', level: 'info', message: 'Agent worker process started, awaiting init' });
147
+ //# sourceMappingURL=agent-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-worker.js","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/agent-worker.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,11 @@
1
1
  /**
2
2
  * Crewly Agent Runtime Service
3
3
  *
4
- * Concrete RuntimeAgentService subclass for the in-process Crewly Agent.
5
- * Unlike PTY-based runtimes (Claude Code, Gemini CLI), this runtime runs
6
- * entirely inside the Node.js process using the Vercel AI SDK.
7
- *
8
- * No tmux session, no shell commands — messages are routed directly to
9
- * the AgentRunnerService.handleMessage() method.
4
+ * Concrete RuntimeAgentService subclass for the Crewly Agent.
5
+ * Supports two execution modes:
6
+ * - **In-process** (default): AgentRunner runs in the main Node.js process
7
+ * - **Worker process**: AgentRunner runs in a child process via fork(),
8
+ * enabling hot-reload and crash isolation
10
9
  *
11
10
  * @module services/agent/crewly-agent/crewly-agent-runtime.service
12
11
  */
@@ -16,19 +15,25 @@ import { type RuntimeType } from '../../../constants.js';
16
15
  import type { CrewlyAgentConfig, AgentRunResult } from './types.js';
17
16
  import { SessionCommandHelper } from '../../session/index.js';
18
17
  /**
19
- * In-process Crewly Agent runtime powered by AI SDK generateText.
18
+ * Crewly Agent runtime with optional worker process isolation.
20
19
  *
21
- * Key differences from PTY-based runtimes:
22
- * - No tmux session needed runs in-process
23
- * - Messages routed via handleMessage() instead of PTY write
24
- * - System prompt loaded from config/roles/orchestrator/prompt.md
25
- * - Ready immediately after initialization (no CLI startup wait)
20
+ * Supports two modes:
21
+ * - **In-process** (default): AgentRunner runs directly in the main process
22
+ * - **Worker process** (`useWorkerProcess: true`): AgentRunner runs in a
23
+ * forked child process, enabling hot-reload and crash isolation
26
24
  *
27
25
  * @example
28
26
  * ```typescript
27
+ * // In-process mode (default)
29
28
  * const runtime = new CrewlyAgentRuntimeService(sessionHelper, projectRoot);
30
29
  * await runtime.initializeInProcess('crewly-orc');
31
- * const result = await runtime.handleMessage('Check all team statuses');
30
+ *
31
+ * // Worker process mode
32
+ * const runtime = new CrewlyAgentRuntimeService(sessionHelper, projectRoot);
33
+ * await runtime.initializeInProcess('crewly-orc', { useWorkerProcess: true });
34
+ *
35
+ * // Hot-reload: restart worker with fresh code, preserving session
36
+ * await runtime.hotReload();
32
37
  * ```
33
38
  */
34
39
  export declare class CrewlyAgentRuntimeService extends RuntimeAgentService {
@@ -40,6 +45,20 @@ export declare class CrewlyAgentRuntimeService extends RuntimeAgentService {
40
45
  private logBuffer;
41
46
  private rateLimiter;
42
47
  private heartbeatTimer;
48
+ /** AbortController for the currently executing message — enables external abort */
49
+ private messageAbortController;
50
+ /** Whether this instance uses a worker process instead of in-process execution */
51
+ private useWorkerProcess;
52
+ /** The forked worker child process */
53
+ private workerProcess;
54
+ /** Stored config for hot-reload — needed to re-init the worker */
55
+ private storedConfig;
56
+ /** Pending promise resolver for the current worker run */
57
+ private workerRunResolve;
58
+ /** Pending promise rejector for the current worker run */
59
+ private workerRunReject;
60
+ /** Whether the worker is currently processing a message */
61
+ private workerProcessing;
43
62
  constructor(sessionHelper: SessionCommandHelper, projectRoot: string);
44
63
  /**
45
64
  * Get the runtime type identifier.
@@ -75,16 +94,18 @@ export declare class CrewlyAgentRuntimeService extends RuntimeAgentService {
75
94
  */
76
95
  protected getRuntimeExitPatterns(): RegExp[];
77
96
  /**
78
- * Initialize the in-process agent runtime.
97
+ * Initialize the agent runtime.
79
98
  *
80
99
  * Loads the system prompt from config/roles/orchestrator/prompt.md,
81
- * creates the AgentRunnerService, and initializes the model.
100
+ * creates the AgentRunnerService (in-process or worker), and initializes the model.
82
101
  *
83
102
  * @param sessionName - Session name for this agent instance
84
- * @param config - Optional partial config overrides
103
+ * @param config - Optional partial config overrides. Set `useWorkerProcess: true` to run in a child process.
85
104
  * @param roleName - Role name for system prompt lookup (default: 'orchestrator')
86
105
  */
87
- initializeInProcess(sessionName: string, config?: Partial<CrewlyAgentConfig>, roleName?: string): Promise<void>;
106
+ initializeInProcess(sessionName: string, config?: Partial<CrewlyAgentConfig> & {
107
+ useWorkerProcess?: boolean;
108
+ }, roleName?: string): Promise<void>;
88
109
  /**
89
110
  * Handle an incoming message by routing it to the AgentRunner.
90
111
  *
@@ -123,6 +144,16 @@ export declare class CrewlyAgentRuntimeService extends RuntimeAgentService {
123
144
  * @returns True if initializeInProcess() has been called successfully
124
145
  */
125
146
  isReady(): boolean;
147
+ /**
148
+ * Abort the currently executing message processing.
149
+ *
150
+ * Cancels the active model call, terminates running tool processes,
151
+ * and returns partial results where possible. Safe to call at any time —
152
+ * returns false if no run is in progress.
153
+ *
154
+ * @returns True if an active run was aborted, false if nothing was running
155
+ */
156
+ abortCurrentRun(): boolean;
126
157
  /**
127
158
  * Get the current agent runner instance (for inspection/testing).
128
159
  *
@@ -140,6 +171,80 @@ export declare class CrewlyAgentRuntimeService extends RuntimeAgentService {
140
171
  * Clears the agent runner and resets state.
141
172
  */
142
173
  shutdown(): void;
174
+ /**
175
+ * Hot-reload the worker process.
176
+ *
177
+ * Kills the existing worker and spawns a fresh one with the stored config.
178
+ * This allows updating agent code without restarting the main backend.
179
+ * Conversation state is reset — use this when deploying new agent logic.
180
+ *
181
+ * @throws Error if not in worker mode or config is missing
182
+ */
183
+ hotReload(): Promise<void>;
184
+ /**
185
+ * Check if the runtime is using a worker process.
186
+ *
187
+ * @returns True if running in worker process mode
188
+ */
189
+ isWorkerMode(): boolean;
190
+ /**
191
+ * Get the worker process PID (for monitoring/debugging).
192
+ *
193
+ * @returns Worker PID, or null if not in worker mode or worker is not running
194
+ */
195
+ getWorkerPid(): number | null;
196
+ /**
197
+ * Initialize a worker child process via fork().
198
+ *
199
+ * Forks the agent-worker.ts entry point and sends the init message
200
+ * with the agent config. Waits for the 'ready' response before resolving.
201
+ *
202
+ * @param config - Full agent config to send to the worker
203
+ * @throws Error if worker fails to initialize within timeout
204
+ */
205
+ private initializeWorker;
206
+ /**
207
+ * Execute a message via the worker process using IPC.
208
+ *
209
+ * Sends a 'run' message to the worker and waits for the 'result' or 'error'
210
+ * response. Streaming events are forwarded to the InProcessLogBuffer in real-time.
211
+ *
212
+ * @param session - Session name
213
+ * @param cleanMessage - Message content (prefix already stripped)
214
+ * @param conversationId - Optional conversation ID
215
+ * @param _metadata - Optional metadata (passed to worker)
216
+ * @returns Agent run result from the worker
217
+ */
218
+ private executeMessageViaWorker;
219
+ /**
220
+ * Handle messages received from the worker process.
221
+ *
222
+ * Routes streaming events to the InProcessLogBuffer and resolves/rejects
223
+ * pending run promises on result/error messages.
224
+ *
225
+ * @param msg - Worker message received via IPC
226
+ */
227
+ private handleWorkerMessage;
228
+ /**
229
+ * Send a typed message to the worker process.
230
+ *
231
+ * @param msg - Parent message to send
232
+ */
233
+ private sendToWorker;
234
+ /**
235
+ * Terminate the worker process gracefully, with a forced kill fallback.
236
+ */
237
+ private terminateWorker;
238
+ /**
239
+ * Get the path to the compiled worker entry file.
240
+ *
241
+ * @returns Absolute path to the agent-worker.js compiled file
242
+ */
243
+ /**
244
+ * @internal Visible for testing — override to provide a custom worker path.
245
+ */
246
+ _workerEntryPath: string | null;
247
+ private getWorkerEntryPath;
143
248
  /**
144
249
  * Start periodic heartbeat to keep the in-process agent marked as active.
145
250
  *
@@ -1 +1 @@
1
- {"version":3,"file":"crewly-agent-runtime.service.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAoD,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE3G,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAS9D;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,yBAA0B,SAAQ,mBAAmB;IAChE,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,cAAc,CAA+C;gBAEzD,aAAa,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM;IAQpE;;;;OAIG;IACH,SAAS,CAAC,cAAc,IAAI,WAAW;IAIvC;;;;;;OAMG;cACa,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI7E;;;;;OAKG;IACH,SAAS,CAAC,uBAAuB,IAAI,MAAM,EAAE;IAI7C;;;;OAIG;IACH,SAAS,CAAC,uBAAuB,IAAI,MAAM,EAAE;IAI7C;;;;OAIG;IACH,SAAS,CAAC,sBAAsB,IAAI,MAAM,EAAE;IAM5C;;;;;;;;;OASG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,EACnC,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IA6ChB;;;;;;;;;;OAUG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IA4ChG;;;;;;;;;;;OAWG;YACW,cAAc;IAuD5B;;;;;OAKG;YACW,yBAAyB;IAavC;;;;OAIG;IACH,OAAO,IAAI,OAAO;IAIlB;;;;OAIG;IACH,cAAc,IAAI,kBAAkB,GAAG,IAAI;IAI3C;;;;OAIG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B;;;OAGG;IACH,QAAQ,IAAI,IAAI;IAsBhB;;;;;;;;;OASG;IACH,OAAO,CAAC,cAAc;IAoCtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;OAKG;YACW,gBAAgB;IAkB9B;;;;;;;;;;;;;OAaG;IACG,yBAAyB,CAAC,QAAQ,GAAE,MAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;IA2BnF;;;;;;;OAOG;YACW,wBAAwB;IAsBtC;;;;;;;;OAQG;YACW,mBAAmB;CAqClC"}
1
+ {"version":3,"file":"crewly-agent-runtime.service.d.ts","sourceRoot":"","sources":["../../../../../../../backend/src/services/agent/crewly-agent/crewly-agent-runtime.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAoD,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE3G,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAA2B,MAAM,YAAY,CAAC;AAG7F,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAS9D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,yBAA0B,SAAQ,mBAAmB;IAChE,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,kBAAkB,CAAuB;IACjD,OAAO,CAAC,eAAe,CAAqB;IAC5C,OAAO,CAAC,kBAAkB,CAAqB;IAC/C,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,WAAW,CAA8B;IACjD,OAAO,CAAC,cAAc,CAA+C;IACrE,mFAAmF;IACnF,OAAO,CAAC,sBAAsB,CAAgC;IAI9D,kFAAkF;IAClF,OAAO,CAAC,gBAAgB,CAAS;IACjC,sCAAsC;IACtC,OAAO,CAAC,aAAa,CAA6B;IAClD,kEAAkE;IAClE,OAAO,CAAC,YAAY,CAAkC;IACtD,0DAA0D;IAC1D,OAAO,CAAC,gBAAgB,CAAmD;IAC3E,0DAA0D;IAC1D,OAAO,CAAC,eAAe,CAAyC;IAChE,2DAA2D;IAC3D,OAAO,CAAC,gBAAgB,CAAS;gBAErB,aAAa,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM;IAQpE;;;;OAIG;IACH,SAAS,CAAC,cAAc,IAAI,WAAW;IAIvC;;;;;;OAMG;cACa,qBAAqB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAO7E;;;;;OAKG;IACH,SAAS,CAAC,uBAAuB,IAAI,MAAM,EAAE;IAI7C;;;;OAIG;IACH,SAAS,CAAC,uBAAuB,IAAI,MAAM,EAAE;IAI7C;;;;OAIG;IACH,SAAS,CAAC,sBAAsB,IAAI,MAAM,EAAE;IAM5C;;;;;;;;;OASG;IACG,mBAAmB,CACvB,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC,GAAG;QAAE,gBAAgB,CAAC,EAAE,OAAO,CAAA;KAAE,EACpE,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAwDhB;;;;;;;;;;OAUG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,cAAc,CAAC;IA0DhG;;;;;;;;;;;OAWG;YACW,cAAc;IAkM5B;;;;;OAKG;YACW,yBAAyB;IAavC;;;;OAIG;IACH,OAAO,IAAI,OAAO;IAOlB;;;;;;;;OAQG;IACH,eAAe,IAAI,OAAO;IAyC1B;;;;OAIG;IACH,cAAc,IAAI,kBAAkB,GAAG,IAAI;IAI3C;;;;OAIG;IACH,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B;;;OAGG;IACH,QAAQ,IAAI,IAAI;IA6BhB;;;;;;;;OAQG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAsBhC;;;;OAIG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,YAAY,IAAI,MAAM,GAAG,IAAI;IAI7B;;;;;;;;OAQG;YACW,gBAAgB;IAgG9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,uBAAuB;IAsD/B;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IA6D3B;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAMpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAmCvB;;;;OAIG;IACH;;OAEG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAEvC,OAAO,CAAC,kBAAkB;IAY1B;;;;;;;;;OASG;IACH,OAAO,CAAC,cAAc;IAoCtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAOrB;;;;;OAKG;YACW,gBAAgB;IAkB9B;;;;;;;;;;;;;OAaG;IACG,yBAAyB,CAAC,QAAQ,GAAE,MAAuB,GAAG,OAAO,CAAC,MAAM,CAAC;IA2BnF;;;;;;;OAOG;YACW,wBAAwB;IAsBtC;;;;;;;;OAQG;YACW,mBAAmB;CAqClC"}