@portel/photon 1.34.2 → 1.35.0

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.
Files changed (105) hide show
  1. package/README.md +1 -0
  2. package/dist/a2a/card-generator.js +1 -1
  3. package/dist/auto-ui/beam/external-mcp.js.map +1 -1
  4. package/dist/auto-ui/beam/routes/api-browse.js +1 -1
  5. package/dist/auto-ui/beam/routes/api-browse.js.map +1 -1
  6. package/dist/auto-ui/beam/routes/api-config.d.ts.map +1 -1
  7. package/dist/auto-ui/beam/routes/api-config.js +27 -8
  8. package/dist/auto-ui/beam/routes/api-config.js.map +1 -1
  9. package/dist/auto-ui/beam/subscription.d.ts.map +1 -1
  10. package/dist/auto-ui/beam/subscription.js +4 -1
  11. package/dist/auto-ui/beam/subscription.js.map +1 -1
  12. package/dist/auto-ui/beam.d.ts +2 -0
  13. package/dist/auto-ui/beam.d.ts.map +1 -1
  14. package/dist/auto-ui/beam.js +60 -3
  15. package/dist/auto-ui/beam.js.map +1 -1
  16. package/dist/auto-ui/bridge/renderers.d.ts.map +1 -1
  17. package/dist/auto-ui/bridge/renderers.js +44 -1
  18. package/dist/auto-ui/bridge/renderers.js.map +1 -1
  19. package/dist/auto-ui/streamable-http-transport.d.ts.map +1 -1
  20. package/dist/auto-ui/streamable-http-transport.js +1 -1
  21. package/dist/auto-ui/streamable-http-transport.js.map +1 -1
  22. package/dist/beam.bundle.js +81 -83
  23. package/dist/beam.bundle.js.map +3 -3
  24. package/dist/cli/commands/info.d.ts.map +1 -1
  25. package/dist/cli/commands/info.js +3 -1
  26. package/dist/cli/commands/info.js.map +1 -1
  27. package/dist/cli/commands/ps.d.ts +2 -4
  28. package/dist/cli/commands/ps.d.ts.map +1 -1
  29. package/dist/cli/commands/ps.js +5 -11
  30. package/dist/cli/commands/ps.js.map +1 -1
  31. package/dist/cli-alias.js +1 -0
  32. package/dist/cli-alias.js.map +1 -1
  33. package/dist/daemon/client.d.ts.map +1 -1
  34. package/dist/daemon/client.js +31 -19
  35. package/dist/daemon/client.js.map +1 -1
  36. package/dist/daemon/manager.d.ts.map +1 -1
  37. package/dist/daemon/manager.js +9 -0
  38. package/dist/daemon/manager.js.map +1 -1
  39. package/dist/daemon/registry-keys.d.ts +6 -0
  40. package/dist/daemon/registry-keys.d.ts.map +1 -1
  41. package/dist/daemon/registry-keys.js +9 -0
  42. package/dist/daemon/registry-keys.js.map +1 -1
  43. package/dist/daemon/server.js +154 -30
  44. package/dist/daemon/server.js.map +1 -1
  45. package/dist/deploy/cloudflare.js.map +1 -1
  46. package/dist/formats/format-registry.d.ts +32 -0
  47. package/dist/formats/format-registry.d.ts.map +1 -0
  48. package/dist/formats/format-registry.js +67 -0
  49. package/dist/formats/format-registry.js.map +1 -0
  50. package/dist/loader.d.ts +6 -0
  51. package/dist/loader.d.ts.map +1 -1
  52. package/dist/loader.js +121 -30
  53. package/dist/loader.js.map +1 -1
  54. package/dist/marketplace-manager.js +1 -1
  55. package/dist/marketplace-manager.js.map +1 -1
  56. package/dist/photon-cli-runner.d.ts.map +1 -1
  57. package/dist/photon-cli-runner.js +1 -0
  58. package/dist/photon-cli-runner.js.map +1 -1
  59. package/dist/serv/middleware/tenant.d.ts.map +1 -1
  60. package/dist/serv/middleware/tenant.js +1 -0
  61. package/dist/serv/middleware/tenant.js.map +1 -1
  62. package/dist/server.d.ts +10 -0
  63. package/dist/server.d.ts.map +1 -1
  64. package/dist/server.js +158 -153
  65. package/dist/server.js.map +1 -1
  66. package/dist/settings-persistence.d.ts +10 -0
  67. package/dist/settings-persistence.d.ts.map +1 -1
  68. package/dist/settings-persistence.js +25 -4
  69. package/dist/settings-persistence.js.map +1 -1
  70. package/dist/shared/audit.d.ts.map +1 -1
  71. package/dist/shared/audit.js +2 -1
  72. package/dist/shared/audit.js.map +1 -1
  73. package/dist/shared/identity.d.ts +50 -0
  74. package/dist/shared/identity.d.ts.map +1 -0
  75. package/dist/shared/identity.js +61 -0
  76. package/dist/shared/identity.js.map +1 -0
  77. package/dist/shared/memory-sqlite.d.ts.map +1 -1
  78. package/dist/shared/memory-sqlite.js +1 -0
  79. package/dist/shared/memory-sqlite.js.map +1 -1
  80. package/dist/shared/security.d.ts.map +1 -1
  81. package/dist/shared/security.js +7 -1
  82. package/dist/shared/security.js.map +1 -1
  83. package/dist/shared-utils.d.ts.map +1 -1
  84. package/dist/shared-utils.js +2 -2
  85. package/dist/shared-utils.js.map +1 -1
  86. package/dist/tasks/store.d.ts.map +1 -1
  87. package/dist/tasks/store.js +2 -1
  88. package/dist/tasks/store.js.map +1 -1
  89. package/dist/telemetry/context.d.ts.map +1 -1
  90. package/dist/telemetry/context.js +8 -2
  91. package/dist/telemetry/context.js.map +1 -1
  92. package/dist/types/server-types.d.ts +12 -0
  93. package/dist/types/server-types.d.ts.map +1 -1
  94. package/dist/version-notify.d.ts.map +1 -1
  95. package/dist/version-notify.js +2 -1
  96. package/dist/version-notify.js.map +1 -1
  97. package/package.json +4 -3
  98. package/templates/cloudflare/worker.ts.template +182 -4
  99. package/dist/photons/canvas/ui/canvas.photon.html +0 -1493
  100. package/dist/photons/canvas.photon.d.ts +0 -400
  101. package/dist/photons/canvas.photon.d.ts.map +0 -1
  102. package/dist/photons/canvas.photon.js +0 -662
  103. package/dist/photons/canvas.photon.js.map +0 -1
  104. package/dist/photons/canvas.photon.ts +0 -814
  105. package/dist/photons/ui/canvas.photon.html +0 -624
