@hamak/smart-data-dico 1.20.0 → 1.22.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/backend/dist/server.mjs +313 -88
- package/package.json +1 -1
package/backend/dist/server.mjs
CHANGED
|
@@ -26807,9 +26807,9 @@ var require_range2 = __commonJS({
|
|
|
26807
26807
|
parseRange(range) {
|
|
26808
26808
|
const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
|
|
26809
26809
|
const memoKey = memoOpts + ":" + range;
|
|
26810
|
-
const
|
|
26811
|
-
if (
|
|
26812
|
-
return
|
|
26810
|
+
const cached3 = cache2.get(memoKey);
|
|
26811
|
+
if (cached3) {
|
|
26812
|
+
return cached3;
|
|
26813
26813
|
}
|
|
26814
26814
|
const loose = this.options.loose;
|
|
26815
26815
|
const hr = loose ? re2[t.HYPHENRANGELOOSE] : re2[t.HYPHENRANGE];
|
|
@@ -44016,10 +44016,10 @@ var init_git_file_info_enricher = __esm({
|
|
|
44016
44016
|
* Get cached status or fetch new one
|
|
44017
44017
|
*/
|
|
44018
44018
|
async getCachedStatus(cacheKey, workspaceId, relativePath) {
|
|
44019
|
-
const
|
|
44019
|
+
const cached3 = this.statusCache.get(cacheKey);
|
|
44020
44020
|
const now2 = Date.now();
|
|
44021
|
-
if (
|
|
44022
|
-
return
|
|
44021
|
+
if (cached3 && now2 - cached3.timestamp < this.cacheTimeout) {
|
|
44022
|
+
return cached3.status;
|
|
44023
44023
|
}
|
|
44024
44024
|
try {
|
|
44025
44025
|
const status = await this.gitService.getStatus(workspaceId, relativePath);
|
|
@@ -44604,8 +44604,8 @@ function invalidatePackageCache(packageName) {
|
|
|
44604
44604
|
else _packageCache.delete(packageName);
|
|
44605
44605
|
}
|
|
44606
44606
|
async function loadPackage(packageName) {
|
|
44607
|
-
const
|
|
44608
|
-
if (
|
|
44607
|
+
const cached3 = _packageCache.get(packageName);
|
|
44608
|
+
if (cached3 && cached3.expires > Date.now()) return cached3.model;
|
|
44609
44609
|
const files = await listPackageYamlFilePaths(packageName);
|
|
44610
44610
|
const parsed = await Promise.all(
|
|
44611
44611
|
files.map(async (p) => ({
|
|
@@ -48508,9 +48508,25 @@ var init_serviceService = __esm({
|
|
|
48508
48508
|
* user to disambiguate.
|
|
48509
48509
|
*/
|
|
48510
48510
|
async findEntityAcrossPackages(entityName, preferredPackage) {
|
|
48511
|
+
const matches = await this.findEntityMatches(entityName, preferredPackage);
|
|
48512
|
+
if (matches.length === 0) return null;
|
|
48513
|
+
if (matches.length === 1) return matches[0];
|
|
48514
|
+
const where = matches.map((m) => m.packageName).join(", ");
|
|
48515
|
+
throw new Error(
|
|
48516
|
+
`Entity "${entityName}" exists in multiple packages: ${where}. Specify the package explicitly.`
|
|
48517
|
+
);
|
|
48518
|
+
}
|
|
48519
|
+
/**
|
|
48520
|
+
* All `{ entity, packageName }` matches for a name. A hit in
|
|
48521
|
+
* `preferredPackage` wins outright (single match, no wider scan) —
|
|
48522
|
+
* same precedence findEntityAcrossPackages always had. Callers that
|
|
48523
|
+
* want a disambiguation list instead of a thrown ambiguity error
|
|
48524
|
+
* (e.g. the AI getEntityDetails tool) consume this directly.
|
|
48525
|
+
*/
|
|
48526
|
+
async findEntityMatches(entityName, preferredPackage) {
|
|
48511
48527
|
if (preferredPackage) {
|
|
48512
48528
|
const e = await this.getEntitySchema(preferredPackage, entityName);
|
|
48513
|
-
if (e) return { entity: e, packageName: preferredPackage };
|
|
48529
|
+
if (e) return [{ entity: e, packageName: preferredPackage }];
|
|
48514
48530
|
}
|
|
48515
48531
|
const allPackages = await listMicroservices();
|
|
48516
48532
|
const matches = [];
|
|
@@ -48519,12 +48535,7 @@ var init_serviceService = __esm({
|
|
|
48519
48535
|
const e = await this.getEntitySchema(p, entityName);
|
|
48520
48536
|
if (e) matches.push({ entity: e, packageName: p });
|
|
48521
48537
|
}
|
|
48522
|
-
|
|
48523
|
-
if (matches.length === 1) return matches[0];
|
|
48524
|
-
const where = matches.map((m) => m.packageName).join(", ");
|
|
48525
|
-
throw new Error(
|
|
48526
|
-
`Entity "${entityName}" exists in multiple packages: ${where}. Specify the package explicitly.`
|
|
48527
|
-
);
|
|
48538
|
+
return matches;
|
|
48528
48539
|
}
|
|
48529
48540
|
async createEntity(service, entity) {
|
|
48530
48541
|
logger.info(`Creating entity: ${service}.${entity.name}`);
|
|
@@ -83510,6 +83521,79 @@ var init_authoringRules = __esm({
|
|
|
83510
83521
|
}
|
|
83511
83522
|
});
|
|
83512
83523
|
|
|
83524
|
+
// backend/src/services/ai/physicalMapping.ts
|
|
83525
|
+
function metaValue2(meta3, name21) {
|
|
83526
|
+
const e = meta3?.find((m) => m.name === name21);
|
|
83527
|
+
return e && e.value != null ? String(e.value) : void 0;
|
|
83528
|
+
}
|
|
83529
|
+
function metaFlag(meta3, name21) {
|
|
83530
|
+
const v = meta3?.find((m) => m.name === name21)?.value;
|
|
83531
|
+
return v === true || /^(true|yes|1)$/i.test(String(v ?? ""));
|
|
83532
|
+
}
|
|
83533
|
+
function resolveAttributePhysical(a) {
|
|
83534
|
+
const columnName = metaValue2(a.metadata, "physical.columnName");
|
|
83535
|
+
const dbType = metaValue2(a.metadata, "physical.dbType");
|
|
83536
|
+
return {
|
|
83537
|
+
...columnName ? { columnName } : {},
|
|
83538
|
+
...dbType ? { dbType } : {},
|
|
83539
|
+
// == null: a YAML `primaryKey:` left empty means "unset", not false —
|
|
83540
|
+
// fall back to the legacy metadata flag in that case too.
|
|
83541
|
+
primaryKey: a.primaryKey == null ? metaFlag(a.metadata, "isPrimaryKey") : !!a.primaryKey
|
|
83542
|
+
};
|
|
83543
|
+
}
|
|
83544
|
+
var init_physicalMapping = __esm({
|
|
83545
|
+
"backend/src/services/ai/physicalMapping.ts"() {
|
|
83546
|
+
"use strict";
|
|
83547
|
+
__name(metaValue2, "metaValue");
|
|
83548
|
+
__name(metaFlag, "metaFlag");
|
|
83549
|
+
__name(resolveAttributePhysical, "resolveAttributePhysical");
|
|
83550
|
+
}
|
|
83551
|
+
});
|
|
83552
|
+
|
|
83553
|
+
// backend/src/services/ai/modelOverviewCache.ts
|
|
83554
|
+
var modelOverviewCache_exports = {};
|
|
83555
|
+
__export(modelOverviewCache_exports, {
|
|
83556
|
+
MODEL_OVERVIEW_TTL_MS: () => MODEL_OVERVIEW_TTL_MS,
|
|
83557
|
+
getModelOverviewCached: () => getModelOverviewCached,
|
|
83558
|
+
invalidateModelOverviewCache: () => invalidateModelOverviewCache,
|
|
83559
|
+
subscribeModelOverviewCache: () => subscribeModelOverviewCache
|
|
83560
|
+
});
|
|
83561
|
+
function invalidateModelOverviewCache() {
|
|
83562
|
+
cached2 = null;
|
|
83563
|
+
generation++;
|
|
83564
|
+
}
|
|
83565
|
+
function subscribeModelOverviewCache(projection) {
|
|
83566
|
+
return projection.onInvalidate(() => invalidateModelOverviewCache());
|
|
83567
|
+
}
|
|
83568
|
+
async function getModelOverviewCached(build) {
|
|
83569
|
+
if (cached2 && Date.now() - cached2.builtAt < MODEL_OVERVIEW_TTL_MS) {
|
|
83570
|
+
return cached2.value;
|
|
83571
|
+
}
|
|
83572
|
+
if (!inflight) {
|
|
83573
|
+
const startedAt = generation;
|
|
83574
|
+
inflight = build().then((value) => {
|
|
83575
|
+
if (generation === startedAt) cached2 = { value, builtAt: Date.now() };
|
|
83576
|
+
return value;
|
|
83577
|
+
}).finally(() => {
|
|
83578
|
+
inflight = null;
|
|
83579
|
+
});
|
|
83580
|
+
}
|
|
83581
|
+
return inflight;
|
|
83582
|
+
}
|
|
83583
|
+
var MODEL_OVERVIEW_TTL_MS, cached2, inflight, generation;
|
|
83584
|
+
var init_modelOverviewCache = __esm({
|
|
83585
|
+
"backend/src/services/ai/modelOverviewCache.ts"() {
|
|
83586
|
+
"use strict";
|
|
83587
|
+
MODEL_OVERVIEW_TTL_MS = 6e4;
|
|
83588
|
+
cached2 = null;
|
|
83589
|
+
inflight = null;
|
|
83590
|
+
generation = 0;
|
|
83591
|
+
__name(invalidateModelOverviewCache, "invalidateModelOverviewCache");
|
|
83592
|
+
__name(subscribeModelOverviewCache, "subscribeModelOverviewCache");
|
|
83593
|
+
__name(getModelOverviewCached, "getModelOverviewCached");
|
|
83594
|
+
}
|
|
83595
|
+
});
|
|
83596
|
+
|
|
83513
83597
|
// backend/src/services/systemPromptStore.ts
|
|
83514
83598
|
import { createHash as createHash2 } from "crypto";
|
|
83515
83599
|
function systemPromptDigest(body) {
|
|
@@ -104542,10 +104626,6 @@ var init_aiMermaid = __esm({
|
|
|
104542
104626
|
});
|
|
104543
104627
|
|
|
104544
104628
|
// backend/src/controllers/aiSql.ts
|
|
104545
|
-
function metaValue2(meta3, name21) {
|
|
104546
|
-
const e = meta3?.find((m) => m.name === name21);
|
|
104547
|
-
return e && e.value != null ? String(e.value) : void 0;
|
|
104548
|
-
}
|
|
104549
104629
|
function nameList(names, max = 8) {
|
|
104550
104630
|
if (!names.length) return "";
|
|
104551
104631
|
return names.length <= max ? names.join(", ") : `${names.slice(0, max).join(", ")} +${names.length - max} more`;
|
|
@@ -104587,44 +104667,107 @@ function sqlType(base, v, dialect) {
|
|
|
104587
104667
|
}
|
|
104588
104668
|
}
|
|
104589
104669
|
function columnFor(a, derived, dialect) {
|
|
104590
|
-
const
|
|
104591
|
-
const physType = metaValue2(a.metadata, "physical.dbType");
|
|
104670
|
+
const phys = resolveAttributePhysical(a);
|
|
104592
104671
|
const resolved = resolveBase(String(a.type || "string"), a.validation, derived);
|
|
104593
104672
|
return {
|
|
104594
104673
|
attribute: a.name,
|
|
104595
|
-
column:
|
|
104596
|
-
dbType:
|
|
104674
|
+
column: phys.columnName ?? a.name,
|
|
104675
|
+
dbType: phys.dbType ?? sqlType(resolved.base, resolved.validation, dialect),
|
|
104597
104676
|
nullable: !a.required,
|
|
104598
|
-
primaryKey:
|
|
104599
|
-
...
|
|
104677
|
+
primaryKey: phys.primaryKey,
|
|
104678
|
+
...phys.columnName || phys.dbType ? {} : { physicalMappingMissing: true }
|
|
104600
104679
|
};
|
|
104601
104680
|
}
|
|
104602
104681
|
async function buildSqlSchema(input, services, opts) {
|
|
104603
104682
|
const dialect = input.dialect ?? "generic";
|
|
104604
104683
|
const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
|
|
104605
|
-
const
|
|
104684
|
+
const allPkgs = await listMicroservices2();
|
|
104685
|
+
if (input.entityNames !== void 0 && !Array.isArray(input.entityNames)) {
|
|
104686
|
+
return {
|
|
104687
|
+
error: `entityNames must be an array of entity names, e.g. entityNames: ['Order']. Retry with an array, or call searchModel({ query: '<entity or business term>' }) to locate the entity first.`
|
|
104688
|
+
};
|
|
104689
|
+
}
|
|
104690
|
+
const requestedNames = Array.isArray(input.entityNames) ? input.entityNames.map((n) => String(n).trim()).filter(Boolean) : void 0;
|
|
104691
|
+
if (input.packageName && !allPkgs.includes(input.packageName)) {
|
|
104692
|
+
return {
|
|
104693
|
+
error: `Package '${input.packageName}' not found. Known packages: ${nameList(allPkgs, 12) || "none"}. Call searchModel({ query: '<entity or business term>' }) to locate the element, or retry with entityNames: ['<EntityName>'] \u2014 entity names resolve across all packages.`
|
|
104694
|
+
};
|
|
104695
|
+
}
|
|
104606
104696
|
const derivedList = await services.derivedTypes.list().catch(() => []);
|
|
104607
104697
|
const derived = new Map(derivedList.map((d) => [d.name, d]));
|
|
104608
|
-
const
|
|
104609
|
-
const nameByUuid = /* @__PURE__ */ new Map();
|
|
104698
|
+
const entitiesByPkg = /* @__PURE__ */ new Map();
|
|
104610
104699
|
for (const p of allPkgs) {
|
|
104611
|
-
|
|
104700
|
+
entitiesByPkg.set(p, await services.serviceService.getServiceEntities(p).catch(() => []));
|
|
104701
|
+
}
|
|
104702
|
+
const nameByUuid = /* @__PURE__ */ new Map();
|
|
104703
|
+
for (const ents of entitiesByPkg.values()) {
|
|
104704
|
+
for (const e of ents) nameByUuid.set(e.uuid, e.name);
|
|
104705
|
+
}
|
|
104706
|
+
const relsByPkg = /* @__PURE__ */ new Map();
|
|
104707
|
+
const relsFor = /* @__PURE__ */ __name(async (p) => {
|
|
104708
|
+
if (!relsByPkg.has(p)) relsByPkg.set(p, await services.serviceService.getPackageRelationships(p).catch(() => []));
|
|
104709
|
+
return relsByPkg.get(p);
|
|
104710
|
+
}, "relsFor");
|
|
104711
|
+
let pkgs;
|
|
104712
|
+
let include = null;
|
|
104713
|
+
let scope;
|
|
104714
|
+
const unresolved = [];
|
|
104715
|
+
if (requestedNames?.length) {
|
|
104716
|
+
pkgs = allPkgs;
|
|
104717
|
+
const wanted = /* @__PURE__ */ new Set();
|
|
104718
|
+
for (const name21 of requestedNames) {
|
|
104719
|
+
const exact = [];
|
|
104720
|
+
const loose = [];
|
|
104721
|
+
for (const ents of entitiesByPkg.values()) {
|
|
104722
|
+
for (const e of ents) {
|
|
104723
|
+
if (e.name === name21) exact.push(e.uuid);
|
|
104724
|
+
else if (e.name.toLowerCase() === name21.toLowerCase()) loose.push(e.uuid);
|
|
104725
|
+
}
|
|
104726
|
+
}
|
|
104727
|
+
const hits = exact.length ? exact : loose;
|
|
104728
|
+
if (hits.length) hits.forEach((u) => wanted.add(u));
|
|
104729
|
+
else unresolved.push(name21);
|
|
104730
|
+
}
|
|
104731
|
+
if (!wanted.size) {
|
|
104732
|
+
return {
|
|
104733
|
+
error: `None of the requested entities (${requestedNames.join(", ")}) exist in any package. Call searchModel({ query: '<entity or business term>' }) to locate the right entity names, then retry.`
|
|
104734
|
+
};
|
|
104735
|
+
}
|
|
104736
|
+
include = new Set(wanted);
|
|
104737
|
+
for (const p of allPkgs) {
|
|
104738
|
+
for (const r of await relsFor(p)) {
|
|
104739
|
+
if (wanted.has(r.source.entity)) include.add(r.target.entity);
|
|
104740
|
+
if (wanted.has(r.target.entity)) include.add(r.source.entity);
|
|
104741
|
+
}
|
|
104742
|
+
}
|
|
104743
|
+
const resolved = requestedNames.filter((n) => !unresolved.includes(n));
|
|
104744
|
+
scope = `entities: ${resolved.join(", ")} (+directly related)`;
|
|
104745
|
+
} else {
|
|
104746
|
+
pkgs = input.packageName ? [input.packageName] : allPkgs;
|
|
104747
|
+
scope = input.packageName ?? "all packages";
|
|
104612
104748
|
}
|
|
104613
104749
|
const tables = [];
|
|
104614
104750
|
const relationships = [];
|
|
104615
104751
|
let missing = 0;
|
|
104752
|
+
const fallbackTables = [];
|
|
104616
104753
|
for (const p of pkgs) {
|
|
104617
|
-
const entities =
|
|
104754
|
+
const entities = (entitiesByPkg.get(p) ?? []).filter((e) => !include || include.has(e.uuid));
|
|
104618
104755
|
for (const e of entities) {
|
|
104619
104756
|
const schema = metaValue2(e.metadata, "physical.schema") ?? (opts?.defaultSchema?.trim() || void 0);
|
|
104620
104757
|
const table = metaValue2(e.metadata, "physical.tableName") ?? e.name;
|
|
104758
|
+
let entityMissing = 0;
|
|
104621
104759
|
const columns = (e.attributes ?? []).map((a) => {
|
|
104622
104760
|
const c = columnFor(a, derived, dialect);
|
|
104623
|
-
if ("physicalMappingMissing" in c)
|
|
104761
|
+
if ("physicalMappingMissing" in c) entityMissing++;
|
|
104624
104762
|
return c;
|
|
104625
104763
|
});
|
|
104764
|
+
if (entityMissing > 0) {
|
|
104765
|
+
missing += entityMissing;
|
|
104766
|
+
if (!fallbackTables.includes(table)) fallbackTables.push(table);
|
|
104767
|
+
}
|
|
104626
104768
|
tables.push({
|
|
104627
104769
|
entity: e.name,
|
|
104770
|
+
package: p,
|
|
104628
104771
|
table,
|
|
104629
104772
|
...schema ? { schema } : {},
|
|
104630
104773
|
// Ready-to-use name for SQL — schema.table when a schema is known.
|
|
@@ -104632,7 +104775,8 @@ async function buildSqlSchema(input, services, opts) {
|
|
|
104632
104775
|
columns
|
|
104633
104776
|
});
|
|
104634
104777
|
}
|
|
104635
|
-
for (const r of await
|
|
104778
|
+
for (const r of await relsFor(p)) {
|
|
104779
|
+
if (include && !(include.has(r.source.entity) && include.has(r.target.entity))) continue;
|
|
104636
104780
|
const from = nameByUuid.get(r.source.entity);
|
|
104637
104781
|
const to = nameByUuid.get(r.target.entity);
|
|
104638
104782
|
if (!from || !to) continue;
|
|
@@ -104645,7 +104789,6 @@ async function buildSqlSchema(input, services, opts) {
|
|
|
104645
104789
|
});
|
|
104646
104790
|
}
|
|
104647
104791
|
}
|
|
104648
|
-
const scope = input.packageName ?? "all packages";
|
|
104649
104792
|
const tableNames = tables.map((t) => t.entity);
|
|
104650
104793
|
return {
|
|
104651
104794
|
// #tool-summary — concise line, NAMES the tables for the tool card.
|
|
@@ -104655,7 +104798,9 @@ async function buildSqlSchema(input, services, opts) {
|
|
|
104655
104798
|
schemaQualifyTables: !!opts?.schemaQualifyTables,
|
|
104656
104799
|
tables,
|
|
104657
104800
|
relationships,
|
|
104658
|
-
|
|
104801
|
+
...unresolved.length ? { unresolvedEntityNames: unresolved } : {},
|
|
104802
|
+
...fallbackTables.length ? { tablesWithFallbackColumns: fallbackTables } : {},
|
|
104803
|
+
note: "Use these PHYSICAL table/column names and dbTypes when writing SQL. " + (opts?.schemaQualifyTables ? "Schema-qualify every table (use each table's qualifiedName). " : "") + (missing > 0 ? `${missing} column(s) in table(s) ${nameList(fallbackTables, 6)} have no explicit physical mapping \u2014 their column names/dbTypes are derived from the logical model; WARN the user before relying on them.` : "All columns have an explicit physical mapping.") + (unresolved.length ? ` Requested entities not found: ${unresolved.join(", ")} \u2014 call searchModel({ query: '<name>' }) to locate them.` : "")
|
|
104659
104804
|
};
|
|
104660
104805
|
}
|
|
104661
104806
|
var getSqlSchemaInputSchema, getSqlSchemaParameters;
|
|
@@ -104663,18 +104808,20 @@ var init_aiSql = __esm({
|
|
|
104663
104808
|
"backend/src/controllers/aiSql.ts"() {
|
|
104664
104809
|
"use strict";
|
|
104665
104810
|
init_zod();
|
|
104811
|
+
init_physicalMapping();
|
|
104666
104812
|
getSqlSchemaInputSchema = external_exports.object({
|
|
104667
104813
|
packageName: external_exports.string().optional().describe("Scope to one package (omit for the whole model)"),
|
|
104814
|
+
entityNames: external_exports.array(external_exports.string()).optional().describe("PREFERRED scope on large models: the target entity names (resolved across all packages). Their directly-related entities are included automatically so JOINs can be derived."),
|
|
104668
104815
|
dialect: external_exports.enum(["generic", "postgres", "mysql", "mssql", "oracle", "sqlite"]).optional().describe("Target SQL dialect \u2014 tunes fallback column types (default generic)")
|
|
104669
104816
|
});
|
|
104670
104817
|
getSqlSchemaParameters = {
|
|
104671
104818
|
type: "object",
|
|
104672
104819
|
properties: {
|
|
104673
104820
|
packageName: { type: "string", description: "Scope to one package (omit for the whole model)" },
|
|
104821
|
+
entityNames: { type: "array", items: { type: "string" }, description: "PREFERRED scope on large models: target entity names, resolved across all packages; directly-related entities are included automatically for JOINs" },
|
|
104674
104822
|
dialect: { type: "string", enum: ["generic", "postgres", "mysql", "mssql", "oracle", "sqlite"], description: "Target SQL dialect (default generic)" }
|
|
104675
104823
|
}
|
|
104676
104824
|
};
|
|
104677
|
-
__name(metaValue2, "metaValue");
|
|
104678
104825
|
__name(nameList, "nameList");
|
|
104679
104826
|
__name(resolveBase, "resolveBase");
|
|
104680
104827
|
__name(sqlType, "sqlType");
|
|
@@ -116875,16 +117022,15 @@ function buildEntityDetails(entity, packageName) {
|
|
|
116875
117022
|
const tableName = metaValue3(entity.metadata, "physical.tableName");
|
|
116876
117023
|
const schema = metaValue3(entity.metadata, "physical.schema");
|
|
116877
117024
|
const attributes = (entity.attributes ?? []).map((a) => {
|
|
116878
|
-
const
|
|
116879
|
-
const dbType = metaValue3(a.metadata, "physical.dbType");
|
|
117025
|
+
const phys = resolveAttributePhysical(a);
|
|
116880
117026
|
return {
|
|
116881
117027
|
name: a.name,
|
|
116882
117028
|
type: a.type,
|
|
116883
117029
|
description: a.description,
|
|
116884
117030
|
required: a.required,
|
|
116885
|
-
primaryKey:
|
|
117031
|
+
primaryKey: phys.primaryKey,
|
|
116886
117032
|
...a.validation ? { validation: a.validation } : {},
|
|
116887
|
-
...columnName || dbType ? { physical: { ...columnName ? { columnName } : {}, ...dbType ? { dbType } : {} } } : {}
|
|
117033
|
+
...phys.columnName || phys.dbType ? { physical: { ...phys.columnName ? { columnName: phys.columnName } : {}, ...phys.dbType ? { dbType: phys.dbType } : {} } } : {}
|
|
116888
117034
|
};
|
|
116889
117035
|
});
|
|
116890
117036
|
const hasPhysical = !!(tableName || schema) || attributes.some((a) => a.physical);
|
|
@@ -116896,6 +117042,7 @@ function buildEntityDetails(entity, packageName) {
|
|
|
116896
117042
|
// #tool-summary — concise self-describing line for the tool card.
|
|
116897
117043
|
summary: `${entity.name}${packageName ? ` (${packageName})` : ""} \u2014 ${attributes.length} attribute${attributes.length === 1 ? "" : "s"}${extras.length ? ` (${extras.join(", ")})` : ""}`,
|
|
116898
117044
|
name: entity.name,
|
|
117045
|
+
...packageName ? { packageName } : {},
|
|
116899
117046
|
description: entity.description,
|
|
116900
117047
|
stereotype: entity.stereotype,
|
|
116901
117048
|
...tableName || schema ? { physical: { ...tableName ? { tableName } : {}, ...schema ? { schema } : {} } } : {},
|
|
@@ -116904,6 +117051,46 @@ function buildEntityDetails(entity, packageName) {
|
|
|
116904
117051
|
...entity.rules?.length ? { rules: entity.rules.map((r) => ({ name: r.name, description: r.description, severity: r.severity })) } : {}
|
|
116905
117052
|
};
|
|
116906
117053
|
}
|
|
117054
|
+
async function executeGetEntityDetails(args, services) {
|
|
117055
|
+
if (!args?.entityName) return { error: "entityName is required." };
|
|
117056
|
+
const matches = await services.serviceService.findEntityMatches(args.entityName, args.packageName || void 0);
|
|
117057
|
+
if (matches.length === 1) {
|
|
117058
|
+
return buildEntityDetails(matches[0].entity, matches[0].packageName);
|
|
117059
|
+
}
|
|
117060
|
+
if (matches.length > 1) {
|
|
117061
|
+
return {
|
|
117062
|
+
summary: `'${args.entityName}' matches ${matches.length} entities \u2014 specify packageName`,
|
|
117063
|
+
ambiguous: true,
|
|
117064
|
+
candidates: matches.map((m) => ({
|
|
117065
|
+
entityName: m.entity.name,
|
|
117066
|
+
packageName: m.packageName,
|
|
117067
|
+
...m.entity.description ? { description: m.entity.description } : {}
|
|
117068
|
+
})),
|
|
117069
|
+
note: "Several packages define an entity with this name. Call getEntityDetails again with the intended packageName."
|
|
117070
|
+
};
|
|
117071
|
+
}
|
|
117072
|
+
return {
|
|
117073
|
+
error: `Entity '${args.entityName}' not found in ${args.packageName ? `package '${args.packageName}' or ` : ""}any package. Call searchModel({ query: '${args.entityName}' }) to locate it by full-text search \u2014 the model may use a different name.`
|
|
117074
|
+
};
|
|
117075
|
+
}
|
|
117076
|
+
async function executeListEntities(args, services) {
|
|
117077
|
+
const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
|
|
117078
|
+
if (args?.packageName) {
|
|
117079
|
+
const packages2 = await listMicroservices2().catch(() => []);
|
|
117080
|
+
if (!packages2.includes(args.packageName)) {
|
|
117081
|
+
return {
|
|
117082
|
+
error: `Package '${args.packageName}' not found. Known packages: ${nameList2(packages2, 12) || "none"}. Call searchModel({ query: '<entity or business term>' }) to locate the element you are after.`
|
|
117083
|
+
};
|
|
117084
|
+
}
|
|
117085
|
+
const entities = await services.serviceService.getServiceEntities(args.packageName);
|
|
117086
|
+
return {
|
|
117087
|
+
summary: `${args.packageName}: ${nameList2(entities.map((e) => e.name)) || "no entities"}`,
|
|
117088
|
+
entities: entities.map((e) => ({ name: e.name, description: e.description, attrCount: e.attributes?.length || 0 }))
|
|
117089
|
+
};
|
|
117090
|
+
}
|
|
117091
|
+
const packages = await listMicroservices2();
|
|
117092
|
+
return { summary: `packages: ${nameList2(packages) || "none"}`, packages };
|
|
117093
|
+
}
|
|
116907
117094
|
async function buildModelOverview(services) {
|
|
116908
117095
|
const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
|
|
116909
117096
|
const pkgNames = await listMicroservices2().catch(() => []);
|
|
@@ -116962,9 +117149,35 @@ function formatModelOutline(o) {
|
|
|
116962
117149
|
Packages:
|
|
116963
117150
|
${pkgLines}${extra.length ? "\n" + extra.join("\n") : ""}`;
|
|
116964
117151
|
}
|
|
117152
|
+
function formatModelOutlineWithinBudget(o, maxChars = MODEL_OUTLINE_MAX_CHARS) {
|
|
117153
|
+
const full = formatModelOutline(o);
|
|
117154
|
+
if (full.length <= maxChars) return full;
|
|
117155
|
+
const t = o.totals;
|
|
117156
|
+
const head = `Current model snapshot \u2014 ${t.packages} package(s), ${t.entities} entities, ${t.relationships} relationships, ${t.cases} cases, ${t.rules} rules, ${t.events} events, ${t.actions} actions, ${t.stateMachines} state machines, ${t.derivedTypes} derived types, ${t.stereotypes} stereotypes.`;
|
|
117157
|
+
const banner = `Entity lists omitted (${t.entities} entities across ${t.packages} packages \u2014 too large to inline). You do NOT have the full entity list. To locate any entity, call searchModel with its name or a business term, then getEntityDetails (packageName optional) or getSqlSchema with entityNames. Do NOT guess entity, package, or table names.`;
|
|
117158
|
+
const pkgLines = o.packages.map((p) => ` - ${p.name}: ${p.entities.length} entit${p.entities.length === 1 ? "y" : "ies"}, ${p.relationships} relationship${p.relationships === 1 ? "" : "s"}`);
|
|
117159
|
+
const fixed = head.length + banner.length + "Packages:\n".length + 4;
|
|
117160
|
+
const lines = [];
|
|
117161
|
+
let used = fixed;
|
|
117162
|
+
for (let i = 0; i < pkgLines.length; i++) {
|
|
117163
|
+
const remaining = pkgLines.length - i;
|
|
117164
|
+
if (used + pkgLines[i].length + 1 > maxChars - 80 && remaining > 1) {
|
|
117165
|
+
lines.push(` \u2026 +${remaining} more packages (call listEntities to enumerate)`);
|
|
117166
|
+
break;
|
|
117167
|
+
}
|
|
117168
|
+
lines.push(pkgLines[i]);
|
|
117169
|
+
used += pkgLines[i].length + 1;
|
|
117170
|
+
}
|
|
117171
|
+
return `${head}
|
|
117172
|
+
${banner}
|
|
117173
|
+
Packages:
|
|
117174
|
+
${lines.join("\n")}`;
|
|
117175
|
+
}
|
|
116965
117176
|
async function safeModelOutline(services) {
|
|
116966
117177
|
try {
|
|
116967
|
-
return
|
|
117178
|
+
return formatModelOutlineWithinBudget(
|
|
117179
|
+
await getModelOverviewCached(() => buildModelOverview(services))
|
|
117180
|
+
);
|
|
116968
117181
|
} catch {
|
|
116969
117182
|
return "";
|
|
116970
117183
|
}
|
|
@@ -117130,7 +117343,7 @@ function buildSystemPrompt(pageContext, conversationSystemPrompt, mode = "design
|
|
|
117130
117343
|
if (typeof modelOutline === "string" && modelOutline.trim().length > 0) {
|
|
117131
117344
|
out += `
|
|
117132
117345
|
|
|
117133
|
-
${modelOutline.trim().slice(0,
|
|
117346
|
+
${modelOutline.trim().slice(0, MODEL_OUTLINE_MAX_CHARS)}`;
|
|
117134
117347
|
}
|
|
117135
117348
|
if (typeof pageContext === "string") {
|
|
117136
117349
|
const trimmed2 = pageContext.trim();
|
|
@@ -117142,7 +117355,7 @@ Page context: ${trimmed2.slice(0, 500)}`;
|
|
|
117142
117355
|
}
|
|
117143
117356
|
return out;
|
|
117144
117357
|
}
|
|
117145
|
-
function buildDirectChatMessages(rawMessages, maxToolResultChars =
|
|
117358
|
+
function buildDirectChatMessages(rawMessages, maxToolResultChars = DIRECT_TOOL_RESULT_MAX_CHARS) {
|
|
117146
117359
|
const out = [];
|
|
117147
117360
|
for (const msg of rawMessages) {
|
|
117148
117361
|
const text2 = msg.parts?.find((p) => p.type === "text")?.text || msg.content || "";
|
|
@@ -117158,10 +117371,13 @@ function buildDirectChatMessages(rawMessages, maxToolResultChars = 2e3) {
|
|
|
117158
117371
|
}))
|
|
117159
117372
|
});
|
|
117160
117373
|
for (const tc of toolCalls) {
|
|
117374
|
+
const serialized = JSON.stringify(tc.output ?? {});
|
|
117161
117375
|
out.push({
|
|
117162
117376
|
role: "tool",
|
|
117163
117377
|
tool_call_id: String(tc.id),
|
|
117164
|
-
|
|
117378
|
+
// Truncation must be LOUD — a silent cut reads as a complete result
|
|
117379
|
+
// and the model trusts a partial schema instead of narrowing scope.
|
|
117380
|
+
content: serialized.length > maxToolResultChars ? serialized.slice(0, maxToolResultChars) + TOOL_RESULT_TRUNCATION_MARKER : serialized
|
|
117165
117381
|
});
|
|
117166
117382
|
}
|
|
117167
117383
|
} else if (text2) {
|
|
@@ -117216,10 +117432,10 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
|
|
|
117216
117432
|
{ type: "function", function: { name: "createAction", description: "Create an Action/command (e.g. PlaceOrder) on an aggregate entity (ownerEntityName), optionally CQRS-classified, with an optional flow of steps. Use flow steps emitEvent {name} and wait {for} to wire a saga/process across actions+events.", parameters: createActionParameters } },
|
|
117217
117433
|
{ type: "function", function: { name: "createStateMachine", description: "Create a state machine on an entity (ownerEntityName) \u2014 its states, initialState, and transitions (from/to/on). Model an entity lifecycle, e.g. Order PENDING\u2192PAID\u2192SHIPPED.", parameters: createStateMachineParameters } },
|
|
117218
117434
|
{ type: "function", function: { name: "listEntities", description: "List packages or entities in a package", parameters: { type: "object", properties: { packageName: { type: "string", description: "Package name (omit to list all)" } } } } },
|
|
117219
|
-
{ type: "function", function: { name: "getEntityDetails", description: "Get full detail for one entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. Call this before writing SQL/DDL so you use the real physical names and types.", parameters: { type: "object", required: ["
|
|
117435
|
+
{ type: "function", function: { name: "getEntityDetails", description: "Get full detail for one entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. packageName is OPTIONAL \u2014 omit it and the entity name is resolved across every package (ambiguous names return a candidate list). Call this before writing SQL/DDL so you use the real physical names and types.", parameters: { type: "object", required: ["entityName"], properties: { packageName: { type: "string", description: "Owning package if known (optional \u2014 resolved across packages when omitted)" }, entityName: { type: "string" } } } } },
|
|
117220
117436
|
{ type: "function", function: { name: "getModelOverview", description: "Get a whole-model outline: every package with its entity names, and a count of each concept (entities, relationships, cases, rules, events, actions, state machines, derived types, stereotypes). A snapshot is already in your context; call this to refresh after changes.", parameters: { type: "object", properties: {} } } },
|
|
117221
117437
|
{ type: "function", function: { name: "generateMermaid", description: 'Convert the model to Mermaid diagram source. diagram: "er" (entity-relationship of a package, or all), "class" (class diagram), "state" (a single entity state machine \u2014 pass entityName), "flow" (actions+events saga). Returns { mermaid }. Present it inside a ```mermaid code block.', parameters: generateMermaidParameters } },
|
|
117222
|
-
{ type: "function", function: { name: "getSqlSchema", description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints.
|
|
117438
|
+
{ type: "function", function: { name: "getSqlSchema", description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints. PREFER scoping with entityNames (target entities, resolved across packages; directly-related entities are included automatically for JOINs) or packageName \u2014 an unscoped call on a large model returns a huge result that may be truncated. Optional dialect. Call this before writing any SQL query or DDL so you use real physical names/types, not the conceptual (logical) names.", parameters: getSqlSchemaParameters } },
|
|
117223
117439
|
{ type: "function", function: { name: "listStereotypes", description: "List available stereotypes", parameters: { type: "object", properties: {} } } },
|
|
117224
117440
|
{ type: "function", function: { name: "navigateTo", description: 'Navigate user to a page. The path MUST be an absolute URL beginning with "/" that matches one of the patterns returned by listRoutes \u2014 call listRoutes first if you are unsure of the exact shape.', parameters: { type: "object", required: ["path", "reason"], properties: { path: { type: "string" }, reason: { type: "string" } } } } },
|
|
117225
117441
|
{ type: "function", function: { name: "listRoutes", description: "List every valid URL pattern in the app with a short description and (where useful) a concrete example. Call this BEFORE navigateTo if you are unsure of the exact path shape \u2014 e.g. plural vs singular, where attribute pages live, what the case route is.", parameters: { type: "object", properties: {} } } }
|
|
@@ -117281,21 +117497,13 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
|
|
|
117281
117497
|
return await executeCreateStateMachine(args, conceptServices);
|
|
117282
117498
|
}
|
|
117283
117499
|
if (name21 === "listEntities") {
|
|
117284
|
-
|
|
117285
|
-
const entities = await services.serviceService.getServiceEntities(args.packageName);
|
|
117286
|
-
return { summary: `${args.packageName}: ${nameList2(entities.map((e) => e.name)) || "no entities"}`, entities: entities.map((e) => ({ name: e.name, description: e.description })) };
|
|
117287
|
-
}
|
|
117288
|
-
const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
|
|
117289
|
-
const packages = await listMicroservices2();
|
|
117290
|
-
return { summary: `packages: ${nameList2(packages) || "none"}`, packages };
|
|
117500
|
+
return await executeListEntities(args, services);
|
|
117291
117501
|
}
|
|
117292
117502
|
if (name21 === "getEntityDetails") {
|
|
117293
|
-
|
|
117294
|
-
if (!entity) return { error: "Entity not found" };
|
|
117295
|
-
return buildEntityDetails(entity, args.packageName);
|
|
117503
|
+
return await executeGetEntityDetails(args, services);
|
|
117296
117504
|
}
|
|
117297
117505
|
if (name21 === "getModelOverview") {
|
|
117298
|
-
return await buildModelOverview(services);
|
|
117506
|
+
return await getModelOverviewCached(() => buildModelOverview(services));
|
|
117299
117507
|
}
|
|
117300
117508
|
if (name21 === "generateMermaid") {
|
|
117301
117509
|
return await generateMermaidDiagram(args, services);
|
|
@@ -117334,8 +117542,11 @@ async function handleDirectChat(req, res, cfg, rawMessages, services, pageContex
|
|
|
117334
117542
|
}
|
|
117335
117543
|
}
|
|
117336
117544
|
const out = await runTool(name21, args);
|
|
117337
|
-
if (isGatedCategory(category)
|
|
117338
|
-
|
|
117545
|
+
if (isGatedCategory(category)) {
|
|
117546
|
+
invalidateModelOverviewCache();
|
|
117547
|
+
if (out && typeof out === "object" && out.success === true) {
|
|
117548
|
+
mutatingSuccessCount++;
|
|
117549
|
+
}
|
|
117339
117550
|
}
|
|
117340
117551
|
return out;
|
|
117341
117552
|
}, "executeTool");
|
|
@@ -117461,7 +117672,7 @@ ${lines.join("\n")}` : "";
|
|
|
117461
117672
|
return "";
|
|
117462
117673
|
}
|
|
117463
117674
|
}
|
|
117464
|
-
var TOOL_CATEGORY_MAP, READ_ONLY_TOOLS, MODE_SYSTEM_SUFFIX, GATED_CATEGORIES, DENIED_RESULT, SYSTEM_PROMPT, aiChat, aiChatApprove, aiStatus, aiGetConfig, aiSaveConfig, aiTestTools, aiTools, aiMentionsSearch, listConversations, getConversation, saveConversation, patchConversation, deleteConversation, getSystemPromptByDigest, listPrompts, getPrompt, createPrompt, updatePrompt, deletePrompt;
|
|
117675
|
+
var TOOL_CATEGORY_MAP, READ_ONLY_TOOLS, MODE_SYSTEM_SUFFIX, GATED_CATEGORIES, MODEL_OUTLINE_MAX_CHARS, DENIED_RESULT, SYSTEM_PROMPT, DIRECT_TOOL_RESULT_MAX_CHARS, TOOL_RESULT_TRUNCATION_MARKER, aiChat, aiChatApprove, aiStatus, aiGetConfig, aiSaveConfig, aiTestTools, aiTools, aiMentionsSearch, listConversations, getConversation, saveConversation, patchConversation, deleteConversation, getSystemPromptByDigest, listPrompts, getPrompt, createPrompt, updatePrompt, deletePrompt;
|
|
117465
117676
|
var init_aiController = __esm({
|
|
117466
117677
|
"backend/src/controllers/aiController.ts"() {
|
|
117467
117678
|
"use strict";
|
|
@@ -117471,6 +117682,8 @@ var init_aiController = __esm({
|
|
|
117471
117682
|
init_config();
|
|
117472
117683
|
init_agentToolRegistry();
|
|
117473
117684
|
init_authoringRules();
|
|
117685
|
+
init_physicalMapping();
|
|
117686
|
+
init_modelOverviewCache();
|
|
117474
117687
|
init_systemPromptStore();
|
|
117475
117688
|
init_appDir();
|
|
117476
117689
|
init_conversationService();
|
|
@@ -117542,8 +117755,12 @@ Mode: REVIEW. You are reviewing the data model for quality issues. Use read-only
|
|
|
117542
117755
|
__name(nameList2, "nameList");
|
|
117543
117756
|
__name(metaValue3, "metaValue");
|
|
117544
117757
|
__name(buildEntityDetails, "buildEntityDetails");
|
|
117758
|
+
__name(executeGetEntityDetails, "executeGetEntityDetails");
|
|
117759
|
+
__name(executeListEntities, "executeListEntities");
|
|
117545
117760
|
__name(buildModelOverview, "buildModelOverview");
|
|
117546
117761
|
__name(formatModelOutline, "formatModelOutline");
|
|
117762
|
+
MODEL_OUTLINE_MAX_CHARS = 4e3;
|
|
117763
|
+
__name(formatModelOutlineWithinBudget, "formatModelOutlineWithinBudget");
|
|
117547
117764
|
__name(safeModelOutline, "safeModelOutline");
|
|
117548
117765
|
__name(isGatedCategory, "isGatedCategory");
|
|
117549
117766
|
__name(resolveToolCategory, "resolveToolCategory");
|
|
@@ -117569,21 +117786,24 @@ This system models a RICH domain \u2014 not just entities. You can author all of
|
|
|
117569
117786
|
- Events \u2014 domain events emitted by aggregates, e.g. OrderPlaced (createEvent)
|
|
117570
117787
|
- Actions \u2014 commands/queries on aggregates with a flow; emitEvent/wait steps wire a saga/process (createAction)
|
|
117571
117788
|
- State machines \u2014 entity lifecycles: states + transitions, e.g. Order PENDING\u2192PAID\u2192SHIPPED (createStateMachine)
|
|
117572
|
-
- Read/inspect: searchModel (full-text search across the whole dictionary \u2014 use it to LOCATE an entity/attribute/rule when you don't know its exact name, then drill in), getModelOverview (whole-model outline \u2014 packages, entities, and concept counts; a current snapshot is already shown to you below), getEntityDetails (one entity in full incl. physical mapping), listEntities, listStereotypes; navigate with navigateTo (call listRoutes first if unsure)
|
|
117789
|
+
- Read/inspect: searchModel (full-text search across the whole dictionary \u2014 use it to LOCATE an entity/attribute/rule when you don't know its exact name, then drill in), getModelOverview (whole-model outline \u2014 packages, entities, and concept counts; a current snapshot is already shown to you below), getEntityDetails (one entity in full incl. physical mapping; packageName optional \u2014 the name resolves across packages), listEntities, listStereotypes; navigate with navigateTo (call listRoutes first if unsure)
|
|
117573
117790
|
- Diagram: generateMermaid converts the model to Mermaid source \u2014 diagram: "er" (entity-relationship of a package/all), "class" (class diagram), "state" (an entity's state machine, needs entityName), or "flow" (actions+events saga). Use it when the user asks for a diagram, ERD, or visualization, and present the result in a fenced mermaid code block.
|
|
117574
117791
|
|
|
117575
117792
|
A "process" or "saga" is NOT a separate object \u2014 it is the graph that emerges from Actions (with emitEvent/wait flow steps) and Events. To model a process, create the Actions and Events; the saga view is derived automatically.
|
|
117576
117793
|
|
|
117577
117794
|
CONCEPTUAL vs PHYSICAL model \u2014 keep these two layers distinct:
|
|
117578
117795
|
- CONCEPTUAL / LOGICAL is the business model: entity names (PascalCase, e.g. Order), attribute names (camelCase, e.g. orderNumber), and logical or derived types (e.g. money, email, currency-code). This is what you author and what users discuss.
|
|
117579
|
-
- PHYSICAL is how it is persisted in a database: a table name (physical.tableName) in a schema, per-column physical names (physical.columnName) and DB types (physical.dbType), plus constraints. The two layers can differ completely (logical Order.orderNumber \u2192 physical orders.order_no VARCHAR). getEntityDetails returns the physical mapping for one entity; getSqlSchema returns the
|
|
117796
|
+
- PHYSICAL is how it is persisted in a database: a table name (physical.tableName) in a schema, per-column physical names (physical.columnName) and DB types (physical.dbType), plus constraints. The two layers can differ completely (logical Order.orderNumber \u2192 physical orders.order_no VARCHAR). getEntityDetails returns the physical mapping for one entity; getSqlSchema returns the physical relational schema (scope it with entityNames or packageName on anything but a small model).
|
|
117580
117797
|
- A logical/derived type (money, email) is NOT a DB type \u2014 it maps to a physical dbType (money \u2192 DECIMAL(12,2), email \u2192 VARCHAR(254)).
|
|
117581
117798
|
- NEVER write DDL or SQL using conceptual names. Always resolve to the physical table/column names and dbTypes first. If an element has no physical mapping yet, getSqlSchema returns a fallback dbType derived from the logical type and flags it \u2014 pass that flag on to the user.
|
|
117582
117799
|
|
|
117583
117800
|
Generating database queries: when the user asks for a SQL query (SELECT / INSERT / UPDATE / DELETE), a report, or DDL \u2014
|
|
117584
|
-
1.
|
|
117585
|
-
2.
|
|
117586
|
-
3.
|
|
117801
|
+
1. LOCATE the entity first. Unless you already know its owning package (from the snapshot, page context, or an @mention), call searchModel with the entity name or business term to resolve entity \u2192 package. NEVER guess a package, entity, or table name \u2014 the snapshot above may not list every entity.
|
|
117802
|
+
2. Call getSqlSchema scoped NARROWLY: pass entityNames: [...] for the target entities (their directly-related entities are included automatically so you can derive JOINs), or a packageName; pass the target dialect. Do not call it unscoped on a large model \u2014 the result gets truncated and misleads you.
|
|
117803
|
+
3. Write the query using ONLY the physical names returned by the tool; derive JOINs from the relationships (join the PK of the "one" side to the FK on the "many" side) and respect the requested dialect.
|
|
117804
|
+
4. If any column is flagged physicalMappingMissing, tell the user those column names/types are unverified fallbacks derived from the logical model \u2014 do not silently pass them off as real.
|
|
117805
|
+
5. Present the query in a fenced sql code block, and briefly note any assumption (an inferred join column, a missing physical mapping). You generate queries for the user to run \u2014 you do NOT execute them against a live database.
|
|
117806
|
+
If a lookup tool returns an error or an empty result, do not retry the same guess \u2014 follow the error's guidance (usually: call searchModel), or ask the user.
|
|
117587
117807
|
|
|
117588
117808
|
When creating data models:
|
|
117589
117809
|
- Use meaningful names (PascalCase for entities/events, camelCase for attributes)
|
|
@@ -117614,6 +117834,8 @@ Be concise in your responses. Show a summary of what you created.`;
|
|
|
117614
117834
|
__name(sqlSettingsInstruction, "sqlSettingsInstruction");
|
|
117615
117835
|
__name(standingSystemPrompt, "standingSystemPrompt");
|
|
117616
117836
|
__name(buildSystemPrompt, "buildSystemPrompt");
|
|
117837
|
+
DIRECT_TOOL_RESULT_MAX_CHARS = 2e4;
|
|
117838
|
+
TOOL_RESULT_TRUNCATION_MARKER = "\u2026[truncated \u2014 result too large; retry with a narrower scope, e.g. packageName or entityNames filter]";
|
|
117617
117839
|
__name(buildDirectChatMessages, "buildDirectChatMessages");
|
|
117618
117840
|
__name(buildUiMessagesWithToolParts, "buildUiMessagesWithToolParts");
|
|
117619
117841
|
__name(handleDirectChat, "handleDirectChat");
|
|
@@ -117666,7 +117888,11 @@ Be concise in your responses. Show a summary of what you created.`;
|
|
|
117666
117888
|
const decision = await awaitApproval(streamId, toolCallId);
|
|
117667
117889
|
if (decision === "deny") return { ...DENIED_RESULT };
|
|
117668
117890
|
}
|
|
117669
|
-
|
|
117891
|
+
try {
|
|
117892
|
+
return await run();
|
|
117893
|
+
} finally {
|
|
117894
|
+
if (isGatedCategory(category)) invalidateModelOverviewCache();
|
|
117895
|
+
}
|
|
117670
117896
|
}, "gate");
|
|
117671
117897
|
const mcpToolEntries = {};
|
|
117672
117898
|
for (const mcpTool of mcpTools) {
|
|
@@ -117837,29 +118063,21 @@ Be concise in your responses. Show a summary of what you created.`;
|
|
|
117837
118063
|
}),
|
|
117838
118064
|
execute: /* @__PURE__ */ __name(async (params) => {
|
|
117839
118065
|
try {
|
|
117840
|
-
|
|
117841
|
-
const entities = await services.serviceService.getServiceEntities(params.packageName || "default");
|
|
117842
|
-
return { summary: `${params.packageName}: ${nameList2(entities.map((e) => e.name)) || "no entities"}`, entities: entities.map((e) => ({ name: e.name, description: e.description, attrCount: e.attributes?.length || 0 })) };
|
|
117843
|
-
}
|
|
117844
|
-
const { listMicroservices: listMicroservices2 } = await Promise.resolve().then(() => (init_fileOperations(), fileOperations_exports));
|
|
117845
|
-
const packages = await listMicroservices2();
|
|
117846
|
-
return { summary: `packages: ${nameList2(packages) || "none"}`, packages };
|
|
118066
|
+
return await executeListEntities(params, services);
|
|
117847
118067
|
} catch (err) {
|
|
117848
118068
|
return { error: err.message };
|
|
117849
118069
|
}
|
|
117850
118070
|
}, "execute")
|
|
117851
118071
|
}),
|
|
117852
118072
|
getEntityDetails: tool({
|
|
117853
|
-
description: "Get full detail for an entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. Use this before writing SQL/DDL so you use the real physical names and types.",
|
|
118073
|
+
description: "Get full detail for an entity: attributes with type/required/primaryKey AND field validation, the PHYSICAL mapping (entity table name + schema, each attribute physical column name + DB type), physical constraints, and inline business rules. packageName is OPTIONAL \u2014 omit it and the entity name is resolved across every package (ambiguous names return a candidate list). Use this before writing SQL/DDL so you use the real physical names and types.",
|
|
117854
118074
|
inputSchema: external_exports.object({
|
|
117855
|
-
packageName: external_exports.string(),
|
|
118075
|
+
packageName: external_exports.string().optional().describe("Owning package if known (optional \u2014 resolved across packages when omitted)"),
|
|
117856
118076
|
entityName: external_exports.string()
|
|
117857
118077
|
}),
|
|
117858
118078
|
execute: /* @__PURE__ */ __name(async (params) => {
|
|
117859
118079
|
try {
|
|
117860
|
-
|
|
117861
|
-
if (!entity) return { error: "Entity not found" };
|
|
117862
|
-
return buildEntityDetails(entity, params.packageName);
|
|
118080
|
+
return await executeGetEntityDetails(params, services);
|
|
117863
118081
|
} catch (err) {
|
|
117864
118082
|
return { error: err.message };
|
|
117865
118083
|
}
|
|
@@ -117870,7 +118088,7 @@ Be concise in your responses. Show a summary of what you created.`;
|
|
|
117870
118088
|
inputSchema: external_exports.object({}),
|
|
117871
118089
|
execute: /* @__PURE__ */ __name(async () => {
|
|
117872
118090
|
try {
|
|
117873
|
-
return await buildModelOverview(services);
|
|
118091
|
+
return await getModelOverviewCached(() => buildModelOverview(services));
|
|
117874
118092
|
} catch (err) {
|
|
117875
118093
|
return { error: err.message };
|
|
117876
118094
|
}
|
|
@@ -117888,7 +118106,7 @@ Be concise in your responses. Show a summary of what you created.`;
|
|
|
117888
118106
|
}, "execute")
|
|
117889
118107
|
}),
|
|
117890
118108
|
getSqlSchema: tool({
|
|
117891
|
-
description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints.
|
|
118109
|
+
description: "Get the PHYSICAL relational schema for writing SQL: per-entity table name + schema, each column (physical name, dbType, nullable, primaryKey), and relationships as join hints. PREFER scoping with entityNames (target entities, resolved across packages; directly-related entities are included automatically for JOINs) or packageName \u2014 an unscoped call on a large model returns a huge result that may be truncated. Optional dialect. Call this before writing any SQL query or DDL so you use real physical names/types, not the conceptual (logical) names.",
|
|
117892
118110
|
inputSchema: getSqlSchemaInputSchema,
|
|
117893
118111
|
execute: /* @__PURE__ */ __name(async (params) => {
|
|
117894
118112
|
try {
|
|
@@ -118321,7 +118539,7 @@ Be concise in your responses. Show a summary of what you created.`;
|
|
|
118321
118539
|
description: "Get full entity detail: attributes + validation, the physical mapping (table/schema, column names, DB types), constraints, and inline rules. Use before writing SQL/DDL.",
|
|
118322
118540
|
source: "builtin",
|
|
118323
118541
|
parameters: [
|
|
118324
|
-
{ name: "packageName", type: "string", required:
|
|
118542
|
+
{ name: "packageName", type: "string", required: false, description: "Owning package if known (omit to resolve the entity name across all packages)" },
|
|
118325
118543
|
{ name: "entityName", type: "string", required: true, description: "Entity name" }
|
|
118326
118544
|
]
|
|
118327
118545
|
},
|
|
@@ -118343,10 +118561,11 @@ Be concise in your responses. Show a summary of what you created.`;
|
|
|
118343
118561
|
},
|
|
118344
118562
|
{
|
|
118345
118563
|
name: "getSqlSchema",
|
|
118346
|
-
description: "Physical relational schema for writing SQL: tables, columns (physical name + dbType + nullable + PK), and relationships as join hints. Use before generating any SQL query/DDL.",
|
|
118564
|
+
description: "Physical relational schema for writing SQL: tables, columns (physical name + dbType + nullable + PK), and relationships as join hints. Use before generating any SQL query/DDL. Prefer scoping with entityNames or packageName on large models.",
|
|
118347
118565
|
source: "builtin",
|
|
118348
118566
|
parameters: [
|
|
118349
118567
|
{ name: "packageName", type: "string", required: false, description: "Scope to one package (omit for all)" },
|
|
118568
|
+
{ name: "entityNames", type: "string[]", required: false, description: "Preferred scope: target entity names, resolved across packages; directly-related entities are included automatically for JOINs" },
|
|
118350
118569
|
{ name: "dialect", type: "generic|postgres|mysql|mssql|oracle|sqlite", required: false, description: "Target SQL dialect (default generic)" }
|
|
118351
118570
|
]
|
|
118352
118571
|
},
|
|
@@ -150141,8 +150360,8 @@ var require_inflight = __commonJS({
|
|
|
150141
150360
|
var wrappy = require_wrappy();
|
|
150142
150361
|
var reqs = /* @__PURE__ */ Object.create(null);
|
|
150143
150362
|
var once = require_once();
|
|
150144
|
-
module.exports = wrappy(
|
|
150145
|
-
function
|
|
150363
|
+
module.exports = wrappy(inflight2);
|
|
150364
|
+
function inflight2(key2, cb) {
|
|
150146
150365
|
if (reqs[key2]) {
|
|
150147
150366
|
reqs[key2].push(cb);
|
|
150148
150367
|
return null;
|
|
@@ -150151,7 +150370,7 @@ var require_inflight = __commonJS({
|
|
|
150151
150370
|
return makeres(key2);
|
|
150152
150371
|
}
|
|
150153
150372
|
}
|
|
150154
|
-
__name(
|
|
150373
|
+
__name(inflight2, "inflight");
|
|
150155
150374
|
function makeres(key2) {
|
|
150156
150375
|
return once(/* @__PURE__ */ __name(function RES() {
|
|
150157
150376
|
var cbs = reqs[key2];
|
|
@@ -150203,7 +150422,7 @@ var require_glob = __commonJS({
|
|
|
150203
150422
|
var alphasorti = common.alphasorti;
|
|
150204
150423
|
var setopts = common.setopts;
|
|
150205
150424
|
var ownProp = common.ownProp;
|
|
150206
|
-
var
|
|
150425
|
+
var inflight2 = require_inflight();
|
|
150207
150426
|
var util2 = __require("util");
|
|
150208
150427
|
var childrenIgnored = common.childrenIgnored;
|
|
150209
150428
|
var isIgnored = common.isIgnored;
|
|
@@ -150535,7 +150754,7 @@ var require_glob = __commonJS({
|
|
|
150535
150754
|
return this._readdir(abs, false, cb);
|
|
150536
150755
|
var lstatkey = "lstat\0" + abs;
|
|
150537
150756
|
var self2 = this;
|
|
150538
|
-
var lstatcb =
|
|
150757
|
+
var lstatcb = inflight2(lstatkey, lstatcb_);
|
|
150539
150758
|
if (lstatcb)
|
|
150540
150759
|
fs16.lstat(abs, lstatcb);
|
|
150541
150760
|
function lstatcb_(er, lstat) {
|
|
@@ -150554,7 +150773,7 @@ var require_glob = __commonJS({
|
|
|
150554
150773
|
Glob.prototype._readdir = function(abs, inGlobStar, cb) {
|
|
150555
150774
|
if (this.aborted)
|
|
150556
150775
|
return;
|
|
150557
|
-
cb =
|
|
150776
|
+
cb = inflight2("readdir\0" + abs + "\0" + inGlobStar, cb);
|
|
150558
150777
|
if (!cb)
|
|
150559
150778
|
return;
|
|
150560
150779
|
if (inGlobStar && !ownProp(this.symlinks, abs))
|
|
@@ -150712,7 +150931,7 @@ var require_glob = __commonJS({
|
|
|
150712
150931
|
}
|
|
150713
150932
|
}
|
|
150714
150933
|
var self2 = this;
|
|
150715
|
-
var statcb =
|
|
150934
|
+
var statcb = inflight2("stat\0" + abs, lstatcb_);
|
|
150716
150935
|
if (statcb)
|
|
150717
150936
|
fs16.lstat(abs, statcb);
|
|
150718
150937
|
function lstatcb_(er, lstat) {
|
|
@@ -174311,6 +174530,12 @@ async function mountFrameworkRoutes() {
|
|
|
174311
174530
|
} catch (searchError) {
|
|
174312
174531
|
logger.warn(`SearchIndex initialization failed: ${searchError instanceof Error ? searchError.message : String(searchError)}`);
|
|
174313
174532
|
}
|
|
174533
|
+
try {
|
|
174534
|
+
const { subscribeModelOverviewCache: subscribeModelOverviewCache2 } = await Promise.resolve().then(() => (init_modelOverviewCache(), modelOverviewCache_exports));
|
|
174535
|
+
subscribeModelOverviewCache2(projection);
|
|
174536
|
+
} catch (cacheError) {
|
|
174537
|
+
logger.warn(`ModelOverviewCache subscription failed: ${cacheError instanceof Error ? cacheError.message : String(cacheError)}`);
|
|
174538
|
+
}
|
|
174314
174539
|
} catch (e) {
|
|
174315
174540
|
logger.warn(`Projection/UuidIndex initialization failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
174316
174541
|
}
|