@m6d/cortex-cli 0.8.0 → 0.9.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/README.md CHANGED
@@ -44,8 +44,8 @@ hard error rather than a hang.
44
44
  | `--control-center` / `--no-control-center` | off | `controlCenter` |
45
45
  | `--yes` | | Accept the defaults instead of asking |
46
46
 
47
- Unselected features are still written to `cortex.config.ts`, commented out, alongside `fastModel`,
48
- `reranker`, and `context` — the generated config documents what else exists. Every credential and
47
+ Unselected features are still written to `cortex.config.ts`, commented out, alongside `reranker`
48
+ and `context` — the generated config documents what else exists. Every credential and
49
49
  URL is a placeholder in `.env`; none of them is prompted for.
50
50
 
51
51
  ## `cortex swagger sync` / `check`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m6d/cortex-cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Scaffold and operate Cortex servers",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  /*
2
2
  * The boundary on a Vega-Lite spec the model wrote, shared by the widget
3
- * (which draws it live) and, as needed, the server:
3
+ * (which draws it live) and the server (which describes it to the model):
4
4
  * inline data only, no fetches, no interactivity, bounded work.
5
5
  */
6
6
 
@@ -18,6 +18,9 @@ const EXPANDING_TRANSFORMS = new Set([
18
18
  "sample",
19
19
  ]);
20
20
 
21
+ /** The boundary as the model reads it in its system prompt, so it writes specs this file accepts. */
22
+ export const CHART_SPEC_GUIDE = `Use Vega-Lite JSON with inline \`data.values\` only, at most ${MAX_CHART_ROWS} rows, and no \`url\` anywhere. Compute folds, trend lines and densities yourself. For several series, write one row per series and x value, or keep one row per x value and draw a layer per series (color by \`datum\`) when that would exceed the row limit. These keys are refused anywhere in the spec: ${[...EXPANDING_TRANSFORMS, "params", "selection"].join(", ")}. Expressions in \`calculate\`, \`filter\` and \`labelExpr\` may use only datum fields, literals, operators and simple math or date-part functions (no format or timeFormat), so put formatted values in the rows or use an axis \`format\`.`;
23
+
21
24
  /** What a single key or value in a chart spec may not be; undefined when it is fine on its own. */
