@m6d/cortex-cli 0.1.0 → 0.2.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m6d/cortex-cli",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Scaffold and operate Cortex servers",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -90,7 +90,7 @@ type Resolve = ReturnType<typeof resolver>;
90
90
 
91
91
  function literalUnion(values: unknown[]) {
92
92
  return values
93
- .filter((value) => SCALAR_TYPES.has(typeof value))
93
+ .filter((value) => value === null || SCALAR_TYPES.has(typeof value))
94
94
  .map((value) => JSON.stringify(value))
95
95
  .join(" | ");
96
96
  }
@@ -125,15 +125,32 @@ function inputType(schema: unknown, resolve: Resolve, depth = 0, indent = 0): st
125
125
  const rendered = variants.map((variant) => inputType(variant, resolve, depth, indent));
126
126
  return [...new Set(rendered)].join(" | ");
127
127
  }
128
- if (schema.type === "null") return "null";
129
- if (schema.type === "array") {
130
- return `${inputType(schema.items, resolve, depth + 1, indent)}[]`;
128
+ const type = primaryType(schema.type);
129
+ const nullable = allowsNull(schema.type) ? " | null" : "";
130
+ if (type === "null") return "null";
131
+ if (type === "array") {
132
+ const item = inputType(schema.items, resolve, depth + 1, indent);
133
+ // A union item type binds looser than `[]`, so it is parenthesized.
134
+ return `${item.includes(" | ") ? `(${item})` : item}[]${nullable}`;
131
135
  }
132
- if (schema.type === "object" || isRecord(schema.properties)) {
133
- return inputObject(schema, resolve, depth, indent);
136
+ if (type === "object" || isRecord(schema.properties)) {
137
+ return inputObject(schema, resolve, depth, indent) + nullable;
134
138
  }
135
- if (schema.type === "integer") return "number";
136
- return SCALAR_TYPES.has(String(schema.type)) ? String(schema.type) : "unknown";
139
+ if (type === "integer") return `number${nullable}`;
140
+ return SCALAR_TYPES.has(String(type)) ? `${String(type)}${nullable}` : "unknown";
141
+ }
142
+
143
+ /** The non-null member of a JSON Schema `type`, so `["string", "null"]` reads as `string`. */
144
+ function primaryType(type: unknown) {
145
+ if (!Array.isArray(type)) return type;
146
+ const members: unknown[] = type;
147
+ return members.find((member) => member !== "null");
148
+ }
149
+
150
+ function allowsNull(type: unknown) {
151
+ if (!Array.isArray(type)) return false;
152
+ const members: unknown[] = type;
153
+ return members.includes("null");
137
154
  }
138
155
 
139
156
  /** The branches of a union schema, under whichever keyword carries them. */
@@ -143,7 +160,9 @@ function variantsOf(schema: Record<string, unknown>) {
143
160
  }
144
161
 
145
162
  function isObjectSchema(schema: unknown): schema is Record<string, unknown> {
146
- return isRecord(schema) && (schema.type === "object" || isRecord(schema.properties));
163
+ return (
164
+ isRecord(schema) && (primaryType(schema.type) === "object" || isRecord(schema.properties))
165
+ );
147
166
  }
148
167
 
149
168
  /**
@@ -176,7 +195,7 @@ function responseObject(schema: Record<string, unknown>, resolve: Resolve, depth
176
195
  const fields = orderedPropertyNames(schema).map((name) => {
177
196
  const child = responseUnion(properties[name], resolve);
178
197
  if (!isRecord(child) || depth >= MAX_DEPTH) return propertyName(name);
179
- if (child.type === "array") {
198
+ if (primaryType(child.type) === "array") {
180
199
  const items = responseUnion(child.items, resolve);
181
200
  return isObjectSchema(items)
182
201
  ? `${propertyName(name)}[].${responseObject(items, resolve, depth + 1)}`
@@ -200,7 +219,7 @@ export function responseShape(schema: unknown) {
200
219
  const resolve = resolver(schema);
201
220
  const root = responseUnion(schema, resolve);
202
221
  if (!isRecord(root)) return "{}";
203
- if (root.type === "array") {
222
+ if (primaryType(root.type) === "array") {
204
223
  const items = responseUnion(root.items, resolve);
205
224
  return isObjectSchema(items) ? `[]${responseObject(items, resolve)}` : "[]";
206
225
  }
@@ -160,9 +160,10 @@ export type TriggerFiringSummary = {
160
160
  };
161
161
 
162
162
  /**
163
- * A stored message as it is persisted and served. TanStack AI's `UIMessage`
164
- * has no metadata field, so cortex owns the envelope: the SDK's parts plus the
165
- * server-derived metadata the UI renders on settled messages.
163
+ * A stored message as it is persisted and served: the SDK's parts plus the
164
+ * server-derived envelope the UIs render, carried in the SDK message's own
165
+ * `metadata` bag so it travels with the message over the stream and the
166
+ * transcript alike.
166
167
  *
167
168
  * `TPart` stays generic so this file keeps its zero dependencies — both
168
169
  * sides substitute the SDK's `MessagePart`.
@@ -175,6 +176,15 @@ export type CortexMessage<TPart = unknown> = {
175
176
  metadata?: MessageMetadata;
176
177
  };
177
178
 
179
+ /**
180
+ * A stored message as the SDK's chat client takes it. The SDK has no `trigger`
181
+ * role, so a firing's message travels as a user turn; its true role stays on
182
+ * the envelope (`metadata.trigger`), which is what the UIs render the event from.
183
+ */
184
+ export function toUiMessage<TPart>(message: CortexMessage<TPart>) {
185
+ return { ...message, role: message.role === "trigger" ? ("user" as const) : message.role };
186
+ }
187
+
178
188
  /**
179
189
  * Key under the AG-UI request's `forwardedProps` carrying the answers to
180
190
  * parked client tool calls on a continuation request. The server owns the
@@ -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.1.0",
30
+ "@m6d/cortex-server": "~0.2.0",
31
31
  "@tanstack/ai": "^0.55.0",
32
32
  "@tanstack/ai-openai": "^0.22.8",
33
33
  hono: "^4.12.3",