@aopslab/aops-server 0.1.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.
- package/LICENSE +202 -0
- package/NOTICE +6 -0
- package/README.md +21 -0
- package/aops-server-runtime.json +11 -0
- package/build/client/_app/immutable/chunks/2_TffmqH.js +1 -0
- package/build/client/_app/immutable/chunks/3DOfIKW0.js +1 -0
- package/build/client/_app/immutable/chunks/B2EkC-sy.js +1 -0
- package/build/client/_app/immutable/chunks/CMkIcmi1.js +2 -0
- package/build/client/_app/immutable/chunks/rqnVXeyB.js +1 -0
- package/build/client/_app/immutable/chunks/sZYZbj9W.js +1 -0
- package/build/client/_app/immutable/chunks/wbPk3Yxo.js +81 -0
- package/build/client/_app/immutable/entry/app.C7STLTX8.js +2 -0
- package/build/client/_app/immutable/entry/start.BC94hOaC.js +1 -0
- package/build/client/_app/immutable/nodes/0.BYBfjxZ5.js +1 -0
- package/build/client/_app/immutable/nodes/1.BNXFXajG.js +1 -0
- package/build/client/_app/version.json +1 -0
- package/build/env.js +70 -0
- package/build/env.js.map +1 -0
- package/build/handler.js +16 -0
- package/build/handler.js.map +1 -0
- package/build/index.js +139 -0
- package/build/index.js.map +1 -0
- package/build/server/chunks/0-RfB6m2nq.js +7 -0
- package/build/server/chunks/0-RfB6m2nq.js.map +1 -0
- package/build/server/chunks/1-_gg8Q0UT.js +9 -0
- package/build/server/chunks/1-_gg8Q0UT.js.map +1 -0
- package/build/server/chunks/_server.ts-6276EQIF.js +44 -0
- package/build/server/chunks/_server.ts-6276EQIF.js.map +1 -0
- package/build/server/chunks/_server.ts-B59WFQzX.js +174 -0
- package/build/server/chunks/_server.ts-B59WFQzX.js.map +1 -0
- package/build/server/chunks/_server.ts-BauJsLZI.js +40 -0
- package/build/server/chunks/_server.ts-BauJsLZI.js.map +1 -0
- package/build/server/chunks/_server.ts-BnGzJw2-.js +81 -0
- package/build/server/chunks/_server.ts-BnGzJw2-.js.map +1 -0
- package/build/server/chunks/_server.ts-CP7qM24V.js +34 -0
- package/build/server/chunks/_server.ts-CP7qM24V.js.map +1 -0
- package/build/server/chunks/_server.ts-Cbq_u99d.js +9 -0
- package/build/server/chunks/_server.ts-Cbq_u99d.js.map +1 -0
- package/build/server/chunks/_server.ts-Ch8fPT-o.js +92 -0
- package/build/server/chunks/_server.ts-Ch8fPT-o.js.map +1 -0
- package/build/server/chunks/_server.ts-Cv-yaXZI.js +7 -0
- package/build/server/chunks/_server.ts-Cv-yaXZI.js.map +1 -0
- package/build/server/chunks/_server.ts-D6lBwOON.js +34 -0
- package/build/server/chunks/_server.ts-D6lBwOON.js.map +1 -0
- package/build/server/chunks/_server.ts-D84K3pp9.js +11 -0
- package/build/server/chunks/_server.ts-D84K3pp9.js.map +1 -0
- package/build/server/chunks/_server.ts-DNzU1ToA.js +277 -0
- package/build/server/chunks/_server.ts-DNzU1ToA.js.map +1 -0
- package/build/server/chunks/_server.ts-DQQnw77t.js +17 -0
- package/build/server/chunks/_server.ts-DQQnw77t.js.map +1 -0
- package/build/server/chunks/_server.ts-DSxr5l15.js +18 -0
- package/build/server/chunks/_server.ts-DSxr5l15.js.map +1 -0
- package/build/server/chunks/_server.ts-DZYokvuR.js +80 -0
- package/build/server/chunks/_server.ts-DZYokvuR.js.map +1 -0
- package/build/server/chunks/_server.ts-Dcqwpz2t.js +144 -0
- package/build/server/chunks/_server.ts-Dcqwpz2t.js.map +1 -0
- package/build/server/chunks/_server.ts-Di9VJnF4.js +81 -0
- package/build/server/chunks/_server.ts-Di9VJnF4.js.map +1 -0
- package/build/server/chunks/_server.ts-FBEHFT8b.js +33 -0
- package/build/server/chunks/_server.ts-FBEHFT8b.js.map +1 -0
- package/build/server/chunks/_server.ts-gZytCuiJ.js +10 -0
- package/build/server/chunks/_server.ts-gZytCuiJ.js.map +1 -0
- package/build/server/chunks/_server.ts-tNULLyEO.js +261 -0
- package/build/server/chunks/_server.ts-tNULLyEO.js.map +1 -0
- package/build/server/chunks/agent-gateway-runtime-DTZ4SxaC.js +2598 -0
- package/build/server/chunks/agent-gateway-runtime-DTZ4SxaC.js.map +1 -0
- package/build/server/chunks/aops-runtime-config-wpVmg7T-.js +179 -0
- package/build/server/chunks/aops-runtime-config-wpVmg7T-.js.map +1 -0
- package/build/server/chunks/discovery-D9JnSgfu.js +894 -0
- package/build/server/chunks/discovery-D9JnSgfu.js.map +1 -0
- package/build/server/chunks/error.svelte-DgUOqi-L.js +45 -0
- package/build/server/chunks/error.svelte-DgUOqi-L.js.map +1 -0
- package/build/server/chunks/handler-BN3-p5rP.js +1733 -0
- package/build/server/chunks/handler-BN3-p5rP.js.map +1 -0
- package/build/server/chunks/hooks.server-C4wxiH5m.js +52 -0
- package/build/server/chunks/hooks.server-C4wxiH5m.js.map +1 -0
- package/build/server/chunks/index.js-nbqdVuWC.js +10698 -0
- package/build/server/chunks/index.js-nbqdVuWC.js.map +1 -0
- package/build/server/chunks/manifest.js-_Re-Wj-y.js +167 -0
- package/build/server/chunks/manifest.js-_Re-Wj-y.js.map +1 -0
- package/build/server/chunks/plugin-error-normalize-Bq14Qbz3.js +297 -0
- package/build/server/chunks/plugin-error-normalize-Bq14Qbz3.js.map +1 -0
- package/build/server/chunks/project-alias-DqE2v58Q.js +29 -0
- package/build/server/chunks/project-alias-DqE2v58Q.js.map +1 -0
- package/build/server/chunks/registry-5amIZito.js +289 -0
- package/build/server/chunks/registry-5amIZito.js.map +1 -0
- package/build/server/chunks/request-base-url-BDdrsaga.js +24 -0
- package/build/server/chunks/request-base-url-BDdrsaga.js.map +1 -0
- package/build/server/chunks/request-context-tNeFQjgb.js +422 -0
- package/build/server/chunks/request-context-tNeFQjgb.js.map +1 -0
- package/build/server/chunks/xf-result-BRDjvftr.js +17 -0
- package/build/server/chunks/xf-result-BRDjvftr.js.map +1 -0
- package/build/shims.js +33 -0
- package/build/shims.js.map +1 -0
- package/cockpit/.vite/manifest.json +198 -0
- package/cockpit/assets/dm-sans-latin-400-normal-BwCSEQnW.woff +0 -0
- package/cockpit/assets/dm-sans-latin-400-normal-CW0RaeGs.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-500-normal-B9HHJjqV.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-500-normal-Dr3UlScf.woff +0 -0
- package/cockpit/assets/dm-sans-latin-700-normal-CUSSCpQX.woff +0 -0
- package/cockpit/assets/dm-sans-latin-700-normal-DvUfVpUG.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-ext-400-normal-BjWJ59Pq.woff +0 -0
- package/cockpit/assets/dm-sans-latin-ext-400-normal-BtiwyxMk.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-ext-500-normal-BJfUCQsA.woff2 +0 -0
- package/cockpit/assets/dm-sans-latin-ext-500-normal-DR84L5F-.woff +0 -0
- package/cockpit/assets/dm-sans-latin-ext-700-normal-BLI3TTWz.woff +0 -0
- package/cockpit/assets/dm-sans-latin-ext-700-normal-CJIcxD6K.woff2 +0 -0
- package/cockpit/assets/index-DDswO4B1.css +1 -0
- package/cockpit/assets/index-bovtnZ98.js +18 -0
- package/cockpit/assets/jetbrains-mono-cyrillic-400-normal-BEIGL1Tu.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-cyrillic-400-normal-ugxPyKxw.woff +0 -0
- package/cockpit/assets/jetbrains-mono-greek-400-normal-B9oWc5Lo.woff +0 -0
- package/cockpit/assets/jetbrains-mono-greek-400-normal-C190GLew.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-latin-400-normal-6-qcROiO.woff +0 -0
- package/cockpit/assets/jetbrains-mono-latin-400-normal-V6pRDFza.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-latin-ext-400-normal-Bc8Ftmh3.woff2 +0 -0
- package/cockpit/assets/jetbrains-mono-latin-ext-400-normal-fXTG6kC5.woff +0 -0
- package/cockpit/assets/jetbrains-mono-vietnamese-400-normal-CqNFfHCs.woff +0 -0
- package/cockpit/assets/outfit-latin-400-normal-BGsTXAXT.woff2 +0 -0
- package/cockpit/assets/outfit-latin-400-normal-DMwTpYkH.woff +0 -0
- package/cockpit/assets/outfit-latin-600-normal-B7SfZ07L.woff2 +0 -0
- package/cockpit/assets/outfit-latin-600-normal-BEfTtDA7.woff +0 -0
- package/cockpit/assets/outfit-latin-ext-400-normal-5tcqmc2S.woff2 +0 -0
- package/cockpit/assets/outfit-latin-ext-400-normal-DHm7mdGe.woff +0 -0
- package/cockpit/assets/outfit-latin-ext-600-normal-B85nYjL1.woff2 +0 -0
- package/cockpit/assets/outfit-latin-ext-600-normal-CWJcPgd7.woff +0 -0
- package/cockpit/assets/unbounded-cyrillic-600-normal-B-s5c2Kn.woff +0 -0
- package/cockpit/assets/unbounded-cyrillic-600-normal-DW6uzIMB.woff2 +0 -0
- package/cockpit/assets/unbounded-latin-600-normal-BPdB_PEv.woff +0 -0
- package/cockpit/assets/unbounded-latin-600-normal-oRSANpZr.woff2 +0 -0
- package/cockpit/assets/unbounded-latin-ext-600-normal-0iZLtTDV.woff2 +0 -0
- package/cockpit/assets/unbounded-latin-ext-600-normal-ClMPf-bu.woff +0 -0
- package/cockpit/assets/unbounded-vietnamese-600-normal-BzfrgZ_C.woff +0 -0
- package/cockpit/assets/unbounded-vietnamese-600-normal-Cx2bTSHN.woff2 +0 -0
- package/cockpit/community.module-inventory.json +2389 -0
- package/cockpit/index.html +14 -0
- package/community-postgres.json +13 -0
- package/migrations/agentspace/0000_thin_carlie_cooper.sql +764 -0
- package/migrations/agentspace/meta/0000_snapshot.json +6885 -0
- package/migrations/agentspace/meta/_journal.json +13 -0
- package/migrations/chatv3/0000_dry_ego.sql +218 -0
- package/migrations/chatv3/0001_nosy_obadiah_stane.sql +35 -0
- package/migrations/chatv3/0002_narrow_darkhawk.sql +4 -0
- package/migrations/chatv3/0003_damp_zarek.sql +2 -0
- package/migrations/chatv3/0004_nervous_martin_li.sql +60 -0
- package/migrations/chatv3/0005_chatv3_server_encrypted_mode.sql +1 -0
- package/migrations/chatv3/meta/0000_snapshot.json +1887 -0
- package/migrations/chatv3/meta/0001_snapshot.json +2175 -0
- package/migrations/chatv3/meta/0002_snapshot.json +2229 -0
- package/migrations/chatv3/meta/0003_snapshot.json +2241 -0
- package/migrations/chatv3/meta/0004_snapshot.json +2746 -0
- package/migrations/chatv3/meta/_journal.json +48 -0
- package/migrations/docman/0000_curvy_valeria_richards.sql +257 -0
- package/migrations/docman/0001_massive_risque.sql +2 -0
- package/migrations/docman/0002_simple_logan.sql +50 -0
- package/migrations/docman/0003_quick_index.sql +45 -0
- package/migrations/docman/0004_known_summary.sql +9 -0
- package/migrations/docman/0005_vector_signal.sql +9 -0
- package/migrations/docman/0006_document_version_current_invariant.sql +15 -0
- package/migrations/docman/meta/_journal.json +55 -0
- package/migrations/projectman/0000_smooth_klaw.sql +257 -0
- package/migrations/projectman/0001_worthless_zodiak.sql +9 -0
- package/migrations/projectman/0002_board_rename.sql +108 -0
- package/migrations/projectman/0003_review_request.sql +62 -0
- package/migrations/projectman/0004_review_request_idempotency.sql +3 -0
- package/migrations/projectman/0005_allow_multi_sprint_per_task.sql +1 -0
- package/migrations/projectman/meta/_journal.json +48 -0
- package/migrations/sys/0000_loose_praxagora.sql +31 -0
- package/migrations/sys/0001_awesome_ronan.sql +2 -0
- package/migrations/sys/0002_steady_maximus.sql +2 -0
- package/migrations/sys/0003_escalating_rate_limiter.sql +2 -0
- package/migrations/sys/0004_rate_limiter_timestamptz.sql +22 -0
- package/migrations/sys/0005_sys_counters.sql +21 -0
- package/migrations/sys/meta/_journal.json +48 -0
- package/npm-shrinkwrap.json +4375 -0
- package/package.json +62 -0
- package/runtime/agentspace-host-adapter.mjs +64 -0
- package/runtime/agentspace-tooling.mjs +389 -0
- package/runtime/docman-host-adapter.mjs +177 -0
- package/runtime/docman-policy.mjs +450 -0
- package/runtime/docman-tooling.mjs +20 -0
- package/runtime/projectman-host-adapter.mjs +597 -0
- package/runtime/scope-context.mjs +99 -0
- package/scripts/community-host.mjs +626 -0
- package/scripts/community-migration-policy-v1.json +296 -0
|
@@ -0,0 +1,894 @@
|
|
|
1
|
+
import { g as getAgentGateway, n as normalizeDomain, a as normalizeToolId, r as resolveOperationKind } from './agent-gateway-runtime-DTZ4SxaC.js';
|
|
2
|
+
import { g as getHostConfig } from './registry-5amIZito.js';
|
|
3
|
+
import { g as getAuthProvider } from './request-base-url-BDdrsaga.js';
|
|
4
|
+
|
|
5
|
+
const COMMUNITY_CLIENT_COMPATIBILITY_SCHEMA_VERSION = 1;
|
|
6
|
+
const COMMUNITY_CLIENT_COMPATIBILITY_PROTOCOL = "aops-community-client-server";
|
|
7
|
+
const COMMUNITY_CLI_COMMAND_SCHEMA_MIN = 1;
|
|
8
|
+
const COMMUNITY_CLI_COMMAND_SCHEMA_MAX = 1;
|
|
9
|
+
const EXACT_SEMVER = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
|
|
10
|
+
function packageVersion(environment) {
|
|
11
|
+
const injected = "0.1.0";
|
|
12
|
+
for (const candidate of [environment.AOPS_SERVER_PACKAGE_VERSION, injected]) {
|
|
13
|
+
const value = candidate?.trim();
|
|
14
|
+
if (value && EXACT_SEMVER.test(value)) return value;
|
|
15
|
+
}
|
|
16
|
+
return "0.0.0";
|
|
17
|
+
}
|
|
18
|
+
function releaseVersion(environment) {
|
|
19
|
+
const value = environment.AOPS_RELEASE_VERSION?.trim() || environment.AOPS_SERVER_RELEASE_VERSION?.trim();
|
|
20
|
+
return value && EXACT_SEMVER.test(value) ? value : null;
|
|
21
|
+
}
|
|
22
|
+
function buildCommunityClientCompatibility(environment = process.env) {
|
|
23
|
+
const release = releaseVersion(environment);
|
|
24
|
+
return Object.freeze({
|
|
25
|
+
schemaVersion: COMMUNITY_CLIENT_COMPATIBILITY_SCHEMA_VERSION,
|
|
26
|
+
protocol: COMMUNITY_CLIENT_COMPATIBILITY_PROTOCOL,
|
|
27
|
+
server: Object.freeze({
|
|
28
|
+
name: "aops-server",
|
|
29
|
+
packageVersion: packageVersion(environment),
|
|
30
|
+
releaseVersion: release,
|
|
31
|
+
source: release ? "release" : "development"
|
|
32
|
+
}),
|
|
33
|
+
cliCommandSchema: Object.freeze({
|
|
34
|
+
min: COMMUNITY_CLI_COMMAND_SCHEMA_MIN,
|
|
35
|
+
max: COMMUNITY_CLI_COMMAND_SCHEMA_MAX
|
|
36
|
+
})
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
const LANDING_PAGE_PATH = "/api-info";
|
|
40
|
+
const DISCOVERY_JSON_ALIAS_PATH = "/api-info.json";
|
|
41
|
+
const DISCOVERY_JSON_PATH = "/api/agent/discovery.json";
|
|
42
|
+
const TOOLS_PATH = "/api/agent/tools";
|
|
43
|
+
const TOOL_DETAIL_PREFIX = "/api/agent/tools/";
|
|
44
|
+
const PUBLIC_OPENAPI_PATH = "/openapi.json";
|
|
45
|
+
const OPENAPI_PATH = "/api/agent/openapi.json";
|
|
46
|
+
const INVOKE_PATH_SUFFIX = "/invoke";
|
|
47
|
+
const READ_KINDS = /* @__PURE__ */ new Set([
|
|
48
|
+
"list",
|
|
49
|
+
"get",
|
|
50
|
+
"search",
|
|
51
|
+
"detail",
|
|
52
|
+
"preview",
|
|
53
|
+
"stats",
|
|
54
|
+
"history",
|
|
55
|
+
"diff",
|
|
56
|
+
"compare",
|
|
57
|
+
"check",
|
|
58
|
+
"read"
|
|
59
|
+
]);
|
|
60
|
+
const WRITE_KINDS = /* @__PURE__ */ new Set([
|
|
61
|
+
"create",
|
|
62
|
+
"update",
|
|
63
|
+
"delete",
|
|
64
|
+
"remove",
|
|
65
|
+
"add",
|
|
66
|
+
"set",
|
|
67
|
+
"link",
|
|
68
|
+
"unlink",
|
|
69
|
+
"publish",
|
|
70
|
+
"restore",
|
|
71
|
+
"reset",
|
|
72
|
+
"cleanup",
|
|
73
|
+
"record",
|
|
74
|
+
"copy"
|
|
75
|
+
]);
|
|
76
|
+
const WORKFLOW_KINDS = /* @__PURE__ */ new Set([
|
|
77
|
+
"compose",
|
|
78
|
+
"generate",
|
|
79
|
+
"plan",
|
|
80
|
+
"review",
|
|
81
|
+
"run",
|
|
82
|
+
"execute",
|
|
83
|
+
"start",
|
|
84
|
+
"end",
|
|
85
|
+
"sync",
|
|
86
|
+
"export",
|
|
87
|
+
"import",
|
|
88
|
+
"convert"
|
|
89
|
+
]);
|
|
90
|
+
const DISCOVERY_FIRST_CONTACT_KIND_ORDER = [
|
|
91
|
+
"list",
|
|
92
|
+
"search",
|
|
93
|
+
"get",
|
|
94
|
+
"detail",
|
|
95
|
+
"preview",
|
|
96
|
+
"stats",
|
|
97
|
+
"history",
|
|
98
|
+
"diff",
|
|
99
|
+
"compare",
|
|
100
|
+
"check"
|
|
101
|
+
];
|
|
102
|
+
const INVOKE_BODY_MODES = [
|
|
103
|
+
{
|
|
104
|
+
id: "raw-input",
|
|
105
|
+
summary: "Send the tool input object directly as the JSON request body."
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
id: "envelope",
|
|
109
|
+
summary: "Use `{ sourceId?, input, preview?, apply?, confirm?, idempotencyKey? }` for guarded writes, preflight, or source overrides."
|
|
110
|
+
}
|
|
111
|
+
];
|
|
112
|
+
const DISCOVERY_METADATA_CONTRACT = {
|
|
113
|
+
canonicalSource: "Domain Capability Manifest (DCM)",
|
|
114
|
+
domainSummary: {
|
|
115
|
+
preferred: "manifest.docs.domain.summary",
|
|
116
|
+
fallback: "manifest.domain.description"
|
|
117
|
+
},
|
|
118
|
+
humanReadableResources: {
|
|
119
|
+
preferred: [
|
|
120
|
+
"manifest.capabilities.resources[].title",
|
|
121
|
+
"manifest.docs.resources[resourceId].summary"
|
|
122
|
+
],
|
|
123
|
+
fallback: ["resource:* tag", "service:* tag", "operationId prefix"]
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
function buildContextHeaders(authProvider) {
|
|
127
|
+
return [
|
|
128
|
+
{
|
|
129
|
+
name: "authorization",
|
|
130
|
+
required: false,
|
|
131
|
+
summary: "Omit on loopback requests when trusted-local auth is active; the runtime supplies a trusted local principal."
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: "x-project-id",
|
|
135
|
+
required: false,
|
|
136
|
+
summary: "Resolve project context by project id."
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "x-project-name",
|
|
140
|
+
required: false,
|
|
141
|
+
summary: "Resolve project context by project name."
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: "x-tenant-id",
|
|
145
|
+
required: false,
|
|
146
|
+
summary: "Tenant context override."
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: "x-locale",
|
|
150
|
+
required: false,
|
|
151
|
+
summary: "Preferred locale for localized responses."
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: "x-fallback-locale",
|
|
155
|
+
required: false,
|
|
156
|
+
summary: "Fallback locale when the requested locale is unavailable."
|
|
157
|
+
}
|
|
158
|
+
];
|
|
159
|
+
}
|
|
160
|
+
function toUrl(serverBaseUrl, path) {
|
|
161
|
+
return serverBaseUrl ? `${serverBaseUrl}${path}` : path;
|
|
162
|
+
}
|
|
163
|
+
function isRecord(value) {
|
|
164
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
165
|
+
}
|
|
166
|
+
function toSafetyPolicy(tool) {
|
|
167
|
+
if (!isRecord(tool.policy)) return {};
|
|
168
|
+
return isRecord(tool.policy.safety) ? tool.policy.safety : {};
|
|
169
|
+
}
|
|
170
|
+
function withDomain(path, domain) {
|
|
171
|
+
const normalizedDomain = normalizeDomain(domain ?? "");
|
|
172
|
+
if (!normalizedDomain) return path;
|
|
173
|
+
const separator = path.includes("?") ? "&" : "?";
|
|
174
|
+
return `${path}${separator}domain=${encodeURIComponent(normalizedDomain)}`;
|
|
175
|
+
}
|
|
176
|
+
function compareDomains(left, right) {
|
|
177
|
+
if (left === right) return 0;
|
|
178
|
+
if (left === "projectman") return -1;
|
|
179
|
+
if (right === "projectman") return 1;
|
|
180
|
+
return left.localeCompare(right);
|
|
181
|
+
}
|
|
182
|
+
function buildUrls(serverBaseUrl, domain) {
|
|
183
|
+
return {
|
|
184
|
+
landingPage: toUrl(serverBaseUrl, withDomain(LANDING_PAGE_PATH, domain)),
|
|
185
|
+
document: toUrl(serverBaseUrl, withDomain(DISCOVERY_JSON_ALIAS_PATH, domain)),
|
|
186
|
+
rawDocument: toUrl(serverBaseUrl, withDomain(DISCOVERY_JSON_PATH, domain)),
|
|
187
|
+
tools: toUrl(serverBaseUrl, withDomain(TOOLS_PATH, domain)),
|
|
188
|
+
openapi: toUrl(serverBaseUrl, withDomain(PUBLIC_OPENAPI_PATH, domain)),
|
|
189
|
+
rawOpenapi: toUrl(serverBaseUrl, withDomain(OPENAPI_PATH, domain)),
|
|
190
|
+
toolDetailTemplate: toUrl(serverBaseUrl, `${TOOL_DETAIL_PREFIX}{toolId}`),
|
|
191
|
+
invokeTemplate: toUrl(serverBaseUrl, `${TOOL_DETAIL_PREFIX}{toolId}${INVOKE_PATH_SUFFIX}`)
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function toManifestProviderSummary(provider) {
|
|
195
|
+
const moduleValue = String(provider.module ?? "").trim();
|
|
196
|
+
return {
|
|
197
|
+
id: provider.id,
|
|
198
|
+
domain: normalizeDomain(provider.domain),
|
|
199
|
+
exportName: provider.exportName,
|
|
200
|
+
module: moduleValue,
|
|
201
|
+
moduleKind: moduleValue.startsWith(".") || moduleValue.startsWith("/") || moduleValue.startsWith("file://") ? "file" : "package"
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function parseExample(exampleRaw) {
|
|
205
|
+
if (!exampleRaw) return {};
|
|
206
|
+
try {
|
|
207
|
+
return JSON.parse(exampleRaw);
|
|
208
|
+
} catch {
|
|
209
|
+
return { raw: exampleRaw };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
function findTagValue(tags, prefix) {
|
|
213
|
+
if (!Array.isArray(tags)) return null;
|
|
214
|
+
const found = tags.find((tag) => typeof tag === "string" && tag.startsWith(prefix));
|
|
215
|
+
if (!found) return null;
|
|
216
|
+
const value = found.slice(prefix.length).trim();
|
|
217
|
+
return value.length > 0 ? value : null;
|
|
218
|
+
}
|
|
219
|
+
function normalizeLabel(value) {
|
|
220
|
+
return value.replace(/[-_.]+/g, " ").replace(/\s+/g, " ").trim();
|
|
221
|
+
}
|
|
222
|
+
function normalizeResourceId(value) {
|
|
223
|
+
return String(value ?? "").trim().toLowerCase();
|
|
224
|
+
}
|
|
225
|
+
function inferOperationKindFromOperationId(operationId) {
|
|
226
|
+
const segments = String(operationId ?? "").toLowerCase().split(".").filter(Boolean);
|
|
227
|
+
const candidate = segments[segments.length - 1] ?? "";
|
|
228
|
+
if (!candidate) return "custom";
|
|
229
|
+
if (READ_KINDS.has(candidate)) return candidate;
|
|
230
|
+
if (WRITE_KINDS.has(candidate)) return candidate;
|
|
231
|
+
if (WORKFLOW_KINDS.has(candidate)) return candidate;
|
|
232
|
+
if (candidate.includes("list")) return "list";
|
|
233
|
+
if (candidate.includes("search")) return "search";
|
|
234
|
+
if (candidate.includes("preview")) return "preview";
|
|
235
|
+
if (candidate.includes("detail")) return "detail";
|
|
236
|
+
if (candidate.includes("history")) return "history";
|
|
237
|
+
if (candidate.includes("diff")) return "diff";
|
|
238
|
+
if (candidate.includes("compare")) return "compare";
|
|
239
|
+
if (candidate.includes("stats")) return "stats";
|
|
240
|
+
if (candidate.includes("check")) return "check";
|
|
241
|
+
if (candidate.includes("get")) return "get";
|
|
242
|
+
if (candidate.includes("create")) return "create";
|
|
243
|
+
if (candidate.includes("update")) return "update";
|
|
244
|
+
if (candidate.includes("delete")) return "delete";
|
|
245
|
+
if (candidate.includes("remove")) return "remove";
|
|
246
|
+
if (candidate.includes("add")) return "add";
|
|
247
|
+
if (candidate.includes("set")) return "set";
|
|
248
|
+
if (candidate.includes("publish")) return "publish";
|
|
249
|
+
if (candidate.includes("restore")) return "restore";
|
|
250
|
+
if (candidate.includes("reset")) return "reset";
|
|
251
|
+
if (candidate.includes("cleanup")) return "cleanup";
|
|
252
|
+
if (candidate.includes("sync")) return "sync";
|
|
253
|
+
if (candidate.includes("generate")) return "generate";
|
|
254
|
+
if (candidate.includes("plan")) return "plan";
|
|
255
|
+
if (candidate.includes("review")) return "review";
|
|
256
|
+
if (candidate.includes("compose")) return "compose";
|
|
257
|
+
if (candidate.includes("convert")) return "convert";
|
|
258
|
+
return candidate;
|
|
259
|
+
}
|
|
260
|
+
function resolveFallbackResourceId(tool) {
|
|
261
|
+
return normalizeResourceId(
|
|
262
|
+
findTagValue(tool.tags, "resource:") ?? findTagValue(tool.tags, "service:") ?? String(tool.operationId ?? "").split(".")[0] ?? "resource"
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
function findExplicitResourceDescriptor(tool, domainMetadata) {
|
|
266
|
+
const resources = domainMetadata?.resources ?? [];
|
|
267
|
+
if (resources.length === 0) return null;
|
|
268
|
+
const resourcesById = new Map(
|
|
269
|
+
resources.map((resource) => [normalizeResourceId(resource.resourceId), resource])
|
|
270
|
+
);
|
|
271
|
+
const candidateIds = [
|
|
272
|
+
findTagValue(tool.tags, "resource:"),
|
|
273
|
+
String(tool.operationId ?? "").split(".")[0] ?? "",
|
|
274
|
+
resolveFallbackResourceId(tool)
|
|
275
|
+
].map((value) => normalizeResourceId(value ?? "")).filter(Boolean);
|
|
276
|
+
for (const candidateId of candidateIds) {
|
|
277
|
+
const descriptor = resourcesById.get(candidateId);
|
|
278
|
+
if (descriptor) return descriptor;
|
|
279
|
+
}
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
function resolveDiscoveryOperationKind(tool) {
|
|
283
|
+
return resolveOperationKind(tool) ?? inferOperationKindFromOperationId(tool.operationId);
|
|
284
|
+
}
|
|
285
|
+
function resolveCapabilityLane(tool, operationKind) {
|
|
286
|
+
const tags = tool.tags ?? [];
|
|
287
|
+
const normalizedTags = tags.map((tag) => tag.toLowerCase());
|
|
288
|
+
if (normalizedTags.includes("maintenance") || normalizedTags.includes("admin") || normalizedTags.includes("system") || operationKind === "cleanup" || operationKind === "reset") {
|
|
289
|
+
return "system-admin";
|
|
290
|
+
}
|
|
291
|
+
if (WORKFLOW_KINDS.has(operationKind)) {
|
|
292
|
+
return "workflow-automation";
|
|
293
|
+
}
|
|
294
|
+
if (tool.sideEffect !== "none" || WRITE_KINDS.has(operationKind)) {
|
|
295
|
+
return "mutating-write";
|
|
296
|
+
}
|
|
297
|
+
return "read-model";
|
|
298
|
+
}
|
|
299
|
+
function resolveSafetyClass(tool, operationKind) {
|
|
300
|
+
if (tool.policy?.safety?.destructive === true) {
|
|
301
|
+
return "destructive";
|
|
302
|
+
}
|
|
303
|
+
if (["delete", "remove", "cleanup", "restore", "reset"].includes(operationKind)) {
|
|
304
|
+
return "destructive";
|
|
305
|
+
}
|
|
306
|
+
if (tool.sideEffect !== "none" || WRITE_KINDS.has(operationKind) || WORKFLOW_KINDS.has(operationKind)) {
|
|
307
|
+
return "stateful-write";
|
|
308
|
+
}
|
|
309
|
+
return "safe-read";
|
|
310
|
+
}
|
|
311
|
+
function buildRecommendationReason(params) {
|
|
312
|
+
const resourceLabel = params.resourceLabel || "resource";
|
|
313
|
+
if (params.safety === "destructive") {
|
|
314
|
+
return `Avoid as a first step because it can change or remove ${resourceLabel}.`;
|
|
315
|
+
}
|
|
316
|
+
if (params.operationKind === "list") {
|
|
317
|
+
return `Safe first read. It enumerates ${resourceLabel} so the agent can see the domain surface before acting.`;
|
|
318
|
+
}
|
|
319
|
+
if (params.operationKind === "search") {
|
|
320
|
+
return `Safe first read. It helps the agent discover matching ${resourceLabel} records quickly.`;
|
|
321
|
+
}
|
|
322
|
+
if (params.operationKind === "get" || params.operationKind === "detail") {
|
|
323
|
+
return `Safe read-only inspection of a single ${resourceLabel} item.`;
|
|
324
|
+
}
|
|
325
|
+
if (params.operationKind === "preview" || params.operationKind === "stats") {
|
|
326
|
+
return `Read-only preview that helps the agent understand ${resourceLabel} without mutating state.`;
|
|
327
|
+
}
|
|
328
|
+
if (params.capability === "workflow-automation") {
|
|
329
|
+
return `Useful after initial discovery, but not ideal as the very first tool because it starts a workflow.`;
|
|
330
|
+
}
|
|
331
|
+
if (params.capability === "mutating-write") {
|
|
332
|
+
return `Useful once the agent has context, but it mutates ${resourceLabel}.`;
|
|
333
|
+
}
|
|
334
|
+
return `General-purpose ${params.capability.replace(/-/g, " ")} tool for ${resourceLabel}.`;
|
|
335
|
+
}
|
|
336
|
+
function buildDiscoveryMetadata(tool, domainMetadata) {
|
|
337
|
+
const operationKind = resolveDiscoveryOperationKind(tool);
|
|
338
|
+
const explicitResource = findExplicitResourceDescriptor(tool, domainMetadata);
|
|
339
|
+
const fallbackResourceId = resolveFallbackResourceId(tool);
|
|
340
|
+
const resourceId = normalizeResourceId(explicitResource?.resourceId ?? fallbackResourceId);
|
|
341
|
+
const resourceTitle = explicitResource?.title?.trim() || normalizeLabel(resourceId);
|
|
342
|
+
const resourceLabel = resourceTitle || normalizeLabel(resourceId);
|
|
343
|
+
const capability = resolveCapabilityLane(tool, operationKind);
|
|
344
|
+
const safety = resolveSafetyClass(tool, operationKind);
|
|
345
|
+
const recommendedForFirstContact = safety === "safe-read" && capability === "read-model" && DISCOVERY_FIRST_CONTACT_KIND_ORDER.includes(
|
|
346
|
+
operationKind
|
|
347
|
+
);
|
|
348
|
+
return {
|
|
349
|
+
operationKind,
|
|
350
|
+
resourceId,
|
|
351
|
+
resourceLabel,
|
|
352
|
+
resourceTitle,
|
|
353
|
+
resourceSummary: explicitResource?.summary,
|
|
354
|
+
resourceKind: explicitResource?.kind,
|
|
355
|
+
resourceNotes: explicitResource?.notes,
|
|
356
|
+
capability,
|
|
357
|
+
safety,
|
|
358
|
+
recommendedForFirstContact,
|
|
359
|
+
recommendationReason: buildRecommendationReason({
|
|
360
|
+
operationKind,
|
|
361
|
+
resourceLabel,
|
|
362
|
+
capability,
|
|
363
|
+
safety
|
|
364
|
+
})
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function buildInvokeExamples(tool, serverBaseUrl) {
|
|
368
|
+
const rawInput = parseExample(tool.examples?.[0]);
|
|
369
|
+
const invokePath = `${TOOL_DETAIL_PREFIX}${encodeURIComponent(tool.toolId)}${INVOKE_PATH_SUFFIX}`;
|
|
370
|
+
const invokeUrl = toUrl(serverBaseUrl, invokePath);
|
|
371
|
+
const sourceId = tool.defaultSourceId ?? tool.sources[0]?.id ?? "local";
|
|
372
|
+
const safety = toSafetyPolicy(tool);
|
|
373
|
+
const curlLines = [
|
|
374
|
+
`curl -X POST '${invokeUrl}'`,
|
|
375
|
+
...[],
|
|
376
|
+
` -H 'Content-Type: application/json'`,
|
|
377
|
+
` -d '${JSON.stringify(rawInput)}'`
|
|
378
|
+
];
|
|
379
|
+
return {
|
|
380
|
+
method: "POST",
|
|
381
|
+
url: invokeUrl,
|
|
382
|
+
rawInput,
|
|
383
|
+
envelope: {
|
|
384
|
+
sourceId,
|
|
385
|
+
input: rawInput,
|
|
386
|
+
...safety.applyRequired === true ? { apply: true, idempotencyKey: "<idempotency-key>" } : {},
|
|
387
|
+
...safety.confirmationRequired === true ? { confirm: true } : {}
|
|
388
|
+
},
|
|
389
|
+
curl: curlLines.join(" \\\n")
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
function buildToolDetail(tool, serverBaseUrl, operationDocs, domainMetadata, inputJsonSchema) {
|
|
393
|
+
const detailPath = `${TOOL_DETAIL_PREFIX}${encodeURIComponent(tool.toolId)}`;
|
|
394
|
+
const invokeExamples = buildInvokeExamples(tool, serverBaseUrl);
|
|
395
|
+
const discovery = buildDiscoveryMetadata(tool, domainMetadata);
|
|
396
|
+
return {
|
|
397
|
+
toolId: tool.toolId,
|
|
398
|
+
domain: tool.domain,
|
|
399
|
+
domainInfo: {
|
|
400
|
+
domain: normalizeDomain(tool.domain),
|
|
401
|
+
displayName: domainMetadata?.displayName ?? normalizeLabel(tool.domain),
|
|
402
|
+
summary: domainMetadata?.summary ?? domainMetadata?.description ?? null,
|
|
403
|
+
notes: domainMetadata?.notes ?? []
|
|
404
|
+
},
|
|
405
|
+
operationId: tool.operationId,
|
|
406
|
+
title: tool.title ?? tool.summary ?? tool.operationId,
|
|
407
|
+
summary: tool.summary ?? tool.title ?? "",
|
|
408
|
+
sideEffect: tool.sideEffect ?? "none",
|
|
409
|
+
tags: tool.tags ?? [],
|
|
410
|
+
inputSchemaRef: tool.inputSchemaRef ?? null,
|
|
411
|
+
inputJsonSchema: inputJsonSchema ?? null,
|
|
412
|
+
outputSchemaRef: tool.outputSchemaRef ?? null,
|
|
413
|
+
policy: tool.policy ?? null,
|
|
414
|
+
defaultSourceId: tool.defaultSourceId ?? null,
|
|
415
|
+
sources: tool.sources,
|
|
416
|
+
examples: (tool.examples ?? []).map((entry) => parseExample(entry)),
|
|
417
|
+
docs: operationDocs ?? null,
|
|
418
|
+
resource: {
|
|
419
|
+
resourceId: discovery.resourceId,
|
|
420
|
+
title: discovery.resourceTitle,
|
|
421
|
+
summary: discovery.resourceSummary ?? null,
|
|
422
|
+
kind: discovery.resourceKind ?? null,
|
|
423
|
+
notes: discovery.resourceNotes ?? []
|
|
424
|
+
},
|
|
425
|
+
discovery,
|
|
426
|
+
links: {
|
|
427
|
+
self: toUrl(serverBaseUrl, detailPath),
|
|
428
|
+
invoke: invokeExamples.url,
|
|
429
|
+
openapi: toUrl(
|
|
430
|
+
serverBaseUrl,
|
|
431
|
+
`${PUBLIC_OPENAPI_PATH}#${encodeURIComponent(`/api/agent/tools/${tool.toolId}/invoke`)}`
|
|
432
|
+
)
|
|
433
|
+
},
|
|
434
|
+
invoke: {
|
|
435
|
+
bodyModes: INVOKE_BODY_MODES,
|
|
436
|
+
url: invokeExamples.url,
|
|
437
|
+
rawInputExample: invokeExamples.rawInput,
|
|
438
|
+
envelopeTemplate: invokeExamples.envelope,
|
|
439
|
+
examples: invokeExamples
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function buildBuckets(values, formatter) {
|
|
444
|
+
const counts = /* @__PURE__ */ new Map();
|
|
445
|
+
for (const value of values) {
|
|
446
|
+
const normalized = value.trim();
|
|
447
|
+
if (!normalized) continue;
|
|
448
|
+
counts.set(normalized, (counts.get(normalized) ?? 0) + 1);
|
|
449
|
+
}
|
|
450
|
+
return Array.from(counts.entries()).map(([id, count]) => ({
|
|
451
|
+
id,
|
|
452
|
+
label: normalizeLabel(id),
|
|
453
|
+
count
|
|
454
|
+
})).sort((left, right) => right.count - left.count || left.label.localeCompare(right.label));
|
|
455
|
+
}
|
|
456
|
+
function buildTaxonomy(tools) {
|
|
457
|
+
return {
|
|
458
|
+
capabilities: buildBuckets(tools.map((tool) => tool.discovery.capability)),
|
|
459
|
+
operationKinds: buildBuckets(tools.map((tool) => tool.discovery.operationKind)),
|
|
460
|
+
resources: buildBuckets(tools.map((tool) => tool.discovery.resourceId))
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
function buildFallbackResourceSummary(resourceTitle, operationKinds, domainLabel) {
|
|
464
|
+
if (operationKinds.length === 0) {
|
|
465
|
+
return `${resourceTitle} entries exposed by the ${domainLabel} domain.`;
|
|
466
|
+
}
|
|
467
|
+
if (operationKinds.length === 1) {
|
|
468
|
+
return `Supports ${operationKinds[0]} operations for ${resourceTitle.toLowerCase()} in the ${domainLabel} domain.`;
|
|
469
|
+
}
|
|
470
|
+
const listedKinds = operationKinds.slice(0, 4).join(", ");
|
|
471
|
+
return `Supports ${listedKinds} operations for ${resourceTitle.toLowerCase()} in the ${domainLabel} domain.`;
|
|
472
|
+
}
|
|
473
|
+
function buildHumanReadableResources(domainTools, domainMetadata) {
|
|
474
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
475
|
+
for (const tool of domainTools) {
|
|
476
|
+
const resourceId = normalizeResourceId(tool.discovery.resourceId);
|
|
477
|
+
const existing = grouped.get(resourceId);
|
|
478
|
+
if (existing) {
|
|
479
|
+
existing.push(tool);
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
grouped.set(resourceId, [tool]);
|
|
483
|
+
}
|
|
484
|
+
const explicitResources = domainMetadata?.resources ?? [];
|
|
485
|
+
const explicitById = new Map(
|
|
486
|
+
explicitResources.map((resource) => [normalizeResourceId(resource.resourceId), resource])
|
|
487
|
+
);
|
|
488
|
+
const resourceIds = /* @__PURE__ */ new Set([
|
|
489
|
+
...grouped.keys(),
|
|
490
|
+
...explicitResources.map((resource) => normalizeResourceId(resource.resourceId))
|
|
491
|
+
]);
|
|
492
|
+
const domainLabel = domainMetadata?.displayName ?? normalizeLabel(domainTools[0]?.domain ?? "domain");
|
|
493
|
+
return [...resourceIds].map((resourceId) => {
|
|
494
|
+
const tools = grouped.get(resourceId) ?? [];
|
|
495
|
+
const explicit = explicitById.get(resourceId);
|
|
496
|
+
const operationKinds = [...new Set(tools.map((tool) => tool.discovery.operationKind))];
|
|
497
|
+
const title = explicit?.title?.trim() || tools[0]?.discovery.resourceTitle || normalizeLabel(resourceId);
|
|
498
|
+
return {
|
|
499
|
+
resourceId,
|
|
500
|
+
title,
|
|
501
|
+
summary: explicit?.summary ?? buildFallbackResourceSummary(title, operationKinds, domainLabel),
|
|
502
|
+
kind: explicit?.kind ?? tools[0]?.discovery.resourceKind,
|
|
503
|
+
notes: explicit?.notes,
|
|
504
|
+
toolCount: tools.length,
|
|
505
|
+
operationKinds,
|
|
506
|
+
sampleToolIds: tools.slice(0, 6).map((tool) => tool.toolId)
|
|
507
|
+
};
|
|
508
|
+
}).sort(
|
|
509
|
+
(left, right) => right.toolCount - left.toolCount || left.title.localeCompare(right.title) || left.resourceId.localeCompare(right.resourceId)
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
function scoreToolForDiscovery(tool) {
|
|
513
|
+
let score = 0;
|
|
514
|
+
if (tool.discovery.safety === "safe-read") score += 120;
|
|
515
|
+
if (tool.discovery.safety === "stateful-write") score -= 25;
|
|
516
|
+
if (tool.discovery.safety === "destructive") score -= 90;
|
|
517
|
+
if (tool.discovery.capability === "read-model") score += 30;
|
|
518
|
+
if (tool.discovery.capability === "workflow-automation") score += 5;
|
|
519
|
+
if (tool.discovery.capability === "mutating-write") score -= 10;
|
|
520
|
+
if (tool.discovery.capability === "system-admin") score -= 20;
|
|
521
|
+
const kindIndex = DISCOVERY_FIRST_CONTACT_KIND_ORDER.indexOf(
|
|
522
|
+
tool.discovery.operationKind
|
|
523
|
+
);
|
|
524
|
+
if (kindIndex >= 0) {
|
|
525
|
+
score += 40 - kindIndex * 3;
|
|
526
|
+
}
|
|
527
|
+
if (tool.examples.length > 0) score += 8;
|
|
528
|
+
if (tool.summary.length > 0) score += 4;
|
|
529
|
+
if (tool.sources.some((source) => source.kind === "local-route")) score += 2;
|
|
530
|
+
if (tool.domain === "projectman") score += 5;
|
|
531
|
+
return score;
|
|
532
|
+
}
|
|
533
|
+
function toRecommendation(tool) {
|
|
534
|
+
return {
|
|
535
|
+
toolId: tool.toolId,
|
|
536
|
+
domain: tool.domain,
|
|
537
|
+
title: tool.title,
|
|
538
|
+
summary: tool.summary,
|
|
539
|
+
reason: tool.discovery.recommendationReason,
|
|
540
|
+
operationKind: tool.discovery.operationKind,
|
|
541
|
+
capability: tool.discovery.capability,
|
|
542
|
+
safety: tool.discovery.safety,
|
|
543
|
+
resource: tool.discovery.resourceLabel,
|
|
544
|
+
links: {
|
|
545
|
+
detail: tool.links.self,
|
|
546
|
+
invoke: tool.links.invoke,
|
|
547
|
+
openapi: tool.links.openapi
|
|
548
|
+
},
|
|
549
|
+
example: tool.invoke.rawInputExample
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function buildRecommendedTools(tools, count) {
|
|
553
|
+
return [...tools].sort((left, right) => scoreToolForDiscovery(right) - scoreToolForDiscovery(left) || left.toolId.localeCompare(right.toolId)).slice(0, count).map((tool) => toRecommendation(tool));
|
|
554
|
+
}
|
|
555
|
+
function groupToolsByDomain(tools, serverBaseUrl, providersByDomain, domainMetadataByDomain) {
|
|
556
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
557
|
+
for (const tool of tools) {
|
|
558
|
+
const domain = normalizeDomain(tool.domain);
|
|
559
|
+
const existing = grouped.get(domain);
|
|
560
|
+
if (existing) {
|
|
561
|
+
existing.push(tool);
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
grouped.set(domain, [tool]);
|
|
565
|
+
}
|
|
566
|
+
return Array.from(grouped.entries()).sort(([left], [right]) => compareDomains(left, right)).map(([domain, domainTools]) => {
|
|
567
|
+
const domainMetadata = domainMetadataByDomain?.[domain];
|
|
568
|
+
return {
|
|
569
|
+
domain,
|
|
570
|
+
displayName: domainMetadata?.displayName ?? normalizeLabel(domain),
|
|
571
|
+
summary: domainMetadata?.summary ?? domainMetadata?.description ?? `${normalizeLabel(domain)} domain exposed through manifest-synced tools.`,
|
|
572
|
+
usageNotes: domainMetadata?.notes ?? [],
|
|
573
|
+
toolCount: domainTools.length,
|
|
574
|
+
provider: providersByDomain?.get(domain) ?? null,
|
|
575
|
+
manifestProvider: providersByDomain?.get(domain) ?? null,
|
|
576
|
+
links: {
|
|
577
|
+
tools: toUrl(serverBaseUrl, withDomain(TOOLS_PATH, domain)),
|
|
578
|
+
openapi: toUrl(serverBaseUrl, withDomain(PUBLIC_OPENAPI_PATH, domain)),
|
|
579
|
+
rawOpenapi: toUrl(serverBaseUrl, withDomain(OPENAPI_PATH, domain)),
|
|
580
|
+
discovery: toUrl(serverBaseUrl, withDomain(DISCOVERY_JSON_ALIAS_PATH, domain)),
|
|
581
|
+
rawDiscovery: toUrl(serverBaseUrl, withDomain(DISCOVERY_JSON_PATH, domain)),
|
|
582
|
+
landingPage: toUrl(serverBaseUrl, withDomain(LANDING_PAGE_PATH, domain))
|
|
583
|
+
},
|
|
584
|
+
previewToolIds: domainTools.slice(0, 6).map((tool) => tool.toolId),
|
|
585
|
+
sampleToolIds: domainTools.slice(0, 6).map((tool) => tool.toolId),
|
|
586
|
+
publicOpenApiUrl: toUrl(serverBaseUrl, withDomain(PUBLIC_OPENAPI_PATH, domain)),
|
|
587
|
+
recommendedFirstTools: buildRecommendedTools(domainTools, 3),
|
|
588
|
+
humanReadableResources: buildHumanReadableResources(domainTools, domainMetadata),
|
|
589
|
+
taxonomy: buildTaxonomy(domainTools),
|
|
590
|
+
tools: domainTools
|
|
591
|
+
};
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
function buildAgentDiscoveryDocument(input) {
|
|
595
|
+
const domain = normalizeDomain(input.domain ?? "") || void 0;
|
|
596
|
+
const authProvider = getAuthProvider();
|
|
597
|
+
const invokeAuthMode = "runtime-principal" ;
|
|
598
|
+
const contextHeaders = buildContextHeaders();
|
|
599
|
+
const urls = buildUrls(input.serverBaseUrl, domain);
|
|
600
|
+
const providerSummaries = (input.manifestProviders ?? []).filter((provider) => provider.enabled).map((provider) => toManifestProviderSummary(provider));
|
|
601
|
+
const providersByDomain = new Map(providerSummaries.map((provider) => [provider.domain, provider]));
|
|
602
|
+
const domainMetadataByDomain = input.listResult.domainMetadataByDomain ?? {};
|
|
603
|
+
const tools = input.listResult.tools.map(
|
|
604
|
+
(tool) => buildToolDetail(
|
|
605
|
+
tool,
|
|
606
|
+
input.serverBaseUrl,
|
|
607
|
+
input.listResult.operationDocsByOperationId?.[normalizeToolId(tool.operationId)],
|
|
608
|
+
domainMetadataByDomain[normalizeDomain(tool.domain)]
|
|
609
|
+
)
|
|
610
|
+
);
|
|
611
|
+
const domains = groupToolsByDomain(tools, input.serverBaseUrl, providersByDomain, domainMetadataByDomain);
|
|
612
|
+
const referenceDomain = domains.find((entry) => entry.domain === "projectman") ?? domains[0] ?? null;
|
|
613
|
+
const featuredTool = referenceDomain?.recommendedFirstTools[0] ?? null;
|
|
614
|
+
const sourceOfTruth = "Domain Capability Manifest (DCM) is canonical. Tool catalog, OpenAPI, public discovery JSON, and landing metadata are generated projections derived from per-domain manifest providers.";
|
|
615
|
+
const publicRoutes = [
|
|
616
|
+
{
|
|
617
|
+
method: "GET",
|
|
618
|
+
auth: "public",
|
|
619
|
+
purpose: "HTML landing page for first-contact AI discovery.",
|
|
620
|
+
url: urls.landingPage
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
method: "GET",
|
|
624
|
+
auth: "public",
|
|
625
|
+
purpose: "Machine-readable discovery JSON alias.",
|
|
626
|
+
url: urls.document
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
method: "GET",
|
|
630
|
+
auth: "public",
|
|
631
|
+
purpose: "Raw discovery JSON under /api/agent.",
|
|
632
|
+
url: urls.rawDocument
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
method: "GET",
|
|
636
|
+
auth: "public",
|
|
637
|
+
purpose: "Tool catalog list.",
|
|
638
|
+
url: urls.tools
|
|
639
|
+
},
|
|
640
|
+
{
|
|
641
|
+
method: "GET",
|
|
642
|
+
auth: "public",
|
|
643
|
+
purpose: "Public OpenAPI alias.",
|
|
644
|
+
url: urls.openapi
|
|
645
|
+
},
|
|
646
|
+
{
|
|
647
|
+
method: "GET",
|
|
648
|
+
auth: "public",
|
|
649
|
+
purpose: "Raw OpenAPI projection under /api/agent.",
|
|
650
|
+
url: urls.rawOpenapi
|
|
651
|
+
},
|
|
652
|
+
{
|
|
653
|
+
method: "GET",
|
|
654
|
+
auth: "public",
|
|
655
|
+
purpose: "Single tool detail document.",
|
|
656
|
+
url: urls.toolDetailTemplate
|
|
657
|
+
}
|
|
658
|
+
];
|
|
659
|
+
const protectedRoutes = [
|
|
660
|
+
{
|
|
661
|
+
method: "POST",
|
|
662
|
+
auth: "runtime-principal" ,
|
|
663
|
+
purpose: "Invoke a tool through the federated gateway.",
|
|
664
|
+
url: urls.invokeTemplate
|
|
665
|
+
}
|
|
666
|
+
];
|
|
667
|
+
const usageProtocol = {
|
|
668
|
+
principle: "Before using a tool, inspect help or detail first. Do not guess architecture from the landing page.",
|
|
669
|
+
helpFirstRule: "If a sibling help-like tool exists (`*.help`, `*.describe`, `*.usage`), inspect that first. Otherwise use tool detail and OpenAPI before invoke.",
|
|
670
|
+
helpToolPatterns: [".help", ".describe", ".usage"],
|
|
671
|
+
steps: [
|
|
672
|
+
{
|
|
673
|
+
order: 1,
|
|
674
|
+
id: "read-aops-summary",
|
|
675
|
+
title: "Read the AOPS summary",
|
|
676
|
+
action: `GET ${urls.document}`,
|
|
677
|
+
outcome: "Understand what this host is and what it is not."
|
|
678
|
+
},
|
|
679
|
+
{
|
|
680
|
+
order: 2,
|
|
681
|
+
id: "pick-tool",
|
|
682
|
+
title: "Pick a manifest-synced tool",
|
|
683
|
+
action: `GET ${urls.tools}`,
|
|
684
|
+
outcome: "Choose a domain and a toolId from the synced catalog."
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
order: 3,
|
|
688
|
+
id: "inspect-help-or-detail",
|
|
689
|
+
title: "Inspect help/detail before execution",
|
|
690
|
+
action: `GET ${urls.toolDetailTemplate}`,
|
|
691
|
+
outcome: "Look for help-like toolIds first; otherwise use tool detail and OpenAPI."
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
order: 4,
|
|
695
|
+
id: "inspect-openapi",
|
|
696
|
+
title: "Inspect schemas only if needed",
|
|
697
|
+
action: `GET ${urls.openapi}`,
|
|
698
|
+
outcome: "Use schema-level details when input/output is not obvious from the detail document."
|
|
699
|
+
},
|
|
700
|
+
{
|
|
701
|
+
order: 5,
|
|
702
|
+
id: "invoke",
|
|
703
|
+
title: "Invoke with trusted local principal" ,
|
|
704
|
+
action: `POST ${urls.invokeTemplate}`,
|
|
705
|
+
outcome: "Execute only after you understand the tool input and safety profile."
|
|
706
|
+
}
|
|
707
|
+
]
|
|
708
|
+
};
|
|
709
|
+
return {
|
|
710
|
+
ok: true,
|
|
711
|
+
discoveryVersion: "1.2",
|
|
712
|
+
clientCompatibility: buildCommunityClientCompatibility(),
|
|
713
|
+
domain,
|
|
714
|
+
catalogVersion: input.listResult.catalogVersion,
|
|
715
|
+
service: {
|
|
716
|
+
name: "aops-server",
|
|
717
|
+
audience: ["ai-agent", "tooling-client", "browser"],
|
|
718
|
+
summary: "AOPS, the Agentic Operations System, exposes a manifest-derived tooling gateway for AI agents. Tool catalog, OpenAPI, and discovery surfaces are generated projections, not the canonical source.",
|
|
719
|
+
discoveryPageUrl: urls.landingPage,
|
|
720
|
+
discoveryJsonUrl: urls.document,
|
|
721
|
+
rawDiscoveryJsonUrl: urls.rawDocument,
|
|
722
|
+
publicOpenApiUrl: urls.openapi,
|
|
723
|
+
rawOpenApiUrl: urls.rawOpenapi
|
|
724
|
+
},
|
|
725
|
+
system: {
|
|
726
|
+
kind: "manifest-synced-tooling-host",
|
|
727
|
+
firstContactStatement: "AOPS stands for Agentic Operations System. It is a manifest-synced host runtime that simultaneously acts as a domain API host, an agent execution gateway, and the AOPS application runtime itself.",
|
|
728
|
+
summary: "AOPS is a manifest-synced tooling host and agent gateway. It exists to help an AI discover, inspect, and invoke tools without treating the discovery surface as an internal topology document.",
|
|
729
|
+
scope: "This page is only the manifest-synced discovery surface for the AOPS agent gateway. It describes tool discovery metadata, tool-detail routes, OpenAPI links, and invoke entry points for manifest-backed tools; it does not describe internal service topology.",
|
|
730
|
+
purpose: [
|
|
731
|
+
"AOPS is a host runtime with three simultaneous roles: domain API host, agent execution gateway, and agentic operations application.",
|
|
732
|
+
"AOPS can host multiple local domain plugins in one runtime and can also route to remote domain sources.",
|
|
733
|
+
"Capability identity comes from kit operation contracts; host/API and agent projections are derived from the same manifest path."
|
|
734
|
+
],
|
|
735
|
+
notThis: [
|
|
736
|
+
"Do not treat this landing page as a microservice architecture description.",
|
|
737
|
+
"Do not infer event sourcing, event-driven topology, or internal service boundaries from this endpoint.",
|
|
738
|
+
"Do not execute a tool before inspecting its help/detail contract."
|
|
739
|
+
]
|
|
740
|
+
},
|
|
741
|
+
catalog: {
|
|
742
|
+
catalogVersion: input.listResult.catalogVersion,
|
|
743
|
+
generatedAt: input.listResult.generatedAt,
|
|
744
|
+
partial: input.listResult.errors.length > 0,
|
|
745
|
+
toolCount: tools.length,
|
|
746
|
+
domainCount: domains.length
|
|
747
|
+
},
|
|
748
|
+
provenance: {
|
|
749
|
+
canonicalSource: "Domain Capability Manifest (DCM)",
|
|
750
|
+
projectionRule: "Host routes, tool catalog, OpenAPI, and public AI discovery surfaces are projections derived from per-domain manifests.",
|
|
751
|
+
discoveryMetadataContract: DISCOVERY_METADATA_CONTRACT,
|
|
752
|
+
manifestProviders: providerSummaries,
|
|
753
|
+
referenceDomain
|
|
754
|
+
},
|
|
755
|
+
auth: {
|
|
756
|
+
discovery: "public-read",
|
|
757
|
+
authProvider,
|
|
758
|
+
invoke: invokeAuthMode,
|
|
759
|
+
summary: "GET discovery endpoints are public. This host uses trusted-local auth, so POST tool invocation uses a trusted local principal on loopback requests." ,
|
|
760
|
+
note: "Discovery endpoints are public. With trusted-local auth, invoke requests succeed only on loopback and use the runtime principal." ,
|
|
761
|
+
publicRoutes,
|
|
762
|
+
protectedRoutes
|
|
763
|
+
},
|
|
764
|
+
routes: {
|
|
765
|
+
landingPage: urls.landingPage,
|
|
766
|
+
discoveryDocument: urls.document,
|
|
767
|
+
rawDiscoveryDocument: urls.rawDocument,
|
|
768
|
+
toolCatalog: urls.tools,
|
|
769
|
+
openapi: urls.openapi,
|
|
770
|
+
rawOpenapi: urls.rawOpenapi,
|
|
771
|
+
toolDetailTemplate: urls.toolDetailTemplate,
|
|
772
|
+
invokeTemplate: urls.invokeTemplate,
|
|
773
|
+
domainApiTemplate: toUrl(input.serverBaseUrl, "/api/{domain}/...")
|
|
774
|
+
},
|
|
775
|
+
instructions: [
|
|
776
|
+
"Treat AOPS as a tooling discovery and invocation host, not as a topology or architecture document.",
|
|
777
|
+
"Start with /api-info.json, then use /api/agent/tools to enumerate manifest-synced toolIds.",
|
|
778
|
+
"Before invoke, inspect a help-like sibling tool when present (`*.help`, `*.describe`, `*.usage`); otherwise read the tool detail document first.",
|
|
779
|
+
"Open /openapi.json only when you need contract-level input/output schema details.",
|
|
780
|
+
"Invoke tools through /api/agent/tools/{toolId}/invoke after the tool purpose, safety, and input are clear. Trusted-local auth supplies a trusted local principal on loopback requests."
|
|
781
|
+
],
|
|
782
|
+
usageProtocol,
|
|
783
|
+
invoke: {
|
|
784
|
+
bodyModes: INVOKE_BODY_MODES,
|
|
785
|
+
contextHeaders
|
|
786
|
+
},
|
|
787
|
+
entry: {
|
|
788
|
+
primer: "AOPS stands for Agentic Operations System. This endpoint is its manifest-synced tooling discovery surface for AI agents: read discovery first, inspect help/detail before execution, and do not infer internal architecture from this endpoint.",
|
|
789
|
+
purpose: "This host exposes an AI-oriented tooling gateway. Start with discovery, inspect tool detail or help, consult OpenAPI only when needed, then invoke tools through the gateway.",
|
|
790
|
+
canonicalSource: "Domain Capability Manifest (DCM)",
|
|
791
|
+
discoveryDocument: urls.document,
|
|
792
|
+
rawDiscoveryDocument: urls.rawDocument,
|
|
793
|
+
toolCatalog: urls.tools,
|
|
794
|
+
openapi: urls.openapi,
|
|
795
|
+
rawOpenapi: urls.rawOpenapi,
|
|
796
|
+
invokeTemplate: urls.invokeTemplate,
|
|
797
|
+
domainApiTemplate: toUrl(input.serverBaseUrl, "/api/{domain}/..."),
|
|
798
|
+
bodyModes: INVOKE_BODY_MODES.map((mode) => mode.id),
|
|
799
|
+
recommendedFlow: [
|
|
800
|
+
`GET ${urls.document}`,
|
|
801
|
+
`GET ${urls.tools}`,
|
|
802
|
+
featuredTool ? `GET ${featuredTool.links.detail}` : null,
|
|
803
|
+
`GET ${urls.openapi}`,
|
|
804
|
+
`POST ${urls.invokeTemplate} (trusted-local runtime principal)`
|
|
805
|
+
].filter((step) => Boolean(step))
|
|
806
|
+
},
|
|
807
|
+
manifestSource: {
|
|
808
|
+
sourceOfTruth,
|
|
809
|
+
discoveryMetadataContract: DISCOVERY_METADATA_CONTRACT,
|
|
810
|
+
manifestProviders: providerSummaries
|
|
811
|
+
},
|
|
812
|
+
openApi: {
|
|
813
|
+
url: urls.openapi,
|
|
814
|
+
rawUrl: urls.rawOpenapi,
|
|
815
|
+
pathCount: tools.length + 2
|
|
816
|
+
},
|
|
817
|
+
taxonomy: buildTaxonomy(tools),
|
|
818
|
+
recommendations: {
|
|
819
|
+
firstContactTools: buildRecommendedTools(tools, 6),
|
|
820
|
+
byDomain: domains.map((entry) => ({
|
|
821
|
+
domain: entry.domain,
|
|
822
|
+
tools: entry.recommendedFirstTools
|
|
823
|
+
}))
|
|
824
|
+
},
|
|
825
|
+
featured: featuredTool ? {
|
|
826
|
+
domain: referenceDomain?.domain ?? featuredTool.domain,
|
|
827
|
+
reason: referenceDomain?.domain === "projectman" ? "Projectman is exposed as a manifest-backed domain and works well as a concrete reference for multi-tool AI discovery." : "First available manifest-backed domain in the current catalog.",
|
|
828
|
+
tool: featuredTool
|
|
829
|
+
} : null,
|
|
830
|
+
tools,
|
|
831
|
+
domains,
|
|
832
|
+
errors: input.listResult.errors
|
|
833
|
+
};
|
|
834
|
+
}
|
|
835
|
+
async function getAgentDiscoveryDocument(params) {
|
|
836
|
+
const gateway = getAgentGateway();
|
|
837
|
+
const domain = normalizeDomain(params.domain ?? "") || void 0;
|
|
838
|
+
const listResult = await gateway.listTools(domain);
|
|
839
|
+
const hostConfig = getHostConfig();
|
|
840
|
+
return buildAgentDiscoveryDocument({
|
|
841
|
+
listResult,
|
|
842
|
+
serverBaseUrl: params.serverBaseUrl,
|
|
843
|
+
domain,
|
|
844
|
+
manifestProviders: hostConfig.agentGateway?.catalog?.manifestProviders
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
async function getAgentToolDetailDocument(params) {
|
|
848
|
+
const gateway = getAgentGateway();
|
|
849
|
+
const toolId = normalizeToolId(params.toolId);
|
|
850
|
+
const listResult = await gateway.listTools();
|
|
851
|
+
const tool = listResult.tools.find((entry) => normalizeToolId(entry.toolId) === toolId);
|
|
852
|
+
if (!tool) {
|
|
853
|
+
return null;
|
|
854
|
+
}
|
|
855
|
+
const hostConfig = getHostConfig();
|
|
856
|
+
const provider = hostConfig.agentGateway?.catalog?.manifestProviders?.filter((entry) => entry.enabled).map((entry) => toManifestProviderSummary(entry)).find((entry) => entry.domain === normalizeDomain(tool.domain));
|
|
857
|
+
const inputJsonSchema = await gateway.getToolInputJsonSchema(tool.toolId);
|
|
858
|
+
return {
|
|
859
|
+
ok: true,
|
|
860
|
+
catalogVersion: listResult.catalogVersion,
|
|
861
|
+
generatedAt: listResult.generatedAt,
|
|
862
|
+
auth: {
|
|
863
|
+
read: "public-read",
|
|
864
|
+
authProvider: getAuthProvider(),
|
|
865
|
+
invoke: "runtime-principal"
|
|
866
|
+
},
|
|
867
|
+
provenance: {
|
|
868
|
+
canonicalSource: "Domain Capability Manifest (DCM)",
|
|
869
|
+
discoveryMetadataContract: DISCOVERY_METADATA_CONTRACT,
|
|
870
|
+
provider
|
|
871
|
+
},
|
|
872
|
+
tool: buildToolDetail(
|
|
873
|
+
tool,
|
|
874
|
+
params.serverBaseUrl,
|
|
875
|
+
listResult.operationDocsByOperationId?.[normalizeToolId(tool.operationId)],
|
|
876
|
+
listResult.domainMetadataByDomain?.[normalizeDomain(tool.domain)],
|
|
877
|
+
inputJsonSchema
|
|
878
|
+
),
|
|
879
|
+
links: {
|
|
880
|
+
discovery: toUrl(params.serverBaseUrl, DISCOVERY_JSON_ALIAS_PATH),
|
|
881
|
+
rawDiscovery: toUrl(params.serverBaseUrl, DISCOVERY_JSON_PATH),
|
|
882
|
+
openapi: toUrl(params.serverBaseUrl, PUBLIC_OPENAPI_PATH),
|
|
883
|
+
rawOpenapi: toUrl(params.serverBaseUrl, OPENAPI_PATH),
|
|
884
|
+
catalog: toUrl(params.serverBaseUrl, TOOLS_PATH),
|
|
885
|
+
filteredCatalog: toUrl(
|
|
886
|
+
params.serverBaseUrl,
|
|
887
|
+
withDomain(TOOLS_PATH, normalizeDomain(tool.domain))
|
|
888
|
+
)
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
export { getAgentToolDetailDocument as a, buildAgentDiscoveryDocument as b, getAgentDiscoveryDocument as g };
|
|
894
|
+
//# sourceMappingURL=discovery-D9JnSgfu.js.map
|