@m6d/cortex-cli 0.18.0 → 0.19.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/package.json +1 -1
- package/src/commands/apply.ts +12 -7
- package/src/commands/management.ts +17 -15
- package/src/commands/setup.ts +72 -60
- package/src/contracts/management/index.ts +169 -0
- package/src/contracts/management/procedures.generated.ts +5891 -0
- package/src/contracts/manifest/index.ts +26 -17
- package/src/management/client.ts +17 -77
- package/src/scaffold/files.ts +2 -2
|
@@ -1476,22 +1476,6 @@ export const agentSettingsSchema = z.strictObject({
|
|
|
1476
1476
|
/** Off, end users cannot message the agent: only its triggers reach it. */
|
|
1477
1477
|
messageTrigger: z.boolean().default(true),
|
|
1478
1478
|
defaultLocale: localeSchema.default(BASE_LOCALE),
|
|
1479
|
-
rateLimits: z
|
|
1480
|
-
.strictObject({
|
|
1481
|
-
allUsers: z
|
|
1482
|
-
.strictObject({
|
|
1483
|
-
messagesPerMinute: rateLimit(agentRateLimits.messagesPerMinute, "allUsers"),
|
|
1484
|
-
tokensPerDay: rateLimit(agentRateLimits.tokensPerDay, "allUsers"),
|
|
1485
|
-
})
|
|
1486
|
-
.prefault({}),
|
|
1487
|
-
perUser: z
|
|
1488
|
-
.strictObject({
|
|
1489
|
-
messagesPerMinute: rateLimit(agentRateLimits.messagesPerMinute, "perUser"),
|
|
1490
|
-
tokensPerDay: rateLimit(agentRateLimits.tokensPerDay, "perUser"),
|
|
1491
|
-
})
|
|
1492
|
-
.prefault({}),
|
|
1493
|
-
})
|
|
1494
|
-
.prefault({}),
|
|
1495
1479
|
context: z
|
|
1496
1480
|
.strictObject({
|
|
1497
1481
|
maxContextTokens: setting(agentContext.maxContextTokens),
|
|
@@ -1536,9 +1520,34 @@ const manifestAgentSchema = z.strictObject({
|
|
|
1536
1520
|
})
|
|
1537
1521
|
.default({}),
|
|
1538
1522
|
settings: agentSettingsSchema.prefault({}),
|
|
1523
|
+
/** Messages a minute and model tokens a UTC day, for all users together and for each; null, no limit. */
|
|
1524
|
+
rateLimits: z
|
|
1525
|
+
.strictObject({
|
|
1526
|
+
allUsers: z
|
|
1527
|
+
.strictObject({
|
|
1528
|
+
messagesPerMinute: rateLimit(agentRateLimits.messagesPerMinute, "allUsers"),
|
|
1529
|
+
tokensPerDay: rateLimit(agentRateLimits.tokensPerDay, "allUsers"),
|
|
1530
|
+
})
|
|
1531
|
+
.prefault({}),
|
|
1532
|
+
perUser: z
|
|
1533
|
+
.strictObject({
|
|
1534
|
+
messagesPerMinute: rateLimit(agentRateLimits.messagesPerMinute, "perUser"),
|
|
1535
|
+
tokensPerDay: rateLimit(agentRateLimits.tokensPerDay, "perUser"),
|
|
1536
|
+
})
|
|
1537
|
+
.prefault({}),
|
|
1538
|
+
})
|
|
1539
|
+
.prefault({}),
|
|
1539
1540
|
suggestions: suggestionsSchema.default(() => byLocale(() => [])),
|
|
1540
1541
|
greeting: greetingSchema.default(() => byLocale(() => "")),
|
|
1541
|
-
overridable: overridable([
|
|
1542
|
+
overridable: overridable([
|
|
1543
|
+
"name",
|
|
1544
|
+
"prompt",
|
|
1545
|
+
"models",
|
|
1546
|
+
"settings",
|
|
1547
|
+
"rateLimits",
|
|
1548
|
+
"suggestions",
|
|
1549
|
+
"greeting",
|
|
1550
|
+
]),
|
|
1542
1551
|
});
|
|
1543
1552
|
export type ManifestAgent = z.input<typeof manifestAgentSchema>;
|
|
1544
1553
|
|
package/src/management/client.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { createManagementClient, MANAGEMENT_BASE_PATH } from "@cortex/contracts/management";
|
|
6
|
+
import type { ManagementTarget } from "@cortex/contracts/management";
|
|
6
7
|
import { z } from "zod";
|
|
7
8
|
|
|
8
9
|
import { profilesPath } from "./profiles";
|
|
@@ -109,7 +110,7 @@ export async function loadOpenApi(url: string) {
|
|
|
109
110
|
const path = cachePath(url);
|
|
110
111
|
const cached = readCache(path);
|
|
111
112
|
try {
|
|
112
|
-
const response = await fetch(`${url}/
|
|
113
|
+
const response = await fetch(`${url}${MANAGEMENT_BASE_PATH}/openapi.json`, {
|
|
113
114
|
headers: cached ? { "If-None-Match": cached.etag } : {},
|
|
114
115
|
});
|
|
115
116
|
if (response.status === 304 && cached)
|
|
@@ -159,71 +160,28 @@ export function inputSchemaOf(operation: OpenApiOperation) {
|
|
|
159
160
|
}
|
|
160
161
|
|
|
161
162
|
/**
|
|
162
|
-
*
|
|
163
|
-
*
|
|
164
|
-
* anything else JSON-encoded, which is how the document declares it. A
|
|
165
|
-
* mutation posts its input as the JSON body. A refusal throws
|
|
166
|
-
* `ManagementError` with the error body's code, message, detail and sentence.
|
|
163
|
+
* Where `profile`'s management calls go; a Cortex that does not answer at
|
|
164
|
+
* all rejects as `UnreachableError`, apart from one that refused.
|
|
167
165
|
*/
|
|
168
|
-
export
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const response = await fetch(url, {
|
|
177
|
-
method: method.toUpperCase(),
|
|
178
|
-
headers: {
|
|
179
|
-
Authorization: `Bearer ${profile.key}`,
|
|
180
|
-
...(method === "post" ? { "Content-Type": "application/json" } : {}),
|
|
181
|
-
},
|
|
182
|
-
body: method === "post" && input !== undefined ? JSON.stringify(input) : undefined,
|
|
183
|
-
}).catch((error: unknown) => {
|
|
184
|
-
throw new UnreachableError(error);
|
|
185
|
-
});
|
|
186
|
-
const body: unknown = await response.json().catch(() => null);
|
|
187
|
-
if (!response.ok) {
|
|
188
|
-
const { code, message, refusal, cause } = (body ?? {}) as {
|
|
189
|
-
code?: string;
|
|
190
|
-
message?: string;
|
|
191
|
-
refusal?: string;
|
|
192
|
-
cause?: unknown;
|
|
193
|
-
};
|
|
194
|
-
throw new ManagementError(
|
|
195
|
-
response.status,
|
|
196
|
-
code ?? "error",
|
|
197
|
-
message ?? response.statusText,
|
|
198
|
-
isRecord(cause) ? cause : undefined,
|
|
199
|
-
refusal,
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
return body;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function isScalar(value: unknown): value is string | number | boolean | null {
|
|
206
|
-
return value === null || ["string", "number", "boolean"].includes(typeof value);
|
|
166
|
+
export function managementTarget(profile: { url: string; key: string }) {
|
|
167
|
+
return {
|
|
168
|
+
...profile,
|
|
169
|
+
fetch: (url: string, init: RequestInit) =>
|
|
170
|
+
fetch(url, init).catch((error: unknown) => {
|
|
171
|
+
throw new UnreachableError(error);
|
|
172
|
+
}),
|
|
173
|
+
} satisfies ManagementTarget;
|
|
207
174
|
}
|
|
208
175
|
|
|
209
|
-
/**
|
|
210
|
-
function
|
|
211
|
-
|
|
212
|
-
for (const [name, value] of Object.entries(input)) {
|
|
213
|
-
if (value === undefined) continue;
|
|
214
|
-
if (isScalar(value)) params.set(name, String(value));
|
|
215
|
-
else if (Array.isArray(value) && value.length > 0 && value.every(isScalar)) {
|
|
216
|
-
for (const item of value) params.append(name, String(item));
|
|
217
|
-
} else params.set(name, JSON.stringify(value));
|
|
218
|
-
}
|
|
219
|
-
const encoded = params.toString();
|
|
220
|
-
return encoded === "" ? "" : `?${encoded}`;
|
|
176
|
+
/** The typed client for the calls the CLI makes by name, over `managementTarget`. */
|
|
177
|
+
export function managementClient(profile: { url: string; key: string }) {
|
|
178
|
+
return createManagementClient(managementTarget(profile));
|
|
221
179
|
}
|
|
222
180
|
|
|
223
181
|
/**
|
|
224
182
|
* Cortex did not answer at all: refused, reset, unresolvable. `fetch` rejects
|
|
225
183
|
* only for these, with whatever its runtime throws (Bun's is a plain `Error`
|
|
226
|
-
* with a `code`), so `
|
|
184
|
+
* with a `code`), so `managementTarget` names them once here.
|
|
227
185
|
*/
|
|
228
186
|
export class UnreachableError extends Error {
|
|
229
187
|
public constructor(cause: unknown) {
|
|
@@ -231,21 +189,3 @@ export class UnreachableError extends Error {
|
|
|
231
189
|
this.name = "UnreachableError";
|
|
232
190
|
}
|
|
233
191
|
}
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* A refusal; `detail` is what the refusal names, when it names something (an
|
|
237
|
-
* entry, the row holding a name), and `refusal` the sentence Cortex words it
|
|
238
|
-
* in, when it has one.
|
|
239
|
-
*/
|
|
240
|
-
export class ManagementError extends Error {
|
|
241
|
-
public constructor(
|
|
242
|
-
public readonly status: number,
|
|
243
|
-
public readonly code: string,
|
|
244
|
-
message: string,
|
|
245
|
-
public readonly detail?: Record<string, unknown>,
|
|
246
|
-
public readonly refusal?: string,
|
|
247
|
-
) {
|
|
248
|
-
super(message);
|
|
249
|
-
this.name = "ManagementError";
|
|
250
|
-
}
|
|
251
|
-
}
|
package/src/scaffold/files.ts
CHANGED
|
@@ -29,7 +29,7 @@ import { applyPorts, type Ports } from "@/scaffold/ports";
|
|
|
29
29
|
* `@m6d/cortex` range below are stamped by scripts/sync-package-versions.ts
|
|
30
30
|
* before the CLI publishes, so a scaffold pins what was current then.
|
|
31
31
|
*/
|
|
32
|
-
const CORTEX_VERSION = "0.
|
|
32
|
+
const CORTEX_VERSION = "0.18.0";
|
|
33
33
|
|
|
34
34
|
/** This machine as Cortex's containers name it: the one private host the stack's egress policy admits. */
|
|
35
35
|
export const DOCKER_HOST = "host.docker.internal";
|
|
@@ -150,7 +150,7 @@ function packageJson({ name, datasets, setup }: Project) {
|
|
|
150
150
|
verify: "bun run format:check && bun run lint && bun run spellcheck && bun run check && bun run audit",
|
|
151
151
|
},
|
|
152
152
|
dependencies: {
|
|
153
|
-
"@m6d/cortex": "~0.
|
|
153
|
+
"@m6d/cortex": "~0.6.0",
|
|
154
154
|
// drizzle 1.0 is in beta; this is the build `@m6d/cortex/drizzle` is tested against.
|
|
155
155
|
...(datasets ? { "drizzle-orm": "1.0.0-beta.15-859cf75" } : {}),
|
|
156
156
|
hono: "^4.12.3",
|