@duckcodeailabs/dql-agent 1.10.0 → 1.10.2
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/agent-run-engine.d.ts.map +1 -1
- package/dist/agent-run-engine.js +6 -1
- package/dist/agent-run-engine.js.map +1 -1
- package/dist/analytical-compatibility.d.ts +61 -0
- package/dist/analytical-compatibility.d.ts.map +1 -0
- package/dist/analytical-compatibility.js +515 -0
- package/dist/analytical-compatibility.js.map +1 -0
- package/dist/analytical-execution-graph.d.ts +174 -0
- package/dist/analytical-execution-graph.d.ts.map +1 -0
- package/dist/analytical-execution-graph.js +599 -0
- package/dist/analytical-execution-graph.js.map +1 -0
- package/dist/analytical-failure-repair.d.ts +91 -0
- package/dist/analytical-failure-repair.d.ts.map +1 -0
- package/dist/analytical-failure-repair.js +325 -0
- package/dist/analytical-failure-repair.js.map +1 -0
- package/dist/analytical-frame.d.ts +19 -0
- package/dist/analytical-frame.d.ts.map +1 -0
- package/dist/analytical-frame.js +299 -0
- package/dist/analytical-frame.js.map +1 -0
- package/dist/analytical-period-resolution.d.ts +53 -0
- package/dist/analytical-period-resolution.d.ts.map +1 -0
- package/dist/analytical-period-resolution.js +218 -0
- package/dist/analytical-period-resolution.js.map +1 -0
- package/dist/analytical-readiness.d.ts +17 -0
- package/dist/analytical-readiness.d.ts.map +1 -0
- package/dist/analytical-readiness.js +95 -0
- package/dist/analytical-readiness.js.map +1 -0
- package/dist/analytical-result-facts.d.ts +79 -0
- package/dist/analytical-result-facts.d.ts.map +1 -0
- package/dist/analytical-result-facts.js +301 -0
- package/dist/analytical-result-facts.js.map +1 -0
- package/dist/answer-loop.d.ts +51 -4
- package/dist/answer-loop.d.ts.map +1 -1
- package/dist/answer-loop.js +866 -35
- package/dist/answer-loop.js.map +1 -1
- package/dist/governed-relational-compiler.d.ts +51 -0
- package/dist/governed-relational-compiler.d.ts.map +1 -1
- package/dist/governed-relational-compiler.js +144 -1
- package/dist/governed-relational-compiler.js.map +1 -1
- package/dist/index.d.ts +16 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/kg/build.d.ts +2 -2
- package/dist/kg/build.d.ts.map +1 -1
- package/dist/kg/build.js +270 -13
- package/dist/kg/build.js.map +1 -1
- package/dist/meaning-resolution.d.ts +13 -0
- package/dist/meaning-resolution.d.ts.map +1 -1
- package/dist/meaning-resolution.js +69 -0
- package/dist/meaning-resolution.js.map +1 -1
- package/dist/metadata/analysis-planner.js +3 -1
- package/dist/metadata/analysis-planner.js.map +1 -1
- package/dist/metadata/catalog.d.ts +4 -2
- package/dist/metadata/catalog.d.ts.map +1 -1
- package/dist/metadata/catalog.js +264 -9
- package/dist/metadata/catalog.js.map +1 -1
- package/dist/metadata/meaning-evidence.d.ts +9 -2
- package/dist/metadata/meaning-evidence.d.ts.map +1 -1
- package/dist/metadata/meaning-evidence.js +105 -7
- package/dist/metadata/meaning-evidence.js.map +1 -1
- package/dist/plan-execution-adapter.d.ts +72 -1
- package/dist/plan-execution-adapter.d.ts.map +1 -1
- package/dist/plan-execution-adapter.js +208 -0
- package/dist/plan-execution-adapter.js.map +1 -1
- package/dist/resolved-analytical-plan.d.ts +14 -3
- package/dist/resolved-analytical-plan.d.ts.map +1 -1
- package/dist/resolved-analytical-plan.js +74 -20
- package/dist/resolved-analytical-plan.js.map +1 -1
- package/dist/router.d.ts +1 -1
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +167 -21
- package/dist/router.js.map +1 -1
- package/dist/semantic-bridge/compose.d.ts +1 -1
- package/dist/semantic-bridge/compose.d.ts.map +1 -1
- package/dist/semantic-bridge/compose.js +27 -5
- package/dist/semantic-bridge/compose.js.map +1 -1
- package/dist/semantic-bridge/member-select.d.ts +1 -1
- package/dist/semantic-bridge/member-select.d.ts.map +1 -1
- package/dist/semantic-bridge/member-select.js +32 -12
- package/dist/semantic-bridge/member-select.js.map +1 -1
- package/dist/skills/loader.d.ts +17 -0
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +62 -4
- package/dist/skills/loader.js.map +1 -1
- package/package.json +4 -4
package/dist/metadata/catalog.js
CHANGED
|
@@ -11,10 +11,10 @@ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync
|
|
|
11
11
|
import { createRequire } from 'node:module';
|
|
12
12
|
import { dirname, join } from 'node:path';
|
|
13
13
|
import { brotliCompressSync, brotliDecompressSync, constants as zlibConstants } from 'node:zlib';
|
|
14
|
-
import { buildManifest, buildManifestKnowledgeGraph, loadDomainPackageRegistry, loadManifestKnowledgeSkills, loadProjectConfig, parseContractRef, resolveDataLexManifestPath, resolveDbtManifestPath, resolveSemanticLayerWithDiagnostics, extractColumnLineage, normalizeDqlArtifactReference, composeEffectiveTrust, } from
|
|
15
|
-
import { buildKGFromManifest, buildKGFromSemanticLayer } from
|
|
16
|
-
import { domainContextSearchDomains } from
|
|
17
|
-
import { buildBlockBusinessFingerprint, buildBlockSqlFingerprints } from
|
|
14
|
+
import { buildManifest, buildManifestKnowledgeGraph, loadDomainPackageRegistry, loadManifestKnowledgeSkills, loadProjectConfig, parseContractRef, resolveDataLexManifestPath, resolveDbtManifestPath, resolveSemanticLayerWithDiagnostics, extractColumnLineage, normalizeDqlArtifactReference, composeEffectiveTrust, normalizeMetricCapabilityContract, } from "@duckcodeailabs/dql-core";
|
|
15
|
+
import { buildKGFromManifest, buildKGFromSemanticLayer } from "../kg/build.js";
|
|
16
|
+
import { domainContextSearchDomains, } from "../domain-context.js";
|
|
17
|
+
import { buildBlockBusinessFingerprint, buildBlockSqlFingerprints, } from "./block-fingerprints.js";
|
|
18
18
|
import { buildAnalysisQuestionPlan, certifiedApplicabilityForObject, scoreAllowedSqlRelationWithAnalysisPlan, scoreMetadataObjectWithAnalysisPlan, sortAllowedSqlContextForAnalysisPlan, } from './analysis-planner.js';
|
|
19
19
|
import { extractSimpleSelectShape, sourceSqlShapeColumns } from './sql-shape.js';
|
|
20
20
|
import { grainMatches, requestedGrainFromPlan, } from './grain-gate.js';
|
|
@@ -835,6 +835,7 @@ export function buildMetadataSnapshot(projectRoot, manifest, semanticLayer, skil
|
|
|
835
835
|
addRawDbtManifestCatalogObjects(projectRoot, manifest, objects, edges, diagnostics);
|
|
836
836
|
addBlockDependencyEdges(manifest, edges);
|
|
837
837
|
addBlockOutputLineageObjects(manifest, objects, edges);
|
|
838
|
+
addCertifiedBlockAnalyticalCapabilities(objects);
|
|
838
839
|
// Manifest v3 is the unified DQL runtime. DataLex is migration input only;
|
|
839
840
|
// retaining it here would reintroduce a second analytical source of truth.
|
|
840
841
|
if (manifest.manifestVersion !== 3) {
|
|
@@ -878,6 +879,205 @@ export function buildMetadataSnapshot(projectRoot, manifest, semanticLayer, skil
|
|
|
878
879
|
snapshot.fingerprint = fingerprintSnapshot(snapshot);
|
|
879
880
|
return snapshot;
|
|
880
881
|
}
|
|
882
|
+
/**
|
|
883
|
+
* Upgrade only fully declared certified blocks into RFC 0005 capabilities.
|
|
884
|
+
* Local/display-name matching is intentionally insufficient: every reusable
|
|
885
|
+
* metric, grain, dimension/filter, and output role must bind exactly to the
|
|
886
|
+
* already-normalized semantic capability in this immutable snapshot.
|
|
887
|
+
*
|
|
888
|
+
* Acceptance: CONTRACT-002, AGT-018.
|
|
889
|
+
*/
|
|
890
|
+
function addCertifiedBlockAnalyticalCapabilities(objects) {
|
|
891
|
+
// Existing certified blocks can carry the pre-ID-001 domain-scoped member
|
|
892
|
+
// identities. Canonicalize those aliases only when exactly one semantic
|
|
893
|
+
// object owns them; repeated leaf aliases intentionally fail closed.
|
|
894
|
+
const semanticIdentityTargets = new Map();
|
|
895
|
+
for (const object of objects.values()) {
|
|
896
|
+
if (!object.objectType.startsWith('semantic_'))
|
|
897
|
+
continue;
|
|
898
|
+
const payload = object.payload ?? {};
|
|
899
|
+
const canonicalIdentity = object.fullName ?? object.name;
|
|
900
|
+
for (const identity of uniqueNonBlank([
|
|
901
|
+
canonicalIdentity,
|
|
902
|
+
stringValue(payload.qualifiedId),
|
|
903
|
+
stringValue(payload.registryQualifiedId),
|
|
904
|
+
stringValue(payload.sourceNativeId),
|
|
905
|
+
...metadataStringArray(payload.aliases),
|
|
906
|
+
])) {
|
|
907
|
+
const targets = semanticIdentityTargets.get(identity) ?? new Set();
|
|
908
|
+
targets.add(canonicalIdentity);
|
|
909
|
+
semanticIdentityTargets.set(identity, targets);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
const canonicalizeSemanticRef = (identity) => {
|
|
913
|
+
const targets = semanticIdentityTargets.get(identity);
|
|
914
|
+
if (!targets)
|
|
915
|
+
return identity;
|
|
916
|
+
return targets.size === 1 ? [...targets][0] : undefined;
|
|
917
|
+
};
|
|
918
|
+
const semanticCapabilities = [...objects.values()].flatMap((object) => {
|
|
919
|
+
if (object.objectType !== "semantic_metric")
|
|
920
|
+
return [];
|
|
921
|
+
const capability = normalizeMetricCapabilityContract(object.payload?.analyticalCapability);
|
|
922
|
+
if (!capability)
|
|
923
|
+
return [];
|
|
924
|
+
const payload = object.payload ?? {};
|
|
925
|
+
return [
|
|
926
|
+
{
|
|
927
|
+
object,
|
|
928
|
+
capability,
|
|
929
|
+
exactRefs: new Set(uniqueNonBlank([
|
|
930
|
+
capability.metricId,
|
|
931
|
+
object.objectKey,
|
|
932
|
+
object.fullName,
|
|
933
|
+
stringValue(payload.qualifiedId),
|
|
934
|
+
stringValue(payload.sourceNativeId),
|
|
935
|
+
...metadataStringArray(payload.aliases),
|
|
936
|
+
])),
|
|
937
|
+
},
|
|
938
|
+
];
|
|
939
|
+
});
|
|
940
|
+
for (const block of objects.values()) {
|
|
941
|
+
if (block.objectType !== "dql_block" || block.status !== "certified")
|
|
942
|
+
continue;
|
|
943
|
+
const payload = block.payload ?? {};
|
|
944
|
+
const metricRefs = uniqueNonBlank([
|
|
945
|
+
...metadataStringArray(payload.metricRefs),
|
|
946
|
+
]);
|
|
947
|
+
if (metricRefs.length !== 1)
|
|
948
|
+
continue;
|
|
949
|
+
const metrics = semanticCapabilities.filter((candidate) => candidate.exactRefs.has(metricRefs[0]));
|
|
950
|
+
if (metrics.length !== 1)
|
|
951
|
+
continue;
|
|
952
|
+
const semantic = metrics[0];
|
|
953
|
+
const authoredGrain = stringValue(payload.grain);
|
|
954
|
+
const grain = authoredGrain ? canonicalizeSemanticRef(authoredGrain) : undefined;
|
|
955
|
+
if (!grain || !semantic.capability.resultGrainIds.includes(grain))
|
|
956
|
+
continue;
|
|
957
|
+
const authoredGroupedRefs = uniqueNonBlank([
|
|
958
|
+
...metadataStringArray(payload.dimensions),
|
|
959
|
+
...metadataStringArray(payload.dimensionsRef),
|
|
960
|
+
]);
|
|
961
|
+
const authoredFilterRefs = uniqueNonBlank(metadataStringArray(payload.allowedFilters));
|
|
962
|
+
const groupedRefs = authoredGroupedRefs.map(canonicalizeSemanticRef);
|
|
963
|
+
const filterRefs = authoredFilterRefs.map(canonicalizeSemanticRef);
|
|
964
|
+
if (groupedRefs.some((ref) => !ref) || filterRefs.some((ref) => !ref))
|
|
965
|
+
continue;
|
|
966
|
+
const canonicalGroupedRefs = groupedRefs.filter((ref) => Boolean(ref));
|
|
967
|
+
const canonicalFilterRefs = filterRefs.filter((ref) => Boolean(ref));
|
|
968
|
+
const declaredRefs = new Set([...canonicalGroupedRefs, ...canonicalFilterRefs]);
|
|
969
|
+
const capabilityDimensionIds = new Set(semantic.capability.dimensions.map((item) => item.dimensionId));
|
|
970
|
+
const capabilityTimeIds = new Set(semantic.capability.timeDimensions.map((item) => item.dimensionId));
|
|
971
|
+
if ([...declaredRefs].some((id) => !capabilityDimensionIds.has(id) && !capabilityTimeIds.has(id)))
|
|
972
|
+
continue;
|
|
973
|
+
const dimensions = semantic.capability.dimensions.flatMap((dimension) => {
|
|
974
|
+
if (!declaredRefs.has(dimension.dimensionId))
|
|
975
|
+
return [];
|
|
976
|
+
const roles = dimension.supportedRoles.filter((role) => (role === "filter" && canonicalFilterRefs.includes(dimension.dimensionId)) ||
|
|
977
|
+
(role === "group_by" &&
|
|
978
|
+
canonicalGroupedRefs.includes(dimension.dimensionId)) ||
|
|
979
|
+
(role === "display" &&
|
|
980
|
+
canonicalGroupedRefs.includes(dimension.dimensionId)) ||
|
|
981
|
+
(role === "rank_entity" &&
|
|
982
|
+
payload.pattern === "ranking" &&
|
|
983
|
+
canonicalGroupedRefs.includes(dimension.dimensionId)));
|
|
984
|
+
return roles.length > 0
|
|
985
|
+
? [{ ...dimension, supportedRoles: roles }]
|
|
986
|
+
: [];
|
|
987
|
+
});
|
|
988
|
+
if ([...declaredRefs].some((id) => capabilityDimensionIds.has(id) &&
|
|
989
|
+
!dimensions.some((dimension) => dimension.dimensionId === id)))
|
|
990
|
+
continue;
|
|
991
|
+
const timeDimensions = semantic.capability.timeDimensions.filter((dimension) => declaredRefs.has(dimension.dimensionId));
|
|
992
|
+
const outputs = analyticalBlockOutputs(payload.outputContract);
|
|
993
|
+
if (!outputs ||
|
|
994
|
+
outputs.ids.length === 0 ||
|
|
995
|
+
!outputs.kinds.includes("metric_value"))
|
|
996
|
+
continue;
|
|
997
|
+
const operations = [];
|
|
998
|
+
if (canonicalFilterRefs.length > 0)
|
|
999
|
+
operations.push("filter");
|
|
1000
|
+
if (canonicalGroupedRefs.some((id) => capabilityDimensionIds.has(id)))
|
|
1001
|
+
operations.push("group");
|
|
1002
|
+
if (payload.pattern === "trend")
|
|
1003
|
+
operations.push("trend");
|
|
1004
|
+
if (payload.pattern === "ranking" && outputs.kinds.includes("rank"))
|
|
1005
|
+
operations.push("rank");
|
|
1006
|
+
if (outputs.kinds.includes("delta") ||
|
|
1007
|
+
outputs.kinds.includes("percent_delta"))
|
|
1008
|
+
operations.push("compare");
|
|
1009
|
+
const blockId = stringValue(payload.qualifiedId) ?? block.objectKey;
|
|
1010
|
+
const fingerprint = stringValue(recordPayload(payload.businessFingerprint)?.hash) ??
|
|
1011
|
+
sha256(stableStringify({
|
|
1012
|
+
blockId,
|
|
1013
|
+
metricRefs,
|
|
1014
|
+
grain,
|
|
1015
|
+
groupedRefs: canonicalGroupedRefs,
|
|
1016
|
+
filterRefs: canonicalFilterRefs,
|
|
1017
|
+
outputs,
|
|
1018
|
+
}));
|
|
1019
|
+
const capability = {
|
|
1020
|
+
...semantic.capability,
|
|
1021
|
+
defaultResultGrainId: grain,
|
|
1022
|
+
resultGrainIds: uniqueNonBlank([
|
|
1023
|
+
grain,
|
|
1024
|
+
...dimensions.map((dimension) => dimension.entityId),
|
|
1025
|
+
]),
|
|
1026
|
+
dimensions,
|
|
1027
|
+
timeDimensions,
|
|
1028
|
+
operations: [...new Set(operations)],
|
|
1029
|
+
supportedOutputKinds: outputs.kinds,
|
|
1030
|
+
declaredOutputIds: outputs.ids,
|
|
1031
|
+
executionCapabilities: [
|
|
1032
|
+
{ route: "certified", adapterId: block.objectKey },
|
|
1033
|
+
],
|
|
1034
|
+
sourceFingerprint: fingerprint.startsWith("sha256:")
|
|
1035
|
+
? fingerprint
|
|
1036
|
+
: `sha256:${fingerprint}`,
|
|
1037
|
+
};
|
|
1038
|
+
const normalized = normalizeMetricCapabilityContract(capability);
|
|
1039
|
+
if (!normalized)
|
|
1040
|
+
continue;
|
|
1041
|
+
objects.set(block.objectKey, {
|
|
1042
|
+
...block,
|
|
1043
|
+
payload: { ...payload, analyticalCapability: normalized },
|
|
1044
|
+
});
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
function analyticalBlockOutputs(value) {
|
|
1048
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
1049
|
+
return undefined;
|
|
1050
|
+
const ids = [];
|
|
1051
|
+
const kinds = [];
|
|
1052
|
+
for (const item of value) {
|
|
1053
|
+
const output = recordPayload(item);
|
|
1054
|
+
const id = stringValue(output?.name);
|
|
1055
|
+
const role = stringValue(output?.role)?.toLowerCase();
|
|
1056
|
+
if (!id || !role)
|
|
1057
|
+
return undefined;
|
|
1058
|
+
const kind = role === "metric" || role === "measure" || role === "value"
|
|
1059
|
+
? "metric_value"
|
|
1060
|
+
: role === "dimension" || role === "grain"
|
|
1061
|
+
? "dimension"
|
|
1062
|
+
: role === "rank"
|
|
1063
|
+
? "rank"
|
|
1064
|
+
: role === "delta"
|
|
1065
|
+
? "delta"
|
|
1066
|
+
: role === "percent_delta"
|
|
1067
|
+
? "percent_delta"
|
|
1068
|
+
: undefined;
|
|
1069
|
+
if (!kind)
|
|
1070
|
+
return undefined;
|
|
1071
|
+
ids.push(id);
|
|
1072
|
+
kinds.push(kind);
|
|
1073
|
+
}
|
|
1074
|
+
return { ids: uniqueNonBlank(ids), kinds: [...new Set(kinds)] };
|
|
1075
|
+
}
|
|
1076
|
+
function recordPayload(value) {
|
|
1077
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
1078
|
+
? value
|
|
1079
|
+
: undefined;
|
|
1080
|
+
}
|
|
881
1081
|
/**
|
|
882
1082
|
* Manifest graph v2 intentionally omits verbose objects and edges. Snapshot
|
|
883
1083
|
* construction rematerializes that compiler graph once, then persists the
|
|
@@ -982,8 +1182,16 @@ function addManifestKnowledgeGraph(manifest, objects, edges) {
|
|
|
982
1182
|
sourceSystem: 'DQL compiled cross-domain policy',
|
|
983
1183
|
payload: compactObject(route),
|
|
984
1184
|
});
|
|
985
|
-
addMetadataEdge(edges,
|
|
986
|
-
|
|
1185
|
+
addMetadataEdge(edges, "cross_domain_route", keyByGraphId.get(`domain::${route.providerDomainId}`) ??
|
|
1186
|
+
`domain:${route.providerDomainId}`, objectKey, {
|
|
1187
|
+
state: route.state,
|
|
1188
|
+
reasonCodes: route.reasonCodes,
|
|
1189
|
+
});
|
|
1190
|
+
addMetadataEdge(edges, "cross_domain_route", objectKey, keyByGraphId.get(`domain::${route.consumerDomainId}`) ??
|
|
1191
|
+
`domain:${route.consumerDomainId}`, {
|
|
1192
|
+
state: route.state,
|
|
1193
|
+
reasonCodes: route.reasonCodes,
|
|
1194
|
+
});
|
|
987
1195
|
}
|
|
988
1196
|
for (const edge of graph.edges ?? []) {
|
|
989
1197
|
const fromKey = keyByGraphId.get(edge.from) ?? edge.from;
|
|
@@ -2356,6 +2564,9 @@ function isQualifiedDqlModelingNode(node) {
|
|
|
2356
2564
|
}
|
|
2357
2565
|
function qualifiedIdentityFromKGNode(node) {
|
|
2358
2566
|
const payload = node.payload ?? {};
|
|
2567
|
+
const registryIdentity = stringValue(payload.registryQualifiedId);
|
|
2568
|
+
if (registryIdentity)
|
|
2569
|
+
return registryIdentity;
|
|
2359
2570
|
const explicit = stringValue(payload.qualifiedId);
|
|
2360
2571
|
if (explicit)
|
|
2361
2572
|
return explicit;
|
|
@@ -2407,7 +2618,8 @@ function addSkillObjects(skills, objects, edges) {
|
|
|
2407
2618
|
domain: skill.domain,
|
|
2408
2619
|
domains: skill.domains ?? [],
|
|
2409
2620
|
modelAreaRefs: skill.modelAreaRefs ?? [],
|
|
2410
|
-
status: skill.status ??
|
|
2621
|
+
status: skill.status ?? "active",
|
|
2622
|
+
analyticalPolicy: skill.analyticalPolicy,
|
|
2411
2623
|
bodyHash,
|
|
2412
2624
|
}));
|
|
2413
2625
|
const objectKey = `skill:${identity}`;
|
|
@@ -2442,6 +2654,7 @@ function addSkillObjects(skills, objects, edges) {
|
|
|
2442
2654
|
examples: skill.examples ?? [],
|
|
2443
2655
|
sourceRefs: skill.sourceRefs ?? [],
|
|
2444
2656
|
vocabulary: skill.vocabulary,
|
|
2657
|
+
analyticalPolicy: skill.analyticalPolicy,
|
|
2445
2658
|
bodyHash,
|
|
2446
2659
|
sourceFingerprint,
|
|
2447
2660
|
isStarter: skill.isStarter,
|
|
@@ -6260,13 +6473,22 @@ function skillFromMetadataObject(object) {
|
|
|
6260
6473
|
examples: stringArrayPayload(payload.examples),
|
|
6261
6474
|
sourceRefs: stringArrayPayload(payload.sourceRefs),
|
|
6262
6475
|
vocabulary: stringRecordPayload(payload.vocabulary),
|
|
6263
|
-
|
|
6264
|
-
|
|
6476
|
+
analyticalPolicy: skillAnalyticalPolicyPayload(payload.analyticalPolicy),
|
|
6477
|
+
body: "",
|
|
6478
|
+
sourcePath: object.sourcePath ?? "",
|
|
6265
6479
|
isStarter: payload.isStarter === true,
|
|
6266
6480
|
};
|
|
6267
6481
|
}
|
|
6268
6482
|
function localContextSkillFromParsed(skill, object) {
|
|
6269
6483
|
const guidance = skill.body.slice(0, 4_000);
|
|
6484
|
+
const sourceHash = stringPayload(object.payload?.sourceFingerprint);
|
|
6485
|
+
const policy = skill.analyticalPolicy && sourceHash
|
|
6486
|
+
? {
|
|
6487
|
+
policyId: `${skill.qualifiedId ?? skill.id}#analytical`,
|
|
6488
|
+
sourceHash,
|
|
6489
|
+
...skill.analyticalPolicy,
|
|
6490
|
+
}
|
|
6491
|
+
: undefined;
|
|
6270
6492
|
return {
|
|
6271
6493
|
objectKey: object.objectKey,
|
|
6272
6494
|
id: skill.id,
|
|
@@ -6286,6 +6508,7 @@ function localContextSkillFromParsed(skill, object) {
|
|
|
6286
6508
|
requiredFilters: [...(skill.requiredFilters ?? [])],
|
|
6287
6509
|
clarifyWhen: [...(skill.clarifyWhen ?? [])],
|
|
6288
6510
|
vocabulary: { ...skill.vocabulary },
|
|
6511
|
+
...(policy ? { analyticalPolicy: policy } : {}),
|
|
6289
6512
|
guidance,
|
|
6290
6513
|
guidanceTruncated: guidance.length < skill.body.length,
|
|
6291
6514
|
sourceRefs: [...(skill.sourceRefs ?? [])],
|
|
@@ -6293,6 +6516,38 @@ function localContextSkillFromParsed(skill, object) {
|
|
|
6293
6516
|
sourcePath: object.sourcePath,
|
|
6294
6517
|
};
|
|
6295
6518
|
}
|
|
6519
|
+
function skillAnalyticalPolicyPayload(value) {
|
|
6520
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6521
|
+
return undefined;
|
|
6522
|
+
const record = value;
|
|
6523
|
+
const completenessPolicy = stringPayload(record.completenessPolicy);
|
|
6524
|
+
const comparisonAlignment = stringPayload(record.comparisonAlignment);
|
|
6525
|
+
const defaultRankingPeriod = stringPayload(record.defaultRankingPeriod);
|
|
6526
|
+
const policy = {
|
|
6527
|
+
metricIds: stringArrayPayload(record.metricIds),
|
|
6528
|
+
timeRole: stringPayload(record.timeRole),
|
|
6529
|
+
calendarId: stringPayload(record.calendarId),
|
|
6530
|
+
timezone: stringPayload(record.timezone),
|
|
6531
|
+
completenessPolicy: completenessPolicy === "partial_current" ||
|
|
6532
|
+
completenessPolicy === "latest_complete" ||
|
|
6533
|
+
completenessPolicy === "closed_period"
|
|
6534
|
+
? completenessPolicy
|
|
6535
|
+
: undefined,
|
|
6536
|
+
comparisonAlignment: comparisonAlignment === "elapsed_period" ||
|
|
6537
|
+
comparisonAlignment === "calendar_period" ||
|
|
6538
|
+
comparisonAlignment === "fiscal_period"
|
|
6539
|
+
? comparisonAlignment
|
|
6540
|
+
: undefined,
|
|
6541
|
+
defaultRankingPeriod: defaultRankingPeriod === "current" ||
|
|
6542
|
+
defaultRankingPeriod === "comparison"
|
|
6543
|
+
? defaultRankingPeriod
|
|
6544
|
+
: undefined,
|
|
6545
|
+
narrativeGuidance: stringArrayPayload(record.narrativeGuidance),
|
|
6546
|
+
};
|
|
6547
|
+
return Object.values(policy).some((item) => Array.isArray(item) ? item.length > 0 : Boolean(item))
|
|
6548
|
+
? policy
|
|
6549
|
+
: undefined;
|
|
6550
|
+
}
|
|
6296
6551
|
function stringPayload(value) {
|
|
6297
6552
|
return typeof value === 'string' && value.trim() ? value : undefined;
|
|
6298
6553
|
}
|