@portel/photon 1.31.2 → 1.32.2
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/README.md +3 -3
- package/dist/auto-ui/beam.d.ts +8 -0
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +88 -10
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +65 -21
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/daemon/manager.d.ts +11 -1
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +113 -8
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/server.js +26 -20
- package/dist/daemon/server.js.map +1 -1
- package/dist/loader.d.ts +11 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +169 -11
- package/dist/loader.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +53 -16
- package/dist/server.js.map +1 -1
- package/dist/settings-persistence.d.ts.map +1 -1
- package/dist/settings-persistence.js +10 -3
- package/dist/settings-persistence.js.map +1 -1
- package/dist/telemetry/context.d.ts +7 -0
- package/dist/telemetry/context.d.ts.map +1 -1
- package/dist/telemetry/context.js +71 -0
- package/dist/telemetry/context.js.map +1 -1
- package/package.json +1 -1
package/dist/loader.d.ts
CHANGED
|
@@ -224,6 +224,10 @@ export declare class PhotonLoader {
|
|
|
224
224
|
* Delegates to shared compilePhotonTS from photon-core
|
|
225
225
|
*/
|
|
226
226
|
private compileTypeScript;
|
|
227
|
+
private compileTypeScriptWithLocalImports;
|
|
228
|
+
private resolveLocalTypeScriptImports;
|
|
229
|
+
private resolveLocalTypeScriptImport;
|
|
230
|
+
private rewriteCompiledLocalImports;
|
|
227
231
|
/**
|
|
228
232
|
* Find the MCP class in a module
|
|
229
233
|
* Delegates to shared findPhotonClass from photon-core
|
|
@@ -367,7 +371,14 @@ export declare class PhotonLoader {
|
|
|
367
371
|
caller?: CallerInfo;
|
|
368
372
|
traceId?: string;
|
|
369
373
|
parentTraceparent?: string;
|
|
374
|
+
signal?: AbortSignal;
|
|
370
375
|
}): Promise<any>;
|
|
376
|
+
/**
|
|
377
|
+
* Long-lived subscription tools are async generators. They must not hold
|
|
378
|
+
* the stateful instance gate for their entire stream lifetime, or every
|
|
379
|
+
* ordinary request to the same photon queues behind the subscription.
|
|
380
|
+
*/
|
|
381
|
+
private _isAsyncGeneratorTool;
|
|
371
382
|
/**
|
|
372
383
|
* Serialize calls targeting the same photon instance. Concurrent callers
|
|
373
384
|
* queue behind the current in-flight call; each invocation gets an exclusive
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,EAAiC,KAAK,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAwB7F,OAAO,EAGL,gBAAgB,EAChB,WAAW,EACX,mBAAmB,
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/loader.js
CHANGED
|
@@ -17,11 +17,11 @@ import { fileURLToPath, pathToFileURL } from 'url';
|
|
|
17
17
|
import * as crypto from 'crypto';
|
|
18
18
|
import { startToolSpan } from './telemetry/otel.js';
|
|
19
19
|
import { recordToolCall, recordCircuitStateChange, recordRateLimitRejection, recordBulkheadRejection, } from './telemetry/metrics.js';
|
|
20
|
-
import { runWithRequestContext, getRequestContext } from './telemetry/context.js';
|
|
20
|
+
import { runWithRequestContext, getRequestContext, runWithPhotonDir } from './telemetry/context.js';
|
|
21
21
|
import { spawn, execSync } from 'child_process';
|
|
22
22
|
import { SchemaExtractor, DependencyManager,
|
|
23
23
|
// Generator utilities (ask/emit pattern from 1.2.0)
|
|
24
|
-
isAsyncGenerator, executeGenerator,
|
|
24
|
+
isAsyncGenerator, executeGenerator, isAskYield, isEmitYield,
|
|
25
25
|
// Implicit stateful execution (auto-detect checkpoint yields)
|
|
26
26
|
maybeStatefulExecute,
|
|
27
27
|
// Elicit for fallback
|
|
@@ -47,6 +47,62 @@ builtinRegistry, MiddlewareRegistry, buildMiddlewareChain, getCacheDir, } from '
|
|
|
47
47
|
import { getDefaultContext } from './context.js';
|
|
48
48
|
import { getInstanceStatePath } from './context-store.js';
|
|
49
49
|
import { ContextRegistry, RepeatDetector, assembleSampleParams, } from './sample-augmenter.js';
|
|
50
|
+
async function executeGeneratorWithAbort(generator, config) {
|
|
51
|
+
const { inputProvider, outputHandler, preProvidedInputs, signal } = config;
|
|
52
|
+
if (!signal) {
|
|
53
|
+
return executeGenerator(generator, { inputProvider, outputHandler, preProvidedInputs });
|
|
54
|
+
}
|
|
55
|
+
let abortHandler;
|
|
56
|
+
const aborted = new Promise((_, reject) => {
|
|
57
|
+
abortHandler = () => {
|
|
58
|
+
void generator.return(undefined).catch(() => { });
|
|
59
|
+
reject(new Error('Tool execution aborted'));
|
|
60
|
+
};
|
|
61
|
+
signal.addEventListener('abort', abortHandler, { once: true });
|
|
62
|
+
});
|
|
63
|
+
const withAbort = (promise) => {
|
|
64
|
+
if (signal.aborted) {
|
|
65
|
+
void generator.return(undefined).catch(() => { });
|
|
66
|
+
throw new Error('Tool execution aborted');
|
|
67
|
+
}
|
|
68
|
+
return Promise.race([promise, aborted]);
|
|
69
|
+
};
|
|
70
|
+
try {
|
|
71
|
+
let askIndex = 0;
|
|
72
|
+
let result = await withAbort(generator.next());
|
|
73
|
+
while (!result.done) {
|
|
74
|
+
const yielded = result.value;
|
|
75
|
+
if (isAskYield(yielded)) {
|
|
76
|
+
const askId = yielded.id || `ask_${askIndex++}`;
|
|
77
|
+
if (preProvidedInputs && askId in preProvidedInputs) {
|
|
78
|
+
result = await withAbort(generator.next(preProvidedInputs[askId]));
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const input = await withAbort(inputProvider(yielded));
|
|
82
|
+
result = await withAbort(generator.next(input));
|
|
83
|
+
}
|
|
84
|
+
else if (isEmitYield(yielded)) {
|
|
85
|
+
if (outputHandler)
|
|
86
|
+
await withAbort(Promise.resolve(outputHandler(yielded)));
|
|
87
|
+
result = await withAbort(generator.next());
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (outputHandler) {
|
|
91
|
+
await withAbort(Promise.resolve(outputHandler({ emit: 'stream', data: yielded })));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.warn('[generator] Unknown yield type without output handler:', yielded);
|
|
95
|
+
}
|
|
96
|
+
result = await withAbort(generator.next());
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return result.value;
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
if (abortHandler)
|
|
103
|
+
signal.removeEventListener('abort', abortHandler);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
50
106
|
import { MarketplaceManager } from './marketplace-manager.js';
|
|
51
107
|
import { PHOTON_VERSION, getResolvedPhotonCoreVersion } from './version.js';
|
|
52
108
|
// Timeout for external fetch requests (marketplace, GitHub)
|
|
@@ -639,7 +695,7 @@ export class PhotonLoader {
|
|
|
639
695
|
* Directory where MCP-specific dependencies are cached
|
|
640
696
|
*/
|
|
641
697
|
getDependencyCacheDir(cacheKey) {
|
|
642
|
-
return path.join(getCacheDir(
|
|
698
|
+
return path.join(getCacheDir(this.baseDir), 'dependencies', cacheKey);
|
|
643
699
|
}
|
|
644
700
|
getBuildCacheDir(cacheKey) {
|
|
645
701
|
return path.join(this.getDependencyCacheDir(cacheKey), '.build');
|
|
@@ -906,14 +962,14 @@ export class PhotonLoader {
|
|
|
906
962
|
return await import(`${fileUrl}?t=${Date.now()}`);
|
|
907
963
|
};
|
|
908
964
|
try {
|
|
909
|
-
module = await importModule
|
|
965
|
+
module = await runWithPhotonDir(this.baseDir, importModule);
|
|
910
966
|
}
|
|
911
967
|
catch (error) {
|
|
912
968
|
if (this.shouldRetryInstall(error) && tsContent && sourceHash && mcpName && cacheKey) {
|
|
913
969
|
this.log(`⚠️ Missing dependency detected, reinstalling dependencies for ${mcpName}`);
|
|
914
970
|
await this.clearAllCaches(cacheKey);
|
|
915
971
|
await this.ensureDependenciesWithHash(cacheKey, mcpName, dependencies, sourceHash, absolutePath);
|
|
916
|
-
module = await importModule
|
|
972
|
+
module = await runWithPhotonDir(this.baseDir, importModule);
|
|
917
973
|
}
|
|
918
974
|
else {
|
|
919
975
|
if (this.isCompilationServiceError(error) && cacheKey) {
|
|
@@ -946,7 +1002,7 @@ export class PhotonLoader {
|
|
|
946
1002
|
// Create instance with injected dependencies
|
|
947
1003
|
let instance;
|
|
948
1004
|
try {
|
|
949
|
-
instance = new MCPClass(...values);
|
|
1005
|
+
instance = (await runWithPhotonDir(this.baseDir, () => new MCPClass(...values)));
|
|
950
1006
|
}
|
|
951
1007
|
catch (error) {
|
|
952
1008
|
// Constructor threw an error (likely validation failure)
|
|
@@ -1618,7 +1674,7 @@ export class PhotonLoader {
|
|
|
1618
1674
|
// Create instance
|
|
1619
1675
|
let instance;
|
|
1620
1676
|
try {
|
|
1621
|
-
instance = new MCPClass(...values);
|
|
1677
|
+
instance = (await runWithPhotonDir(this.baseDir, () => new MCPClass(...values)));
|
|
1622
1678
|
}
|
|
1623
1679
|
catch (error) {
|
|
1624
1680
|
let constructorParams = [];
|
|
@@ -1988,10 +2044,91 @@ export class PhotonLoader {
|
|
|
1988
2044
|
*/
|
|
1989
2045
|
async compileTypeScript(tsFilePath, cacheKey, tsContent) {
|
|
1990
2046
|
const cacheDir = this.getBuildCacheDir(cacheKey);
|
|
1991
|
-
const
|
|
2047
|
+
const compiled = new Map();
|
|
2048
|
+
const result = await this.compileTypeScriptWithLocalImports(path.resolve(tsFilePath), cacheDir, compiled, tsContent);
|
|
1992
2049
|
this.log(`Compiled: ${path.basename(tsFilePath)}`, { cached: result });
|
|
1993
2050
|
return result;
|
|
1994
2051
|
}
|
|
2052
|
+
async compileTypeScriptWithLocalImports(tsFilePath, cacheDir, compiled, tsContent) {
|
|
2053
|
+
const absolutePath = path.resolve(tsFilePath);
|
|
2054
|
+
const existing = compiled.get(absolutePath);
|
|
2055
|
+
if (existing) {
|
|
2056
|
+
return existing;
|
|
2057
|
+
}
|
|
2058
|
+
const source = tsContent ?? (await readText(absolutePath));
|
|
2059
|
+
const result = await compilePhotonTS(absolutePath, { cacheDir, content: source });
|
|
2060
|
+
compiled.set(absolutePath, result);
|
|
2061
|
+
const localImports = await this.resolveLocalTypeScriptImports(source, absolutePath);
|
|
2062
|
+
if (localImports.length === 0) {
|
|
2063
|
+
return result;
|
|
2064
|
+
}
|
|
2065
|
+
const rewrites = new Map();
|
|
2066
|
+
for (const localImport of localImports) {
|
|
2067
|
+
const compiledImportPath = await this.compileTypeScriptWithLocalImports(localImport.filePath, cacheDir, compiled);
|
|
2068
|
+
const relative = path
|
|
2069
|
+
.relative(path.dirname(result), compiledImportPath)
|
|
2070
|
+
.split(path.sep)
|
|
2071
|
+
.join('/');
|
|
2072
|
+
rewrites.set(localImport.specifier, relative.startsWith('.') ? relative : `./${relative}`);
|
|
2073
|
+
}
|
|
2074
|
+
await this.rewriteCompiledLocalImports(result, rewrites);
|
|
2075
|
+
return result;
|
|
2076
|
+
}
|
|
2077
|
+
async resolveLocalTypeScriptImports(source, importerPath) {
|
|
2078
|
+
const imports = [];
|
|
2079
|
+
const seen = new Set();
|
|
2080
|
+
const importRegex = /(?:import|export)\s+(?:[^'"]*?\s+from\s+)?['"]([^'"]+)['"]|import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
|
|
2081
|
+
let match;
|
|
2082
|
+
while ((match = importRegex.exec(source)) !== null) {
|
|
2083
|
+
const specifier = match[1] ?? match[2];
|
|
2084
|
+
if (!specifier || !specifier.startsWith('.')) {
|
|
2085
|
+
continue;
|
|
2086
|
+
}
|
|
2087
|
+
const resolved = this.resolveLocalTypeScriptImport(specifier, importerPath);
|
|
2088
|
+
if (!resolved || seen.has(specifier)) {
|
|
2089
|
+
continue;
|
|
2090
|
+
}
|
|
2091
|
+
seen.add(specifier);
|
|
2092
|
+
imports.push({ specifier, filePath: resolved });
|
|
2093
|
+
}
|
|
2094
|
+
return imports;
|
|
2095
|
+
}
|
|
2096
|
+
resolveLocalTypeScriptImport(specifier, importerPath) {
|
|
2097
|
+
const basePath = path.resolve(path.dirname(importerPath), specifier);
|
|
2098
|
+
const ext = path.extname(basePath);
|
|
2099
|
+
const candidates = [];
|
|
2100
|
+
if (ext === '.ts' || ext === '.tsx') {
|
|
2101
|
+
candidates.push(basePath);
|
|
2102
|
+
}
|
|
2103
|
+
else if (ext === '.js' || ext === '.mjs') {
|
|
2104
|
+
candidates.push(basePath.slice(0, -ext.length) + '.ts');
|
|
2105
|
+
candidates.push(basePath.slice(0, -ext.length) + '.tsx');
|
|
2106
|
+
}
|
|
2107
|
+
else if (!ext) {
|
|
2108
|
+
candidates.push(basePath + '.ts');
|
|
2109
|
+
candidates.push(basePath + '.tsx');
|
|
2110
|
+
candidates.push(path.join(basePath, 'index.ts'));
|
|
2111
|
+
candidates.push(path.join(basePath, 'index.tsx'));
|
|
2112
|
+
}
|
|
2113
|
+
for (const candidate of candidates) {
|
|
2114
|
+
if (existsSync(candidate) && statSync(candidate).isFile()) {
|
|
2115
|
+
return path.resolve(candidate);
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
return null;
|
|
2119
|
+
}
|
|
2120
|
+
async rewriteCompiledLocalImports(compiledPath, rewrites) {
|
|
2121
|
+
if (rewrites.size === 0) {
|
|
2122
|
+
return;
|
|
2123
|
+
}
|
|
2124
|
+
let code = await readText(compiledPath);
|
|
2125
|
+
for (const [from, to] of rewrites) {
|
|
2126
|
+
const escaped = from.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
2127
|
+
code = code.replace(new RegExp(`((?:import|export)\\s+(?:[^'"]*?\\s+from\\s+)?)(['"])${escaped}\\2`, 'g'), `$1$2${to}$2`);
|
|
2128
|
+
code = code.replace(new RegExp(`(import\\s*\\(\\s*)(['"])${escaped}\\2(\\s*\\))`, 'g'), `$1$2${to}$2$3`);
|
|
2129
|
+
}
|
|
2130
|
+
await writeText(compiledPath, code);
|
|
2131
|
+
}
|
|
1995
2132
|
/**
|
|
1996
2133
|
* Find the MCP class in a module
|
|
1997
2134
|
* Delegates to shared findPhotonClass from photon-core
|
|
@@ -3192,16 +3329,36 @@ Run: photon mcp ${mcpName} --config
|
|
|
3192
3329
|
parentTraceparent: resolvedParentTraceparent,
|
|
3193
3330
|
caller: options?.caller,
|
|
3194
3331
|
cwd: resolvedCallerCwd,
|
|
3332
|
+
photonDir: this.baseDir,
|
|
3195
3333
|
startedAt: Date.now(),
|
|
3196
3334
|
}, () => this._executeToolInner(mcp, toolName, parameters, {
|
|
3197
3335
|
...options,
|
|
3198
3336
|
parentTraceparent: resolvedParentTraceparent,
|
|
3199
3337
|
}));
|
|
3200
3338
|
const gateKey = mcp.instance;
|
|
3201
|
-
if (!gateKey)
|
|
3339
|
+
if (!gateKey || this._isAsyncGeneratorTool(mcp, toolName))
|
|
3202
3340
|
return run();
|
|
3203
3341
|
return this._withInstanceGate(gateKey, run);
|
|
3204
3342
|
}
|
|
3343
|
+
/**
|
|
3344
|
+
* Long-lived subscription tools are async generators. They must not hold
|
|
3345
|
+
* the stateful instance gate for their entire stream lifetime, or every
|
|
3346
|
+
* ordinary request to the same photon queues behind the subscription.
|
|
3347
|
+
*/
|
|
3348
|
+
_isAsyncGeneratorTool(mcp, toolName) {
|
|
3349
|
+
const localToolName = toolName.includes('/') ? toolName.split('/').pop() : toolName;
|
|
3350
|
+
const candidates = [
|
|
3351
|
+
mcp.instance?.[localToolName],
|
|
3352
|
+
mcp.instance ? Object.getPrototypeOf(mcp.instance)?.[localToolName] : undefined,
|
|
3353
|
+
mcp.classConstructor?.[localToolName],
|
|
3354
|
+
];
|
|
3355
|
+
for (const method of candidates) {
|
|
3356
|
+
if (typeof method === 'function' && method.constructor?.name === 'AsyncGeneratorFunction') {
|
|
3357
|
+
return true;
|
|
3358
|
+
}
|
|
3359
|
+
}
|
|
3360
|
+
return false;
|
|
3361
|
+
}
|
|
3205
3362
|
/**
|
|
3206
3363
|
* Serialize calls targeting the same photon instance. Concurrent callers
|
|
3207
3364
|
* queue behind the current in-flight call; each invocation gets an exclusive
|
|
@@ -3381,9 +3538,10 @@ Run: photon mcp ${mcpName} --config
|
|
|
3381
3538
|
const result = await mcp.instance.executeTool(toolName, parameters, { outputHandler });
|
|
3382
3539
|
// Handle generator result (if tool returns a generator)
|
|
3383
3540
|
if (isAsyncGenerator(result)) {
|
|
3384
|
-
return
|
|
3541
|
+
return executeGeneratorWithAbort(result, {
|
|
3385
3542
|
inputProvider,
|
|
3386
3543
|
outputHandler,
|
|
3544
|
+
signal: options?.signal,
|
|
3387
3545
|
});
|
|
3388
3546
|
}
|
|
3389
3547
|
return result;
|
|
@@ -4140,7 +4298,7 @@ Run: photon mcp ${mcpName} --config
|
|
|
4140
4298
|
return;
|
|
4141
4299
|
this.onProgress?.('running onInitialize');
|
|
4142
4300
|
try {
|
|
4143
|
-
await hook.call(instance, ctx);
|
|
4301
|
+
await runWithPhotonDir(this.baseDir, () => hook.call(instance, ctx));
|
|
4144
4302
|
}
|
|
4145
4303
|
catch (error) {
|
|
4146
4304
|
const message = ctx
|