@cerebro-labs/agentnava-sdk 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +12 -0
  3. package/README.md +230 -0
  4. package/agent.d.ts +285 -0
  5. package/agent.js +394 -0
  6. package/agent.js.map +1 -0
  7. package/attach.d.ts +49 -0
  8. package/attach.js +115 -0
  9. package/attach.js.map +1 -0
  10. package/connection-status.d.ts +28 -0
  11. package/connection-status.js +61 -0
  12. package/connection-status.js.map +1 -0
  13. package/connection.d.ts +89 -0
  14. package/connection.js +143 -0
  15. package/connection.js.map +1 -0
  16. package/conversation.d.ts +177 -0
  17. package/conversation.js +348 -0
  18. package/conversation.js.map +1 -0
  19. package/end-user.d.ts +159 -0
  20. package/end-user.js +209 -0
  21. package/end-user.js.map +1 -0
  22. package/errors.d.ts +43 -0
  23. package/errors.js +55 -0
  24. package/errors.js.map +1 -0
  25. package/http.d.ts +32 -0
  26. package/http.js +192 -0
  27. package/http.js.map +1 -0
  28. package/import-tools.d.ts +282 -0
  29. package/import-tools.js +686 -0
  30. package/import-tools.js.map +1 -0
  31. package/index.d.ts +16 -0
  32. package/index.js +38 -0
  33. package/index.js.map +1 -0
  34. package/knowledge-base.d.ts +165 -0
  35. package/knowledge-base.js +274 -0
  36. package/knowledge-base.js.map +1 -0
  37. package/load-agent-dir.d.ts +17 -0
  38. package/load-agent-dir.js +192 -0
  39. package/load-agent-dir.js.map +1 -0
  40. package/package.json +32 -0
  41. package/project.d.ts +94 -0
  42. package/project.js +155 -0
  43. package/project.js.map +1 -0
  44. package/secret.d.ts +45 -0
  45. package/secret.js +69 -0
  46. package/secret.js.map +1 -0
  47. package/templates-inline.d.ts +2 -0
  48. package/templates-inline.js +16 -0
  49. package/templates-inline.js.map +1 -0
  50. package/templates.d.ts +16 -0
  51. package/templates.js +32 -0
  52. package/templates.js.map +1 -0
  53. package/turn.d.ts +11 -0
  54. package/turn.js +244 -0
  55. package/turn.js.map +1 -0
  56. package/types.d.ts +485 -0
  57. package/types.js +4 -0
  58. package/types.js.map +1 -0
  59. package/version.d.ts +1 -0
  60. package/version.js +5 -0
  61. package/version.js.map +1 -0
  62. package/workflows.d.ts +36 -0
  63. package/workflows.js +101 -0
  64. package/workflows.js.map +1 -0
  65. package/workspace.d.ts +290 -0
  66. package/workspace.js +390 -0
  67. package/workspace.js.map +1 -0