package/dist/server.js CHANGED
@@ -1182,8 +1182,9 @@ export class PhotonServer {
1182
1182
  toolDef['x-output-format'] = schema.outputFormat;
1183
1183
  if (schema.layoutHints)
1184
1184
  toolDef['x-layout-hints'] = schema.layoutHints;
1185
- if (schema.scopes)
1186
- toolDef.scopes = schema.scopes;
1185
+ const toolScopes = schema.scopes;
1186
+ if (toolScopes)
1187
+ toolDef.scopes = toolScopes;
1187
1188
  if (schema.buttonLabel)
1188
1189
  toolDef['x-button-label'] = schema.buttonLabel;
1189
1190
  if (schema.icon)
@@ -1585,6 +1586,155 @@ export class PhotonServer {
1585
1586
  return this.formatTemplateResult(result);
1586
1587
  }
1587
1588
  // ─── Transport-specific setup ─────────────────────────────────────
1589
+ /**
1590
+ * Unified tools/call handling for every MCP transport.
1591
+ *
1592
+ * Both setupHandlers (STDIO) and setupSessionHandlers (SSE) delegate here
1593
+ * so @async fire-and-forget, task-mode dispatch, config elicitation retry,
1594
+ * and error formatting behave identically regardless of how the request
1595
+ * arrived. Session-specific routing (which server gets notifications,
1596
+ * which instance name applies) comes exclusively from ctx.
1597
+ */
1598
+ async handleCallToolRequest(ctx, request, extra) {
1599
+ // Deferred conflict resolution (set only by STDIO startup options)
1600
+ if (!this.mcp && this.options.unresolvedPhoton) {
1601
+ await this.resolveUnresolvedPhoton();
1602
+ }
1603
+ // @async fire-and-forget execution
1604
+ if (this.mcp) {
1605
+ const { name: toolName, arguments: args } = request.params;
1606
+ const tool = this.mcp.tools.find((t) => t.name === toolName);
1607
+ if (tool?.isAsync) {
1608
+ // Generate a W3C-compatible OTel trace ID (32 hex chars = 128-bit)
1609
+ const traceId = crypto.randomBytes(16).toString('hex');
1610
+ const executionId = traceId;
1611
+ const inputProvider = this.createMCPInputProvider(ctx.server);
1612
+ const samplingProvider = this.createMCPSamplingProvider(ctx.server);
1613
+ const clientProgressToken = request.params?._meta?.progressToken;
1614
+ const progressToken = clientProgressToken ?? `progress_${toolName}`;
1615
+ const outputHandler = (emit) => {
1616
+ this.channelManager.publishIfChannel(emit);
1617
+ // Forward emit yields as MCP notifications for async tools
1618
+ if (emit?.emit === 'progress' || emit?.emit === 'status') {
1619
+ const rawValue = emit?.emit === 'progress' && typeof emit.value === 'number' ? emit.value : 0;
1620
+ const progress = rawValue <= 1 ? rawValue * 100 : rawValue;
1621
+ const payload = emit.value ?? emit.data;
1622
+ void ctx.server.notification({
1623
+ method: 'notifications/progress',
1624
+ params: {
1625
+ progressToken,
1626
+ progress,
1627
+ total: 100,
1628
+ message: emit.message || '',
1629
+ ...(payload !== undefined &&
1630
+ (emit?.emit === 'status' || typeof payload !== 'number')
1631
+ ? { data: payload }
1632
+ : {}),
1633
+ },
1634
+ });
1635
+ }
1636
+ else if (emit?.emit === 'log') {
1637
+ void ctx.server.notification({
1638
+ method: 'notifications/message',
1639
+ params: {
1640
+ level: emit.level || 'info',
1641
+ data: emit.message || '',
1642
+ },
1643
+ });
1644
+ }
1645
+ else if (emit?.emit === 'render') {
1646
+ try {
1647
+ void ctx.server.notification({
1648
+ method: 'notifications/message',
1649
+ params: {
1650
+ level: 'info',
1651
+ data: JSON.stringify({
1652
+ _render: true,
1653
+ format: emit.format,
1654
+ value: emit.value,
1655
+ }),
1656
+ },
1657
+ });
1658
+ }
1659
+ catch {
1660
+ // Client may not support logging capability
1661
+ }
1662
+ }
1663
+ else if (emit?.emit === 'render:clear') {
1664
+ try {
1665
+ void ctx.server.notification({
1666
+ method: 'notifications/message',
1667
+ params: {
1668
+ level: 'info',
1669
+ data: JSON.stringify({ _render: true, clear: true }),
1670
+ },
1671
+ });
1672
+ }
1673
+ catch {
1674
+ // Client may not support logging capability
1675
+ }
1676
+ }
1677
+ };
1678
+ this.loader
1679
+ .executeTool(this.mcp, toolName, args || {}, {
1680
+ inputProvider,
1681
+ outputHandler,
1682
+ samplingProvider,
1683
+ traceId,
1684
+ roots: this.rootsByServer.get(ctx.server),
1685
+ })
1686
+ .catch((error) => {
1687
+ this.log('error', `Async tool ${toolName} failed`, {
1688
+ executionId,
1689
+ error: getErrorMessage(error),
1690
+ });
1691
+ });
1692
+ // Build W3C traceparent: 00-{traceId}-{spanId}-01
1693
+ const spanId = crypto.randomBytes(8).toString('hex');
1694
+ const traceparent = `00-${traceId}-${spanId}-01`;
1695
+ return {
1696
+ content: [
1697
+ {
1698
+ type: 'text',
1699
+ text: JSON.stringify({
1700
+ executionId,
1701
+ _traceId: traceId,
1702
+ _traceparent: traceparent,
1703
+ status: 'running',
1704
+ photon: this.mcp.name,
1705
+ method: toolName,
1706
+ message: `Task started in background. Use execution ID to check status.`,
1707
+ }, null, 2),
1708
+ },
1709
+ ],
1710
+ };
1711
+ }
1712
+ }
1713
+ // ── Task mode: when params contain task field, run async ──
1714
+ const taskField = request.params?.task;
1715
+ if (taskField && this.mcp) {
1716
+ const { name: toolName, arguments: args } = request.params;
1717
+ return this.taskExecutor.handleTaskModeCall(this.mcp.name, toolName, args || {}, taskField);
1718
+ }
1719
+ try {
1720
+ return await this.handleCallTool(ctx, request, extra);
1721
+ }
1722
+ catch (error) {
1723
+ const { name: toolName, arguments: args } = request.params;
1724
+ if (this.mcp?.instance?._photonConfigError &&
1725
+ this.capabilityNegotiator.supportsElicitation(ctx.server)) {
1726
+ const retryResult = await this.attemptConfigElicitation(toolName, args || {}, ctx.server);
1727
+ if (retryResult)
1728
+ return retryResult;
1729
+ }
1730
+ this.log('error', 'Tool execution failed', {
1731
+ tool: toolName,
1732
+ error: getErrorMessage(error),
1733
+ args: this.options.devMode ? args : undefined,
1734
+ });
1735
+ return this.formatError(error, toolName, args);
1736
+ }
1737
+ }
1588
1738
  /**
1589
1739
  * Set up MCP protocol handlers (STDIO transport)
1590
1740
  */
@@ -1609,146 +1759,7 @@ export class PhotonServer {
1609
1759
  return this.handleListTools(ctx);
1610
1760
  });
