@pikku/core 0.12.3 → 0.12.5
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 +17 -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/in-memory-workflow-service.d.ts +15 -2
- package/dist/services/in-memory-workflow-service.js +56 -11
- 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/workflow/pikku-workflow-service.js +7 -8
- package/package.json +3 -2
- package/src/dev/hot-reload.test.ts +484 -0
- package/src/dev/hot-reload.ts +212 -0
- package/src/middleware-runner.ts +6 -0
- package/src/permissions.ts +8 -0
- package/src/services/in-memory-workflow-service.test.ts +5 -5
- package/src/services/in-memory-workflow-service.ts +78 -14
- package/src/wirings/ai-agent/ai-agent-prepare.ts +25 -2
- package/src/wirings/channel/channel-middleware-runner.ts +6 -0
- package/src/wirings/workflow/pikku-workflow-service.ts +12 -9
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
|
-
## 0.12.
|
|
1
|
+
## 0.12.4
|
|
2
|
+
|
|
3
|
+
## 0.12.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 198e68f: Add hot-reload for dev mode: reload functions, middleware, and permissions without server restart.
|
|
8
|
+
|
|
9
|
+
## 0.12.4
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- 688b5e8: InMemoryWorkflowService now implements WorkflowRunService interface, adding listRuns, getRunSteps, getDistinctWorkflowNames, and deleteRun methods.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- InMemoryWorkflowService now implements WorkflowRunService interface (listRuns, getRunSteps, getDistinctWorkflowNames, deleteRun)
|
|
2
18
|
|
|
3
19
|
## 0.12.3
|
|
4
20
|
|
|
@@ -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
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { PikkuWorkflowService } from '../wirings/workflow/pikku-workflow-service.js';
|
|
2
2
|
import type { SerializedError } from '../types/core.types.js';
|
|
3
|
-
import type { WorkflowRun, WorkflowRunWire, StepState, WorkflowStatus, WorkflowVersionStatus, WorkflowStepOptions } from '../wirings/workflow/workflow.types.js';
|
|
3
|
+
import type { WorkflowRun, WorkflowRunService, WorkflowRunWire, StepState, WorkflowStatus, WorkflowVersionStatus, WorkflowStepOptions } from '../wirings/workflow/workflow.types.js';
|
|
4
4
|
/**
|
|
5
5
|
* In-memory implementation of WorkflowService for inline-only execution
|
|
6
6
|
*
|
|
@@ -16,7 +16,7 @@ import type { WorkflowRun, WorkflowRunWire, StepState, WorkflowStatus, WorkflowV
|
|
|
16
16
|
* await workflowService.startWorkflow('myWorkflow', input, { type: 'cli' }, rpc, { inline: true })
|
|
17
17
|
* ```
|
|
18
18
|
*/
|
|
19
|
-
export declare class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
19
|
+
export declare class InMemoryWorkflowService extends PikkuWorkflowService implements WorkflowRunService {
|
|
20
20
|
private runs;
|
|
21
21
|
private steps;
|
|
22
22
|
private stepData;
|
|
@@ -37,6 +37,19 @@ export declare class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
37
37
|
setStepResult(stepId: string, result: any): Promise<void>;
|
|
38
38
|
setStepError(stepId: string, error: Error): Promise<void>;
|
|
39
39
|
createRetryAttempt(failedStepId: string, status: 'pending' | 'running'): Promise<StepState>;
|
|
40
|
+
listRuns(options?: {
|
|
41
|
+
workflowName?: string;
|
|
42
|
+
status?: string;
|
|
43
|
+
limit?: number;
|
|
44
|
+
offset?: number;
|
|
45
|
+
}): Promise<WorkflowRun[]>;
|
|
46
|
+
getRunSteps(runId: string): Promise<Array<StepState & {
|
|
47
|
+
stepName: string;
|
|
48
|
+
rpcName?: string;
|
|
49
|
+
data?: any;
|
|
50
|
+
}>>;
|
|
51
|
+
getDistinctWorkflowNames(): Promise<string[]>;
|
|
52
|
+
deleteRun(id: string): Promise<boolean>;
|
|
40
53
|
withRunLock<T>(_id: string, fn: () => Promise<T>): Promise<T>;
|
|
41
54
|
withStepLock<T>(_runId: string, _stepName: string, fn: () => Promise<T>): Promise<T>;
|
|
42
55
|
close(): Promise<void>;
|
|
@@ -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
|
}
|
|
@@ -171,6 +166,7 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
171
166
|
retryDelay: failedStep.retryDelay,
|
|
172
167
|
createdAt: now,
|
|
173
168
|
updatedAt: now,
|
|
169
|
+
stepName: stepName,
|
|
174
170
|
};
|
|
175
171
|
if (status === 'running') {
|
|
176
172
|
newStep.runningAt = now;
|
|
@@ -181,12 +177,61 @@ export class InMemoryWorkflowService extends PikkuWorkflowService {
|
|
|
181
177
|
if (failedStepData) {
|
|
182
178
|
this.stepData.set(newStepId, { ...failedStepData });
|
|
183
179
|
}
|
|
184
|
-
// Add to history
|
|
180
|
+
// Add to history (same reference so mutations are reflected)
|
|
185
181
|
const history = this.stepHistory.get(runId) || [];
|
|
186
|
-
history.push(
|
|
182
|
+
history.push(newStep);
|
|
187
183
|
this.stepHistory.set(runId, history);
|
|
188
184
|
return newStep;
|
|
189
185
|
}
|
|
186
|
+
async listRuns(options) {
|
|
187
|
+
let runs = Array.from(this.runs.values());
|
|
188
|
+
if (options?.workflowName) {
|
|
189
|
+
runs = runs.filter((r) => r.workflow === options.workflowName);
|
|
190
|
+
}
|
|
191
|
+
if (options?.status) {
|
|
192
|
+
runs = runs.filter((r) => r.status === options.status);
|
|
193
|
+
}
|
|
194
|
+
runs.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
195
|
+
const offset = options?.offset ?? 0;
|
|
196
|
+
const limit = options?.limit ?? runs.length;
|
|
197
|
+
return runs.slice(offset, offset + limit);
|
|
198
|
+
}
|
|
199
|
+
async getRunSteps(runId) {
|
|
200
|
+
const history = this.stepHistory.get(runId) || [];
|
|
201
|
+
return history.map((step) => {
|
|
202
|
+
const stepDataEntry = this.stepData.get(step.stepId);
|
|
203
|
+
return {
|
|
204
|
+
...step,
|
|
205
|
+
rpcName: stepDataEntry?.rpcName ?? undefined,
|
|
206
|
+
data: stepDataEntry?.data,
|
|
207
|
+
};
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async getDistinctWorkflowNames() {
|
|
211
|
+
const names = new Set();
|
|
212
|
+
for (const run of this.runs.values()) {
|
|
213
|
+
names.add(run.workflow);
|
|
214
|
+
}
|
|
215
|
+
return Array.from(names);
|
|
216
|
+
}
|
|
217
|
+
async deleteRun(id) {
|
|
218
|
+
const existed = this.runs.has(id);
|
|
219
|
+
this.runs.delete(id);
|
|
220
|
+
this.stepHistory.delete(id);
|
|
221
|
+
this.runState.delete(id);
|
|
222
|
+
const prefix = `${id}:`;
|
|
223
|
+
for (const key of this.steps.keys()) {
|
|
224
|
+
if (key.startsWith(prefix)) {
|
|
225
|
+
const step = this.steps.get(key);
|
|
226
|
+
if (step) {
|
|
227
|
+
this.stepData.delete(step.stepId);
|
|
228
|
+
this.branchKeys.delete(step.stepId);
|
|
229
|
+
}
|
|
230
|
+
this.steps.delete(key);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return existed;
|
|
234
|
+
}
|
|
190
235
|
async withRunLock(_id, fn) {
|
|
191
236
|
// In-memory service doesn't need locking for inline execution
|
|
192
237
|
return fn();
|
|
@@ -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]) {
|
|
@@ -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 {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pikku/core",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.5",
|
|
4
4
|
"author": "yasser.fadl@gmail.com",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -44,7 +44,8 @@
|
|
|
44
44
|
"./crypto-utils": "./dist/crypto-utils.js",
|
|
45
45
|
"./internal": "./dist/internal.js",
|
|
46
46
|
"./schema": "./dist/schema.js",
|
|
47
|
-
"./testing": "./dist/testing/index.js"
|
|
47
|
+
"./testing": "./dist/testing/index.js",
|
|
48
|
+
"./dev": "./dist/dev/hot-reload.js"
|
|
48
49
|
},
|
|
49
50
|
"dependencies": {
|
|
50
51
|
"@standard-schema/spec": "^1.1.0",
|