@pikku/core 0.12.19 → 0.12.21
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 +77 -0
- package/dist/dev/hot-reload.js +20 -6
- package/dist/errors/error-handler.d.ts +1 -1
- package/dist/errors/error-handler.js +2 -2
- package/dist/function/function-runner.js +53 -3
- package/dist/function/functions.types.d.ts +3 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -2
- package/dist/middleware/index.d.ts +2 -2
- package/dist/middleware/index.js +2 -2
- package/dist/middleware/telemetry.d.ts +2 -2
- package/dist/middleware/telemetry.js +2 -2
- package/dist/middleware-runner.d.ts +15 -27
- package/dist/middleware-runner.js +25 -30
- package/dist/permissions.d.ts +15 -22
- package/dist/permissions.js +30 -25
- package/dist/pikku-request.js +1 -1
- package/dist/pikku-state.js +2 -3
- package/dist/services/ai-agent-runner-service.d.ts +1 -0
- package/dist/services/content-service.d.ts +66 -37
- package/dist/services/in-memory-queue-service.js +1 -1
- package/dist/services/in-memory-workflow-service.d.ts +15 -13
- package/dist/services/in-memory-workflow-service.js +31 -13
- package/dist/services/index.d.ts +1 -1
- package/dist/services/local-content.d.ts +10 -12
- package/dist/services/local-content.js +54 -38
- package/dist/services/user-session-service.d.ts +1 -1
- package/dist/testing/service-tests.js +24 -0
- package/dist/types/core.types.d.ts +4 -0
- package/dist/types/state.types.d.ts +2 -18
- package/dist/wirings/ai-agent/ai-agent-memory.d.ts +24 -5
- package/dist/wirings/ai-agent/ai-agent-memory.js +128 -23
- package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +10 -1
- package/dist/wirings/ai-agent/ai-agent-model-config.js +15 -35
- package/dist/wirings/ai-agent/ai-agent-prepare.js +4 -1
- package/dist/wirings/ai-agent/ai-agent-runner.js +45 -31
- package/dist/wirings/ai-agent/ai-agent-stream.js +63 -34
- package/dist/wirings/ai-agent/ai-agent.types.d.ts +20 -0
- package/dist/wirings/channel/channel-handler.js +1 -1
- package/dist/wirings/channel/channel-store.d.ts +13 -0
- package/dist/wirings/channel/channel.types.d.ts +3 -0
- package/dist/wirings/channel/local/local-channel-runner.js +23 -5
- package/dist/wirings/channel/pikku-abstract-channel-handler.js +8 -0
- package/dist/wirings/channel/serverless/serverless-channel-runner.js +9 -0
- package/dist/wirings/cli/cli-runner.js +24 -5
- package/dist/wirings/cli/command-parser.js +19 -4
- package/dist/wirings/http/http-runner.js +72 -36
- package/dist/wirings/http/http.types.d.ts +1 -0
- package/dist/wirings/http/pikku-fetch-http-request.js +3 -1
- package/dist/wirings/http/web-request.js +32 -0
- package/dist/wirings/rpc/rpc-runner.d.ts +3 -2
- package/dist/wirings/rpc/rpc-runner.js +45 -11
- package/dist/wirings/workflow/graph/graph-node.d.ts +8 -0
- package/dist/wirings/workflow/graph/graph-node.js +4 -0
- package/dist/wirings/workflow/graph/graph-runner.js +12 -10
- package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +4 -0
- package/dist/wirings/workflow/index.d.ts +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +81 -16
- package/dist/wirings/workflow/pikku-workflow-service.js +266 -45
- package/dist/wirings/workflow/workflow.types.d.ts +34 -0
- package/package.json +1 -1
- package/run-tests.sh +4 -1
- package/src/dev/hot-reload.test.ts +62 -11
- package/src/dev/hot-reload.ts +28 -7
- package/src/errors/error-handler.ts +8 -2
- package/src/errors/error.test.ts +2 -0
- package/src/function/function-runner.test.ts +500 -10
- package/src/function/function-runner.ts +68 -3
- package/src/function/functions.types.ts +3 -2
- package/src/index.ts +22 -3
- package/src/middleware/index.ts +11 -2
- package/src/middleware/telemetry.ts +2 -2
- package/src/middleware-runner.test.ts +16 -16
- package/src/middleware-runner.ts +42 -30
- package/src/permissions.test.ts +27 -24
- package/src/permissions.ts +41 -25
- package/src/pikku-request.test.ts +35 -0
- package/src/pikku-request.ts +1 -1
- package/src/pikku-state.ts +2 -3
- package/src/run-tests-script.test.ts +18 -0
- package/src/services/ai-agent-runner-service.ts +1 -0
- package/src/services/content-service.ts +79 -51
- package/src/services/in-memory-queue-service.ts +1 -1
- package/src/services/in-memory-session-store.ts +1 -2
- package/src/services/in-memory-workflow-service.test.ts +33 -11
- package/src/services/in-memory-workflow-service.ts +49 -13
- package/src/services/index.ts +10 -1
- package/src/services/local-content.test.ts +54 -0
- package/src/services/local-content.ts +80 -53
- package/src/services/typed-credential-service.ts +3 -3
- package/src/services/typed-secret-service.ts +3 -3
- package/src/services/typed-variables-service.ts +3 -3
- package/src/services/user-session-service.ts +4 -4
- package/src/testing/service-tests.ts +30 -0
- package/src/types/core.types.ts +6 -2
- package/src/types/state.types.ts +2 -13
- package/src/wirings/ai-agent/ai-agent-memory.test.ts +324 -0
- package/src/wirings/ai-agent/ai-agent-memory.ts +187 -36
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +12 -90
- package/src/wirings/ai-agent/ai-agent-model-config.ts +14 -38
- package/src/wirings/ai-agent/ai-agent-prepare.test.ts +292 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +4 -1
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +230 -3
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +625 -6
- package/src/wirings/ai-agent/ai-agent-runner.ts +65 -50
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +544 -5
- package/src/wirings/ai-agent/ai-agent-stream.ts +71 -69
- package/src/wirings/ai-agent/ai-agent.types.ts +24 -0
- package/src/wirings/channel/channel-handler.test.ts +272 -0
- package/src/wirings/channel/channel-handler.ts +1 -1
- package/src/wirings/channel/channel-middleware-runner.test.ts +163 -0
- package/src/wirings/channel/channel-store.ts +19 -0
- package/src/wirings/channel/channel.types.ts +4 -0
- package/src/wirings/channel/local/local-channel-runner.test.ts +63 -0
- package/src/wirings/channel/local/local-channel-runner.ts +41 -5
- package/src/wirings/channel/local/local-eventhub-service.ts +3 -3
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +9 -2
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +23 -5
- package/src/wirings/cli/channel/cli-raw-channel-runner.ts +7 -2
- package/src/wirings/cli/cli-runner.test.ts +255 -2
- package/src/wirings/cli/cli-runner.ts +31 -10
- package/src/wirings/cli/cli.types.ts +4 -8
- package/src/wirings/cli/command-parser.test.ts +83 -0
- package/src/wirings/cli/command-parser.ts +23 -4
- package/src/wirings/http/http-runner.test.ts +296 -1
- package/src/wirings/http/http-runner.ts +87 -57
- package/src/wirings/http/http.types.ts +11 -26
- package/src/wirings/http/pikku-fetch-http-request.ts +8 -4
- package/src/wirings/http/pikku-fetch-http-response.test.ts +41 -0
- package/src/wirings/http/web-request.test.ts +115 -0
- package/src/wirings/http/web-request.ts +43 -5
- package/src/wirings/mcp/mcp-runner.test.ts +367 -0
- package/src/wirings/queue/queue.types.ts +2 -5
- package/src/wirings/rpc/rpc-runner.test.ts +511 -0
- package/src/wirings/rpc/rpc-runner.ts +60 -21
- package/src/wirings/rpc/wire-addon.test.ts +57 -0
- package/src/wirings/workflow/graph/graph-node.ts +12 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +98 -0
- package/src/wirings/workflow/graph/graph-runner.ts +28 -10
- package/src/wirings/workflow/graph/workflow-graph.types.ts +4 -0
- package/src/wirings/workflow/index.ts +1 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +19 -2
- package/src/wirings/workflow/pikku-workflow-service.ts +370 -71
- package/src/wirings/workflow/workflow-queue-workers.test.ts +131 -0
- package/src/wirings/workflow/workflow.types.ts +68 -5
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -1,60 +1,89 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Arguments for signing a content key into a time-limited URL.
|
|
3
|
+
*/
|
|
4
|
+
export interface SignContentKeyArgs<TBucket extends string = string> {
|
|
5
|
+
bucket: TBucket;
|
|
6
|
+
contentKey: string;
|
|
7
|
+
dateLessThan: Date;
|
|
8
|
+
dateGreaterThan?: Date;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Arguments for signing an arbitrary URL.
|
|
12
|
+
*/
|
|
13
|
+
export interface SignURLArgs {
|
|
14
|
+
url: string;
|
|
15
|
+
dateLessThan: Date;
|
|
16
|
+
dateGreaterThan?: Date;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Arguments for minting a presigned upload URL.
|
|
20
|
+
*/
|
|
21
|
+
export interface GetUploadURLArgs<TBucket extends string = string> {
|
|
22
|
+
bucket: TBucket;
|
|
23
|
+
fileKey: string;
|
|
24
|
+
contentType: string;
|
|
25
|
+
size?: number;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Result of minting a presigned upload URL.
|
|
29
|
+
*/
|
|
30
|
+
export interface UploadURLResult {
|
|
31
|
+
uploadUrl: string;
|
|
32
|
+
assetKey: string;
|
|
33
|
+
uploadHeaders?: Record<string, string>;
|
|
34
|
+
uploadMethod?: 'PUT' | 'POST';
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Arguments for an operation that targets a single object by key.
|
|
38
|
+
*/
|
|
39
|
+
export interface BucketKeyArgs<TBucket extends string = string> {
|
|
40
|
+
bucket: TBucket;
|
|
41
|
+
key: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Arguments for writing a stream to storage.
|
|
45
|
+
*/
|
|
46
|
+
export interface WriteFileArgs<TBucket extends string = string> extends BucketKeyArgs<TBucket> {
|
|
47
|
+
stream: ReadableStream | NodeJS.ReadableStream;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Arguments for copying a local file into storage.
|
|
51
|
+
*/
|
|
52
|
+
export interface CopyFileArgs<TBucket extends string = string> extends BucketKeyArgs<TBucket> {
|
|
53
|
+
fromAbsolutePath: string;
|
|
54
|
+
}
|
|
55
|
+
export interface ContentService<TBucket extends string = string> {
|
|
2
56
|
/**
|
|
3
57
|
* Signs a content key to generate a secure, time-limited access URL.
|
|
4
|
-
* @param contentKey - The key representing the content object.
|
|
5
|
-
* @param dateLessThan - The expiration time for the signed URL.
|
|
6
|
-
* @param dateGreaterThan - (Optional) Start time before which access is denied.
|
|
7
58
|
*/
|
|
8
|
-
signContentKey(
|
|
59
|
+
signContentKey(args: SignContentKeyArgs<TBucket>): Promise<string>;
|
|
9
60
|
/**
|
|
10
61
|
* Signs an arbitrary URL to generate a secure, time-limited access URL.
|
|
11
|
-
* @param url - The full URL that needs signing.
|
|
12
|
-
* @param dateLessThan - The expiration time for the signed URL.
|
|
13
|
-
* @param dateGreaterThan - (Optional) Start time before which access is denied.
|
|
14
62
|
*/
|
|
15
|
-
signURL(
|
|
63
|
+
signURL(args: SignURLArgs): Promise<string>;
|
|
16
64
|
/**
|
|
17
65
|
* Generates a signed URL for uploading a file directly to storage.
|
|
18
|
-
*
|
|
19
|
-
* @param contentType - The MIME type of the file.
|
|
20
|
-
* @returns A signed upload URL and the finalized asset key.
|
|
66
|
+
* Bucket policy (size limits, MIME allowlist) is enforced by the implementation.
|
|
21
67
|
*/
|
|
22
|
-
getUploadURL(
|
|
23
|
-
uploadUrl: string;
|
|
24
|
-
assetKey: string;
|
|
25
|
-
uploadHeaders?: Record<string, string>;
|
|
26
|
-
uploadMethod?: 'PUT' | 'POST';
|
|
27
|
-
}>;
|
|
68
|
+
getUploadURL(args: GetUploadURLArgs<TBucket>): Promise<UploadURLResult>;
|
|
28
69
|
/**
|
|
29
70
|
* Deletes a file from the storage backend.
|
|
30
|
-
* @param fileName - The name or key of the file to delete.
|
|
31
|
-
* @returns A boolean indicating success.
|
|
32
71
|
*/
|
|
33
|
-
deleteFile(
|
|
72
|
+
deleteFile(args: BucketKeyArgs<TBucket>): Promise<boolean>;
|
|
34
73
|
/**
|
|
35
|
-
* Uploads a file stream to storage under
|
|
36
|
-
* @param assetKey - The key where the file will be saved.
|
|
37
|
-
* @param stream - A readable stream of the file contents.
|
|
38
|
-
* @returns A boolean indicating success.
|
|
74
|
+
* Uploads a file stream to storage under the specified bucket + key.
|
|
39
75
|
*/
|
|
40
|
-
writeFile(
|
|
76
|
+
writeFile(args: WriteFileArgs<TBucket>): Promise<boolean>;
|
|
41
77
|
/**
|
|
42
|
-
* Copies a file from a local absolute path into storage
|
|
43
|
-
* @param assetKey - The destination key.
|
|
44
|
-
* @param fromAbsolutePath - The local absolute file path.
|
|
45
|
-
* @returns A boolean indicating success.
|
|
78
|
+
* Copies a file from a local absolute path into storage.
|
|
46
79
|
*/
|
|
47
|
-
copyFile(
|
|
80
|
+
copyFile(args: CopyFileArgs<TBucket>): Promise<boolean>;
|
|
48
81
|
/**
|
|
49
82
|
* Reads a file from storage as a readable stream.
|
|
50
|
-
* @param assetKey - The key of the file to read.
|
|
51
|
-
* @returns A readable file stream.
|
|
52
83
|
*/
|
|
53
|
-
readFile(
|
|
84
|
+
readFile(args: BucketKeyArgs<TBucket>): Promise<ReadableStream | NodeJS.ReadableStream>;
|
|
54
85
|
/**
|
|
55
86
|
* Reads an entire file from storage into a Buffer.
|
|
56
|
-
* @param assetKey - The key of the file to read.
|
|
57
|
-
* @returns The file contents as a Buffer.
|
|
58
87
|
*/
|
|
59
|
-
readFileAsBuffer(
|
|
88
|
+
readFileAsBuffer(args: BucketKeyArgs<TBucket>): Promise<Buffer>;
|
|
60
89
|
}
|
|
@@ -11,7 +11,7 @@ export class InMemoryQueueService {
|
|
|
11
11
|
status: () => 'active',
|
|
12
12
|
pikkuUserId: options?.pikkuUserId,
|
|
13
13
|
};
|
|
14
|
-
const delay = options?.delay ??
|
|
14
|
+
const delay = options?.delay ?? 100 + Math.floor(Math.random() * 201);
|
|
15
15
|
setTimeout(async () => {
|
|
16
16
|
try {
|
|
17
17
|
await runQueueJob({ job });
|
|
@@ -17,6 +17,7 @@ import type { WorkflowPlannedStep, WorkflowRun, WorkflowRunService, WorkflowRunW
|
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
19
|
export declare class InMemoryWorkflowService extends PikkuWorkflowService implements WorkflowRunService {
|
|
20
|
+
private sleepTimers;
|
|
20
21
|
private runs;
|
|
21
22
|
private steps;
|
|
22
23
|
private stepData;
|
|
@@ -24,23 +25,24 @@ export declare class InMemoryWorkflowService extends PikkuWorkflowService implem
|
|
|
24
25
|
private runState;
|
|
25
26
|
private branchKeys;
|
|
26
27
|
private workflowVersions;
|
|
27
|
-
|
|
28
|
+
protected createRunImpl(workflowName: string, input: any, inline: boolean, graphHash: string, wire: WorkflowRunWire, options?: {
|
|
28
29
|
deterministic?: boolean;
|
|
29
30
|
plannedSteps?: WorkflowPlannedStep[];
|
|
30
31
|
}): Promise<string>;
|
|
32
|
+
protected scheduleSleep(runId: string, stepId: string, duration: number): Promise<boolean>;
|
|
31
33
|
getRun(id: string): Promise<WorkflowRun | null>;
|
|
32
34
|
getRunHistory(runId: string): Promise<Array<StepState & {
|
|
33
35
|
stepName: string;
|
|
34
36
|
}>>;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
protected updateRunStatusImpl(id: string, status: WorkflowStatus, output?: any, error?: SerializedError): Promise<void>;
|
|
38
|
+
protected insertStepStateImpl(runId: string, stepName: string, rpcName: string | null, data: any, stepOptions?: WorkflowStepOptions): Promise<StepState>;
|
|
37
39
|
getStepState(runId: string, stepName: string): Promise<StepState>;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
protected setStepRunningImpl(stepId: string): Promise<void>;
|
|
41
|
+
protected setStepScheduledImpl(stepId: string): Promise<void>;
|
|
42
|
+
protected setStepResultImpl(stepId: string, result: any): Promise<void>;
|
|
43
|
+
protected setStepErrorImpl(stepId: string, error: Error): Promise<void>;
|
|
44
|
+
protected setStepChildRunIdImpl(stepId: string, childRunId: string): Promise<void>;
|
|
45
|
+
protected createRetryAttemptImpl(failedStepId: string, status: 'pending' | 'running'): Promise<StepState>;
|
|
44
46
|
listRuns(options?: {
|
|
45
47
|
workflowName?: string;
|
|
46
48
|
status?: string;
|
|
@@ -65,11 +67,11 @@ export declare class InMemoryWorkflowService extends PikkuWorkflowService implem
|
|
|
65
67
|
getNodesWithoutSteps(runId: string, nodeIds: string[]): Promise<string[]>;
|
|
66
68
|
getNodeResults(runId: string, nodeIds: string[]): Promise<Record<string, any>>;
|
|
67
69
|
setBranchKey(runId: string, nodeId: string, branchKey: string): Promise<void>;
|
|
68
|
-
|
|
69
|
-
|
|
70
|
+
protected setBranchTakenImpl(stepId: string, branchKey: string): Promise<void>;
|
|
71
|
+
protected updateRunStateImpl(runId: string, name: string, value: unknown): Promise<void>;
|
|
70
72
|
getRunState(runId: string): Promise<Record<string, unknown>>;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
protected upsertWorkflowVersionImpl(name: string, graphHash: string, graph: any, source: string, status?: WorkflowVersionStatus): Promise<void>;
|
|
74
|
+
protected updateWorkflowVersionStatusImpl(name: string, graphHash: string, status: WorkflowVersionStatus): Promise<void>;
|
|
73
75
|
getWorkflowVersion(name: string, graphHash: string): Promise<{
|
|
74
76
|
graph: any;
|
|
75
77
|
source: string;
|
|
@@ -16,6 +16,7 @@ import { PikkuWorkflowService } from '../wirings/workflow/pikku-workflow-service
|
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
18
|
export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
19
|
+
sleepTimers = new Set();
|
|
19
20
|
runs = new Map();
|
|
20
21
|
steps = new Map(); // keyed by `${runId}:${stepName}`
|
|
21
22
|
stepData = new Map(); // keyed by stepId
|
|
@@ -23,7 +24,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
23
24
|
runState = new Map(); // keyed by runId
|
|
24
25
|
branchKeys = new Map(); // keyed by stepId
|
|
25
26
|
workflowVersions = new Map(); // keyed by `${name}:${graphHash}`
|
|
26
|
-
async
|
|
27
|
+
async createRunImpl(workflowName, input, inline, graphHash, wire, options) {
|
|
27
28
|
const runId = randomUUID();
|
|
28
29
|
const now = new Date();
|
|
29
30
|
const run = {
|
|
@@ -47,13 +48,26 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
47
48
|
}
|
|
48
49
|
return runId;
|
|
49
50
|
}
|
|
51
|
+
async scheduleSleep(runId, stepId, duration) {
|
|
52
|
+
const timer = setTimeout(async () => {
|
|
53
|
+
this.sleepTimers.delete(timer);
|
|
54
|
+
try {
|
|
55
|
+
await this.executeWorkflowSleepCompleted(runId, stepId);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
this.logger?.error(`Failed to resume workflow sleep for runId ${runId}: ${error?.message ?? error}`);
|
|
59
|
+
}
|
|
60
|
+
}, duration);
|
|
61
|
+
this.sleepTimers.add(timer);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
50
64
|
async getRun(id) {
|
|
51
65
|
return this.runs.get(id) || null;
|
|
52
66
|
}
|
|
53
67
|
async getRunHistory(runId) {
|
|
54
68
|
return this.stepHistory.get(runId) || [];
|
|
55
69
|
}
|
|
56
|
-
async
|
|
70
|
+
async updateRunStatusImpl(id, status, output, error) {
|
|
57
71
|
const run = this.runs.get(id);
|
|
58
72
|
if (run) {
|
|
59
73
|
run.status = status;
|
|
@@ -64,7 +78,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
64
78
|
run.error = error;
|
|
65
79
|
}
|
|
66
80
|
}
|
|
67
|
-
async
|
|
81
|
+
async insertStepStateImpl(runId, stepName, rpcName, data, stepOptions) {
|
|
68
82
|
const stepId = randomUUID();
|
|
69
83
|
const now = new Date();
|
|
70
84
|
const step = {
|
|
@@ -94,7 +108,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
94
108
|
}
|
|
95
109
|
return step;
|
|
96
110
|
}
|
|
97
|
-
async
|
|
111
|
+
async setStepRunningImpl(stepId) {
|
|
98
112
|
for (const step of this.steps.values()) {
|
|
99
113
|
if (step.stepId === stepId) {
|
|
100
114
|
step.status = 'running';
|
|
@@ -104,7 +118,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
104
118
|
}
|
|
105
119
|
}
|
|
106
120
|
}
|
|
107
|
-
async
|
|
121
|
+
async setStepScheduledImpl(stepId) {
|
|
108
122
|
for (const step of this.steps.values()) {
|
|
109
123
|
if (step.stepId === stepId) {
|
|
110
124
|
step.status = 'scheduled';
|
|
@@ -114,7 +128,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
114
128
|
}
|
|
115
129
|
}
|
|
116
130
|
}
|
|
117
|
-
async
|
|
131
|
+
async setStepResultImpl(stepId, result) {
|
|
118
132
|
for (const step of this.steps.values()) {
|
|
119
133
|
if (step.stepId === stepId) {
|
|
120
134
|
step.status = 'succeeded';
|
|
@@ -125,7 +139,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
125
139
|
}
|
|
126
140
|
}
|
|
127
141
|
}
|
|
128
|
-
async
|
|
142
|
+
async setStepErrorImpl(stepId, error) {
|
|
129
143
|
for (const step of this.steps.values()) {
|
|
130
144
|
if (step.stepId === stepId) {
|
|
131
145
|
step.status = 'failed';
|
|
@@ -140,7 +154,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
140
154
|
}
|
|
141
155
|
}
|
|
142
156
|
}
|
|
143
|
-
async
|
|
157
|
+
async setStepChildRunIdImpl(stepId, childRunId) {
|
|
144
158
|
for (const step of this.steps.values()) {
|
|
145
159
|
if (step.stepId === stepId) {
|
|
146
160
|
step.childRunId = childRunId;
|
|
@@ -149,7 +163,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
149
163
|
}
|
|
150
164
|
}
|
|
151
165
|
}
|
|
152
|
-
async
|
|
166
|
+
async createRetryAttemptImpl(failedStepId, status) {
|
|
153
167
|
// Find the failed step
|
|
154
168
|
let failedStep;
|
|
155
169
|
let runId;
|
|
@@ -252,6 +266,10 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
252
266
|
return fn();
|
|
253
267
|
}
|
|
254
268
|
async close() {
|
|
269
|
+
for (const timer of this.sleepTimers) {
|
|
270
|
+
clearTimeout(timer);
|
|
271
|
+
}
|
|
272
|
+
this.sleepTimers.clear();
|
|
255
273
|
// Clear all in-memory state
|
|
256
274
|
this.runs.clear();
|
|
257
275
|
this.steps.clear();
|
|
@@ -317,10 +335,10 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
317
335
|
this.branchKeys.set(step.stepId, branchKey);
|
|
318
336
|
}
|
|
319
337
|
}
|
|
320
|
-
async
|
|
338
|
+
async setBranchTakenImpl(stepId, branchKey) {
|
|
321
339
|
this.branchKeys.set(stepId, branchKey);
|
|
322
340
|
}
|
|
323
|
-
async
|
|
341
|
+
async updateRunStateImpl(runId, name, value) {
|
|
324
342
|
const state = this.runState.get(runId) || {};
|
|
325
343
|
state[name] = value;
|
|
326
344
|
this.runState.set(runId, state);
|
|
@@ -328,14 +346,14 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
328
346
|
async getRunState(runId) {
|
|
329
347
|
return this.runState.get(runId) || {};
|
|
330
348
|
}
|
|
331
|
-
async
|
|
349
|
+
async upsertWorkflowVersionImpl(name, graphHash, graph, source, status) {
|
|
332
350
|
this.workflowVersions.set(`${name}:${graphHash}`, {
|
|
333
351
|
graph,
|
|
334
352
|
source,
|
|
335
353
|
status: status ?? 'active',
|
|
336
354
|
});
|
|
337
355
|
}
|
|
338
|
-
async
|
|
356
|
+
async updateWorkflowVersionStatusImpl(name, graphHash, status) {
|
|
339
357
|
const key = `${name}:${graphHash}`;
|
|
340
358
|
const version = this.workflowVersions.get(key);
|
|
341
359
|
if (version) {
|
package/dist/services/index.d.ts
CHANGED
|
@@ -16,7 +16,7 @@ export { InMemoryQueueService } from './in-memory-queue-service.js';
|
|
|
16
16
|
export { InMemoryTriggerService } from './in-memory-trigger-service.js';
|
|
17
17
|
export { InMemoryAIRunStateService } from './in-memory-ai-run-state-service.js';
|
|
18
18
|
export { LocalGatewayService } from './local-gateway-service.js';
|
|
19
|
-
export type { ContentService } from './content-service.js';
|
|
19
|
+
export type { ContentService, SignContentKeyArgs, SignURLArgs, GetUploadURLArgs, UploadURLResult, BucketKeyArgs, WriteFileArgs, CopyFileArgs, } from './content-service.js';
|
|
20
20
|
export type { JWTService } from './jwt-service.js';
|
|
21
21
|
export type { Logger } from './logger.js';
|
|
22
22
|
export type { SecretService } from './secret-service.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ContentService, JWTService, Logger } from '@pikku/core/services';
|
|
1
|
+
import type { BucketKeyArgs, ContentService, CopyFileArgs, GetUploadURLArgs, JWTService, Logger, SignContentKeyArgs, SignURLArgs, UploadURLResult, WriteFileArgs } from '@pikku/core/services';
|
|
2
2
|
export interface LocalContentConfig {
|
|
3
3
|
localFileUploadPath: string;
|
|
4
4
|
uploadUrlPrefix: string;
|
|
@@ -12,18 +12,16 @@ export declare class LocalContent implements ContentService {
|
|
|
12
12
|
private jwt?;
|
|
13
13
|
constructor(config: LocalContentConfig, logger: Logger, jwt?: JWTService | undefined);
|
|
14
14
|
private safePath;
|
|
15
|
+
private joinKey;
|
|
15
16
|
init(): Promise<void>;
|
|
16
17
|
private signParams;
|
|
17
|
-
signURL(
|
|
18
|
-
signContentKey(
|
|
19
|
-
getUploadURL(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
readFile(assetKey: string): Promise<ReadableStream | NodeJS.ReadableStream>;
|
|
26
|
-
readFileAsBuffer(assetKey: string): Promise<Buffer>;
|
|
27
|
-
deleteFile(assetKey: string): Promise<boolean>;
|
|
18
|
+
signURL(args: SignURLArgs): Promise<string>;
|
|
19
|
+
signContentKey(args: SignContentKeyArgs): Promise<string>;
|
|
20
|
+
getUploadURL(args: GetUploadURLArgs): Promise<UploadURLResult>;
|
|
21
|
+
writeFile(args: WriteFileArgs): Promise<boolean>;
|
|
22
|
+
copyFile(args: CopyFileArgs): Promise<boolean>;
|
|
23
|
+
readFile(args: BucketKeyArgs): Promise<ReadableStream | NodeJS.ReadableStream>;
|
|
24
|
+
readFileAsBuffer(args: BucketKeyArgs): Promise<Buffer>;
|
|
25
|
+
deleteFile(args: BucketKeyArgs): Promise<boolean>;
|
|
28
26
|
private createDirectoryForFile;
|
|
29
27
|
}
|
|
@@ -11,14 +11,18 @@ export class LocalContent {
|
|
|
11
11
|
this.logger = logger;
|
|
12
12
|
this.jwt = jwt;
|
|
13
13
|
}
|
|
14
|
-
safePath(
|
|
14
|
+
safePath(bucket, key) {
|
|
15
15
|
const base = resolve(this.config.localFileUploadPath);
|
|
16
|
-
const
|
|
16
|
+
const scoped = resolve(base, normalize(bucket));
|
|
17
|
+
const target = resolve(scoped, normalize(key));
|
|
17
18
|
if (!target.startsWith(base + '/') && target !== base) {
|
|
18
19
|
throw new Error('Invalid asset key');
|
|
19
20
|
}
|
|
20
21
|
return target;
|
|
21
22
|
}
|
|
23
|
+
joinKey(bucket, key) {
|
|
24
|
+
return `${bucket}/${key}`;
|
|
25
|
+
}
|
|
22
26
|
async init() { }
|
|
23
27
|
async signParams(dateLessThan, dateGreaterThan) {
|
|
24
28
|
const signedAt = Date.now();
|
|
@@ -32,86 +36,98 @@ export class LocalContent {
|
|
|
32
36
|
}
|
|
33
37
|
if (this.jwt) {
|
|
34
38
|
const expiresInSeconds = Math.max(1, Math.floor((expiresAt - signedAt) / 1000));
|
|
35
|
-
const
|
|
39
|
+
const payload = {
|
|
40
|
+
signedAt,
|
|
41
|
+
expiresAt,
|
|
42
|
+
};
|
|
43
|
+
if (dateGreaterThan) {
|
|
44
|
+
payload.notBefore = dateGreaterThan.getTime();
|
|
45
|
+
}
|
|
46
|
+
const signature = await this.jwt.encode({ value: expiresInSeconds, unit: 'second' }, payload);
|
|
36
47
|
params.set('signature', signature);
|
|
37
48
|
}
|
|
38
49
|
return params.toString();
|
|
39
50
|
}
|
|
40
|
-
async signURL(
|
|
41
|
-
const params = await this.signParams(dateLessThan, dateGreaterThan);
|
|
42
|
-
return `${url}?${params}`;
|
|
51
|
+
async signURL(args) {
|
|
52
|
+
const params = await this.signParams(args.dateLessThan, args.dateGreaterThan);
|
|
53
|
+
return `${args.url}?${params}`;
|
|
43
54
|
}
|
|
44
|
-
async signContentKey(
|
|
55
|
+
async signContentKey(args) {
|
|
56
|
+
const fullKey = this.joinKey(args.bucket, args.contentKey);
|
|
45
57
|
const base = this.config.server
|
|
46
|
-
? `${this.config.server}${this.config.assetUrlPrefix}/${
|
|
47
|
-
: `${this.config.assetUrlPrefix}/${
|
|
48
|
-
return this.signURL(
|
|
58
|
+
? `${this.config.server}${this.config.assetUrlPrefix}/${fullKey}`
|
|
59
|
+
: `${this.config.assetUrlPrefix}/${fullKey}`;
|
|
60
|
+
return this.signURL({
|
|
61
|
+
url: base,
|
|
62
|
+
dateLessThan: args.dateLessThan,
|
|
63
|
+
dateGreaterThan: args.dateGreaterThan,
|
|
64
|
+
});
|
|
49
65
|
}
|
|
50
|
-
async getUploadURL(
|
|
51
|
-
this.
|
|
66
|
+
async getUploadURL(args) {
|
|
67
|
+
const fullKey = this.joinKey(args.bucket, args.fileKey);
|
|
68
|
+
this.logger.debug(`Going to upload with key: ${fullKey}`);
|
|
52
69
|
return {
|
|
53
|
-
uploadUrl: `${this.config.uploadUrlPrefix}/${
|
|
54
|
-
assetKey,
|
|
70
|
+
uploadUrl: `${this.config.uploadUrlPrefix}/${fullKey}`,
|
|
71
|
+
assetKey: fullKey,
|
|
55
72
|
};
|
|
56
73
|
}
|
|
57
|
-
async writeFile(
|
|
58
|
-
this.logger.debug(`Writing file: ${
|
|
59
|
-
const path = this.safePath(
|
|
74
|
+
async writeFile(args) {
|
|
75
|
+
this.logger.debug(`Writing file: ${args.bucket}/${args.key}`);
|
|
76
|
+
const path = this.safePath(args.bucket, args.key);
|
|
60
77
|
try {
|
|
61
78
|
await this.createDirectoryForFile(path);
|
|
62
79
|
const fileStream = createWriteStream(path);
|
|
63
|
-
|
|
64
|
-
await pipeline(stream, fileStream);
|
|
80
|
+
await pipeline(args.stream, fileStream);
|
|
65
81
|
return true;
|
|
66
82
|
}
|
|
67
83
|
catch (e) {
|
|
68
84
|
console.error(e);
|
|
69
|
-
this.logger.error(`Error writing content ${
|
|
85
|
+
this.logger.error(`Error writing content ${args.bucket}/${args.key}`, e);
|
|
70
86
|
return false;
|
|
71
87
|
}
|
|
72
88
|
}
|
|
73
|
-
async copyFile(
|
|
74
|
-
this.logger.debug(`Writing file: ${
|
|
89
|
+
async copyFile(args) {
|
|
90
|
+
this.logger.debug(`Writing file: ${args.bucket}/${args.key}`);
|
|
75
91
|
try {
|
|
76
|
-
const path = this.safePath(
|
|
92
|
+
const path = this.safePath(args.bucket, args.key);
|
|
77
93
|
await this.createDirectoryForFile(path);
|
|
78
|
-
await promises.copyFile(fromAbsolutePath, path);
|
|
94
|
+
await promises.copyFile(args.fromAbsolutePath, path);
|
|
95
|
+
return true;
|
|
79
96
|
}
|
|
80
97
|
catch (e) {
|
|
81
98
|
console.error(e);
|
|
82
|
-
this.logger.error(`Error inserting content ${
|
|
99
|
+
this.logger.error(`Error inserting content ${args.bucket}/${args.key}`, e);
|
|
83
100
|
}
|
|
84
101
|
return false;
|
|
85
102
|
}
|
|
86
|
-
async readFile(
|
|
87
|
-
this.logger.debug(`Getting key: ${
|
|
88
|
-
const filePath = this.safePath(
|
|
103
|
+
async readFile(args) {
|
|
104
|
+
this.logger.debug(`Getting key: ${args.bucket}/${args.key}`);
|
|
105
|
+
const filePath = this.safePath(args.bucket, args.key);
|
|
89
106
|
try {
|
|
90
107
|
const stream = createReadStream(filePath);
|
|
91
|
-
// Handle early stream errors (like file not found, permission denied, etc.)
|
|
92
108
|
stream.on('error', (err) => {
|
|
93
|
-
this.logger.error(`Error getting content ${
|
|
109
|
+
this.logger.error(`Error getting content ${args.bucket}/${args.key}`, err);
|
|
94
110
|
});
|
|
95
111
|
return stream;
|
|
96
112
|
}
|
|
97
113
|
catch (e) {
|
|
98
|
-
this.logger.error(`Error setting up stream for ${
|
|
114
|
+
this.logger.error(`Error setting up stream for ${args.bucket}/${args.key}`, e);
|
|
99
115
|
throw e;
|
|
100
116
|
}
|
|
101
117
|
}
|
|
102
|
-
async readFileAsBuffer(
|
|
103
|
-
const filePath = this.safePath(
|
|
104
|
-
this.logger.debug(`Reading file as buffer: ${
|
|
118
|
+
async readFileAsBuffer(args) {
|
|
119
|
+
const filePath = this.safePath(args.bucket, args.key);
|
|
120
|
+
this.logger.debug(`Reading file as buffer: ${args.bucket}/${args.key}`);
|
|
105
121
|
return readFile(filePath);
|
|
106
122
|
}
|
|
107
|
-
async deleteFile(
|
|
108
|
-
this.logger.debug(`deleting key: ${
|
|
123
|
+
async deleteFile(args) {
|
|
124
|
+
this.logger.debug(`deleting key: ${args.bucket}/${args.key}`);
|
|
109
125
|
try {
|
|
110
|
-
await promises.unlink(this.safePath(
|
|
126
|
+
await promises.unlink(this.safePath(args.bucket, args.key));
|
|
111
127
|
return true;
|
|
112
128
|
}
|
|
113
129
|
catch (e) {
|
|
114
|
-
this.logger.error(`Error deleting content ${
|
|
130
|
+
this.logger.error(`Error deleting content ${args.bucket}/${args.key}`, e);
|
|
115
131
|
}
|
|
116
132
|
return false;
|
|
117
133
|
}
|
|
@@ -13,7 +13,7 @@ export declare class PikkuSessionService<UserSession extends CoreUserSession> im
|
|
|
13
13
|
private sessionStore?;
|
|
14
14
|
sessionChanged: boolean;
|
|
15
15
|
initial: UserSession | undefined;
|
|
16
|
-
|
|
16
|
+
protected session: UserSession | undefined;
|
|
17
17
|
private pikkuUserId?;
|
|
18
18
|
constructor(sessionStore?: SessionStore<UserSession> | undefined);
|
|
19
19
|
setPikkuUserId(id: string): void;
|
|
@@ -49,6 +49,30 @@ export function defineServiceTests(config) {
|
|
|
49
49
|
test('removeChannels with empty array is no-op', async () => {
|
|
50
50
|
await store.removeChannels([]);
|
|
51
51
|
});
|
|
52
|
+
test('session round-trip — set / get / clear', async () => {
|
|
53
|
+
await store.addChannel({
|
|
54
|
+
channelId: 'ch-state',
|
|
55
|
+
channelName: 'test-channel',
|
|
56
|
+
});
|
|
57
|
+
// initially undefined
|
|
58
|
+
const empty = await store.getState('ch-state');
|
|
59
|
+
assert.equal(empty, undefined);
|
|
60
|
+
// set + get
|
|
61
|
+
const payload = { userId: 'u-7', meta: { foo: 1 } };
|
|
62
|
+
await store.setState('ch-state', payload);
|
|
63
|
+
const got = await store.getState('ch-state');
|
|
64
|
+
assert.deepEqual(got, payload);
|
|
65
|
+
// overwrite
|
|
66
|
+
const next = { userId: 'u-8' };
|
|
67
|
+
await store.setState('ch-state', next);
|
|
68
|
+
const got2 = await store.getState('ch-state');
|
|
69
|
+
assert.deepEqual(got2, next);
|
|
70
|
+
// clear
|
|
71
|
+
await store.clearState('ch-state');
|
|
72
|
+
const after = await store.getState('ch-state');
|
|
73
|
+
assert.equal(after, undefined);
|
|
74
|
+
await store.removeChannels(['ch-state']);
|
|
75
|
+
});
|
|
52
76
|
});
|
|
53
77
|
}
|
|
54
78
|
if (services.eventHubStore) {
|
|
@@ -5,6 +5,7 @@ import type { SchemaService } from '../services/schema-service.js';
|
|
|
5
5
|
import type { JWTService } from '../services/jwt-service.js';
|
|
6
6
|
import type { PikkuHTTP } from '../wirings/http/http.types.js';
|
|
7
7
|
import type { PikkuChannel, CorePikkuChannelMiddleware, CorePikkuChannelMiddlewareFactory } from '../wirings/channel/channel.types.js';
|
|
8
|
+
import type { EventHubService } from '../wirings/channel/eventhub-service.js';
|
|
8
9
|
import type { PikkuRPC } from '../wirings/rpc/rpc-types.js';
|
|
9
10
|
import type { PikkuMCP } from '../wirings/mcp/mcp.types.js';
|
|
10
11
|
import type { PikkuScheduledTask } from '../wirings/scheduler/scheduler.types.js';
|
|
@@ -82,6 +83,7 @@ export type FunctionRuntimeMeta = {
|
|
|
82
83
|
version?: number;
|
|
83
84
|
approvalRequired?: boolean;
|
|
84
85
|
approvalDescription?: string;
|
|
86
|
+
implementationHash?: string;
|
|
85
87
|
contractHash?: string;
|
|
86
88
|
inputHash?: string;
|
|
87
89
|
outputHash?: string;
|
|
@@ -162,6 +164,8 @@ export interface CoreSingletonServices<Config extends CoreConfig = CoreConfig> {
|
|
|
162
164
|
workflowService?: WorkflowService;
|
|
163
165
|
/** The queue service */
|
|
164
166
|
queueService?: QueueService;
|
|
167
|
+
/** Event hub for realtime pub/sub across channels */
|
|
168
|
+
eventHub?: EventHubService<Record<string, any>>;
|
|
165
169
|
/** The scheduler service */
|
|
166
170
|
schedulerService?: SchedulerService;
|
|
167
171
|
/** The deployment service for service discovery */
|
|
@@ -88,6 +88,7 @@ export interface PikkuPackageState {
|
|
|
88
88
|
middleware: {
|
|
89
89
|
tagGroup: Record<string, CorePikkuMiddlewareGroup>;
|
|
90
90
|
httpGroup: Record<string, CorePikkuMiddlewareGroup>;
|
|
91
|
+
global: CorePikkuMiddlewareGroup;
|
|
91
92
|
};
|
|
92
93
|
channelMiddleware: {
|
|
93
94
|
tagGroup: Record<string, CorePikkuChannelMiddleware[]>;
|
|
@@ -95,6 +96,7 @@ export interface PikkuPackageState {
|
|
|
95
96
|
permissions: {
|
|
96
97
|
tagGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
|
|
97
98
|
httpGroup: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
|
|
99
|
+
global: (CorePermissionGroup | CorePikkuPermission)[];
|
|
98
100
|
};
|
|
99
101
|
misc: {
|
|
100
102
|
errors: Map<PikkuError, ErrorDetails>;
|
|
@@ -103,24 +105,6 @@ export interface PikkuPackageState {
|
|
|
103
105
|
channelMiddleware: Record<string, CorePikkuChannelMiddleware[]>;
|
|
104
106
|
permissions: Record<string, CorePermissionGroup | CorePikkuPermission[]>;
|
|
105
107
|
};
|
|
106
|
-
models: {
|
|
107
|
-
config: {
|
|
108
|
-
models?: Record<string, string | {
|
|
109
|
-
model: string;
|
|
110
|
-
temperature?: number;
|
|
111
|
-
maxSteps?: number;
|
|
112
|
-
}>;
|
|
113
|
-
agentDefaults?: {
|
|
114
|
-
temperature?: number;
|
|
115
|
-
maxSteps?: number;
|
|
116
|
-
};
|
|
117
|
-
agentOverrides?: Record<string, {
|
|
118
|
-
model?: string;
|
|
119
|
-
temperature?: number;
|
|
120
|
-
maxSteps?: number;
|
|
121
|
-
}>;
|
|
122
|
-
} | null;
|
|
123
|
-
};
|
|
124
108
|
package: {
|
|
125
109
|
/** Service factory functions for addon packages */
|
|
126
110
|
factories: {
|