@pikku/core 0.7.7 → 0.8.0

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 (151) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/dist/errors/error-handler.d.ts +2 -0
  3. package/dist/errors/errors.js +2 -0
  4. package/dist/{channel → events/channel}/channel-handler.d.ts +1 -1
  5. package/dist/{channel → events/channel}/channel-handler.js +2 -2
  6. package/dist/{channel → events/channel}/channel-runner.d.ts +1 -1
  7. package/dist/{channel → events/channel}/channel-runner.js +8 -8
  8. package/dist/{channel → events/channel}/channel-store.d.ts +1 -1
  9. package/dist/{channel → events/channel}/channel.types.d.ts +5 -9
  10. package/dist/{channel → events/channel}/local/local-channel-runner.js +10 -10
  11. package/dist/{channel → events/channel}/log-channels.d.ts +1 -1
  12. package/dist/{channel → events/channel}/log-channels.js +1 -1
  13. package/dist/{channel → events/channel}/serverless/serverless-channel-runner.js +11 -11
  14. package/dist/{http → events/http}/http-runner.d.ts +2 -2
  15. package/dist/{http → events/http}/http-runner.js +30 -19
  16. package/dist/{http → events/http}/http.types.d.ts +4 -3
  17. package/dist/{http → events/http}/index.d.ts +0 -1
  18. package/dist/{http → events/http}/index.js +0 -1
  19. package/dist/{http → events/http}/log-http-routes.d.ts +1 -1
  20. package/dist/{http → events/http}/log-http-routes.js +1 -1
  21. package/dist/{http → events/http}/pikku-fetch-http-request.js +1 -1
  22. package/dist/events/mcp/index.d.ts +2 -0
  23. package/dist/events/mcp/index.js +2 -0
  24. package/dist/events/mcp/mcp-runner.d.ts +30 -0
  25. package/dist/events/mcp/mcp-runner.js +192 -0
  26. package/dist/events/mcp/mcp.types.d.ts +117 -0
  27. package/dist/events/queue/index.d.ts +6 -0
  28. package/dist/events/queue/index.js +6 -0
  29. package/dist/events/queue/queue-runner.d.ts +24 -0
  30. package/dist/events/queue/queue-runner.js +83 -0
  31. package/dist/events/queue/queue.types.d.ts +154 -0
  32. package/dist/events/queue/register-queue-helper.d.ts +17 -0
  33. package/dist/events/queue/register-queue-helper.js +34 -0
  34. package/dist/events/queue/validate-worker-config.d.ts +41 -0
  35. package/dist/events/queue/validate-worker-config.js +50 -0
  36. package/dist/events/rpc/index.d.ts +2 -0
  37. package/dist/events/rpc/rpc-runner.d.ts +28 -0
  38. package/dist/{rpc → events/rpc}/rpc-runner.js +2 -2
  39. package/dist/events/scheduler/index.d.ts +3 -0
  40. package/dist/events/scheduler/index.js +3 -0
  41. package/dist/{scheduler → events/scheduler}/log-schedulers.d.ts +1 -1
  42. package/dist/{scheduler → events/scheduler}/log-schedulers.js +1 -1
  43. package/dist/{scheduler → events/scheduler}/scheduler-runner.d.ts +4 -3
  44. package/dist/{scheduler → events/scheduler}/scheduler-runner.js +7 -4
  45. package/dist/{scheduler → events/scheduler}/scheduler.types.d.ts +3 -4
  46. package/dist/function/function-runner.js +8 -0
  47. package/dist/function/functions.types.d.ts +3 -2
  48. package/dist/handle-error.d.ts +2 -2
  49. package/dist/handle-error.js +1 -1
  50. package/dist/index.d.ts +10 -6
  51. package/dist/index.js +10 -6
  52. package/dist/middleware-runner.d.ts +4 -4
  53. package/dist/middleware-runner.js +4 -2
  54. package/dist/pikku-state.d.ts +18 -4
  55. package/dist/pikku-state.js +12 -0
  56. package/dist/services/user-session-service.d.ts +1 -1
  57. package/dist/types/core.types.d.ts +22 -4
  58. package/dist/types/core.types.js +9 -1
  59. package/lcov.info +3557 -3476
  60. package/package.json +8 -7
  61. package/src/errors/error-handler.ts +2 -1
  62. package/src/errors/errors.ts +2 -0
  63. package/src/{channel → events/channel}/channel-handler.ts +3 -3
  64. package/src/{channel → events/channel}/channel-runner.ts +9 -9
  65. package/src/{channel → events/channel}/channel-store.ts +1 -1
  66. package/src/{channel → events/channel}/channel.types.ts +5 -9
  67. package/src/{channel → events/channel}/local/local-channel-runner.test.ts +1 -1
  68. package/src/{channel → events/channel}/local/local-channel-runner.ts +11 -11
  69. package/src/{channel → events/channel}/local/local-eventhub-service.test.ts +1 -1
  70. package/src/{channel → events/channel}/log-channels.ts +2 -2
  71. package/src/{channel → events/channel}/serverless/serverless-channel-runner.ts +12 -12
  72. package/src/{http → events/http}/http-runner.test.ts +4 -4
  73. package/src/{http → events/http}/http-runner.ts +39 -20
  74. package/src/{http → events/http}/http.types.ts +4 -3
  75. package/src/{http → events/http}/index.ts +0 -1
  76. package/src/{http → events/http}/log-http-routes.ts +2 -2
  77. package/src/{http → events/http}/pikku-fetch-http-request.ts +1 -1
  78. package/src/events/mcp/index.ts +2 -0
  79. package/src/events/mcp/mcp-runner.ts +321 -0
  80. package/src/events/mcp/mcp.types.ts +150 -0
  81. package/src/events/queue/index.ts +18 -0
  82. package/src/events/queue/queue-runner.ts +125 -0
  83. package/src/events/queue/queue.types.ts +176 -0
  84. package/src/events/queue/register-queue-helper.ts +62 -0
  85. package/src/events/queue/validate-worker-config.ts +113 -0
  86. package/src/events/rpc/index.ts +2 -0
  87. package/src/{rpc → events/rpc}/rpc-runner.ts +3 -3
  88. package/src/events/scheduler/index.ts +9 -0
  89. package/src/{scheduler → events/scheduler}/log-schedulers.ts +2 -2
  90. package/src/{scheduler → events/scheduler}/scheduler-runner.ts +11 -10
  91. package/src/{scheduler → events/scheduler}/scheduler.types.ts +2 -4
  92. package/src/function/function-runner.ts +19 -1
  93. package/src/function/functions.types.ts +3 -1
  94. package/src/handle-error.ts +2 -2
  95. package/src/index.ts +23 -6
  96. package/src/middleware-runner.ts +14 -7
  97. package/src/pikku-state.ts +40 -4
  98. package/src/services/user-session-service.ts +1 -1
  99. package/src/types/core.types.ts +31 -4
  100. package/tsconfig.json +3 -2
  101. package/tsconfig.tsbuildinfo +1 -1
  102. package/dist/rpc/index.d.ts +0 -2
  103. package/dist/rpc/rpc-runner.d.ts +0 -27
  104. package/dist/scheduler/index.d.ts +0 -3
  105. package/dist/scheduler/index.js +0 -3
  106. package/src/http/incomingmessage-to-request-convertor.ts +0 -0
  107. package/src/rpc/index.ts +0 -2
  108. package/src/scheduler/index.ts +0 -5
  109. /package/dist/{channel → events/channel}/channel-store.js +0 -0
  110. /package/dist/{channel → events/channel}/channel.types.js +0 -0
  111. /package/dist/{channel → events/channel}/eventhub-service.d.ts +0 -0
  112. /package/dist/{channel → events/channel}/eventhub-service.js +0 -0
  113. /package/dist/{channel → events/channel}/eventhub-store.d.ts +0 -0
  114. /package/dist/{channel → events/channel}/eventhub-store.js +0 -0
  115. /package/dist/{channel → events/channel}/index.d.ts +0 -0
  116. /package/dist/{channel → events/channel}/index.js +0 -0
  117. /package/dist/{channel → events/channel}/local/index.d.ts +0 -0
  118. /package/dist/{channel → events/channel}/local/index.js +0 -0
  119. /package/dist/{channel → events/channel}/local/local-channel-handler.d.ts +0 -0
  120. /package/dist/{channel → events/channel}/local/local-channel-handler.js +0 -0
  121. /package/dist/{channel → events/channel}/local/local-channel-runner.d.ts +0 -0
  122. /package/dist/{channel → events/channel}/local/local-eventhub-service.d.ts +0 -0
  123. /package/dist/{channel → events/channel}/local/local-eventhub-service.js +0 -0
  124. /package/dist/{channel → events/channel}/pikku-abstract-channel-handler.d.ts +0 -0
  125. /package/dist/{channel → events/channel}/pikku-abstract-channel-handler.js +0 -0
  126. /package/dist/{channel → events/channel}/serverless/index.d.ts +0 -0
  127. /package/dist/{channel → events/channel}/serverless/index.js +0 -0
  128. /package/dist/{channel → events/channel}/serverless/serverless-channel-runner.d.ts +0 -0
  129. /package/dist/{http → events/http}/http.types.js +0 -0
  130. /package/dist/{http → events/http}/pikku-fetch-http-request.d.ts +0 -0
  131. /package/dist/{http → events/http}/pikku-fetch-http-response.d.ts +0 -0
  132. /package/dist/{http → events/http}/pikku-fetch-http-response.js +0 -0
  133. /package/dist/{http/incomingmessage-to-request-convertor.d.ts → events/mcp/mcp.types.js} +0 -0
  134. /package/dist/{http/incomingmessage-to-request-convertor.js → events/queue/queue.types.js} +0 -0
  135. /package/dist/{rpc → events/rpc}/index.js +0 -0
  136. /package/dist/{rpc → events/rpc}/rpc-types.d.ts +0 -0
  137. /package/dist/{rpc → events/rpc}/rpc-types.js +0 -0
  138. /package/dist/{scheduler → events/scheduler}/scheduler.types.js +0 -0
  139. /package/src/{channel → events/channel}/eventhub-service.ts +0 -0
  140. /package/src/{channel → events/channel}/eventhub-store.ts +0 -0
  141. /package/src/{channel → events/channel}/index.ts +0 -0
  142. /package/src/{channel → events/channel}/local/index.ts +0 -0
  143. /package/src/{channel → events/channel}/local/local-channel-handler.ts +0 -0
  144. /package/src/{channel → events/channel}/local/local-eventhub-service.ts +0 -0
  145. /package/src/{channel → events/channel}/pikku-abstract-channel-handler.test.ts +0 -0
  146. /package/src/{channel → events/channel}/pikku-abstract-channel-handler.ts +0 -0
  147. /package/src/{channel → events/channel}/serverless/index.ts +0 -0
  148. /package/src/{http → events/http}/pikku-fetch-http-request.test.ts +0 -0
  149. /package/src/{http → events/http}/pikku-fetch-http-response.test.ts +0 -0
  150. /package/src/{http → events/http}/pikku-fetch-http-response.ts +0 -0
  151. /package/src/{rpc → events/rpc}/rpc-types.ts +0 -0
