@portel/photon 1.19.0 → 1.20.1
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/dist/auto-ui/beam/routes/api-browse.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-browse.js +16 -4
- package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-config.js +165 -24
- package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.d.ts.map +1 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js +14 -1
- package/dist/auto-ui/beam/routes/api-marketplace.js.map +1 -1
- package/dist/auto-ui/beam.d.ts.map +1 -1
- package/dist/auto-ui/beam.js +187 -77
- package/dist/auto-ui/beam.js.map +1 -1
- package/dist/auto-ui/bridge/index.d.ts.map +1 -1
- package/dist/auto-ui/bridge/index.js +17 -0
- package/dist/auto-ui/bridge/index.js.map +1 -1
- package/dist/auto-ui/bridge/renderers.d.ts.map +1 -1
- package/dist/auto-ui/bridge/renderers.js +12 -4
- package/dist/auto-ui/bridge/renderers.js.map +1 -1
- package/dist/auto-ui/streamable-http-transport.d.ts +1 -0
- package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
- package/dist/auto-ui/streamable-http-transport.js +179 -44
- package/dist/auto-ui/streamable-http-transport.js.map +1 -1
- package/dist/auto-ui/types.d.ts +12 -0
- package/dist/auto-ui/types.d.ts.map +1 -1
- package/dist/auto-ui/types.js.map +1 -1
- package/dist/beam-form.bundle.js +63 -185
- package/dist/beam-form.bundle.js.map +4 -4
- package/dist/beam.bundle.js +2115 -761
- package/dist/beam.bundle.js.map +4 -4
- package/dist/capability-negotiator.d.ts +67 -0
- package/dist/capability-negotiator.d.ts.map +1 -0
- package/dist/capability-negotiator.js +104 -0
- package/dist/capability-negotiator.js.map +1 -0
- package/dist/channel-manager.d.ts +122 -0
- package/dist/channel-manager.d.ts.map +1 -0
- package/dist/channel-manager.js +266 -0
- package/dist/channel-manager.js.map +1 -0
- package/dist/cli/commands/beam.d.ts.map +1 -1
- package/dist/cli/commands/beam.js +47 -30
- package/dist/cli/commands/beam.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +27 -2
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/daemon.d.ts.map +1 -1
- package/dist/cli/commands/daemon.js +12 -6
- package/dist/cli/commands/daemon.js.map +1 -1
- package/dist/cli/commands/mcp.d.ts.map +1 -1
- package/dist/cli/commands/mcp.js +18 -6
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/package.d.ts.map +1 -1
- package/dist/cli/commands/package.js +25 -7
- package/dist/cli/commands/package.js.map +1 -1
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/serve.js +14 -2
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli-alias.d.ts.map +1 -1
- package/dist/cli-alias.js +2 -3
- package/dist/cli-alias.js.map +1 -1
- package/dist/context-store.d.ts +4 -4
- package/dist/context-store.d.ts.map +1 -1
- package/dist/context-store.js +18 -15
- package/dist/context-store.js.map +1 -1
- package/dist/context.d.ts +25 -2
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +69 -4
- package/dist/context.js.map +1 -1
- package/dist/daemon/client.d.ts.map +1 -1
- package/dist/daemon/client.js +16 -1
- package/dist/daemon/client.js.map +1 -1
- package/dist/daemon/manager.d.ts +2 -0
- package/dist/daemon/manager.d.ts.map +1 -1
- package/dist/daemon/manager.js +40 -8
- package/dist/daemon/manager.js.map +1 -1
- package/dist/daemon/server.js +89 -64
- package/dist/daemon/server.js.map +1 -1
- package/dist/daemon/worker-host.js +7 -0
- package/dist/daemon/worker-host.js.map +1 -1
- package/dist/daemon/worker-manager.d.ts.map +1 -1
- package/dist/daemon/worker-manager.js +79 -17
- package/dist/daemon/worker-manager.js.map +1 -1
- package/dist/daemon/worker-protocol.d.ts +3 -0
- package/dist/daemon/worker-protocol.d.ts.map +1 -1
- package/dist/deploy/cloudflare.d.ts.map +1 -1
- package/dist/deploy/cloudflare.js +2 -4
- package/dist/deploy/cloudflare.js.map +1 -1
- package/dist/loader.d.ts +11 -1
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +129 -13
- package/dist/loader.js.map +1 -1
- package/dist/marketplace-manager.d.ts +7 -1
- package/dist/marketplace-manager.d.ts.map +1 -1
- package/dist/marketplace-manager.js +165 -61
- package/dist/marketplace-manager.js.map +1 -1
- package/dist/namespace-migration.d.ts +1 -0
- package/dist/namespace-migration.d.ts.map +1 -1
- package/dist/namespace-migration.js +86 -0
- package/dist/namespace-migration.js.map +1 -1
- package/dist/photon-cli-runner.d.ts.map +1 -1
- package/dist/photon-cli-runner.js +40 -21
- package/dist/photon-cli-runner.js.map +1 -1
- package/dist/photon-doc-extractor.d.ts.map +1 -1
- package/dist/photon-doc-extractor.js +59 -15
- package/dist/photon-doc-extractor.js.map +1 -1
- package/dist/resource-server.d.ts +105 -0
- package/dist/resource-server.d.ts.map +1 -0
- package/dist/resource-server.js +723 -0
- package/dist/resource-server.js.map +1 -0
- package/dist/serv/auth/jwt.d.ts +2 -0
- package/dist/serv/auth/jwt.d.ts.map +1 -1
- package/dist/serv/auth/jwt.js +11 -5
- package/dist/serv/auth/jwt.js.map +1 -1
- package/dist/serv/vault/token-vault.d.ts +2 -0
- package/dist/serv/vault/token-vault.d.ts.map +1 -1
- package/dist/serv/vault/token-vault.js +6 -0
- package/dist/serv/vault/token-vault.js.map +1 -1
- package/dist/server.d.ts +20 -149
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +246 -1233
- package/dist/server.js.map +1 -1
- package/dist/shared/audit.d.ts.map +1 -1
- package/dist/shared/audit.js +7 -0
- package/dist/shared/audit.js.map +1 -1
- package/dist/shared/security.d.ts +10 -0
- package/dist/shared/security.d.ts.map +1 -1
- package/dist/shared/security.js +27 -0
- package/dist/shared/security.js.map +1 -1
- package/dist/shared-utils.d.ts +4 -0
- package/dist/shared-utils.d.ts.map +1 -1
- package/dist/shared-utils.js +22 -0
- package/dist/shared-utils.js.map +1 -1
- package/dist/task-executor.d.ts +69 -0
- package/dist/task-executor.d.ts.map +1 -0
- package/dist/task-executor.js +182 -0
- package/dist/task-executor.js.map +1 -0
- package/dist/template-manager.d.ts.map +1 -1
- package/dist/template-manager.js +56 -234
- package/dist/template-manager.js.map +1 -1
- package/dist/types/photon-instance.d.ts +50 -0
- package/dist/types/photon-instance.d.ts.map +1 -0
- package/dist/types/photon-instance.js +9 -0
- package/dist/types/photon-instance.js.map +1 -0
- package/dist/types/server-types.d.ts +61 -0
- package/dist/types/server-types.d.ts.map +1 -0
- package/dist/types/server-types.js +8 -0
- package/dist/types/server-types.js.map +1 -0
- package/package.json +3 -3
|
@@ -68,6 +68,28 @@ function decodeJWTCaller(authHeader) {
|
|
|
68
68
|
const sessions = new Map();
|
|
69
69
|
const pendingElicitations = new Map();
|
|
70
70
|
const APPROVALS_DIR = join(homedir(), '.photon', 'state');
|
|
71
|
+
// Simple async mutex for file operations
|
|
72
|
+
function createMutex() {
|
|
73
|
+
let locked = Promise.resolve();
|
|
74
|
+
return {
|
|
75
|
+
async acquire(fn) {
|
|
76
|
+
let release;
|
|
77
|
+
const next = new Promise((resolve) => {
|
|
78
|
+
release = resolve;
|
|
79
|
+
});
|
|
80
|
+
const prev = locked;
|
|
81
|
+
locked = next;
|
|
82
|
+
await prev;
|
|
83
|
+
try {
|
|
84
|
+
return await fn();
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
release();
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const approvalsMutex = createMutex();
|
|
71
93
|
function approvalsPath(photonName) {
|
|
72
94
|
return join(APPROVALS_DIR, photonName, 'approvals.json');
|
|
73
95
|
}
|
|
@@ -92,18 +114,22 @@ async function saveApprovals(photonName, approvals) {
|
|
|
92
114
|
await writeFile(approvalsPath(photonName), JSON.stringify(approvals, null, 2));
|
|
93
115
|
}
|
|
94
116
|
async function addApproval(approval) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
117
|
+
return approvalsMutex.acquire(async () => {
|
|
118
|
+
const approvals = await loadApprovals(approval.photon);
|
|
119
|
+
approvals.push(approval);
|
|
120
|
+
await saveApprovals(approval.photon, approvals);
|
|
121
|
+
});
|
|
98
122
|
}
|
|
99
123
|
async function resolveApproval(photonName, approvalId, status) {
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
124
|
+
return approvalsMutex.acquire(async () => {
|
|
125
|
+
const approvals = await loadApprovals(photonName);
|
|
126
|
+
const idx = approvals.findIndex((a) => a.id === approvalId);
|
|
127
|
+
if (idx === -1)
|
|
128
|
+
return undefined;
|
|
129
|
+
approvals[idx].status = status;
|
|
130
|
+
await saveApprovals(photonName, approvals);
|
|
131
|
+
return approvals[idx];
|
|
132
|
+
});
|
|
107
133
|
}
|
|
108
134
|
async function getAllPendingApprovals(photonNames) {
|
|
109
135
|
const all = [];
|
|
@@ -146,16 +172,114 @@ function parseDurationToMs(duration) {
|
|
|
146
172
|
return 5 * 60 * 1000;
|
|
147
173
|
}
|
|
148
174
|
}
|
|
175
|
+
// ── Elicitation lifecycle helpers ──
|
|
176
|
+
/** Duration before an unanswered elicitation moves to pending approvals */
|
|
177
|
+
const ELICITATION_DEFER_MS = 30_000; // 30 seconds
|
|
178
|
+
/** Maximum time an elicitation stays alive in pending queue */
|
|
179
|
+
const ELICITATION_EXPIRY_MS = 30 * 60 * 1000; // 30 minutes
|
|
180
|
+
/** Interval between progress keepalive broadcasts */
|
|
181
|
+
const KEEPALIVE_INTERVAL_MS = 25_000; // 25 seconds (under 30s SDK default)
|
|
182
|
+
/** Clean up all timers associated with a pending elicitation */
|
|
183
|
+
function cleanupElicitation(pending) {
|
|
184
|
+
if (pending.timer)
|
|
185
|
+
clearTimeout(pending.timer);
|
|
186
|
+
if (pending.deferTimer)
|
|
187
|
+
clearTimeout(pending.deferTimer);
|
|
188
|
+
if (pending.keepaliveInterval)
|
|
189
|
+
clearInterval(pending.keepaliveInterval);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Set up two-phase timeout for an elicitation:
|
|
193
|
+
* Phase 1 (30s): Modal shown to user. If no response, move to pending queue.
|
|
194
|
+
* Phase 2 (30min): Keepalive progress notifications sent. Final expiry cancels.
|
|
195
|
+
*/
|
|
196
|
+
function setupElicitationTimeout(elicitationId, pending, resolve) {
|
|
197
|
+
const photon = pending.photonName || 'unknown';
|
|
198
|
+
const method = pending.methodName || 'unknown';
|
|
199
|
+
const message = pending.message || 'Approval required';
|
|
200
|
+
// Phase 1: After 30s without response, defer to pending queue
|
|
201
|
+
pending.deferTimer = setTimeout(() => {
|
|
202
|
+
// Only defer if still pending (user may have responded)
|
|
203
|
+
if (!pendingElicitations.has(elicitationId))
|
|
204
|
+
return;
|
|
205
|
+
const approvalId = elicitationId; // reuse ID for linking
|
|
206
|
+
pending.approvalId = approvalId;
|
|
207
|
+
const expiresAt = new Date(Date.now() + ELICITATION_EXPIRY_MS).toISOString();
|
|
208
|
+
// Write to persistent approval storage (fire-and-forget, non-blocking)
|
|
209
|
+
void addApproval({
|
|
210
|
+
id: approvalId,
|
|
211
|
+
photon,
|
|
212
|
+
method,
|
|
213
|
+
message,
|
|
214
|
+
status: 'pending',
|
|
215
|
+
createdAt: new Date().toISOString(),
|
|
216
|
+
expiresAt,
|
|
217
|
+
});
|
|
218
|
+
// Tell Beam frontend to close modal and show badge
|
|
219
|
+
broadcastToBeam('beam/elicitation-deferred', {
|
|
220
|
+
elicitationId,
|
|
221
|
+
approvalId,
|
|
222
|
+
photon,
|
|
223
|
+
method,
|
|
224
|
+
message,
|
|
225
|
+
expiresAt,
|
|
226
|
+
});
|
|
227
|
+
// Start progress keepalives to prevent external MCP client timeout
|
|
228
|
+
pending.keepaliveInterval = setInterval(() => {
|
|
229
|
+
if (!pendingElicitations.has(elicitationId)) {
|
|
230
|
+
if (pending.keepaliveInterval)
|
|
231
|
+
clearInterval(pending.keepaliveInterval);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
broadcastNotification('notifications/progress', {
|
|
235
|
+
progressToken: `approval_${elicitationId}`,
|
|
236
|
+
progress: 0,
|
|
237
|
+
total: 0,
|
|
238
|
+
message: `Waiting for user approval: ${message}`,
|
|
239
|
+
});
|
|
240
|
+
}, KEEPALIVE_INTERVAL_MS);
|
|
241
|
+
// Phase 2: Final expiry after 30 minutes
|
|
242
|
+
pending.timer = setTimeout(() => {
|
|
243
|
+
if (pendingElicitations.has(elicitationId)) {
|
|
244
|
+
cleanupElicitation(pending);
|
|
245
|
+
pendingElicitations.delete(elicitationId);
|
|
246
|
+
// Mark approval as expired on disk
|
|
247
|
+
void resolveApproval(photon, approvalId, 'rejected');
|
|
248
|
+
// Notify frontend
|
|
249
|
+
broadcastToBeam('beam/approval-resolved', {
|
|
250
|
+
approvalId,
|
|
251
|
+
photon,
|
|
252
|
+
status: 'expired',
|
|
253
|
+
});
|
|
254
|
+
resolve({ action: 'cancel' });
|
|
255
|
+
}
|
|
256
|
+
}, ELICITATION_EXPIRY_MS);
|
|
257
|
+
}, ELICITATION_DEFER_MS);
|
|
258
|
+
}
|
|
149
259
|
// Clean up old sessions periodically (30 min timeout)
|
|
150
260
|
const SESSION_TIMEOUT_MS = 30 * 60 * 1000;
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
261
|
+
let sessionCleanupInterval = null;
|
|
262
|
+
function startSessionCleanup() {
|
|
263
|
+
if (sessionCleanupInterval)
|
|
264
|
+
return;
|
|
265
|
+
sessionCleanupInterval = setInterval(() => {
|
|
266
|
+
const now = Date.now();
|
|
267
|
+
for (const [id, session] of sessions) {
|
|
268
|
+
if (now - session.lastActivity.getTime() > SESSION_TIMEOUT_MS) {
|
|
269
|
+
sessions.delete(id);
|
|
270
|
+
}
|
|
156
271
|
}
|
|
272
|
+
}, 60 * 1000);
|
|
273
|
+
sessionCleanupInterval.unref();
|
|
274
|
+
}
|
|
275
|
+
export function stopSessionCleanup() {
|
|
276
|
+
if (sessionCleanupInterval) {
|
|
277
|
+
clearInterval(sessionCleanupInterval);
|
|
278
|
+
sessionCleanupInterval = null;
|
|
157
279
|
}
|
|
158
|
-
}
|
|
280
|
+
}
|
|
281
|
+
// Start cleanup on module load
|
|
282
|
+
startSessionCleanup();
|
|
159
283
|
function getOrCreateSession(sessionId) {
|
|
160
284
|
if (sessionId && sessions.has(sessionId)) {
|
|
161
285
|
const session = sessions.get(sessionId);
|
|
@@ -506,8 +630,17 @@ const handlers = {
|
|
|
506
630
|
};
|
|
507
631
|
}
|
|
508
632
|
pendingElicitations.delete(elicitationId);
|
|
509
|
-
|
|
510
|
-
|
|
633
|
+
cleanupElicitation(pending);
|
|
634
|
+
// If this elicitation was deferred to approvals, resolve the approval on disk too
|
|
635
|
+
if (pending.approvalId) {
|
|
636
|
+
const status = params?.cancelled ? 'rejected' : 'approved';
|
|
637
|
+
await resolveApproval(pending.photonName || 'unknown', pending.approvalId, status);
|
|
638
|
+
broadcastToBeam('beam/approval-resolved', {
|
|
639
|
+
approvalId: pending.approvalId,
|
|
640
|
+
photon: pending.photonName || 'unknown',
|
|
641
|
+
status,
|
|
642
|
+
});
|
|
643
|
+
}
|
|
511
644
|
if (params?.cancelled) {
|
|
512
645
|
pending.reject(new Error('Elicitation cancelled by user'));
|
|
513
646
|
}
|
|
@@ -540,8 +673,7 @@ const handlers = {
|
|
|
540
673
|
const pending = pendingElicitations.get(params.approvalId);
|
|
541
674
|
if (pending) {
|
|
542
675
|
pendingElicitations.delete(params.approvalId);
|
|
543
|
-
|
|
544
|
-
clearTimeout(pending.timer);
|
|
676
|
+
cleanupElicitation(pending);
|
|
545
677
|
if (params.approved) {
|
|
546
678
|
pending.resolve(true);
|
|
547
679
|
}
|
|
@@ -630,11 +762,19 @@ const handlers = {
|
|
|
630
762
|
inputSchema: method.params || { type: 'object', properties: {} },
|
|
631
763
|
'x-photon-id': photon.id, // Unique ID (hash of path) for subscriptions
|
|
632
764
|
'x-photon-path': photon.path, // File path for View Source
|
|
765
|
+
// Editable when the photon file sits directly in the base dir (user-owned).
|
|
766
|
+
// Marketplace-installed photons live in a subdirectory and are read-only.
|
|
767
|
+
'x-photon-editable': photon.path
|
|
768
|
+
? dirname(photon.path) === (ctx.workingDir || '')
|
|
769
|
+
: false,
|
|
633
770
|
'x-photon-description': photon.description,
|
|
634
771
|
'x-photon-icon': photon.icon,
|
|
635
772
|
'x-photon-internal': photon.internal,
|
|
636
773
|
'x-photon-stateful': photon.stateful || false,
|
|
637
774
|
'x-photon-has-settings': photon.hasSettings || false,
|
|
775
|
+
'x-photon-short-name': photon.shortName,
|
|
776
|
+
'x-photon-namespace': photon.namespace,
|
|
777
|
+
'x-photon-qualified-name': photon.qualifiedName,
|
|
638
778
|
'x-photon-install-source': photon.installSource,
|
|
639
779
|
'x-photon-prompt-count': photon.promptCount ?? 0,
|
|
640
780
|
'x-photon-resource-count': photon.resourceCount ?? 0,
|
|
@@ -1111,7 +1251,7 @@ const handlers = {
|
|
|
1111
1251
|
const elicitResult = await requestBeamElicitation({
|
|
1112
1252
|
ask: 'confirm',
|
|
1113
1253
|
message: `"${methodName}" is a destructive operation. Continue?`,
|
|
1114
|
-
});
|
|
1254
|
+
}, { photonName: serverName, methodName });
|
|
1115
1255
|
if (elicitResult.action !== 'accept' || elicitResult.content === false) {
|
|
1116
1256
|
return {
|
|
1117
1257
|
jsonrpc: '2.0',
|
|
@@ -1155,7 +1295,7 @@ const handlers = {
|
|
|
1155
1295
|
ask: 'select',
|
|
1156
1296
|
message: 'Select an instance',
|
|
1157
1297
|
options: selectOptions,
|
|
1158
|
-
});
|
|
1298
|
+
}, { photonName: serverName, methodName });
|
|
1159
1299
|
if (elicitResult.action !== 'accept' || !elicitResult.content) {
|
|
1160
1300
|
return {
|
|
1161
1301
|
jsonrpc: '2.0',
|
|
@@ -1173,7 +1313,7 @@ const handlers = {
|
|
|
1173
1313
|
ask: 'text',
|
|
1174
1314
|
message: 'Enter a name for the new instance',
|
|
1175
1315
|
placeholder: 'e.g. groceries, work, personal',
|
|
1176
|
-
});
|
|
1316
|
+
}, { photonName: serverName, methodName });
|
|
1177
1317
|
if (nameResult.action !== 'accept' || !nameResult.content) {
|
|
1178
1318
|
return {
|
|
1179
1319
|
jsonrpc: '2.0',
|
|
@@ -2052,7 +2192,7 @@ const handlers = {
|
|
|
2052
2192
|
}
|
|
2053
2193
|
// If input_required right now, handle elicitation before waiting
|
|
2054
2194
|
if (task.state === 'input_required' && task.input) {
|
|
2055
|
-
const elicitResult = await requestBeamElicitation(task.input);
|
|
2195
|
+
const elicitResult = await requestBeamElicitation(task.input, { photonName: task.photon || 'task', methodName: task.method || taskId });
|
|
2056
2196
|
if (elicitResult.action === 'accept') {
|
|
2057
2197
|
resolveTaskInput(taskId, elicitResult.content);
|
|
2058
2198
|
}
|
|
@@ -2073,7 +2213,7 @@ const handlers = {
|
|
|
2073
2213
|
}
|
|
2074
2214
|
if (current.state === 'input_required' && current.input) {
|
|
2075
2215
|
// Send elicitation to the client
|
|
2076
|
-
const elicitResult = await requestBeamElicitation(current.input);
|
|
2216
|
+
const elicitResult = await requestBeamElicitation(current.input, { photonName: task.photon || 'task', methodName: task.method || taskId });
|
|
2077
2217
|
if (elicitResult.action === 'accept') {
|
|
2078
2218
|
resolveTaskInput(taskId, elicitResult.content);
|
|
2079
2219
|
}
|
|
@@ -2360,7 +2500,7 @@ async function handleBeamRemove(req, ctx, args) {
|
|
|
2360
2500
|
const elicitResult = await requestBeamElicitation({
|
|
2361
2501
|
ask: 'confirm',
|
|
2362
2502
|
message: `Remove "${photonName}"? The photon and its assets will be moved to trash.`,
|
|
2363
|
-
});
|
|
2503
|
+
}, { photonName, methodName: 'remove' });
|
|
2364
2504
|
if (elicitResult.action !== 'accept' || elicitResult.content === false) {
|
|
2365
2505
|
return {
|
|
2366
2506
|
jsonrpc: '2.0',
|
|
@@ -3368,8 +3508,7 @@ export function sendToSession(sessionId, method, params) {
|
|
|
3368
3508
|
*/
|
|
3369
3509
|
export function requestExternalElicitation(mcpName, request) {
|
|
3370
3510
|
const elicitationId = randomUUID();
|
|
3371
|
-
return new Promise((resolve
|
|
3372
|
-
// Store pending elicitation
|
|
3511
|
+
return new Promise((resolve) => {
|
|
3373
3512
|
const pending = {
|
|
3374
3513
|
resolve: (value) => {
|
|
3375
3514
|
resolve({ action: 'accept', content: value });
|
|
@@ -3382,7 +3521,10 @@ export function requestExternalElicitation(mcpName, request) {
|
|
|
3382
3521
|
resolve({ action: 'decline' });
|
|
3383
3522
|
}
|
|
3384
3523
|
},
|
|
3385
|
-
sessionId: '',
|
|
3524
|
+
sessionId: '',
|
|
3525
|
+
photonName: mcpName,
|
|
3526
|
+
methodName: 'elicitation',
|
|
3527
|
+
message: request.message,
|
|
3386
3528
|
};
|
|
3387
3529
|
pendingElicitations.set(elicitationId, pending);
|
|
3388
3530
|
// Broadcast elicitation request to all Beam clients
|
|
@@ -3394,13 +3536,8 @@ export function requestExternalElicitation(mcpName, request) {
|
|
|
3394
3536
|
schema: request.requestedSchema,
|
|
3395
3537
|
url: request.url,
|
|
3396
3538
|
});
|
|
3397
|
-
//
|
|
3398
|
-
pending
|
|
3399
|
-
if (pendingElicitations.has(elicitationId)) {
|
|
3400
|
-
pendingElicitations.delete(elicitationId);
|
|
3401
|
-
resolve({ action: 'cancel' });
|
|
3402
|
-
}
|
|
3403
|
-
}, 300000);
|
|
3539
|
+
// Two-phase timeout: 30s modal → pending queue with keepalives → 30min expiry
|
|
3540
|
+
setupElicitationTimeout(elicitationId, pending, resolve);
|
|
3404
3541
|
});
|
|
3405
3542
|
}
|
|
3406
3543
|
/**
|
|
@@ -3408,7 +3545,7 @@ export function requestExternalElicitation(mcpName, request) {
|
|
|
3408
3545
|
* Unlike requestExternalElicitation which uses MCP form/url mode, this sends
|
|
3409
3546
|
* the ask type directly so the elicitation modal renders the appropriate UI.
|
|
3410
3547
|
*/
|
|
3411
|
-
function requestBeamElicitation(data) {
|
|
3548
|
+
function requestBeamElicitation(data, context) {
|
|
3412
3549
|
const elicitationId = randomUUID();
|
|
3413
3550
|
return new Promise((resolve) => {
|
|
3414
3551
|
const pending = {
|
|
@@ -3424,6 +3561,9 @@ function requestBeamElicitation(data) {
|
|
|
3424
3561
|
}
|
|
3425
3562
|
},
|
|
3426
3563
|
sessionId: '',
|
|
3564
|
+
photonName: context?.photonName,
|
|
3565
|
+
methodName: context?.methodName,
|
|
3566
|
+
message: data.message,
|
|
3427
3567
|
};
|
|
3428
3568
|
pendingElicitations.set(elicitationId, pending);
|
|
3429
3569
|
// Broadcast with Photon-native ask format (not MCP form mode)
|
|
@@ -3431,13 +3571,8 @@ function requestBeamElicitation(data) {
|
|
|
3431
3571
|
elicitationId,
|
|
3432
3572
|
...data,
|
|
3433
3573
|
});
|
|
3434
|
-
//
|
|
3435
|
-
pending
|
|
3436
|
-
if (pendingElicitations.has(elicitationId)) {
|
|
3437
|
-
pendingElicitations.delete(elicitationId);
|
|
3438
|
-
resolve({ action: 'cancel' });
|
|
3439
|
-
}
|
|
3440
|
-
}, 300000);
|
|
3574
|
+
// Two-phase timeout: 30s modal → pending queue with keepalives → 30min expiry
|
|
3575
|
+
setupElicitationTimeout(elicitationId, pending, resolve);
|
|
3441
3576
|
});
|
|
3442
3577
|
}
|
|
3443
3578
|
//# sourceMappingURL=streamable-http-transport.js.map
|