@pikku/core 0.12.22 → 0.12.24
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 +22 -0
- package/dist/function/function-runner.js +62 -15
- package/dist/function/functions.types.d.ts +8 -5
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1 -0
- package/dist/middleware-runner.d.ts +2 -2
- package/dist/permissions.d.ts +1 -1
- package/dist/services/ai-agent-runner-service.d.ts +6 -0
- package/dist/services/audit-service.d.ts +50 -0
- package/dist/services/audit-service.js +106 -0
- package/dist/services/content-service.d.ts +1 -0
- package/dist/services/email-service.d.ts +36 -0
- package/dist/services/email-service.js +1 -0
- package/dist/services/index.d.ts +5 -1
- package/dist/services/index.js +2 -0
- package/dist/services/local-content.js +1 -0
- package/dist/services/local-email-service.d.ts +4 -0
- package/dist/services/local-email-service.js +26 -0
- package/dist/services/local-secrets.d.ts +1 -0
- package/dist/services/local-secrets.js +11 -2
- package/dist/services/meta-service.d.ts +36 -0
- package/dist/services/meta-service.js +59 -0
- package/dist/types/core.types.d.ts +15 -1
- package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +2 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.js +8 -2
- package/dist/wirings/ai-agent/ai-agent-runner.js +3 -1
- package/dist/wirings/ai-agent/ai-agent-stream.js +2 -1
- package/dist/wirings/ai-agent/ai-agent-utils.d.ts +1 -0
- package/dist/wirings/ai-agent/ai-agent-utils.js +1 -0
- package/dist/wirings/rpc/rpc-runner.js +9 -2
- package/package.json +1 -1
- package/src/function/function-runner.test.ts +255 -0
- package/src/function/function-runner.ts +66 -20
- package/src/function/functions.types.ts +26 -11
- package/src/index.ts +35 -0
- package/src/middleware-runner.ts +10 -10
- package/src/permissions.ts +4 -4
- package/src/services/ai-agent-runner-service.ts +6 -0
- package/src/services/audit-service.test.ts +44 -0
- package/src/services/audit-service.ts +198 -0
- package/src/services/content-service.ts +1 -0
- package/src/services/email-service.ts +46 -0
- package/src/services/index.ts +33 -0
- package/src/services/local-content.ts +1 -0
- package/src/services/local-email-service.test.ts +108 -0
- package/src/services/local-email-service.ts +30 -0
- package/src/services/local-secrets.ts +11 -2
- package/src/services/meta-service.ts +115 -0
- package/src/types/core.types.ts +20 -2
- package/src/wirings/ai-agent/ai-agent-prepare.ts +11 -2
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +105 -0
- package/src/wirings/ai-agent/ai-agent-runner.ts +4 -1
- package/src/wirings/ai-agent/ai-agent-stream.ts +3 -1
- package/src/wirings/ai-agent/ai-agent-utils.ts +1 -0
- package/src/wirings/rpc/rpc-runner.ts +9 -2
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 0.12.24
|
|
2
|
+
|
|
3
|
+
### Patch Changes
|
|
4
|
+
|
|
5
|
+
- c02275f: Add per-request API key override to AI agent runner
|
|
6
|
+
|
|
7
|
+
`VercelAIAgentRunner` gains an optional `providerFactory` constructor param and a `withApiKey(apiKey)` method that forks a new runner scoped to a given key without touching the global singleton.
|
|
8
|
+
|
|
9
|
+
`RunAIAgentParams` gains an optional `getCredential` accessor so callers can thread per-request credentials (e.g. a user's `AI_API_KEY` from the credential wire service) into `prepareAgentRun`. If a credential is found and the runner supports `withApiKey`, the runner is forked before the agent executes.
|
|
10
|
+
|
|
11
|
+
`AIAgentRunnerService` interface gains the optional `withApiKey?` method.
|
|
12
|
+
|
|
13
|
+
- 0bd0433: Add `db.engine` and `db.pgVersion` to the CLI config types, and make local env-backed secrets fall back to raw strings when JSON parsing fails.
|
|
14
|
+
|
|
15
|
+
## 0.12.23
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 8d09f12: Forward pikkuAgent function name to LiteLLM as request metadata for per-agent usage breakdown.
|
|
20
|
+
|
|
21
|
+
Adds an optional `agentId` field to `AIAgentRunnerParams`. The wiring layer (`runAIAgent`, `streamAIAgent`, and the resume path) sets this to the agent's registered function name before invoking the runner. `VercelAIAgentRunner` injects it into `providerOptions` as `metadata.agent_id` so LiteLLM includes it in spend logs, enabling per-agent token and cost breakdowns.
|
|
22
|
+
|
|
1
23
|
## 0.12.22
|
|
2
24
|
|
|
3
25
|
### Patch Changes
|
|
@@ -8,6 +8,7 @@ import { PikkuSessionService, createFunctionSessionWireProps, } from '../service
|
|
|
8
8
|
import { ForbiddenError, ReadonlySessionError } from '../errors/errors.js';
|
|
9
9
|
import { PikkuCredentialWireService, createWireServicesCredentialWireProps, } from '../services/credential-wire-service.js';
|
|
10
10
|
import { defaultPikkuUserIdResolver } from '../services/pikku-user-id.js';
|
|
11
|
+
import { resolveAuditConfig } from '../services/audit-service.js';
|
|
11
12
|
import { rpcService } from '../wirings/rpc/rpc-runner.js';
|
|
12
13
|
import { closeWireServices } from '../utils.js';
|
|
13
14
|
async function resolveSession(wire, singletonServices, sessionService) {
|
|
@@ -165,6 +166,7 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
165
166
|
if (!funcMeta) {
|
|
166
167
|
throw new Error(`Function meta not found: ${funcName}`);
|
|
167
168
|
}
|
|
169
|
+
const resolvedFunctionId = funcMeta.pikkuFuncId ?? funcName;
|
|
168
170
|
// For addon packages, get or create their singleton services
|
|
169
171
|
const resolvedSingletonServices = packageName
|
|
170
172
|
? await getOrCreatePackageSingletonServices(packageName, singletonServices)
|
|
@@ -192,6 +194,13 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
192
194
|
new PikkuCredentialWireService(resolvedSingletonServices.credentialService, resolvedWire);
|
|
193
195
|
Object.assign(resolvedWire, createWireServicesCredentialWireProps(resolvedCredentialWireService));
|
|
194
196
|
}
|
|
197
|
+
const resolvedAuditConfig = resolveAuditConfig(funcConfig.audit);
|
|
198
|
+
const invocationWire = resolvedWire;
|
|
199
|
+
const previousFunctionId = invocationWire.functionId;
|
|
200
|
+
const previousAudit = invocationWire.audit;
|
|
201
|
+
const previousRpcDescriptor = Object.getOwnPropertyDescriptor(invocationWire, 'rpc');
|
|
202
|
+
invocationWire.functionId = resolvedFunctionId;
|
|
203
|
+
invocationWire.audit = resolvedAuditConfig;
|
|
195
204
|
// Convert tags to PermissionMetadata and merge with inheritedPermissions
|
|
196
205
|
let mergedInheritedPermissions;
|
|
197
206
|
if (tags && tags.length > 0) {
|
|
@@ -205,15 +214,15 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
205
214
|
}
|
|
206
215
|
// Helper function to run permissions and execute the function
|
|
207
216
|
const executeFunction = async () => {
|
|
208
|
-
await resolveSession(
|
|
217
|
+
await resolveSession(invocationWire, resolvedSingletonServices, sessionService);
|
|
209
218
|
if (sessionService) {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
219
|
+
invocationWire.session = sessionService.freezeInitial();
|
|
220
|
+
invocationWire.setSession = (s) => sessionService.set(s);
|
|
221
|
+
invocationWire.clearSession = () => sessionService.clear();
|
|
222
|
+
invocationWire.getSession = () => sessionService.get();
|
|
223
|
+
invocationWire.hasSessionChanged = () => sessionService.sessionChanged;
|
|
215
224
|
}
|
|
216
|
-
const session =
|
|
225
|
+
const session = invocationWire.session;
|
|
217
226
|
if (funcMeta.sessionless) {
|
|
218
227
|
if (wiringAuth === true || funcConfig.auth === true) {
|
|
219
228
|
if (!session) {
|
|
@@ -263,22 +272,22 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
263
272
|
funcInheritedPermissions: funcMeta.permissions,
|
|
264
273
|
funcPermissions: funcConfig.permissions,
|
|
265
274
|
services: resolvedSingletonServices,
|
|
266
|
-
wire:
|
|
275
|
+
wire: invocationWire,
|
|
267
276
|
data: actualData,
|
|
268
277
|
packageName,
|
|
269
278
|
});
|
|
270
279
|
}
|
|
271
280
|
let wireServices;
|
|
272
281
|
try {
|
|
273
|
-
wireServices = (await resolvedCreateWireServices?.(resolvedSingletonServices,
|
|
282
|
+
wireServices = (await resolvedCreateWireServices?.(resolvedSingletonServices, invocationWire));
|
|
274
283
|
const services = wireServices && Object.keys(wireServices).length > 0
|
|
275
284
|
? { ...resolvedSingletonServices, ...wireServices }
|
|
276
285
|
: resolvedSingletonServices;
|
|
277
286
|
const callerPackageName = packageName;
|
|
278
|
-
Object.defineProperty(
|
|
287
|
+
Object.defineProperty(invocationWire, 'rpc', {
|
|
279
288
|
get() {
|
|
280
|
-
const rpc = rpcService.getContextRPCService(services,
|
|
281
|
-
Object.defineProperty(
|
|
289
|
+
const rpc = rpcService.getContextRPCService(services, invocationWire, { sessionService }, 0, callerPackageName);
|
|
290
|
+
Object.defineProperty(invocationWire, 'rpc', {
|
|
282
291
|
value: rpc,
|
|
283
292
|
writable: true,
|
|
284
293
|
configurable: true,
|
|
@@ -288,7 +297,7 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
288
297
|
configurable: true,
|
|
289
298
|
enumerable: true,
|
|
290
299
|
});
|
|
291
|
-
return await funcConfig.func(services, actualData,
|
|
300
|
+
return await funcConfig.func(services, actualData, invocationWire);
|
|
292
301
|
}
|
|
293
302
|
finally {
|
|
294
303
|
if (wireServices && Object.keys(wireServices).length > 0) {
|
|
@@ -304,7 +313,45 @@ export const runPikkuFunc = async (wireType, wireId, funcName, { singletonServic
|
|
|
304
313
|
packageName,
|
|
305
314
|
});
|
|
306
315
|
if (allMiddleware.length > 0) {
|
|
307
|
-
|
|
316
|
+
try {
|
|
317
|
+
return (await runMiddleware(resolvedSingletonServices, invocationWire, allMiddleware, executeFunction));
|
|
318
|
+
}
|
|
319
|
+
finally {
|
|
320
|
+
if (previousRpcDescriptor) {
|
|
321
|
+
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor);
|
|
322
|
+
}
|
|
323
|
+
if (previousFunctionId === undefined) {
|
|
324
|
+
delete invocationWire.functionId;
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
invocationWire.functionId = previousFunctionId;
|
|
328
|
+
}
|
|
329
|
+
if (previousAudit === undefined) {
|
|
330
|
+
delete invocationWire.audit;
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
invocationWire.audit = previousAudit;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
return (await executeFunction());
|
|
339
|
+
}
|
|
340
|
+
finally {
|
|
341
|
+
if (previousRpcDescriptor) {
|
|
342
|
+
Object.defineProperty(invocationWire, 'rpc', previousRpcDescriptor);
|
|
343
|
+
}
|
|
344
|
+
if (previousFunctionId === undefined) {
|
|
345
|
+
delete invocationWire.functionId;
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
invocationWire.functionId = previousFunctionId;
|
|
349
|
+
}
|
|
350
|
+
if (previousAudit === undefined) {
|
|
351
|
+
delete invocationWire.audit;
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
invocationWire.audit = previousAudit;
|
|
355
|
+
}
|
|
308
356
|
}
|
|
309
|
-
return (await executeFunction());
|
|
310
357
|
};
|
|
@@ -15,7 +15,7 @@ export type ZodLike<T = any> = StandardSchemaV1<T, T>;
|
|
|
15
15
|
* @template Services - The services type, defaults to `CoreServices`.
|
|
16
16
|
* @template Wire - The wire type, defaults to `PikkuWire<In, Out>`.
|
|
17
17
|
*/
|
|
18
|
-
export type CorePikkuFunction<In, Out, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession, Wire extends PikkuWire<In, Out> = PikkuWire<In, Out, true, Session>> = (services: Services, data: In, wire: Wire) => Wire['channel'] extends null ? Promise<Out> : Promise<Out> | Promise<void>;
|
|
18
|
+
export type CorePikkuFunction<In, Out, Services extends CoreSingletonServices = CoreServices, Session extends CoreUserSession = CoreUserSession, Wire extends PikkuWire<In, Out, true, Session> = PikkuWire<In, Out, true, Session>> = (services: Services, data: In, wire: Wire) => Wire['channel'] extends null ? Promise<Out> : Promise<Out> | Promise<void>;
|
|
19
19
|
/**
|
|
20
20
|
* Represents a core API function that can be used without a session.
|
|
21
21
|
*
|
|
@@ -32,7 +32,7 @@ export type CorePikkuFunctionSessionless<In, Out, Services extends CoreSingleton
|
|
|
32
32
|
* @template Services - The services type, defaults to `CoreServices`.
|
|
33
33
|
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
34
34
|
*/
|
|
35
|
-
export type CorePikkuPermission<In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PikkuWire<In, never, false,
|
|
35
|
+
export type CorePikkuPermission<In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PikkuWire<In, never, false, any, any, never, never> = PikkuWire<In, never, false, any, never, never, never>> = (services: Services, data: In, wire: Wire) => Promise<boolean>;
|
|
36
36
|
/**
|
|
37
37
|
* Configuration object for creating a permission with metadata
|
|
38
38
|
*
|
|
@@ -40,7 +40,7 @@ export type CorePikkuPermission<In = any, Services extends CoreSingletonServices
|
|
|
40
40
|
* @template Services - The services type, defaults to `CoreServices`.
|
|
41
41
|
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
42
42
|
*/
|
|
43
|
-
export type CorePikkuPermissionConfig<In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PikkuWire<In, never, false,
|
|
43
|
+
export type CorePikkuPermissionConfig<In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PikkuWire<In, never, false, any> = PikkuWire<In, never, false, any>> = {
|
|
44
44
|
/** The permission function */
|
|
45
45
|
func: CorePikkuPermission<In, Services, Wire>;
|
|
46
46
|
/** Optional human-readable name for the permission */
|
|
@@ -73,7 +73,7 @@ export type CorePikkuPermissionConfig<In = any, Services extends CoreSingletonSe
|
|
|
73
73
|
* })
|
|
74
74
|
* ```
|
|
75
75
|
*/
|
|
76
|
-
export declare const pikkuPermission: <In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PickRequired<PikkuWire<In, never, false,
|
|
76
|
+
export declare const pikkuPermission: <In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PickRequired<PikkuWire<In, never, false, any>, "session"> = PickRequired<PikkuWire<In, never, false, any>, "session">>(permission: CorePikkuPermission<In, Services, Wire> | CorePikkuPermissionConfig<In, Services, Wire>) => CorePikkuPermission<In, Services, Wire>;
|
|
77
77
|
/**
|
|
78
78
|
* A factory function that takes input and returns a permission
|
|
79
79
|
* Used when permissions need configuration/input parameters
|
|
@@ -82,7 +82,7 @@ export declare const pikkuPermission: <In = any, Services extends CoreSingletonS
|
|
|
82
82
|
* @template Services - The services type, defaults to `CoreServices`.
|
|
83
83
|
* @template Session - The session type, defaults to `CoreUserSession`.
|
|
84
84
|
*/
|
|
85
|
-
export type CorePikkuPermissionFactory<In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PikkuWire<In, never, false,
|
|
85
|
+
export type CorePikkuPermissionFactory<In = any, Services extends CoreSingletonServices = CoreServices, Wire extends PikkuWire<In, never, false, any> = PikkuWire<In, never, false, any>> = (input: In) => CorePikkuPermission<any, Services, Wire>;
|
|
86
86
|
/**
|
|
87
87
|
* Factory function for creating permission factories
|
|
88
88
|
* Use this when your permission needs configuration/input parameters
|
|
@@ -149,6 +149,9 @@ export type CorePikkuFunctionConfig<PikkuFunction extends CorePikkuFunction<any,
|
|
|
149
149
|
readonly?: boolean;
|
|
150
150
|
deploy?: 'serverless' | 'server' | 'auto';
|
|
151
151
|
approvalRequired?: boolean;
|
|
152
|
+
audit?: boolean | {
|
|
153
|
+
durability?: 'best-effort' | 'transactional';
|
|
154
|
+
};
|
|
152
155
|
approvalDescription?: any;
|
|
153
156
|
func: PikkuFunction;
|
|
154
157
|
auth?: boolean;
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export { NotFoundError } from './errors/errors.js';
|
|
|
22
22
|
export type { EventHubService } from './wirings/channel/eventhub-service.js';
|
|
23
23
|
export type { QueueService } from './wirings/queue/queue.types.js';
|
|
24
24
|
export type { JWTService } from './services/jwt-service.js';
|
|
25
|
+
export type { EmailService, EmailTemplateReference, SendEmailInput, SendEmailResult, SendHTMLEmailInput, SendTemplateEmailInput, SendTextEmailInput, } from './services/email-service.js';
|
|
25
26
|
export type { SecretService } from './services/secret-service.js';
|
|
26
27
|
export type { VariablesService } from './services/variables-service.js';
|
|
27
28
|
export type { ContentService, SignContentKeyArgs, SignURLArgs, GetUploadURLArgs, UploadURLResult, BucketKeyArgs, WriteFileArgs, CopyFileArgs, } from './services/content-service.js';
|
|
@@ -31,9 +32,12 @@ export type { GatewayService } from './services/gateway-service.js';
|
|
|
31
32
|
export type { TriggerService } from './services/trigger-service.js';
|
|
32
33
|
export type { SchemaService } from './services/schema-service.js';
|
|
33
34
|
export type { SessionService } from './services/user-session-service.js';
|
|
35
|
+
export { NoopAuditService, createInvocationAudit, resolveAuditActorFromWire, resolveAuditConfig, } from './services/audit-service.js';
|
|
36
|
+
export type { AuditActor, AuditConfig, AuditDurability, AuditEvent, AuditEventBatch, AuditLog, AuditLogWriteInput, AuditOutcome, AuditService, AuditSource, ResolvedAuditConfig, } from './services/audit-service.js';
|
|
34
37
|
export type { AIAgentRunnerService } from './services/ai-agent-runner-service.js';
|
|
35
38
|
export type { AIRunStateService } from './services/ai-run-state-service.js';
|
|
36
39
|
export type { AIStorageService } from './services/ai-storage-service.js';
|
|
40
|
+
export type { EmailsMeta, EmailTemplateMeta, EmailTemplateLocaleMeta, EmailTemplateAssets, MetaService, } from './services/meta-service.js';
|
|
37
41
|
export type { HTTPMethod } from './wirings/http/http.types.js';
|
|
38
42
|
export type { GraphNodeConfig } from './wirings/workflow/graph/workflow-graph.types.js';
|
|
39
43
|
export { createGraph } from './wirings/workflow/graph/graph-node.js';
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export { runMCPTool, runMCPResource, runMCPPrompt, } from './wirings/mcp/mcp-run
|
|
|
11
11
|
export { runQueueJob } from './wirings/queue/queue-runner.js';
|
|
12
12
|
export { runScheduledTask } from './wirings/scheduler/scheduler-runner.js';
|
|
13
13
|
export { NotFoundError } from './errors/errors.js';
|
|
14
|
+
export { NoopAuditService, createInvocationAudit, resolveAuditActorFromWire, resolveAuditConfig, } from './services/audit-service.js';
|
|
14
15
|
export { createGraph } from './wirings/workflow/graph/graph-node.js';
|
|
15
16
|
export { wireAddon } from './wirings/rpc/wire-addon.js';
|
|
16
17
|
export { runMiddleware, addTagMiddleware, addTagMiddleware as addMiddleware, addGlobalMiddleware, } from './middleware-runner.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CorePikkuMiddleware, CorePikkuMiddlewareGroup, PikkuWiringTypes, MiddlewareMetadata } from './types/core.types.js';
|
|
2
2
|
/**
|
|
3
3
|
* Runs a chain of middleware functions in sequence before executing the main function.
|
|
4
4
|
*
|
|
@@ -16,7 +16,7 @@ import type { CoreSingletonServices, PikkuWire, CorePikkuMiddleware, CorePikkuMi
|
|
|
16
16
|
* async () => { return await runMain(); }
|
|
17
17
|
* );
|
|
18
18
|
*/
|
|
19
|
-
export declare const runMiddleware: <Middleware extends CorePikkuMiddleware
|
|
19
|
+
export declare const runMiddleware: <Middleware extends CorePikkuMiddleware<any, any>>(services: Parameters<Middleware>[0], wire: Parameters<Middleware>[1], middlewares: readonly Middleware[], main?: () => Promise<unknown>) => Promise<unknown>;
|
|
20
20
|
/**
|
|
21
21
|
* Registers tag-scoped middleware. Applies to any wiring (HTTP, Channel,
|
|
22
22
|
* Queue, Scheduler, MCP, CLI, Workflow, Agent) that carries the matching tag.
|
package/dist/permissions.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export declare const runPermissions: (wireType: PikkuWiringTypes, uid: string, {
|
|
|
33
33
|
funcInheritedPermissions?: PermissionMetadata[];
|
|
34
34
|
funcPermissions?: CorePermissionGroup | CorePikkuPermission[];
|
|
35
35
|
services: CoreServices;
|
|
36
|
-
wire: PikkuWire<any, never, any, never, never, never>;
|
|
36
|
+
wire: PikkuWire<any, never, any, CoreUserSession, never, never, never>;
|
|
37
37
|
data: any;
|
|
38
38
|
packageName?: string | null;
|
|
39
39
|
}) => Promise<void>;
|
|
@@ -8,6 +8,9 @@ export type AIAgentRunnerParams = {
|
|
|
8
8
|
maxSteps: number;
|
|
9
9
|
toolChoice: 'auto' | 'required' | 'none';
|
|
10
10
|
outputSchema?: Record<string, unknown>;
|
|
11
|
+
/** Pikku agent function name — forwarded to the LLM proxy (LiteLLM) as
|
|
12
|
+
* request-level metadata so usage can be broken down per agent. */
|
|
13
|
+
agentId?: string;
|
|
11
14
|
};
|
|
12
15
|
export type AIAgentRunnerResult = {
|
|
13
16
|
text: string;
|
|
@@ -41,4 +44,7 @@ export type AIAgentStepResult = {
|
|
|
41
44
|
export interface AIAgentRunnerService {
|
|
42
45
|
stream(params: AIAgentRunnerParams, channel: AIStreamChannel): Promise<AIAgentStepResult>;
|
|
43
46
|
run(params: AIAgentRunnerParams): Promise<AIAgentStepResult>;
|
|
47
|
+
/** Return a new runner that uses the given API key for every LLM call.
|
|
48
|
+
* Optional — runners that don't support per-key scoping leave this undefined. */
|
|
49
|
+
withApiKey?(apiKey: string): AIAgentRunnerService;
|
|
44
50
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { CoreUserSession, PikkuWire, PikkuWiringTypes } from '../types/core.types.js';
|
|
2
|
+
export type AuditDurability = 'best-effort' | 'transactional';
|
|
3
|
+
export type AuditOutcome = 'success' | 'failed' | 'denied';
|
|
4
|
+
export type AuditSource = 'auto' | 'explicit';
|
|
5
|
+
export type AuditConfig = boolean | {
|
|
6
|
+
durability?: AuditDurability;
|
|
7
|
+
};
|
|
8
|
+
export type ResolvedAuditConfig = {
|
|
9
|
+
durability: AuditDurability;
|
|
10
|
+
};
|
|
11
|
+
export type AuditActor = {
|
|
12
|
+
userId?: string;
|
|
13
|
+
orgId?: string;
|
|
14
|
+
pikkuUserId?: string;
|
|
15
|
+
};
|
|
16
|
+
export type AuditEvent = {
|
|
17
|
+
eventId?: string;
|
|
18
|
+
type: string;
|
|
19
|
+
source: AuditSource;
|
|
20
|
+
outcome?: AuditOutcome;
|
|
21
|
+
occurredAt: string;
|
|
22
|
+
functionId?: string;
|
|
23
|
+
wireType?: PikkuWiringTypes;
|
|
24
|
+
wireId?: string;
|
|
25
|
+
traceId?: string;
|
|
26
|
+
transactionId?: string | null;
|
|
27
|
+
queryId?: string | null;
|
|
28
|
+
actor?: AuditActor;
|
|
29
|
+
input?: unknown;
|
|
30
|
+
metadata?: Record<string, unknown>;
|
|
31
|
+
};
|
|
32
|
+
export type AuditEventBatch = AuditEvent[];
|
|
33
|
+
export interface AuditService {
|
|
34
|
+
audit(event: AuditEvent): Promise<void>;
|
|
35
|
+
write?(batch: AuditEventBatch): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export declare class NoopAuditService implements AuditService {
|
|
38
|
+
audit(_event: AuditEvent): Promise<void>;
|
|
39
|
+
write(_batch: AuditEventBatch): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export type AuditLogWriteInput = Omit<AuditEvent, 'occurredAt'>;
|
|
42
|
+
export interface AuditLog {
|
|
43
|
+
readonly config: ResolvedAuditConfig | undefined;
|
|
44
|
+
write(event: AuditLogWriteInput): Promise<void>;
|
|
45
|
+
flush(): Promise<void>;
|
|
46
|
+
close(): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
export declare const resolveAuditConfig: (config?: AuditConfig) => ResolvedAuditConfig | undefined;
|
|
49
|
+
export declare const createInvocationAudit: (service: AuditService, wire: PikkuWire<any, any, any, CoreUserSession>) => AuditLog;
|
|
50
|
+
export declare const resolveAuditActorFromWire: (wire: PikkuWire<any, any, any, CoreUserSession>) => AuditActor | undefined;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export class NoopAuditService {
|
|
2
|
+
async audit(_event) { }
|
|
3
|
+
async write(_batch) { }
|
|
4
|
+
}
|
|
5
|
+
class DisabledInvocationAudit {
|
|
6
|
+
wire;
|
|
7
|
+
config = undefined;
|
|
8
|
+
warned = false;
|
|
9
|
+
constructor(wire) {
|
|
10
|
+
this.wire = wire;
|
|
11
|
+
}
|
|
12
|
+
async write(_event) {
|
|
13
|
+
if (!this.warned) {
|
|
14
|
+
this.warned = true;
|
|
15
|
+
this.wire.logger?.warn?.('audit.write() called for an invocation without wire.audit enabled');
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async flush() { }
|
|
19
|
+
async close() { }
|
|
20
|
+
}
|
|
21
|
+
class InvocationAuditLog {
|
|
22
|
+
config;
|
|
23
|
+
service;
|
|
24
|
+
wire;
|
|
25
|
+
buffer = [];
|
|
26
|
+
constructor(config, service, wire) {
|
|
27
|
+
this.config = config;
|
|
28
|
+
this.service = service;
|
|
29
|
+
this.wire = wire;
|
|
30
|
+
}
|
|
31
|
+
async write(event) {
|
|
32
|
+
const resolved = this.resolveEvent(event);
|
|
33
|
+
if (this.config.durability === 'transactional') {
|
|
34
|
+
await this.service.audit(resolved);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.buffer.push(resolved);
|
|
38
|
+
}
|
|
39
|
+
async flush() {
|
|
40
|
+
if (this.config.durability === 'transactional' ||
|
|
41
|
+
this.buffer.length === 0) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const batch = this.buffer.splice(0, this.buffer.length);
|
|
45
|
+
const queryEvents = batch.filter((event) => event.queryId != null);
|
|
46
|
+
if (queryEvents.length === 1) {
|
|
47
|
+
queryEvents[0].queryId = null;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
if (this.service.write) {
|
|
51
|
+
await this.service.write(batch);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
for (const event of batch) {
|
|
55
|
+
await this.service.audit(event);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
;
|
|
60
|
+
this.wire.logger?.warn?.('best-effort audit flush failed', error);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async close() {
|
|
64
|
+
await this.flush();
|
|
65
|
+
}
|
|
66
|
+
resolveEvent(event) {
|
|
67
|
+
return {
|
|
68
|
+
functionId: this.wire.functionId,
|
|
69
|
+
wireType: this.wire.wireType,
|
|
70
|
+
wireId: this.wire.wireId,
|
|
71
|
+
traceId: this.wire.traceId,
|
|
72
|
+
actor: event.actor ?? resolveAuditActorFromWire(this.wire),
|
|
73
|
+
...event,
|
|
74
|
+
occurredAt: new Date().toISOString(),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
export const resolveAuditConfig = (config) => {
|
|
79
|
+
if (config === true) {
|
|
80
|
+
return { durability: 'best-effort' };
|
|
81
|
+
}
|
|
82
|
+
if (!config) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
durability: config.durability ?? 'best-effort',
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
export const createInvocationAudit = (service, wire) => {
|
|
90
|
+
if (!wire.audit) {
|
|
91
|
+
return new DisabledInvocationAudit(wire);
|
|
92
|
+
}
|
|
93
|
+
return new InvocationAuditLog(wire.audit, service, wire);
|
|
94
|
+
};
|
|
95
|
+
export const resolveAuditActorFromWire = (wire) => {
|
|
96
|
+
const session = wire.session;
|
|
97
|
+
const actor = {
|
|
98
|
+
userId: session?.userId,
|
|
99
|
+
orgId: session?.orgId,
|
|
100
|
+
pikkuUserId: wire.pikkuUserId,
|
|
101
|
+
};
|
|
102
|
+
if (!actor.userId && !actor.orgId && !actor.pikkuUserId) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
return actor;
|
|
106
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface EmailTemplateReference {
|
|
2
|
+
name: string;
|
|
3
|
+
locale?: string;
|
|
4
|
+
data?: Record<string, unknown>;
|
|
5
|
+
}
|
|
6
|
+
export interface BaseSendEmailInput {
|
|
7
|
+
to: string | string[];
|
|
8
|
+
from?: string;
|
|
9
|
+
cc?: string | string[];
|
|
10
|
+
bcc?: string | string[];
|
|
11
|
+
replyTo?: string | string[];
|
|
12
|
+
headers?: Record<string, string>;
|
|
13
|
+
subject?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface SendTextEmailInput extends BaseSendEmailInput {
|
|
16
|
+
text: string;
|
|
17
|
+
html?: never;
|
|
18
|
+
template?: never;
|
|
19
|
+
}
|
|
20
|
+
export interface SendHTMLEmailInput extends BaseSendEmailInput {
|
|
21
|
+
html: string;
|
|
22
|
+
text?: string;
|
|
23
|
+
template?: never;
|
|
24
|
+
}
|
|
25
|
+
export interface SendTemplateEmailInput extends BaseSendEmailInput {
|
|
26
|
+
template: EmailTemplateReference;
|
|
27
|
+
html?: never;
|
|
28
|
+
text?: never;
|
|
29
|
+
}
|
|
30
|
+
export type SendEmailInput = SendTextEmailInput | SendHTMLEmailInput | SendTemplateEmailInput;
|
|
31
|
+
export interface SendEmailResult {
|
|
32
|
+
messageId?: string;
|
|
33
|
+
}
|
|
34
|
+
export interface EmailService {
|
|
35
|
+
send(input: SendEmailInput): Promise<SendEmailResult>;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/services/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export { TypedSecretService } from './typed-secret-service.js';
|
|
|
8
8
|
export { PikkuCredentialWireService, createMiddlewareCredentialWireProps, createWireServicesCredentialWireProps, } from './credential-wire-service.js';
|
|
9
9
|
export { TypedVariablesService } from './typed-variables-service.js';
|
|
10
10
|
export { LocalSecretService } from './local-secrets.js';
|
|
11
|
+
export { LocalEmailService } from './local-email-service.js';
|
|
11
12
|
export { LocalCredentialService } from './local-credential-service.js';
|
|
12
13
|
export { LocalVariablesService } from './local-variables.js';
|
|
13
14
|
export { ConsoleLogger, JsonConsoleLogger } from './logger-console.js';
|
|
@@ -18,6 +19,7 @@ export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js';
|
|
|
18
19
|
export { LocalGatewayService } from './local-gateway-service.js';
|
|
19
20
|
export type { ContentService, SignContentKeyArgs, SignURLArgs, GetUploadURLArgs, UploadURLResult, BucketKeyArgs, WriteFileArgs, CopyFileArgs, } from './content-service.js';
|
|
20
21
|
export type { JWTService } from './jwt-service.js';
|
|
22
|
+
export type { EmailService, EmailTemplateReference, SendEmailInput, SendEmailResult, SendHTMLEmailInput, SendTemplateEmailInput, SendTextEmailInput, } from './email-service.js';
|
|
21
23
|
export type { Logger } from './logger.js';
|
|
22
24
|
export type { SecretService } from './secret-service.js';
|
|
23
25
|
export type { VariablesService } from './variables-service.js';
|
|
@@ -37,5 +39,7 @@ export type { CredentialStatusInfo, CredentialMetaInfo, } from './typed-credenti
|
|
|
37
39
|
export type { VariableStatus, VariableMeta } from './typed-variables-service.js';
|
|
38
40
|
export type { MetaService } from './meta-service.js';
|
|
39
41
|
export type { SessionStore } from './session-store.js';
|
|
42
|
+
export { NoopAuditService, createInvocationAudit, resolveAuditActorFromWire, resolveAuditConfig, } from './audit-service.js';
|
|
43
|
+
export type { AuditActor, AuditConfig, AuditDurability, AuditEvent, AuditEventBatch, AuditLog, AuditLogWriteInput, AuditOutcome, AuditService, AuditSource, ResolvedAuditConfig, } from './audit-service.js';
|
|
40
44
|
export { InMemorySessionStore } from './in-memory-session-store.js';
|
|
41
|
-
export type { MCPMeta, RPCMetaRecord, ServiceMeta, ServicesMetaRecord, MiddlewareDefinitionMeta, MiddlewareInstanceMeta, GroupMeta, MiddlewareGroupsMeta, PermissionDefinitionMeta, PermissionsGroupsMeta, FunctionsMeta, FunctionMeta, MiddlewareMeta, PermissionMeta, AgentsMeta, AgentMeta, } from './meta-service.js';
|
|
45
|
+
export type { MCPMeta, RPCMetaRecord, ServiceMeta, ServicesMetaRecord, MiddlewareDefinitionMeta, MiddlewareInstanceMeta, GroupMeta, MiddlewareGroupsMeta, PermissionDefinitionMeta, PermissionsGroupsMeta, FunctionsMeta, FunctionMeta, MiddlewareMeta, PermissionMeta, AgentsMeta, AgentMeta, EmailsMeta, EmailTemplateMeta, EmailTemplateLocaleMeta, EmailTemplateAssets, } from './meta-service.js';
|
package/dist/services/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export { TypedSecretService } from './typed-secret-service.js';
|
|
|
8
8
|
export { PikkuCredentialWireService, createMiddlewareCredentialWireProps, createWireServicesCredentialWireProps, } from './credential-wire-service.js';
|
|
9
9
|
export { TypedVariablesService } from './typed-variables-service.js';
|
|
10
10
|
export { LocalSecretService } from './local-secrets.js';
|
|
11
|
+
export { LocalEmailService } from './local-email-service.js';
|
|
11
12
|
export { LocalCredentialService } from './local-credential-service.js';
|
|
12
13
|
export { LocalVariablesService } from './local-variables.js';
|
|
13
14
|
export { ConsoleLogger, JsonConsoleLogger } from './logger-console.js';
|
|
@@ -17,4 +18,5 @@ export { InMemoryTriggerService } from './in-memory-trigger-service.js';
|
|
|
17
18
|
export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js';
|
|
18
19
|
export { LocalGatewayService } from './local-gateway-service.js';
|
|
19
20
|
export { TypedCredentialService } from './typed-credential-service.js';
|
|
21
|
+
export { NoopAuditService, createInvocationAudit, resolveAuditActorFromWire, resolveAuditConfig, } from './audit-service.js';
|
|
20
22
|
export { InMemorySessionStore } from './in-memory-session-store.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export class LocalEmailService {
|
|
2
|
+
async send(input) {
|
|
3
|
+
const payload = {
|
|
4
|
+
type: 'email',
|
|
5
|
+
message: 'this email was sent',
|
|
6
|
+
to: input.to,
|
|
7
|
+
from: input.from ?? null,
|
|
8
|
+
cc: input.cc ?? null,
|
|
9
|
+
bcc: input.bcc ?? null,
|
|
10
|
+
replyTo: input.replyTo ?? null,
|
|
11
|
+
subject: input.subject ?? null,
|
|
12
|
+
};
|
|
13
|
+
if ('template' in input && input.template) {
|
|
14
|
+
payload.template = input.template;
|
|
15
|
+
}
|
|
16
|
+
if ('html' in input && typeof input.html === 'string') {
|
|
17
|
+
payload.htmlLength = input.html.length;
|
|
18
|
+
payload.textLength = input.text?.length ?? null;
|
|
19
|
+
}
|
|
20
|
+
if ('text' in input && typeof input.text === 'string') {
|
|
21
|
+
payload.textLength = input.text.length;
|
|
22
|
+
}
|
|
23
|
+
console.info(JSON.stringify(payload));
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -6,6 +6,15 @@ import { LocalVariablesService } from './local-variables.js';
|
|
|
6
6
|
export class LocalSecretService {
|
|
7
7
|
variables;
|
|
8
8
|
localSecrets = new Map();
|
|
9
|
+
// TODO: Drop this fallback once secrets and variables expose aligned typed/raw access paths again.
|
|
10
|
+
parseSecret(raw) {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(raw);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return raw;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
9
18
|
/**
|
|
10
19
|
* Creates an instance of LocalSecretService.
|
|
11
20
|
*/
|
|
@@ -23,12 +32,12 @@ export class LocalSecretService {
|
|
|
23
32
|
// Check local storage first
|
|
24
33
|
const localValue = this.localSecrets.get(key);
|
|
25
34
|
if (localValue) {
|
|
26
|
-
return
|
|
35
|
+
return this.parseSecret(localValue);
|
|
27
36
|
}
|
|
28
37
|
// Fall back to environment variables
|
|
29
38
|
const value = await this.variables.get(key);
|
|
30
39
|
if (value) {
|
|
31
|
-
return
|
|
40
|
+
return this.parseSecret(value);
|
|
32
41
|
}
|
|
33
42
|
throw new Error('Requested secret not found');
|
|
34
43
|
}
|