1611
1761
  this.server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
1612
- // STDIO-only: deferred conflict resolution
1613
- if (!this.mcp && this.options.unresolvedPhoton) {
1614
- await this.resolveUnresolvedPhoton();
1615
- }
1616
- // STDIO-only: @async fire-and-forget execution
1617
- if (this.mcp) {
1618
- const { name: toolName, arguments: args } = request.params;
1619
- const tool = this.mcp.tools.find((t) => t.name === toolName);
1620
- if (tool?.isAsync) {
1621
- // Generate a W3C-compatible OTel trace ID (32 hex chars = 128-bit)
1622
- const traceId = crypto.randomBytes(16).toString('hex');
1623
- const executionId = traceId;
1624
- const inputProvider = this.createMCPInputProvider();
1625
- const samplingProvider = this.createMCPSamplingProvider();
1626
- const clientProgressToken = request.params?._meta?.progressToken;
1627
- const progressToken = clientProgressToken ?? `progress_${toolName}`;
1628
- const outputHandler = (emit) => {
1629
- this.channelManager.publishIfChannel(emit);
1630
- // Forward emit yields as MCP notifications for async tools
1631
- if (emit?.emit === 'progress' || emit?.emit === 'status') {
1632
- const rawValue = emit?.emit === 'progress' && typeof emit.value === 'number' ? emit.value : 0;
1633
- const progress = rawValue <= 1 ? rawValue * 100 : rawValue;
1634
- const payload = emit.value ?? emit.data;
1635
- void this.server?.notification({
1636
- method: 'notifications/progress',
1637
- params: {
1638
- progressToken,
1639
- progress,
1640
- total: 100,
1641
- message: emit.message || '',
1642
- ...(payload !== undefined &&
1643
- (emit?.emit === 'status' || typeof payload !== 'number')
1644
- ? { data: payload }
1645
- : {}),
1646
- },
1647
- });
1648
- }
1649
- else if (emit?.emit === 'log') {
1650
- void this.server?.notification({
1651
- method: 'notifications/message',
1652
- params: {
1653
- level: emit.level || 'info',
1654
- data: emit.message || '',
1655
- },
1656
- });
1657
- }
1658
- else if (emit?.emit === 'render') {
1659
- try {
1660
- void this.server?.notification({
1661
- method: 'notifications/message',
1662
- params: {
1663
- level: 'info',
1664
- data: JSON.stringify({
1665
- _render: true,
1666
- format: emit.format,
1667
- value: emit.value,
1668
- }),
1669
- },
1670
- });
1671
- }
1672
- catch {
1673
- // Client may not support logging capability
1674
- }
1675
- }
1676
- else if (emit?.emit === 'render:clear') {
1677
- try {
1678
- void this.server?.notification({
1679
- method: 'notifications/message',
1680
- params: {
1681
- level: 'info',
1682
- data: JSON.stringify({ _render: true, clear: true }),
1683
- },
1684
- });
1685
- }
1686
- catch {
1687
- // Client may not support logging capability
1688
- }
1689
- }
1690
- };
1691
- this.loader
1692
- .executeTool(this.mcp, toolName, args || {}, {
1693
- inputProvider,
1694
- outputHandler,
1695
- samplingProvider,
1696
- traceId,
1697
- roots: this.rootsByServer.get(ctx.server),
1698
- })
1699
- .catch((error) => {
1700
- this.log('error', `Async tool ${toolName} failed`, {
1701
- executionId,
1702
- error: getErrorMessage(error),
1703
- });
1704
- });
1705
- // Build W3C traceparent: 00-{traceId}-{spanId}-01
1706
- const spanId = crypto.randomBytes(8).toString('hex');
1707
- const traceparent = `00-${traceId}-${spanId}-01`;
1708
- return {
1709
- content: [
1710
- {
1711
- type: 'text',
1712
- text: JSON.stringify({
1713
- executionId,
1714
- _traceId: traceId,
1715
- _traceparent: traceparent,
1716
- status: 'running',
1717
- photon: this.mcp.name,
1718
- method: toolName,
1719
- message: `Task started in background. Use execution ID to check status.`,
1720
- }, null, 2),
1721
- },
1722
- ],
1723
- };
1724
- }
1725
- }
1726
- // ── Task mode: when params contain task field, run async ──
1727
- const taskField = request.params?.task;
1728
- if (taskField && this.mcp) {
1729
- const { name: toolName, arguments: args } = request.params;
1730
- return this.taskExecutor.handleTaskModeCall(this.mcp.name, toolName, args || {}, taskField);
1731
- }
1732
- try {
1733
- return await this.handleCallTool(ctx, request, extra);
1734
- }
1735
- catch (error) {
1736
- // STDIO-only: config elicitation retry
1737
- const { name: toolName, arguments: args } = request.params;
1738
- if (this.mcp?.instance?._photonConfigError &&
1739
- this.capabilityNegotiator.supportsElicitation(this.server)) {
1740
- const retryResult = await this.attemptConfigElicitation(toolName, args || {});
1741
- if (retryResult)
1742
- return retryResult;
1743
- }
1744
- // STDIO-only: verbose error logging
1745
- this.log('error', 'Tool execution failed', {
1746
- tool: toolName,
1747
- error: getErrorMessage(error),
1748
- args: this.options.devMode ? args : undefined,
1749
- });
1750
- return this.formatError(error, toolName, args);
1751
- }
1762
+ return this.handleCallToolRequest(ctx, request, extra);
1752
1763
  });