@@ -0,0 +1,321 @@
1
+ import type {
2
+ CoreServices,
3
+ CoreSingletonServices,
4
+ CoreUserSession,
5
+ CreateSessionServices,
6
+ } from '../../types/core.types.js'
7
+ import type {
8
+ CoreMCPResource,
9
+ CoreMCPTool,
10
+ CoreMCPPrompt,
11
+ JsonRpcRequest,
12
+ JsonRpcResponse,
13
+ JsonRpcErrorResponse,
14
+ PikkuMCP,
15
+ } from './mcp.types.js'
16
+ import type { CoreAPIFunctionSessionless } from '../../function/functions.types.js'
17
+ import { getErrorResponse } from '../../errors/error-handler.js'
18
+ import { closeSessionServices } from '../../utils.js'
19
+ import { pikkuState } from '../../pikku-state.js'
20
+ import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
21
+ import { rpcService } from '../rpc/rpc-runner.js'
22
+ import { BadRequestError, NotFoundError } from '../../errors/errors.js'
23
+
24
+ export class MCPError extends Error {
25
+ constructor(public readonly error: JsonRpcErrorResponse) {
26
+ super(error?.message || 'MCP Error')
27
+ this.name = 'MCPError'
28
+ this.stack = new Error().stack
29
+ }
30
+ }
31
+
32
+ export type RunMCPEndpointParams<Tools extends string = any> = {
33
+ session?: CoreUserSession
34
+ singletonServices: CoreSingletonServices
35
+ mcp?: PikkuMCP<Tools>
36
+ createSessionServices?: CreateSessionServices<
37
+ CoreSingletonServices,
38
+ CoreServices<CoreSingletonServices>,
39
+ CoreUserSession
40
+ >
41
+ }
42
+
43
+ export type JsonRpcError = {
44
+ code: number
45
+ message: string
46
+ data?: any
47
+ }
48
+
49
+ export const addMCPResource = <
50
+ APIFunction extends CoreAPIFunctionSessionless<any, any>,
51
+ >(
52
+ mcpResource: CoreMCPResource<APIFunction>
53
+ ) => {
54
+ const resourcesMeta = pikkuState('mcp', 'resourcesMeta')
55
+ const mcpResourceMeta = resourcesMeta[mcpResource.uri]
56
+ if (!mcpResourceMeta) {
57
+ throw new Error(`MCP resource metadata not found for '${mcpResource.uri}'`)
58
+ }
59
+ addFunction(mcpResourceMeta.pikkuFuncName, {
60
+ func: mcpResource.func,
61
+ })
62
+ const resources = pikkuState('mcp', 'resources')
63
+ if (resources.has(mcpResource.uri)) {
64
+ throw new Error(`MCP resource already exists: ${mcpResource.uri}`)
65
+ }
66
+ resources.set(mcpResource.uri, mcpResource)
67
+ }
68
+
69
+ export const addMCPTool = <
70
+ APIFunction extends CoreAPIFunctionSessionless<any, any>,
71
+ >(
72
+ mcpTool: CoreMCPTool<APIFunction>
73
+ ) => {
74
+ const toolsMeta = pikkuState('mcp', 'toolsMeta')
75
+ const mcpToolMeta = toolsMeta[mcpTool.name]
76
+ if (!mcpToolMeta) {
77
+ throw new Error(`MCP tool metadata not found for '${mcpTool.name}'`)
78
+ }
79
+ addFunction(mcpToolMeta.pikkuFuncName, {
80
+ func: mcpTool.func,
81
+ })
82
+ const tools = pikkuState('mcp', 'tools')
83
+ if (tools.has(mcpTool.name)) {
84
+ throw new Error(`MCP tool already exists: ${mcpTool.name}`)
85
+ }
86
+ tools.set(mcpTool.name, mcpTool)
87
+ }
88
+
89
+ export const addMCPPrompt = <
90
+ APIFunction extends CoreAPIFunctionSessionless<any, any>,
91
+ >(
92
+ mcpPrompt: CoreMCPPrompt<APIFunction>
93
+ ) => {
94
+ const promptsMeta = pikkuState('mcp', 'promptsMeta')
95
+ const mcpPromptMeta = promptsMeta[mcpPrompt.name]
96
+ if (!mcpPromptMeta) {
97
+ throw new Error(`MCP prompt metadata not found for '${mcpPrompt.name}'`)
98
+ }
99
+ addFunction(mcpPromptMeta.pikkuFuncName, {
100
+ func: mcpPrompt.func,
101
+ })
102
+ const prompts = pikkuState('mcp', 'prompts')
103
+ if (prompts.has(mcpPrompt.name)) {
104
+ throw new Error(`MCP prompt already exists: ${mcpPrompt.name}`)
105
+ }
106
+ prompts.set(mcpPrompt.name, mcpPrompt)
107
+ }
108
+
109
+ export async function runMCPResource(
110
+ request: JsonRpcRequest,
111
+ params: RunMCPEndpointParams,
112
+ uri: string
113
+ ) {
114
+ let endpoint: CoreMCPResource | undefined
115
+ let pikkuFuncName: string | undefined
116
+ let extractedParams: Record<string, string> = {}
117
+
118
+ const metas = pikkuState('mcp', 'resourcesMeta')
119
+ const endpoints = pikkuState('mcp', 'resources')
120
+
121
+ if (endpoints.has(uri)) {
122
+ endpoint = endpoints.get(uri)
123
+ pikkuFuncName = metas[uri]?.pikkuFuncName
124
+ } else {
125
+ for (const [uriTemplate, value] of endpoints.entries()) {
126
+ // Extract parameter names from the template
127
+ const paramNames = Array.from(
128
+ uriTemplate.matchAll(/\{([^}]+)\}/g),
129
+ (m) => m[1]
130
+ )
131
+
132
+ // Create regex pattern to match and capture parameter values
133
+ const regexPattern = uriTemplate.replace(/\{[^}]+\}/g, '([^/]+)')
134
+ const regex = new RegExp(`^${regexPattern}$`)
135
+ const match = uri.match(regex)
136
+
137
+ if (match) {
138
+ endpoint = value
139
+ pikkuFuncName = metas[uriTemplate]?.pikkuFuncName
140
+
141
+ // Extract parameter values and create params object
142
+ for (let i = 0; i < paramNames.length; i++) {
143
+ extractedParams[paramNames[i]!] = match[i + 1]! // match[0] is the full match
144
+ }
145
+ break
146
+ }
147
+ }
148
+ }
149
+
150
+ return await runMCPPikkuFunc(
151
+ {
152
+ ...request,
153
+ params: { ...request.params, ...extractedParams },
154
+ },
155
+ 'resource',
156
+ uri,
157
+ endpoint,
158
+ pikkuFuncName,
159
+ { ...params, mcp: { uri } } as RunMCPEndpointParams<keyof CoreMCPResource>
160
+ )
161
+ }
162
+
163
+ export async function runMCPTool(
164
+ request: JsonRpcRequest,
165
+ params: RunMCPEndpointParams,
166
+ name: string
167
+ ) {
168
+ const endpoint = pikkuState('mcp', 'tools').get(name)
169
+ const meta = pikkuState('mcp', 'toolsMeta')[name]
170
+ return await runMCPPikkuFunc(
171
+ request,
172
+ 'tool',
173
+ name,
174
+ endpoint,
175
+ meta?.pikkuFuncName,
176
+ params
177
+ )
178
+ }
179
+
180
+ export async function runMCPPrompt(
181
+ request: JsonRpcRequest,
182
+ params: RunMCPEndpointParams,
183
+ name: string
184
+ ) {
185
+ const endpoint = pikkuState('mcp', 'prompts').get(name)
186
+ const meta = pikkuState('mcp', 'promptsMeta')[name]
187
+ return await runMCPPikkuFunc(
188
+ request,
189
+ 'prompt',
190
+ name,
191
+ endpoint,
192
+ meta?.pikkuFuncName,
193
+ params
194
+ )
195
+ }
196
+
197
+ /**
198
+ * JSON-RPC 2.0 compatible MCP endpoint runner
199
+ */
200
+ async function runMCPPikkuFunc(
201
+ request: JsonRpcRequest,
202
+ type: 'resource' | 'tool' | 'prompt',
203
+ name: string,
204
+ mcp: CoreMCPResource | CoreMCPTool | CoreMCPPrompt | undefined,
205
+ pikkuFuncName: string | undefined,
206
+ {
207
+ session,
208
+ singletonServices,
209
+ createSessionServices,
210
+ mcp: interaction,
211
+ }: RunMCPEndpointParams
212
+ ): Promise<JsonRpcResponse> {
213
+ let sessionServices: any
214
+
215
+ try {
216
+ // Validate JSON-RPC request structure
217
+ if (request.jsonrpc !== '2.0') {
218
+ throw new BadRequestError(
219
+ 'Invalid JSON-RPC version, only supoorted version is 2.0'
220
+ )
221
+ }
222
+
223
+ if (!mcp) {
224
+ throw new NotFoundError(
225
+ `MCP '${type}' registration not found for '${name}'`
226
+ )
227
+ }
228
+
229
+ if (!pikkuFuncName) {
230
+ throw new NotFoundError(
231
+ `MCP '${type}' PikkuFunction Mapping not found for '${name}'`
232
+ )
233
+ }
234
+
235
+ singletonServices.logger.debug(`Running MCP ${type}: ${name}`)
236
+
237
+ const getAllServices = async () => {
238
+ if (createSessionServices) {
239
+ const services = await createSessionServices(
240
+ singletonServices,
241
+ { mcp: interaction },
242
+ session
243
+ )
244
+ sessionServices = services
245
+ return rpcService.injectRPCService({
246
+ ...singletonServices,
247
+ ...services,
248
+ mcp: interaction,
249
+ })
250
+ }
251
+ return rpcService.injectRPCService({
252
+ ...singletonServices,
253
+ mcp: interaction,
254
+ })
255
+ }
256
+
257
+ const result = await runPikkuFunc(pikkuFuncName, {
258
+ getAllServices,
259
+ session,
260
+ data: request.params,
261
+ })
262
+
263
+ return {
264
+ id: request.id,
265
+ result,
266
+ }
267
+ } catch (e: any) {
268
+ singletonServices.logger.error(
269
+ `Error running MCP ${type} '${name}':`,
270
+ e.constructor
271
+ )
272
+ const errorResponse = getErrorResponse(e)
273
+ if (errorResponse?.mcpCode) {
274
+ throw new MCPError({
275
+ id: request.id,
276
+ code: errorResponse.mcpCode,
277
+ message: errorResponse.message,
278
+ })
279
+ } else {
280
+ if (errorResponse) {
281
+ singletonServices.logger.warn(
282
+ `Got error without a mapping: ${errorResponse.message}`
283
+ )
284
+ }
285
+ throw new MCPError({
286
+ id: request.id,
287
+ code: -32603,
288
+ message: 'Internal error',
289
+ data: { message: e.message, stack: e.stack },
290
+ })
291
+ }
292
+ } finally {
293
+ if (sessionServices) {
294
+ await closeSessionServices(singletonServices.logger, sessionServices)
295
+ }
296
+ }
297
+ }
298
+
299
+ export const getMCPTools = () => {
300
+ return pikkuState('mcp', 'tools')
301
+ }
302
+
303
+ export const getMCPResources = () => {
304
+ return pikkuState('mcp', 'resources')
305
+ }
306
+
307
+ export const getMCPResourcesMeta = () => {
308
+ return pikkuState('mcp', 'resourcesMeta')
309
+ }
310
+
311
+ export const getMCPToolsMeta = () => {
312
+ return pikkuState('mcp', 'toolsMeta')
313
+ }
314
+
315
+ export const getMCPPrompts = () => {
316
+ return pikkuState('mcp', 'prompts')
317
+ }
318
+
319
+ export const getMCPPromptsMeta = () => {
320
+ return pikkuState('mcp', 'promptsMeta')
321
+ }
@@ -0,0 +1,150 @@
1
+ import { CoreAPIFunctionSessionless } from '../../function/functions.types.js'
2
+
3
+ export type PikkuMCP<Tools extends string = any> = {
4
+ // elicitInput: <Input>(message: string) => Promise<{ action: string, content: Input }>
5
+ uri?: string
6
+ sendResourceUpdated: (uri: string) => void
7
+ enableResources: (resources: Record<string, boolean>) => Promise<boolean>
8
+ enablePrompts: (prompts: Record<string, boolean>) => Promise<boolean>
9
+ enableTools: (tools: Record<Tools, boolean>) => Promise<boolean>
10
+ }
11
+
12
+ /**
13
+ * Represents metadata for MCP resources, including name, description, and documentation.
14
+ */
15
+ export type MCPResourceMeta = Record<
16
+ string,
17
+ Omit<CoreMCPResource, 'func'> & {
18
+ pikkuFuncName: string
19
+ inputSchema: string | null
20
+ outputSchema: string | null
21
+ }
22
+ >
23
+
24
+ /**
25
+ * Represents metadata for MCP tools, including name, description, and documentation.
26
+ */
27
+ export type MCPToolMeta = Record<
28
+ string,
29
+ Omit<CoreMCPTool, 'func'> & {
30
+ pikkuFuncName: string
31
+ inputSchema: string | null
32
+ outputSchema: string | null
33
+ }
34
+ >
35
+
36
+ /**
37
+ * Represents metadata for MCP prompts, including name, description, and arguments.
38
+ */
39
+ export type MCPPromptMeta = Record<
40
+ string,
41
+ Omit<CoreMCPPrompt, 'func'> & {
42
+ pikkuFuncName: string
43
+ inputSchema: string | null
44
+ outputSchema: string | null
45
+ arguments: Array<{
46
+ name: string
47
+ description: string
48
+ required: boolean
49
+ }>
50
+ }
51
+ >
52
+
53
+ /**
54
+ * Represents an MCP resource with specific properties.
55
+ */
56
+ export type CoreMCPResource<
57
+ APIFunction = CoreAPIFunctionSessionless<any, any>,
58
+ > = {
59
+ uri: string
60
+ title: string
61
+ description?: string
62
+ mimeType?: string
63
+ size?: number
64
+ streaming?: boolean
65
+ func: APIFunction
66
+ tags?: string[]
67
+ }
68
+
69
+ /**
70
+ * Represents an MCP tool with specific properties.
71
+ */
72
+ export type CoreMCPTool<APIFunction = CoreAPIFunctionSessionless<any, any>> = {
73
+ name: string
74
+ title?: string
75
+ description: string
76
+ annotations?: Record<string, any>
77
+ func: APIFunction
78
+ tags?: string[]
79
+ streaming?: boolean
80
+ }
81
+
82
+ /**
83
+ * Represents an MCP prompt with specific properties.
84
+ */
85
+ export type CoreMCPPrompt<
86
+ APIFunction = CoreAPIFunctionSessionless<any, MCPPromptResponse>,
87
+ > = {
88
+ name: string
89
+ description?: string
90
+ func: APIFunction
91
+ tags?: string[]
92
+ }
93
+
94
+ export type JsonRpcRequest = {
95
+ jsonrpc: string
96
+ id?: string | number | null
97
+ params?: any
98
+ }
99
+
100
+ export type JsonRpcResponse = {
101
+ id?: string | number | null
102
+ result?: any
103
+ }
104
+
105
+ export type JsonRpcErrorResponse = {
106
+ id?: string | number | null
107
+ code: number
108
+ message: string
109
+ data?: any
110
+ }
111
+
112
+ /**
113
+ * Represents a message in an MCP prompt response
114
+ */
115
+ export type MCPPromptMessage = {
116
+ role: 'user' | 'assistant' | 'system'
117
+ content: {
118
+ type: 'text' | 'image'
119
+ text: string
120
+ data?: string // for image content
121
+ }
122
+ }
123
+
124
+ /**
125
+ * Standard response type for MCP prompts - array of messages
126
+ */
127
+ export type MCPPromptResponse = MCPPromptMessage[]
128
+
129
+ export type MCPResourceMessage = {
130
+ uri: string
131
+ text: string
132
+ }
133
+
134
+ export type MCPResourceResponse = MCPResourceMessage[]
135
+
136
+ /**
137
+ * Standard response type for MCP prompts - array of messages
138
+ */
139
+
140
+ export type MCPToolMessage =
141
+ | {
142
+ type: 'text'
143
+ text: string
144
+ }
145
+ | {
146
+ type: 'image'
147
+ data: string // base64 encoded image data
148
+ }
149
+
150
+ export type MCPToolResponse = MCPToolMessage[]
@@ -0,0 +1,18 @@
1
+ // Queue types
2
+ export type * from './queue.types.js'
3
+
4
+ // Queue processor management
5
+ export {
6
+ addQueueWorker,
7
+ runQueueJob,
8
+ getQueueWorkers,
9
+ removeQueueWorker,
10
+ } from './queue-runner.js'
11
+
12
+ // Configuration validation
13
+ export { validateWorkerConfig } from './validate-worker-config.js'
14
+ export type { QueueConfigMapping } from './validate-worker-config.js'
15
+
16
+ // Queue registration helper
17
+ export { registerqueueWorkers } from './register-queue-helper.js'
18
+ export type { QueueRegistrationCallback } from './register-queue-helper.js'
@@ -0,0 +1,125 @@
1
+ import type { CoreServices } from '../../types/core.types.js'
2
+ import type { CoreQueueWorker, QueueJob } from './queue.types.js'
3
+ import type { CoreAPIFunctionSessionless } from '../../function/functions.types.js'
4
+ import { getErrorResponse } from '../../errors/error-handler.js'
5
+ import { pikkuState } from '../../pikku-state.js'
6
+ import { addFunction, runPikkuFunc } from '../../function/function-runner.js'
7
+ import { CreateSessionServices } from '../../types/core.types.js'
8
+
9
+ /**
10
+ * Error class for queue processor not found
11
+ */
12
+ class QueueWorkerNotFoundError extends Error {
13
+ constructor(name: string) {
14
+ super(`Queue processor not found: ${name}`)
15
+ }
16
+ }
17
+ /**
18
+ * Add a queue processor to the system
19
+ */
20
+ export const addQueueWorker = <
21
+ InputData = any,
22
+ OutputData = any,
23
+ APIFunction extends CoreAPIFunctionSessionless<
24
+ InputData,
25
+ OutputData
26
+ > = CoreAPIFunctionSessionless<InputData, OutputData>,
27
+ >(
28
+ queueWorker: CoreQueueWorker<APIFunction>
29
+ ) => {
30
+ // Get processor metadata
31
+ const meta = pikkuState('queue', 'meta')
32
+ const processorMeta = meta[queueWorker.queueName]
33
+ if (!processorMeta) {
34
+ throw new Error(
35
+ `Queue processor metadata not found for '${queueWorker.queueName}'. Make sure to run the CLI to generate metadata.`
36
+ )
37
+ }
38
+
39
+ // Register the function with pikku
40
+ addFunction(processorMeta.pikkuFuncName, {
41
+ func: queueWorker.func,
42
+ })
43
+
44
+ // Store processor definition in state - runtime adapters will pick this up
45
+ const registrations = pikkuState('queue', 'registrations')
46
+ registrations.set(queueWorker.queueName, queueWorker)
47
+ }
48
+
49
+ /**
50
+ * Get all registered queue processors
51
+ */
52
+ export function getQueueWorkers(): Map<string, CoreQueueWorker> {
53
+ return pikkuState('queue', 'registrations')
54
+ }
55
+
56
+ /**
57
+ * Stop and remove a queue processor
58
+ */
59
+ export async function removeQueueWorker(name: string): Promise<void> {
60
+ const registrations = pikkuState('queue', 'registrations')
61
+ const registration = registrations.get(name)
62
+
63
+ if (!registration) {
64
+ throw new QueueWorkerNotFoundError(name)
65
+ }
66
+
67
+ registrations.delete(name)
68
+ }
69
+
70
+ /**
71
+ * Process a single queue job - this function is called by queue consumers
72
+ */
73
+ export async function runQueueJob({
74
+ singletonServices,
75
+ createSessionServices,
76
+ job,
77
+ }: {
78
+ singletonServices: CoreServices
79
+ createSessionServices?: CreateSessionServices
80
+ job: QueueJob
81
+ }): Promise<void> {
82
+ const logger = singletonServices.logger
83
+
84
+ const meta = pikkuState('queue', 'meta')
85
+ const processorMeta = meta[job.queueName]
86
+ if (!processorMeta) {
87
+ throw new Error(`Processor metadata not found for: ${job.queueName}`)
88
+ }
89
+
90
+ try {
91
+ logger.info(`Processing job ${job.id} in queue ${job.queueName}`)
92
+
93
+ // Use provided singleton services
94
+ const getAllServices = () => ({
95
+ ...singletonServices,
96
+ ...(createSessionServices
97
+ ? createSessionServices(singletonServices, {}, undefined)
98
+ : {}),
99
+ })
100
+
101
+ // Execute the pikku function with the job data
102
+ const result = await runPikkuFunc(processorMeta.pikkuFuncName, {
103
+ getAllServices,
104
+ data: job.data,
105
+ })
106
+
107
+ logger.debug(
108
+ `Successfully processed job ${job.id} in queue ${job.queueName}`
109
+ )
110
+ return result
111
+ } catch (error: any) {
112
+ logger.error(
113
+ `Error processing job ${job.id} in queue ${job.queueName}:`,
114
+ error
115
+ )
116
+
117
+ const errorResponse = getErrorResponse(error)
118
+ if (errorResponse != null) {
119
+ logger.error('Processed error response:', errorResponse)
120
+ }
121
+
122
+ // Re-throw the error so the queue service can handle retries/DLQ
123
+ throw error
124
+ }
125
+ }