@vibescope/mcp-server 0.3.0 → 0.3.3

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 (154) hide show
  1. package/dist/api-client/blockers.d.ts +46 -0
  2. package/dist/api-client/blockers.js +43 -0
  3. package/dist/api-client/cost.d.ts +112 -0
  4. package/dist/api-client/cost.js +76 -0
  5. package/dist/api-client/decisions.d.ts +55 -0
  6. package/dist/api-client/decisions.js +32 -0
  7. package/dist/api-client/discovery.d.ts +62 -0
  8. package/dist/api-client/discovery.js +21 -0
  9. package/dist/api-client/ideas.d.ts +75 -0
  10. package/dist/api-client/ideas.js +36 -0
  11. package/dist/api-client/index.d.ts +749 -0
  12. package/dist/api-client/index.js +291 -0
  13. package/dist/api-client/project.d.ts +132 -0
  14. package/dist/api-client/project.js +45 -0
  15. package/dist/api-client/session.d.ts +163 -0
  16. package/dist/api-client/session.js +52 -0
  17. package/dist/api-client/tasks.d.ts +328 -0
  18. package/dist/api-client/tasks.js +132 -0
  19. package/dist/api-client/types.d.ts +25 -0
  20. package/dist/api-client/types.js +4 -0
  21. package/dist/api-client/worktrees.d.ts +33 -0
  22. package/dist/api-client/worktrees.js +26 -0
  23. package/dist/api-client.d.ts +9 -0
  24. package/dist/api-client.js +104 -25
  25. package/dist/cli-init.d.ts +17 -0
  26. package/dist/cli-init.js +445 -0
  27. package/dist/cli.js +0 -0
  28. package/dist/handlers/cloud-agents.d.ts +21 -0
  29. package/dist/handlers/cloud-agents.js +91 -0
  30. package/dist/handlers/discovery.js +7 -0
  31. package/dist/handlers/index.d.ts +1 -0
  32. package/dist/handlers/index.js +3 -0
  33. package/dist/handlers/session.js +3 -1
  34. package/dist/handlers/tasks.js +10 -12
  35. package/dist/handlers/types.d.ts +2 -1
  36. package/dist/handlers/validation.js +5 -1
  37. package/dist/index.js +8 -3
  38. package/dist/token-tracking.js +2 -2
  39. package/dist/tools/blockers.d.ts +13 -0
  40. package/dist/tools/blockers.js +119 -0
  41. package/dist/tools/bodies-of-work.d.ts +19 -0
  42. package/dist/tools/bodies-of-work.js +280 -0
  43. package/dist/tools/cloud-agents.d.ts +9 -0
  44. package/dist/tools/cloud-agents.js +67 -0
  45. package/dist/tools/connectors.d.ts +14 -0
  46. package/dist/tools/connectors.js +188 -0
  47. package/dist/tools/cost.d.ts +11 -0
  48. package/dist/tools/cost.js +108 -0
  49. package/dist/tools/decisions.d.ts +12 -0
  50. package/dist/tools/decisions.js +108 -0
  51. package/dist/tools/deployment.d.ts +24 -0
  52. package/dist/tools/deployment.js +439 -0
  53. package/dist/tools/discovery.d.ts +10 -0
  54. package/dist/tools/discovery.js +73 -0
  55. package/dist/tools/fallback.d.ts +11 -0
  56. package/dist/tools/fallback.js +108 -0
  57. package/dist/tools/file-checkouts.d.ts +13 -0
  58. package/dist/tools/file-checkouts.js +141 -0
  59. package/dist/tools/findings.d.ts +13 -0
  60. package/dist/tools/findings.js +98 -0
  61. package/dist/tools/git-issues.d.ts +11 -0
  62. package/dist/tools/git-issues.js +127 -0
  63. package/dist/tools/ideas.d.ts +13 -0
  64. package/dist/tools/ideas.js +159 -0
  65. package/dist/tools/index.d.ts +71 -0
  66. package/dist/tools/index.js +98 -0
  67. package/dist/tools/milestones.d.ts +12 -0
  68. package/dist/tools/milestones.js +115 -0
  69. package/dist/tools/organizations.d.ts +17 -0
  70. package/dist/tools/organizations.js +221 -0
  71. package/dist/tools/progress.d.ts +9 -0
  72. package/dist/tools/progress.js +70 -0
  73. package/dist/tools/project.d.ts +13 -0
  74. package/dist/tools/project.js +199 -0
  75. package/dist/tools/requests.d.ts +10 -0
  76. package/dist/tools/requests.js +65 -0
  77. package/dist/tools/roles.d.ts +11 -0
  78. package/dist/tools/roles.js +109 -0
  79. package/dist/tools/session.d.ts +15 -0
  80. package/dist/tools/session.js +178 -0
  81. package/dist/tools/sprints.d.ts +18 -0
  82. package/dist/tools/sprints.js +295 -0
  83. package/dist/tools/tasks.d.ts +27 -0
  84. package/dist/tools/tasks.js +539 -0
  85. package/dist/tools/types.d.ts +7 -0
  86. package/dist/tools/types.js +6 -0
  87. package/dist/tools/validation.d.ts +10 -0
  88. package/dist/tools/validation.js +72 -0
  89. package/dist/tools/worktrees.d.ts +9 -0
  90. package/dist/tools/worktrees.js +63 -0
  91. package/dist/utils.d.ts +66 -0
  92. package/dist/utils.js +102 -0
  93. package/docs/TOOLS.md +55 -2
  94. package/package.json +5 -3
  95. package/scripts/generate-docs.ts +1 -1
  96. package/src/api-client/blockers.ts +86 -0
  97. package/src/api-client/cost.ts +185 -0
  98. package/src/api-client/decisions.ts +87 -0
  99. package/src/api-client/discovery.ts +81 -0
  100. package/src/api-client/ideas.ts +112 -0
  101. package/src/api-client/index.ts +378 -0
  102. package/src/api-client/project.ts +179 -0
  103. package/src/api-client/session.ts +220 -0
  104. package/src/api-client/tasks.ts +450 -0
  105. package/src/api-client/types.ts +32 -0
  106. package/src/api-client/worktrees.ts +53 -0
  107. package/src/api-client.test.ts +136 -9
  108. package/src/api-client.ts +125 -27
  109. package/src/cli-init.ts +504 -0
  110. package/src/handlers/__test-utils__.ts +2 -0
  111. package/src/handlers/cloud-agents.ts +138 -0
  112. package/src/handlers/discovery.ts +7 -0
  113. package/src/handlers/index.ts +3 -0
  114. package/src/handlers/session.ts +3 -1
  115. package/src/handlers/tasks.ts +10 -12
  116. package/src/handlers/tool-categories.test.ts +1 -1
  117. package/src/handlers/types.ts +2 -1
  118. package/src/handlers/validation.ts +6 -1
  119. package/src/index.test.ts +2 -2
  120. package/src/index.ts +8 -2
  121. package/src/token-tracking.ts +3 -2
  122. package/src/tools/blockers.ts +122 -0
  123. package/src/tools/bodies-of-work.ts +283 -0
  124. package/src/tools/cloud-agents.ts +70 -0
  125. package/src/tools/connectors.ts +191 -0
  126. package/src/tools/cost.ts +111 -0
  127. package/src/tools/decisions.ts +111 -0
  128. package/src/tools/deployment.ts +442 -0
  129. package/src/tools/discovery.ts +76 -0
  130. package/src/tools/fallback.ts +111 -0
  131. package/src/tools/file-checkouts.ts +145 -0
  132. package/src/tools/findings.ts +101 -0
  133. package/src/tools/git-issues.ts +130 -0
  134. package/src/tools/ideas.ts +162 -0
  135. package/src/tools/index.ts +131 -0
  136. package/src/tools/milestones.ts +118 -0
  137. package/src/tools/organizations.ts +224 -0
  138. package/src/tools/progress.ts +73 -0
  139. package/src/tools/project.ts +202 -0
  140. package/src/tools/requests.ts +68 -0
  141. package/src/tools/roles.ts +112 -0
  142. package/src/tools/session.ts +181 -0
  143. package/src/tools/sprints.ts +298 -0
  144. package/src/tools/tasks.ts +542 -0
  145. package/src/tools/tools.test.ts +222 -0
  146. package/src/tools/types.ts +9 -0
  147. package/src/tools/validation.ts +75 -0
  148. package/src/tools/worktrees.ts +66 -0
  149. package/src/tools.test.ts +1 -1
  150. package/src/utils.test.ts +229 -0
  151. package/src/utils.ts +117 -0
  152. package/dist/tools.d.ts +0 -2
  153. package/dist/tools.js +0 -3602
  154. package/src/tools.ts +0 -3607
