dna-sdk 0.10.0 → 0.12.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/bootstrap.js +6 -0
- package/dist/extensions/cloud/kinds/tenant-plan.kind.yaml +105 -0
- package/dist/extensions/cloud/kinds/tier.kind.yaml +135 -0
- package/dist/extensions/cloud.d.ts +31 -0
- package/dist/extensions/cloud.js +39 -0
- package/dist/extensions/guardrails.js +4 -0
- package/dist/extensions/helix.js +19 -6
- package/dist/extensions/intel/kinds/insight.kind.yaml +148 -0
- package/dist/extensions/intel/kinds/intel-source.kind.yaml +117 -0
- package/dist/extensions/intel.d.ts +30 -0
- package/dist/extensions/intel.js +38 -0
- package/dist/extensions/portfolio/kinds/membership.kind.yaml +114 -0
- package/dist/extensions/portfolio/kinds/organization.kind.yaml +99 -0
- package/dist/extensions/portfolio/kinds/project.kind.yaml +124 -0
- package/dist/extensions/portfolio/kinds/repo.kind.yaml +99 -0
- package/dist/extensions/portfolio/kinds/role.kind.yaml +96 -0
- package/dist/extensions/portfolio.d.ts +45 -0
- package/dist/extensions/portfolio.js +53 -0
- package/dist/extensions/sdlc/kinds/lesson-learned.kind.yaml +0 -1
- package/dist/index.d.ts +1 -0
- package/dist/kernel/composition-resolver.js +17 -1
- package/dist/kernel/index.d.ts +50 -0
- package/dist/kernel/index.js +98 -0
- package/dist/kernel/instance.d.ts +8 -0
- package/dist/kernel/instance.js +9 -0
- package/dist/kernel/kind_base.d.ts +10 -0
- package/dist/kernel/kind_base.js +36 -18
- package/dist/kernel/meta.d.ts +1 -0
- package/dist/kernel/meta.js +11 -1
- package/dist/kernel/models.d.ts +23 -23
- package/dist/kernel/models.js +8 -2
- package/dist/kernel/prompt-builder.d.ts +64 -0
- package/dist/kernel/prompt-builder.js +208 -3
- package/dist/kernel/write-pipeline.d.ts +6 -0
- package/dist/kernel/write-pipeline.js +7 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type { PreviewBlock } from "./kernel/preview.js";
|
|
|
12
12
|
export { Document } from "./kernel/document.js";
|
|
13
13
|
export { Resource, type ResourceDep } from "./kernel/resource.js";
|
|
14
14
|
export { PromptBuilder } from "./kernel/prompt-builder.js";
|
|
15
|
+
export type { SectionProvenance, PromptExplanation, ExplainOpts, } from "./kernel/prompt-builder.js";
|
|
15
16
|
export { CompositionEngine } from "./kernel/composition-resolver.js";
|
|
16
17
|
export { BOOTSTRAP_KINDS, DEFAULT_NON_INHERITABLE_KINDS_V1, DEFAULT_INHERITABLE_KINDS_V1, MAX_RESOLUTION_DEPTH, ResolutionLayer, ResolutionPath, ResolvedDocument, mergeOverrideFull, mergeFieldLevel, type Contribution, type Raw, } from "./kernel/resolver.js";
|
|
17
18
|
export { CompositionResolver } from "./kernel/composition-resolver.js";
|
|
@@ -450,7 +450,23 @@ export class CompositionResolver {
|
|
|
450
450
|
// multi-package conflict surface below.
|
|
451
451
|
const catalogHits = [];
|
|
452
452
|
for (const [layerScope, layerTenant] of chain) {
|
|
453
|
-
|
|
453
|
+
let raw;
|
|
454
|
+
try {
|
|
455
|
+
raw = await k._granularDoc([layerScope, kind, name, layerTenant ?? ""]);
|
|
456
|
+
}
|
|
457
|
+
catch (e) {
|
|
458
|
+
// A parent/catalog scope in the chain may not exist on this source
|
|
459
|
+
// (e.g. a `_lib` library scope absent in a bare checkout). Treat it
|
|
460
|
+
// as "no contribution at this layer" — the same fail-soft the
|
|
461
|
+
// instance builder applies — instead of crashing the whole resolve.
|
|
462
|
+
// (Matches Py resolve_document's FileNotFoundError guard.)
|
|
463
|
+
if (e instanceof Error && /Scope not found/.test(e.message)) {
|
|
464
|
+
raw = null;
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
throw e;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
454
470
|
// NOTE: the Py twin registers `_layer_observers` reverse-deps here
|
|
455
471
|
// (cache invalidation infra). Intentionally not ported — the TS
|
|
456
472
|
// kernel has no granular cache to invalidate.
|
package/dist/kernel/index.d.ts
CHANGED
|
@@ -55,6 +55,18 @@ export declare const MODEL_REGISTRY_SCOPE = "_lib";
|
|
|
55
55
|
* 1:1 parity with Python `Kernel._VOICE_POLICY_SCOPE`.
|
|
56
56
|
*/
|
|
57
57
|
export declare const VOICE_POLICY_SCOPE = "_lib";
|
|
58
|
+
/**
|
|
59
|
+
* The scope that owns the canonical Tier (DNA Cloud pricing) registry.
|
|
60
|
+
* GLOBAL like ModelProfile — queried directly regardless of the caller's
|
|
61
|
+
* scope. 1:1 parity with Python `RegistryAccessor._TIER_REGISTRY_SCOPE`.
|
|
62
|
+
*/
|
|
63
|
+
export declare const TIER_REGISTRY_SCOPE = "_lib";
|
|
64
|
+
/**
|
|
65
|
+
* The scope that owns the canonical TenantPlan (tenant→Tier assignment)
|
|
66
|
+
* registry. GLOBAL like Tier — queried directly regardless of the caller's
|
|
67
|
+
* scope. 1:1 parity with Python `RegistryAccessor._TENANT_PLAN_REGISTRY_SCOPE`.
|
|
68
|
+
*/
|
|
69
|
+
export declare const TENANT_PLAN_REGISTRY_SCOPE = "_lib";
|
|
58
70
|
export declare class Kernel {
|
|
59
71
|
private static readonly _BOOTSTRAP_KINDS;
|
|
60
72
|
private static readonly _LEGACY_NON_INHERITABLE;
|
|
@@ -181,6 +193,12 @@ export declare class Kernel {
|
|
|
181
193
|
* `WritePipeline.validateKindWriter` (Fase 2,
|
|
182
194
|
* s-kernel-decomp-f2-writepipeline). */
|
|
183
195
|
_validateKindWriter(spec: Record<string, unknown>): void;
|
|
196
|
+
/** Validate `raw.spec` against the Kind's declared JSON Schema — the SAME
|
|
197
|
+
* check writeDocument enforces on the write path, exposed as a public
|
|
198
|
+
* pre-flight so read-only callers catch a schema-violating doc BEFORE the
|
|
199
|
+
* write (i-validation-shallow). Throws SpecValidationError on violation,
|
|
200
|
+
* honouring DNA_WRITE_VALIDATION. Twin of Python Kernel.validate_document. */
|
|
201
|
+
validateDocument(scope: string, kind: string, name: string, raw: Record<string, unknown>, apiVersion?: string): void;
|
|
184
202
|
/** All registered KindPorts. Order matches registration. Facade over
|
|
185
203
|
* `this._kindreg.allPorts()` (Fase 3). */
|
|
186
204
|
kindPorts(): KindPort[];
|
|
@@ -611,6 +629,38 @@ export declare class Kernel {
|
|
|
611
629
|
* @returns The matching Document, or null on miss or error.
|
|
612
630
|
*/
|
|
613
631
|
modelProfile(modelIdOrAlias: string): Promise<import("./document.js").Document | null>;
|
|
632
|
+
/**
|
|
633
|
+
* Resolve a Tier (DNA Cloud pricing plan) from the `_lib` scope by
|
|
634
|
+
* `tier_id` (pass 1) or `aliases[]` (pass 2). Returns the matching
|
|
635
|
+
* Document or null on miss.
|
|
636
|
+
*
|
|
637
|
+
* Always queries `TIER_REGISTRY_SCOPE` ("_lib") directly — Tier is GLOBAL
|
|
638
|
+
* and NOT in `INHERITABLE_KINDS`; any caller scope is irrelevant. The
|
|
639
|
+
* quota enforcer reads the caps from here — never hardcode calls_per_day /
|
|
640
|
+
* rate_per_sec / max_tenants in code.
|
|
641
|
+
*
|
|
642
|
+
* 1:1 parity with Python `Kernel.tier(tier_id_or_alias)`.
|
|
643
|
+
*
|
|
644
|
+
* @param idOrAlias - The tier_id string or an alias declared on the tier.
|
|
645
|
+
* @returns The matching Document, or null on miss or error.
|
|
646
|
+
*/
|
|
647
|
+
tier(idOrAlias: string): Promise<import("./document.js").Document | null>;
|
|
648
|
+
/**
|
|
649
|
+
* Resolve a TenantPlan (a tenant→Tier assignment) from the `_lib` scope by
|
|
650
|
+
* `spec.tenant`. Returns the matching Document or null when no assignment
|
|
651
|
+
* exists for `tenant`.
|
|
652
|
+
*
|
|
653
|
+
* Always queries `TENANT_PLAN_REGISTRY_SCOPE` ("_lib") directly — TenantPlan
|
|
654
|
+
* is GLOBAL and NOT in `INHERITABLE_KINDS`; any caller scope is irrelevant.
|
|
655
|
+
* The billing→enforcement bridge: dna-cloud's Stripe webhook writes the doc;
|
|
656
|
+
* the SDK only reads it here. No alias pass — the match is on `tenant`.
|
|
657
|
+
*
|
|
658
|
+
* 1:1 parity with Python `Kernel.tenant_plan(tenant)`.
|
|
659
|
+
*
|
|
660
|
+
* @param tenant - The DNA tenant to resolve the plan assignment for.
|
|
661
|
+
* @returns The matching Document, or null on miss or error.
|
|
662
|
+
*/
|
|
663
|
+
tenantPlan(tenant: string): Promise<import("./document.js").Document | null>;
|
|
614
664
|
/**
|
|
615
665
|
* Resolve a VoicePolicy from the `_lib` scope by metadata name.
|
|
616
666
|
* Returns the matching Document, the first policy as a fallback, or null
|
package/dist/kernel/index.js
CHANGED
|
@@ -59,6 +59,18 @@ export const MODEL_REGISTRY_SCOPE = SYSTEM_SCOPE;
|
|
|
59
59
|
* 1:1 parity with Python `Kernel._VOICE_POLICY_SCOPE`.
|
|
60
60
|
*/
|
|
61
61
|
export const VOICE_POLICY_SCOPE = SYSTEM_SCOPE;
|
|
62
|
+
/**
|
|
63
|
+
* The scope that owns the canonical Tier (DNA Cloud pricing) registry.
|
|
64
|
+
* GLOBAL like ModelProfile — queried directly regardless of the caller's
|
|
65
|
+
* scope. 1:1 parity with Python `RegistryAccessor._TIER_REGISTRY_SCOPE`.
|
|
66
|
+
*/
|
|
67
|
+
export const TIER_REGISTRY_SCOPE = SYSTEM_SCOPE;
|
|
68
|
+
/**
|
|
69
|
+
* The scope that owns the canonical TenantPlan (tenant→Tier assignment)
|
|
70
|
+
* registry. GLOBAL like Tier — queried directly regardless of the caller's
|
|
71
|
+
* scope. 1:1 parity with Python `RegistryAccessor._TENANT_PLAN_REGISTRY_SCOPE`.
|
|
72
|
+
*/
|
|
73
|
+
export const TENANT_PLAN_REGISTRY_SCOPE = SYSTEM_SCOPE;
|
|
62
74
|
export class Kernel {
|
|
63
75
|
// ── Kind classification — DERIVED from KindPort attributes ──────────────
|
|
64
76
|
// s-kernel-kindport-classification-attrs: the kernel no longer hardcodes
|
|
@@ -242,6 +254,19 @@ export class Kernel {
|
|
|
242
254
|
_validateKindWriter(spec) {
|
|
243
255
|
this._writePipeline.validateKindWriter(spec);
|
|
244
256
|
}
|
|
257
|
+
/** Validate `raw.spec` against the Kind's declared JSON Schema — the SAME
|
|
258
|
+
* check writeDocument enforces on the write path, exposed as a public
|
|
259
|
+
* pre-flight so read-only callers catch a schema-violating doc BEFORE the
|
|
260
|
+
* write (i-validation-shallow). Throws SpecValidationError on violation,
|
|
261
|
+
* honouring DNA_WRITE_VALIDATION. Twin of Python Kernel.validate_document. */
|
|
262
|
+
validateDocument(scope, kind, name, raw, apiVersion) {
|
|
263
|
+
const api = apiVersion ??
|
|
264
|
+
(typeof raw === "object" && raw !== null
|
|
265
|
+
? raw.apiVersion
|
|
266
|
+
: undefined);
|
|
267
|
+
const port = this._kindPortFor(kind, api);
|
|
268
|
+
this._writePipeline.validateSpecSchema(scope, kind, name, raw, port);
|
|
269
|
+
}
|
|
245
270
|
/** All registered KindPorts. Order matches registration. Facade over
|
|
246
271
|
* `this._kindreg.allPorts()` (Fase 3). */
|
|
247
272
|
kindPorts() {
|
|
@@ -1610,6 +1635,79 @@ export class Kernel {
|
|
|
1610
1635
|
}
|
|
1611
1636
|
return null;
|
|
1612
1637
|
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Resolve a Tier (DNA Cloud pricing plan) from the `_lib` scope by
|
|
1640
|
+
* `tier_id` (pass 1) or `aliases[]` (pass 2). Returns the matching
|
|
1641
|
+
* Document or null on miss.
|
|
1642
|
+
*
|
|
1643
|
+
* Always queries `TIER_REGISTRY_SCOPE` ("_lib") directly — Tier is GLOBAL
|
|
1644
|
+
* and NOT in `INHERITABLE_KINDS`; any caller scope is irrelevant. The
|
|
1645
|
+
* quota enforcer reads the caps from here — never hardcode calls_per_day /
|
|
1646
|
+
* rate_per_sec / max_tenants in code.
|
|
1647
|
+
*
|
|
1648
|
+
* 1:1 parity with Python `Kernel.tier(tier_id_or_alias)`.
|
|
1649
|
+
*
|
|
1650
|
+
* @param idOrAlias - The tier_id string or an alias declared on the tier.
|
|
1651
|
+
* @returns The matching Document, or null on miss or error.
|
|
1652
|
+
*/
|
|
1653
|
+
async tier(idOrAlias) {
|
|
1654
|
+
let rows;
|
|
1655
|
+
try {
|
|
1656
|
+
const mi = await this.instance(TIER_REGISTRY_SCOPE);
|
|
1657
|
+
rows = mi._all("Tier");
|
|
1658
|
+
}
|
|
1659
|
+
catch {
|
|
1660
|
+
return null;
|
|
1661
|
+
}
|
|
1662
|
+
// Pass 1: exact tier_id match
|
|
1663
|
+
for (const row of rows) {
|
|
1664
|
+
const spec = (row.spec ?? {});
|
|
1665
|
+
if (spec.tier_id === idOrAlias) {
|
|
1666
|
+
return row;
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
// Pass 2: aliases[]
|
|
1670
|
+
for (const row of rows) {
|
|
1671
|
+
const spec = (row.spec ?? {});
|
|
1672
|
+
const aliases = (spec.aliases ?? []);
|
|
1673
|
+
if (aliases.includes(idOrAlias)) {
|
|
1674
|
+
return row;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
return null;
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* Resolve a TenantPlan (a tenant→Tier assignment) from the `_lib` scope by
|
|
1681
|
+
* `spec.tenant`. Returns the matching Document or null when no assignment
|
|
1682
|
+
* exists for `tenant`.
|
|
1683
|
+
*
|
|
1684
|
+
* Always queries `TENANT_PLAN_REGISTRY_SCOPE` ("_lib") directly — TenantPlan
|
|
1685
|
+
* is GLOBAL and NOT in `INHERITABLE_KINDS`; any caller scope is irrelevant.
|
|
1686
|
+
* The billing→enforcement bridge: dna-cloud's Stripe webhook writes the doc;
|
|
1687
|
+
* the SDK only reads it here. No alias pass — the match is on `tenant`.
|
|
1688
|
+
*
|
|
1689
|
+
* 1:1 parity with Python `Kernel.tenant_plan(tenant)`.
|
|
1690
|
+
*
|
|
1691
|
+
* @param tenant - The DNA tenant to resolve the plan assignment for.
|
|
1692
|
+
* @returns The matching Document, or null on miss or error.
|
|
1693
|
+
*/
|
|
1694
|
+
async tenantPlan(tenant) {
|
|
1695
|
+
let rows;
|
|
1696
|
+
try {
|
|
1697
|
+
const mi = await this.instance(TENANT_PLAN_REGISTRY_SCOPE);
|
|
1698
|
+
rows = mi._all("TenantPlan");
|
|
1699
|
+
}
|
|
1700
|
+
catch {
|
|
1701
|
+
return null;
|
|
1702
|
+
}
|
|
1703
|
+
for (const row of rows) {
|
|
1704
|
+
const spec = (row.spec ?? {});
|
|
1705
|
+
if (spec.tenant === tenant) {
|
|
1706
|
+
return row;
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
return null;
|
|
1710
|
+
}
|
|
1613
1711
|
/**
|
|
1614
1712
|
* Resolve a VoicePolicy from the `_lib` scope by metadata name.
|
|
1615
1713
|
* Returns the matching Document, the first policy as a fallback, or null
|
|
@@ -16,6 +16,7 @@ import type { CompositionResult, KindPort, SourcePort } from "./protocols.js";
|
|
|
16
16
|
import type { CompositionProfile } from "./composition-resolver.js";
|
|
17
17
|
import type { PreviewBlock } from "./preview.js";
|
|
18
18
|
import { PromptBuilder } from "./prompt-builder.js";
|
|
19
|
+
import type { ExplainOpts, PromptExplanation } from "./prompt-builder.js";
|
|
19
20
|
import { CompositionEngine } from "./composition-resolver.js";
|
|
20
21
|
import { Navigator } from "./navigator.js";
|
|
21
22
|
import { LockManager } from "./lock-manager.js";
|
|
@@ -199,6 +200,13 @@ export declare class ManifestInstance {
|
|
|
199
200
|
*/
|
|
200
201
|
ref(value: string): Promise<string>;
|
|
201
202
|
buildPrompt(opts?: BuildPromptOpts): Promise<string>;
|
|
203
|
+
/**
|
|
204
|
+
* Compose the agent AND return per-section provenance. The `prompt` field is
|
|
205
|
+
* byte-identical to {@link buildPrompt}; `sections` attributes each composed
|
|
206
|
+
* section (instruction, soul, skills, guardrails) to its source artifact,
|
|
207
|
+
* hash, version, and layer/overlay origin. See {@link PromptBuilder.explain}.
|
|
208
|
+
*/
|
|
209
|
+
explainPrompt(opts?: ExplainOpts): Promise<PromptExplanation>;
|
|
202
210
|
resolve(layers?: Record<string, string>): ManifestInstance;
|
|
203
211
|
generateLock(): Lockfile;
|
|
204
212
|
/** Auto-register Hook documents on the kernel's HookRegistry. */
|
package/dist/kernel/instance.js
CHANGED
|
@@ -351,6 +351,15 @@ export class ManifestInstance {
|
|
|
351
351
|
async buildPrompt(opts) {
|
|
352
352
|
return this.prompt.build(opts);
|
|
353
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* Compose the agent AND return per-section provenance. The `prompt` field is
|
|
356
|
+
* byte-identical to {@link buildPrompt}; `sections` attributes each composed
|
|
357
|
+
* section (instruction, soul, skills, guardrails) to its source artifact,
|
|
358
|
+
* hash, version, and layer/overlay origin. See {@link PromptBuilder.explain}.
|
|
359
|
+
*/
|
|
360
|
+
async explainPrompt(opts) {
|
|
361
|
+
return this.prompt.explain(opts);
|
|
362
|
+
}
|
|
354
363
|
// -- Layers ---------------------------------------------------------------
|
|
355
364
|
resolve(layers) {
|
|
356
365
|
if (!layers)
|
|
@@ -54,6 +54,16 @@ export declare const SCHEMA_ANNOTATION_FORMATS: readonly string[];
|
|
|
54
54
|
* goes through here so options stay in one place. strict:false accepts the
|
|
55
55
|
* lenient JSON Schema shapes users author in YAML. */
|
|
56
56
|
export declare function createAjv(): Ajv;
|
|
57
|
+
/** Normalize a spec for hashing: drop volatile + transport fields and fold a
|
|
58
|
+
* resolved instruction_file into its inline body (s-sync-s1). Shared by
|
|
59
|
+
* KindBase and DeclarativeKindPort so both digest identically — never a second
|
|
60
|
+
* copy. Twin of Python KindBase._canonical_spec. */
|
|
61
|
+
export declare function canonicalSpecOf(volatileSpecFields: ReadonlySet<string>, spec: Record<string, unknown>): Record<string, unknown>;
|
|
62
|
+
/** Stable SHA-256 of a doc's authored identity — the source diff/sync basis
|
|
63
|
+
* (s-sync-s1). Invariant to key order, formatting, volatile stamps, and
|
|
64
|
+
* instruction_file-vs-inline; sensitive to real content. Twin of Python
|
|
65
|
+
* KindBase.canonical_digest. */
|
|
66
|
+
export declare function canonicalDigestOf(kind: string, volatileSpecFields: ReadonlySet<string>, doc: Document): string;
|
|
57
67
|
export declare abstract class KindBase implements Omit<KindPort, "apiVersion" | "kind" | "alias" | "storage"> {
|
|
58
68
|
readonly origin?: string;
|
|
59
69
|
readonly isPromptTarget: boolean;
|
package/dist/kernel/kind_base.js
CHANGED
|
@@ -83,6 +83,36 @@ function _stableStringify(value) {
|
|
|
83
83
|
keys.map((k) => JSON.stringify(k) + ":" + _stableStringify(obj[k])).join(",") +
|
|
84
84
|
"}");
|
|
85
85
|
}
|
|
86
|
+
/** Normalize a spec for hashing: drop volatile + transport fields and fold a
|
|
87
|
+
* resolved instruction_file into its inline body (s-sync-s1). Shared by
|
|
88
|
+
* KindBase and DeclarativeKindPort so both digest identically — never a second
|
|
89
|
+
* copy. Twin of Python KindBase._canonical_spec. */
|
|
90
|
+
export function canonicalSpecOf(volatileSpecFields, spec) {
|
|
91
|
+
const out = {};
|
|
92
|
+
for (const [k, v] of Object.entries(spec ?? {})) {
|
|
93
|
+
if (volatileSpecFields.has(k))
|
|
94
|
+
continue;
|
|
95
|
+
out[k] = v;
|
|
96
|
+
}
|
|
97
|
+
delete out["source_files"]; // pure transport, never identity
|
|
98
|
+
if (out["instruction_file"] && out["instruction"]) {
|
|
99
|
+
delete out["instruction_file"]; // file-backed == inline once resolved
|
|
100
|
+
}
|
|
101
|
+
return out;
|
|
102
|
+
}
|
|
103
|
+
/** Stable SHA-256 of a doc's authored identity — the source diff/sync basis
|
|
104
|
+
* (s-sync-s1). Invariant to key order, formatting, volatile stamps, and
|
|
105
|
+
* instruction_file-vs-inline; sensitive to real content. Twin of Python
|
|
106
|
+
* KindBase.canonical_digest. */
|
|
107
|
+
export function canonicalDigestOf(kind, volatileSpecFields, doc) {
|
|
108
|
+
const spec = (doc.spec ?? {});
|
|
109
|
+
const payload = {
|
|
110
|
+
kind: doc.kind ?? kind,
|
|
111
|
+
name: doc.name ?? null,
|
|
112
|
+
spec: canonicalSpecOf(volatileSpecFields, { ...spec }),
|
|
113
|
+
};
|
|
114
|
+
return createHash("sha256").update(_stableStringify(payload), "utf8").digest("hex");
|
|
115
|
+
}
|
|
86
116
|
export class KindBase {
|
|
87
117
|
// ---- Identity (subclasses MUST set these) -----------------------
|
|
88
118
|
// abstract apiVersion: string;
|
|
@@ -233,29 +263,17 @@ export class KindBase {
|
|
|
233
263
|
return [];
|
|
234
264
|
}
|
|
235
265
|
// ---- Source-sync digest (s-sync-s1; twin of Python canonical_digest) ----
|
|
266
|
+
// The algorithm lives in the module-level `canonicalSpecOf`/`canonicalDigestOf`
|
|
267
|
+
// helpers so DeclarativeKindPort (meta.ts) shares the SAME code instead of a
|
|
268
|
+
// divergent copy — a descriptor Kind digests byte-identically to its
|
|
269
|
+
// hand-written twin (twin of Python meta.py delegating to KindBase).
|
|
236
270
|
canonicalSpec(spec) {
|
|
237
|
-
|
|
238
|
-
for (const [k, v] of Object.entries(spec ?? {})) {
|
|
239
|
-
if (this.volatileSpecFields.has(k))
|
|
240
|
-
continue;
|
|
241
|
-
out[k] = v;
|
|
242
|
-
}
|
|
243
|
-
delete out["source_files"]; // pure transport, never identity
|
|
244
|
-
if (out["instruction_file"] && out["instruction"]) {
|
|
245
|
-
delete out["instruction_file"]; // file-backed == inline once resolved
|
|
246
|
-
}
|
|
247
|
-
return out;
|
|
271
|
+
return canonicalSpecOf(this.volatileSpecFields, spec);
|
|
248
272
|
}
|
|
249
273
|
/** Stable SHA-256 of the doc's authored identity — basis for source
|
|
250
274
|
* diff/sync. Invariant to key order, formatting, volatile stamps, and
|
|
251
275
|
* instruction_file-vs-inline; sensitive to real content. */
|
|
252
276
|
canonicalDigest(doc) {
|
|
253
|
-
|
|
254
|
-
const payload = {
|
|
255
|
-
kind: doc.kind ?? this.kind,
|
|
256
|
-
name: doc.name ?? null,
|
|
257
|
-
spec: this.canonicalSpec({ ...spec }),
|
|
258
|
-
};
|
|
259
|
-
return createHash("sha256").update(_stableStringify(payload), "utf8").digest("hex");
|
|
277
|
+
return canonicalDigestOf(this.kind, this.volatileSpecFields, doc);
|
|
260
278
|
}
|
|
261
279
|
}
|
package/dist/kernel/meta.d.ts
CHANGED
|
@@ -125,6 +125,7 @@ export declare class DeclarativeKindPort implements KindPort, DeclarativeMarker
|
|
|
125
125
|
* Required fields surface first, optional after.
|
|
126
126
|
*/
|
|
127
127
|
preview(doc: Document): PreviewBlock[];
|
|
128
|
+
canonicalDigest(doc: Document): string;
|
|
128
129
|
static fromTyped(typedDef: TypedKindDefinition): DeclarativeKindPort;
|
|
129
130
|
}
|
|
130
131
|
/**
|
package/dist/kernel/meta.js
CHANGED
|
@@ -38,7 +38,7 @@ function hslToHex(h, s, l) {
|
|
|
38
38
|
const toHex = (v) => Math.round((v + m) * 255).toString(16).padStart(2, "0");
|
|
39
39
|
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
40
40
|
}
|
|
41
|
-
import { DEFAULT_VOLATILE_SPEC_FIELDS, createAjv } from "./kind_base.js";
|
|
41
|
+
import { DEFAULT_VOLATILE_SPEC_FIELDS, canonicalDigestOf, createAjv } from "./kind_base.js";
|
|
42
42
|
import { StudioUIMetadata } from "./studio_ui.js";
|
|
43
43
|
import { SD, } from "./protocols.js";
|
|
44
44
|
/** Convert a literal YAML storage dict into a StorageDescriptor. */
|
|
@@ -714,6 +714,16 @@ export class DeclarativeKindPort {
|
|
|
714
714
|
}
|
|
715
715
|
return blocks;
|
|
716
716
|
}
|
|
717
|
+
// ---- Source-sync digest (s-sync-s1) -------------------------------------
|
|
718
|
+
// Share KindBase's canonical algorithm VERBATIM (the same `canonicalDigestOf`
|
|
719
|
+
// helper) so a descriptor (F3) Kind digests byte-identically to its
|
|
720
|
+
// hand-written twin — never a divergent second copy. `this.volatileSpecFields`
|
|
721
|
+
// (KindBase defaults ∪ descriptor extras) + `this.kind` feed it. Twin of the
|
|
722
|
+
// Python fix (meta.py delegating to KindBase); keeps the port digest-capable
|
|
723
|
+
// for a future TS source-sync path (no TS consumer exercises it today).
|
|
724
|
+
canonicalDigest(doc) {
|
|
725
|
+
return canonicalDigestOf(this.kind, this.volatileSpecFields, doc);
|
|
726
|
+
}
|
|
717
727
|
static fromTyped(typedDef) {
|
|
718
728
|
return new DeclarativeKindPort(typedDef);
|
|
719
729
|
}
|
package/dist/kernel/models.d.ts
CHANGED
|
@@ -517,9 +517,9 @@ export declare const AgentSpecSchema: z.ZodObject<{
|
|
|
517
517
|
type?: string | undefined;
|
|
518
518
|
skills?: string[] | undefined;
|
|
519
519
|
guardrails?: string[] | undefined;
|
|
520
|
-
instruction?: string | undefined;
|
|
521
520
|
promptTemplate?: string | undefined;
|
|
522
521
|
layout?: string | undefined;
|
|
522
|
+
instruction?: string | undefined;
|
|
523
523
|
model?: string | undefined;
|
|
524
524
|
instruction_file?: string | undefined;
|
|
525
525
|
tags?: string[] | undefined;
|
|
@@ -737,9 +737,9 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
737
737
|
type?: string | undefined;
|
|
738
738
|
skills?: string[] | undefined;
|
|
739
739
|
guardrails?: string[] | undefined;
|
|
740
|
-
instruction?: string | undefined;
|
|
741
740
|
promptTemplate?: string | undefined;
|
|
742
741
|
layout?: string | undefined;
|
|
742
|
+
instruction?: string | undefined;
|
|
743
743
|
model?: string | undefined;
|
|
744
744
|
instruction_file?: string | undefined;
|
|
745
745
|
tags?: string[] | undefined;
|
|
@@ -865,9 +865,9 @@ export declare const AgentSchema: z.ZodObject<{
|
|
|
865
865
|
type?: string | undefined;
|
|
866
866
|
skills?: string[] | undefined;
|
|
867
867
|
guardrails?: string[] | undefined;
|
|
868
|
-
instruction?: string | undefined;
|
|
869
868
|
promptTemplate?: string | undefined;
|
|
870
869
|
layout?: string | undefined;
|
|
870
|
+
instruction?: string | undefined;
|
|
871
871
|
model?: string | undefined;
|
|
872
872
|
instruction_file?: string | undefined;
|
|
873
873
|
tags?: string[] | undefined;
|
|
@@ -1516,15 +1516,15 @@ export declare const AgentDefinitionSchema: z.ZodObject<{
|
|
|
1516
1516
|
export type TypedAgentDefinition = z.output<typeof AgentDefinitionSchema>;
|
|
1517
1517
|
export declare const GuardrailSpecSchema: z.ZodObject<{
|
|
1518
1518
|
rules: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1519
|
-
severity: z.ZodDefault<z.ZodOptional<z.
|
|
1520
|
-
scope: z.ZodDefault<z.ZodOptional<z.
|
|
1519
|
+
severity: z.ZodDefault<z.ZodOptional<z.ZodEnum<["warn", "error", "hard"]>>>;
|
|
1520
|
+
scope: z.ZodDefault<z.ZodOptional<z.ZodEnum<["input", "output", "both"]>>>;
|
|
1521
1521
|
}, "strip", z.ZodTypeAny, {
|
|
1522
|
-
scope:
|
|
1523
|
-
severity:
|
|
1522
|
+
scope: "input" | "both" | "output";
|
|
1523
|
+
severity: "error" | "warn" | "hard";
|
|
1524
1524
|
rules: string[];
|
|
1525
1525
|
}, {
|
|
1526
|
-
scope?:
|
|
1527
|
-
severity?:
|
|
1526
|
+
scope?: "input" | "both" | "output" | undefined;
|
|
1527
|
+
severity?: "error" | "warn" | "hard" | undefined;
|
|
1528
1528
|
rules?: string[] | undefined;
|
|
1529
1529
|
}>;
|
|
1530
1530
|
export declare const GuardrailSchema: z.ZodObject<{
|
|
@@ -1554,15 +1554,15 @@ export declare const GuardrailSchema: z.ZodObject<{
|
|
|
1554
1554
|
}>;
|
|
1555
1555
|
spec: z.ZodDefault<z.ZodObject<{
|
|
1556
1556
|
rules: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
1557
|
-
severity: z.ZodDefault<z.ZodOptional<z.
|
|
1558
|
-
scope: z.ZodDefault<z.ZodOptional<z.
|
|
1557
|
+
severity: z.ZodDefault<z.ZodOptional<z.ZodEnum<["warn", "error", "hard"]>>>;
|
|
1558
|
+
scope: z.ZodDefault<z.ZodOptional<z.ZodEnum<["input", "output", "both"]>>>;
|
|
1559
1559
|
}, "strip", z.ZodTypeAny, {
|
|
1560
|
-
scope:
|
|
1561
|
-
severity:
|
|
1560
|
+
scope: "input" | "both" | "output";
|
|
1561
|
+
severity: "error" | "warn" | "hard";
|
|
1562
1562
|
rules: string[];
|
|
1563
1563
|
}, {
|
|
1564
|
-
scope?:
|
|
1565
|
-
severity?:
|
|
1564
|
+
scope?: "input" | "both" | "output" | undefined;
|
|
1565
|
+
severity?: "error" | "warn" | "hard" | undefined;
|
|
1566
1566
|
rules?: string[] | undefined;
|
|
1567
1567
|
}>>;
|
|
1568
1568
|
}, "strip", z.ZodTypeAny, {
|
|
@@ -1575,8 +1575,8 @@ export declare const GuardrailSchema: z.ZodObject<{
|
|
|
1575
1575
|
labels: Record<string, string>;
|
|
1576
1576
|
};
|
|
1577
1577
|
spec: {
|
|
1578
|
-
scope:
|
|
1579
|
-
severity:
|
|
1578
|
+
scope: "input" | "both" | "output";
|
|
1579
|
+
severity: "error" | "warn" | "hard";
|
|
1580
1580
|
rules: string[];
|
|
1581
1581
|
};
|
|
1582
1582
|
apiVersion: "github.com/ruinosus/dna/v1";
|
|
@@ -1593,8 +1593,8 @@ export declare const GuardrailSchema: z.ZodObject<{
|
|
|
1593
1593
|
apiVersion: "github.com/ruinosus/dna/v1";
|
|
1594
1594
|
kind: "Guardrail";
|
|
1595
1595
|
spec?: {
|
|
1596
|
-
scope?:
|
|
1597
|
-
severity?:
|
|
1596
|
+
scope?: "input" | "both" | "output" | undefined;
|
|
1597
|
+
severity?: "error" | "warn" | "hard" | undefined;
|
|
1598
1598
|
rules?: string[] | undefined;
|
|
1599
1599
|
} | undefined;
|
|
1600
1600
|
}>;
|
|
@@ -1634,9 +1634,9 @@ export declare const KindDefinitionSpecSchema: z.ZodObject<{
|
|
|
1634
1634
|
description_fallback_field: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1635
1635
|
}, "strip", z.ZodTypeAny, {
|
|
1636
1636
|
origin: string;
|
|
1637
|
+
alias: string;
|
|
1637
1638
|
is_root: boolean;
|
|
1638
1639
|
flatten_in_context: boolean;
|
|
1639
|
-
alias: string;
|
|
1640
1640
|
storage: Record<string, unknown>;
|
|
1641
1641
|
plane: "composition" | "record";
|
|
1642
1642
|
schema: Record<string, unknown>;
|
|
@@ -1753,9 +1753,9 @@ export declare const KindDefinitionSchema: z.ZodObject<{
|
|
|
1753
1753
|
description_fallback_field: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
1754
1754
|
}, "strip", z.ZodTypeAny, {
|
|
1755
1755
|
origin: string;
|
|
1756
|
+
alias: string;
|
|
1756
1757
|
is_root: boolean;
|
|
1757
1758
|
flatten_in_context: boolean;
|
|
1758
|
-
alias: string;
|
|
1759
1759
|
storage: Record<string, unknown>;
|
|
1760
1760
|
plane: "composition" | "record";
|
|
1761
1761
|
schema: Record<string, unknown>;
|
|
@@ -1818,9 +1818,9 @@ export declare const KindDefinitionSchema: z.ZodObject<{
|
|
|
1818
1818
|
tenant_scope_declared: boolean;
|
|
1819
1819
|
summary: Record<string, unknown> | null;
|
|
1820
1820
|
origin: string;
|
|
1821
|
+
alias: string;
|
|
1821
1822
|
is_root: boolean;
|
|
1822
1823
|
flatten_in_context: boolean;
|
|
1823
|
-
alias: string;
|
|
1824
1824
|
storage: Record<string, unknown>;
|
|
1825
1825
|
plane: "composition" | "record";
|
|
1826
1826
|
schema: Record<string, unknown>;
|
|
@@ -1891,9 +1891,9 @@ export declare const KindDefinitionSchema: z.ZodObject<{
|
|
|
1891
1891
|
tenant_scope_declared: boolean;
|
|
1892
1892
|
summary: Record<string, unknown> | null;
|
|
1893
1893
|
origin: string;
|
|
1894
|
+
alias: string;
|
|
1894
1895
|
is_root: boolean;
|
|
1895
1896
|
flatten_in_context: boolean;
|
|
1896
|
-
alias: string;
|
|
1897
1897
|
storage: Record<string, unknown>;
|
|
1898
1898
|
plane: "composition" | "record";
|
|
1899
1899
|
schema: Record<string, unknown>;
|
package/dist/kernel/models.js
CHANGED
|
@@ -396,8 +396,14 @@ export const AgentDefinitionSchema = z.object({
|
|
|
396
396
|
// ---------------------------------------------------------------------------
|
|
397
397
|
export const GuardrailSpecSchema = z.object({
|
|
398
398
|
rules: z.array(z.string()).default([]),
|
|
399
|
-
severity
|
|
400
|
-
|
|
399
|
+
// Constrained fields — the documented severity/scope contracts. Typed as
|
|
400
|
+
// z.enum so zodSpecToJsonSchema emits `{type:"string", enum:[...]}`
|
|
401
|
+
// (i-validation-shallow): a bare z.string() degraded to `{type:"string"}` and
|
|
402
|
+
// accepted `severity: critical`/garbage on the write path. Parity: the Python
|
|
403
|
+
// twin's GuardrailSpec uses Literal[...] → the same enum shape. warn lets the
|
|
404
|
+
// turn continue; error fails the turn; hard refuses to answer.
|
|
405
|
+
severity: z.enum(["warn", "error", "hard"]).optional().default("warn"),
|
|
406
|
+
scope: z.enum(["input", "output", "both"]).optional().default("both"),
|
|
401
407
|
});
|
|
402
408
|
export const GuardrailSchema = z.object({
|
|
403
409
|
apiVersion: z.literal("github.com/ruinosus/dna/v1"),
|
|
@@ -9,6 +9,41 @@
|
|
|
9
9
|
* return identical results.
|
|
10
10
|
*/
|
|
11
11
|
import type { ManifestInstance, BuildPromptOpts } from "./instance.js";
|
|
12
|
+
/** Provenance for ONE composed prompt section (instruction / soul / skill /
|
|
13
|
+
* guardrail). Reconstructed from the layout template + depFilters +
|
|
14
|
+
* flattenInContext plus the layer provenance `resolveDocument` returns — NOT
|
|
15
|
+
* by re-running composition. */
|
|
16
|
+
export interface SectionProvenance {
|
|
17
|
+
/** Label, e.g. `instruction` / `soul:warm` / `skill:greeting`. */
|
|
18
|
+
section: string;
|
|
19
|
+
/** Contributing Kind (`Agent` / `Soul` / `Skill` / `Guardrail`). */
|
|
20
|
+
kind: string;
|
|
21
|
+
/** Contributing document name. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Canonical source artifact path, e.g. `skills/greeting/SKILL.md`. */
|
|
24
|
+
source: string;
|
|
25
|
+
/** SHA-256 of the resolved (effective) raw doc, or null. */
|
|
26
|
+
hash: string | null;
|
|
27
|
+
/** `metadata.version` of the resolved doc, when the author set one. */
|
|
28
|
+
version: string | null;
|
|
29
|
+
/** Effective layer scope the section resolved from. */
|
|
30
|
+
origin: string;
|
|
31
|
+
/** True when `origin` differs from the requested scope (inherited). */
|
|
32
|
+
isInherited: boolean;
|
|
33
|
+
/** True when a TENANT overlay changed this section vs the base. */
|
|
34
|
+
overriddenByTenant: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** The composed prompt PLUS a section→provenance map. `prompt` is
|
|
37
|
+
* byte-identical to `buildPrompt` — explain mode never re-renders. */
|
|
38
|
+
export interface PromptExplanation {
|
|
39
|
+
prompt: string;
|
|
40
|
+
sections: SectionProvenance[];
|
|
41
|
+
}
|
|
42
|
+
/** Options for {@link PromptBuilder.explain}. */
|
|
43
|
+
export interface ExplainOpts extends BuildPromptOpts {
|
|
44
|
+
/** Resolve with this tenant's overlays (marks overridden sections). */
|
|
45
|
+
tenant?: string | null;
|
|
46
|
+
}
|
|
12
47
|
export declare class PromptBuilder {
|
|
13
48
|
private host;
|
|
14
49
|
constructor(host: ManifestInstance);
|
|
@@ -17,6 +52,35 @@ export declare class PromptBuilder {
|
|
|
17
52
|
* Equivalent to `mi.buildPrompt(opts)`.
|
|
18
53
|
*/
|
|
19
54
|
build(opts?: BuildPromptOpts): Promise<string>;
|
|
55
|
+
/**
|
|
56
|
+
* Compose the agent AND return per-section provenance.
|
|
57
|
+
*
|
|
58
|
+
* Returns the composed prompt (byte-identical to {@link build} — explain
|
|
59
|
+
* mode never re-renders) plus a section→provenance map: the source artifact,
|
|
60
|
+
* content hash, version, and layer/overlay origin of each declared
|
|
61
|
+
* composition input (instruction, soul, skills, guardrails). Provenance is
|
|
62
|
+
* reconstructed from the kernel's own declared blocks (layout template +
|
|
63
|
+
* depFilters + flattenInContext) + the layer provenance `resolveDocument`
|
|
64
|
+
* already returns. 1:1 with Python `PromptBuilder.explain`.
|
|
65
|
+
*/
|
|
66
|
+
explain(opts?: ExplainOpts): Promise<PromptExplanation>;
|
|
67
|
+
private _defaultAgentName;
|
|
68
|
+
private _mergeSlots;
|
|
69
|
+
private _effectiveTemplate;
|
|
70
|
+
private _kpByAlias;
|
|
71
|
+
/**
|
|
72
|
+
* Reconstruct the ordered composition inputs → `[label, kp, name]`. A
|
|
73
|
+
* depFilter field contributes a section iff the layout actually renders it —
|
|
74
|
+
* a flatten Kind whose flatten var appears in the template (Soul →
|
|
75
|
+
* soul_content) or a Kind whose alias appears as a Mustache section
|
|
76
|
+
* (Skill/Guardrail). Non-prompt deps (tools, actors) fall out.
|
|
77
|
+
*/
|
|
78
|
+
private _sectionSpecs;
|
|
79
|
+
private _contributesToPrompt;
|
|
80
|
+
private _resolve;
|
|
81
|
+
private static _docHash;
|
|
82
|
+
private _sectionProvenance;
|
|
83
|
+
private static _sourcePath;
|
|
20
84
|
private _findAgent;
|
|
21
85
|
private _buildContext;
|
|
22
86
|
private _renderPrompt;
|