@foresthubai/workflow-core 0.3.0 → 0.4.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 (77) hide show
  1. package/LICENSE +202 -202
  2. package/NOTICE +14 -14
  3. package/README.md +63 -63
  4. package/dist/api/workflow.d.ts +2 -2
  5. package/dist/api/workflow.d.ts.map +1 -1
  6. package/package.json +1 -1
  7. package/src/api/index.ts +11 -11
  8. package/src/api/workflow.ts +607 -607
  9. package/src/channel/Channel.ts +11 -11
  10. package/src/channel/ChannelDefinition.ts +76 -76
  11. package/src/channel/index.ts +6 -6
  12. package/src/channel/serialization.ts +68 -68
  13. package/src/deploy/index.ts +1 -1
  14. package/src/deploy/requirements.test.ts +61 -61
  15. package/src/deploy/requirements.ts +41 -41
  16. package/src/diagnostics/__fixtures__/diagnosticFixtures.ts +158 -158
  17. package/src/diagnostics/diagnostics.test.ts +878 -878
  18. package/src/diagnostics/diagnostics.ts +936 -936
  19. package/src/diagnostics/index.ts +11 -11
  20. package/src/edge/Edge.ts +23 -23
  21. package/src/edge/EdgeDefinition.ts +45 -45
  22. package/src/edge/EdgeType.ts +19 -19
  23. package/src/edge/index.ts +8 -8
  24. package/src/edge/serialization.ts +83 -83
  25. package/src/expression/index.ts +4 -4
  26. package/src/expression/parser.ts +362 -362
  27. package/src/expression/types.ts +30 -30
  28. package/src/function/FunctionDeclaration.ts +54 -54
  29. package/src/function/index.ts +3 -3
  30. package/src/function/serialization.ts +40 -40
  31. package/src/globals.d.ts +9 -9
  32. package/src/id/index.ts +8 -8
  33. package/src/index.ts +22 -22
  34. package/src/memory/Memory.ts +15 -15
  35. package/src/memory/MemoryDefinition.ts +16 -16
  36. package/src/memory/MemoryFileDefinition.ts +37 -37
  37. package/src/memory/MemoryRegistry.ts +35 -35
  38. package/src/memory/VectorDatabaseDefinition.ts +21 -21
  39. package/src/memory/index.ts +8 -8
  40. package/src/memory/serialization.ts +47 -47
  41. package/src/migration/index.ts +4 -4
  42. package/src/migration/migrate.test.ts +44 -44
  43. package/src/migration/migrate.ts +58 -58
  44. package/src/migration/migrations.ts +24 -24
  45. package/src/migration/version.ts +9 -9
  46. package/src/model/LLMModelDefinition.ts +12 -12
  47. package/src/model/Model.ts +39 -39
  48. package/src/model/ModelDefinition.ts +15 -15
  49. package/src/model/ModelRegistry.ts +33 -33
  50. package/src/model/index.ts +7 -7
  51. package/src/model/serialization.ts +30 -30
  52. package/src/node/AgentNode.ts +82 -82
  53. package/src/node/DataNode.ts +41 -41
  54. package/src/node/FunctionNode.ts +76 -76
  55. package/src/node/InputNode.ts +185 -185
  56. package/src/node/LogicNode.ts +33 -33
  57. package/src/node/MqttNode.ts +127 -127
  58. package/src/node/Node.ts +61 -61
  59. package/src/node/NodeDefinition.ts +37 -37
  60. package/src/node/NodeRegistry.ts +85 -85
  61. package/src/node/OutputNode.ts +87 -87
  62. package/src/node/ToolNode.ts +32 -32
  63. package/src/node/TriggerNode.ts +272 -272
  64. package/src/node/constants.ts +16 -16
  65. package/src/node/index.ts +26 -26
  66. package/src/node/methods.ts +278 -278
  67. package/src/node/serialization.ts +544 -544
  68. package/src/parameter/OutputParameter.ts +68 -68
  69. package/src/parameter/Parameter.ts +243 -243
  70. package/src/parameter/index.ts +33 -33
  71. package/src/variable/Variable.ts +10 -10
  72. package/src/variable/index.ts +16 -16
  73. package/src/variable/operations.ts +106 -106
  74. package/src/workflow/Workflow.ts +41 -41
  75. package/src/workflow/index.ts +3 -3
  76. package/src/workflow/serialization.test.ts +240 -240
  77. package/src/workflow/serialization.ts +242 -242