@@ -23,11 +23,14 @@ const mockFetch = vi.fn();
23
23
  global.fetch = mockFetch;
24
24
 
25
25
  // Helper to create mock response
26
- function createMockResponse(data: unknown, ok = true, status = 200) {
26
+ function createMockResponse(data: unknown, ok = true, status = 200, headers?: Record<string, string>) {
27
27
  return {
28
28
  ok,
29
29
  status,
30
30
  json: vi.fn().mockResolvedValue(data),
31
+ headers: {
32
+ get: (name: string) => headers?.[name] ?? null,
33
+ },
31
34
  };
32
35
  }
33
36
 
@@ -36,12 +39,21 @@ function createNetworkError(message: string) {
36
39
  return new Error(message);
37
40
  }
38
41
 
42
+ // Fast retry config for tests (1ms delays instead of 1000ms)
43
+ const FAST_RETRY_CONFIG = {
44
+ maxRetries: 3,
45
+ baseDelayMs: 1,
46
+ maxDelayMs: 10,
47
+ retryStatusCodes: [429, 503, 504],
48
+ };
49
+
39
50
  describe('VibescopeApiClient', () => {
40
51
  let client: VibescopeApiClient;
41
52
 
42
53
  beforeEach(() => {
43
54
  vi.clearAllMocks();
44
- client = new VibescopeApiClient({ apiKey: 'test-api-key' });
55
+ // Use fast retry config so tests don't take forever
56
+ client = new VibescopeApiClient({ apiKey: 'test-api-key', retry: FAST_RETRY_CONFIG });
45
57
  });
46
58
 
47
59
  afterEach(() => {
@@ -181,29 +193,33 @@ describe('VibescopeApiClient', () => {
181
193
  });
182
194
  });
183
195
 
184
- it('should handle network errors', async () => {
196
+ it('should handle network errors after retries', async () => {
185
197
  mockFetch.mockRejectedValue(createNetworkError('Network request failed'));
186
198
 
187
199
  const result = await client.validateAuth();
188
200
 
201
+ // Network errors are retried, so 4 attempts total (1 initial + 3 retries)
202
+ expect(mockFetch).toHaveBeenCalledTimes(4);
189
203
  expect(result).toEqual({
190
204
  ok: false,
191
205
  status: 0,
192
206
  error: 'Network request failed',
193
207
  });
194
- });
208
+ }, 30000);
195
209
 
196
- it('should handle non-Error exceptions', async () => {
210
+ it('should handle non-Error exceptions after retries', async () => {
197
211
  mockFetch.mockRejectedValue('String error');
198
212
 
199
213
  const result = await client.validateAuth();
200
214
 
215
+ // Non-Error exceptions are converted to Error('Network error') and retried
216
+ expect(mockFetch).toHaveBeenCalledTimes(4);
201
217
  expect(result).toEqual({
202
218
  ok: false,
203
219
  status: 0,
204
220
  error: 'Network error',
205
221
  });
206
- });
222
+ }, 30000);
207
223
  });
208
224
 
209
225
  // ============================================================================
@@ -693,31 +709,142 @@ describe('VibescopeApiClient', () => {
693
709
  // ============================================================================
694
710
 
695
711
  describe('error handling edge cases', () => {
696
- it('should handle JSON parse error in response', async () => {
712
+ it('should handle JSON parse error in response after retries', async () => {
697
713
  mockFetch.mockResolvedValue({
698
714
  ok: true,
699
715
  status: 200,
700
716
  json: vi.fn().mockRejectedValue(new SyntaxError('Invalid JSON')),
717
+ headers: { get: () => null },
701
718
  });
702
719
 
703
720
  const result = await client.validateAuth();
704
721
 
722
+ // JSON parse errors are treated as network errors and retried
723
+ expect(mockFetch).toHaveBeenCalledTimes(4);
705
724
  expect(result.ok).toBe(false);
706
725
  expect(result.error).toContain('Invalid JSON');
707
- });
726
+ }, 30000);
708
727
 
709
- it('should handle timeout errors', async () => {
728
+ it('should handle timeout errors after retries', async () => {
710
729
  const timeoutError = new Error('Request timeout');
711
730
  timeoutError.name = 'AbortError';
712
731
  mockFetch.mockRejectedValue(timeoutError);
713
732
 
714
733
  const result = await client.validateAuth();
715
734
 
735
+ // Timeout errors are retried
736
+ expect(mockFetch).toHaveBeenCalledTimes(4);
716
737
  expect(result).toEqual({
717
738
  ok: false,
718
739
  status: 0,
719
740
  error: 'Request timeout',
720
741
  });
742
+ }, 30000);
743
+ });
744
+
745
+ // ============================================================================
746
+ // Retry Logic Tests
747
+ // ============================================================================
748
+
749
+ describe('retry logic', () => {
750
+ it('should retry on 429 status code', async () => {
751
+ // First two calls return 429, third succeeds
752
+ mockFetch
753
+ .mockResolvedValueOnce(createMockResponse({ error: 'Rate limited' }, false, 429))
754
+ .mockResolvedValueOnce(createMockResponse({ error: 'Rate limited' }, false, 429))
755
+ .mockResolvedValueOnce(createMockResponse({ valid: true }, true, 200));
756
+
757
+ const result = await client.validateAuth();
758
+
759
+ expect(mockFetch).toHaveBeenCalledTimes(3);
760
+ expect(result.ok).toBe(true);
761
+ });
762
+
763
+ it('should retry on 503 status code', async () => {
764
+ mockFetch
765
+ .mockResolvedValueOnce(createMockResponse({ error: 'Service unavailable' }, false, 503))
766
+ .mockResolvedValueOnce(createMockResponse({ valid: true }, true, 200));
767
+
768
+ const result = await client.validateAuth();
769
+
770
+ expect(mockFetch).toHaveBeenCalledTimes(2);
771
+ expect(result.ok).toBe(true);
772
+ });
773
+
774
+ it('should retry on 504 status code', async () => {
775
+ mockFetch
776
+ .mockResolvedValueOnce(createMockResponse({ error: 'Gateway timeout' }, false, 504))
777
+ .mockResolvedValueOnce(createMockResponse({ valid: true }, true, 200));
778
+
779
+ const result = await client.validateAuth();
780
+
781
+ expect(mockFetch).toHaveBeenCalledTimes(2);
782
+ expect(result.ok).toBe(true);
783
+ });
784
+
785
+ it('should not retry on non-retryable status codes (400)', async () => {
786
+ mockFetch.mockResolvedValueOnce(createMockResponse({ error: 'Bad request' }, false, 400));
787
+
788
+ const result = await client.validateAuth();
789
+
790
+ expect(mockFetch).toHaveBeenCalledTimes(1);
791
+ expect(result.ok).toBe(false);
792
+ expect(result.status).toBe(400);
793
+ });
794
+
795
+ it('should not retry on non-retryable status codes (401)', async () => {
796
+ mockFetch.mockResolvedValueOnce(createMockResponse({ error: 'Unauthorized' }, false, 401));
797
+
798
+ const result = await client.validateAuth();
799
+
800
+ expect(mockFetch).toHaveBeenCalledTimes(1);
801
+ expect(result.ok).toBe(false);
802
+ expect(result.status).toBe(401);
721
803
  });
804
+
805
+ it('should not retry on non-retryable status codes (500)', async () => {
806
+ mockFetch.mockResolvedValueOnce(createMockResponse({ error: 'Server error' }, false, 500));
807
+
808
+ const result = await client.validateAuth();
809
+
810
+ expect(mockFetch).toHaveBeenCalledTimes(1);
811
+ expect(result.ok).toBe(false);
812
+ expect(result.status).toBe(500);
813
+ });
814
+
815
+ it('should stop after max retries (3)', async () => {
816
+ // All 4 attempts (1 initial + 3 retries) return 429
817
+ mockFetch.mockResolvedValue(createMockResponse({ error: 'Rate limited' }, false, 429));
818
+
819
+ const result = await client.validateAuth();
820
+
821
+ expect(mockFetch).toHaveBeenCalledTimes(4); // 1 initial + 3 retries
822
+ expect(result.ok).toBe(false);
823
+ expect(result.status).toBe(429);
824
+ // API error message takes precedence over generic retry message
825
+ expect(result.error).toBe('Rate limited');
826
+ }, 30000);
827
+
828
+ it('should retry on network errors', async () => {
829
+ mockFetch
830
+ .mockRejectedValueOnce(new Error('Network error'))
831
+ .mockResolvedValueOnce(createMockResponse({ valid: true }, true, 200));
832
+
833
+ const result = await client.validateAuth();
834
+
835
+ expect(mockFetch).toHaveBeenCalledTimes(2);
836
+ expect(result.ok).toBe(true);
837
+ }, 10000);
838
+
839
+ it('should return last error after all retries exhausted on network failure', async () => {
840
+ mockFetch.mockRejectedValue(new Error('Connection refused'));
841
+
842
+ const result = await client.validateAuth();
843
+
844
+ expect(mockFetch).toHaveBeenCalledTimes(4);
845
+ expect(result.ok).toBe(false);
846
+ expect(result.status).toBe(0);
847
+ expect(result.error).toBe('Connection refused');
848
+ }, 30000);
722
849
  });
723
850
  });
package/src/api-client.ts CHANGED
@@ -7,9 +7,23 @@
7
7
 
8
8
  const DEFAULT_API_URL = 'https://vibescope.dev';
9
9
 
10
+ // Retry configuration defaults
11
+ const DEFAULT_RETRY_STATUS_CODES = [429, 503, 504];
12
+ const DEFAULT_MAX_RETRIES = 3;
13
+ const DEFAULT_BASE_DELAY_MS = 1000;
14
+ const DEFAULT_MAX_DELAY_MS = 30000;
15
+
16
+ interface RetryConfig {
17
+ maxRetries?: number;
18
+ baseDelayMs?: number;
19
+ maxDelayMs?: number;
20
+ retryStatusCodes?: number[];
21
+ }
22
+
10
23
  interface ApiClientConfig {
11
24
  apiKey: string;
12
25
  baseUrl?: string;
26
+ retry?: RetryConfig;
13
27
  }
14
28
 
15
29
  interface ApiResponse<T> {
@@ -19,51 +33,134 @@ interface ApiResponse<T> {
19
33
  error?: string;
20
34
  }
21
35
 
36
+ /**
37
+ * Calculate delay for exponential backoff with jitter
38
+ */
39
+ function calculateBackoffDelay(
40
+ attempt: number,
41
+ baseDelayMs: number,
42
+ maxDelayMs: number,
43
+ retryAfter?: number
44
+ ): number {
45
+ // If Retry-After header is present, use it (in seconds)
46
+ if (retryAfter !== undefined && retryAfter > 0) {
47
+ return Math.min(retryAfter * 1000, maxDelayMs);
48
+ }
49
+ // Exponential backoff: base * 2^attempt with jitter
50
+ const exponentialDelay = baseDelayMs * Math.pow(2, attempt);
51
+ const jitter = Math.random() * 0.3 * exponentialDelay; // 0-30% jitter
52
+ return Math.min(exponentialDelay + jitter, maxDelayMs);
53
+ }
54
+
55
+ /**
56
+ * Sleep for a specified duration
57
+ */
58
+ function sleep(ms: number): Promise<void> {
59
+ return new Promise(resolve => setTimeout(resolve, ms));
60
+ }
61
+
22
62
  export class VibescopeApiClient {
23
63
  private apiKey: string;
24
64
  private baseUrl: string;
65
+ private retryConfig: Required<RetryConfig>;
25
66
 
26
67
  constructor(config: ApiClientConfig) {
27
68
  this.apiKey = config.apiKey;
28
69
  this.baseUrl = config.baseUrl || process.env.VIBESCOPE_API_URL || DEFAULT_API_URL;
70
+ this.retryConfig = {
71
+ maxRetries: config.retry?.maxRetries ?? DEFAULT_MAX_RETRIES,
72
+ baseDelayMs: config.retry?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS,
73
+ maxDelayMs: config.retry?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS,
74
+ retryStatusCodes: config.retry?.retryStatusCodes ?? DEFAULT_RETRY_STATUS_CODES,
75
+ };
29
76
  }
30
77
 
31
78
  private async request<T>(method: string, path: string, body?: unknown): Promise<ApiResponse<T>> {
32
79
  const url = `${this.baseUrl}${path}`;
80
+ const { maxRetries, baseDelayMs, maxDelayMs, retryStatusCodes } = this.retryConfig;
81
+ let lastError: Error | null = null;
82
+ let lastResponse: Response | null = null;
83
+
84
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
85
+ try {
86
+ const response = await fetch(url, {
87
+ method,
88
+ headers: {
89
+ 'Content-Type': 'application/json',
90
+ 'X-API-Key': this.apiKey
91
+ },
92
+ body: body ? JSON.stringify(body) : undefined
93
+ });
94
+
95
+ // Check if we should retry this status code
96
+ if (retryStatusCodes.includes(response.status) && attempt < maxRetries) {
97
+ lastResponse = response;
98
+ // Parse Retry-After header if present (can be seconds or HTTP-date)
99
+ const retryAfterHeader = response.headers.get('Retry-After');
100
+ let retryAfter: number | undefined;
101
+ if (retryAfterHeader) {
102
+ const seconds = parseInt(retryAfterHeader, 10);
103
+ if (!isNaN(seconds)) {
104
+ retryAfter = seconds;
105
+ }
106
+ }
107
+ const delay = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs, retryAfter);
108
+ await sleep(delay);
109
+ continue;
110
+ }
111
+
112
+ const data = await response.json();
113
+
114
+ if (!response.ok) {
115
+ return {
116
+ ok: false,
117
+ status: response.status,
118
+ error: data.error || `HTTP ${response.status}`,
119
+ data // Include full response data for additional error context
120
+ };
121
+ }
33
122
 
34
- try {
35
- const response = await fetch(url, {
36
- method,
37
- headers: {
38
- 'Content-Type': 'application/json',
39
- 'X-API-Key': this.apiKey
40
- },
41
- body: body ? JSON.stringify(body) : undefined
42
- });
43
-
44
- const data = await response.json();
45
-
46
- if (!response.ok) {
47
123
  return {
48
- ok: false,
124
+ ok: true,
49
125
  status: response.status,
50
- error: data.error || `HTTP ${response.status}`,
51
- data // Include full response data for additional error context
126
+ data
52
127
  };
128
+ } catch (err) {
129
+ lastError = err instanceof Error ? err : new Error('Network error');
130
+ // Retry on network errors (connection failures, timeouts)
131
+ if (attempt < maxRetries) {
132
+ const delay = calculateBackoffDelay(attempt, baseDelayMs, maxDelayMs);
133
+ await sleep(delay);
134
+ continue;
135
+ }
53
136
  }
137
+ }
54
138
 
55
- return {
56
- ok: true,
57
- status: response.status,
58
- data
59
- };
60
- } catch (err) {
61
- return {
62
- ok: false,
63
- status: 0,
64
- error: err instanceof Error ? err.message : 'Network error'
65
- };
139
+ // All retries exhausted
140
+ if (lastResponse) {
141
+ // We had a response but it was a retryable error status
142
+ try {
143
+ const data = await lastResponse.json();
144
+ return {
145
+ ok: false,
146
+ status: lastResponse.status,
147
+ error: data.error || `HTTP ${lastResponse.status} after ${maxRetries} retries`,
148
+ data
149
+ };
150
+ } catch {
151
+ return {
152
+ ok: false,
153
+ status: lastResponse.status,
154
+ error: `HTTP ${lastResponse.status} after ${maxRetries} retries`
155
+ };
156
+ }
66
157
  }
158
+
159
+ return {
160
+ ok: false,
161
+ status: 0,
162
+ error: lastError?.message || 'Network error after retries'
163
+ };
67
164
  }
68
165
 
69
166
  // Auth endpoints
@@ -87,6 +184,7 @@ export class VibescopeApiClient {
87
184
  role?: string; // Open-ended - any role name accepted
88
185
  hostname?: string; // Machine hostname for worktree tracking
89
186
  agent_type?: string; // Open-ended - any agent type accepted
187
+ agent_name?: string; // Explicit name for cloud/remote agents (skips persona pool)
90
188
  }): Promise<ApiResponse<{
91
189
  session_started: boolean;
92
190
  session_id?: string;