@robota-sdk/agent-transport 3.0.0-beta.75 → 3.0.0-beta.76

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 (187) hide show
  1. package/README.md +10 -10
  2. package/dist/node/headless/index.cjs +1 -1
  3. package/dist/node/{headless-CT2ibQnr.cjs → headless-OnpVk4-k.cjs} +7 -7
  4. package/dist/node/index.cjs +1 -1
  5. package/dist/node/index.d.ts +1 -6
  6. package/dist/node/index.d.ts.map +1 -1
  7. package/dist/node/index.js +1 -1
  8. package/dist/node/index.js.map +1 -1
  9. package/package.json +7 -75
  10. package/src/index.ts +1 -5
  11. package/src/transport-registry.ts +0 -9
  12. package/dist/node/http/index.cjs +0 -1
  13. package/dist/node/http/index.d.ts +0 -2
  14. package/dist/node/http/index.js +0 -1
  15. package/dist/node/http-2Jiuflc1.js +0 -2
  16. package/dist/node/http-2Jiuflc1.js.map +0 -1
  17. package/dist/node/http-CBAvefLw.cjs +0 -1
  18. package/dist/node/index-BNccqSpv.d.ts +0 -86
  19. package/dist/node/index-BNccqSpv.d.ts.map +0 -1
  20. package/dist/node/index-BUhHIf7X.d.ts +0 -86
  21. package/dist/node/index-BUhHIf7X.d.ts.map +0 -1
  22. package/dist/node/index-BnAGE-u9.d.ts +0 -33
  23. package/dist/node/index-BnAGE-u9.d.ts.map +0 -1
  24. package/dist/node/index-BrQ4gGw0.d.ts +0 -213
  25. package/dist/node/index-BrQ4gGw0.d.ts.map +0 -1
  26. package/dist/node/index-CoeBF21y.d.ts +0 -213
  27. package/dist/node/index-CoeBF21y.d.ts.map +0 -1
  28. package/dist/node/index-DHt-2VQ-.d.ts +0 -46
  29. package/dist/node/index-DHt-2VQ-.d.ts.map +0 -1
  30. package/dist/node/index-DMwKN5Le.d.ts +0 -33
  31. package/dist/node/index-DMwKN5Le.d.ts.map +0 -1
  32. package/dist/node/index-c0M42fsA.d.ts +0 -46
  33. package/dist/node/index-c0M42fsA.d.ts.map +0 -1
  34. package/dist/node/mcp/index.cjs +0 -1
  35. package/dist/node/mcp/index.d.ts +0 -2
  36. package/dist/node/mcp/index.js +0 -1
  37. package/dist/node/mcp-BOglBJNy.cjs +0 -1
  38. package/dist/node/mcp-D3BBVK7C.js +0 -2
  39. package/dist/node/mcp-D3BBVK7C.js.map +0 -1
  40. package/dist/node/rolldown-runtime-CMqjfN_6.cjs +0 -1
  41. package/dist/node/tui/index.cjs +0 -1
  42. package/dist/node/tui/index.d.ts +0 -2
  43. package/dist/node/tui/index.js +0 -1
  44. package/dist/node/tui-CcH5EsQh.js +0 -25
  45. package/dist/node/tui-CcH5EsQh.js.map +0 -1
  46. package/dist/node/tui-DznRbcku.cjs +0 -24
  47. package/dist/node/ws/index.cjs +0 -1
  48. package/dist/node/ws/index.d.ts +0 -2
  49. package/dist/node/ws/index.js +0 -1
  50. package/dist/node/ws-Dc2RUwVs.js +0 -2
  51. package/dist/node/ws-Dc2RUwVs.js.map +0 -1
  52. package/dist/node/ws-QNMQn5kg.cjs +0 -1
  53. package/src/http/__tests__/http-transport.test.ts +0 -55
  54. package/src/http/__tests__/routes.test.ts +0 -168
  55. package/src/http/http-transport.ts +0 -41
  56. package/src/http/index.ts +0 -4
  57. package/src/http/routes.ts +0 -152
  58. package/src/mcp/__tests__/mcp-server.test.ts +0 -66
  59. package/src/mcp/__tests__/mcp-transport.test.ts +0 -46
  60. package/src/mcp/index.ts +0 -4
  61. package/src/mcp/mcp-server.ts +0 -163
  62. package/src/mcp/mcp-transport.ts +0 -48
  63. package/src/tui/App.tsx +0 -491
  64. package/src/tui/BackgroundTaskPanel.tsx +0 -36
  65. package/src/tui/CjkTextInput.tsx +0 -199
  66. package/src/tui/ConfirmPrompt.tsx +0 -70
  67. package/src/tui/ContextWarningBanner.tsx +0 -34
  68. package/src/tui/ExecutionWorkspaceDetailPane.tsx +0 -64
  69. package/src/tui/ExecutionWorkspaceSwitcher.tsx +0 -187
  70. package/src/tui/InputArea.tsx +0 -310
  71. package/src/tui/InteractivePrompt.tsx +0 -59
  72. package/src/tui/ListPicker.tsx +0 -95
  73. package/src/tui/MenuSelect.tsx +0 -104
  74. package/src/tui/MessageList.tsx +0 -284
  75. package/src/tui/PermissionPrompt.tsx +0 -86
  76. package/src/tui/PluginTUI.tsx +0 -258
  77. package/src/tui/SessionPicker.tsx +0 -68
  78. package/src/tui/SessionStatusBar.tsx +0 -73
  79. package/src/tui/SlashAutocomplete.tsx +0 -110
  80. package/src/tui/StatusBar.tsx +0 -236
  81. package/src/tui/StreamingIndicator.tsx +0 -93
  82. package/src/tui/TextPrompt.tsx +0 -81
  83. package/src/tui/ToolCommandOutput.tsx +0 -39
  84. package/src/tui/ToolDiffBlock.tsx +0 -32
  85. package/src/tui/TransportTUI.tsx +0 -117
  86. package/src/tui/TuiInteractionChannel.ts +0 -495
  87. package/src/tui/UpdateNotice.tsx +0 -14
  88. package/src/tui/UsageSummaryEntry.tsx +0 -39
  89. package/src/tui/WaveText.tsx +0 -44
  90. package/src/tui/__tests__/InteractivePrompt.test.tsx +0 -82
  91. package/src/tui/__tests__/ListPicker.test.tsx +0 -159
  92. package/src/tui/__tests__/MenuSelect.test.tsx +0 -103
  93. package/src/tui/__tests__/PluginTUI.test.tsx +0 -167
  94. package/src/tui/__tests__/SlashAutocomplete.test.tsx +0 -140
  95. package/src/tui/__tests__/TextPrompt.test.tsx +0 -98
  96. package/src/tui/__tests__/TuiInteractionChannel.display-contract.test.ts +0 -239
  97. package/src/tui/__tests__/TuiInteractionChannel.lifecycle.test.ts +0 -297
  98. package/src/tui/__tests__/TuiInteractionChannel.requestAction.test.ts +0 -124
  99. package/src/tui/__tests__/UpdateNotice.test.tsx +0 -15
  100. package/src/tui/__tests__/abort-after-permission.test.tsx +0 -169
  101. package/src/tui/__tests__/abort-streaming-e2e.test.tsx +0 -183
  102. package/src/tui/__tests__/background-task-panel.test.tsx +0 -53
  103. package/src/tui/__tests__/background-task-row-format.test.ts +0 -59
  104. package/src/tui/__tests__/channel-factory-integration.test.ts +0 -138
  105. package/src/tui/__tests__/cjk-text-input-flow.test.ts +0 -109
  106. package/src/tui/__tests__/cjk-text-input.test.ts +0 -191
  107. package/src/tui/__tests__/command-effect-handler.test.ts +0 -127
  108. package/src/tui/__tests__/command-output-summary.test.ts +0 -95
  109. package/src/tui/__tests__/compact-event-bridge.test.ts +0 -20
  110. package/src/tui/__tests__/confirm-permission-flow.test.ts +0 -130
  111. package/src/tui/__tests__/confirm-prompt.test.tsx +0 -87
  112. package/src/tui/__tests__/execution-workspace-switcher.test.tsx +0 -110
  113. package/src/tui/__tests__/execution-workspace-view-model.test.ts +0 -93
  114. package/src/tui/__tests__/fixtures/provider-setup-prompt-driver.tsx +0 -125
  115. package/src/tui/__tests__/input-area-flow.test.ts +0 -164
  116. package/src/tui/__tests__/message-list-rendering.test.tsx +0 -353
  117. package/src/tui/__tests__/prompt-queue.test.tsx +0 -255
  118. package/src/tui/__tests__/provider-setup-pty-e2e.test.ts +0 -233
  119. package/src/tui/__tests__/pty/pty-driver.ts +0 -135
  120. package/src/tui/__tests__/pty/tui-pty.ptytest.ts +0 -61
  121. package/src/tui/__tests__/render-channel-options.test.ts +0 -32
  122. package/src/tui/__tests__/render-markdown.test.ts +0 -72
  123. package/src/tui/__tests__/selection-flow.test.ts +0 -61
  124. package/src/tui/__tests__/session-init-poller.test.ts +0 -102
  125. package/src/tui/__tests__/session-naming.test.ts +0 -64
  126. package/src/tui/__tests__/session-switch-channel.test.tsx +0 -307
  127. package/src/tui/__tests__/slash-routing-effects.test.ts +0 -228
  128. package/src/tui/__tests__/status-activity.test.ts +0 -71
  129. package/src/tui/__tests__/status-bar.test.tsx +0 -177
  130. package/src/tui/__tests__/streaming-indicator.test.tsx +0 -137
  131. package/src/tui/__tests__/text-prompt-flow.test.ts +0 -77
  132. package/src/tui/__tests__/tui-channel-init-failure.test.ts +0 -57
  133. package/src/tui/__tests__/tui-state-manager.test.ts +0 -401
  134. package/src/tui/background-task-row-format.ts +0 -53
  135. package/src/tui/command-interaction.ts +0 -9
  136. package/src/tui/command-output-summary.ts +0 -122
  137. package/src/tui/create-default-tui-cli-adapter.ts +0 -41
  138. package/src/tui/execution-workspace-view-model.ts +0 -123
  139. package/src/tui/flows/cjk-text-input-flow.ts +0 -285
  140. package/src/tui/flows/confirm-prompt-flow.ts +0 -45
  141. package/src/tui/flows/input-area-flow.ts +0 -189
  142. package/src/tui/flows/permission-prompt-flow.ts +0 -85
  143. package/src/tui/flows/selection-flow.ts +0 -126
  144. package/src/tui/flows/session-init-poller.ts +0 -77
  145. package/src/tui/flows/text-prompt-flow.ts +0 -98
  146. package/src/tui/hooks/command-effect-handler.ts +0 -97
  147. package/src/tui/hooks/command-effect-queue.ts +0 -39
  148. package/src/tui/hooks/side-effects-types.ts +0 -35
  149. package/src/tui/hooks/useAutocomplete.ts +0 -87
  150. package/src/tui/hooks/usePluginCallbacks.ts +0 -31
  151. package/src/tui/hooks/usePluginScreenData.ts +0 -85
  152. package/src/tui/hooks/useSideEffects.ts +0 -175
  153. package/src/tui/hooks/useSlashRouting.ts +0 -118
  154. package/src/tui/hooks/useStatusLineSettings.ts +0 -37
  155. package/src/tui/hooks/useTuiChannel.ts +0 -95
  156. package/src/tui/index.ts +0 -14
  157. package/src/tui/interactions/CommandConfirm.tsx +0 -36
  158. package/src/tui/interactions/CommandPicker.tsx +0 -77
  159. package/src/tui/interactions/__tests__/CommandConfirm.test.tsx +0 -124
  160. package/src/tui/interactions/__tests__/CommandPicker.test.tsx +0 -138
  161. package/src/tui/plugin-tui-handlers.ts +0 -163
  162. package/src/tui/render-markdown.ts +0 -130
  163. package/src/tui/render.tsx +0 -129
  164. package/src/tui/session-naming.ts +0 -33
  165. package/src/tui/status-activity.ts +0 -63
  166. package/src/tui/tui-cli-adapter-context.tsx +0 -13
  167. package/src/tui/tui-cli-adapter.ts +0 -25
  168. package/src/tui/tui-state-manager.ts +0 -226
  169. package/src/tui/tui-transport.ts +0 -35
  170. package/src/tui/types.ts +0 -15
  171. package/src/tui/utils/__tests__/edit-diff.test.ts +0 -426
  172. package/src/tui/utils/__tests__/paste-detection.test.ts +0 -116
  173. package/src/tui/utils/__tests__/paste-labels.test.ts +0 -46
  174. package/src/tui/utils/__tests__/tool-call-extractor.test.ts +0 -227
  175. package/src/tui/utils/__tests__/tool-diff-summary.test.ts +0 -104
  176. package/src/tui/utils/edit-diff.ts +0 -153
  177. package/src/tui/utils/paste-labels.ts +0 -9
  178. package/src/tui/utils/tool-call-extractor.ts +0 -92
  179. package/src/tui/utils/tool-diff-summary.ts +0 -75
  180. package/src/ws/__tests__/ws-handler.test.ts +0 -409
  181. package/src/ws/__tests__/ws-transport.test.ts +0 -53
  182. package/src/ws/index.ts +0 -13
  183. package/src/ws/ws-background-messages.ts +0 -170
  184. package/src/ws/ws-handler.ts +0 -280
  185. package/src/ws/ws-protocol.ts +0 -78
  186. package/src/ws/ws-transport-configurable.ts +0 -128
  187. package/src/ws/ws-transport.ts +0 -42
