@gobing-ai/ts-ai-decision 0.5.13
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 +142 -0
- package/dist/catalog.d.ts +16 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +253 -0
- package/dist/errors.d.ts +47 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +67 -0
- package/dist/hub.d.ts +142 -0
- package/dist/hub.d.ts.map +1 -0
- package/dist/hub.js +262 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/params.d.ts +31 -0
- package/dist/params.d.ts.map +1 -0
- package/dist/params.js +149 -0
- package/dist/registry.d.ts +42 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +74 -0
- package/dist/schema.d.ts +137 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +71 -0
- package/dist/types.d.ts +84 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +0 -0
- package/examples/decisions.yaml +42 -0
- package/examples/support.yaml +54 -0
- package/package.json +66 -0
- package/schemas/decision-catalog.schema.json +226 -0
- package/src/catalog.ts +359 -0
- package/src/errors.ts +72 -0
- package/src/hub.ts +419 -0
- package/src/index.ts +7 -0
- package/src/params.ts +170 -0
- package/src/registry.ts +99 -0
- package/src/schema.ts +95 -0
- package/src/types.ts +80 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,aAAa,EAAE,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC7G,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACjF,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAGlF,wHAAwH;AACxH,MAAM,MAAM,WAAW,GAAG,aAAa,GAAG,CAAC,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;AAEzF,4GAA4G;AAC5G,MAAM,WAAW,mBAAmB;IAChC,oGAAoG;IACpG,QAAQ,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC,CAAC;IACnF,mHAAmH;IACnH,QAAQ,CAAC,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,eAAe,CAAC;QAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,iBAAiB,CAAA;KAAE,CAAC;CACjH;AAID;;;;;;;;GAQG;AACH,qBAAa,qBAAqB;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGpB;IAEJ,sFAAsF;gBAC1E,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,mBAAmB,GAAG,KAAK,CAAA;KAAE;IAYhE,oGAAoG;IACpG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI;IAWjD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B,KAAK,IAAI,MAAM,EAAE;IAIjB;;;;OAIG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CA2BtD"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { createDecisionMaker } from '@gobing-ai/ts-ai-runner';
|
|
2
|
+
import { createFmDriver } from '@gobing-ai/ts-decision-fm';
|
|
3
|
+
import { createLayaDriver } from '@gobing-ai/ts-laya-mlx';
|
|
4
|
+
import { DecisionRegistryError, UnknownDecisionMakerError } from './errors.js';
|
|
5
|
+
const NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
6
|
+
/**
|
|
7
|
+
* Registry mapping plain names to {@link DecisionMaker}s (task 0091, ADR-033
|
|
8
|
+
* § Maker registry). Built-ins are registered as lazy factories, so
|
|
9
|
+
* `register`, `has` and `names` never construct a maker or driver; the first
|
|
10
|
+
* `resolve` runs the factory and memoises the maker, while a failed factory
|
|
11
|
+
* stays un-memoised so a later resolve retries (e.g. a model not yet
|
|
12
|
+
* downloaded). No catalog dependency — catalog code depends on this, never
|
|
13
|
+
* the reverse.
|
|
14
|
+
*/
|
|
15
|
+
export class DecisionMakerRegistry {
|
|
16
|
+
entries = new Map();
|
|
17
|
+
/** Pre-registers `typesafe`, `fm-local` and `laya-local` unless `builtins: false`. */
|
|
18
|
+
constructor(options) {
|
|
19
|
+
if (options?.builtins === false)
|
|
20
|
+
return;
|
|
21
|
+
const { makerOptions = {}, driverOptions = {} } = options?.builtins ?? {};
|
|
22
|
+
this.register('typesafe', () => createDecisionMaker({ backend: 'typesafe', ...makerOptions }));
|
|
23
|
+
this.register('fm-local', () => createDecisionMaker({ driver: createFmDriver(driverOptions['fm-local'] ?? {}), ...makerOptions }));
|
|
24
|
+
this.register('laya-local', () => createDecisionMaker({ driver: createLayaDriver(driverOptions['laya-local'] ?? {}), ...makerOptions }));
|
|
25
|
+
}
|
|
26
|
+
/** Register a maker or factory under `name`; chains. Throws on a bad or already-registered name. */
|
|
27
|
+
register(name, source) {
|
|
28
|
+
if (!NAME_PATTERN.test(name)) {
|
|
29
|
+
throw new DecisionRegistryError(`Invalid decision maker name '${name}' — must match ${NAME_PATTERN}.`);
|
|
30
|
+
}
|
|
31
|
+
if (this.entries.has(name)) {
|
|
32
|
+
throw new DecisionRegistryError(`Decision maker '${name}' is already registered.`);
|
|
33
|
+
}
|
|
34
|
+
this.entries.set(name, { source });
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
has(name) {
|
|
38
|
+
return this.entries.has(name);
|
|
39
|
+
}
|
|
40
|
+
names() {
|
|
41
|
+
return [...this.entries.keys()];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve `name` to a maker, running and memoising a factory on first use. Factory errors
|
|
45
|
+
* propagate unchanged. Concurrent resolves of one name share a single in-flight factory run
|
|
46
|
+
* so every caller gets the same instance; a rejected run is cleared so a later resolve retries.
|
|
47
|
+
*/
|
|
48
|
+
async resolve(name) {
|
|
49
|
+
const entry = this.entries.get(name);
|
|
50
|
+
if (entry === undefined) {
|
|
51
|
+
throw new UnknownDecisionMakerError(`Unknown decision maker '${name}' — register it or use a built-in.`, name);
|
|
52
|
+
}
|
|
53
|
+
if (entry.maker)
|
|
54
|
+
return entry.maker;
|
|
55
|
+
// A check-then-set across `await` would let two concurrent callers run the factory and
|
|
56
|
+
// receive different instances, so the run itself is memoised while in flight. The
|
|
57
|
+
// rejection teardown attaches via .catch instead of a try/finally inside the run: with a
|
|
58
|
+
// finally-based clear, Bun's test runner reports the settled rejection as an unhandled
|
|
59
|
+
// error when a later resolve retries (false positive).
|
|
60
|
+
if (!entry.pending) {
|
|
61
|
+
const run = (async () => {
|
|
62
|
+
const maker = typeof entry.source === 'function' ? await entry.source() : entry.source;
|
|
63
|
+
entry.maker = maker;
|
|
64
|
+
return maker;
|
|
65
|
+
})();
|
|
66
|
+
run.catch(() => {
|
|
67
|
+
if (entry.pending === run)
|
|
68
|
+
entry.pending = undefined; // allow a later resolve to retry
|
|
69
|
+
});
|
|
70
|
+
entry.pending = run;
|
|
71
|
+
}
|
|
72
|
+
return await entry.pending;
|
|
73
|
+
}
|
|
74
|
+
}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { Desc } from '@gobing-ai/ts-ai-runner';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
/**
|
|
4
|
+
* Zod schema for the decision catalog — the runtime source of truth (task 0089 R4).
|
|
5
|
+
* `schemas/decision-catalog.schema.json` describes the same shape for editors and
|
|
6
|
+
* standard validators; strictness (`additionalProperties: false` / `.strict()`) applies
|
|
7
|
+
* at every level. Cross-field semantics (fallback vocabulary, template refs, defaults,
|
|
8
|
+
* reserved `instructions`) are enforced by the loader in `catalog.ts`.
|
|
9
|
+
*/
|
|
10
|
+
export declare const DECISION_ID_PATTERN: RegExp;
|
|
11
|
+
/** Declared parameter names: lowercase-start identifier, no hyphens. */
|
|
12
|
+
export declare const PARAM_NAME_PATTERN: RegExp;
|
|
13
|
+
/** Maker registry names: lowercase kebab-case. */
|
|
14
|
+
export declare const MAKER_NAME_PATTERN: RegExp;
|
|
15
|
+
/** Full parameter form; the shorthand is the bare {@link ParamTypeSchema} string. */
|
|
16
|
+
declare const FullParamSchema: z.ZodObject<{
|
|
17
|
+
type: z.ZodEnum<{
|
|
18
|
+
string: "string";
|
|
19
|
+
number: "number";
|
|
20
|
+
boolean: "boolean";
|
|
21
|
+
enum: "enum";
|
|
22
|
+
json: "json";
|
|
23
|
+
}>;
|
|
24
|
+
default: z.ZodOptional<z.ZodUnknown>;
|
|
25
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
26
|
+
description: z.ZodOptional<z.ZodString>;
|
|
27
|
+
}, z.core.$strict>;
|
|
28
|
+
/** Authored parameter form: the bare type shorthand or the full strict object. */
|
|
29
|
+
export declare const ParamSchema: z.ZodUnion<readonly [z.ZodEnum<{
|
|
30
|
+
string: "string";
|
|
31
|
+
number: "number";
|
|
32
|
+
boolean: "boolean";
|
|
33
|
+
enum: "enum";
|
|
34
|
+
json: "json";
|
|
35
|
+
}>, z.ZodObject<{
|
|
36
|
+
type: z.ZodEnum<{
|
|
37
|
+
string: "string";
|
|
38
|
+
number: "number";
|
|
39
|
+
boolean: "boolean";
|
|
40
|
+
enum: "enum";
|
|
41
|
+
json: "json";
|
|
42
|
+
}>;
|
|
43
|
+
default: z.ZodOptional<z.ZodUnknown>;
|
|
44
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
45
|
+
description: z.ZodOptional<z.ZodString>;
|
|
46
|
+
}, z.core.$strict>]>;
|
|
47
|
+
/** One authored decision (strict; cross-field semantics are enforced by the loader in `catalog.ts`). */
|
|
48
|
+
export declare const DecisionSchema: z.ZodObject<{
|
|
49
|
+
type: z.ZodEnum<{
|
|
50
|
+
choice: "choice";
|
|
51
|
+
score: "score";
|
|
52
|
+
noul: "noul";
|
|
53
|
+
}>;
|
|
54
|
+
description: z.ZodOptional<z.ZodString>;
|
|
55
|
+
instructions: z.ZodOptional<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>;
|
|
56
|
+
parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodEnum<{
|
|
57
|
+
string: "string";
|
|
58
|
+
number: "number";
|
|
59
|
+
boolean: "boolean";
|
|
60
|
+
enum: "enum";
|
|
61
|
+
json: "json";
|
|
62
|
+
}>, z.ZodObject<{
|
|
63
|
+
type: z.ZodEnum<{
|
|
64
|
+
string: "string";
|
|
65
|
+
number: "number";
|
|
66
|
+
boolean: "boolean";
|
|
67
|
+
enum: "enum";
|
|
68
|
+
json: "json";
|
|
69
|
+
}>;
|
|
70
|
+
default: z.ZodOptional<z.ZodUnknown>;
|
|
71
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
72
|
+
description: z.ZodOptional<z.ZodString>;
|
|
73
|
+
}, z.core.$strict>]>>>;
|
|
74
|
+
criteria: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
75
|
+
true: z.ZodOptional<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>;
|
|
76
|
+
false: z.ZodOptional<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>;
|
|
77
|
+
}, z.core.$strict>, z.ZodRecord<z.ZodString, z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>, z.ZodArray<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>]>>;
|
|
78
|
+
fallback: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>;
|
|
79
|
+
minConfidence: z.ZodOptional<z.ZodNumber>;
|
|
80
|
+
maker: z.ZodOptional<z.ZodString>;
|
|
81
|
+
model: z.ZodOptional<z.ZodString>;
|
|
82
|
+
}, z.core.$strict>;
|
|
83
|
+
/** Whole-catalog schema (strict; `version` must be 1 and at least one decision is required). */
|
|
84
|
+
export declare const DecisionCatalogSchema: z.ZodObject<{
|
|
85
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
86
|
+
version: z.ZodLiteral<1>;
|
|
87
|
+
defaults: z.ZodOptional<z.ZodObject<{
|
|
88
|
+
maker: z.ZodOptional<z.ZodString>;
|
|
89
|
+
model: z.ZodOptional<z.ZodString>;
|
|
90
|
+
minConfidence: z.ZodOptional<z.ZodNumber>;
|
|
91
|
+
}, z.core.$strict>>;
|
|
92
|
+
decisions: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
93
|
+
type: z.ZodEnum<{
|
|
94
|
+
choice: "choice";
|
|
95
|
+
score: "score";
|
|
96
|
+
noul: "noul";
|
|
97
|
+
}>;
|
|
98
|
+
description: z.ZodOptional<z.ZodString>;
|
|
99
|
+
instructions: z.ZodOptional<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>;
|
|
100
|
+
parameters: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodEnum<{
|
|
101
|
+
string: "string";
|
|
102
|
+
number: "number";
|
|
103
|
+
boolean: "boolean";
|
|
104
|
+
enum: "enum";
|
|
105
|
+
json: "json";
|
|
106
|
+
}>, z.ZodObject<{
|
|
107
|
+
type: z.ZodEnum<{
|
|
108
|
+
string: "string";
|
|
109
|
+
number: "number";
|
|
110
|
+
boolean: "boolean";
|
|
111
|
+
enum: "enum";
|
|
112
|
+
json: "json";
|
|
113
|
+
}>;
|
|
114
|
+
default: z.ZodOptional<z.ZodUnknown>;
|
|
115
|
+
values: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
116
|
+
description: z.ZodOptional<z.ZodString>;
|
|
117
|
+
}, z.core.$strict>]>>>;
|
|
118
|
+
criteria: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
119
|
+
true: z.ZodOptional<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>;
|
|
120
|
+
false: z.ZodOptional<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>;
|
|
121
|
+
}, z.core.$strict>, z.ZodRecord<z.ZodString, z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>, z.ZodArray<z.ZodType<Desc, unknown, z.core.$ZodTypeInternals<Desc, unknown>>>]>>;
|
|
122
|
+
fallback: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>;
|
|
123
|
+
minConfidence: z.ZodOptional<z.ZodNumber>;
|
|
124
|
+
maker: z.ZodOptional<z.ZodString>;
|
|
125
|
+
model: z.ZodOptional<z.ZodString>;
|
|
126
|
+
}, z.core.$strict>>;
|
|
127
|
+
}, z.core.$strict>;
|
|
128
|
+
/** Inferred shape of a validated catalog body. */
|
|
129
|
+
export type ParsedCatalog = z.infer<typeof DecisionCatalogSchema>;
|
|
130
|
+
/** Inferred shape of one validated decision body. */
|
|
131
|
+
export type ParsedDecision = z.infer<typeof DecisionSchema>;
|
|
132
|
+
/** Inferred shape of the full (non-shorthand) parameter form. */
|
|
133
|
+
export type ParsedParam = z.infer<typeof FullParamSchema>;
|
|
134
|
+
/** The whole parameter union: the shorthand type string or the full form. */
|
|
135
|
+
export type ParsedParamUnion = z.infer<typeof ParamSchema>;
|
|
136
|
+
export {};
|
|
137
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAQ,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;GAMG;AAEH,eAAO,MAAM,mBAAmB,QAAuB,CAAC;AACxD,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,QAAyB,CAAC;AACzD,kDAAkD;AAClD,eAAO,MAAM,kBAAkB,QAAsB,CAAC;AAoBtD,qFAAqF;AACrF,QAAA,MAAM,eAAe;;;;;;;;;;;kBAOR,CAAC;AAEd,kFAAkF;AAClF,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;oBAA8C,CAAC;AAMvE,wGAAwG;AACxG,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAYd,CAAC;AAEd,gGAAgG;AAChG,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAiB5B,CAAC;AAEP,kDAAkD;AAClD,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAClE,qDAAqD;AACrD,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAC5D,iEAAiE;AACjE,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAC1D,6EAA6E;AAC7E,MAAM,MAAM,gBAAgB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* Zod schema for the decision catalog — the runtime source of truth (task 0089 R4).
|
|
4
|
+
* `schemas/decision-catalog.schema.json` describes the same shape for editors and
|
|
5
|
+
* standard validators; strictness (`additionalProperties: false` / `.strict()`) applies
|
|
6
|
+
* at every level. Cross-field semantics (fallback vocabulary, template refs, defaults,
|
|
7
|
+
* reserved `instructions`) are enforced by the loader in `catalog.ts`.
|
|
8
|
+
*/
|
|
9
|
+
export const DECISION_ID_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
10
|
+
/** Declared parameter names: lowercase-start identifier, no hyphens. */
|
|
11
|
+
export const PARAM_NAME_PATTERN = /^[a-z][a-zA-Z0-9_]*$/;
|
|
12
|
+
/** Maker registry names: lowercase kebab-case. */
|
|
13
|
+
export const MAKER_NAME_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
14
|
+
const JsonValueSchema = z.lazy(() => z.union([
|
|
15
|
+
z.string(),
|
|
16
|
+
z.number(),
|
|
17
|
+
z.boolean(),
|
|
18
|
+
z.null(),
|
|
19
|
+
z.array(JsonValueSchema),
|
|
20
|
+
z.record(z.string(), JsonValueSchema),
|
|
21
|
+
]));
|
|
22
|
+
/** A Jev entry: string, JSON object, JSON array, or null ("left undescribed"). */
|
|
23
|
+
const JevEntrySchema = z.lazy(() => z.union([z.string(), z.null(), z.array(JsonValueSchema), z.record(z.string(), JsonValueSchema)]));
|
|
24
|
+
const ParamTypeSchema = z.enum(['string', 'number', 'boolean', 'enum', 'json']);
|
|
25
|
+
/** Full parameter form; the shorthand is the bare {@link ParamTypeSchema} string. */
|
|
26
|
+
const FullParamSchema = z
|
|
27
|
+
.object({
|
|
28
|
+
type: ParamTypeSchema,
|
|
29
|
+
default: z.unknown().optional(),
|
|
30
|
+
values: z.array(z.string()).min(1).optional(),
|
|
31
|
+
description: z.string().optional(),
|
|
32
|
+
})
|
|
33
|
+
.strict();
|
|
34
|
+
/** Authored parameter form: the bare type shorthand or the full strict object. */
|
|
35
|
+
export const ParamSchema = z.union([ParamTypeSchema, FullParamSchema]);
|
|
36
|
+
const NoulCriteriaSchema = z.object({ true: JevEntrySchema.optional(), false: JevEntrySchema.optional() }).strict();
|
|
37
|
+
const ChoiceCriteriaSchema = z.record(z.string().min(1), JevEntrySchema);
|
|
38
|
+
const ScoreCriteriaSchema = z.array(JevEntrySchema);
|
|
39
|
+
/** One authored decision (strict; cross-field semantics are enforced by the loader in `catalog.ts`). */
|
|
40
|
+
export const DecisionSchema = z
|
|
41
|
+
.object({
|
|
42
|
+
type: z.enum(['choice', 'score', 'noul']),
|
|
43
|
+
description: z.string().optional(),
|
|
44
|
+
instructions: JevEntrySchema.optional(),
|
|
45
|
+
parameters: z.record(z.string().regex(PARAM_NAME_PATTERN), ParamSchema).optional(),
|
|
46
|
+
criteria: z.union([NoulCriteriaSchema, ChoiceCriteriaSchema, ScoreCriteriaSchema]).optional(),
|
|
47
|
+
fallback: z.union([z.string(), z.number(), z.boolean()]),
|
|
48
|
+
minConfidence: z.number().min(0).max(1).optional(),
|
|
49
|
+
maker: z.string().regex(MAKER_NAME_PATTERN).optional(),
|
|
50
|
+
model: z.string().optional(),
|
|
51
|
+
})
|
|
52
|
+
.strict();
|
|
53
|
+
/** Whole-catalog schema (strict; `version` must be 1 and at least one decision is required). */
|
|
54
|
+
export const DecisionCatalogSchema = z
|
|
55
|
+
.object({
|
|
56
|
+
$schema: z.string().optional(),
|
|
57
|
+
version: z.literal(1),
|
|
58
|
+
defaults: z
|
|
59
|
+
.object({
|
|
60
|
+
maker: z.string().regex(MAKER_NAME_PATTERN).optional(),
|
|
61
|
+
model: z.string().optional(),
|
|
62
|
+
minConfidence: z.number().min(0).max(1).optional(),
|
|
63
|
+
})
|
|
64
|
+
.strict()
|
|
65
|
+
.optional(),
|
|
66
|
+
decisions: z.record(z.string().regex(DECISION_ID_PATTERN), DecisionSchema),
|
|
67
|
+
})
|
|
68
|
+
.strict()
|
|
69
|
+
.refine((catalog) => Object.keys(catalog.decisions).length >= 1, {
|
|
70
|
+
message: 'decisions must declare at least one decision',
|
|
71
|
+
});
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Desc, Json } from '@gobing-ai/ts-ai-runner';
|
|
2
|
+
/** Jev question types a decision can declare (task 0089 R4). */
|
|
3
|
+
export type DecisionType = 'choice' | 'score' | 'noul';
|
|
4
|
+
/** Declared parameter types; `enum` requires `values`, `json` accepts any JSON value. */
|
|
5
|
+
export type ParamType = 'string' | 'number' | 'boolean' | 'enum' | 'json';
|
|
6
|
+
/** One declared parameter, normalized from the shorthand (`name: type`) or full form. */
|
|
7
|
+
export interface DecisionParam {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly type: ParamType;
|
|
10
|
+
/** True when authored without a `default` key: every call must supply it. */
|
|
11
|
+
readonly required: boolean;
|
|
12
|
+
/** Authored `default` value (may be null); defined exactly when not required. */
|
|
13
|
+
readonly default?: Json;
|
|
14
|
+
/** Accepted strings for `type: enum` (at least one). */
|
|
15
|
+
readonly values?: readonly string[];
|
|
16
|
+
readonly description?: string;
|
|
17
|
+
}
|
|
18
|
+
/** A criteria/instructions entry: description string, JSON object, JSON array, or null ("undescribed"). */
|
|
19
|
+
export type JevEntry = Desc;
|
|
20
|
+
/** Normalized criteria of a decision, shaped by its `type`. */
|
|
21
|
+
export type DecisionCriteria = {
|
|
22
|
+
readonly kind: 'choice';
|
|
23
|
+
readonly labels: Readonly<Record<string, JevEntry>>;
|
|
24
|
+
} | {
|
|
25
|
+
readonly kind: 'score';
|
|
26
|
+
readonly levels: readonly JevEntry[];
|
|
27
|
+
} | {
|
|
28
|
+
readonly kind: 'noul';
|
|
29
|
+
readonly outcomes?: {
|
|
30
|
+
readonly true?: JevEntry;
|
|
31
|
+
readonly false?: JevEntry;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
/** One typed decision definition as produced by the loader. */
|
|
35
|
+
export interface DecisionDefinition {
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly source: string;
|
|
38
|
+
readonly type: DecisionType;
|
|
39
|
+
/** Documentation only; never sent to the model. */
|
|
40
|
+
readonly description?: string;
|
|
41
|
+
/** Authored instructions template; {@link DEFAULT_INSTRUCTIONS_TEMPLATE} when absent. */
|
|
42
|
+
readonly instructions: JevEntry;
|
|
43
|
+
/** Declared parameters plus the implicit reserved `instructions` parameter. */
|
|
44
|
+
readonly parameters: Readonly<Record<string, DecisionParam>>;
|
|
45
|
+
readonly criteria: DecisionCriteria;
|
|
46
|
+
readonly fallback: string | number | boolean;
|
|
47
|
+
/** Overrides `defaults.minConfidence` (0..1). */
|
|
48
|
+
readonly minConfidence?: number;
|
|
49
|
+
/** Registry name, checked at hub load, not by the catalog loader. */
|
|
50
|
+
readonly maker?: string;
|
|
51
|
+
readonly model?: string;
|
|
52
|
+
}
|
|
53
|
+
/** Catalog-wide maker/model/minConfidence defaults; every key optional. */
|
|
54
|
+
export interface CatalogDefaults {
|
|
55
|
+
readonly maker?: string;
|
|
56
|
+
readonly model?: string;
|
|
57
|
+
readonly minConfidence?: number;
|
|
58
|
+
}
|
|
59
|
+
/** A loaded catalog: typed definitions, all-or-nothing (task 0089 invariant). */
|
|
60
|
+
export interface DecisionCatalog {
|
|
61
|
+
readonly source: string;
|
|
62
|
+
readonly defaults: CatalogDefaults;
|
|
63
|
+
readonly decisions: Readonly<Record<string, DecisionDefinition>>;
|
|
64
|
+
}
|
|
65
|
+
/** Fully resolved parameter values for one `decide` call, including `instructions`. */
|
|
66
|
+
export type ResolvedParams = Record<string, Json>;
|
|
67
|
+
/** The rendered Jev question for one decision, ready for the neutral surface. */
|
|
68
|
+
export type JevQuestion = {
|
|
69
|
+
readonly type: 'choice';
|
|
70
|
+
readonly instructions: JevEntry;
|
|
71
|
+
readonly criteria: Readonly<Record<string, JevEntry>>;
|
|
72
|
+
} | {
|
|
73
|
+
readonly type: 'score';
|
|
74
|
+
readonly instructions: JevEntry;
|
|
75
|
+
readonly criteria: readonly JevEntry[];
|
|
76
|
+
} | {
|
|
77
|
+
readonly type: 'noul';
|
|
78
|
+
readonly instructions: JevEntry;
|
|
79
|
+
readonly criteria?: {
|
|
80
|
+
readonly true?: JevEntry;
|
|
81
|
+
readonly false?: JevEntry;
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../schemas/decision-catalog.schema.json
|
|
2
|
+
$schema: "@gobing-ai/ts-ai-decision/schemas/decision-catalog.schema.json"
|
|
3
|
+
version: 1
|
|
4
|
+
defaults: # optional; every key optional
|
|
5
|
+
maker: typesafe # a registered maker name (built-ins: typesafe | fm-local | laya-local)
|
|
6
|
+
model: jev-latest # forwarded as the ask-level model; omit for the backend default
|
|
7
|
+
minConfidence: 0.7 # 0..1; package default 0.7 when absent everywhere
|
|
8
|
+
|
|
9
|
+
decisions:
|
|
10
|
+
category:
|
|
11
|
+
type: choice
|
|
12
|
+
description: Route an inbound support ticket # documentation only; never sent to the model
|
|
13
|
+
instructions: "Classify this ${params.channel} ticket: ${params.instructions}"
|
|
14
|
+
parameters:
|
|
15
|
+
channel: { type: enum, values: [email, chat], default: email }
|
|
16
|
+
criteria: # label -> description (null = undescribed); >= 2 labels
|
|
17
|
+
bug_report: The user is reporting something that is broken or producing errors
|
|
18
|
+
billing: Charges, invoices, refunds, subscriptions
|
|
19
|
+
feature_request: The user is requesting new functionality
|
|
20
|
+
account: Login, permissions, profile, security
|
|
21
|
+
fallback: account # must be a criteria label
|
|
22
|
+
|
|
23
|
+
bug_severity:
|
|
24
|
+
type: score
|
|
25
|
+
parameters:
|
|
26
|
+
component: string # shorthand: type only -> required
|
|
27
|
+
affected_users: { type: number, default: 10 }
|
|
28
|
+
# no `instructions` key -> defaults to "${params.instructions}"
|
|
29
|
+
criteria: # ordered rubric, index = level; >= 2 entries
|
|
30
|
+
- Cosmetic; no impact to functionality
|
|
31
|
+
- Broken or degraded feature in ${params.component}; workaround exists
|
|
32
|
+
- Blocking issue; no workaround exists
|
|
33
|
+
fallback: 1 # integer level in [0, criteria.length - 1]
|
|
34
|
+
maker: laya-local # per-decision override
|
|
35
|
+
|
|
36
|
+
refund_requested:
|
|
37
|
+
type: noul
|
|
38
|
+
criteria: # optional; Jev keys
|
|
39
|
+
true: The customer explicitly asks for money back
|
|
40
|
+
false: Anything else
|
|
41
|
+
fallback: false # boolean
|
|
42
|
+
minConfidence: 0.8
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# yaml-language-server: $schema=../schemas/decision-catalog.schema.json
|
|
2
|
+
$schema: "@gobing-ai/ts-ai-decision/schemas/decision-catalog.schema.json"
|
|
3
|
+
version: 1
|
|
4
|
+
defaults:
|
|
5
|
+
maker: typesafe # a registered maker name (built-ins: typesafe | fm-local | laya-local)
|
|
6
|
+
model: jev-latest # forwarded as the ask-level model; omit for the backend default
|
|
7
|
+
minConfidence: 0.7
|
|
8
|
+
|
|
9
|
+
decisions:
|
|
10
|
+
category:
|
|
11
|
+
type: choice
|
|
12
|
+
description: Route an inbound support ticket
|
|
13
|
+
instructions: "Classify this ${params.channel} ticket: ${params.instructions}"
|
|
14
|
+
parameters:
|
|
15
|
+
channel: { type: enum, values: [email, chat], default: email }
|
|
16
|
+
criteria: # label -> description; >= 2 labels
|
|
17
|
+
bug_report: The user is reporting something that is broken or producing errors
|
|
18
|
+
billing: Charges, invoices, refunds, subscriptions
|
|
19
|
+
feature_request: The user is requesting new functionality
|
|
20
|
+
account: Login, permissions, profile, security
|
|
21
|
+
fallback: account # must be a criteria label
|
|
22
|
+
|
|
23
|
+
bug_severity:
|
|
24
|
+
type: score
|
|
25
|
+
parameters:
|
|
26
|
+
component: string # shorthand: type only -> required
|
|
27
|
+
affected_users: { type: number, default: 10 }
|
|
28
|
+
# no `instructions` key -> defaults to "${params.instructions}"
|
|
29
|
+
criteria: # ordered rubric, index = level; >= 2 entries
|
|
30
|
+
- Cosmetic; no impact to functionality
|
|
31
|
+
- "Broken or degraded feature in ${params.component}; workaround exists"
|
|
32
|
+
- Blocking issue; no workaround exists
|
|
33
|
+
fallback: 1 # integer level in [0, criteria.length - 1]
|
|
34
|
+
maker: laya-local # per-decision override
|
|
35
|
+
|
|
36
|
+
refund_requested:
|
|
37
|
+
type: noul
|
|
38
|
+
criteria: # optional; Jev keys
|
|
39
|
+
true: The customer explicitly asks for money back
|
|
40
|
+
false: Anything else
|
|
41
|
+
fallback: false # boolean
|
|
42
|
+
minConfidence: 0.8
|
|
43
|
+
|
|
44
|
+
send_reply:
|
|
45
|
+
type: choice
|
|
46
|
+
description: Draft or drop an automated reply
|
|
47
|
+
instructions: "Reply in a ${params.tone} tone. Context: ${params.context}"
|
|
48
|
+
parameters:
|
|
49
|
+
tone: { type: enum, values: [formal, casual], default: casual }
|
|
50
|
+
context: { type: json, default: null } # optional; substitutes as "" when null
|
|
51
|
+
criteria:
|
|
52
|
+
send: Draft a reply for review
|
|
53
|
+
discard: Do not reply
|
|
54
|
+
fallback: discard
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gobing-ai/ts-ai-decision",
|
|
3
|
+
"version": "0.5.13",
|
|
4
|
+
"description": "@gobing-ai/ts-ai-decision — Declarative YAML decision catalog over the ts-ai-runner DecisionMaker surface.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"typescript",
|
|
7
|
+
"ai",
|
|
8
|
+
"decision",
|
|
9
|
+
"catalog",
|
|
10
|
+
"llm"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/gobing-ai/ts-libs.git",
|
|
15
|
+
"directory": "packages/ai-decision"
|
|
16
|
+
},
|
|
17
|
+
"author": "Robin Min <minlongbing@gmail.com>",
|
|
18
|
+
"contributors": [
|
|
19
|
+
"Robin Min <minlongbing@gmail.com>"
|
|
20
|
+
],
|
|
21
|
+
"type": "module",
|
|
22
|
+
"private": false,
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"license": "Apache-2.0",
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"import": "./dist/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./schemas/*": "./schemas/*",
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"dist",
|
|
37
|
+
"src",
|
|
38
|
+
"schemas",
|
|
39
|
+
"examples",
|
|
40
|
+
"README.md"
|
|
41
|
+
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc -p tsconfig.build.json && bun ../../scripts/builder.ts fix-dist-esm-extensions dist",
|
|
44
|
+
"test": "NODE_ENV=test bun test --coverage --coverage-dir=.coverage --reporter=dots",
|
|
45
|
+
"test:full": "NODE_ENV=test bun test --update-snapshots --coverage --coverage-dir=.coverage",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"lint": "biome check . && bun run typecheck",
|
|
48
|
+
"format": "biome check . --write",
|
|
49
|
+
"check": "bun run lint && bun run test",
|
|
50
|
+
"prepublishOnly": "bun ../../scripts/builder.ts check-publish-manifest . && bun run build",
|
|
51
|
+
"release": "echo 'Manual publish is disabled. Releases go through GitHub Actions via Trusted Publishing — push a tag: git tag @gobing-ai/ts-ai-decision-v<version> && git push --tags' && exit 1"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@gobing-ai/ts-ai-runner": "^0.5.13",
|
|
55
|
+
"@gobing-ai/ts-decision-fm": "^0.5.13",
|
|
56
|
+
"@gobing-ai/ts-laya-mlx": "^0.5.13",
|
|
57
|
+
"@gobing-ai/ts-runtime": "^0.5.13",
|
|
58
|
+
"zod": "^4.1.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/bun": "1.3.14"
|
|
62
|
+
},
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
}
|
|
66
|
+
}
|