@@ -1,47 +1,47 @@
1
- import type { Schemas } from "../api";
2
- import type { Memory } from "./Memory";
3
-
4
- export type ApiMemory = Schemas["Memory"];
5
-
6
- /**
7
- * Serialize a domain Memory to the API discriminated-union shape.
8
- * MemoryFile drops `maxSizeBytes` when unset (absent and null both mean "unlimited").
9
- */
10
- export function serialize(mem: Memory): ApiMemory {
11
- const { id, label, type, arguments: args } = mem;
12
- switch (type) {
13
- case "MemoryFile":
14
- return {
15
- type,
16
- id,
17
- label,
18
- description: (args.description as string) ?? "",
19
- content: (args.content as string) ?? "",
20
- ...(args.maxSizeBytes != null ? { maxSizeBytes: args.maxSizeBytes as number } : {}),
21
- };
22
- case "VectorDatabase":
23
- return {
24
- type,
25
- id,
26
- label,
27
- ...(args.description != null ? { description: args.description as string } : {}),
28
- };
29
- }
30
- }
31
-
32
- /** Convert an API Memory into a domain Memory. */
33
- export function deserialize(api: ApiMemory): Memory {
34
- const { id, label, type } = api;
35
- const args: Record<string, unknown> = {};
36
- switch (type) {
37
- case "MemoryFile":
38
- args.description = api.description ?? "";
39
- args.content = api.content ?? "";
40
- if (api.maxSizeBytes != null) args.maxSizeBytes = api.maxSizeBytes;
41
- break;
42
- case "VectorDatabase":
43
- if (api.description != null) args.description = api.description;
44
- break;
45
- }
46
- return { id, label, type, arguments: args };
47
- }
1
+ import type { Schemas } from "../api";
2
+ import type { Memory } from "./Memory";
3
+
4
+ export type ApiMemory = Schemas["Memory"];
5
+
6
+ /**
7
+ * Serialize a domain Memory to the API discriminated-union shape.
8
+ * MemoryFile drops `maxSizeBytes` when unset (absent and null both mean "unlimited").
9
+ */
10
+ export function serialize(mem: Memory): ApiMemory {
11
+ const { id, label, type, arguments: args } = mem;
12
+ switch (type) {
13
+ case "MemoryFile":
14
+ return {
15
+ type,
16
+ id,
17
+ label,
18
+ description: (args.description as string) ?? "",
19
+ content: (args.content as string) ?? "",
20
+ ...(args.maxSizeBytes != null ? { maxSizeBytes: args.maxSizeBytes as number } : {}),
21
+ };
22
+ case "VectorDatabase":
23
+ return {
24
+ type,
25
+ id,
26
+ label,
27
+ ...(args.description != null ? { description: args.description as string } : {}),
28
+ };
29
+ }
30
+ }
31
+
32
+ /** Convert an API Memory into a domain Memory. */
33
+ export function deserialize(api: ApiMemory): Memory {
34
+ const { id, label, type } = api;
35
+ const args: Record<string, unknown> = {};
36
+ switch (type) {
37
+ case "MemoryFile":
38
+ args.description = api.description ?? "";
39
+ args.content = api.content ?? "";
40
+ if (api.maxSizeBytes != null) args.maxSizeBytes = api.maxSizeBytes;
41
+ break;
42
+ case "VectorDatabase":
43
+ if (api.description != null) args.description = api.description;
44
+ break;
45
+ }
46
+ return { id, label, type, arguments: args };
47
+ }
@@ -1,4 +1,4 @@
1
- export { CURRENT_SCHEMA_VERSION, BASELINE_SCHEMA_VERSION } from "./version";
2
- export { migrate, readSchemaVersion } from "./migrate";
3
- export { MIGRATIONS } from "./migrations";
4
- export type { Migration } from "./migrations";
1
+ export { CURRENT_SCHEMA_VERSION, BASELINE_SCHEMA_VERSION } from "./version";
2
+ export { migrate, readSchemaVersion } from "./migrate";
3
+ export { MIGRATIONS } from "./migrations";
4
+ export type { Migration } from "./migrations";
@@ -1,44 +1,44 @@
1
- import { describe, it, expect } from "vitest";
2
- import { migrate, readSchemaVersion } from "./migrate";
3
- import { CURRENT_SCHEMA_VERSION } from "./version";
4
-
5
- describe("readSchemaVersion", () => {
6
- it("reads an explicit integer version", () => {
7
- expect(readSchemaVersion({ schemaVersion: 3 })).toBe(3);
8
- });
9
-
10
- it("defaults missing, non-integer, or out-of-range to the baseline", () => {
11
- expect(readSchemaVersion({})).toBe(1);
12
- expect(readSchemaVersion({ schemaVersion: 1.5 })).toBe(1);
13
- expect(readSchemaVersion({ schemaVersion: 0 })).toBe(1);
14
- expect(readSchemaVersion({ schemaVersion: "2" })).toBe(1);
15
- });
16
- });
17
-
18
- describe("migrate", () => {
19
- it("stamps the current version on a baseline document", () => {
20
- const out = migrate({ nodes: [], edges: [] });
21
- expect(out.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
22
- });
23
-
24
- it("passes through a document already at the current version", () => {
25
- const doc = { schemaVersion: CURRENT_SCHEMA_VERSION, nodes: [] };
26
- expect(migrate(doc).schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
27
- });
28
-
29
- it("does not mutate its input", () => {
30
- const doc: Record<string, unknown> = { nodes: [] };
31
- migrate(doc);
32
- expect("schemaVersion" in doc).toBe(false);
33
- });
34
-
35
- it("rejects a document newer than this build supports", () => {
36
- expect(() => migrate({ schemaVersion: CURRENT_SCHEMA_VERSION + 1 })).toThrow(/newer than this build/);
37
- });
38
-
39
- it("rejects a non-object document", () => {
40
- expect(() => migrate(null)).toThrow(/must be a JSON object/);
41
- expect(() => migrate([])).toThrow(/must be a JSON object/);
42
- expect(() => migrate(42)).toThrow(/must be a JSON object/);
43
- });
44
- });
1
+ import { describe, it, expect } from "vitest";
2
+ import { migrate, readSchemaVersion } from "./migrate";
3
+ import { CURRENT_SCHEMA_VERSION } from "./version";
4
+
5
+ describe("readSchemaVersion", () => {
6
+ it("reads an explicit integer version", () => {
7
+ expect(readSchemaVersion({ schemaVersion: 3 })).toBe(3);
8
+ });
9
+
10
+ it("defaults missing, non-integer, or out-of-range to the baseline", () => {
11
+ expect(readSchemaVersion({})).toBe(1);
12
+ expect(readSchemaVersion({ schemaVersion: 1.5 })).toBe(1);
13
+ expect(readSchemaVersion({ schemaVersion: 0 })).toBe(1);
14
+ expect(readSchemaVersion({ schemaVersion: "2" })).toBe(1);
15
+ });
16
+ });
17
+
18
+ describe("migrate", () => {
19
+ it("stamps the current version on a baseline document", () => {
20
+ const out = migrate({ nodes: [], edges: [] });
21
+ expect(out.schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
22
+ });
23
+
24
+ it("passes through a document already at the current version", () => {
25
+ const doc = { schemaVersion: CURRENT_SCHEMA_VERSION, nodes: [] };
26
+ expect(migrate(doc).schemaVersion).toBe(CURRENT_SCHEMA_VERSION);
27
+ });
28
+
29
+ it("does not mutate its input", () => {
30
+ const doc: Record<string, unknown> = { nodes: [] };
31
+ migrate(doc);
32
+ expect("schemaVersion" in doc).toBe(false);
33
+ });
34
+
35
+ it("rejects a document newer than this build supports", () => {
36
+ expect(() => migrate({ schemaVersion: CURRENT_SCHEMA_VERSION + 1 })).toThrow(/newer than this build/);
37
+ });
38
+
39
+ it("rejects a non-object document", () => {
40
+ expect(() => migrate(null)).toThrow(/must be a JSON object/);
41
+ expect(() => migrate([])).toThrow(/must be a JSON object/);
42
+ expect(() => migrate(42)).toThrow(/must be a JSON object/);
43
+ });
44
+ });
@@ -1,58 +1,58 @@
1
- import type { ApiWorkflow } from "../workflow/Workflow";
2
- import { MIGRATIONS, type Migration } from "./migrations";
3
- import { BASELINE_SCHEMA_VERSION, CURRENT_SCHEMA_VERSION } from "./version";
4
-
5
- /**
6
- * Index the registry by `from` and assert it forms a contiguous chain over
7
- * [BASELINE_SCHEMA_VERSION, CURRENT_SCHEMA_VERSION). A gap or duplicate is a
8
- * programming error, so it throws at module load rather than on first use.
9
- */
10
- function buildChain(migrations: readonly Migration[]): ReadonlyMap<number, Migration> {
11
- const byFrom = new Map<number, Migration>();
12
- for (const m of migrations) {
13
- if (!Number.isInteger(m.from) || m.from < BASELINE_SCHEMA_VERSION || m.from >= CURRENT_SCHEMA_VERSION) {
14
- throw new Error(`[migration] from must be an integer in [${BASELINE_SCHEMA_VERSION}, ${CURRENT_SCHEMA_VERSION}), got ${m.from}`);
15
- }
16
- if (byFrom.has(m.from)) {
17
- throw new Error(`[migration] duplicate migration from ${m.from}`);
18
- }
19
- byFrom.set(m.from, m);
20
- }
21
- for (let v = BASELINE_SCHEMA_VERSION; v < CURRENT_SCHEMA_VERSION; v++) {
22
- if (!byFrom.has(v)) throw new Error(`[migration] missing migration from ${v} -> ${v + 1}`);
23
- }
24
- return byFrom;
25
- }
26
-
27
- const CHAIN = buildChain(MIGRATIONS);
28
-
29
- /** Read the schema version, defaulting absent/invalid to the baseline. */
30
- export function readSchemaVersion(doc: Record<string, unknown>): number {
31
- const v = doc.schemaVersion;
32
- return typeof v === "number" && Number.isInteger(v) && v >= BASELINE_SCHEMA_VERSION ? v : BASELINE_SCHEMA_VERSION;
33
- }
34
-
35
- /**
36
- * Upgrade a raw, parsed workflow document to CURRENT_SCHEMA_VERSION and return
37
- * it as the current {@link ApiWorkflow}, ready for `deserialize`. Runs on
38
- * untyped JSON so each migration stays pinned to the shape it was written for.
39
- * Throws on a non-object, or a version newer than this build supports.
40
- */
41
- export function migrate(raw: unknown): ApiWorkflow {
42
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
43
- throw new Error("[migration] workflow document must be a JSON object");
44
- }
45
- let doc: Record<string, unknown> = { ...(raw as Record<string, unknown>) };
46
-
47
- const version = readSchemaVersion(doc);
48
- if (version > CURRENT_SCHEMA_VERSION) {
49
- throw new Error(`[migration] schemaVersion ${version} is newer than this build supports (${CURRENT_SCHEMA_VERSION})`);
50
- }
51
-
52
- for (let v = version; v < CURRENT_SCHEMA_VERSION; v++) {
53
- doc = CHAIN.get(v)!.migrate(doc); // non-null: buildChain covers every v in range
54
- }
55
-
56
- doc.schemaVersion = CURRENT_SCHEMA_VERSION;
57
- return doc as ApiWorkflow;
58
- }
1
+ import type { ApiWorkflow } from "../workflow/Workflow";
2
+ import { MIGRATIONS, type Migration } from "./migrations";
3
+ import { BASELINE_SCHEMA_VERSION, CURRENT_SCHEMA_VERSION } from "./version";
4
+
5
+ /**
6
+ * Index the registry by `from` and assert it forms a contiguous chain over
7
+ * [BASELINE_SCHEMA_VERSION, CURRENT_SCHEMA_VERSION). A gap or duplicate is a
8
+ * programming error, so it throws at module load rather than on first use.
9
+ */
10
+ function buildChain(migrations: readonly Migration[]): ReadonlyMap<number, Migration> {
11
+ const byFrom = new Map<number, Migration>();
12
+ for (const m of migrations) {
13
+ if (!Number.isInteger(m.from) || m.from < BASELINE_SCHEMA_VERSION || m.from >= CURRENT_SCHEMA_VERSION) {
14
+ throw new Error(`[migration] from must be an integer in [${BASELINE_SCHEMA_VERSION}, ${CURRENT_SCHEMA_VERSION}), got ${m.from}`);
15
+ }
16
+ if (byFrom.has(m.from)) {
17
+ throw new Error(`[migration] duplicate migration from ${m.from}`);
18
+ }
19
+ byFrom.set(m.from, m);
20
+ }
21
+ for (let v = BASELINE_SCHEMA_VERSION; v < CURRENT_SCHEMA_VERSION; v++) {
22
+ if (!byFrom.has(v)) throw new Error(`[migration] missing migration from ${v} -> ${v + 1}`);
23
+ }
24
+ return byFrom;
25
+ }
26
+
27
+ const CHAIN = buildChain(MIGRATIONS);
28
+
29
+ /** Read the schema version, defaulting absent/invalid to the baseline. */
30
+ export function readSchemaVersion(doc: Record<string, unknown>): number {
31
+ const v = doc.schemaVersion;
32
+ return typeof v === "number" && Number.isInteger(v) && v >= BASELINE_SCHEMA_VERSION ? v : BASELINE_SCHEMA_VERSION;
33
+ }
34
+
35
+ /**
36
+ * Upgrade a raw, parsed workflow document to CURRENT_SCHEMA_VERSION and return
37
+ * it as the current {@link ApiWorkflow}, ready for `deserialize`. Runs on
38
+ * untyped JSON so each migration stays pinned to the shape it was written for.
39
+ * Throws on a non-object, or a version newer than this build supports.
40
+ */
41
+ export function migrate(raw: unknown): ApiWorkflow {
42
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
43
+ throw new Error("[migration] workflow document must be a JSON object");
44
+ }
45
+ let doc: Record<string, unknown> = { ...(raw as Record<string, unknown>) };
46
+
47
+ const version = readSchemaVersion(doc);
48
+ if (version > CURRENT_SCHEMA_VERSION) {
49
+ throw new Error(`[migration] schemaVersion ${version} is newer than this build supports (${CURRENT_SCHEMA_VERSION})`);
50
+ }
51
+
52
+ for (let v = version; v < CURRENT_SCHEMA_VERSION; v++) {
53
+ doc = CHAIN.get(v)!.migrate(doc); // non-null: buildChain covers every v in range
54
+ }
55
+
56
+ doc.schemaVersion = CURRENT_SCHEMA_VERSION;
57
+ return doc as ApiWorkflow;
58
+ }
@@ -1,24 +1,24 @@
1
- /**
2
- * A single-step upgrade of the persisted workflow format, from `from` to
3
- * `from + 1`. Operates on the raw parsed document, never the domain types.
4
- * Forward-only: there is no down-path.
5
- *
6
- * A shipped migration is immutable — saved files depend on its exact behaviour.
7
- * Express the next change as a new migration, never an edit to an old one.
8
- */
9
- export interface Migration {
10
- /** Schema version this migration expects as input. Produces `from + 1`. */
11
- readonly from: number;
12
- /** Pure transform on the raw document; must not mutate its input. */
13
- migrate(doc: Record<string, unknown>): Record<string, unknown>;
14
- }
15
-
16
- /**
17
- * Ordered registry of single-step format migrations. To change the format:
18
- * bump CURRENT_SCHEMA_VERSION, append one migration with `from` set to the
19
- * previous value, and reconcile serialize/deserialize. {@link migrate} asserts
20
- * at load that the chain is contiguous over [BASELINE, CURRENT).
21
- */
22
- export const MIGRATIONS: readonly Migration[] = [
23
- // First entry will be `{ from: 1, migrate: (doc) => ... }`.
24
- ];
1
+ /**
2
+ * A single-step upgrade of the persisted workflow format, from `from` to
3
+ * `from + 1`. Operates on the raw parsed document, never the domain types.
4
+ * Forward-only: there is no down-path.
5
+ *
6
+ * A shipped migration is immutable — saved files depend on its exact behaviour.
7
+ * Express the next change as a new migration, never an edit to an old one.
8
+ */
9
+ export interface Migration {
10
+ /** Schema version this migration expects as input. Produces `from + 1`. */
11
+ readonly from: number;
12
+ /** Pure transform on the raw document; must not mutate its input. */
13
+ migrate(doc: Record<string, unknown>): Record<string, unknown>;
14
+ }
15
+
16
+ /**
17
+ * Ordered registry of single-step format migrations. To change the format:
18
+ * bump CURRENT_SCHEMA_VERSION, append one migration with `from` set to the
19
+ * previous value, and reconcile serialize/deserialize. {@link migrate} asserts
20
+ * at load that the chain is contiguous over [BASELINE, CURRENT).
21
+ */
22
+ export const MIGRATIONS: readonly Migration[] = [
23
+ // First entry will be `{ from: 1, migrate: (doc) => ... }`.
24
+ ];
@@ -1,9 +1,9 @@
1
- /**
2
- * Persisted-format version this build reads and writes. A plain monotonic
3
- * integer, decoupled from the contract/package semver. Bump only when the
4
- * serialized {@link ApiWorkflow} shape changes, adding a matching migration.
5
- */
6
- export const CURRENT_SCHEMA_VERSION = 1;
7
-
8
- /** Version assumed for documents that carry no `schemaVersion`. */
9
- export const BASELINE_SCHEMA_VERSION = 1;
1
+ /**
2
+ * Persisted-format version this build reads and writes. A plain monotonic
3
+ * integer, decoupled from the contract/package semver. Bump only when the
4
+ * serialized {@link ApiWorkflow} shape changes, adding a matching migration.
5
+ */
6
+ export const CURRENT_SCHEMA_VERSION = 1;
7
+
8
+ /** Version assumed for documents that carry no `schemaVersion`. */
9
+ export const BASELINE_SCHEMA_VERSION = 1;
@@ -1,12 +1,12 @@
1
- import type { ModelDefinition } from "./ModelDefinition";
2
-
3
- /**
4
- * A declared custom/self-hosted LLM model.
5
- * Capabilities default to ["chat"] on serialize; a capability editor can be added later.
6
- */
7
- export const LLMModelDefinition: ModelDefinition = {
8
- type: "LLMModel",
9
- label: "Custom LLM Model",
10
- description: "A self-hosted or custom LLM the llmproxy doesn't ship by default",
11
- parameters: [],
12
- };
1
+ import type { ModelDefinition } from "./ModelDefinition";
2
+
3
+ /**
4
+ * A declared custom/self-hosted LLM model.
5
+ * Capabilities default to ["chat"] on serialize; a capability editor can be added later.
6
+ */
7
+ export const LLMModelDefinition: ModelDefinition = {
8
+ type: "LLMModel",
9
+ label: "Custom LLM Model",
10
+ description: "A self-hosted or custom LLM the llmproxy doesn't ship by default",
11
+ parameters: [],
12
+ };
@@ -1,39 +1,39 @@
1
- // Domain Model — covers two distinct things that share a picker:
2
- // 1. The STATIC catalog (ModelInfo[]): the set of models the llmproxy already
3
- // supports. Supplied to the editor as data (props), not declared per-workflow.
4
- // A node simply stores the chosen catalog ModelID directly.
5
- // 2. DECLARED custom models (Model): self-hosted / custom models the
6
- // llmproxy doesn't ship. These are channel-like — declared in the workflow,
7
- // referenced by id from nodes, and mapped to an llmproxy provider at deploy.
8
- //
9
- // A node's `model` field is always just a ModelID string either way; static ids
10
- // resolve via the catalog (no mapping), custom ids via a declared Model.
11
- //
12
- // `type` is the api discriminator; new model families (e.g. future YOLO/ONNX
13
- // variants) register their own definition in ModelRegistry, mirroring nodes.
14
-
15
- import type { Schemas } from "../api";
16
-
17
- /** A capability a model supports (chat, embedding, vision, ...). From the api. */
18
- export type ModelCapability = Schemas["ModelCapability"];
19
-
20
- export type ModelType = "LLMModel";
21
-
22
- export const ALL_MODEL_TYPES: ModelType[] = ["LLMModel"];
23
-
24
- export interface Model {
25
- id: string;
26
- label: string;
27
- type: ModelType;
28
- arguments: Record<string, unknown>;
29
- }
30
-
31
- /**
32
- * One entry in the static model catalog handed to the builder via props. The
33
- * embedder maps the llmproxy's richer ModelInfo down to this minimal shape.
34
- */
35
- export interface ModelInfo {
36
- id: string;
37
- label: string;
38
- capabilities: ModelCapability[];
39
- }
1
+ // Domain Model — covers two distinct things that share a picker:
2
+ // 1. The STATIC catalog (ModelInfo[]): the set of models the llmproxy already
3
+ // supports. Supplied to the editor as data (props), not declared per-workflow.
4
+ // A node simply stores the chosen catalog ModelID directly.
5
+ // 2. DECLARED custom models (Model): self-hosted / custom models the
6
+ // llmproxy doesn't ship. These are channel-like — declared in the workflow,
7
+ // referenced by id from nodes, and mapped to an llmproxy provider at deploy.
8
+ //
9
+ // A node's `model` field is always just a ModelID string either way; static ids
10
+ // resolve via the catalog (no mapping), custom ids via a declared Model.
11
+ //
12
+ // `type` is the api discriminator; new model families (e.g. future YOLO/ONNX
13
+ // variants) register their own definition in ModelRegistry, mirroring nodes.
14
+
15
+ import type { Schemas } from "../api";
16
+
17
+ /** A capability a model supports (chat, embedding, vision, ...). From the api. */
18
+ export type ModelCapability = Schemas["ModelCapability"];
19
+
20
+ export type ModelType = "LLMModel";
21
+
22
+ export const ALL_MODEL_TYPES: ModelType[] = ["LLMModel"];
23
+
24
+ export interface Model {
25
+ id: string;
26
+ label: string;
27
+ type: ModelType;
28
+ arguments: Record<string, unknown>;
29
+ }
30
+
31
+ /**
32
+ * One entry in the static model catalog handed to the builder via props. The
33
+ * embedder maps the llmproxy's richer ModelInfo down to this minimal shape.
34
+ */
35
+ export interface ModelInfo {
36
+ id: string;
37
+ label: string;
38
+ capabilities: ModelCapability[];
39
+ }
@@ -1,15 +1,15 @@
1
- import type { Parameter } from "../parameter";
2
- import type { ModelType } from "./Model";
3
-
4
- /**
5
- * Static, per-type metadata for a declared (custom) model variant. Mirrors
6
- * MemoryDefinition / NodeDefinition: one definition object per ModelType,
7
- * registered in ModelRegistry. `label` is a top-level instance field (edited
8
- * like a channel label), so it is never a parameter here.
9
- */
10
- export interface ModelDefinition {
11
- type: ModelType;
12
- label: string;
13
- description: string;
14
- parameters: Parameter[];
15
- }
1
+ import type { Parameter } from "../parameter";
2
+ import type { ModelType } from "./Model";
3
+
4
+ /**
5
+ * Static, per-type metadata for a declared (custom) model variant. Mirrors
6
+ * MemoryDefinition / NodeDefinition: one definition object per ModelType,
7
+ * registered in ModelRegistry. `label` is a top-level instance field (edited
8
+ * like a channel label), so it is never a parameter here.
9
+ */
10
+ export interface ModelDefinition {
11
+ type: ModelType;
12
+ label: string;
13
+ description: string;
14
+ parameters: Parameter[];
15
+ }
@@ -1,33 +1,33 @@
1
- import type { ModelType } from "./Model";
2
- import type { ModelDefinition } from "./ModelDefinition";
3
- import { LLMModelDefinition } from "./LLMModelDefinition";
4
-
5
- /**
6
- * Central registry for declared (custom) model variant definitions (one per
7
- * ModelType). Mirrors MemoryRegistry / NodeRegistry.
8
- */
9
- class ModelDefinitionRegistry {
10
- private models: Map<ModelType, ModelDefinition> = new Map();
11
- private initialized = false;
12
-
13
- initialize() {
14
- if (this.initialized) return;
15
- this.register(LLMModelDefinition);
16
- this.initialized = true;
17
- }
18
-
19
- private register(definition: ModelDefinition) {
20
- this.models.set(definition.type, definition);
21
- }
22
-
23
- getAll(): ModelDefinition[] {
24
- return Array.from(this.models.values());
25
- }
26
-
27
- getByType(type: ModelType): ModelDefinition | undefined {
28
- return this.models.get(type);
29
- }
30
- }
31
-
32
- export const ModelRegistry = new ModelDefinitionRegistry();
33
- ModelRegistry.initialize();
1
+ import type { ModelType } from "./Model";
2
+ import type { ModelDefinition } from "./ModelDefinition";
3
+ import { LLMModelDefinition } from "./LLMModelDefinition";
4
+
5
+ /**
6
+ * Central registry for declared (custom) model variant definitions (one per
7
+ * ModelType). Mirrors MemoryRegistry / NodeRegistry.
8
+ */
9
+ class ModelDefinitionRegistry {
10
+ private models: Map<ModelType, ModelDefinition> = new Map();
11
+ private initialized = false;
12
+
13
+ initialize() {
14
+ if (this.initialized) return;
15
+ this.register(LLMModelDefinition);
16
+ this.initialized = true;
17
+ }
18
+
19
+ private register(definition: ModelDefinition) {
20
+ this.models.set(definition.type, definition);
21
+ }
22
+
23
+ getAll(): ModelDefinition[] {
24
+ return Array.from(this.models.values());
25
+ }
26
+
27
+ getByType(type: ModelType): ModelDefinition | undefined {
28
+ return this.models.get(type);
29
+ }
30
+ }
31
+
32
+ export const ModelRegistry = new ModelDefinitionRegistry();
33
+ ModelRegistry.initialize();
@@ -1,7 +1,7 @@
1
- export type { ModelType, Model, ModelCapability, ModelInfo } from "./Model";
2
- export { ALL_MODEL_TYPES } from "./Model";
3
- export type { ModelDefinition } from "./ModelDefinition";
4
- export { LLMModelDefinition } from "./LLMModelDefinition";
5
- export { ModelRegistry } from "./ModelRegistry";
6
- export { serialize, deserialize } from "./serialization";
7
- export type { ApiModel } from "./serialization";
1
+ export type { ModelType, Model, ModelCapability, ModelInfo } from "./Model";
2
+ export { ALL_MODEL_TYPES } from "./Model";
3
+ export type { ModelDefinition } from "./ModelDefinition";
4
+ export { LLMModelDefinition } from "./LLMModelDefinition";
5
+ export { ModelRegistry } from "./ModelRegistry";
6
+ export { serialize, deserialize } from "./serialization";
7
+ export type { ApiModel } from "./serialization";