@markbrutx/promptbook-core 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/dist/edge/index.js +3 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/interpolate.d.ts.map +1 -1
- package/dist/interpolate.js +1 -2
- package/dist/interpolate.js.map +1 -1
- package/dist/required-context.d.ts +27 -0
- package/dist/required-context.d.ts.map +1 -0
- package/dist/required-context.js +71 -0
- package/dist/required-context.js.map +1 -0
- package/dist/vars.d.ts +12 -0
- package/dist/vars.d.ts.map +1 -0
- package/dist/vars.js +22 -0
- package/dist/vars.js.map +1 -0
- package/package.json +19 -2
- package/src/index.ts +3 -0
- package/src/interpolate.ts +1 -3
- package/src/required-context.ts +95 -0
- package/src/vars.ts +22 -0
package/dist/edge/index.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// Generated by `npm run build:edge`; do not edit by hand.
|
|
2
2
|
|
|
3
|
-
// dist/
|
|
3
|
+
// dist/vars.js
|
|
4
4
|
var VAR_RE = /(\\?)\$\{([^}]+)\}/g;
|
|
5
|
+
|
|
6
|
+
// dist/interpolate.js
|
|
5
7
|
function interpolate(body, context, onMissing) {
|
|
6
8
|
return body.replace(VAR_RE, (_match, backslash, expr) => {
|
|
7
9
|
if (backslash) {
|
package/dist/index.d.ts
CHANGED
|
@@ -16,7 +16,10 @@ export type { BannedTokensOptions, DanglingReferenceOptions, DeadRuleOptions, Ex
|
|
|
16
16
|
export { bannedTokens, type DefaultRulesOptions, danglingReference, deadRule, defaultRules, estimateTokensByChars, exampleBalance, languageDirectivePosition, tokenBudget, unusedFragment, } from "./lint/rules/index.js";
|
|
17
17
|
export type { LintFinding, LintInput, LintReport, LintRule, LintScope, Severity } from "./lint/types.js";
|
|
18
18
|
export { loadPrompts } from "./load.js";
|
|
19
|
+
export type { RequiredContext } from "./required-context.js";
|
|
20
|
+
export { requiredContext } from "./required-context.js";
|
|
19
21
|
export { resolve } from "./resolve.js";
|
|
20
22
|
export { resolveBook } from "./resolve-book.js";
|
|
21
23
|
export type { AddTrace, CodePrompt, CodePromptSample, Composition, Context, ContextValue, ForbidTrace, Fragment, FsAdapter, PromptBook, ReplaceTrace, ResolveInput, ResolveResult, Rule, RuleAction, RuleTrace, Trace, UnmatchedAxis, When, } from "./types.js";
|
|
24
|
+
export { extractVariables } from "./vars.js";
|
|
22
25
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,uBAAuB,EACvB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EACV,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,OAAO,EACP,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,gCAAgC,EAChC,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,yBAAyB,EACzB,WAAW,EACX,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACzG,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,SAAS,EACT,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,IAAI,EACJ,UAAU,EACV,SAAS,EACT,KAAK,EACL,aAAa,EACb,IAAI,GACL,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,uBAAuB,EACvB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EACV,SAAS,EACT,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,SAAS,EACT,UAAU,EACV,OAAO,EACP,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,UAAU,GACX,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AACtC,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,YAAY,EACV,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,qBAAqB,EACrB,gCAAgC,EAChC,kBAAkB,EAClB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,YAAY,EACZ,KAAK,mBAAmB,EACxB,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,yBAAyB,EACzB,WAAW,EACX,cAAc,GACf,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACzG,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,SAAS,EACT,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,IAAI,EACJ,UAAU,EACV,SAAS,EACT,KAAK,EACL,aAAa,EACb,IAAI,GACL,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export { lint } from "./lint/lint.js";
|
|
|
10
10
|
export { iterateReferences } from "./lint/references.js";
|
|
11
11
|
export { bannedTokens, danglingReference, deadRule, defaultRules, estimateTokensByChars, exampleBalance, languageDirectivePosition, tokenBudget, unusedFragment, } from "./lint/rules/index.js";
|
|
12
12
|
export { loadPrompts } from "./load.js";
|
|
13
|
+
export { requiredContext } from "./required-context.js";
|
|
13
14
|
export { resolve } from "./resolve.js";
|
|
14
15
|
export { resolveBook } from "./resolve-book.js";
|
|
16
|
+
export { extractVariables } from "./vars.js";
|
|
15
17
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,uBAAuB,EACvB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAevD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAUzD,OAAO,EACL,YAAY,EAEZ,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,yBAAyB,EACzB,WAAW,EACX,cAAc,GACf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,UAAU,EACV,uBAAuB,EACvB,cAAc,GACf,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,uBAAuB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACxF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAevD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAEtC,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAUzD,OAAO,EACL,YAAY,EAEZ,iBAAiB,EACjB,QAAQ,EACR,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,yBAAyB,EACzB,WAAW,EACX,cAAc,GACf,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAsBhD,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.d.ts","sourceRoot":"","sources":["../src/interpolate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"interpolate.d.ts","sourceRoot":"","sources":["../src/interpolate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAG1C;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,CAapG"}
|
package/dist/interpolate.js
CHANGED
package/dist/interpolate.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interpolate.js","sourceRoot":"","sources":["../src/interpolate.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"interpolate.js","sourceRoot":"","sources":["../src/interpolate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAEnC;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,OAAgB,EAAE,SAAgC;IAC1F,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,MAAM,EAAE,SAAiB,EAAE,IAAY,EAAE,EAAE;QACtE,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,MAAM,IAAI,GAAG,CAAC;QACvB,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,SAAS,CAAC,GAAG,CAAC,CAAC;YACf,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ContextValue, PromptBook } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The context a composition declares it needs, derived statically (no cascade
|
|
4
|
+
* run). Lets a consumer see the keys to supply instead of discovering holes one
|
|
5
|
+
* `Missing variable` at a time.
|
|
6
|
+
*/
|
|
7
|
+
export interface RequiredContext {
|
|
8
|
+
/** `${var}` keys across the composition's reachable fragments; sorted, unique. */
|
|
9
|
+
vars: string[];
|
|
10
|
+
/** `when`-axis key → sorted unique option values seen across its rules. */
|
|
11
|
+
axes: Record<string, ContextValue[]>;
|
|
12
|
+
/** Provenance: each var → the fragment ids that introduce it; sorted, unique. */
|
|
13
|
+
sources: Record<string, string[]>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Statically report the context a composition needs: the `${var}` keys across
|
|
17
|
+
* every fragment it can reach (`base ∪ add-ids ∪ replace-targets`) and the
|
|
18
|
+
* `when`-axes its rules branch on.
|
|
19
|
+
*
|
|
20
|
+
* Directed over-approximation: it unions vars across *all* rules without running
|
|
21
|
+
* the cascade, so supplying every reported key never leaves a hole in any
|
|
22
|
+
* context (a never-firing `add` may over-report, never under-report). `forbid`
|
|
23
|
+
* and `order` introduce no new fragments, so they contribute no vars. Throws on
|
|
24
|
+
* an unknown composition, matching `resolveBook`.
|
|
25
|
+
*/
|
|
26
|
+
export declare function requiredContext(book: PromptBook, compName: string): RequiredContext;
|
|
27
|
+
//# sourceMappingURL=required-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required-context.d.ts","sourceRoot":"","sources":["../src/required-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAG3D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,kFAAkF;IAClF,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2EAA2E;IAC3E,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;IACrC,iFAAiF;IACjF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACnC;AAKD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,CA2CnF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { iterateReferences } from "./lint/references.js";
|
|
2
|
+
import { extractVariables } from "./vars.js";
|
|
3
|
+
/** Roles that can put a fragment into the assembled output (so its vars matter). */
|
|
4
|
+
const REACHABLE_ROLES = new Set(["base", "add", "replace-to"]);
|
|
5
|
+
/**
|
|
6
|
+
* Statically report the context a composition needs: the `${var}` keys across
|
|
7
|
+
* every fragment it can reach (`base ∪ add-ids ∪ replace-targets`) and the
|
|
8
|
+
* `when`-axes its rules branch on.
|
|
9
|
+
*
|
|
10
|
+
* Directed over-approximation: it unions vars across *all* rules without running
|
|
11
|
+
* the cascade, so supplying every reported key never leaves a hole in any
|
|
12
|
+
* context (a never-firing `add` may over-report, never under-report). `forbid`
|
|
13
|
+
* and `order` introduce no new fragments, so they contribute no vars. Throws on
|
|
14
|
+
* an unknown composition, matching `resolveBook`.
|
|
15
|
+
*/
|
|
16
|
+
export function requiredContext(book, compName) {
|
|
17
|
+
const composition = book.compositions.get(compName);
|
|
18
|
+
if (!composition) {
|
|
19
|
+
const available = [...book.compositions.keys()].sort().join(", ") || "(none)";
|
|
20
|
+
throw new Error(`Unknown prompt "${compName}". Available compositions: ${available}.`);
|
|
21
|
+
}
|
|
22
|
+
const reachable = new Set();
|
|
23
|
+
for (const ref of iterateReferences(book)) {
|
|
24
|
+
if (ref.composition === compName && REACHABLE_ROLES.has(ref.role)) {
|
|
25
|
+
reachable.add(ref.id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const sourceSets = new Map();
|
|
29
|
+
for (const id of reachable) {
|
|
30
|
+
const fragment = book.fragments.get(id);
|
|
31
|
+
if (!fragment) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
for (const key of extractVariables(fragment.body)) {
|
|
35
|
+
addTo(sourceSets, key, id);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const axisSets = new Map();
|
|
39
|
+
for (const rule of composition.rules) {
|
|
40
|
+
for (const [key, value] of Object.entries(rule.when)) {
|
|
41
|
+
addTo(axisSets, key, value);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const vars = [...sourceSets.keys()].sort();
|
|
45
|
+
const sources = {};
|
|
46
|
+
for (const key of vars) {
|
|
47
|
+
sources[key] = [...(sourceSets.get(key) ?? [])].sort();
|
|
48
|
+
}
|
|
49
|
+
const axes = {};
|
|
50
|
+
for (const key of [...axisSets.keys()].sort()) {
|
|
51
|
+
axes[key] = [...(axisSets.get(key) ?? [])].sort(compareContextValues);
|
|
52
|
+
}
|
|
53
|
+
return { vars, axes, sources };
|
|
54
|
+
}
|
|
55
|
+
/** Append `value` to the set under `key`, creating the set on first use. */
|
|
56
|
+
function addTo(map, key, value) {
|
|
57
|
+
let set = map.get(key);
|
|
58
|
+
if (set === undefined) {
|
|
59
|
+
set = new Set();
|
|
60
|
+
map.set(key, set);
|
|
61
|
+
}
|
|
62
|
+
set.add(value);
|
|
63
|
+
}
|
|
64
|
+
/** Stable order for axis options: numeric when both numbers, else by string. */
|
|
65
|
+
function compareContextValues(a, b) {
|
|
66
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
67
|
+
return a - b;
|
|
68
|
+
}
|
|
69
|
+
return String(a).localeCompare(String(b));
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=required-context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required-context.js","sourceRoot":"","sources":["../src/required-context.ts"],"names":[],"mappings":"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"}
|
package/dist/vars.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Matches `${path}` placeholders, capturing an optional leading `\` escape. */
|
|
2
|
+
export declare const VAR_RE: RegExp;
|
|
3
|
+
/**
|
|
4
|
+
* Extract the variable keys referenced by `${path}` placeholders in `body`.
|
|
5
|
+
*
|
|
6
|
+
* Shares its syntax with {@link interpolate} (both read {@link VAR_RE}), so the
|
|
7
|
+
* keys reported here are exactly the ones interpolation substitutes. Escaped
|
|
8
|
+
* `\${path}` placeholders are ignored (they render literally); keys are trimmed,
|
|
9
|
+
* sorted and de-duplicated.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractVariables(body: string): string[];
|
|
12
|
+
//# sourceMappingURL=vars.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vars.d.ts","sourceRoot":"","sources":["../src/vars.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,eAAO,MAAM,MAAM,QAAwB,CAAC;AAE5C;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAUvD"}
|
package/dist/vars.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Matches `${path}` placeholders, capturing an optional leading `\` escape. */
|
|
2
|
+
export const VAR_RE = /(\\?)\$\{([^}]+)\}/g;
|
|
3
|
+
/**
|
|
4
|
+
* Extract the variable keys referenced by `${path}` placeholders in `body`.
|
|
5
|
+
*
|
|
6
|
+
* Shares its syntax with {@link interpolate} (both read {@link VAR_RE}), so the
|
|
7
|
+
* keys reported here are exactly the ones interpolation substitutes. Escaped
|
|
8
|
+
* `\${path}` placeholders are ignored (they render literally); keys are trimmed,
|
|
9
|
+
* sorted and de-duplicated.
|
|
10
|
+
*/
|
|
11
|
+
export function extractVariables(body) {
|
|
12
|
+
const keys = new Set();
|
|
13
|
+
for (const match of body.matchAll(VAR_RE)) {
|
|
14
|
+
const [, backslash, expr] = match;
|
|
15
|
+
if (backslash || expr === undefined) {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
keys.add(expr.trim());
|
|
19
|
+
}
|
|
20
|
+
return [...keys].sort();
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=vars.js.map
|
package/dist/vars.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vars.js","sourceRoot":"","sources":["../src/vars.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,CAAC,MAAM,MAAM,GAAG,qBAAqB,CAAC;AAE5C;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1C,MAAM,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;QAClC,IAAI,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACpC,SAAS;QACX,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1B,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markbrutx/promptbook-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Agnostic, deterministic core for composing prompts from reusable fragments via declarative rules.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"prompt",
|
|
9
|
+
"prompt-engineering",
|
|
10
|
+
"prompt-management",
|
|
11
|
+
"llm",
|
|
12
|
+
"ai",
|
|
13
|
+
"composition",
|
|
14
|
+
"deterministic",
|
|
15
|
+
"agnostic"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/markbrutx/promptbook.git",
|
|
20
|
+
"directory": "packages/core"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/markbrutx/promptbook#readme",
|
|
23
|
+
"bugs": "https://github.com/markbrutx/promptbook/issues",
|
|
7
24
|
"exports": {
|
|
8
25
|
".": {
|
|
9
26
|
"types": "./dist/index.d.ts",
|
|
@@ -37,8 +54,8 @@
|
|
|
37
54
|
"devDependencies": {
|
|
38
55
|
"@biomejs/biome": "latest",
|
|
39
56
|
"@types/node": "^20.14.0",
|
|
40
|
-
"esbuild": "^0.21.5",
|
|
41
57
|
"@typescript/native-preview": "latest",
|
|
58
|
+
"esbuild": "^0.21.5",
|
|
42
59
|
"typescript": "^5.6.0",
|
|
43
60
|
"vitest": "^2.1.0"
|
|
44
61
|
},
|
package/src/index.ts
CHANGED
|
@@ -59,6 +59,8 @@ export {
|
|
|
59
59
|
} from "./lint/rules/index.js";
|
|
60
60
|
export type { LintFinding, LintInput, LintReport, LintRule, LintScope, Severity } from "./lint/types.js";
|
|
61
61
|
export { loadPrompts } from "./load.js";
|
|
62
|
+
export type { RequiredContext } from "./required-context.js";
|
|
63
|
+
export { requiredContext } from "./required-context.js";
|
|
62
64
|
export { resolve } from "./resolve.js";
|
|
63
65
|
export { resolveBook } from "./resolve-book.js";
|
|
64
66
|
export type {
|
|
@@ -82,3 +84,4 @@ export type {
|
|
|
82
84
|
UnmatchedAxis,
|
|
83
85
|
When,
|
|
84
86
|
} from "./types.js";
|
|
87
|
+
export { extractVariables } from "./vars.js";
|
package/src/interpolate.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { Context } from "./types.js";
|
|
2
|
-
|
|
3
|
-
/** Matches `${path}` placeholders, capturing an optional leading `\` escape. */
|
|
4
|
-
const VAR_RE = /(\\?)\$\{([^}]+)\}/g;
|
|
2
|
+
import { VAR_RE } from "./vars.js";
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* Substitute `${path}` placeholders in `body` using `context`.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { FragmentReference } from "./lint/references.js";
|
|
2
|
+
import { iterateReferences } from "./lint/references.js";
|
|
3
|
+
import type { ContextValue, PromptBook } from "./types.js";
|
|
4
|
+
import { extractVariables } from "./vars.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The context a composition declares it needs, derived statically (no cascade
|
|
8
|
+
* run). Lets a consumer see the keys to supply instead of discovering holes one
|
|
9
|
+
* `Missing variable` at a time.
|
|
10
|
+
*/
|
|
11
|
+
export interface RequiredContext {
|
|
12
|
+
/** `${var}` keys across the composition's reachable fragments; sorted, unique. */
|
|
13
|
+
vars: string[];
|
|
14
|
+
/** `when`-axis key → sorted unique option values seen across its rules. */
|
|
15
|
+
axes: Record<string, ContextValue[]>;
|
|
16
|
+
/** Provenance: each var → the fragment ids that introduce it; sorted, unique. */
|
|
17
|
+
sources: Record<string, string[]>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** Roles that can put a fragment into the assembled output (so its vars matter). */
|
|
21
|
+
const REACHABLE_ROLES = new Set<FragmentReference["role"]>(["base", "add", "replace-to"]);
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Statically report the context a composition needs: the `${var}` keys across
|
|
25
|
+
* every fragment it can reach (`base ∪ add-ids ∪ replace-targets`) and the
|
|
26
|
+
* `when`-axes its rules branch on.
|
|
27
|
+
*
|
|
28
|
+
* Directed over-approximation: it unions vars across *all* rules without running
|
|
29
|
+
* the cascade, so supplying every reported key never leaves a hole in any
|
|
30
|
+
* context (a never-firing `add` may over-report, never under-report). `forbid`
|
|
31
|
+
* and `order` introduce no new fragments, so they contribute no vars. Throws on
|
|
32
|
+
* an unknown composition, matching `resolveBook`.
|
|
33
|
+
*/
|
|
34
|
+
export function requiredContext(book: PromptBook, compName: string): RequiredContext {
|
|
35
|
+
const composition = book.compositions.get(compName);
|
|
36
|
+
if (!composition) {
|
|
37
|
+
const available = [...book.compositions.keys()].sort().join(", ") || "(none)";
|
|
38
|
+
throw new Error(`Unknown prompt "${compName}". Available compositions: ${available}.`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const reachable = new Set<string>();
|
|
42
|
+
for (const ref of iterateReferences(book)) {
|
|
43
|
+
if (ref.composition === compName && REACHABLE_ROLES.has(ref.role)) {
|
|
44
|
+
reachable.add(ref.id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const sourceSets = new Map<string, Set<string>>();
|
|
49
|
+
for (const id of reachable) {
|
|
50
|
+
const fragment = book.fragments.get(id);
|
|
51
|
+
if (!fragment) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
for (const key of extractVariables(fragment.body)) {
|
|
55
|
+
addTo(sourceSets, key, id);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const axisSets = new Map<string, Set<ContextValue>>();
|
|
60
|
+
for (const rule of composition.rules) {
|
|
61
|
+
for (const [key, value] of Object.entries(rule.when)) {
|
|
62
|
+
addTo(axisSets, key, value);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const vars = [...sourceSets.keys()].sort();
|
|
67
|
+
const sources: Record<string, string[]> = {};
|
|
68
|
+
for (const key of vars) {
|
|
69
|
+
sources[key] = [...(sourceSets.get(key) ?? [])].sort();
|
|
70
|
+
}
|
|
71
|
+
const axes: Record<string, ContextValue[]> = {};
|
|
72
|
+
for (const key of [...axisSets.keys()].sort()) {
|
|
73
|
+
axes[key] = [...(axisSets.get(key) ?? [])].sort(compareContextValues);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return { vars, axes, sources };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Append `value` to the set under `key`, creating the set on first use. */
|
|
80
|
+
function addTo<V>(map: Map<string, Set<V>>, key: string, value: V): void {
|
|
81
|
+
let set = map.get(key);
|
|
82
|
+
if (set === undefined) {
|
|
83
|
+
set = new Set();
|
|
84
|
+
map.set(key, set);
|
|
85
|
+
}
|
|
86
|
+
set.add(value);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Stable order for axis options: numeric when both numbers, else by string. */
|
|
90
|
+
function compareContextValues(a: ContextValue, b: ContextValue): number {
|
|
91
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
92
|
+
return a - b;
|
|
93
|
+
}
|
|
94
|
+
return String(a).localeCompare(String(b));
|
|
95
|
+
}
|
package/src/vars.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Matches `${path}` placeholders, capturing an optional leading `\` escape. */
|
|
2
|
+
export const VAR_RE = /(\\?)\$\{([^}]+)\}/g;
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Extract the variable keys referenced by `${path}` placeholders in `body`.
|
|
6
|
+
*
|
|
7
|
+
* Shares its syntax with {@link interpolate} (both read {@link VAR_RE}), so the
|
|
8
|
+
* keys reported here are exactly the ones interpolation substitutes. Escaped
|
|
9
|
+
* `\${path}` placeholders are ignored (they render literally); keys are trimmed,
|
|
10
|
+
* sorted and de-duplicated.
|
|
11
|
+
*/
|
|
12
|
+
export function extractVariables(body: string): string[] {
|
|
13
|
+
const keys = new Set<string>();
|
|
14
|
+
for (const match of body.matchAll(VAR_RE)) {
|
|
15
|
+
const [, backslash, expr] = match;
|
|
16
|
+
if (backslash || expr === undefined) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
keys.add(expr.trim());
|
|
20
|
+
}
|
|
21
|
+
return [...keys].sort();
|
|
22
|
+
}
|