22
25
  function chartNodeViolation(key: string, value: unknown) {
23
26
  if (key === "url") return "Charts may only use inline data and no URLs.";
@@ -1,4 +1,5 @@
1
1
  export {
2
+ CHART_SPEC_GUIDE,
2
3
  chartSpecViolation,
3
4
  externalResourceIn,
4
5
  IMAGE_FUNCTION,
@@ -14,6 +14,7 @@ import {
14
14
  variableDeclarationSchema,
15
15
  } from "./grammar";
16
16
  import { publishedAuthSchema } from "./auth";
17
+ import { runtimeModelsSchema } from "./models";
17
18
  import { triggerDeclarationSchema } from "./triggers";
18
19
  import { datasetHostDeclarationSchema, datasetIdentifierSchema } from "./datasets";
19
20
 
@@ -216,6 +217,12 @@ export const runtimeAgentConfigSchema = z.object({
216
217
  suggestions: suggestionsSchema,
217
218
  /** Operational like `suggestions`. */
218
219
  greeting: greetingSchema,
220
+ /**
221
+ * The model picks of the agent's server and of the agent, with the
222
+ * providers they and the agent's triggers name. Operational like
223
+ * `greeting`: edited without republishing.
224
+ */
225
+ models: runtimeModelsSchema,
219
226
  /** The resolved agent's id; reports about it carry this so they attach to it whatever the slug or alias later means. */
220
227
  agentRef: agentRefSchema,
221
228
  catalogVersion: catalogVersionSchema,
@@ -7,6 +7,7 @@ export * from "./grammar";
7
7
  export * from "./auth";
8
8
  export * from "./api";
9
9
  export * from "./triggers";
10
+ export * from "./models";
10
11
  export * from "./datasets";
11
12
  export * from "./dataset-sql";
12
13
  export * from "./dataset-sql-guide";
@@ -0,0 +1,50 @@
1
+ import { z } from "zod";
2
+
3
+ /**
4
+ * One level's pick of what a run talks to: a model a Control Center
5
+ * provider lists, the reasoning effort sent with it, both, or neither. An
6
+ * unset part inherits from the level above (trigger, then agent, then
7
+ * server, then the server's code config). An effort carries down only as
8
+ * far as the level that picked the model, and is sent only when that
9
+ * model's provider lists it.
10
+ */
11
+ export const modelChoiceSchema = z
12
+ .object({
13
+ provider: z.string().min(1).nullable(),
14
+ model: z.string().min(1).nullable(),
15
+ effort: z.string().min(1).nullable(),
16
+ })
17
+ .refine((choice) => (choice.provider === null) === (choice.model === null), {
18
+ error: "A provider and its model are picked together.",
19
+ });
20
+ export type ModelChoice = z.infer<typeof modelChoiceSchema>;
21
+
22
+ /** A pick that inherits everything. */
23
+ export const INHERIT_MODEL = {
24
+ provider: null,
25
+ model: null,
26
+ effort: null,
27
+ } satisfies ModelChoice;
28
+
29
+ /**
30
+ * An OpenAI-compatible endpoint as a server calls it: cc resolves the key
31
+ * from the provider's secret, and `efforts` are the values it accepts as
32
+ * `reasoning_effort`.
33
+ */
34
+ export const modelProviderEndpointSchema = z.object({
35
+ baseURL: z.url(),
36
+ apiKey: z.string().min(1),
37
+ efforts: z.array(z.string().min(1)),
38
+ });
39
+
40
+ /**
41
+ * The model picks a server needs to run one agent: its server's and the
42
+ * agent's own (each trigger carries its own on its declaration), plus every
43
+ * provider any of them names.
44
+ */
45
+ export const runtimeModelsSchema = z.object({
46
+ providers: z.record(z.string(), modelProviderEndpointSchema),
47
+ server: modelChoiceSchema,
48
+ agent: modelChoiceSchema,
49
+ });
50
+ export type RuntimeModels = z.infer<typeof runtimeModelsSchema>;
@@ -1,5 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { datasetIdentifierSchema } from "./datasets";
3
+ import { modelChoiceSchema } from "./models";
3
4
  import {
4
5
  agentRefSchema,
5
6
  agentSlugSchema,
@@ -20,6 +21,9 @@ import {
20
21
 
21
22
  export const MESSAGE_TRIGGER_NAME = "message";
22
23
 
24
+ /** The tool a trigger run with an output schema answers through; no other tool may take its name. */
25
+ export const TRIGGER_ANSWER_TOOL_NAME = "submitAnswer";
26
+
23
27
  /**
24
28
  * The first characters of a fire bearer say what it is: the secret callers
25
29
  * hold, or a one-shot test token the console minted. A test token is a JWT
@@ -98,9 +102,10 @@ export const triggerDeclarationSchema = z.object({
98
102
  input: z.record(z.string(), z.unknown()),
99
103
  /**
100
104
  * JSON Schema the run's answer must match, or null for a free-text run.
101
- * The server asks the model for that shape, validates what comes back,
102
- * and stores it as the firing's `output`; a run whose answer does not
103
- * parse fails with reason `invalid_output`.
105
+ * The run submits it through an answer tool whose input is this schema,
106
+ * and the server stores it as the firing's `output`; a run that never
107
+ * submits fails with `no_output`, one whose answers the schema refused
108
+ * with `invalid_output`.
104
109
  */
105
110
  output: z.record(z.string(), z.unknown()).nullable(),
106
111
  /**
@@ -118,6 +123,8 @@ export const triggerDeclarationSchema = z.object({
118
123
  /** Consecutive failed or rejected firings before the trigger disables itself. */
119
124
  disableAfterFailures: z.number().int().positive(),
120
125
  hasCredential: z.boolean(),
126
+ /** What runs of this trigger talk to, over the agent's pick; read live like the credential. */
127
+ modelChoice: modelChoiceSchema,
121
128
  /**
122
129
  * sha256 of the fire secret, so a server checks a presented bearer in
123
130
  * process; the Control Center hears only about console test secrets,
@@ -27,7 +27,7 @@ export type Database = "postgres" | "mssql";
27
27
  // sync (scripts/sync-package-versions.ts) restamps it and files.test.ts holds
28
28
  // them to that.
29
29
  export const DEPENDENCIES = {
30
- "@m6d/cortex-server": "~0.8.0",
30
+ "@m6d/cortex-server": "~0.9.0",
31
31
  "@tanstack/ai": "^0.55.0",
32
32
  "@tanstack/ai-openai": "^0.22.8",
33
33
  hono: "^4.12.3",
@@ -86,18 +86,10 @@ function packageJson(name: string) {
86
86
 
87
87
  /**
88
88
  * Never toggled, so they only ever appear commented out: `context` is fully
89
- * defaulted, and the other two are what you reach for once a real problem shows
90
- * up — noisy graph retrieval, a cheap-model path — not on day one.
89
+ * defaulted, and `reranker` is what you reach for once graph retrieval comes
90
+ * back noisy, not on day one.
91
91
  */
92
92
  const NEVER_SCAFFOLDED = [
93
- [
94
- "A cheaper, faster model for auxiliary passes. Same shape as `model`.",
95
- `fastModel: {
96
- baseURL: process.env["CORTEX_FAST_MODEL_URL"]!,
97
- apiKey: process.env["CORTEX_FAST_MODEL_KEY"]!,
98
- modelName: process.env["CORTEX_FAST_MODEL_NAME"]!,
99
- },`,
100
- ],
101
93
  [
102
94
  "Re-ranks knowledge-graph retrieval when it comes back noisy.",
103
95
  `reranker: {