@caplets/core 0.16.0 → 0.18.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.
@@ -1,16 +1,15 @@
1
- export type NativeCapletsMode = "auto" | "local" | "remote";
1
+ import { type CapletsMode, type CapletsServerEnv, type CapletsServerInput } from "../server/options";
2
+ export type NativeCapletsMode = CapletsMode;
2
3
  export type NativeRemoteCapletsOptions = {
3
- url?: string;
4
- user?: string;
5
- password?: string;
6
4
  pollIntervalMs?: number;
7
5
  fetch?: typeof fetch;
8
6
  };
9
7
  export type NativeCapletsServiceResolutionInput = {
10
8
  mode?: NativeCapletsMode;
9
+ server?: CapletsServerInput;
11
10
  remote?: NativeRemoteCapletsOptions;
12
11
  };
13
- export type NativeCapletsEnv = Partial<Record<"CAPLETS_NATIVE_MODE" | "CAPLETS_REMOTE_URL" | "CAPLETS_REMOTE_USER" | "CAPLETS_REMOTE_PASSWORD", string>>;
12
+ export type NativeCapletsEnv = CapletsServerEnv;
14
13
  export type NativeRemoteAuthOptions = {
15
14
  enabled: false;
16
15
  user: string;
@@ -4,6 +4,7 @@ export type RemoteCapletsTool = {
4
4
  name: string;
5
5
  title?: string | undefined;
6
6
  description?: string | undefined;
7
+ inputSchema?: unknown;
7
8
  };
8
9
  export type RemoteCapletsClient = {
9
10
  listTools(): Promise<RemoteCapletsTool[]>;
@@ -1,6 +1,7 @@
1
1
  import type { NativeCapletsServiceResolutionInput } from "./options";
2
2
  import { resolveNativeCapletsServiceOptions } from "./options";
3
3
  import { type RemoteCapletsClient } from "./remote";
4
+ import { generatedToolInputJsonSchemaForCaplet } from "../generated-tool-input-schema";
4
5
  export type NativeCapletsServiceOptions = NativeCapletsServiceResolutionInput & {
5
6
  configPath?: string;
6
7
  projectConfigPath?: string;
@@ -18,6 +19,8 @@ export type NativeCapletTool = {
18
19
  title: string;
19
20
  description: string;
20
21
  promptGuidance: string[];
22
+ inputSchema?: ReturnType<typeof generatedToolInputJsonSchemaForCaplet> | Record<string, unknown>;
23
+ operationNames?: string[];
21
24
  };
22
25
  export type NativeCapletsToolsChangedListener = (tools: NativeCapletTool[]) => void;
23
26
  export type NativeCapletsService = {
package/dist/native.js CHANGED
@@ -1,76 +1,33 @@
1
- import { K as ToolListChangedNotificationSchema, Tt as CapletsError, a as capabilityDescription, d as StreamableHTTPClientTransport, m as Client, n as generatedToolInputSchema, t as CapletsEngine } from "./engine-Brwid_mq.js";
2
- import { generatedToolInputJsonSchema } from "./generated-tool-input-schema.js";
3
- import { Buffer } from "node:buffer";
1
+ import { Ot as CapletsError, Q as ToolListChangedNotificationSchema, _ as StreamableHTTPClientTransport, a as resolveCapletsServer, b as Client, i as resolveCapletsMode, l as capabilityDescription, n as mcpUrlForBase, o as CapletsEngine } from "./options-DM1cMRcp.js";
2
+ import { a as generatedToolInputJsonSchemaForCaplet, i as generatedToolInputJsonSchema, l as operations, o as generatedToolInputSchema } from "./generated-tool-input-schema-B6rce396.js";
4
3
  //#region src/native/options.ts
5
- const DEFAULT_REMOTE_USER = "caplets";
6
4
  const DEFAULT_POLL_INTERVAL_MS = 3e4;
7
5
  function resolveNativeCapletsServiceOptions(input = {}, env = process.env) {
8
- const mode = parseMode(input.mode ?? env.CAPLETS_NATIVE_MODE ?? "auto");
9
- if (mode === "local") return { mode: "local" };
10
- const rawUrl = nonEmpty(input.remote?.url, "remote.url") ?? nonEmpty(env.CAPLETS_REMOTE_URL, "CAPLETS_REMOTE_URL");
11
- if (mode === "remote" && rawUrl === void 0) throw new CapletsError("REQUEST_INVALID", "CAPLETS_NATIVE_MODE=remote requires CAPLETS_REMOTE_URL or remote.url.");
12
- if (rawUrl === void 0) return { mode: "local" };
13
- const url = parseRemoteUrl(rawUrl);
14
- const userWasExplicit = input.remote?.user !== void 0 || hasEnv(env.CAPLETS_REMOTE_USER);
15
- const user = nonEmpty(input.remote?.user, "remote.user") ?? nonEmpty(env.CAPLETS_REMOTE_USER, "CAPLETS_REMOTE_USER") ?? DEFAULT_REMOTE_USER;
16
- const password = nonEmpty(input.remote?.password, "remote.password") ?? nonEmpty(env.CAPLETS_REMOTE_PASSWORD, "CAPLETS_REMOTE_PASSWORD");
17
- if (userWasExplicit && password === void 0) throw new CapletsError("REQUEST_INVALID", "Remote Caplets Basic Auth requires a password; set CAPLETS_REMOTE_PASSWORD or remote.password.");
18
- const auth = password === void 0 ? {
19
- enabled: false,
20
- user
21
- } : {
22
- enabled: true,
23
- user,
24
- password
25
- };
26
- const requestInit = auth.enabled ? { headers: { Authorization: basicAuthHeader(auth.user, auth.password) } } : {};
6
+ if (resolveCapletsMode({
7
+ ...input.mode ? { mode: input.mode } : {},
8
+ ...input.server?.url ? { serverUrl: input.server.url } : {}
9
+ }, env).mode === "local") return { mode: "local" };
10
+ const serverFetch = input.remote?.fetch ?? input.server?.fetch;
11
+ const server = resolveCapletsServer({
12
+ ...input.server,
13
+ ...serverFetch ? { fetch: serverFetch } : {}
14
+ }, env);
27
15
  return {
28
16
  mode: "remote",
29
17
  remote: {
30
- url,
31
- auth,
18
+ url: mcpUrlForBase(server.baseUrl),
19
+ auth: server.auth,
32
20
  pollIntervalMs: parsePollInterval(input.remote?.pollIntervalMs),
33
- requestInit,
34
- ...input.remote?.fetch ? { fetch: input.remote.fetch } : {}
21
+ requestInit: server.requestInit,
22
+ ...server.fetch ? { fetch: server.fetch } : {}
35
23
  }
36
24
  };
37
25
  }
38
- function parseMode(value) {
39
- if (value === "auto" || value === "local" || value === "remote") return value;
40
- throw new CapletsError("REQUEST_INVALID", `Expected CAPLETS_NATIVE_MODE to be auto, local, or remote, got ${value}`);
41
- }
42
- function parseRemoteUrl(value) {
43
- let url;
44
- try {
45
- url = new URL(value);
46
- } catch {
47
- throw new CapletsError("REQUEST_INVALID", "Invalid remote Caplets URL.");
48
- }
49
- if (url.username !== "" || url.password !== "") throw new CapletsError("REQUEST_INVALID", "Remote Caplets URL must not include username or password; use CAPLETS_REMOTE_USER/CAPLETS_REMOTE_PASSWORD or remote.user/remote.password instead.");
50
- if (url.protocol === "https:") return url;
51
- if (url.protocol === "http:" && isLoopbackHost(url.hostname)) return url;
52
- throw new CapletsError("REQUEST_INVALID", "Remote Caplets URL must use https except loopback development URLs.");
53
- }
54
- function isLoopbackHost(host) {
55
- return host === "localhost" || host === "127.0.0.1" || host === "[::1]" || host === "::1";
56
- }
57
26
  function parsePollInterval(value) {
58
27
  if (value === void 0) return DEFAULT_POLL_INTERVAL_MS;
59
28
  if (!Number.isInteger(value) || value < 1e3) throw new CapletsError("REQUEST_INVALID", "remote.pollIntervalMs must be an integer >= 1000.");
60
29
  return value;
61
30
  }
62
- function basicAuthHeader(user, password) {
63
- return `Basic ${Buffer.from(`${user}:${password}`).toString("base64")}`;
64
- }
65
- function nonEmpty(value, label) {
66
- if (value === void 0) return;
67
- const trimmed = value.trim();
68
- if (!trimmed) throw new CapletsError("REQUEST_INVALID", `${label} must not be empty`);
69
- return trimmed;
70
- }
71
- function hasEnv(value) {
72
- return value !== void 0 && value.trim() !== "";
73
- }
74
31
  //#endregion
75
32
  //#region src/native/tools.ts
76
33
  function nativeCapletToolName(capletId) {
@@ -85,12 +42,12 @@ function nativeCapletsSystemGuidance(toolNames) {
85
42
  "Available Caplets native tools:",
86
43
  toolNames.length > 0 ? toolNames.map((tool) => `- ${tool}`).join("\n") : "- none",
87
44
  "",
88
- "Flow: get_caplet when the domain is unfamiliar; search_tools or list_tools to find exact downstream names; get_tool only when schemas are unclear; call_tool with downstream inputs inside arguments.",
45
+ "Flow: get_caplet when the domain is unfamiliar; use search_tools/list_tools for actions; MCP-backed Caplets may also expose resources, prompts, and completions in their tool schema.",
89
46
  "Use fields on call_tool when a non-GraphQL downstream outputSchema allows selecting only needed structured paths."
90
47
  ].join("\n");
91
48
  }
92
49
  function nativeCapletPromptGuidance(toolName, caplet) {
93
- return [`Use ${toolName} for the ${caplet.name} Caplet capability domain.`];
50
+ return caplet.backend === "mcp" ? [`Use ${toolName} for the ${caplet.name} Caplet capability domain.`, "Prefer resources for readable context, prompts for reusable workflows, and tools for actions."] : [`Use ${toolName} for the ${caplet.name} Caplet capability domain.`];
94
51
  }
95
52
  function nativeCapletToolDescription(toolName, caplet) {
96
53
  return [
@@ -123,7 +80,8 @@ function createSdkRemoteCapletsClient(options) {
123
80
  return ((await client.listTools()).tools ?? []).map((tool) => ({
124
81
  name: tool.name,
125
82
  ...tool.title ? { title: tool.title } : {},
126
- ...tool.description ? { description: tool.description } : {}
83
+ ...tool.description ? { description: tool.description } : {},
84
+ ...tool.inputSchema ? { inputSchema: tool.inputSchema } : {}
127
85
  }));
128
86
  },
129
87
  async callTool(name, args) {
@@ -264,6 +222,7 @@ var RemoteNativeCapletsService = class {
264
222
  };
265
223
  function remoteToolToNativeTool(tool) {
266
224
  const toolName = nativeCapletToolName(tool.name);
225
+ const inputSchema = isPlainObject(tool.inputSchema) ? tool.inputSchema : generatedToolInputJsonSchemaForCaplet({ backend: "tool" });
267
226
  return {
268
227
  caplet: tool.name,
269
228
  toolName,
@@ -274,14 +233,26 @@ function remoteToolToNativeTool(tool) {
274
233
  `Native tool name: ${toolName}`,
275
234
  `Remote Caplet ID: ${tool.name}`
276
235
  ].join("\n"),
277
- promptGuidance: [`Use ${toolName} through the remote Caplets service.`]
236
+ promptGuidance: [`Use ${toolName} through the remote Caplets service.`],
237
+ inputSchema,
238
+ operationNames: operationNamesFromSchema(inputSchema)
278
239
  };
279
240
  }
241
+ function operationNamesFromSchema(schema) {
242
+ const properties = schema.properties;
243
+ if (!isPlainObject(properties)) return [...operations];
244
+ const operation = properties.operation;
245
+ if (!isPlainObject(operation) || !Array.isArray(operation.enum)) return [...operations];
246
+ return operation.enum.filter((value) => typeof value === "string");
247
+ }
248
+ function isPlainObject(value) {
249
+ return value !== null && typeof value === "object" && !Array.isArray(value);
250
+ }
280
251
  function errorMessage(error) {
281
252
  return error instanceof Error ? error.message : String(error);
282
253
  }
283
254
  function remoteAuthError() {
284
- return new CapletsError("AUTH_FAILED", "Remote Caplets authentication failed; check CAPLETS_REMOTE_USER and CAPLETS_REMOTE_PASSWORD.");
255
+ return new CapletsError("AUTH_FAILED", "Remote Caplets authentication failed; check CAPLETS_SERVER_USER and CAPLETS_SERVER_PASSWORD.");
285
256
  }
286
257
  function isSessionFailure(error) {
287
258
  const message = errorMessage(error).toLowerCase();
@@ -315,12 +286,15 @@ var DefaultNativeCapletsService = class {
315
286
  listTools() {
316
287
  return this.engine.enabledServers().map((caplet) => {
317
288
  const toolName = nativeCapletToolName(caplet.server);
289
+ const inputSchema = generatedToolInputJsonSchemaForCaplet(caplet);
318
290
  return {
319
291
  caplet: caplet.server,
320
292
  toolName,
321
293
  title: caplet.name,
322
294
  description: nativeCapletToolDescription(toolName, caplet),
323
- promptGuidance: nativeCapletPromptGuidance(toolName, caplet)
295
+ promptGuidance: nativeCapletPromptGuidance(toolName, caplet),
296
+ inputSchema,
297
+ operationNames: [...inputSchema.properties.operation.enum]
324
298
  };
325
299
  });
326
300
  }