@xopcai/xopc 0.0.232 → 0.0.234
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/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-VXCWz43N.js → activity-store-BzswYHcj.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BXRaZYW8.js → agent-avatar-dicebear-CztNAQyE.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-BHeLVAW5.js +1 -0
- package/dist/gateway/static/root/assets/agents-B8c0U7Ze.js +1 -0
- package/dist/gateway/static/root/assets/{api-wGPgL8xY.js → api-7zOtMbaE.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BJfClfPx.js → app-management-settings-panel-BxBMAdWc.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C_R0vUAu.js → appearance-settings-DVAxCOPL.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-CBow8pBI.js → apps-page-BtzXxSYK.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DnFHkSHE.js → archive-plugin-DawToDU8.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DZrEwytM.js → attachment-load-BpCKsdiO.js} +1 -1
- package/dist/gateway/static/root/assets/attachment-preview-renderer-BDTD8YUe.js +12 -0
- package/dist/gateway/static/root/assets/{automations-page-DpkKajui.js → automations-page-a6_hTplT.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-C7ZwZl04.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-Ckc_Csue.js → binary-plugins-OqUf-uET.js} +2 -2
- package/dist/gateway/static/root/assets/{block-editor-DAC6w-iV.js → block-editor-9OAYqVKF.js} +3 -3
- package/dist/gateway/static/root/assets/browser-settings-page-CEHhbDj0.js +8 -0
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-BGd7R8GO.js → browser-workflow-inputs-4ooVX-Tx.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-DUfj7ntM.js → browser-workflows-page-CUgwXXsi.js} +2 -2
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-97gkGeSV.js → capabilities-settings-panel-CAbI9beX.js} +5 -5
- package/dist/gateway/static/root/assets/channels-settings-BksDnAyv.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-CfboECLt.js → channels-status-swr-BDJvMnA_.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-CA9fndbZ.js → chat-terminal-dock-DB9zi_dy.js} +2 -2
- package/dist/gateway/static/root/assets/connectors-page-CnY8lcGJ.js +2 -0
- package/dist/gateway/static/root/assets/{cron-expression-CqPu7HYJ.js → cron-expression-a9Jyianb.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-C8dJsCgk.js → date-picker-B_l2CHWO.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-Iz2wYimy.js → dependency-picker-DjcEIzVJ.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-C3h40FmG.js → desktop-pet-ZCBsj8Je.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-YfeVVzLe.js → desktop-pet-settings-DJJf0EvL.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-CChgztz_.js → extension-debug-page-CMXbAkx-.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DF6ct6_y.js → extension-page-WWePedpo.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-jgBsjn0F.js → extension-settings-page-DjIhNJVI.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-CVajuIGL.js → gateway-config-api-BNj6srhV.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-swr-BGQn8duh.js → gateway-config-swr-R702lNJR.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-BbssNGid.js → gateway-settings-DvlFDxhZ.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-D2Rnh9fX.js → gateway-startup-retry-2rVSUvyw.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-Dlahslof.js +1 -0
- package/dist/gateway/static/root/assets/home-page-DJhUd30b.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-D7W2p5_8.js → image-generation-api-B28USRCK.js} +1 -1
- package/dist/gateway/static/root/assets/index-BTUuTnc9.css +2 -0
- package/dist/gateway/static/root/assets/index-CXGQihfj.js +70 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BvHYyNus.js → keyboard-shortcuts-settings-d12AAEaC.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-DUP0UiFY.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-Cb8t2wWM.js → local-apps-page-_z2o0cD1.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-DLwVxS3V.js → locale-store-8k4mvYGL.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CPUaLcGH.js +2 -0
- package/dist/gateway/static/root/assets/{management-settings-B8Jie4-J.js → management-settings-eTBfNgXU.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-BD1r4o2i.js → markdown-split-7rTfQCN_.js} +1 -1
- package/dist/gateway/static/root/assets/markdown-view-D02mJdoU.js +201 -0
- package/dist/gateway/static/root/assets/{media-plugins-BCev8fkW.js → media-plugins-BIfKo5Ow.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CoovNoMn.js +3 -0
- package/dist/gateway/static/root/assets/{mobile-device-api-DACoHhhk.js → mobile-device-api-CvjVB_TB.js} +1 -1
- package/dist/gateway/static/root/assets/models-hub-cache-CYr6LzvY.js +1 -0
- package/dist/gateway/static/root/assets/{notes-api-DEdNKw0I.js → notes-api-p2Pncp2B.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-BBTLjJwa.js → notes-page-dOvbZBOQ.js} +1 -1
- package/dist/gateway/static/root/assets/notes-workbench-DQMUpDc9.js +4 -0
- package/dist/gateway/static/root/assets/{oauth-api-BNCO2YK5.js → oauth-api-DpLONwfK.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-fEBbRekH.js → product-open-page-CgZhadZQ.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-D1HidxgT.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-CxwNbbud.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-Cvr4Qm7N.js → registry-api-B7b0LJgI.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CK59rSc_.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BT5B74IH.js → runtime-tools-settings-panel-D3PS55Yg.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-C4tB34S5.js → schema-form-H-aeWTzM.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-C2tP7363.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-DlYBA2N-.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-D1oXhkgI.js → settings-form-section-B9oF8Rhw.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-CldfX6FJ.js → settings-loading-skeleton-CazDM3n5.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-c3LJnbvE.js → settings-page-C6pmQNzY.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Cn2E0G2o.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DptCK_mk.js → share-preview-page-XgxvE8cx.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-Czph0_fM.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-DDq_QEqd.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-OHBeBtSg.js → skills-page-CfNV6kgb.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page.utils-B9WZbOLC.js → skills-page.utils-DgxGb7v7.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-Dj_DpOGw.js → system-settings-panel-B4W--Ukh.js} +1 -1
- package/dist/gateway/static/root/assets/task-detail-page-UY5kNWoR.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-Cpd3Gd5R.js → theme-store-CpcBI73Q.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-DCl5Yq7N.js → use-autosave-DR7YWBzR.js} +1 -1
- package/dist/gateway/static/root/assets/user-context-page-DnUL8kJU.js +1 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-BB_ZQV8F.js → voice-api-key-field-BZhqoxBR.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-BNiYmpl5.js → voice-config-api-ynE-vY6I.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-BrIdtdum.js → work-discovery-overlay-CouKiK45.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-hKh-uCLo.js → workflow-run-setup-panel-CUqAESrr.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-B8dJRjMJ.js +5 -0
- package/dist/gateway/static/root/index.html +13 -13
- package/dist/package.js +1 -1
- package/dist/packages/endpoint-tools-protocol/src/index.js +162 -2
- package/dist/packages/gateway-contract/src/product-delivery.js +6 -2
- package/dist/packages/gateway-contract/src/turn-outcome.js +77 -1
- package/dist/src/agent/agent-manager.js +4 -4
- package/dist/src/agent/background-review/run-background-review.js +1 -1
- package/dist/src/agent/capabilities/definitions.d.ts +1 -1
- package/dist/src/agent/capabilities/definitions.js +2 -1
- package/dist/src/agent/embedded/model-runtime.js +1 -1
- package/dist/src/agent/embedded/run-for-session.js +57 -8
- package/dist/src/agent/embedded/types.d.ts +5 -0
- package/dist/src/agent/external-tools/endpoint-provider.js +5 -1
- package/dist/src/agent/image/tool-model-config.js +1 -1
- package/dist/src/agent/ipc/inbox.js +1 -1
- package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +5 -0
- package/dist/src/agent/service.js +2 -2
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/tasks/task-judge-service.js +3 -3
- package/dist/src/agent/tools/create-share-tool.js +2 -1
- package/dist/src/agent/tools/exec-command.d.ts +2 -0
- package/dist/src/agent/tools/exec-command.js +24 -7
- package/dist/src/agent/tools/factory.js +2 -0
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/publish-artifacts.d.ts +8 -0
- package/dist/src/agent/tools/publish-artifacts.js +95 -0
- package/dist/src/agent/tools/send-media.js +2 -1
- package/dist/src/ai-assist/text-assist.js +1 -1
- package/dist/src/auth/credentials.js +2 -2
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +1 -1
- package/dist/src/cli/command-catalog.js +4 -0
- package/dist/src/cli/command-loaders.js +1 -0
- package/dist/src/cli/command-manifest.js +4 -0
- package/dist/src/cli/commands/auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard/model.js +1 -1
- package/dist/src/cli/commands/providers.js +1 -1
- package/dist/src/cli/commands/support.d.ts +1 -0
- package/dist/src/cli/commands/support.js +51 -0
- package/dist/src/config/index.js +4 -4
- package/dist/src/config/loader.js +1 -1
- package/dist/src/config/models-json.js +1 -1
- package/dist/src/endpoint-tools/binding-service.d.ts +22 -0
- package/dist/src/endpoint-tools/binding-service.js +45 -0
- package/dist/src/endpoint-tools/index.d.ts +1 -0
- package/dist/src/endpoint-tools/index.js +2 -1
- package/dist/src/endpoint-tools/invocation-service.d.ts +1 -0
- package/dist/src/endpoint-tools/invocation-service.js +8 -0
- package/dist/src/endpoint-tools/policy.d.ts +4 -1
- package/dist/src/endpoint-tools/policy.js +68 -5
- package/dist/src/endpoint-tools/registry.js +1 -1
- package/dist/src/endpoint-tools/runtime.d.ts +2 -0
- package/dist/src/endpoint-tools/runtime.js +8 -0
- package/dist/src/extensions/lockfile.js +1 -1
- package/dist/src/files/file-service.js +14 -5
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +5 -0
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/middleware/auth.js +3 -2
- package/dist/src/gateway/hono/routes/endpoint-tools.js +68 -1
- package/dist/src/gateway/hono/routes/files.js +7 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/media.js +46 -2
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/support.d.ts +3 -0
- package/dist/src/gateway/hono/routes/support.js +28 -0
- package/dist/src/gateway/hono/routes/you.js +24 -0
- package/dist/src/gateway/service/config-coordinator.js +1 -1
- package/dist/src/gateway/service/run-gateway-agent.js +0 -35
- package/dist/src/gateway/service.js +3 -3
- package/dist/src/media/store.js +9 -0
- package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/providers/register-runtime-providers.js +1 -1
- package/dist/src/session/store.js +4 -2
- package/dist/src/session/turn-outcome-projector.d.ts +9 -0
- package/dist/src/session/turn-outcome-projector.js +209 -0
- package/dist/src/share/hosted-session-share.js +1 -1
- package/dist/src/storage/sqlite/endpoint-session-binding-repository.d.ts +8 -0
- package/dist/src/storage/sqlite/endpoint-session-binding-repository.js +32 -0
- package/dist/src/storage/sqlite/index.d.ts +1 -0
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/migrations/139_turn_outcome_artifact_backfill.sql +231 -0
- package/dist/src/storage/sqlite/migrations/140_endpoint_session_bindings.sql +8 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/support/build-support-investigation-prompt.d.ts +2 -0
- package/dist/src/support/build-support-investigation-prompt.js +29 -0
- package/dist/src/support/collect-support-report.d.ts +16 -0
- package/dist/src/support/collect-support-report.js +216 -0
- package/dist/src/support/redact-support-report.d.ts +16 -0
- package/dist/src/support/redact-support-report.js +89 -0
- package/dist/src/support/types.d.ts +76 -0
- package/dist/src/support/types.js +18 -0
- package/dist/src/tui/tui-startup-resources.js +1 -1
- package/dist/src/tui/tui.js +1 -1
- package/dist/src/user-context/user-avatar.d.ts +17 -0
- package/dist/src/user-context/user-avatar.js +116 -0
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-dR7HMaRX.js +0 -1
- package/dist/gateway/static/root/assets/agents-Bileycwe.js +0 -1
- package/dist/gateway/static/root/assets/attachment-preview-renderer-Cmo-5BP5.js +0 -11
- package/dist/gateway/static/root/assets/automations-workspace-BBntVWgv.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-DrsMd-Po.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-CuBsz8UI.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-SuL7td7Z.js +0 -2
- package/dist/gateway/static/root/assets/heartbeat-settings-CJtXu8iD.js +0 -1
- package/dist/gateway/static/root/assets/home-page-Be1o1AXQ.js +0 -1
- package/dist/gateway/static/root/assets/index-B2OJSXX9.js +0 -70
- package/dist/gateway/static/root/assets/index-rHjAElxG.css +0 -2
- package/dist/gateway/static/root/assets/local-app-workbench-page-COfelgk7.js +0 -2
- package/dist/gateway/static/root/assets/logs-page-DA8oDjeB.js +0 -2
- package/dist/gateway/static/root/assets/markdown-view-B-BHEcNd.js +0 -201
- package/dist/gateway/static/root/assets/messages-Dp1OxSKt.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-cache-C8zjqmIv.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-DICgUGPv.js +0 -4
- package/dist/gateway/static/root/assets/project-detail-page-CqdkznYJ.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-dHDXpMCg.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-2feZudJw.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-CO2JCFdy.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DxMVaqdn.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-DZNHb6A5.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-DakZ2AGN.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-BOiNkWJC.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-D5Nbe3C8.js +0 -1
- package/dist/gateway/static/root/assets/user-context-page-CAPSUK8B.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-ahDvypGO.js +0 -5
- package/dist/src/gateway/chat-stream/turn-outcome-collector.d.ts +0 -16
- package/dist/src/gateway/chat-stream/turn-outcome-collector.js +0 -111
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/endpoint-tools/binding-service.ts
|
|
2
|
+
function memoryStore() {
|
|
3
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
4
|
+
return {
|
|
5
|
+
get: (sessionKey) => bindings.get(sessionKey),
|
|
6
|
+
set: (binding) => {
|
|
7
|
+
bindings.set(binding.sessionKey, binding);
|
|
8
|
+
return binding;
|
|
9
|
+
},
|
|
10
|
+
delete: (sessionKey) => bindings.delete(sessionKey)
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
var EndpointBindingService = class {
|
|
14
|
+
constructor(registry, store = memoryStore()) {
|
|
15
|
+
this.registry = registry;
|
|
16
|
+
this.store = store;
|
|
17
|
+
}
|
|
18
|
+
bind(sessionKey, endpointId, now = Date.now()) {
|
|
19
|
+
const normalizedSessionKey = this.normalizeSessionKey(sessionKey);
|
|
20
|
+
if (!this.registry.get(endpointId)) throw new Error("Endpoint is offline");
|
|
21
|
+
const binding = {
|
|
22
|
+
sessionKey: normalizedSessionKey,
|
|
23
|
+
endpointId,
|
|
24
|
+
boundAt: now
|
|
25
|
+
};
|
|
26
|
+
return this.store.set(binding);
|
|
27
|
+
}
|
|
28
|
+
get(sessionKey) {
|
|
29
|
+
return this.store.get(this.normalizeSessionKey(sessionKey));
|
|
30
|
+
}
|
|
31
|
+
resolve(sessionKey) {
|
|
32
|
+
const binding = this.get(sessionKey);
|
|
33
|
+
return binding ? this.registry.get(binding.endpointId) : void 0;
|
|
34
|
+
}
|
|
35
|
+
unbind(sessionKey) {
|
|
36
|
+
return this.store.delete(this.normalizeSessionKey(sessionKey));
|
|
37
|
+
}
|
|
38
|
+
normalizeSessionKey(sessionKey) {
|
|
39
|
+
const normalized = sessionKey.trim();
|
|
40
|
+
if (!normalized || normalized.length > 500) throw new TypeError("Invalid session key");
|
|
41
|
+
return normalized;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
//#endregion
|
|
45
|
+
export { EndpointBindingService };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { EndpointToolRuntime } from './runtime.js';
|
|
2
|
+
export { EndpointBindingService, type EndpointSessionBinding, type EndpointSessionBindingStore, } from './binding-service.js';
|
|
2
3
|
export { EndpointInvocationService, EndpointToolExecutionError, type EndpointInvocationAuditSink, type EndpointInvocationResult, } from './invocation-service.js';
|
|
3
4
|
export { EndpointToolPolicy, EndpointToolPolicyError } from './policy.js';
|
|
4
5
|
export { EndpointRegistry, endpointToolRevision, type EndpointConnectionSnapshot, type RegisteredEndpointTool, } from './registry.js';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { EndpointBindingService } from "./binding-service.js";
|
|
1
2
|
import { EndpointToolPolicy, EndpointToolPolicyError } from "./policy.js";
|
|
2
3
|
import { EndpointInvocationService, EndpointToolExecutionError } from "./invocation-service.js";
|
|
3
4
|
import { EndpointRegistry, endpointToolRevision } from "./registry.js";
|
|
4
5
|
import { ENDPOINT_UPLOAD_MAX_BYTES, EndpointUploadError, EndpointUploadService } from "./upload-service.js";
|
|
5
6
|
import { EndpointToolRuntime } from "./runtime.js";
|
|
6
|
-
export { ENDPOINT_UPLOAD_MAX_BYTES, EndpointInvocationService, EndpointRegistry, EndpointToolExecutionError, EndpointToolPolicy, EndpointToolPolicyError, EndpointToolRuntime, EndpointUploadError, EndpointUploadService, endpointToolRevision };
|
|
7
|
+
export { ENDPOINT_UPLOAD_MAX_BYTES, EndpointBindingService, EndpointInvocationService, EndpointRegistry, EndpointToolExecutionError, EndpointToolPolicy, EndpointToolPolicyError, EndpointToolRuntime, EndpointUploadError, EndpointUploadService, endpointToolRevision };
|
|
@@ -43,6 +43,7 @@ export declare class EndpointInvocationService {
|
|
|
43
43
|
private readonly options;
|
|
44
44
|
private readonly pending;
|
|
45
45
|
private readonly policy;
|
|
46
|
+
private readonly ajv;
|
|
46
47
|
constructor(registry: EndpointRegistry, options?: EndpointInvocationServiceOptions);
|
|
47
48
|
invoke(params: {
|
|
48
49
|
endpointId: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ENDPOINT_INVOCATION_RECEIPT_TIMEOUT_MS, canonicalJson } from "../../packages/endpoint-tools-protocol/src/index.js";
|
|
2
2
|
import { EndpointToolPolicy, EndpointToolPolicyError } from "./policy.js";
|
|
3
3
|
import crypto from "node:crypto";
|
|
4
|
+
import Ajv2020 from "ajv/dist/2020.js";
|
|
4
5
|
//#region src/endpoint-tools/invocation-service.ts
|
|
5
6
|
var EndpointToolExecutionError = class extends Error {
|
|
6
7
|
constructor(code, message) {
|
|
@@ -12,6 +13,10 @@ var EndpointToolExecutionError = class extends Error {
|
|
|
12
13
|
var EndpointInvocationService = class {
|
|
13
14
|
pending = /* @__PURE__ */ new Map();
|
|
14
15
|
policy;
|
|
16
|
+
ajv = new Ajv2020({
|
|
17
|
+
allErrors: true,
|
|
18
|
+
strict: true
|
|
19
|
+
});
|
|
15
20
|
constructor(registry, options = {}) {
|
|
16
21
|
this.registry = registry;
|
|
17
22
|
this.options = options;
|
|
@@ -58,6 +63,7 @@ var EndpointInvocationService = class {
|
|
|
58
63
|
id: invocationId,
|
|
59
64
|
endpointId: params.endpointId,
|
|
60
65
|
toolName: params.toolName,
|
|
66
|
+
descriptor: tool.descriptor,
|
|
61
67
|
state: "sent",
|
|
62
68
|
receiptTimer: setTimeout(() => {
|
|
63
69
|
this.fail(invocationId, this.error("TOOL_TIMEOUT", "Endpoint did not receive the invocation"));
|
|
@@ -111,6 +117,8 @@ var EndpointInvocationService = class {
|
|
|
111
117
|
case "tool.result":
|
|
112
118
|
if (pending.state !== "running") return;
|
|
113
119
|
try {
|
|
120
|
+
const validate = this.ajv.compile(pending.descriptor.outputSchema);
|
|
121
|
+
if (!validate(message.payload.content)) throw new Error(`Endpoint result does not match its contract: ${this.ajv.errorsText(validate.errors)}`);
|
|
114
122
|
this.options.uploads?.validateAndClose(invocationId, message.payload.content);
|
|
115
123
|
} catch (error) {
|
|
116
124
|
this.fail(invocationId, this.error("PROTOCOL_ERROR", error instanceof Error ? error.message : String(error)));
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type EndpointAvailability, type EndpointKind, type EndpointToolDescriptor } from '@xopcai/endpoint-tools-protocol';
|
|
2
2
|
export interface EndpointToolPolicyDecision {
|
|
3
3
|
confirmationRequired: boolean;
|
|
4
4
|
}
|
|
5
5
|
export declare class EndpointToolPolicyError extends Error {
|
|
6
6
|
}
|
|
7
7
|
export declare class EndpointToolPolicy {
|
|
8
|
+
private readonly ajv;
|
|
8
9
|
validateDescriptor(kind: EndpointKind, descriptor: EndpointToolDescriptor): void;
|
|
9
10
|
evaluate(descriptor: EndpointToolDescriptor, availability: EndpointAvailability): EndpointToolPolicyDecision;
|
|
11
|
+
private validatePolicyFields;
|
|
12
|
+
private assertFields;
|
|
10
13
|
}
|
|
@@ -1,17 +1,80 @@
|
|
|
1
|
+
import { ENDPOINT_CONTACT_LIST_OUTPUT_SCHEMA, ENDPOINT_CONTACT_OUTPUT_SCHEMA, ENDPOINT_FILE_OUTPUT_SCHEMA, ENDPOINT_TEXT_OUTPUT_SCHEMA, canonicalJson } from "../../packages/endpoint-tools-protocol/src/index.js";
|
|
2
|
+
import Ajv2020 from "ajv/dist/2020.js";
|
|
1
3
|
//#region src/endpoint-tools/policy.ts
|
|
2
4
|
var EndpointToolPolicyError = class extends Error {};
|
|
5
|
+
function contract(policyId, outputSchema, resultKinds, permissions) {
|
|
6
|
+
return {
|
|
7
|
+
policyId,
|
|
8
|
+
outputSchema,
|
|
9
|
+
resultKinds,
|
|
10
|
+
permissions
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const POLICY_BY_TOOL = {
|
|
14
|
+
"web.file.pick": contract("personal.foreground-read", ENDPOINT_FILE_OUTPUT_SCHEMA, ["file"], ["file-read"]),
|
|
15
|
+
"web.file.download": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["file-download"]),
|
|
16
|
+
"web.page.get_selection": contract("public.foreground-read", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], []),
|
|
17
|
+
"web.clipboard.write": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-write"]),
|
|
18
|
+
"web.page.navigate": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["navigation"]),
|
|
19
|
+
"desktop.file.pick": contract("personal.foreground-read", ENDPOINT_FILE_OUTPUT_SCHEMA, ["file"], ["file-read"]),
|
|
20
|
+
"desktop.file.save": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["file-write"]),
|
|
21
|
+
"desktop.notification.show": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["notifications"]),
|
|
22
|
+
"desktop.clipboard.read": contract("personal.foreground-read", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-read"]),
|
|
23
|
+
"desktop.clipboard.write": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-write"]),
|
|
24
|
+
"desktop.app.open_external": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["open-external-url"]),
|
|
25
|
+
"mobile.contacts.pick": contract("personal.foreground-read", ENDPOINT_CONTACT_OUTPUT_SCHEMA, ["json"], ["contacts-read-selected"]),
|
|
26
|
+
"mobile.contacts.search": contract("personal.foreground-read", ENDPOINT_CONTACT_LIST_OUTPUT_SCHEMA, ["json"], ["contacts-read"]),
|
|
27
|
+
"mobile.contacts.get": contract("personal.foreground-read", ENDPOINT_CONTACT_OUTPUT_SCHEMA, ["json"], ["contacts-read"]),
|
|
28
|
+
"mobile.file.pick": contract("personal.foreground-read", ENDPOINT_FILE_OUTPUT_SCHEMA, ["file"], ["file-read"]),
|
|
29
|
+
"mobile.file.share": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["file-share"]),
|
|
30
|
+
"mobile.notification.show": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["notifications"]),
|
|
31
|
+
"mobile.device.get_info": contract("public.background-read", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], []),
|
|
32
|
+
"mobile.clipboard.write": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["clipboard-write"]),
|
|
33
|
+
"mobile.app.open_url": contract("user.foreground-write", ENDPOINT_TEXT_OUTPUT_SCHEMA, ["text"], ["open-external-url"])
|
|
34
|
+
};
|
|
3
35
|
var EndpointToolPolicy = class {
|
|
36
|
+
ajv = new Ajv2020({
|
|
37
|
+
allErrors: true,
|
|
38
|
+
strict: true
|
|
39
|
+
});
|
|
4
40
|
validateDescriptor(kind, descriptor) {
|
|
5
41
|
if (!descriptor.name.startsWith(`${kind}.`)) throw new EndpointToolPolicyError(`Tool ${descriptor.name} does not belong to ${kind}`);
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
42
|
+
const contract = POLICY_BY_TOOL[descriptor.name];
|
|
43
|
+
if (!contract) throw new EndpointToolPolicyError(`Tool ${descriptor.name} has no trusted server policy`);
|
|
44
|
+
if (descriptor.policyId !== contract.policyId) throw new EndpointToolPolicyError(`Tool ${descriptor.name} does not match its trusted server policy`);
|
|
45
|
+
if (canonicalJson(descriptor.outputSchema) !== canonicalJson(contract.outputSchema) || canonicalJson(descriptor.resultKinds) !== canonicalJson(contract.resultKinds) || canonicalJson([...descriptor.requiredPermissions].sort()) !== canonicalJson([...contract.permissions].sort())) throw new EndpointToolPolicyError(`Tool ${descriptor.name} does not match its trusted server contract`);
|
|
46
|
+
this.validatePolicyFields(descriptor);
|
|
47
|
+
try {
|
|
48
|
+
this.ajv.compile(descriptor.outputSchema);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
throw new EndpointToolPolicyError(`Tool ${descriptor.name} has an invalid output schema: ${error instanceof Error ? error.message : String(error)}`);
|
|
10
51
|
}
|
|
11
52
|
}
|
|
12
53
|
evaluate(descriptor, availability) {
|
|
13
54
|
if (descriptor.requiresForeground && availability !== "foreground") throw new EndpointToolPolicyError("Endpoint is not in the foreground");
|
|
14
|
-
return { confirmationRequired: descriptor.confirmation === "always"
|
|
55
|
+
return { confirmationRequired: descriptor.confirmation === "always" };
|
|
56
|
+
}
|
|
57
|
+
validatePolicyFields(descriptor) {
|
|
58
|
+
switch (descriptor.policyId) {
|
|
59
|
+
case "public.background-read":
|
|
60
|
+
this.assertFields(descriptor, "read", "never", false, "public");
|
|
61
|
+
return;
|
|
62
|
+
case "public.foreground-read":
|
|
63
|
+
this.assertFields(descriptor, "read", "never", true, "public");
|
|
64
|
+
return;
|
|
65
|
+
case "personal.foreground-read":
|
|
66
|
+
this.assertFields(descriptor, "read", "always", true, "personal");
|
|
67
|
+
if (descriptor.requiredPermissions.length === 0) throw new EndpointToolPolicyError(`Personal tool ${descriptor.name} must declare a permission`);
|
|
68
|
+
return;
|
|
69
|
+
case "user.foreground-write":
|
|
70
|
+
if (descriptor.effect === "read") throw new EndpointToolPolicyError(`Mutating tool ${descriptor.name} cannot declare a read effect`);
|
|
71
|
+
if (descriptor.confirmation !== "always" || !descriptor.requiresForeground || descriptor.sensitivity !== "personal" || descriptor.requiredPermissions.length === 0) throw new EndpointToolPolicyError(`Mutating tool ${descriptor.name} violates its trusted policy`);
|
|
72
|
+
return;
|
|
73
|
+
default: throw new EndpointToolPolicyError(`Unknown endpoint policy: ${descriptor.policyId}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
assertFields(descriptor, effect, confirmation, requiresForeground, sensitivity) {
|
|
77
|
+
if (descriptor.effect !== effect || descriptor.confirmation !== confirmation || descriptor.requiresForeground !== requiresForeground || descriptor.sensitivity !== sensitivity) throw new EndpointToolPolicyError(`Tool ${descriptor.name} violates its trusted policy`);
|
|
15
78
|
}
|
|
16
79
|
};
|
|
17
80
|
//#endregion
|
|
@@ -93,7 +93,7 @@ var EndpointRegistry = class {
|
|
|
93
93
|
const connection = this.connectionByEndpointId.get(endpointId);
|
|
94
94
|
if (!connection || connection.transport.readyState !== 1) throw new Error(`Endpoint is offline: ${endpointId}`);
|
|
95
95
|
const message = {
|
|
96
|
-
protocolVersion:
|
|
96
|
+
protocolVersion: 2,
|
|
97
97
|
messageId: crypto.randomUUID(),
|
|
98
98
|
type,
|
|
99
99
|
sentAt: Date.now(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ClientEndpointMessage, type EndpointHelloPayload } from '@xopcai/endpoint-tools-protocol';
|
|
2
2
|
import { type EndpointAuthenticatorDeps } from './auth.js';
|
|
3
|
+
import { EndpointBindingService } from './binding-service.js';
|
|
3
4
|
import { EndpointInvocationService, type EndpointInvocationAuditSink } from './invocation-service.js';
|
|
4
5
|
import { EndpointRegistry, type EndpointRegistration, type EndpointTransport } from './registry.js';
|
|
5
6
|
import { EndpointUploadService } from './upload-service.js';
|
|
@@ -7,6 +8,7 @@ export declare class EndpointToolRuntime {
|
|
|
7
8
|
readonly registry: EndpointRegistry;
|
|
8
9
|
readonly invocations: EndpointInvocationService;
|
|
9
10
|
readonly uploads: EndpointUploadService;
|
|
11
|
+
readonly bindings: EndpointBindingService;
|
|
10
12
|
private readonly authenticator;
|
|
11
13
|
private closed;
|
|
12
14
|
constructor(options?: {
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { resolveStateDir } from "../config/paths-state.js";
|
|
2
2
|
import { createLogger } from "../utils/logger/index.js";
|
|
3
3
|
import { init_logger } from "../utils/logger.js";
|
|
4
|
+
import { deleteEndpointSessionBinding, getEndpointSessionBinding, setEndpointSessionBinding } from "../storage/sqlite/endpoint-session-binding-repository.js";
|
|
4
5
|
import { bindEndpointPrincipal, getEndpointPrincipal, touchEndpointPrincipal } from "../storage/sqlite/endpoint-principal-repository.js";
|
|
5
6
|
import { finishEndpointToolInvocationAudit, startEndpointToolInvocationAudit } from "../storage/sqlite/endpoint-tool-invocation-repository.js";
|
|
6
7
|
import "../storage/sqlite/index.js";
|
|
7
8
|
import { init_paths } from "../config/paths.js";
|
|
8
9
|
import { EndpointAuthenticator } from "./auth.js";
|
|
10
|
+
import { EndpointBindingService } from "./binding-service.js";
|
|
9
11
|
import { EndpointToolPolicy } from "./policy.js";
|
|
10
12
|
import { EndpointInvocationService } from "./invocation-service.js";
|
|
11
13
|
import { EndpointRegistry } from "./registry.js";
|
|
@@ -20,11 +22,17 @@ var EndpointToolRuntime = class {
|
|
|
20
22
|
registry;
|
|
21
23
|
invocations;
|
|
22
24
|
uploads;
|
|
25
|
+
bindings;
|
|
23
26
|
authenticator;
|
|
24
27
|
closed = false;
|
|
25
28
|
constructor(options = {}) {
|
|
26
29
|
const policy = new EndpointToolPolicy();
|
|
27
30
|
this.registry = new EndpointRegistry(policy);
|
|
31
|
+
this.bindings = new EndpointBindingService(this.registry, {
|
|
32
|
+
get: getEndpointSessionBinding,
|
|
33
|
+
set: setEndpointSessionBinding,
|
|
34
|
+
delete: deleteEndpointSessionBinding
|
|
35
|
+
});
|
|
28
36
|
this.authenticator = new EndpointAuthenticator(options.auth ?? {
|
|
29
37
|
getPrincipal: getEndpointPrincipal,
|
|
30
38
|
bindEndpoint: bindEndpointPrincipal,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
|
-
import { init_paths, resolveExtensionsDir, resolveExtensionsLockPath } from "../config/paths.js";
|
|
4
3
|
import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
|
|
4
|
+
import { init_paths, resolveExtensionsDir, resolveExtensionsLockPath } from "../config/paths.js";
|
|
5
5
|
import { dirname, join } from "path";
|
|
6
6
|
import { existsSync } from "fs";
|
|
7
7
|
import { mkdir, readFile } from "fs/promises";
|
|
@@ -26,6 +26,7 @@ const TEXT_EXTENSIONS = new Set([
|
|
|
26
26
|
"svg",
|
|
27
27
|
"ts",
|
|
28
28
|
"tsx",
|
|
29
|
+
"tsv",
|
|
29
30
|
"txt",
|
|
30
31
|
"xml",
|
|
31
32
|
"yaml",
|
|
@@ -50,10 +51,18 @@ const MIME_TYPES = {
|
|
|
50
51
|
ts: "text/typescript",
|
|
51
52
|
tsx: "text/typescript",
|
|
52
53
|
csv: "text/csv",
|
|
54
|
+
tsv: "text/tab-separated-values",
|
|
53
55
|
xml: "application/xml",
|
|
54
56
|
yaml: "application/yaml",
|
|
55
57
|
yml: "application/yaml",
|
|
56
58
|
pdf: "application/pdf",
|
|
59
|
+
doc: "application/msword",
|
|
60
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
61
|
+
xls: "application/vnd.ms-excel",
|
|
62
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
63
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
64
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
65
|
+
zip: "application/zip",
|
|
57
66
|
mp3: "audio/mpeg",
|
|
58
67
|
wav: "audio/wav",
|
|
59
68
|
ogg: "audio/ogg",
|
|
@@ -106,13 +115,13 @@ async function resolveFilePath(root, path, mustExist = true) {
|
|
|
106
115
|
const canonicalRoot = await realpath(root).catch(() => {
|
|
107
116
|
throw new FileServiceError(404, "File space is unavailable");
|
|
108
117
|
});
|
|
109
|
-
const candidate = resolve(canonicalRoot, normalizeRelativePath(path));
|
|
110
|
-
if (!isWithin(canonicalRoot, candidate)) throw new FileServiceError(400, "Invalid file path");
|
|
118
|
+
const candidate = isAbsolute(path) ? resolve(path) : resolve(canonicalRoot, normalizeRelativePath(path));
|
|
111
119
|
if (!mustExist) {
|
|
112
|
-
|
|
120
|
+
const parent = await realpath(dirname(candidate)).catch(() => {
|
|
113
121
|
throw new FileServiceError(404, "Parent directory not found");
|
|
114
|
-
})
|
|
115
|
-
|
|
122
|
+
});
|
|
123
|
+
if (!isWithin(canonicalRoot, parent)) throw new FileServiceError(400, "Invalid file path");
|
|
124
|
+
return resolve(parent, basename(candidate));
|
|
116
125
|
}
|
|
117
126
|
const canonicalTarget = await realpath(candidate).catch(() => {
|
|
118
127
|
throw new FileServiceError(404, "File not found");
|
|
@@ -247,4 +247,4 @@ export declare const GATEWAY_BUILTIN_TOOLS: readonly [{
|
|
|
247
247
|
readonly zh: "使用已验证的参数执行选定的外部工具。";
|
|
248
248
|
};
|
|
249
249
|
}];
|
|
250
|
-
export declare const GATEWAY_BUILTIN_TOOL_IDS: ("automation" | "workflow" | "find" | "todo" | "image" | "clarify" | "dreaming" | "memory_search" | "memory_get" | "web_search" | "web_fetch" | "browser_use" | "grep" | "session_search" | "read_file" | "list_dir" | "write_file" | "apply_patch" | "exec_command" | "update_plan" | "
|
|
250
|
+
export declare const GATEWAY_BUILTIN_TOOL_IDS: ("automation" | "workflow" | "find" | "todo" | "image" | "clarify" | "dreaming" | "memory_search" | "memory_get" | "web_search" | "web_fetch" | "browser_use" | "grep" | "session_search" | "read_file" | "list_dir" | "write_file" | "apply_patch" | "exec_command" | "update_plan" | "web_extract" | "image_generate" | "skills_list" | "skill_view" | "skill_manage" | "skills_marketplace_search" | "xopc_tool_search" | "xopc_tool_describe" | "xopc_tool_execute" | "send_message" | "send_media" | "read_media" | "create_share" | "session_status" | "tool_manual" | "delegate_task" | "skill_install" | "text_to_speech" | "execute_code" | "create_desktop_pet")[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveAgentDir, resolveAgentProfileDir, resolveAgentWorkspaceDir, resolveDefaultAgentId, resolveUserPath, validateAgentIdForNewAgent } from "../agent/agent-scope.js";
|
|
2
|
-
import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
|
|
3
2
|
import { WORKSPACE_FILES, init_paths } from "../config/paths.js";
|
|
3
|
+
import { resolveEffectiveAgentProfile } from "../config/agent-profile.js";
|
|
4
4
|
import { AGENT_PROFILE_MARKDOWN_SYSTEM_FILES, REQUIRED_AGENT_PROFILE_MARKDOWN_FILE_SET } from "../agent/context/workspace.js";
|
|
5
5
|
import { isPathUnderWorkspace, resolveWorkspaceSafePath } from "./workspace-editor-path.js";
|
|
6
6
|
import { seedAgentProfileMarkdownFiles } from "../agent/context/workspace-seed.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseTurnOutcome } from "../../../packages/gateway-contract/src/turn-outcome.js";
|
|
1
2
|
import { resolveToolActivity } from "../../../packages/gateway-contract/src/tool-activity.js";
|
|
2
3
|
import { createPetFeedback } from "./pet-feedback.js";
|
|
3
4
|
//#region src/gateway/chat-stream/mapper.ts
|
|
@@ -126,6 +127,10 @@ var ChatStreamMapper = class {
|
|
|
126
127
|
kind
|
|
127
128
|
}] : [];
|
|
128
129
|
}) : [] })];
|
|
130
|
+
case "turn_outcome": {
|
|
131
|
+
const outcome = parseTurnOutcome(event.outcome);
|
|
132
|
+
return outcome ? [this.make("turn_outcome", outcome)] : [];
|
|
133
|
+
}
|
|
129
134
|
case "error": return [this.make("error", {
|
|
130
135
|
code: "AGENT_RUN_ERROR",
|
|
131
136
|
message: String(event.content ?? event.message ?? "Unknown error"),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { ContextCompactionPolicySchema, UserContextDreamingSchema, UserContextPrivacySchema, init_config } from "../../../user-context/config.js";
|
|
2
2
|
import { init_agent_scope, listAgentEntries, normalizeAgentId, resolveDefaultAgentId } from "../../../agent/agent-scope.js";
|
|
3
3
|
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
4
|
-
import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
|
|
5
4
|
import { init_models_json, loadModelsJson } from "../../../config/models-json.js";
|
|
6
5
|
import { CredentialResolver, init_credentials } from "../../../auth/credentials.js";
|
|
6
|
+
import { buildChannelCatalogForConfig, buildChannelCatalogFromSnapshot, getChannelSetupStatus, init_channel_catalog_service } from "../../../channels/catalog/channel-catalog-service.js";
|
|
7
7
|
import { getProviderRegistry, init_plugin_registry } from "../../../providers/plugin-registry.js";
|
|
8
8
|
import { getAllProviders, init_providers, isProviderConfigured } from "../../../providers/index.js";
|
|
9
9
|
import { normalizeConfiguredMcpServers } from "../../../config/mcp-config-normalize.js";
|
|
@@ -31,7 +31,7 @@ function extractTokenFromHeader(authHeader) {
|
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
33
|
* SECURITY: query-string tokens leak into server logs, Referer headers, and
|
|
34
|
-
* browser history. We accept them only for
|
|
34
|
+
* browser history. We accept them only for avatar `<img>` loads, where an
|
|
35
35
|
* Authorization header cannot be set. Realtime WebSocket authentication uses a
|
|
36
36
|
* one-time ticket acquired over authenticated HTTP.
|
|
37
37
|
*/
|
|
@@ -39,9 +39,10 @@ function extractTokenFromQuery(url) {
|
|
|
39
39
|
return new URL(url).searchParams.get("token");
|
|
40
40
|
}
|
|
41
41
|
const AGENT_AVATAR_GET_PATH = /^\/api\/agents\/[^/]+\/avatar$/;
|
|
42
|
+
const USER_AVATAR_GET_PATH = "/api/you/avatar";
|
|
42
43
|
/** Exported for gateway security tests. */
|
|
43
44
|
function isQueryTokenAllowedPath(path, method) {
|
|
44
|
-
if (method === "GET" && AGENT_AVATAR_GET_PATH.test(path)) return true;
|
|
45
|
+
if (method === "GET" && (AGENT_AVATAR_GET_PATH.test(path) || path === USER_AVATAR_GET_PATH)) return true;
|
|
45
46
|
return false;
|
|
46
47
|
}
|
|
47
48
|
function resolveRemoteAddress(c) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { endpointPrincipalRegistrationSchema } from "../../../../packages/endpoint-tools-protocol/src/index.js";
|
|
1
|
+
import { endpointPrincipalRegistrationSchema, endpointSessionBindingRequestSchema } from "../../../../packages/endpoint-tools-protocol/src/index.js";
|
|
2
2
|
import { createEndpointPrincipal, getEndpointPrincipal, listEndpointPrincipals, revokeEndpointPrincipal } from "../../../storage/sqlite/endpoint-principal-repository.js";
|
|
3
3
|
import { listEndpointToolInvocationAudits } from "../../../storage/sqlite/endpoint-tool-invocation-repository.js";
|
|
4
4
|
import "../../../storage/sqlite/index.js";
|
|
@@ -130,6 +130,73 @@ function registerEndpointToolRoutes(authenticated, deps) {
|
|
|
130
130
|
payload: listEndpointToolInvocationAudits(Number.isFinite(limit) ? limit : 100)
|
|
131
131
|
});
|
|
132
132
|
});
|
|
133
|
+
authenticated.get("/api/endpoint-tools/bindings/:sessionKey", (c) => {
|
|
134
|
+
try {
|
|
135
|
+
const binding = deps.service.endpointTools.bindings.get(c.req.param("sessionKey"));
|
|
136
|
+
return binding ? c.json({
|
|
137
|
+
ok: true,
|
|
138
|
+
payload: binding
|
|
139
|
+
}) : c.json({
|
|
140
|
+
ok: false,
|
|
141
|
+
error: {
|
|
142
|
+
code: "NOT_FOUND",
|
|
143
|
+
message: "Endpoint binding not found"
|
|
144
|
+
}
|
|
145
|
+
}, 404);
|
|
146
|
+
} catch {
|
|
147
|
+
return c.json({
|
|
148
|
+
ok: false,
|
|
149
|
+
error: {
|
|
150
|
+
code: "BAD_REQUEST",
|
|
151
|
+
message: "Invalid session key"
|
|
152
|
+
}
|
|
153
|
+
}, 400);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
authenticated.put("/api/endpoint-tools/bindings/:sessionKey", async (c) => {
|
|
157
|
+
const parsed = endpointSessionBindingRequestSchema.safeParse(await c.req.json().catch(() => null));
|
|
158
|
+
if (!parsed.success) return c.json({
|
|
159
|
+
ok: false,
|
|
160
|
+
error: {
|
|
161
|
+
code: "BAD_REQUEST",
|
|
162
|
+
message: "Invalid endpoint binding"
|
|
163
|
+
}
|
|
164
|
+
}, 400);
|
|
165
|
+
try {
|
|
166
|
+
const binding = deps.service.endpointTools.bindings.bind(c.req.param("sessionKey"), parsed.data.endpointId);
|
|
167
|
+
return c.json({
|
|
168
|
+
ok: true,
|
|
169
|
+
payload: binding
|
|
170
|
+
});
|
|
171
|
+
} catch (error) {
|
|
172
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
173
|
+
const status = message === "Endpoint is offline" ? 409 : 400;
|
|
174
|
+
return c.json({
|
|
175
|
+
ok: false,
|
|
176
|
+
error: {
|
|
177
|
+
code: "BINDING_FAILED",
|
|
178
|
+
message
|
|
179
|
+
}
|
|
180
|
+
}, status);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
authenticated.delete("/api/endpoint-tools/bindings/:sessionKey", (c) => {
|
|
184
|
+
try {
|
|
185
|
+
const removed = deps.service.endpointTools.bindings.unbind(c.req.param("sessionKey"));
|
|
186
|
+
return c.json({
|
|
187
|
+
ok: true,
|
|
188
|
+
payload: { removed }
|
|
189
|
+
});
|
|
190
|
+
} catch {
|
|
191
|
+
return c.json({
|
|
192
|
+
ok: false,
|
|
193
|
+
error: {
|
|
194
|
+
code: "BAD_REQUEST",
|
|
195
|
+
message: "Invalid session key"
|
|
196
|
+
}
|
|
197
|
+
}, 400);
|
|
198
|
+
}
|
|
199
|
+
});
|
|
133
200
|
authenticated.post("/api/endpoint-tools/invocations/:invocationId/files", async (c) => {
|
|
134
201
|
const invocationId = c.req.param("invocationId");
|
|
135
202
|
const endpointId = c.req.header("x-endpoint-id") ?? "";
|
|
@@ -119,6 +119,13 @@ function registerFilesRoutes(authenticated, deps) {
|
|
|
119
119
|
return errorResponse(c, error);
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
|
+
authenticated.get("/api/files/:id/host-path", async (c) => {
|
|
123
|
+
try {
|
|
124
|
+
return c.json({ absolutePath: (await files.resource(c.req.param("id"))).absolutePath });
|
|
125
|
+
} catch (error) {
|
|
126
|
+
return errorResponse(c, error);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
122
129
|
authenticated.get("/api/files/:id/content", async (c) => {
|
|
123
130
|
try {
|
|
124
131
|
const { resource, absolutePath } = await files.resource(c.req.param("id"));
|
|
@@ -100,6 +100,14 @@ const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
|
|
|
100
100
|
} };
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
+
{
|
|
104
|
+
id: "support",
|
|
105
|
+
match: (path) => startsWithAny(path, ["/api/support"]),
|
|
106
|
+
load: async () => {
|
|
107
|
+
const { registerSupportRoutes } = await import("./support.js");
|
|
108
|
+
return { register: registerSupportRoutes };
|
|
109
|
+
}
|
|
110
|
+
},
|
|
103
111
|
{
|
|
104
112
|
id: "image-generation",
|
|
105
113
|
match: (path) => startsWithAny(path, ["/api/image-generation"]) || /^\/api\/agents\/[^/]+\/image-generation(?:\/setup)?$/.test(path),
|
|
@@ -9,6 +9,26 @@ import { messagesReferenceMediaUri } from "../../../media/session-references.js"
|
|
|
9
9
|
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
10
10
|
//#region src/gateway/hono/routes/media.ts
|
|
11
11
|
const log = createGatewayRouteLogger("Media");
|
|
12
|
+
function parseByteRange(header, size) {
|
|
13
|
+
if (!header) return null;
|
|
14
|
+
const match = /^bytes=(\d*)-(\d*)$/i.exec(header.trim());
|
|
15
|
+
if (!match || !match[1] && !match[2] || size <= 0) return "invalid";
|
|
16
|
+
if (!match[1]) {
|
|
17
|
+
const suffixLength = Number(match[2]);
|
|
18
|
+
if (!Number.isSafeInteger(suffixLength) || suffixLength <= 0) return "invalid";
|
|
19
|
+
return {
|
|
20
|
+
start: Math.max(0, size - suffixLength),
|
|
21
|
+
end: size - 1
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const start = Number(match[1]);
|
|
25
|
+
const requestedEnd = match[2] ? Number(match[2]) : size - 1;
|
|
26
|
+
if (!Number.isSafeInteger(start) || !Number.isSafeInteger(requestedEnd) || start < 0 || start >= size || requestedEnd < start) return "invalid";
|
|
27
|
+
return {
|
|
28
|
+
start,
|
|
29
|
+
end: Math.min(requestedEnd, size - 1)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
12
32
|
function registerMediaRoutes(authenticated, deps) {
|
|
13
33
|
const tasks = new TaskRepository();
|
|
14
34
|
authenticated.post("/api/media", deps.strictRateLimitMiddleware, async (c) => {
|
|
@@ -64,9 +84,33 @@ function registerMediaRoutes(authenticated, deps) {
|
|
|
64
84
|
}, 404);
|
|
65
85
|
const { buffer, path } = await readMediaReference(parsed.uri);
|
|
66
86
|
const contentType = mimeTypeFromMediaPath(path);
|
|
87
|
+
const range = parseByteRange(c.req.header("Range"), buffer.byteLength);
|
|
88
|
+
const commonHeaders = {
|
|
89
|
+
"Accept-Ranges": "bytes",
|
|
90
|
+
"Cache-Control": "private, max-age=3600",
|
|
91
|
+
"Content-Type": contentType
|
|
92
|
+
};
|
|
93
|
+
if (range === "invalid") return new Response(null, {
|
|
94
|
+
status: 416,
|
|
95
|
+
headers: {
|
|
96
|
+
...commonHeaders,
|
|
97
|
+
"Content-Range": `bytes */${buffer.byteLength}`
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
if (range) {
|
|
101
|
+
const body = buffer.subarray(range.start, range.end + 1);
|
|
102
|
+
return new Response(body, {
|
|
103
|
+
status: 206,
|
|
104
|
+
headers: {
|
|
105
|
+
...commonHeaders,
|
|
106
|
+
"Content-Length": String(body.byteLength),
|
|
107
|
+
"Content-Range": `bytes ${range.start}-${range.end}/${buffer.byteLength}`
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
67
111
|
return new Response(buffer, { headers: {
|
|
68
|
-
|
|
69
|
-
"
|
|
112
|
+
...commonHeaders,
|
|
113
|
+
"Content-Length": String(buffer.byteLength)
|
|
70
114
|
} });
|
|
71
115
|
} catch (err) {
|
|
72
116
|
const em = err instanceof Error ? err.message : String(err);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
2
1
|
import { init_resolve_config_value, testApiKeyResolution } from "../../../config/resolve-config-value.js";
|
|
2
|
+
import { resolveModelsJsonPath } from "../../../config/paths.js";
|
|
3
3
|
import { init_models_json, loadModelsJson, saveModelsJson, validateModelsConfig } from "../../../config/models-json.js";
|
|
4
4
|
import { getModelCatalogStore, init_model_catalog_store } from "../../../providers/model-catalog-store.js";
|
|
5
5
|
import { getModelRegistry } from "../../../providers/model-registry.js";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { buildSupportInvestigationPrompt } from "../../../support/build-support-investigation-prompt.js";
|
|
2
|
+
import { collectSupportReport } from "../../../support/collect-support-report.js";
|
|
3
|
+
import { SupportReportInputSchema } from "../../../support/types.js";
|
|
4
|
+
//#region src/gateway/hono/routes/support.ts
|
|
5
|
+
function registerSupportRoutes(authenticated, deps) {
|
|
6
|
+
authenticated.post("/api/support/report", deps.strictRateLimitMiddleware, async (c) => {
|
|
7
|
+
const parsed = SupportReportInputSchema.safeParse(await c.req.json().catch(() => null));
|
|
8
|
+
if (!parsed.success) return c.json({
|
|
9
|
+
ok: false,
|
|
10
|
+
error: "Invalid support report input"
|
|
11
|
+
}, 400);
|
|
12
|
+
const health = deps.service.getHealth();
|
|
13
|
+
const channels = Object.fromEntries(deps.service.getChannelsStatus().map((channel) => [channel.name, !channel.enabled ? "disabled" : channel.connected ? "connected" : "disconnected"]));
|
|
14
|
+
const report = await collectSupportReport(parsed.data, { runtime: {
|
|
15
|
+
gatewayStatus: health.status,
|
|
16
|
+
gatewayVersion: health.version,
|
|
17
|
+
gatewayUptimeMs: health.uptime,
|
|
18
|
+
channels
|
|
19
|
+
} });
|
|
20
|
+
return c.json({
|
|
21
|
+
ok: true,
|
|
22
|
+
report,
|
|
23
|
+
investigationPrompt: buildSupportInvestigationPrompt(report)
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { registerSupportRoutes };
|