@pikku/core 0.12.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/errors/errors.d.ts +6 -0
- package/dist/errors/errors.js +10 -0
- package/dist/errors/index.d.ts +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/function/function-runner.d.ts +3 -3
- package/dist/function/function-runner.js +66 -44
- package/dist/function/functions.types.d.ts +1 -0
- package/dist/handle-error.d.ts +2 -2
- package/dist/handle-error.js +2 -2
- package/dist/index.d.ts +5 -3
- package/dist/index.js +2 -1
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +2 -0
- package/dist/middleware/auth-bearer.d.ts +1 -1
- package/dist/middleware/auth-bearer.js +1 -1
- package/dist/middleware/auth-cookie.d.ts +2 -2
- package/dist/middleware/auth-cookie.js +1 -1
- package/dist/middleware/cors.d.ts +2 -2
- package/dist/middleware/cors.js +45 -37
- package/dist/middleware-runner.d.ts +1 -1
- package/dist/permissions.d.ts +2 -2
- package/dist/pikku-state.d.ts +9 -8
- package/dist/pikku-state.js +30 -17
- package/dist/schema.d.ts +4 -4
- package/dist/schema.js +9 -5
- package/dist/services/ai-agent-runner-service.d.ts +22 -3
- package/dist/services/ai-run-state-service.d.ts +1 -1
- package/dist/services/ai-storage-service.d.ts +1 -1
- package/dist/services/content-service.d.ts +6 -0
- package/dist/services/gopass-secrets.d.ts +1 -1
- package/dist/services/gopass-secrets.js +3 -0
- package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
- package/dist/services/in-memory-ai-run-state-service.js +44 -0
- package/dist/services/in-memory-trigger-service.d.ts +0 -1
- package/dist/services/in-memory-trigger-service.js +6 -8
- package/dist/services/index.d.ts +3 -2
- package/dist/services/index.js +1 -0
- package/dist/services/local-content.d.ts +2 -1
- package/dist/services/local-content.js +6 -1
- package/dist/services/local-secrets.d.ts +2 -2
- package/dist/services/local-variables.d.ts +1 -1
- package/dist/services/logger-console.d.ts +2 -1
- package/dist/services/scheduler-service.d.ts +0 -12
- package/dist/services/scheduler-service.js +0 -6
- package/dist/services/scoped-secret-service.d.ts +1 -1
- package/dist/services/trigger-service.d.ts +0 -7
- package/dist/services/user-session-service.d.ts +3 -3
- package/dist/services/workflow-service.d.ts +2 -3
- package/dist/types/core.types.d.ts +24 -18
- package/dist/types/state.types.d.ts +17 -15
- package/dist/utils.d.ts +5 -5
- package/dist/utils.js +12 -9
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
- package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +146 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
- package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +4 -5
- package/dist/wirings/ai-agent/ai-agent-prepare.js +66 -30
- package/dist/wirings/ai-agent/ai-agent-registry.d.ts +1 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +107 -8
- package/dist/wirings/ai-agent/ai-agent-stream.d.ts +2 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +246 -87
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +61 -2
- package/dist/wirings/ai-agent/index.d.ts +3 -1
- package/dist/wirings/ai-agent/index.js +2 -0
- package/dist/wirings/channel/channel-common.d.ts +2 -2
- package/dist/wirings/channel/channel-handler.d.ts +3 -3
- package/dist/wirings/channel/channel-handler.js +4 -4
- package/dist/wirings/channel/channel-runner.d.ts +5 -5
- package/dist/wirings/channel/channel-runner.js +3 -2
- package/dist/wirings/channel/channel-store.d.ts +1 -1
- package/dist/wirings/channel/channel.types.d.ts +4 -6
- package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
- package/dist/wirings/channel/local/local-channel-runner.js +4 -3
- package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
- package/dist/wirings/channel/log-channels.d.ts +1 -1
- package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +1 -1
- package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +25 -19
- package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
- package/dist/wirings/cli/cli-runner.d.ts +2 -2
- package/dist/wirings/cli/cli.types.d.ts +3 -3
- package/dist/wirings/cli/command-parser.d.ts +1 -1
- package/dist/wirings/http/http-runner.d.ts +9 -9
- package/dist/wirings/http/http-runner.js +33 -14
- package/dist/wirings/http/http.types.d.ts +2 -6
- package/dist/wirings/http/log-http-routes.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
- package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
- package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
- package/dist/wirings/http/routers/http-router.d.ts +1 -1
- package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
- package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
- package/dist/wirings/mcp/mcp-runner.d.ts +0 -3
- package/dist/wirings/mcp/mcp-runner.js +4 -2
- package/dist/wirings/mcp/mcp.types.d.ts +2 -2
- package/dist/wirings/oauth2/oauth2-client.d.ts +3 -3
- package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +1 -1
- package/dist/wirings/queue/index.d.ts +1 -1
- package/dist/wirings/queue/index.js +1 -1
- package/dist/wirings/queue/queue-runner.d.ts +1 -12
- package/dist/wirings/queue/queue-runner.js +4 -12
- package/dist/wirings/queue/queue.types.d.ts +3 -9
- package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
- package/dist/wirings/queue/register-queue-helper.js +1 -1
- package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
- package/dist/wirings/rpc/index.d.ts +2 -0
- package/dist/wirings/rpc/index.js +1 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +36 -14
- package/dist/wirings/rpc/rpc-runner.js +56 -28
- package/dist/wirings/rpc/rpc-types.d.ts +14 -2
- package/dist/wirings/rpc/wire-addon.d.ts +10 -0
- package/dist/wirings/rpc/wire-addon.js +9 -0
- package/dist/wirings/scheduler/index.d.ts +1 -1
- package/dist/wirings/scheduler/index.js +1 -1
- package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
- package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -10
- package/dist/wirings/scheduler/scheduler-runner.js +4 -25
- package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
- package/dist/wirings/trigger/pikku-trigger-service.d.ts +2 -6
- package/dist/wirings/trigger/pikku-trigger-service.js +11 -16
- package/dist/wirings/trigger/trigger-runner.d.ts +1 -5
- package/dist/wirings/trigger/trigger-runner.js +4 -3
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +2 -6
- package/dist/wirings/workflow/pikku-workflow-service.js +20 -29
- package/dist/wirings/workflow/workflow.types.d.ts +2 -2
- package/package.json +2 -1
- package/src/crypto-utils.test.ts +116 -0
- package/src/errors/error.test.ts +143 -2
- package/src/errors/errors.ts +10 -0
- package/src/errors/index.ts +1 -0
- package/src/function/function-runner.test.ts +2 -2
- package/src/function/function-runner.ts +72 -49
- package/src/function/functions.types.ts +1 -0
- package/src/handle-error.test.ts +361 -0
- package/src/handle-error.ts +4 -4
- package/src/index.ts +3 -10
- package/src/internal.ts +6 -0
- package/src/middleware/auth-apikey.test.ts +1 -1
- package/src/middleware/auth-bearer.test.ts +1 -1
- package/src/middleware/auth-bearer.ts +2 -5
- package/src/middleware/auth-cookie.test.ts +1 -1
- package/src/middleware/auth-cookie.ts +3 -5
- package/src/middleware/cors.test.ts +424 -0
- package/src/middleware/cors.ts +14 -6
- package/src/middleware/remote-auth.test.ts +488 -0
- package/src/middleware-runner.test.ts +1 -1
- package/src/middleware-runner.ts +1 -1
- package/src/permissions.test.ts +2 -2
- package/src/permissions.ts +2 -2
- package/src/pikku-state.test.ts +224 -0
- package/src/pikku-state.ts +40 -28
- package/src/schema.test.ts +198 -6
- package/src/schema.ts +11 -7
- package/src/services/ai-agent-runner-service.ts +15 -3
- package/src/services/ai-run-state-service.ts +1 -1
- package/src/services/ai-storage-service.ts +1 -1
- package/src/services/content-service.ts +7 -0
- package/src/services/gopass-secrets.ts +4 -1
- package/src/services/in-memory-ai-run-state-service.ts +73 -0
- package/src/services/in-memory-trigger-service.ts +6 -10
- package/src/services/in-memory-workflow-service.test.ts +351 -0
- package/src/services/index.ts +2 -1
- package/src/services/local-content.ts +9 -3
- package/src/services/local-secrets.test.ts +80 -0
- package/src/services/local-secrets.ts +2 -2
- package/src/services/local-variables.test.ts +61 -0
- package/src/services/local-variables.ts +1 -1
- package/src/services/logger-console.test.ts +118 -0
- package/src/services/logger-console.ts +2 -1
- package/src/services/scheduler-service.ts +0 -18
- package/src/services/scoped-secret-service.test.ts +74 -0
- package/src/services/scoped-secret-service.ts +1 -1
- package/src/services/trigger-service.ts +0 -21
- package/src/services/typed-secret-service.test.ts +93 -0
- package/src/services/typed-variables-service.test.ts +73 -0
- package/src/services/user-session-service.test.ts +113 -0
- package/src/services/user-session-service.ts +3 -3
- package/src/services/workflow-service.ts +2 -12
- package/src/time-utils.test.ts +1 -1
- package/src/types/core.types.ts +25 -19
- package/src/types/state.types.ts +24 -15
- package/src/utils.test.ts +350 -0
- package/src/utils.ts +14 -13
- package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
- package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +214 -0
- package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
- package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +79 -45
- package/src/wirings/ai-agent/ai-agent-registry.ts +1 -1
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +245 -3
- package/src/wirings/ai-agent/ai-agent-runner.ts +121 -7
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +430 -24
- package/src/wirings/ai-agent/ai-agent-stream.ts +377 -102
- package/src/wirings/ai-agent/ai-agent.types.ts +57 -2
- package/src/wirings/ai-agent/index.ts +11 -0
- package/src/wirings/channel/channel-common.ts +2 -2
- package/src/wirings/channel/channel-handler.ts +13 -9
- package/src/wirings/channel/channel-runner.ts +6 -6
- package/src/wirings/channel/channel-store.ts +1 -1
- package/src/wirings/channel/channel.types.ts +4 -8
- package/src/wirings/channel/local/local-channel-runner.test.ts +19 -12
- package/src/wirings/channel/local/local-channel-runner.ts +18 -13
- package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
- package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
- package/src/wirings/channel/log-channels.ts +1 -1
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +1 -1
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +37 -32
- package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
- package/src/wirings/cli/cli-runner.test.ts +1 -1
- package/src/wirings/cli/cli-runner.ts +11 -4
- package/src/wirings/cli/cli.types.ts +3 -3
- package/src/wirings/cli/command-parser.test.ts +1 -1
- package/src/wirings/cli/command-parser.ts +1 -1
- package/src/wirings/http/http-routes.test.ts +1 -1
- package/src/wirings/http/http-runner.test.ts +9 -17
- package/src/wirings/http/http-runner.ts +43 -27
- package/src/wirings/http/http.types.ts +1 -14
- package/src/wirings/http/log-http-routes.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
- package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
- package/src/wirings/http/routers/http-router.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
- package/src/wirings/http/routers/path-to-regex.ts +4 -3
- package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
- package/src/wirings/mcp/mcp-runner.ts +9 -15
- package/src/wirings/mcp/mcp.types.ts +2 -2
- package/src/wirings/oauth2/oauth2-client.ts +3 -3
- package/src/wirings/oauth2/wire-oauth2-credential.ts +1 -1
- package/src/wirings/queue/index.ts +0 -1
- package/src/wirings/queue/queue-runner.test.ts +52 -25
- package/src/wirings/queue/queue-runner.ts +8 -30
- package/src/wirings/queue/queue.types.ts +3 -13
- package/src/wirings/queue/register-queue-helper.ts +3 -5
- package/src/wirings/queue/validate-worker-config.test.ts +108 -0
- package/src/wirings/queue/validate-worker-config.ts +4 -1
- package/src/wirings/rpc/index.ts +2 -0
- package/src/wirings/rpc/rpc-runner.ts +92 -49
- package/src/wirings/rpc/rpc-types.ts +17 -2
- package/src/wirings/rpc/wire-addon.ts +20 -0
- package/src/wirings/scheduler/index.ts +0 -1
- package/src/wirings/scheduler/log-schedulers.ts +1 -1
- package/src/wirings/scheduler/scheduler-runner.test.ts +49 -60
- package/src/wirings/scheduler/scheduler-runner.ts +9 -56
- package/src/wirings/scheduler/scheduler.types.ts +2 -2
- package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
- package/src/wirings/trigger/pikku-trigger-service.ts +17 -39
- package/src/wirings/trigger/trigger-runner.test.ts +79 -0
- package/src/wirings/trigger/trigger-runner.ts +8 -11
- package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +14 -22
- package/src/wirings/workflow/graph/template.test.ts +49 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +15 -27
- package/src/wirings/workflow/pikku-workflow-service.ts +29 -45
- package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
- package/src/wirings/workflow/workflow.types.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/wirings/workflow/workflow-utils.d.ts +0 -1
- package/dist/wirings/workflow/workflow-utils.js +0 -1
- package/src/wirings/workflow/workflow-utils.ts +0 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, test } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import {
|
|
4
|
+
agent,
|
|
5
|
+
agentStream,
|
|
6
|
+
agentResume,
|
|
7
|
+
agentApprove,
|
|
8
|
+
} from './ai-agent-helpers.js'
|
|
9
|
+
|
|
10
|
+
describe('agent helpers', () => {
|
|
11
|
+
describe('agent', () => {
|
|
12
|
+
test('should return an object with func', () => {
|
|
13
|
+
const a = agent('myAgent')
|
|
14
|
+
assert.strictEqual(typeof a.func, 'function')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('func should call rpc.agent.run', async () => {
|
|
18
|
+
const a = agent('myAgent')
|
|
19
|
+
let calledWith: any
|
|
20
|
+
const rpc = {
|
|
21
|
+
agent: {
|
|
22
|
+
run: async (...args: any[]) => {
|
|
23
|
+
calledWith = args
|
|
24
|
+
return {
|
|
25
|
+
runId: 'run-1',
|
|
26
|
+
result: 'done',
|
|
27
|
+
usage: { inputTokens: 10, outputTokens: 20 },
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
}
|
|
32
|
+
const input = { message: 'hello', threadId: 't1', resourceId: 'r1' }
|
|
33
|
+
const result = await a.func({}, input, { rpc })
|
|
34
|
+
assert.strictEqual(calledWith[0], 'myAgent')
|
|
35
|
+
assert.deepStrictEqual(calledWith[1], input)
|
|
36
|
+
assert.strictEqual(result.runId, 'run-1')
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('agentStream', () => {
|
|
41
|
+
test('should return an object with func', () => {
|
|
42
|
+
const a = agentStream('myAgent')
|
|
43
|
+
assert.strictEqual(typeof a.func, 'function')
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('func should call rpc.agent.stream with bound name', async () => {
|
|
47
|
+
const a = agentStream('myAgent')
|
|
48
|
+
let calledWith: any
|
|
49
|
+
const rpc = {
|
|
50
|
+
agent: {
|
|
51
|
+
stream: async (...args: any[]) => {
|
|
52
|
+
calledWith = args
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
const input = { message: 'hello', threadId: 't1', resourceId: 'r1' }
|
|
57
|
+
await a.func({}, input, { rpc })
|
|
58
|
+
assert.strictEqual(calledWith[0], 'myAgent')
|
|
59
|
+
assert.deepStrictEqual(calledWith[1], input)
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
test('func should extract agentName from data when no name bound', async () => {
|
|
63
|
+
const a = agentStream()
|
|
64
|
+
let calledWith: any
|
|
65
|
+
const rpc = {
|
|
66
|
+
agent: {
|
|
67
|
+
stream: async (...args: any[]) => {
|
|
68
|
+
calledWith = args
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
const input = {
|
|
73
|
+
agentName: 'dynamicAgent',
|
|
74
|
+
message: 'hello',
|
|
75
|
+
threadId: 't1',
|
|
76
|
+
resourceId: 'r1',
|
|
77
|
+
}
|
|
78
|
+
await a.func({}, input, { rpc })
|
|
79
|
+
assert.strictEqual(calledWith[0], 'dynamicAgent')
|
|
80
|
+
assert.deepStrictEqual(calledWith[1], {
|
|
81
|
+
message: 'hello',
|
|
82
|
+
threadId: 't1',
|
|
83
|
+
resourceId: 'r1',
|
|
84
|
+
})
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test('func should throw when no name bound and no agentName in data', async () => {
|
|
88
|
+
const a = agentStream()
|
|
89
|
+
const rpc = { agent: { stream: async () => {} } }
|
|
90
|
+
await assert.rejects(() => a.func({}, { message: 'hello' }, { rpc }), {
|
|
91
|
+
message:
|
|
92
|
+
'agentStream requires an agentName either as a parameter or in the input data',
|
|
93
|
+
})
|
|
94
|
+
})
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
describe('agentResume', () => {
|
|
98
|
+
test('should return an object with func', () => {
|
|
99
|
+
const a = agentResume()
|
|
100
|
+
assert.strictEqual(typeof a.func, 'function')
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
test('func should call rpc.agent.resume', async () => {
|
|
104
|
+
const a = agentResume()
|
|
105
|
+
let calledWith: any
|
|
106
|
+
const rpc = {
|
|
107
|
+
agent: {
|
|
108
|
+
resume: async (...args: any[]) => {
|
|
109
|
+
calledWith = args
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
}
|
|
113
|
+
const data = { runId: 'run-1', toolCallId: 'tc1', approved: true }
|
|
114
|
+
await a.func({}, data, { rpc })
|
|
115
|
+
assert.strictEqual(calledWith[0], 'run-1')
|
|
116
|
+
assert.deepStrictEqual(calledWith[1], {
|
|
117
|
+
toolCallId: 'tc1',
|
|
118
|
+
approved: true,
|
|
119
|
+
})
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
describe('agentApprove', () => {
|
|
124
|
+
test('should return an object with func', () => {
|
|
125
|
+
const a = agentApprove('myAgent')
|
|
126
|
+
assert.strictEqual(typeof a.func, 'function')
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
test('func should call rpc.agent.approve', async () => {
|
|
130
|
+
const a = agentApprove('myAgent')
|
|
131
|
+
let calledWith: any
|
|
132
|
+
const rpc = {
|
|
133
|
+
agent: {
|
|
134
|
+
approve: async (...args: any[]) => {
|
|
135
|
+
calledWith = args
|
|
136
|
+
return { approved: true }
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
}
|
|
140
|
+
const data = {
|
|
141
|
+
runId: 'run-1',
|
|
142
|
+
approvals: [{ toolCallId: 'tc1', approved: true }],
|
|
143
|
+
}
|
|
144
|
+
const result = await a.func({}, data, { rpc })
|
|
145
|
+
assert.strictEqual(calledWith[0], 'run-1')
|
|
146
|
+
assert.deepStrictEqual(calledWith[1], [
|
|
147
|
+
{ toolCallId: 'tc1', approved: true },
|
|
148
|
+
])
|
|
149
|
+
assert.deepStrictEqual(result, { approved: true })
|
|
150
|
+
})
|
|
151
|
+
})
|
|
152
|
+
})
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export function agent<TAgentMap extends Record<string, { output: any }>>(
|
|
2
|
+
agentName: string & keyof TAgentMap
|
|
3
|
+
): { func: (services: any, data: any, wire: any) => Promise<any> } {
|
|
4
|
+
return {
|
|
5
|
+
func: async (_services: any, data: any, { rpc }: any) => {
|
|
6
|
+
return rpc.agent.run(agentName, data)
|
|
7
|
+
},
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function agentStream<TAgentMap extends Record<string, { output: any }>>(
|
|
12
|
+
agentName?: string & keyof TAgentMap
|
|
13
|
+
): { func: (services: any, data: any, wire: any) => Promise<void> } {
|
|
14
|
+
return {
|
|
15
|
+
func: async (_services: any, data: any, { rpc }: any) => {
|
|
16
|
+
if (agentName) {
|
|
17
|
+
await rpc.agent.stream(agentName, data)
|
|
18
|
+
} else {
|
|
19
|
+
const { agentName: name, ...rest } = data
|
|
20
|
+
if (!name) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
'agentStream requires an agentName either as a parameter or in the input data'
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
await rpc.agent.stream(name, rest)
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function agentResume(): {
|
|
32
|
+
func: (
|
|
33
|
+
services: any,
|
|
34
|
+
data: { runId: string; toolCallId: string; approved: boolean },
|
|
35
|
+
wire: any
|
|
36
|
+
) => Promise<void>
|
|
37
|
+
} {
|
|
38
|
+
return {
|
|
39
|
+
func: async (
|
|
40
|
+
_services: any,
|
|
41
|
+
data: { runId: string; toolCallId: string; approved: boolean },
|
|
42
|
+
{ rpc }: any
|
|
43
|
+
) => {
|
|
44
|
+
await rpc.agent.resume(data.runId, {
|
|
45
|
+
toolCallId: data.toolCallId,
|
|
46
|
+
approved: data.approved,
|
|
47
|
+
})
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function agentApprove<TAgentMap extends Record<string, { output: any }>>(
|
|
53
|
+
_agentName: string & keyof TAgentMap
|
|
54
|
+
): {
|
|
55
|
+
func: (
|
|
56
|
+
services: any,
|
|
57
|
+
data: {
|
|
58
|
+
runId: string
|
|
59
|
+
approvals: { toolCallId: string; approved: boolean }[]
|
|
60
|
+
},
|
|
61
|
+
wire: any
|
|
62
|
+
) => Promise<any>
|
|
63
|
+
} {
|
|
64
|
+
return {
|
|
65
|
+
func: async (
|
|
66
|
+
_services: any,
|
|
67
|
+
data: {
|
|
68
|
+
runId: string
|
|
69
|
+
approvals: { toolCallId: string; approved: boolean }[]
|
|
70
|
+
},
|
|
71
|
+
{ rpc }: any
|
|
72
|
+
) => {
|
|
73
|
+
return rpc.agent.approve(data.runId, data.approvals)
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { describe, test, beforeEach } from 'node:test'
|
|
2
|
+
import assert from 'node:assert'
|
|
3
|
+
import { resolveModelConfig } from './ai-agent-model-config.js'
|
|
4
|
+
import { resetPikkuState, pikkuState } from '../../pikku-state.js'
|
|
5
|
+
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
resetPikkuState()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
describe('resolveModelConfig', () => {
|
|
11
|
+
test('should return agent model when no config', () => {
|
|
12
|
+
const result = resolveModelConfig('testAgent', {
|
|
13
|
+
model: 'anthropic/claude-3',
|
|
14
|
+
temperature: 0.7,
|
|
15
|
+
})
|
|
16
|
+
assert.strictEqual(result.model, 'anthropic/claude-3')
|
|
17
|
+
assert.strictEqual(result.temperature, 0.7)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('should resolve model alias to string', () => {
|
|
21
|
+
pikkuState(null, 'models', 'config', {
|
|
22
|
+
models: { fast: 'anthropic/claude-haiku' },
|
|
23
|
+
} as any)
|
|
24
|
+
|
|
25
|
+
const result = resolveModelConfig('testAgent', { model: 'fast' })
|
|
26
|
+
assert.strictEqual(result.model, 'anthropic/claude-haiku')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('should resolve model alias with temperature and maxSteps', () => {
|
|
30
|
+
pikkuState(null, 'models', 'config', {
|
|
31
|
+
models: {
|
|
32
|
+
smart: {
|
|
33
|
+
model: 'anthropic/claude-opus',
|
|
34
|
+
temperature: 0.3,
|
|
35
|
+
maxSteps: 10,
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
} as any)
|
|
39
|
+
|
|
40
|
+
const result = resolveModelConfig('testAgent', { model: 'smart' })
|
|
41
|
+
assert.strictEqual(result.model, 'anthropic/claude-opus')
|
|
42
|
+
assert.strictEqual(result.temperature, 0.3)
|
|
43
|
+
assert.strictEqual(result.maxSteps, 10)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
test('should throw for unknown model alias', () => {
|
|
47
|
+
pikkuState(null, 'models', 'config', {
|
|
48
|
+
models: {},
|
|
49
|
+
} as any)
|
|
50
|
+
|
|
51
|
+
assert.throws(() => resolveModelConfig('testAgent', { model: 'unknown' }), {
|
|
52
|
+
message: "Unknown model alias 'unknown'.",
|
|
53
|
+
})
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
test('should pass through model with slash (not an alias)', () => {
|
|
57
|
+
pikkuState(null, 'models', 'config', {
|
|
58
|
+
models: {},
|
|
59
|
+
} as any)
|
|
60
|
+
|
|
61
|
+
const result = resolveModelConfig('testAgent', { model: 'openai/gpt-4' })
|
|
62
|
+
assert.strictEqual(result.model, 'openai/gpt-4')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
test('should use agent override model', () => {
|
|
66
|
+
pikkuState(null, 'models', 'config', {
|
|
67
|
+
models: { fast: 'anthropic/haiku' },
|
|
68
|
+
agentOverrides: { testAgent: { model: 'fast' } },
|
|
69
|
+
} as any)
|
|
70
|
+
|
|
71
|
+
const result = resolveModelConfig('testAgent', {
|
|
72
|
+
model: 'anthropic/default',
|
|
73
|
+
})
|
|
74
|
+
assert.strictEqual(result.model, 'anthropic/haiku')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('should use agent override temperature over alias', () => {
|
|
78
|
+
pikkuState(null, 'models', 'config', {
|
|
79
|
+
models: { smart: { model: 'anthropic/opus', temperature: 0.5 } },
|
|
80
|
+
agentOverrides: { testAgent: { model: 'smart', temperature: 0.1 } },
|
|
81
|
+
} as any)
|
|
82
|
+
|
|
83
|
+
const result = resolveModelConfig('testAgent', {
|
|
84
|
+
model: 'anthropic/default',
|
|
85
|
+
})
|
|
86
|
+
assert.strictEqual(result.temperature, 0.1)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('should use agentDefaults as fallback', () => {
|
|
90
|
+
pikkuState(null, 'models', 'config', {
|
|
91
|
+
models: {},
|
|
92
|
+
agentDefaults: { temperature: 0.5, maxSteps: 20 },
|
|
93
|
+
} as any)
|
|
94
|
+
|
|
95
|
+
const result = resolveModelConfig('testAgent', {
|
|
96
|
+
model: 'anthropic/claude-3',
|
|
97
|
+
})
|
|
98
|
+
assert.strictEqual(result.temperature, 0.5)
|
|
99
|
+
assert.strictEqual(result.maxSteps, 20)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test('should prioritize: override > alias > defaults > agent', () => {
|
|
103
|
+
pikkuState(null, 'models', 'config', {
|
|
104
|
+
models: { fast: { model: 'anthropic/haiku', temperature: 0.3 } },
|
|
105
|
+
agentDefaults: { temperature: 0.5 },
|
|
106
|
+
agentOverrides: { testAgent: { temperature: 0.1 } },
|
|
107
|
+
} as any)
|
|
108
|
+
|
|
109
|
+
const result = resolveModelConfig('testAgent', {
|
|
110
|
+
model: 'fast',
|
|
111
|
+
temperature: 0.9,
|
|
112
|
+
})
|
|
113
|
+
assert.strictEqual(result.temperature, 0.1)
|
|
114
|
+
})
|
|
115
|
+
})
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
type CoreSingletonServices,
|
|
3
|
-
type CoreServices,
|
|
4
|
-
type CoreUserSession,
|
|
5
|
-
type CreateWireServices,
|
|
6
|
-
PikkuWire,
|
|
7
|
-
} from '../../types/core.types.js'
|
|
1
|
+
import type { PikkuWire, CoreUserSession } from '../../types/core.types.js'
|
|
8
2
|
import type {
|
|
9
3
|
CoreAIAgent,
|
|
10
4
|
AIAgentInput,
|
|
@@ -12,10 +6,15 @@ import type {
|
|
|
12
6
|
AIMessage,
|
|
13
7
|
AIStreamChannel,
|
|
14
8
|
AIStreamEvent,
|
|
9
|
+
PikkuAIMiddlewareHooks,
|
|
15
10
|
} from './ai-agent.types.js'
|
|
16
11
|
import type { AIAgentRunnerParams } from '../../services/ai-agent-runner-service.js'
|
|
17
12
|
import { PikkuError } from '../../errors/error-handler.js'
|
|
18
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
pikkuState,
|
|
15
|
+
getSingletonServices,
|
|
16
|
+
getCreateWireServices,
|
|
17
|
+
} from '../../pikku-state.js'
|
|
19
18
|
import { runPikkuFunc } from '../../function/function-runner.js'
|
|
20
19
|
import { createMiddlewareSessionWireProps } from '../../services/user-session-service.js'
|
|
21
20
|
import type { SessionService } from '../../services/user-session-service.js'
|
|
@@ -29,13 +28,7 @@ import {
|
|
|
29
28
|
import { resolveModelConfig } from './ai-agent-model-config.js'
|
|
30
29
|
|
|
31
30
|
export type RunAIAgentParams = {
|
|
32
|
-
singletonServices: CoreSingletonServices
|
|
33
31
|
sessionService?: SessionService<CoreUserSession>
|
|
34
|
-
createWireServices?: CreateWireServices<
|
|
35
|
-
CoreSingletonServices,
|
|
36
|
-
CoreServices<CoreSingletonServices>,
|
|
37
|
-
CoreUserSession
|
|
38
|
-
>
|
|
39
32
|
}
|
|
40
33
|
|
|
41
34
|
export type StreamAIAgentOptions = {
|
|
@@ -88,8 +81,8 @@ export const resolveAgent = (
|
|
|
88
81
|
if (colonIndex !== -1) {
|
|
89
82
|
const namespace = agentName.substring(0, colonIndex)
|
|
90
83
|
const localName = agentName.substring(colonIndex + 1)
|
|
91
|
-
const
|
|
92
|
-
const pkgConfig =
|
|
84
|
+
const addons = pikkuState(null, 'rpc', 'addons')
|
|
85
|
+
const pkgConfig = addons.get(namespace)
|
|
93
86
|
if (pkgConfig) {
|
|
94
87
|
const extAgent = pikkuState(pkgConfig.package, 'agent', 'agents').get(
|
|
95
88
|
localName
|
|
@@ -163,6 +156,7 @@ export function createScopedChannel(
|
|
|
163
156
|
return
|
|
164
157
|
}
|
|
165
158
|
if (
|
|
159
|
+
event.type === 'step-start' ||
|
|
166
160
|
event.type === 'text-delta' ||
|
|
167
161
|
event.type === 'reasoning-delta' ||
|
|
168
162
|
event.type === 'tool-call' ||
|
|
@@ -179,14 +173,15 @@ export function createScopedChannel(
|
|
|
179
173
|
}
|
|
180
174
|
|
|
181
175
|
export function buildToolDefs(
|
|
182
|
-
singletonServices: CoreSingletonServices,
|
|
183
176
|
params: RunAIAgentParams,
|
|
184
177
|
agentSessionMap: Map<string, string>,
|
|
185
178
|
resourceId: string,
|
|
186
179
|
agentName: string,
|
|
187
180
|
packageName: string | null,
|
|
188
|
-
streamContext?: StreamContext
|
|
181
|
+
streamContext?: StreamContext,
|
|
182
|
+
aiMiddlewares?: PikkuAIMiddlewareHooks[]
|
|
189
183
|
): { tools: AIAgentToolDef[]; missingRpcs: string[] } {
|
|
184
|
+
const singletonServices = getSingletonServices()
|
|
190
185
|
const tools: AIAgentToolDef[] = []
|
|
191
186
|
const missingRpcs: string[] = []
|
|
192
187
|
const approvalPolicy =
|
|
@@ -228,39 +223,18 @@ export function buildToolDefs(
|
|
|
228
223
|
approvalPolicy === 'all' ||
|
|
229
224
|
(approvalPolicy === 'explicit' && fnMeta?.requiresApproval)
|
|
230
225
|
|
|
231
|
-
if (needsApproval) {
|
|
232
|
-
inputSchema = {
|
|
233
|
-
...inputSchema,
|
|
234
|
-
properties: {
|
|
235
|
-
...((inputSchema.properties as Record<string, unknown>) || {}),
|
|
236
|
-
toolApprovalReason: {
|
|
237
|
-
type: 'string',
|
|
238
|
-
description: 'Brief explanation of why this action is needed',
|
|
239
|
-
},
|
|
240
|
-
},
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
226
|
tools.push({
|
|
245
227
|
name: pikkuFuncId,
|
|
246
228
|
description: fnMeta?.description || fnMeta?.title || toolName,
|
|
247
229
|
inputSchema,
|
|
230
|
+
needsApproval: needsApproval || undefined,
|
|
248
231
|
execute: async (toolInput: unknown) => {
|
|
249
|
-
if (needsApproval) {
|
|
250
|
-
const { toolApprovalReason, ...cleanArgs } = toolInput as any
|
|
251
|
-
return {
|
|
252
|
-
__approvalRequired: true,
|
|
253
|
-
toolName: pikkuFuncId,
|
|
254
|
-
args: cleanArgs,
|
|
255
|
-
reason: toolApprovalReason,
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
232
|
const wire: PikkuWire = params.sessionService
|
|
259
233
|
? { ...createMiddlewareSessionWireProps(params.sessionService) }
|
|
260
234
|
: {}
|
|
261
235
|
return runPikkuFunc('agent', `tool:${pikkuFuncId}`, pikkuFuncId, {
|
|
262
236
|
singletonServices,
|
|
263
|
-
createWireServices:
|
|
237
|
+
createWireServices: getCreateWireServices(),
|
|
264
238
|
data: () => toolInput,
|
|
265
239
|
wire,
|
|
266
240
|
sessionService: params.sessionService,
|
|
@@ -362,6 +336,62 @@ export function buildToolDefs(
|
|
|
362
336
|
}
|
|
363
337
|
}
|
|
364
338
|
|
|
339
|
+
const hasToolHooks = aiMiddlewares?.some(
|
|
340
|
+
(mw) => mw.beforeToolCall || mw.afterToolCall
|
|
341
|
+
)
|
|
342
|
+
if (hasToolHooks) {
|
|
343
|
+
for (const tool of tools) {
|
|
344
|
+
const originalExecute = tool.execute
|
|
345
|
+
tool.execute = async (toolInput: unknown) => {
|
|
346
|
+
const toolCallId = randomUUID()
|
|
347
|
+
let args = (toolInput ?? {}) as Record<string, unknown>
|
|
348
|
+
|
|
349
|
+
for (const mw of aiMiddlewares!) {
|
|
350
|
+
if (mw.beforeToolCall) {
|
|
351
|
+
const beforeResult = await mw.beforeToolCall(singletonServices, {
|
|
352
|
+
toolName: tool.name,
|
|
353
|
+
toolCallId,
|
|
354
|
+
args,
|
|
355
|
+
})
|
|
356
|
+
if (beforeResult && 'args' in beforeResult) {
|
|
357
|
+
args = beforeResult.args
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const startTime = Date.now()
|
|
363
|
+
let result: unknown
|
|
364
|
+
let execError: unknown
|
|
365
|
+
try {
|
|
366
|
+
result = await originalExecute(args)
|
|
367
|
+
} catch (err) {
|
|
368
|
+
execError = err
|
|
369
|
+
result = err instanceof Error ? err.message : String(err)
|
|
370
|
+
}
|
|
371
|
+
const durationMs = Date.now() - startTime
|
|
372
|
+
|
|
373
|
+
for (let i = aiMiddlewares!.length - 1; i >= 0; i--) {
|
|
374
|
+
const mw = aiMiddlewares![i]
|
|
375
|
+
if (mw.afterToolCall) {
|
|
376
|
+
const afterResult = await mw.afterToolCall(singletonServices, {
|
|
377
|
+
toolName: tool.name,
|
|
378
|
+
toolCallId,
|
|
379
|
+
args,
|
|
380
|
+
result,
|
|
381
|
+
durationMs,
|
|
382
|
+
})
|
|
383
|
+
if (afterResult && 'result' in afterResult) {
|
|
384
|
+
result = afterResult.result
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (execError) throw execError
|
|
390
|
+
return result
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
365
395
|
return { tools, missingRpcs }
|
|
366
396
|
}
|
|
367
397
|
|
|
@@ -372,7 +402,7 @@ export async function prepareAgentRun(
|
|
|
372
402
|
agentSessionMap: Map<string, string>,
|
|
373
403
|
streamContext?: StreamContext
|
|
374
404
|
) {
|
|
375
|
-
const
|
|
405
|
+
const singletonServices = getSingletonServices()
|
|
376
406
|
const { agent, packageName, resolvedName } = resolveAgent(agentName)
|
|
377
407
|
|
|
378
408
|
const agentRunner = singletonServices.aiAgentRunner
|
|
@@ -428,19 +458,22 @@ export async function prepareAgentRun(
|
|
|
428
458
|
const allMessages = [...contextMessages, ...messages, userMessage]
|
|
429
459
|
const trimmedMessages = trimMessages(allMessages)
|
|
430
460
|
|
|
461
|
+
const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
|
|
462
|
+
|
|
431
463
|
const { tools, missingRpcs } = buildToolDefs(
|
|
432
|
-
singletonServices,
|
|
433
464
|
params,
|
|
434
465
|
agentSessionMap,
|
|
435
466
|
input.resourceId,
|
|
436
467
|
resolvedName,
|
|
437
468
|
packageName,
|
|
438
|
-
streamContext
|
|
469
|
+
streamContext,
|
|
470
|
+
aiMiddlewares
|
|
439
471
|
)
|
|
440
472
|
|
|
441
473
|
const instructions = buildInstructions(resolvedName, packageName)
|
|
442
474
|
|
|
443
475
|
const resolved = resolveModelConfig(resolvedName, agent)
|
|
476
|
+
const maxSteps = resolved.maxSteps ?? 10
|
|
444
477
|
|
|
445
478
|
const runnerParams: AIAgentRunnerParams = {
|
|
446
479
|
model: resolved.model,
|
|
@@ -448,7 +481,7 @@ export async function prepareAgentRun(
|
|
|
448
481
|
instructions,
|
|
449
482
|
messages: trimmedMessages,
|
|
450
483
|
tools,
|
|
451
|
-
maxSteps:
|
|
484
|
+
maxSteps: 1,
|
|
452
485
|
toolChoice: agent.toolChoice ?? 'auto',
|
|
453
486
|
outputSchema,
|
|
454
487
|
}
|
|
@@ -463,6 +496,7 @@ export async function prepareAgentRun(
|
|
|
463
496
|
threadId,
|
|
464
497
|
userMessage,
|
|
465
498
|
runnerParams,
|
|
499
|
+
maxSteps,
|
|
466
500
|
missingRpcs,
|
|
467
501
|
workingMemoryJsonSchema,
|
|
468
502
|
workingMemorySchemaName,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CoreAIAgent, AgentRunState } from './ai-agent.types.js'
|
|
2
2
|
import { pikkuState } from '../../pikku-state.js'
|
|
3
|
-
import { AIRunStateService } from '../../services/ai-run-state-service.js'
|
|
3
|
+
import type { AIRunStateService } from '../../services/ai-run-state-service.js'
|
|
4
4
|
import { PikkuMissingMetaError } from '../../errors/errors.js'
|
|
5
5
|
|
|
6
6
|
export const addAIAgent = (
|