@@ -1,152 +0,0 @@
1
- /**
2
- * HTTP transport adapter — exposes IInteractiveSession over REST API.
3
- *
4
- * Built on Hono for Cloudflare Workers + Node.js + AWS Lambda compatibility.
5
- * Each endpoint maps 1:1 to an IInteractiveSession API method.
6
- */
7
-
8
- import { Hono } from 'hono';
9
- import { streamSSE } from 'hono/streaming';
10
-
11
- import type { IInteractiveSession } from '@robota-sdk/agent-interface-transport';
12
- import type { Context } from 'hono';
13
-
14
- /** Callback that resolves an IInteractiveSession from the request context. */
15
- export type TSessionFactory = (c: Context) => IInteractiveSession | Promise<IInteractiveSession>;
16
-
17
- export interface IAgentRoutesOptions {
18
- /** Resolve an IInteractiveSession per request (e.g., by auth token, session ID). */
19
- sessionFactory: TSessionFactory;
20
- }
21
-
22
- /**
23
- * Create a Hono router with all agent HTTP endpoints.
24
- *
25
- * Usage:
26
- * ```typescript
27
- * const routes = createAgentRoutes({ sessionFactory });
28
- * app.route('/agent', routes); // mount on existing app
29
- * export default routes; // or use standalone (CF Workers)
30
- * ```
31
- */
32
- export function createAgentRoutes(options: IAgentRoutesOptions): Hono {
33
- const { sessionFactory } = options;
34
- const app = new Hono();
35
-
36
- // POST /submit — execute prompt, stream events via SSE
37
- app.post('/submit', async (c) => {
38
- const session = await sessionFactory(c);
39
- const body = await c.req.json<{ prompt: string }>();
40
-
41
- if (!body.prompt || typeof body.prompt !== 'string') {
42
- return c.json({ error: 'prompt is required' }, 400);
43
- }
44
-
45
- return streamSSE(c, async (stream) => {
46
- const cleanup: Array<() => void> = [];
47
-
48
- const subscribe = <T>(event: string, handler: (data: T) => void): void => {
49
- session.on(event as 'text_delta', handler as () => void);
50
- cleanup.push(() => session.off(event as 'text_delta', handler as () => void));
51
- };
52
-
53
- let completed = false;
54
- const done = new Promise<void>((resolve) => {
55
- subscribe('text_delta', (delta: string) => {
56
- stream.writeSSE({ event: 'text_delta', data: JSON.stringify({ delta }) });
57
- });
58
-
59
- subscribe('tool_start', (state) => {
60
- stream.writeSSE({ event: 'tool_start', data: JSON.stringify(state) });
61
- });
62
-
63
- subscribe('tool_end', (state) => {
64
- stream.writeSSE({ event: 'tool_end', data: JSON.stringify(state) });
65
- });
66
-
67
- subscribe('thinking', (isThinking: boolean) => {
68
- stream.writeSSE({ event: 'thinking', data: JSON.stringify({ isThinking }) });
69
- if (!isThinking && completed) {
70
- resolve();
71
- }
72
- });
73
-
74
- subscribe('complete', (result) => {
75
- completed = true;
76
- stream.writeSSE({ event: 'complete', data: JSON.stringify(result) });
77
- });
78
-
79
- subscribe('interrupted', (result) => {
80
- completed = true;
81
- stream.writeSSE({ event: 'interrupted', data: JSON.stringify(result) });
82
- });
83
-
84
- subscribe('error', (error: Error) => {
85
- completed = true;
86
- stream.writeSSE({ event: 'error', data: JSON.stringify({ message: error.message }) });
87
- });
88
- });
89
-
90
- await session.submit(body.prompt);
91
- await done;
92
-
93
- for (const fn of cleanup) fn();
94
- });
95
- });
96
-
97
- // POST /command — execute system command
98
- app.post('/command', async (c) => {
99
- const session = await sessionFactory(c);
100
- const body = await c.req.json<{ name: string; args?: string }>();
101
-
102
- if (!body.name || typeof body.name !== 'string') {
103
- return c.json({ error: 'name is required' }, 400);
104
- }
105
-
106
- const result = await session.executeCommand(body.name, body.args ?? '');
107
- if (!result) {
108
- return c.json({ error: `Unknown command: ${body.name}` }, 404);
109
- }
110
- return c.json(result);
111
- });
112
-
113
- // POST /abort — abort current execution
114
- app.post('/abort', async (c) => {
115
- const session = await sessionFactory(c);
116
- session.abort();
117
- return c.json({ ok: true });
118
- });
119
-
120
- // POST /cancel-queue — cancel queued prompt
121
- app.post('/cancel-queue', async (c) => {
122
- const session = await sessionFactory(c);
123
- session.cancelQueue();
124
- return c.json({ ok: true });
125
- });
126
-
127
- // GET /messages — get message history
128
- app.get('/messages', async (c) => {
129
- const session = await sessionFactory(c);
130
- return c.json(session.getMessages());
131
- });
132
-
133
- // GET /context — get context window state
134
- app.get('/context', async (c) => {
135
- const session = await sessionFactory(c);
136
- return c.json(session.getContextState());
137
- });
138
-
139
- // GET /executing — check if currently executing
140
- app.get('/executing', async (c) => {
141
- const session = await sessionFactory(c);
142
- return c.json({ executing: session.isExecuting() });
143
- });
144
-
145
- // GET /pending — get pending queued prompt
146
- app.get('/pending', async (c) => {
147
- const session = await sessionFactory(c);
148
- return c.json({ pending: session.getPendingPrompt() });
149
- });
150
-
151
- return app;
152
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * Tests for MCP transport adapter.
3
- */
4
-
5
- import { describe, it, expect, vi } from 'vitest';
6
- import { createAgentMcpServer } from '../mcp-server.js';
7
- import type { IInteractiveSession } from '@robota-sdk/agent-interface-transport';
8
-
9
- function createMockSession(commands?: Array<{ name: string; description: string }>) {
10
- return {
11
- submit: vi.fn(),
12
- abort: vi.fn(),
13
- cancelQueue: vi.fn(),
14
- getMessages: vi.fn().mockReturnValue([]),
15
- getContextState: vi
16
- .fn()
17
- .mockReturnValue({ usedTokens: 0, maxTokens: 200000, usedPercentage: 0 }),
18
- isExecuting: vi.fn().mockReturnValue(false),
19
- getPendingPrompt: vi.fn().mockReturnValue(null),
20
- executeCommand: vi.fn().mockResolvedValue({ message: 'done', success: true }),
21
- listCommands: vi.fn().mockReturnValue(
22
- commands ?? [
23
- { name: 'clear', description: 'Clear history' },
24
- { name: 'mode', description: 'Permission mode' },
25
- ],
26
- ),
27
- on: vi.fn(),
28
- off: vi.fn(),
29
- } as unknown as IInteractiveSession;
30
- }
31
-
32
- describe('createAgentMcpServer', () => {
33
- it('creates a server instance', () => {
34
- const server = createAgentMcpServer({
35
- name: 'test-agent',
36
- version: '1.0.0',
37
- session: createMockSession(),
38
- });
39
- expect(server).toBeDefined();
40
- });
41
-
42
- it('exposeCommands=false does not call listCommands', () => {
43
- const session = createMockSession();
44
- createAgentMcpServer({
45
- name: 'test',
46
- version: '1.0.0',
47
- session,
48
- exposeCommands: false,
49
- });
50
- expect(session.listCommands).not.toHaveBeenCalled();
51
- });
52
-
53
- it('exposeCommands=true calls session.listCommands()', () => {
54
- const session = createMockSession([
55
- { name: 'clear', description: 'Clear' },
56
- { name: 'help', description: 'Help' },
57
- ]);
58
- createAgentMcpServer({
59
- name: 'test',
60
- version: '1.0.0',
61
- session,
62
- exposeCommands: true,
63
- });
64
- expect(session.listCommands).toHaveBeenCalled();
65
- });
66
- });
@@ -1,46 +0,0 @@
1
- import { describe, it, expect, vi } from 'vitest';
2
- import { createMcpTransport } from '../mcp-transport.js';
3
- import type { IInteractiveSession } from '@robota-sdk/agent-interface-transport';
4
-
5
- function createMockSession(): IInteractiveSession {
6
- return {
7
- submit: vi.fn(),
8
- abort: vi.fn(),
9
- cancelQueue: vi.fn(),
10
- getMessages: vi.fn().mockReturnValue([]),
11
- getContextState: vi
12
- .fn()
13
- .mockReturnValue({ usedPercentage: 0, usedTokens: 0, maxTokens: 200000 }),
14
- isExecuting: vi.fn().mockReturnValue(false),
15
- getPendingPrompt: vi.fn().mockReturnValue(null),
16
- executeCommand: vi.fn().mockResolvedValue({ message: 'ok', success: true }),
17
- listCommands: vi.fn().mockReturnValue([]),
18
- on: vi.fn(),
19
- off: vi.fn(),
20
- } as unknown as IInteractiveSession;
21
- }
22
-
23
- describe('createMcpTransport', () => {
24
- it('returns an adapter with name "mcp"', () => {
25
- const transport = createMcpTransport({ name: 'test', version: '1.0.0' });
26
- expect(transport.name).toBe('mcp');
27
- });
28
-
29
- it('throws if start() is called without attach()', async () => {
30
- const transport = createMcpTransport({ name: 'test', version: '1.0.0' });
31
- await expect(transport.start()).rejects.toThrow('No session attached');
32
- });
33
-
34
- it('throws if getServer() is called before start()', () => {
35
- const transport = createMcpTransport({ name: 'test', version: '1.0.0' });
36
- expect(() => transport.getServer()).toThrow('Transport not started');
37
- });
38
-
39
- it('creates an MCP server after attach + start', async () => {
40
- const transport = createMcpTransport({ name: 'test', version: '1.0.0' });
41
- transport.attach(createMockSession() as never);
42
- await transport.start();
43
- const server = transport.getServer();
44
- expect(server).toBeDefined();
45
- });
46
- });
package/src/mcp/index.ts DELETED
@@ -1,4 +0,0 @@
1
- export { createAgentMcpServer } from './mcp-server.js';
2
- export type { IAgentMcpOptions } from './mcp-server.js';
3
- export { createMcpTransport } from './mcp-transport.js';
4
- export type { IMcpTransportOptions } from './mcp-transport.js';
@@ -1,163 +0,0 @@
1
- /**
2
- * MCP transport adapter — exposes IInteractiveSession as an MCP server.
3
- *
4
- * Uses the low-level MCP Server class to avoid TypeScript depth issues
5
- * with McpServer.registerTool() generics. Registers tools/list and
6
- * tools/call handlers directly.
7
- */
8
-
9
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
10
- import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
11
-
12
- import type { IExecutionResult, IInteractiveSession } from '@robota-sdk/agent-interface-transport';
13
-
14
- export interface IAgentMcpOptions {
15
- /** Name for the MCP server. */
16
- name: string;
17
- /** Version string. */
18
- version: string;
19
- /** IInteractiveSession to expose. */
20
- session: IInteractiveSession;
21
- /** If true, register each system command as a separate MCP tool. Default: true. */
22
- exposeCommands?: boolean;
23
- }
24
-
25
- /**
26
- * Create an MCP server that exposes IInteractiveSession over Model Context Protocol.
27
- *
28
- * Usage:
29
- * ```typescript
30
- * const server = createAgentMcpServer({
31
- * name: 'robota-agent',
32
- * version: '1.0.0',
33
- * session: interactiveSession,
34
- * });
35
- *
36
- * import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
37
- * await server.connect(new StdioServerTransport());
38
- * ```
39
- */
40
- export function createAgentMcpServer(options: IAgentMcpOptions): Server {
41
- const { name, version, session, exposeCommands = true } = options;
42
-
43
- const server = new Server({ name, version }, { capabilities: { tools: {} } });
44
-
45
- // Build tool definitions
46
- const tools: Array<{
47
- name: string;
48
- description: string;
49
- inputSchema: Record<string, unknown>;
50
- }> = [
51
- {
52
- name: 'submit',
53
- description: 'Submit a prompt to the AI agent and wait for the response',
54
- inputSchema: {
55
- type: 'object',
56
- properties: {
57
- prompt: { type: 'string', description: 'The prompt to send to the agent' },
58
- },
59
- required: ['prompt'],
60
- },
61
- },
62
- ];
63
-
64
- if (exposeCommands) {
65
- for (const cmd of session.listCommands()) {
66
- tools.push({
67
- name: `command_${cmd.name}`,
68
- description: cmd.description,
69
- inputSchema: {
70
- type: 'object',
71
- properties: {
72
- args: { type: 'string', description: 'Command arguments' },
73
- },
74
- },
75
- });
76
- }
77
- }
78
-
79
- // tools/list handler
80
- server.setRequestHandler(ListToolsRequestSchema, async () => ({
81
- tools,
82
- }));
83
-
84
- // tools/call handler
85
- server.setRequestHandler(CallToolRequestSchema, async (request) => {
86
- const { name: toolName, arguments: toolArgs } = request.params;
87
-
88
- if (toolName === 'submit') {
89
- const prompt = (toolArgs as Record<string, string>)?.prompt;
90
- if (!prompt) {
91
- return {
92
- content: [{ type: 'text', text: 'Error: prompt is required' }],
93
- isError: true,
94
- };
95
- }
96
- const result = await waitForCompletion(session, prompt);
97
- return {
98
- content: [{ type: 'text', text: result.response }],
99
- };
100
- }
101
-
102
- // System commands: command_<name>
103
- if (toolName.startsWith('command_')) {
104
- const cmdName = toolName.slice('command_'.length);
105
- const args = (toolArgs as Record<string, string>)?.args ?? '';
106
- const result = await session.executeCommand(cmdName, args);
107
- return {
108
- content: [
109
- {
110
- type: 'text',
111
- text: result?.message ?? `Unknown command: ${cmdName}`,
112
- },
113
- ],
114
- isError: !result,
115
- };
116
- }
117
-
118
- return {
119
- content: [{ type: 'text', text: `Unknown tool: ${toolName}` }],
120
- isError: true,
121
- };
122
- });
123
-
124
- return server;
125
- }
126
-
127
- /**
128
- * Submit a prompt and wait for the complete/interrupted/error event.
129
- */
130
- function waitForCompletion(
131
- session: IInteractiveSession,
132
- prompt: string,
133
- ): Promise<IExecutionResult> {
134
- return new Promise((resolve, reject) => {
135
- const onComplete = (result: IExecutionResult): void => {
136
- cleanup();
137
- resolve(result);
138
- };
139
- const onInterrupted = (result: IExecutionResult): void => {
140
- cleanup();
141
- resolve(result);
142
- };
143
- const onError = (error: Error): void => {
144
- cleanup();
145
- reject(error);
146
- };
147
-
148
- const cleanup = (): void => {
149
- session.off('complete', onComplete);
150
- session.off('interrupted', onInterrupted);
151
- session.off('error', onError);
152
- };
153
-
154
- session.on('complete', onComplete);
155
- session.on('interrupted', onInterrupted);
156
- session.on('error', onError);
157
-
158
- session.submit(prompt).catch((err) => {
159
- cleanup();
160
- reject(err instanceof Error ? err : new Error(String(err)));
161
- });
162
- });
163
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * ITransportAdapter implementation for MCP transport.
3
- *
4
- * Wraps createAgentMcpServer into the unified ITransportAdapter interface
5
- * while exposing the underlying MCP Server via getServer().
6
- */
7
-
8
- import { createAgentMcpServer } from './mcp-server.js';
9
-
10
- import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
11
- import type { IInteractiveSession, ITransportAdapter } from '@robota-sdk/agent-interface-transport';
12
-
13
- export interface IMcpTransportOptions {
14
- /** Name for the MCP server. */
15
- name: string;
16
- /** Version string. */
17
- version: string;
18
- /** If true, register each system command as a separate MCP tool. Default: true. */
19
- exposeCommands?: boolean;
20
- }
21
-
22
- export function createMcpTransport(
23
- options: IMcpTransportOptions,
24
- ): ITransportAdapter<IInteractiveSession> & { getServer(): Server } {
25
- let session: IInteractiveSession | null = null;
26
- let server: Server | null = null;
27
-
28
- return {
29
- name: 'mcp',
30
- attach(s: IInteractiveSession) {
31
- session = s;
32
- },
33
- async start() {
34
- if (!session) throw new Error('No session attached. Call attach() first.');
35
- server = createAgentMcpServer({ ...options, session });
36
- },
37
- async stop() {
38
- if (server) {
39
- await server.close();
40
- server = null;
41
- }
42
- },
43
- getServer() {
44
- if (!server) throw new Error('Transport not started. Call start() first.');
45
- return server;
46
- },
47
- };
48
- }