@pikku/core 0.12.4 → 0.12.6
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 +21 -1
- package/dist/dev/hot-reload.d.ts +10 -0
- package/dist/dev/hot-reload.js +158 -0
- package/dist/middleware-runner.d.ts +1 -0
- package/dist/middleware-runner.js +5 -0
- package/dist/permissions.d.ts +1 -0
- package/dist/permissions.js +5 -0
- package/dist/services/content-service.d.ts +2 -0
- package/dist/services/in-memory-workflow-service.d.ts +1 -0
- package/dist/services/in-memory-workflow-service.js +16 -11
- package/dist/services/workflow-service.d.ts +1 -0
- package/dist/wirings/ai-agent/ai-agent-prepare.js +16 -1
- package/dist/wirings/channel/channel-middleware-runner.d.ts +1 -0
- package/dist/wirings/channel/channel-middleware-runner.js +5 -0
- package/dist/wirings/http/http-runner.js +1 -1
- package/dist/wirings/workflow/pikku-workflow-service.d.ts +6 -0
- package/dist/wirings/workflow/pikku-workflow-service.js +51 -16
- package/dist/wirings/workflow/workflow.types.d.ts +2 -0
- package/package.json +5 -3
- package/src/crypto-utils.test.ts +214 -0
- package/src/crypto-utils.ts +213 -0
- package/src/dev/hot-reload.test.ts +484 -0
- package/src/dev/hot-reload.ts +212 -0
- package/src/errors/error-handler.ts +62 -0
- package/src/errors/error.test.ts +195 -0
- package/src/errors/errors.ts +374 -0
- package/src/errors/index.ts +2 -0
- package/src/factory-functions.test.ts +109 -0
- package/src/function/function-runner.test.ts +536 -0
- package/src/function/function-runner.ts +365 -0
- package/src/function/functions.types.ts +304 -0
- package/src/function/index.ts +5 -0
- package/src/handle-error.test.ts +424 -0
- package/src/handle-error.ts +69 -0
- package/src/index.ts +118 -0
- package/src/internal.ts +6 -0
- package/src/middleware/auth-apikey.test.ts +363 -0
- package/src/middleware/auth-apikey.ts +47 -0
- package/src/middleware/auth-bearer.test.ts +450 -0
- package/src/middleware/auth-bearer.ts +72 -0
- package/src/middleware/auth-cookie.test.ts +528 -0
- package/src/middleware/auth-cookie.ts +80 -0
- package/src/middleware/cors.test.ts +424 -0
- package/src/middleware/cors.ts +104 -0
- package/src/middleware/index.ts +5 -0
- package/src/middleware/remote-auth.test.ts +488 -0
- package/src/middleware/remote-auth.ts +68 -0
- package/src/middleware/timeout.ts +15 -0
- package/src/middleware-runner.test.ts +418 -0
- package/src/middleware-runner.ts +240 -0
- package/src/permissions.test.ts +434 -0
- package/src/permissions.ts +327 -0
- package/src/pikku-request.ts +23 -0
- package/src/pikku-response.ts +5 -0
- package/src/pikku-state.test.ts +224 -0
- package/src/pikku-state.ts +216 -0
- package/src/run-tests-script.test.ts +49 -0
- package/src/schema.test.ts +249 -0
- package/src/schema.ts +151 -0
- package/src/services/ai-agent-runner-service.ts +41 -0
- package/src/services/ai-run-state-service.ts +20 -0
- package/src/services/ai-storage-service.ts +39 -0
- package/src/services/content-service.ts +81 -0
- package/src/services/deployment-service.ts +22 -0
- package/src/services/gateway-service.ts +20 -0
- package/src/services/gopass-secrets.ts +98 -0
- package/src/services/in-memory-ai-run-state-service.ts +73 -0
- package/src/services/in-memory-trigger-service.ts +64 -0
- package/src/services/in-memory-workflow-service.test.ts +351 -0
- package/src/services/in-memory-workflow-service.ts +512 -0
- package/src/services/index.ts +56 -0
- package/src/services/jwt-service.ts +30 -0
- package/src/services/local-content.ts +120 -0
- package/src/services/local-gateway-service.ts +62 -0
- package/src/services/local-secrets.test.ts +80 -0
- package/src/services/local-secrets.ts +94 -0
- package/src/services/local-variables.test.ts +61 -0
- package/src/services/local-variables.ts +39 -0
- package/src/services/logger-console.test.ts +118 -0
- package/src/services/logger-console.ts +98 -0
- package/src/services/logger.ts +57 -0
- package/src/services/scheduler-service.ts +86 -0
- package/src/services/schema-service.ts +33 -0
- package/src/services/scoped-secret-service.test.ts +74 -0
- package/src/services/scoped-secret-service.ts +41 -0
- package/src/services/secret-service.ts +38 -0
- package/src/services/trigger-service.ts +17 -0
- package/src/services/typed-secret-service.test.ts +93 -0
- package/src/services/typed-secret-service.ts +70 -0
- package/src/services/typed-variables-service.test.ts +73 -0
- package/src/services/typed-variables-service.ts +81 -0
- package/src/services/user-session-service.test.ts +113 -0
- package/src/services/user-session-service.ts +86 -0
- package/src/services/variables-service.ts +11 -0
- package/src/services/workflow-service.ts +96 -0
- package/src/testing/index.ts +2 -0
- package/src/testing/service-tests.ts +873 -0
- package/src/time-utils.test.ts +56 -0
- package/src/time-utils.ts +107 -0
- package/src/types/core.types.ts +478 -0
- package/src/types/state.types.ts +188 -0
- package/src/utils/hash.test.ts +68 -0
- package/src/utils/hash.ts +26 -0
- package/src/utils.test.ts +350 -0
- package/src/utils.ts +129 -0
- package/src/version.test.ts +80 -0
- package/src/version.ts +25 -0
- package/src/wirings/ai-agent/agent-dynamic-workflow.ts +469 -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-memory.ts +310 -0
- package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
- package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
- package/src/wirings/ai-agent/ai-agent-prepare.ts +659 -0
- package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
- package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
- package/src/wirings/ai-agent/ai-agent-runner.test.ts +319 -0
- package/src/wirings/ai-agent/ai-agent-runner.ts +773 -0
- package/src/wirings/ai-agent/ai-agent-stream.test.ts +859 -0
- package/src/wirings/ai-agent/ai-agent-stream.ts +1153 -0
- package/src/wirings/ai-agent/ai-agent.types.ts +382 -0
- package/src/wirings/ai-agent/index.ts +37 -0
- package/src/wirings/channel/channel-common.ts +90 -0
- package/src/wirings/channel/channel-handler.ts +250 -0
- package/src/wirings/channel/channel-middleware-runner.ts +126 -0
- package/src/wirings/channel/channel-runner.ts +166 -0
- package/src/wirings/channel/channel-store.ts +29 -0
- package/src/wirings/channel/channel.types.ts +172 -0
- package/src/wirings/channel/define-channel-routes.ts +25 -0
- package/src/wirings/channel/eventhub-service.ts +34 -0
- package/src/wirings/channel/eventhub-store.ts +13 -0
- package/src/wirings/channel/index.ts +24 -0
- package/src/wirings/channel/local/index.ts +3 -0
- package/src/wirings/channel/local/local-channel-handler.ts +81 -0
- package/src/wirings/channel/local/local-channel-runner.test.ts +215 -0
- package/src/wirings/channel/local/local-channel-runner.ts +210 -0
- package/src/wirings/channel/local/local-eventhub-service.test.ts +95 -0
- package/src/wirings/channel/local/local-eventhub-service.ts +101 -0
- package/src/wirings/channel/log-channels.ts +20 -0
- package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +54 -0
- package/src/wirings/channel/pikku-abstract-channel-handler.ts +45 -0
- package/src/wirings/channel/serverless/index.ts +5 -0
- package/src/wirings/channel/serverless/serverless-channel-runner.ts +289 -0
- package/src/wirings/cli/channel/cli-channel-runner.ts +136 -0
- package/src/wirings/cli/channel/index.ts +1 -0
- package/src/wirings/cli/cli-runner.test.ts +403 -0
- package/src/wirings/cli/cli-runner.ts +529 -0
- package/src/wirings/cli/cli.types.ts +358 -0
- package/src/wirings/cli/command-parser.test.ts +445 -0
- package/src/wirings/cli/command-parser.ts +504 -0
- package/src/wirings/cli/define-cli-commands.ts +24 -0
- package/src/wirings/cli/index.ts +19 -0
- package/src/wirings/gateway/gateway-runner.test.ts +474 -0
- package/src/wirings/gateway/gateway-runner.ts +411 -0
- package/src/wirings/gateway/gateway.types.ts +149 -0
- package/src/wirings/gateway/index.ts +13 -0
- package/src/wirings/http/http-routes.test.ts +322 -0
- package/src/wirings/http/http-routes.ts +197 -0
- package/src/wirings/http/http-runner.test.ts +144 -0
- package/src/wirings/http/http-runner.ts +588 -0
- package/src/wirings/http/http.types.ts +369 -0
- package/src/wirings/http/index.ts +28 -0
- package/src/wirings/http/log-http-routes.ts +22 -0
- package/src/wirings/http/pikku-fetch-http-request.test.ts +237 -0
- package/src/wirings/http/pikku-fetch-http-request.ts +170 -0
- package/src/wirings/http/pikku-fetch-http-response.test.ts +82 -0
- package/src/wirings/http/pikku-fetch-http-response.ts +147 -0
- package/src/wirings/http/routers/http-router.ts +13 -0
- package/src/wirings/http/routers/path-to-regex.test.ts +319 -0
- package/src/wirings/http/routers/path-to-regex.ts +126 -0
- package/src/wirings/http/web-request.test.ts +236 -0
- package/src/wirings/http/web-request.ts +104 -0
- package/src/wirings/mcp/index.ts +27 -0
- package/src/wirings/mcp/mcp-endpoint-registry.test.ts +389 -0
- package/src/wirings/mcp/mcp-endpoint-registry.ts +159 -0
- package/src/wirings/mcp/mcp-runner.ts +323 -0
- package/src/wirings/mcp/mcp.types.ts +216 -0
- package/src/wirings/node/index.ts +2 -0
- package/src/wirings/node/node.types.ts +23 -0
- package/src/wirings/oauth2/index.ts +3 -0
- package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
- package/src/wirings/oauth2/oauth2-client.ts +335 -0
- package/src/wirings/oauth2/oauth2.types.ts +69 -0
- package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
- package/src/wirings/queue/index.ts +31 -0
- package/src/wirings/queue/queue-runner.test.ts +710 -0
- package/src/wirings/queue/queue-runner.ts +192 -0
- package/src/wirings/queue/queue.types.ts +189 -0
- package/src/wirings/queue/register-queue-helper.ts +60 -0
- package/src/wirings/queue/validate-worker-config.test.ts +108 -0
- package/src/wirings/queue/validate-worker-config.ts +116 -0
- package/src/wirings/rpc/index.ts +4 -0
- package/src/wirings/rpc/rpc-runner.ts +460 -0
- package/src/wirings/rpc/rpc-types.ts +56 -0
- package/src/wirings/rpc/wire-addon.ts +21 -0
- package/src/wirings/scheduler/index.ts +11 -0
- package/src/wirings/scheduler/log-schedulers.ts +20 -0
- package/src/wirings/scheduler/scheduler-runner.test.ts +660 -0
- package/src/wirings/scheduler/scheduler-runner.ts +133 -0
- package/src/wirings/scheduler/scheduler.types.ts +53 -0
- package/src/wirings/secret/index.ts +9 -0
- package/src/wirings/secret/secret.types.ts +32 -0
- package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
- package/src/wirings/secret/validate-secret-definitions.ts +82 -0
- package/src/wirings/trigger/index.ts +10 -0
- package/src/wirings/trigger/pikku-trigger-service.ts +112 -0
- package/src/wirings/trigger/trigger-runner.test.ts +79 -0
- package/src/wirings/trigger/trigger-runner.ts +135 -0
- package/src/wirings/trigger/trigger.types.ts +178 -0
- package/src/wirings/variable/index.ts +8 -0
- package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
- package/src/wirings/variable/validate-variable-definitions.ts +69 -0
- package/src/wirings/variable/variable.types.ts +22 -0
- package/src/wirings/workflow/dsl/index.ts +31 -0
- package/src/wirings/workflow/dsl/workflow-dsl.types.ts +320 -0
- package/src/wirings/workflow/dsl/workflow-runner.ts +28 -0
- package/src/wirings/workflow/graph/graph-node.ts +222 -0
- package/src/wirings/workflow/graph/graph-runner.test.ts +487 -0
- package/src/wirings/workflow/graph/graph-runner.ts +816 -0
- package/src/wirings/workflow/graph/graph-validation.test.ts +170 -0
- package/src/wirings/workflow/graph/graph-validation.ts +237 -0
- package/src/wirings/workflow/graph/index.ts +19 -0
- package/src/wirings/workflow/graph/template.test.ts +49 -0
- package/src/wirings/workflow/graph/template.ts +42 -0
- package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
- package/src/wirings/workflow/graph/workflow-graph.types.ts +104 -0
- package/src/wirings/workflow/index.ts +82 -0
- package/src/wirings/workflow/pikku-workflow-service.test.ts +200 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +1229 -0
- package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
- package/src/wirings/workflow/workflow-helpers.ts +79 -0
- package/src/wirings/workflow/workflow.types.ts +276 -0
- package/tsconfig.json +14 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/lcov.info +0 -18891
package/CHANGELOG.md
CHANGED
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
## 0.12.
|
|
1
|
+
## 0.12.4
|
|
2
|
+
|
|
3
|
+
## 0.12.6
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- bb27710: Add optional `uploadHeaders` to `ContentService.getUploadURL` return type, allowing storage backends (e.g. Backblaze B2) to provide required headers for direct uploads.
|
|
8
|
+
- a31bc63: Fix SSE error handler to send `[DONE]` as JSON (`{"type":"done"}`) for consistency with all other SSE messages.
|
|
9
|
+
- 3e79248: Add setStepChildRunId to workflow service implementations and auto-bootstrap in pikku all
|
|
10
|
+
- b0a81cc: Support sub-workflows in `workflow.do()`: when a string name is passed, it now checks if the name refers to a registered workflow and runs it as a sub-workflow, falling back to RPC invocation if not found. The `TypedWorkflow.do` type now also accepts workflow names with typed input/output. Steps that spawn sub-workflows expose `childRunId` on the step state so clients can stream sub-workflow progress.
|
|
11
|
+
- 6413df7: Propagate session and RPC service from the originating request to workflow runs, fixing "Authentication required" errors for workflows with `auth: true`.
|
|
12
|
+
|
|
13
|
+
## 0.12.5
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 198e68f: Add hot-reload for dev mode: reload functions, middleware, and permissions without server restart.
|
|
2
18
|
|
|
3
19
|
## 0.12.4
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
|
6
22
|
|
|
23
|
+
- 688b5e8: InMemoryWorkflowService now implements WorkflowRunService interface, adding listRuns, getRunSteps, getDistinctWorkflowNames, and deleteRun methods.
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
7
27
|
- InMemoryWorkflowService now implements WorkflowRunService interface (listRuns, getRunSteps, getDistinctWorkflowNames, deleteRun)
|
|
8
28
|
|
|
9
29
|
## 0.12.3
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Logger } from '../services/logger.js';
|
|
2
|
+
interface PikkuDevReloaderOptions {
|
|
3
|
+
srcDirectories: string[];
|
|
4
|
+
logger: Logger;
|
|
5
|
+
pikkuDir?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function pikkuDevReloader(options: PikkuDevReloaderOptions): Promise<{
|
|
8
|
+
close: () => void;
|
|
9
|
+
}>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { watch } from 'node:fs';
|
|
2
|
+
import { stat, readFile } from 'node:fs/promises';
|
|
3
|
+
import { join, resolve, relative } from 'node:path';
|
|
4
|
+
import { pikkuState } from '../pikku-state.js';
|
|
5
|
+
import { addFunction } from '../function/function-runner.js';
|
|
6
|
+
import { clearMiddlewareCache } from '../middleware-runner.js';
|
|
7
|
+
import { clearPermissionsCache } from '../permissions.js';
|
|
8
|
+
import { clearChannelMiddlewareCache } from '../wirings/channel/channel-middleware-runner.js';
|
|
9
|
+
import { httpRouter } from '../wirings/http/routers/http-router.js';
|
|
10
|
+
import { addSchema, compileAllSchemas } from '../schema.js';
|
|
11
|
+
const isFunctionConfig = (value) => {
|
|
12
|
+
return (typeof value === 'object' &&
|
|
13
|
+
value !== null &&
|
|
14
|
+
'func' in value &&
|
|
15
|
+
typeof value.func === 'function');
|
|
16
|
+
};
|
|
17
|
+
const findCompiledFile = async (tsFile, srcDir, pikkuDir) => {
|
|
18
|
+
const rel = relative(srcDir, tsFile).replace(/\.ts$/, '.js');
|
|
19
|
+
const candidates = [
|
|
20
|
+
join(pikkuDir, 'dist', rel),
|
|
21
|
+
join(srcDir, rel),
|
|
22
|
+
tsFile.replace(/\.ts$/, '.js'),
|
|
23
|
+
];
|
|
24
|
+
for (const candidate of candidates) {
|
|
25
|
+
try {
|
|
26
|
+
await stat(candidate);
|
|
27
|
+
return candidate;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
// not found, try next
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
};
|
|
35
|
+
// Use data: URLs to import modules. This bypasses TypeScript loaders
|
|
36
|
+
// (e.g. tsx) that intercept file:// imports and break dynamic ESM loading.
|
|
37
|
+
// Each import gets unique content so there's no module cache to worry about.
|
|
38
|
+
const reimportModule = async (filePath) => {
|
|
39
|
+
try {
|
|
40
|
+
const content = await readFile(resolve(filePath), 'utf-8');
|
|
41
|
+
const dataUrl = 'data:text/javascript;base64,' + Buffer.from(content).toString('base64');
|
|
42
|
+
return await import(dataUrl);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const isWatchedTsFile = (filename) => {
|
|
49
|
+
return (filename.endsWith('.ts') &&
|
|
50
|
+
!filename.endsWith('.test.ts') &&
|
|
51
|
+
!filename.endsWith('.d.ts') &&
|
|
52
|
+
!filename.endsWith('.gen.ts'));
|
|
53
|
+
};
|
|
54
|
+
export async function pikkuDevReloader(options) {
|
|
55
|
+
const { srcDirectories, logger, pikkuDir = '.pikku' } = options;
|
|
56
|
+
const absSrcDirs = srcDirectories.map((d) => resolve(d));
|
|
57
|
+
const absPikkuDir = resolve(pikkuDir);
|
|
58
|
+
const watchers = [];
|
|
59
|
+
const functionsMap = pikkuState(null, 'function', 'functions');
|
|
60
|
+
const handleFileChange = async (changedTsFile) => {
|
|
61
|
+
const start = Date.now();
|
|
62
|
+
const reloadedNames = [];
|
|
63
|
+
const srcDir = absSrcDirs.find((d) => changedTsFile.startsWith(d));
|
|
64
|
+
if (!srcDir)
|
|
65
|
+
return;
|
|
66
|
+
const compiledFile = await findCompiledFile(changedTsFile, srcDir, absPikkuDir);
|
|
67
|
+
if (!compiledFile) {
|
|
68
|
+
logger.warn(`Could not find compiled JS for: ${relative(process.cwd(), changedTsFile)}`);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const mod = await reimportModule(compiledFile);
|
|
72
|
+
if (!mod) {
|
|
73
|
+
logger.error(`Failed to import: ${relative(process.cwd(), compiledFile)} (keeping old code)`);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
let schemasChanged = false;
|
|
77
|
+
for (const [exportName, exportValue] of Object.entries(mod)) {
|
|
78
|
+
if (isFunctionConfig(exportValue) && functionsMap.has(exportName)) {
|
|
79
|
+
addFunction(exportName, exportValue);
|
|
80
|
+
reloadedNames.push(exportName);
|
|
81
|
+
if (exportValue.input) {
|
|
82
|
+
addSchema(exportName, exportValue.input);
|
|
83
|
+
schemasChanged = true;
|
|
84
|
+
}
|
|
85
|
+
if (exportValue.output) {
|
|
86
|
+
addSchema(`${exportName}Output`, exportValue.output);
|
|
87
|
+
schemasChanged = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (reloadedNames.length > 0) {
|
|
92
|
+
clearMiddlewareCache();
|
|
93
|
+
clearPermissionsCache();
|
|
94
|
+
clearChannelMiddlewareCache();
|
|
95
|
+
httpRouter.reset();
|
|
96
|
+
if (schemasChanged) {
|
|
97
|
+
try {
|
|
98
|
+
compileAllSchemas(logger);
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
102
|
+
if (msg.includes('SchemaService') ||
|
|
103
|
+
(msg.includes('schema') && msg.includes('not'))) {
|
|
104
|
+
logger.warn('Schema recompilation skipped (no SchemaService)');
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
logger.error(`Schema recompilation failed: ${msg}`);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const elapsed = Date.now() - start;
|
|
113
|
+
logger.info(`Hot-reloaded: ${reloadedNames.join(', ')} (${elapsed}ms)`);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
let debounceTimer;
|
|
117
|
+
const pendingChanges = new Set();
|
|
118
|
+
const scheduleReload = (filePath) => {
|
|
119
|
+
pendingChanges.add(filePath);
|
|
120
|
+
if (debounceTimer)
|
|
121
|
+
clearTimeout(debounceTimer);
|
|
122
|
+
debounceTimer = setTimeout(async () => {
|
|
123
|
+
const files = [...pendingChanges];
|
|
124
|
+
pendingChanges.clear();
|
|
125
|
+
for (const file of files) {
|
|
126
|
+
try {
|
|
127
|
+
await handleFileChange(file);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
logger.error(`Hot-reload error for ${relative(process.cwd(), file)}: ${err instanceof Error ? err.message : String(err)}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}, 50);
|
|
134
|
+
};
|
|
135
|
+
for (const srcDir of absSrcDirs) {
|
|
136
|
+
try {
|
|
137
|
+
const watcher = watch(srcDir, { recursive: true }, (eventType, filename) => {
|
|
138
|
+
if (filename && isWatchedTsFile(filename)) {
|
|
139
|
+
scheduleReload(join(srcDir, filename));
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
watchers.push(watcher);
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
logger.error(`Failed to watch directory ${srcDir}: ${err?.message || err}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
logger.info(`Hot-reload active for: ${srcDirectories.join(', ')}`);
|
|
149
|
+
return {
|
|
150
|
+
close: () => {
|
|
151
|
+
if (debounceTimer)
|
|
152
|
+
clearTimeout(debounceTimer);
|
|
153
|
+
for (const watcher of watchers) {
|
|
154
|
+
watcher.close();
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
}
|
|
@@ -51,6 +51,7 @@ export declare const runMiddleware: <Middleware extends CorePikkuMiddleware>(ser
|
|
|
51
51
|
* ```
|
|
52
52
|
*/
|
|
53
53
|
export declare const addMiddleware: <PikkuMiddleware extends CorePikkuMiddleware>(tag: string, middleware: CorePikkuMiddlewareGroup, packageName?: string | null) => CorePikkuMiddlewareGroup;
|
|
54
|
+
export declare const clearMiddlewareCache: () => void;
|
|
54
55
|
/**
|
|
55
56
|
* Combines wiring-specific middleware with function-level middleware.
|
|
56
57
|
*
|
|
@@ -98,6 +98,11 @@ const middlewareCache = {
|
|
|
98
98
|
workflow: {},
|
|
99
99
|
gateway: {},
|
|
100
100
|
};
|
|
101
|
+
export const clearMiddlewareCache = () => {
|
|
102
|
+
for (const key of Object.keys(middlewareCache)) {
|
|
103
|
+
middlewareCache[key] = {};
|
|
104
|
+
}
|
|
105
|
+
};
|
|
101
106
|
/**
|
|
102
107
|
* Combines wiring-specific middleware with function-level middleware.
|
|
103
108
|
*
|
package/dist/permissions.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ import type { CorePermissionGroup, CorePikkuPermission } from './function/functi
|
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
31
|
export declare const addPermission: (tag: string, permissions: CorePermissionGroup | CorePikkuPermission[], packageName?: string | null) => CorePermissionGroup | CorePikkuPermission[];
|
|
32
|
+
export declare const clearPermissionsCache: () => void;
|
|
32
33
|
/**
|
|
33
34
|
* Runs permission checks using combined permissions from all sources.
|
|
34
35
|
* Combines permissions from wire and function levels, then validates them.
|
package/dist/permissions.js
CHANGED
|
@@ -101,6 +101,11 @@ const combinedPermissionsCache = {
|
|
|
101
101
|
workflow: {},
|
|
102
102
|
gateway: {},
|
|
103
103
|
};
|
|
104
|
+
export const clearPermissionsCache = () => {
|
|
105
|
+
for (const key of Object.keys(combinedPermissionsCache)) {
|
|
106
|
+
combinedPermissionsCache[key] = {};
|
|
107
|
+
}
|
|
108
|
+
};
|
|
104
109
|
/**
|
|
105
110
|
* Combines wiring-specific permissions with function-level permissions.
|
|
106
111
|
*
|
|
@@ -22,6 +22,8 @@ export interface ContentService {
|
|
|
22
22
|
getUploadURL(fileKey: string, contentType: string): Promise<{
|
|
23
23
|
uploadUrl: string;
|
|
24
24
|
assetKey: string;
|
|
25
|
+
uploadHeaders?: Record<string, string>;
|
|
26
|
+
uploadMethod?: 'PUT' | 'POST';
|
|
25
27
|
}>;
|
|
26
28
|
/**
|
|
27
29
|
* Deletes a file from the storage backend.
|
|
@@ -36,6 +36,7 @@ export declare class InMemoryWorkflowService extends PikkuWorkflowService implem
|
|
|
36
36
|
setStepScheduled(stepId: string): Promise<void>;
|
|
37
37
|
setStepResult(stepId: string, result: any): Promise<void>;
|
|
38
38
|
setStepError(stepId: string, error: Error): Promise<void>;
|
|
39
|
+
setStepChildRunId(stepId: string, childRunId: string): Promise<void>;
|
|
39
40
|
createRetryAttempt(failedStepId: string, status: 'pending' | 'running'): Promise<StepState>;
|
|
40
41
|
listRuns(options?: {
|
|
41
42
|
workflowName?: string;
|
|
@@ -73,13 +73,14 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
73
73
|
retryDelay: stepOptions?.retryDelay,
|
|
74
74
|
createdAt: now,
|
|
75
75
|
updatedAt: now,
|
|
76
|
+
stepName,
|
|
76
77
|
};
|
|
77
78
|
const key = `${runId}:${stepName}`;
|
|
78
79
|
this.steps.set(key, step);
|
|
79
80
|
this.stepData.set(stepId, { rpcName, data, stepName });
|
|
80
|
-
// Add to history
|
|
81
|
+
// Add to history (same reference so mutations are reflected)
|
|
81
82
|
const history = this.stepHistory.get(runId) || [];
|
|
82
|
-
history.push(
|
|
83
|
+
history.push(step);
|
|
83
84
|
this.stepHistory.set(runId, history);
|
|
84
85
|
return step;
|
|
85
86
|
}
|
|
@@ -87,13 +88,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
87
88
|
const key = `${runId}:${stepName}`;
|
|
88
89
|
const step = this.steps.get(key);
|
|
89
90
|
if (!step) {
|
|
90
|
-
|
|
91
|
-
stepId: '',
|
|
92
|
-
status: 'pending',
|
|
93
|
-
attemptCount: 0,
|
|
94
|
-
createdAt: new Date(),
|
|
95
|
-
updatedAt: new Date(),
|
|
96
|
-
};
|
|
91
|
+
throw new Error(`Step not found: runId=${runId}, stepName=${stepName}. Use insertStepState to create it.`);
|
|
97
92
|
}
|
|
98
93
|
return step;
|
|
99
94
|
}
|
|
@@ -143,6 +138,15 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
143
138
|
}
|
|
144
139
|
}
|
|
145
140
|
}
|
|
141
|
+
async setStepChildRunId(stepId, childRunId) {
|
|
142
|
+
for (const step of this.steps.values()) {
|
|
143
|
+
if (step.stepId === stepId) {
|
|
144
|
+
step.childRunId = childRunId;
|
|
145
|
+
step.updatedAt = new Date();
|
|
146
|
+
break;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
146
150
|
async createRetryAttempt(failedStepId, status) {
|
|
147
151
|
// Find the failed step
|
|
148
152
|
let failedStep;
|
|
@@ -171,6 +175,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
171
175
|
retryDelay: failedStep.retryDelay,
|
|
172
176
|
createdAt: now,
|
|
173
177
|
updatedAt: now,
|
|
178
|
+
stepName: stepName,
|
|
174
179
|
};
|
|
175
180
|
if (status === 'running') {
|
|
176
181
|
newStep.runningAt = now;
|
|
@@ -181,9 +186,9 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
181
186
|
if (failedStepData) {
|
|
182
187
|
this.stepData.set(newStepId, { ...failedStepData });
|
|
183
188
|
}
|
|
184
|
-
// Add to history
|
|
189
|
+
// Add to history (same reference so mutations are reflected)
|
|
185
190
|
const history = this.stepHistory.get(runId) || [];
|
|
186
|
-
history.push(
|
|
191
|
+
history.push(newStep);
|
|
187
192
|
this.stepHistory.set(runId, history);
|
|
188
193
|
return newStep;
|
|
189
194
|
}
|
|
@@ -31,6 +31,7 @@ export interface WorkflowService {
|
|
|
31
31
|
setStepRunning(stepId: string): Promise<void>;
|
|
32
32
|
setStepScheduled(stepId: string): Promise<void>;
|
|
33
33
|
setStepResult(stepId: string, result: any): Promise<void>;
|
|
34
|
+
setStepChildRunId(stepId: string, childRunId: string): Promise<void>;
|
|
34
35
|
setStepError(stepId: string, error: Error): Promise<void>;
|
|
35
36
|
createRetryAttempt(stepId: string, status: 'pending' | 'running'): Promise<StepState>;
|
|
36
37
|
executeWorkflowStep(runId: string, stepName: string, rpcName: string | null, data: any, rpcService: any): Promise<void>;
|
|
@@ -5,7 +5,7 @@ import { randomUUID } from 'crypto';
|
|
|
5
5
|
import { streamAIAgent } from './ai-agent-stream.js';
|
|
6
6
|
import { runAIAgent } from './ai-agent-runner.js';
|
|
7
7
|
import { resolveNamespace, ContextAwareRPCService, } from '../../wirings/rpc/rpc-runner.js';
|
|
8
|
-
import { buildDynamicWorkflowInstructions, buildWorkflowTools } from './agent-dynamic-workflow.js';
|
|
8
|
+
import { buildDynamicWorkflowInstructions, buildWorkflowTools, } from './agent-dynamic-workflow.js';
|
|
9
9
|
import { resolveMemoryServices, loadContextMessages, trimMessages, } from './ai-agent-memory.js';
|
|
10
10
|
import { resolveModelConfig } from './ai-agent-model-config.js';
|
|
11
11
|
export class ToolApprovalRequired extends PikkuError {
|
|
@@ -272,6 +272,21 @@ export async function buildToolDefs(params, agentSessionMap, resourceId, agentNa
|
|
|
272
272
|
}
|
|
273
273
|
// No stream context: sub-agent runs non-streaming
|
|
274
274
|
const result = await runAIAgent(subAgentName, { message, threadId, resourceId }, params, agentSessionMap);
|
|
275
|
+
if (result.status === 'suspended' &&
|
|
276
|
+
result.pendingApprovals?.length) {
|
|
277
|
+
return {
|
|
278
|
+
__approvalRequired: true,
|
|
279
|
+
toolName: subAgentName,
|
|
280
|
+
args: toolInput,
|
|
281
|
+
agentRunId: result.runId,
|
|
282
|
+
subApprovals: result.pendingApprovals.map((a) => ({
|
|
283
|
+
toolCallId: a.toolCallId,
|
|
284
|
+
toolName: a.toolName,
|
|
285
|
+
args: a.args,
|
|
286
|
+
runId: a.runId,
|
|
287
|
+
})),
|
|
288
|
+
};
|
|
289
|
+
}
|
|
275
290
|
return result.object ?? result.text;
|
|
276
291
|
},
|
|
277
292
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CoreSingletonServices, MiddlewareMetadata, PikkuWire } from '../../types/core.types.js';
|
|
2
2
|
import type { CorePikkuChannelMiddleware } from './channel.types.js';
|
|
3
3
|
export declare const addChannelMiddleware: (tag: string, middleware: CorePikkuChannelMiddleware[], packageName?: string | null) => CorePikkuChannelMiddleware[];
|
|
4
|
+
export declare const clearChannelMiddlewareCache: () => void;
|
|
4
5
|
export declare const combineChannelMiddleware: (wireType: string, uid: string, { wireInheritedChannelMiddleware, wireChannelMiddleware, packageName, }?: {
|
|
5
6
|
wireInheritedChannelMiddleware?: MiddlewareMetadata[];
|
|
6
7
|
wireChannelMiddleware?: CorePikkuChannelMiddleware[];
|
|
@@ -11,6 +11,11 @@ const getChannelMiddlewareByName = (name) => {
|
|
|
11
11
|
return middleware?.[0];
|
|
12
12
|
};
|
|
13
13
|
const channelMiddlewareCache = {};
|
|
14
|
+
export const clearChannelMiddlewareCache = () => {
|
|
15
|
+
for (const key of Object.keys(channelMiddlewareCache)) {
|
|
16
|
+
delete channelMiddlewareCache[key];
|
|
17
|
+
}
|
|
18
|
+
};
|
|
14
19
|
export const combineChannelMiddleware = (wireType, uid, { wireInheritedChannelMiddleware, wireChannelMiddleware, packageName = null, } = {}) => {
|
|
15
20
|
const cacheKey = `${wireType}:${uid}`;
|
|
16
21
|
if (channelMiddlewareCache[cacheKey]) {
|
|
@@ -402,7 +402,7 @@ export const fetchData = async (request, response, { skipUserSession = false, re
|
|
|
402
402
|
type: 'error',
|
|
403
403
|
errorText: e instanceof Error ? e.message : String(e),
|
|
404
404
|
}));
|
|
405
|
-
response.arrayBuffer('
|
|
405
|
+
response.arrayBuffer(JSON.stringify({ type: 'done' }));
|
|
406
406
|
}
|
|
407
407
|
catch (streamErr) {
|
|
408
408
|
singletonServices.logger.error(`SSE error while sending error payload: ${streamErr instanceof Error ? streamErr.message : String(streamErr)}`);
|
|
@@ -119,6 +119,12 @@ export declare abstract class PikkuWorkflowService implements WorkflowService {
|
|
|
119
119
|
* @param result - Step result
|
|
120
120
|
*/
|
|
121
121
|
abstract setStepResult(stepId: string, result: any): Promise<void>;
|
|
122
|
+
/**
|
|
123
|
+
* Set the child workflow run ID on a step
|
|
124
|
+
* @param stepId - Step ID
|
|
125
|
+
* @param childRunId - Child workflow run ID
|
|
126
|
+
*/
|
|
127
|
+
abstract setStepChildRunId(stepId: string, childRunId: string): Promise<void>;
|
|
122
128
|
/**
|
|
123
129
|
* Store step error and mark as failed
|
|
124
130
|
* Updates both workflow_step and workflow_step_history
|
|
@@ -175,17 +175,16 @@ export class PikkuWorkflowService {
|
|
|
175
175
|
if (!workflowMeta.graphHash) {
|
|
176
176
|
throw new Error(`Missing workflow graphHash for '${name}'`);
|
|
177
177
|
}
|
|
178
|
-
const
|
|
179
|
-
|
|
178
|
+
const shouldInline = options?.inline || !getSingletonServices()?.queueService;
|
|
179
|
+
const runId = await this.createRun(name, input, shouldInline, workflowMeta.graphHash, wire);
|
|
180
|
+
if (shouldInline) {
|
|
180
181
|
this.inlineRuns.add(runId);
|
|
181
|
-
}
|
|
182
|
-
if (options?.inline || !getSingletonServices()?.queueService) {
|
|
183
182
|
this.runWorkflowJob(runId, rpcService)
|
|
184
|
-
.catch(() => {
|
|
183
|
+
.catch((err) => {
|
|
184
|
+
getSingletonServices().logger.error(`Workflow ${name} (run ${runId}) failed:`, err);
|
|
185
|
+
})
|
|
185
186
|
.finally(() => {
|
|
186
|
-
|
|
187
|
-
this.inlineRuns.delete(runId);
|
|
188
|
-
}
|
|
187
|
+
this.inlineRuns.delete(runId);
|
|
189
188
|
});
|
|
190
189
|
}
|
|
191
190
|
else {
|
|
@@ -237,7 +236,11 @@ export class PikkuWorkflowService {
|
|
|
237
236
|
}
|
|
238
237
|
await this.withRunLock(runId, async () => {
|
|
239
238
|
const workflowWire = this.createWorkflowWire(run.workflow, runId, rpcService);
|
|
240
|
-
const wire = {
|
|
239
|
+
const wire = {
|
|
240
|
+
workflow: workflowWire,
|
|
241
|
+
session: rpcService.wire?.session,
|
|
242
|
+
rpc: rpcService.wire?.rpc,
|
|
243
|
+
};
|
|
241
244
|
try {
|
|
242
245
|
const result = await runPikkuFunc('workflow', workflowMeta.name, workflowMeta.pikkuFuncId, {
|
|
243
246
|
singletonServices: getSingletonServices(),
|
|
@@ -460,13 +463,45 @@ export class PikkuWorkflowService {
|
|
|
460
463
|
while (true) {
|
|
461
464
|
try {
|
|
462
465
|
await this.setStepRunning(currentStepState.stepId);
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
466
|
+
// Check if the name refers to a workflow
|
|
467
|
+
const workflowMeta = pikkuState(null, 'workflows', 'meta')[rpcName];
|
|
468
|
+
let result;
|
|
469
|
+
if (workflowMeta) {
|
|
470
|
+
const childWire = {
|
|
471
|
+
type: 'workflow',
|
|
472
|
+
id: rpcName,
|
|
473
|
+
parentRunId: runId,
|
|
474
|
+
};
|
|
475
|
+
const { runId: childRunId } = await this.startWorkflow(rpcName, data, childWire, rpcService, { inline: true });
|
|
476
|
+
await this.setStepChildRunId(currentStepState.stepId, childRunId);
|
|
477
|
+
// Poll until child workflow completes
|
|
478
|
+
while (true) {
|
|
479
|
+
const childRun = await this.getRun(childRunId);
|
|
480
|
+
if (!childRun) {
|
|
481
|
+
throw new WorkflowRunNotFoundError(childRunId);
|
|
482
|
+
}
|
|
483
|
+
if (WORKFLOW_END_STATES.has(childRun.status)) {
|
|
484
|
+
if (childRun.status === 'failed') {
|
|
485
|
+
throw new Error(childRun.error?.message || 'Sub-workflow failed');
|
|
486
|
+
}
|
|
487
|
+
if (childRun.status === 'cancelled') {
|
|
488
|
+
throw new Error('Sub-workflow was cancelled');
|
|
489
|
+
}
|
|
490
|
+
result = childRun.output;
|
|
491
|
+
break;
|
|
492
|
+
}
|
|
493
|
+
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
result = await rpcService.rpcWithWire(rpcName, data, {
|
|
498
|
+
workflowStep: {
|
|
499
|
+
runId,
|
|
500
|
+
stepId: currentStepState.stepId,
|
|
501
|
+
attemptCount: currentStepState.attemptCount,
|
|
502
|
+
},
|
|
503
|
+
});
|
|
504
|
+
}
|
|
470
505
|
await this.setStepResult(currentStepState.stepId, result);
|
|
471
506
|
return result;
|
|
472
507
|
}
|
|
@@ -76,6 +76,8 @@ export interface StepState {
|
|
|
76
76
|
createdAt: Date;
|
|
77
77
|
/** Last update timestamp */
|
|
78
78
|
updatedAt: Date;
|
|
79
|
+
/** Child workflow run ID (if this step spawned a sub-workflow) */
|
|
80
|
+
childRunId?: string;
|
|
79
81
|
/** Timestamp when step started running */
|
|
80
82
|
runningAt?: Date;
|
|
81
83
|
/** Timestamp when step was scheduled */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.6",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
"release": "npm run build && npm test",
|
|
14
14
|
"test": "bash run-tests.sh",
|
|
15
15
|
"test:watch": "bash run-tests.sh --watch",
|
|
16
|
-
"test:coverage": "bash run-tests.sh --coverage"
|
|
16
|
+
"test:coverage": "bash run-tests.sh --coverage",
|
|
17
|
+
"prepublishOnly": "yarn build"
|
|
17
18
|
},
|
|
18
19
|
"exports": {
|
|
19
20
|
".": "./dist/index.js",
|
|
@@ -44,7 +45,8 @@
|
|
|
44
45
|
"./crypto-utils": "./dist/crypto-utils.js",
|
|
45
46
|
"./internal": "./dist/internal.js",
|
|
46
47
|
"./schema": "./dist/schema.js",
|
|
47
|
-
"./testing": "./dist/testing/index.js"
|
|
48
|
+
"./testing": "./dist/testing/index.js",
|
|
49
|
+
"./dev": "./dist/dev/hot-reload.js"
|
|
48
50
|
},
|
|
49
51
|
"dependencies": {
|
|
50
52
|
"@standard-schema/spec": "^1.1.0",
|