package/http.js ADDED
@@ -0,0 +1,192 @@
1
+ // The transport. Everything else in this SDK is objects and method names.
2
+ import { AgentNavaError, networkError } from "./errors.js";
3
+ import { SDK_VERSION } from "./version.js";
4
+ /** Tells the server which SDK is calling, on every request.
5
+ *
6
+ * WHY A CUSTOM HEADER AND NOT `User-Agent`. `User-Agent` is on the fetch
7
+ * spec's forbidden-header list, so a browser DROPS it SILENTLY: the request
8
+ * still goes, the header just is not there, and the server sees a client of
9
+ * unknown age with nothing to indicate anything went wrong. A header we name
10
+ * ourselves is sent by every runtime the same way. `X-AgentNava-User-Id`
11
+ * already exists on this API, so the shape is not new.
12
+ *
13
+ * WHAT IT IS FOR. Not gating: the server does not refuse an old client on
14
+ * sight. It is so the question "who would break if we removed this field"
15
+ * has an answer that is a query rather than a guess. Once the package is on
16
+ * a public registry, a customer can pin 0.25.0 and still be calling in three
17
+ * years, and we have no other way to know they exist.
18
+ *
19
+ * The runtime note is best-effort and deliberately coarse. It separates Node
20
+ * from Bun from a browser, which is the distinction that explains most
21
+ * support questions, and carries nothing identifying. */
22
+ const CLIENT_HEADER = 'X-AgentNava-Client';
23
+ function runtimeTag() {
24
+ const g = globalThis;
25
+ if (g.Bun?.version)
26
+ return `bun/${g.Bun.version}`;
27
+ if (g.process?.versions?.node)
28
+ return `node/${g.process.versions.node}`;
29
+ if (g.document !== undefined)
30
+ return 'browser';
31
+ return 'unknown';
32
+ }
33
+ /** `agentnava-sdk/0.25.0 (node/22.20.0)`. Computed once: it cannot change
34
+ * within a process, and rebuilding it per request buys nothing. */
35
+ const CLIENT_ID = `agentnava-sdk/${SDK_VERSION} (${runtimeTag()})`;
36
+ const DEFAULT_BASE_URL = 'https://api.agentnava.com';
37
+ const DEFAULT_TIMEOUT_MS = 60_000;
38
+ /** Read a variable without assuming which runtime we are on.
39
+ *
40
+ * This SDK runs in Node, Bun, Deno, Workers and a browser bundle. `process` is
41
+ * absent in several of those and touching it throws rather than returning
42
+ * undefined, so the access is guarded rather than defaulted. */
43
+ function readEnv(name) {
44
+ try {
45
+ const proc = globalThis.process;
46
+ return proc?.env?.[name];
47
+ }
48
+ catch {
49
+ return undefined;
50
+ }
51
+ }
52
+ export class Http {
53
+ #apiKey;
54
+ #baseURL;
55
+ #timeout;
56
+ #doFetch;
57
+ constructor(options = {}) {
58
+ const key = options.apiKey ?? readEnv('AGENTNAVA_API_KEY');
59
+ // Thrown at construction, not at the first call. A missing key is a
60
+ // configuration mistake, and finding it three layers into an async call
61
+ // stack makes it look like the call was at fault.
62
+ if (!key) {
63
+ throw new AgentNavaError({
64
+ message: 'No API key. Pass `AgentNava.getWorkspace({ apiKey })` or set AGENTNAVA_API_KEY in the environment.',
65
+ code: 'no_api_key',
66
+ status: 401,
67
+ });
68
+ }
69
+ this.#apiKey = key;
70
+ this.#baseURL = (options.baseURL ?? readEnv('AGENTNAVA_BASE_URL') ?? DEFAULT_BASE_URL).replace(/\/+$/, '');
71
+ this.#timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;
72
+ this.#doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);
73
+ }
74
+ url(path, query) {
75
+ const url = new URL(this.#baseURL + path);
76
+ for (const [k, v] of Object.entries(query ?? {})) {
77
+ if (v !== undefined)
78
+ url.searchParams.set(k, String(v));
79
+ }
80
+ return url.toString();
81
+ }
82
+ /** Make the request and hand back the raw Response, errors already thrown. */
83
+ async send(path, options = {}) {
84
+ const headers = {
85
+ Authorization: `Bearer ${this.#apiKey}`,
86
+ [CLIENT_HEADER]: CLIENT_ID,
87
+ };
88
+ let body;
89
+ if (options.bytes !== undefined) {
90
+ body = options.bytes;
91
+ headers['Content-Type'] = options.contentType ?? 'application/octet-stream';
92
+ }
93
+ else if (options.body !== undefined) {
94
+ body = JSON.stringify(options.body);
95
+ headers['Content-Type'] = 'application/json';
96
+ }
97
+ // The caller's signal and our timeout both have to be able to abort, and
98
+ // AbortSignal.any is too new to rely on across every runtime this ships to.
99
+ const controller = new AbortController();
100
+ const timer = setTimeout(() => controller.abort(), this.#timeout);
101
+ const onAbort = () => controller.abort();
102
+ options.signal?.addEventListener('abort', onAbort, { once: true });
103
+ let res;
104
+ try {
105
+ res = await this.#doFetch(this.url(path, options.query), {
106
+ method: options.method ?? 'GET',
107
+ headers,
108
+ ...(body !== undefined && { body }),
109
+ signal: controller.signal,
110
+ });
111
+ }
112
+ catch (err) {
113
+ if (options.signal?.aborted)
114
+ throw err;
115
+ throw networkError(controller.signal.aborted
116
+ ? `Request to ${path} timed out after ${this.#timeout}ms`
117
+ : `Request to ${path} failed: ${err instanceof Error ? err.message : String(err)}`, err);
118
+ }
119
+ finally {
120
+ clearTimeout(timer);
121
+ options.signal?.removeEventListener('abort', onAbort);
122
+ }
123
+ if (!res.ok)
124
+ throw await toError(res, path);
125
+ return res;
126
+ }
127
+ async request(path, options = {}) {
128
+ const res = await this.send(path, options);
129
+ // 204, and any other empty body, is a successful nothing rather than a
130
+ // JSON parse error.
131
+ if (res.status === 204)
132
+ return undefined;
133
+ const text = await res.text();
134
+ if (text.length === 0)
135
+ return undefined;
136
+ try {
137
+ return JSON.parse(text);
138
+ }
139
+ catch {
140
+ throw new AgentNavaError({
141
+ message: `Expected JSON from ${path}, got: ${text.slice(0, 200)}`,
142
+ code: 'bad_response',
143
+ status: res.status,
144
+ });
145
+ }
146
+ }
147
+ get(path, query) {
148
+ return this.request(path, { method: 'GET', ...(query && { query }) });
149
+ }
150
+ post(path, body, query) {
151
+ return this.request(path, { method: 'POST', body, ...(query && { query }) });
152
+ }
153
+ patch(path, body) {
154
+ return this.request(path, { method: 'PATCH', body });
155
+ }
156
+ delete(path, query) {
157
+ return this.request(path, { method: 'DELETE', ...(query && { query }) });
158
+ }
159
+ }
160
+ /** Turn a failed Response into the one error type this SDK throws. */
161
+ async function toError(res, path) {
162
+ let message = `${res.status} from ${path}`;
163
+ let code = `http_${res.status}`;
164
+ try {
165
+ const text = await res.text();
166
+ if (text) {
167
+ try {
168
+ const parsed = JSON.parse(text);
169
+ message = parsed.message ?? parsed.error ?? text.slice(0, 300);
170
+ if (parsed.code)
171
+ code = parsed.code;
172
+ }
173
+ catch {
174
+ message = text.slice(0, 300);
175
+ }
176
+ }
177
+ }
178
+ catch {
179
+ // A body we cannot read is not worth failing over; the status still is.
180
+ }
181
+ const retryAfterHeader = res.headers.get('retry-after');
182
+ const retryAfter = retryAfterHeader ? Number(retryAfterHeader) : undefined;
183
+ const requestId = res.headers.get('x-request-id') ?? undefined;
184
+ return new AgentNavaError({
185
+ message,
186
+ code,
187
+ status: res.status,
188
+ ...(retryAfter !== undefined && Number.isFinite(retryAfter) && { retryAfter }),
189
+ ...(requestId !== undefined && { requestId }),
190
+ });
191
+ }
192
+ //# sourceMappingURL=http.js.map
package/http.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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","sourcesContent":["// The transport. Everything else in this SDK is objects and method names.\n\nimport { AgentNavaError, networkError } from './errors.ts';\nimport { SDK_VERSION } from './version.ts';\n\nexport interface ClientOptions {\n\t/** Defaults to `AGENTNAVA_API_KEY` from the environment. */\n\tapiKey?: string;\n\t/** Defaults to `https://api.agentnava.com`. */\n\tbaseURL?: string;\n\t/** Per-request timeout in milliseconds. Default 60_000. */\n\ttimeout?: number;\n\t/** Swap the fetch implementation, for tests or a proxy. */\n\tfetch?: typeof globalThis.fetch;\n}\n\n/** Tells the server which SDK is calling, on every request.\n *\n * WHY A CUSTOM HEADER AND NOT `User-Agent`. `User-Agent` is on the fetch\n * spec's forbidden-header list, so a browser DROPS it SILENTLY: the request\n * still goes, the header just is not there, and the server sees a client of\n * unknown age with nothing to indicate anything went wrong. A header we name\n * ourselves is sent by every runtime the same way. `X-AgentNava-User-Id`\n * already exists on this API, so the shape is not new.\n *\n * WHAT IT IS FOR. Not gating: the server does not refuse an old client on\n * sight. It is so the question \"who would break if we removed this field\"\n * has an answer that is a query rather than a guess. Once the package is on\n * a public registry, a customer can pin 0.25.0 and still be calling in three\n * years, and we have no other way to know they exist.\n *\n * The runtime note is best-effort and deliberately coarse. It separates Node\n * from Bun from a browser, which is the distinction that explains most\n * support questions, and carries nothing identifying. */\nconst CLIENT_HEADER = 'X-AgentNava-Client';\n\nfunction runtimeTag(): string {\n\tconst g = globalThis as {\n\t\tBun?: { version?: string };\n\t\tprocess?: { versions?: { node?: string } };\n\t\tdocument?: unknown;\n\t};\n\tif (g.Bun?.version) return `bun/${g.Bun.version}`;\n\tif (g.process?.versions?.node) return `node/${g.process.versions.node}`;\n\tif (g.document !== undefined) return 'browser';\n\treturn 'unknown';\n}\n\n/** `agentnava-sdk/0.25.0 (node/22.20.0)`. Computed once: it cannot change\n * within a process, and rebuilding it per request buys nothing. */\nconst CLIENT_ID = `agentnava-sdk/${SDK_VERSION} (${runtimeTag()})`;\n\nconst DEFAULT_BASE_URL = 'https://api.agentnava.com';\nconst DEFAULT_TIMEOUT_MS = 60_000;\n\n/** Read a variable without assuming which runtime we are on.\n *\n * This SDK runs in Node, Bun, Deno, Workers and a browser bundle. `process` is\n * absent in several of those and touching it throws rather than returning\n * undefined, so the access is guarded rather than defaulted. */\nfunction readEnv(name: string): string | undefined {\n\ttry {\n\t\tconst proc = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process;\n\t\treturn proc?.env?.[name];\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nexport interface RequestOptions {\n\tmethod?: 'GET' | 'POST' | 'PATCH' | 'PUT' | 'DELETE';\n\t/** Sent as a JSON body. Mutually exclusive with `bytes`. */\n\tbody?: unknown;\n\t/** Sent as the raw body, for file writes. Mutually exclusive with `body`. */\n\tbytes?: ArrayBuffer | Uint8Array;\n\tcontentType?: string;\n\tquery?: Record<string, string | number | boolean | undefined>;\n\t/* THERE IS DELIBERATELY NO `raw` FLAG.\n\t *\n\t * One was declared here, described as \"return the Response untouched\", and\n\t * read by nothing. `request` parses JSON unconditionally, so every caller\n\t * that asked for `raw: true` got a parsed body and then called `.text()` or\n\t * `.arrayBuffer()` on it. `kb.files.text()` and `kb.files.get()` were broken\n\t * for every developer from the day they shipped, and the flag is why: it made\n\t * the call site look correct.\n\t *\n\t * Use `send()` for a Response and `request<T>()` for parsed JSON. Two methods\n\t * that differ by return type cannot be confused the way one method with a\n\t * boolean can. */\n\tsignal?: AbortSignal;\n}\n\nexport class Http {\n\treadonly #apiKey: string;\n\treadonly #baseURL: string;\n\treadonly #timeout: number;\n\treadonly #doFetch: typeof globalThis.fetch;\n\n\tconstructor(options: ClientOptions = {}) {\n\t\tconst key = options.apiKey ?? readEnv('AGENTNAVA_API_KEY');\n\t\t// Thrown at construction, not at the first call. A missing key is a\n\t\t// configuration mistake, and finding it three layers into an async call\n\t\t// stack makes it look like the call was at fault.\n\t\tif (!key) {\n\t\t\tthrow new AgentNavaError({\n\t\t\t\tmessage:\n\t\t\t\t\t'No API key. Pass `AgentNava.getWorkspace({ apiKey })` or set AGENTNAVA_API_KEY in the environment.',\n\t\t\t\tcode: 'no_api_key',\n\t\t\t\tstatus: 401,\n\t\t\t});\n\t\t}\n\t\tthis.#apiKey = key;\n\t\tthis.#baseURL = (options.baseURL ?? readEnv('AGENTNAVA_BASE_URL') ?? DEFAULT_BASE_URL).replace(\n\t\t\t/\\/+$/,\n\t\t\t'',\n\t\t);\n\t\tthis.#timeout = options.timeout ?? DEFAULT_TIMEOUT_MS;\n\t\tthis.#doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n\t}\n\n\tprivate url(path: string, query?: RequestOptions['query']): string {\n\t\tconst url = new URL(this.#baseURL + path);\n\t\tfor (const [k, v] of Object.entries(query ?? {})) {\n\t\t\tif (v !== undefined) url.searchParams.set(k, String(v));\n\t\t}\n\t\treturn url.toString();\n\t}\n\n\t/** Make the request and hand back the raw Response, errors already thrown. */\n\tasync send(path: string, options: RequestOptions = {}): Promise<Response> {\n\t\tconst headers: Record<string, string> = {\n\t\t\tAuthorization: `Bearer ${this.#apiKey}`,\n\t\t\t[CLIENT_HEADER]: CLIENT_ID,\n\t\t};\n\t\tlet body: BodyInit | undefined;\n\t\tif (options.bytes !== undefined) {\n\t\t\tbody = options.bytes as BodyInit;\n\t\t\theaders['Content-Type'] = options.contentType ?? 'application/octet-stream';\n\t\t} else if (options.body !== undefined) {\n\t\t\tbody = JSON.stringify(options.body);\n\t\t\theaders['Content-Type'] = 'application/json';\n\t\t}\n\n\t\t// The caller's signal and our timeout both have to be able to abort, and\n\t\t// AbortSignal.any is too new to rely on across every runtime this ships to.\n\t\tconst controller = new AbortController();\n\t\tconst timer = setTimeout(() => controller.abort(), this.#timeout);\n\t\tconst onAbort = () => controller.abort();\n\t\toptions.signal?.addEventListener('abort', onAbort, { once: true });\n\n\t\tlet res: Response;\n\t\ttry {\n\t\t\tres = await this.#doFetch(this.url(path, options.query), {\n\t\t\t\tmethod: options.method ?? 'GET',\n\t\t\t\theaders,\n\t\t\t\t...(body !== undefined && { body }),\n\t\t\t\tsignal: controller.signal,\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tif (options.signal?.aborted) throw err;\n\t\t\tthrow networkError(\n\t\t\t\tcontroller.signal.aborted\n\t\t\t\t\t? `Request to ${path} timed out after ${this.#timeout}ms`\n\t\t\t\t\t: `Request to ${path} failed: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t\terr,\n\t\t\t);\n\t\t} finally {\n\t\t\tclearTimeout(timer);\n\t\t\toptions.signal?.removeEventListener('abort', onAbort);\n\t\t}\n\n\t\tif (!res.ok) throw await toError(res, path);\n\t\treturn res;\n\t}\n\n\tasync request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n\t\tconst res = await this.send(path, options);\n\t\t// 204, and any other empty body, is a successful nothing rather than a\n\t\t// JSON parse error.\n\t\tif (res.status === 204) return undefined as T;\n\t\tconst text = await res.text();\n\t\tif (text.length === 0) return undefined as T;\n\t\ttry {\n\t\t\treturn JSON.parse(text) as T;\n\t\t} catch {\n\t\t\tthrow new AgentNavaError({\n\t\t\t\tmessage: `Expected JSON from ${path}, got: ${text.slice(0, 200)}`,\n\t\t\t\tcode: 'bad_response',\n\t\t\t\tstatus: res.status,\n\t\t\t});\n\t\t}\n\t}\n\n\tget<T>(path: string, query?: RequestOptions['query']): Promise<T> {\n\t\treturn this.request<T>(path, { method: 'GET', ...(query && { query }) });\n\t}\n\tpost<T>(path: string, body?: unknown, query?: RequestOptions['query']): Promise<T> {\n\t\treturn this.request<T>(path, { method: 'POST', body, ...(query && { query }) });\n\t}\n\tpatch<T>(path: string, body?: unknown): Promise<T> {\n\t\treturn this.request<T>(path, { method: 'PATCH', body });\n\t}\n\tdelete<T>(path: string, query?: RequestOptions['query']): Promise<T> {\n\t\treturn this.request<T>(path, { method: 'DELETE', ...(query && { query }) });\n\t}\n}\n\n/** Turn a failed Response into the one error type this SDK throws. */\nasync function toError(res: Response, path: string): Promise<AgentNavaError> {\n\tlet message = `${res.status} from ${path}`;\n\tlet code = `http_${res.status}`;\n\ttry {\n\t\tconst text = await res.text();\n\t\tif (text) {\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(text) as { message?: string; code?: string; error?: string };\n\t\t\t\tmessage = parsed.message ?? parsed.error ?? text.slice(0, 300);\n\t\t\t\tif (parsed.code) code = parsed.code;\n\t\t\t} catch {\n\t\t\t\tmessage = text.slice(0, 300);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// A body we cannot read is not worth failing over; the status still is.\n\t}\n\n\tconst retryAfterHeader = res.headers.get('retry-after');\n\tconst retryAfter = retryAfterHeader ? Number(retryAfterHeader) : undefined;\n\tconst requestId = res.headers.get('x-request-id') ?? undefined;\n\n\treturn new AgentNavaError({\n\t\tmessage,\n\t\tcode,\n\t\tstatus: res.status,\n\t\t...(retryAfter !== undefined && Number.isFinite(retryAfter) && { retryAfter }),\n\t\t...(requestId !== undefined && { requestId }),\n\t});\n}\n"]}
@@ -0,0 +1,282 @@
1
+ import type { HttpTool } from './types.ts';
2
+ /** Something a human has to look at before these tools are good. */
3
+ export type ImportWarningKind =
4
+ /** The source had no description worth showing a model. */
5
+ 'description-missing'
6
+ /** A credential was found and replaced with a secret placeholder. */
7
+ | 'credential-stripped'
8
+ /** The request body is a shape we cannot express (file upload, form-data). */
9
+ | 'unsupported-body'
10
+ /** More tools than a model chooses well between. */
11
+ | 'too-many-tools'
12
+ /** A `{{variable}}` the source never defined. */
13
+ | 'undefined-variable'
14
+ /** Two endpoints produced the same tool name. */
15
+ | 'name-collision'
16
+ /** A parameter was renamed to something the API will accept. */
17
+ | 'param-renamed';
18
+ export interface ImportWarning {
19
+ kind: ImportWarningKind;
20
+ /** The tool it concerns, when it concerns one. */
21
+ tool?: string;
22
+ message: string;
23
+ }
24
+ export interface ImportedSecret {
25
+ /** Create this with `ws.secrets.create({ name, value })`. */
26
+ name: string;
27
+ /** The tools that reference it. */
28
+ usedBy: string[];
29
+ /** Where in the source it came from, so you can find the real value. */
30
+ from: string;
31
+ }
32
+ export interface ImportedTools {
33
+ /** Drafts. Read them before you ship them. */
34
+ tools: HttpTool[];
35
+ /** Secrets these tools need. None of them carries a value: see the note on
36
+ * credentials in this module's header. */
37
+ secrets: ImportedSecret[];
38
+ /** Everything a human should decide. Never silently resolved. */
39
+ warnings: ImportWarning[];
40
+ }
41
+ export interface ImportOptions {
42
+ /** Name for the credential these requests authenticate with. Defaults are
43
+ * derived from the header (`Authorization` becomes `API_TOKEN`), which is
44
+ * fine for one API and confusing once you have three. */
45
+ secretName?: string;
46
+ /** Keep only the operations you want. Returning everything is rarely right:
47
+ * a model picks markedly worse between forty tools than between eight. */
48
+ include?: (candidate: {
49
+ name: string;
50
+ method: string;
51
+ url: string;
52
+ }) => boolean;
53
+ /** Above this many tools, a `too-many-tools` warning is added. */
54
+ warnAbove?: number;
55
+ }
56
+ /** A tool name the API will accept: `^[a-z][a-z0-9_]{0,63}$`. */
57
+ export declare function toolNameFrom(raw: string, fallback?: string): string;
58
+ /** A param name the API will accept: `^[A-Za-z][A-Za-z0-9_]*$`.
59
+ *
60
+ * THE WIRE NAME IS NOT THE PARAM NAME, and conflating them is what broke this.
61
+ * An API's query key is whatever the API says it is (`page-size`,
62
+ * `filter[status]`), while a param name is an identifier both our validator and
63
+ * the runtime's placeholder regex constrain to `[A-Za-z][A-Za-z0-9_]*`. Copying
64
+ * the wire name into the param name produced `400 params has invalid key
65
+ * "page-size"` on documents that are completely ordinary, which is exactly the
66
+ * unactionable 400 `uniqueName` exists to avoid. So the key on the wire keeps
67
+ * its spelling and only the identifier is normalised. */
68
+ export declare function paramNameFrom(raw: string, fallback?: string): string;
69
+ interface PostmanItem {
70
+ name?: string;
71
+ request?: PostmanRequest | string;
72
+ item?: PostmanItem[];
73
+ description?: string;
74
+ }
75
+ interface PostmanRequest {
76
+ method?: string;
77
+ url?: string | {
78
+ raw?: string;
79
+ host?: string[];
80
+ path?: string[];
81
+ query?: {
82
+ key?: string;
83
+ value?: string;
84
+ description?: string;
85
+ disabled?: boolean;
86
+ }[];
87
+ };
88
+ header?: {
89
+ key?: string;
90
+ value?: string;
91
+ disabled?: boolean;
92
+ }[];
93
+ body?: {
94
+ mode?: string;
95
+ raw?: string;
96
+ };
97
+ description?: string;
98
+ auth?: {
99
+ type?: string;
100
+ [k: string]: unknown;
101
+ };
102
+ }
103
+ export interface PostmanCollection {
104
+ info?: {
105
+ name?: string;
106
+ description?: string;
107
+ };
108
+ item?: PostmanItem[];
109
+ variable?: {
110
+ key?: string;
111
+ value?: string;
112
+ }[];
113
+ auth?: {
114
+ type?: string;
115
+ [k: string]: unknown;
116
+ };
117
+ }
118
+ /**
119
+ * Draft tools from a Postman collection export (v2.0 or v2.1).
120
+ *
121
+ * WHY POSTMAN AND NOT ONLY OPENAPI. OpenAPI is tidier; a collection is truer. It
122
+ * holds the requests somebody has actually run, with the header names that
123
+ * really work and real values in the body, which is what a tool has to
124
+ * reproduce. Teams also already have one, and the best format to ask for is the
125
+ * one nobody has to make.
126
+ *
127
+ * WHAT IT COSTS: a collection has no parameter TYPES, so every parameter comes
128
+ * back a string. That is usually right and always safe; `fromOpenApi` gives real
129
+ * types where a document exists.
130
+ *
131
+ * VARIABLES. Postman writes `{{baseUrl}}`, which is the same shape as our own
132
+ * placeholders, so they map across almost directly. A variable the collection
133
+ * DEFINES is substituted, unless it holds something that looks like a
134
+ * credential, in which case it becomes a secret instead of being inlined. An
135
+ * undefined variable becomes a secret too, with a warning, because the
136
+ * alternative is a URL with a placeholder nothing resolves.
137
+ */
138
+ export declare function fromPostman(collection: PostmanCollection, options?: ImportOptions): ImportedTools;
139
+ interface OpenApiParam {
140
+ name?: string;
141
+ in?: string;
142
+ required?: boolean;
143
+ description?: string;
144
+ schema?: {
145
+ type?: string;
146
+ enum?: (string | number)[];
147
+ };
148
+ }
149
+ interface OpenApiOperation {
150
+ operationId?: string;
151
+ summary?: string;
152
+ description?: string;
153
+ parameters?: OpenApiParam[];
154
+ requestBody?: {
155
+ content?: Record<string, unknown>;
156
+ };
157
+ security?: unknown[];
158
+ }
159
+ export interface OpenApiDocument {
160
+ openapi?: string;
161
+ swagger?: string;
162
+ info?: {
163
+ title?: string;
164
+ };
165
+ servers?: {
166
+ url?: string;
167
+ }[];
168
+ host?: string;
169
+ basePath?: string;
170
+ schemes?: string[];
171
+ paths?: Record<string, Record<string, OpenApiOperation>>;
172
+ components?: {
173
+ securitySchemes?: Record<string, {
174
+ type?: string;
175
+ scheme?: string;
176
+ name?: string;
177
+ in?: string;
178
+ }>;
179
+ };
180
+ securityDefinitions?: Record<string, {
181
+ type?: string;
182
+ name?: string;
183
+ in?: string;
184
+ }>;
185
+ security?: unknown[];
186
+ }
187
+ /**
188
+ * Draft tools from an OpenAPI 3 or Swagger 2 document.
189
+ *
190
+ * WHAT THIS GIVES THAT POSTMAN DOES NOT: real parameter types and required
191
+ * flags, which is exactly the shape `HttpToolParam` wants, and an enum where the
192
+ * document declares one. FastAPI publishes this at `/openapi.json` without
193
+ * anybody writing it, so for a FastAPI shop this is usually the richer source.
194
+ *
195
+ * WHAT IT STILL DOES NOT GIVE: a description a model can choose on. `summary`
196
+ * is written for a developer reading a reference. Read the warnings.
197
+ */
198
+ export declare function fromOpenApi(doc: OpenApiDocument, options?: ImportOptions): ImportedTools;
199
+ /**
200
+ * Fetch an OpenAPI document and draft tools from it.
201
+ *
202
+ * THE FETCH GOES TO YOUR SERVER, NOT OURS. Pass `headers` if the document itself
203
+ * is behind auth. Nothing about the document is sent to AgentNava: the drafts
204
+ * are built in this process and you decide what to do with them.
205
+ */
206
+ export declare function fromOpenApiUrl(url: string, options?: ImportOptions & {
207
+ headers?: Record<string, string>;
208
+ fetch?: typeof fetch;
209
+ }): Promise<ImportedTools>;
210
+ /**
211
+ * Draft one tool from a curl command.
212
+ *
213
+ * THE LOWEST BAR ON PURPOSE. A team with no collection and no document still has
214
+ * a curl command that works, usually pasted in a chat thread, and that is enough
215
+ * to start. Handles the flags people actually use: `-X`, `-H`, `-d`/`--data`,
216
+ * `--data-raw`, `--url`, and a bare URL.
217
+ *
218
+ * Give it a `name` and a `description`: a curl command carries neither, and the
219
+ * description is the field that decides whether the agent picks this tool.
220
+ */
221
+ export declare function fromCurl(command: string, options?: ImportOptions & {
222
+ name?: string;
223
+ description?: string;
224
+ }): ImportedTools;
225
+ /** Where a draft comes from. Exactly one key. */
226
+ export type ImportSource =
227
+ /** An OpenAPI 3 or Swagger 2 document you already have in memory. */
228
+ {
229
+ openapi: OpenApiDocument;
230
+ }
231
+ /** A URL serving one. FastAPI publishes `/openapi.json` for free. The fetch
232
+ * goes to YOUR server; nothing is sent to AgentNava. */
233
+ | {
234
+ openapiUrl: string;
235
+ headers?: Record<string, string>;
236
+ fetch?: typeof fetch;
237
+ }
238
+ /** A Postman collection export, v2.0 or v2.1. */
239
+ | {
240
+ postman: PostmanCollection;
241
+ }
242
+ /** One working curl command. */
243
+ | {
244
+ curl: string;
245
+ name?: string;
246
+ description?: string;
247
+ };
248
+ /**
249
+ * Draft tools from whatever a company already has.
250
+ *
251
+ * NO SOURCE IS THE PRIMARY ONE, and that is deliberate. Which artifact a team
252
+ * can hand you is an accident of what they already keep, not a statement about
253
+ * how good their API is:
254
+ *
255
+ * OpenAPI the actual standard, and what every API gateway publishes
256
+ * (Apigee, MuleSoft, Kong, Azure APIM). Gives real parameter
257
+ * TYPES, required flags and enums. Often auto-generated, which
258
+ * means the descriptions are frequently empty.
259
+ * Postman the most widely used API client there is, and for many teams the
260
+ * only artifact anybody maintains. No parameter types, but it holds
261
+ * the requests somebody has actually RUN: the header names that
262
+ * really work and real example bodies.
263
+ * curl the lowest bar. A team with neither of the above still has a
264
+ * command that works, usually pasted in a chat thread.
265
+ *
266
+ * They all produce the same reviewable shape, because the useful step is not the
267
+ * parsing. It is what comes after: choosing which operations an agent should
268
+ * have and writing what each one is for.
269
+ *
270
+ * ```ts
271
+ * const draft = await importTools({ openapiUrl: 'https://api.acme.com/openapi.json' });
272
+ * const draft = importTools({ postman: collection });
273
+ * const draft = importTools({ curl: 'curl -X POST https://api.acme.com/refunds -d ...' });
274
+ * ```
275
+ */
276
+ export declare function importTools(source: Exclude<ImportSource, {
277
+ openapiUrl: string;
278
+ }>, options?: ImportOptions): ImportedTools;
279
+ export declare function importTools(source: Extract<ImportSource, {
280
+ openapiUrl: string;
281
+ }>, options?: ImportOptions): Promise<ImportedTools>;
282
+ export {};