1753
1764
  this.server.setRequestHandler(ListPromptsRequestSchema, async () => {
1754
1765
  return this.handleListPrompts();
@@ -2070,7 +2081,7 @@ export class PhotonServer {
2070
2081
  /**
2071
2082
  * Attempt config elicitation to resolve missing env vars, then retry tool call
2072
2083
  */
2073
- async attemptConfigElicitation(toolName, args) {
2084
+ async attemptConfigElicitation(toolName, args, server = this.server) {
2074
2085
  try {
2075
2086
  // Extract constructor params to build form
2076
2087
  const params = await this.loader.extractConstructorParams(this.options.filePath);
@@ -2099,7 +2110,7 @@ export class PhotonServer {
2099
2110
  }
2100
2111
  if (Object.keys(properties).length === 0)
2101
2112
  return null;
2102
- const result = await this.server.elicitInput({
2113
+ const result = await server.elicitInput({
2103
2114
  message: `${photonName} requires configuration. Please provide the following:`,
2104
2115
  requestedSchema: {
2105
2116
  type: 'object',
@@ -2121,8 +2132,8 @@ export class PhotonServer {
2121
2132
  this.mcp = await this.loader.loadFile(this.options.filePath);
2122
2133
  await this.notifyListsChanged();
2123
2134
  // Retry the original tool call
2124
- const inputProvider = this.createMCPInputProvider();
2125
- const samplingProvider = this.createMCPSamplingProvider();
2135
+ const inputProvider = this.createMCPInputProvider(server);
2136
+ const samplingProvider = this.createMCPSamplingProvider(server);
2126
2137
  const outputHandler = (emit) => {
2127
2138
  this.channelManager.publishIfChannel(emit);
2128
2139
  };
@@ -3254,13 +3265,7 @@ export class PhotonServer {
3254
3265
  return this.handleListTools(ctx);
3255
3266
  });
3256
3267
  sessionServer.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
3257
- try {
3258
- return await this.handleCallTool(ctx, request, extra);
3259
- }
3260
- catch (error) {
3261
- const { name: toolName, arguments: args } = request.params;
3262
- return this.formatError(error, toolName, args);
3263
- }
3268
+ return this.handleCallToolRequest(ctx, request, extra);
3264
3269
  });
3265
3270
  sessionServer.setRequestHandler(ListPromptsRequestSchema, async () => {
3266
3271
  return this.handleListPrompts();