@axiom-lattice/core 4.4.0 → 6.0.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/index.d.mts +74 -43
- package/dist/index.d.ts +74 -43
- package/dist/index.js +550 -2077
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +537 -2062
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -445,11 +445,11 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
|
|
|
445
445
|
* @param key Lattice键名
|
|
446
446
|
* @param tool 已有的StructuredTool实例
|
|
447
447
|
*/
|
|
448
|
-
registerExistingTool(key5,
|
|
448
|
+
registerExistingTool(key5, tool68) {
|
|
449
449
|
const config = {
|
|
450
|
-
name:
|
|
451
|
-
description:
|
|
452
|
-
schema:
|
|
450
|
+
name: tool68.name,
|
|
451
|
+
description: tool68.description,
|
|
452
|
+
schema: tool68.schema,
|
|
453
453
|
// StructuredTool的schema已经是Zod兼容的
|
|
454
454
|
needUserApprove: false
|
|
455
455
|
// MCP工具默认不需要用户批准
|
|
@@ -457,7 +457,7 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
|
|
|
457
457
|
const toolLattice = {
|
|
458
458
|
key: key5,
|
|
459
459
|
config,
|
|
460
|
-
client:
|
|
460
|
+
client: tool68
|
|
461
461
|
};
|
|
462
462
|
this.register(key5, toolLattice);
|
|
463
463
|
}
|
|
@@ -468,14 +468,14 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
|
|
|
468
468
|
* @param key - tool lattice key (no tenant prefix)
|
|
469
469
|
* @param tool - the StructuredTool client
|
|
470
470
|
*/
|
|
471
|
-
registerExistingToolWithTenant(tenantId2, key5,
|
|
471
|
+
registerExistingToolWithTenant(tenantId2, key5, tool68) {
|
|
472
472
|
const config = {
|
|
473
|
-
name:
|
|
474
|
-
description:
|
|
475
|
-
schema:
|
|
473
|
+
name: tool68.name,
|
|
474
|
+
description: tool68.description,
|
|
475
|
+
schema: tool68.schema,
|
|
476
476
|
needUserApprove: false
|
|
477
477
|
};
|
|
478
|
-
const toolLattice = { key: key5, config, client:
|
|
478
|
+
const toolLattice = { key: key5, config, client: tool68 };
|
|
479
479
|
this.registerWithTenant(tenantId2, key5, toolLattice);
|
|
480
480
|
}
|
|
481
481
|
/**
|
|
@@ -525,8 +525,8 @@ var ToolLatticeManager = class _ToolLatticeManager extends BaseLatticeManager {
|
|
|
525
525
|
};
|
|
526
526
|
var toolLatticeManager = ToolLatticeManager.getInstance();
|
|
527
527
|
var registerToolLattice = (key5, config, executor) => toolLatticeManager.registerLattice(key5, config, executor);
|
|
528
|
-
var registerExistingTool = (key5,
|
|
529
|
-
var registerExistingToolWithTenant = (tenantId2, key5,
|
|
528
|
+
var registerExistingTool = (key5, tool68) => toolLatticeManager.registerExistingTool(key5, tool68);
|
|
529
|
+
var registerExistingToolWithTenant = (tenantId2, key5, tool68) => toolLatticeManager.registerExistingToolWithTenant(tenantId2, key5, tool68);
|
|
530
530
|
var getToolLattice = (key5) => toolLatticeManager.getToolLattice(key5);
|
|
531
531
|
var getToolClientWithTenant = (tenantId2, key5) => toolLatticeManager.getToolClientWithTenant(tenantId2, key5);
|
|
532
532
|
var getToolDefinition = (key5) => toolLatticeManager.getToolDefinition(key5);
|
|
@@ -1363,15 +1363,15 @@ ${body}` : `${frontmatter}
|
|
|
1363
1363
|
const resourcesDir = path.join(skillDir, "resources");
|
|
1364
1364
|
try {
|
|
1365
1365
|
const entries = await fs.readdir(resourcesDir, { withFileTypes: true, recursive: true });
|
|
1366
|
-
const
|
|
1366
|
+
const resources2 = [];
|
|
1367
1367
|
for (const entry of entries) {
|
|
1368
1368
|
if (!entry.isDirectory()) {
|
|
1369
1369
|
const fullPath = path.join(entry.path, entry.name);
|
|
1370
1370
|
const relativePath = path.relative(resourcesDir, fullPath);
|
|
1371
|
-
|
|
1371
|
+
resources2.push(relativePath.replace(/\\/g, "/"));
|
|
1372
1372
|
}
|
|
1373
1373
|
}
|
|
1374
|
-
return
|
|
1374
|
+
return resources2.sort();
|
|
1375
1375
|
} catch (error) {
|
|
1376
1376
|
if (error.code === "ENOENT") {
|
|
1377
1377
|
return [];
|
|
@@ -11661,11 +11661,11 @@ var PluginRegistry = class {
|
|
|
11661
11661
|
if (!isRecord2(rawDefinition) || typeof rawDefinition.version !== "string" || rawDefinition.version.trim().length === 0 || typeof rawDefinition.content !== "string") {
|
|
11662
11662
|
throw new Error(`Plugin "${key5}": skill "${name}" version and content must be a string`);
|
|
11663
11663
|
}
|
|
11664
|
-
const
|
|
11665
|
-
if (
|
|
11664
|
+
const resources2 = rawDefinition.resources;
|
|
11665
|
+
if (resources2 !== void 0 && !isRecord2(resources2)) {
|
|
11666
11666
|
throw new Error(`Plugin "${key5}": skill "${name}" resources must be an object`);
|
|
11667
11667
|
}
|
|
11668
|
-
for (const [path8, resource] of Object.entries(
|
|
11668
|
+
for (const [path8, resource] of Object.entries(resources2 ?? {})) {
|
|
11669
11669
|
try {
|
|
11670
11670
|
validateRelativePath(path8, "resource");
|
|
11671
11671
|
} catch {
|
|
@@ -12818,7 +12818,7 @@ function isSafeUiPath(path8) {
|
|
|
12818
12818
|
}
|
|
12819
12819
|
function validateSandboxPluginManifest(args) {
|
|
12820
12820
|
const diagnostics = [];
|
|
12821
|
-
const error = (code, message, pluginType,
|
|
12821
|
+
const error = (code, message, pluginType, tool68) => diagnostics.push({ level: "error", code, message, pluginType, tool: tool68 });
|
|
12822
12822
|
const raw = args.raw;
|
|
12823
12823
|
if (!isRecord5(raw)) {
|
|
12824
12824
|
error("MANIFEST_NOT_OBJECT", "manifest must be a JSON object", args.dirName);
|
|
@@ -13826,9 +13826,9 @@ function freezeMetadata(metadata) {
|
|
|
13826
13826
|
...resourceSelector ? { resourceSelector } : {}
|
|
13827
13827
|
});
|
|
13828
13828
|
}
|
|
13829
|
-
function toolName(
|
|
13830
|
-
if (typeof
|
|
13831
|
-
return typeof
|
|
13829
|
+
function toolName(tool68) {
|
|
13830
|
+
if (typeof tool68 !== "object" || tool68 === null || !("name" in tool68)) return void 0;
|
|
13831
|
+
return typeof tool68.name === "string" ? tool68.name : void 0;
|
|
13832
13832
|
}
|
|
13833
13833
|
function schemaHasConnectionKey(schema6) {
|
|
13834
13834
|
const definition = isRecord7(schema6._def) ? schema6._def : void 0;
|
|
@@ -13836,10 +13836,10 @@ function schemaHasConnectionKey(schema6) {
|
|
|
13836
13836
|
const fields = typeof shape === "function" ? shape() : shape;
|
|
13837
13837
|
return isRecord7(fields) && Object.prototype.hasOwnProperty.call(fields, "connectionKey");
|
|
13838
13838
|
}
|
|
13839
|
-
function hasConnectionKeySchema(
|
|
13840
|
-
if (!isRecord7(
|
|
13841
|
-
if (schemaHasConnectionKey(
|
|
13842
|
-
const definition = isRecord7(
|
|
13839
|
+
function hasConnectionKeySchema(tool68) {
|
|
13840
|
+
if (!isRecord7(tool68) || !isRecord7(tool68.schema)) return false;
|
|
13841
|
+
if (schemaHasConnectionKey(tool68.schema)) return true;
|
|
13842
|
+
const definition = isRecord7(tool68.schema._def) ? tool68.schema._def : void 0;
|
|
13843
13843
|
if (Array.isArray(definition?.options) && definition.options.length > 0) {
|
|
13844
13844
|
return definition.options.every(
|
|
13845
13845
|
(option) => isRecord7(option) && schemaHasConnectionKey(option)
|
|
@@ -13894,8 +13894,8 @@ var CapabilityToolRegistry = class {
|
|
|
13894
13894
|
* @remarks Standard connection authorization is captured only for tools whose
|
|
13895
13895
|
* schema declares `connectionKey`; legacy selectors remain explicit metadata.
|
|
13896
13896
|
*/
|
|
13897
|
-
register(name, metadata,
|
|
13898
|
-
this.registerInternal(name, metadata, hasConnectionKeySchema(
|
|
13897
|
+
register(name, metadata, tool68) {
|
|
13898
|
+
this.registerInternal(name, metadata, hasConnectionKeySchema(tool68));
|
|
13899
13899
|
}
|
|
13900
13900
|
/**
|
|
13901
13901
|
* Registers all tools actually exposed by a middleware instance.
|
|
@@ -13906,13 +13906,13 @@ var CapabilityToolRegistry = class {
|
|
|
13906
13906
|
* @returns Nothing.
|
|
13907
13907
|
*/
|
|
13908
13908
|
registerMiddleware(capabilityType, middleware, resourceSelectors = {}) {
|
|
13909
|
-
for (const
|
|
13910
|
-
const name = toolName(
|
|
13909
|
+
for (const tool68 of middleware.tools ?? []) {
|
|
13910
|
+
const name = toolName(tool68);
|
|
13911
13911
|
if (name) {
|
|
13912
13912
|
this.registerInternal(name, {
|
|
13913
13913
|
capabilityType,
|
|
13914
13914
|
resourceSelector: resourceSelectors[name]
|
|
13915
|
-
}, hasConnectionKeySchema(
|
|
13915
|
+
}, hasConnectionKeySchema(tool68));
|
|
13916
13916
|
}
|
|
13917
13917
|
}
|
|
13918
13918
|
}
|
|
@@ -14604,9 +14604,9 @@ var ReActAgentGraphBuilder = class {
|
|
|
14604
14604
|
*/
|
|
14605
14605
|
async build(agentLattice, params) {
|
|
14606
14606
|
const tools = params.tools.map((t) => {
|
|
14607
|
-
const
|
|
14608
|
-
return
|
|
14609
|
-
}).filter((
|
|
14607
|
+
const tool68 = getToolClientWithTenant(params.tenantId ?? "default", t.key);
|
|
14608
|
+
return tool68;
|
|
14609
|
+
}).filter((tool68) => tool68 !== void 0);
|
|
14610
14610
|
const stateSchema2 = createReactAgentSchema(params.stateSchema);
|
|
14611
14611
|
const middlewareConfigs = params.middleware || [];
|
|
14612
14612
|
const filesystemBackend = createFilesystemBackendFactory(middlewareConfigs);
|
|
@@ -15779,8 +15779,8 @@ function validateCapability(value, index) {
|
|
|
15779
15779
|
fieldPath: `/capabilities/${index}/allowedTools`
|
|
15780
15780
|
});
|
|
15781
15781
|
}
|
|
15782
|
-
for (const [toolIndex,
|
|
15783
|
-
if (typeof
|
|
15782
|
+
for (const [toolIndex, tool68] of capability.allowedTools.entries()) {
|
|
15783
|
+
if (typeof tool68 !== "string") {
|
|
15784
15784
|
throw new CapabilityBundleValidationError(
|
|
15785
15785
|
"CAPABILITY_BUNDLE_INVALID_CAPABILITY",
|
|
15786
15786
|
"allowedTools entries must be strings",
|
|
@@ -15794,10 +15794,10 @@ function validateCapability(value, index) {
|
|
|
15794
15794
|
fieldPath: `/capabilities/${index}/allowedTools`
|
|
15795
15795
|
});
|
|
15796
15796
|
}
|
|
15797
|
-
const toolNames = new Set(plugin.meta.tools.map((
|
|
15798
|
-
for (const [toolIndex,
|
|
15799
|
-
if (typeof
|
|
15800
|
-
throw new CapabilityBundleValidationError("CAPABILITY_BUNDLE_UNKNOWN_TOOL", `Unknown tool '${String(
|
|
15797
|
+
const toolNames = new Set(plugin.meta.tools.map((tool68) => tool68.name));
|
|
15798
|
+
for (const [toolIndex, tool68] of capability.allowedTools.entries()) {
|
|
15799
|
+
if (typeof tool68 !== "string" || !toolNames.has(tool68)) {
|
|
15800
|
+
throw new CapabilityBundleValidationError("CAPABILITY_BUNDLE_UNKNOWN_TOOL", `Unknown tool '${String(tool68)}'`, {
|
|
15801
15801
|
capabilityType,
|
|
15802
15802
|
fieldPath: `/capabilities/${index}/allowedTools/${toolIndex}`
|
|
15803
15803
|
});
|
|
@@ -16280,7 +16280,7 @@ function applyStaticCeiling(capabilities, staticMiddleware) {
|
|
|
16280
16280
|
const projectTools = capability.allowedTools;
|
|
16281
16281
|
const staticTools = ceiling.allowedTools;
|
|
16282
16282
|
const effectiveStaticTools = staticTools?.length === 0 ? void 0 : staticTools;
|
|
16283
|
-
const allowedTools = projectTools === void 0 ? effectiveStaticTools : effectiveStaticTools === void 0 ? projectTools : projectTools.filter((
|
|
16283
|
+
const allowedTools = projectTools === void 0 ? effectiveStaticTools : effectiveStaticTools === void 0 ? projectTools : projectTools.filter((tool68) => effectiveStaticTools.includes(tool68));
|
|
16284
16284
|
runtime[capability.type] = structuredClone({
|
|
16285
16285
|
...capability,
|
|
16286
16286
|
config: applyStaticResourceCeiling(capability, ceiling),
|
|
@@ -22040,7 +22040,7 @@ var DeepAgentGraphBuilder = class {
|
|
|
22040
22040
|
const tools = params.tools.map((t) => {
|
|
22041
22041
|
const toolClient = getToolClientWithTenant(params.tenantId ?? "default", t.key);
|
|
22042
22042
|
return toolClient;
|
|
22043
|
-
}).filter((
|
|
22043
|
+
}).filter((tool68) => tool68 !== void 0);
|
|
22044
22044
|
const subagents = await Promise.all(params.subAgents.map(async (sa) => {
|
|
22045
22045
|
if (sa.client) {
|
|
22046
22046
|
return {
|
|
@@ -23688,7 +23688,7 @@ var TeamAgentGraphBuilder = class {
|
|
|
23688
23688
|
const tools = params.tools.map((t) => {
|
|
23689
23689
|
const toolClient = getToolClientWithTenant(params.tenantId ?? "default", t.key);
|
|
23690
23690
|
return toolClient;
|
|
23691
|
-
}).filter((
|
|
23691
|
+
}).filter((tool68) => tool68 !== void 0);
|
|
23692
23692
|
const teammates = params.subAgents.map((sa) => {
|
|
23693
23693
|
const baseConfig = sa.config;
|
|
23694
23694
|
return {
|
|
@@ -28080,7 +28080,7 @@ function requireSkillDeclaration(skillLoaded) {
|
|
|
28080
28080
|
return void 0;
|
|
28081
28081
|
}
|
|
28082
28082
|
async function validateAgentReferences(input, tenantId2) {
|
|
28083
|
-
const availableTools = getAvailableTools(tenantId2).map((
|
|
28083
|
+
const availableTools = getAvailableTools(tenantId2).map((tool68) => tool68.key);
|
|
28084
28084
|
const availableMiddlewareTypes = getAvailableMiddlewareTypes();
|
|
28085
28085
|
const availableCustomMiddlewareKeys = CustomMiddlewareRegistry.list().filter(
|
|
28086
28086
|
(key5) => CustomMiddlewareRegistry.get(key5) !== void 0
|
|
@@ -28847,7 +28847,7 @@ var agentArchitectConfig = {
|
|
|
28847
28847
|
"delete_agent",
|
|
28848
28848
|
"manage_binding"
|
|
28849
28849
|
],
|
|
28850
|
-
subAgents: ["document-parser-benchmark"],
|
|
28850
|
+
subAgents: ["document-parser", "document-parser-benchmark"],
|
|
28851
28851
|
middleware: [
|
|
28852
28852
|
{
|
|
28853
28853
|
id: "filesystem",
|
|
@@ -30552,6 +30552,7 @@ async function removeCollectionVectorStore(name, tenantId2) {
|
|
|
30552
30552
|
|
|
30553
30553
|
// src/mcp_lattice/McpLatticeManager.ts
|
|
30554
30554
|
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
|
|
30555
|
+
import { DynamicStructuredTool as DynamicStructuredTool2 } from "@langchain/core/tools";
|
|
30555
30556
|
|
|
30556
30557
|
// src/mcp_lattice/reconnectPolicy.ts
|
|
30557
30558
|
var DEFAULT_CONNECT_TIMEOUT_MS = 15e3;
|
|
@@ -30560,6 +30561,13 @@ var DEFAULT_DELAY_MS = 1e3;
|
|
|
30560
30561
|
var MAX_BACKOFF_MS = 3e4;
|
|
30561
30562
|
var HEALTH_CHECK_INTERVAL_MS = 3e4;
|
|
30562
30563
|
var HEALTH_CHECK_TIMEOUT_MS = 5e3;
|
|
30564
|
+
function isMcpConnectionError(error) {
|
|
30565
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
30566
|
+
if (!message) return false;
|
|
30567
|
+
return /not connected|connection closed|session not found|no session|maximum reconnection/i.test(
|
|
30568
|
+
message
|
|
30569
|
+
);
|
|
30570
|
+
}
|
|
30563
30571
|
function nextBackoffDelay(attempt, base = DEFAULT_DELAY_MS, max = MAX_BACKOFF_MS) {
|
|
30564
30572
|
if (attempt <= 0) return base;
|
|
30565
30573
|
return Math.min(base * Math.pow(2, attempt - 1), max);
|
|
@@ -30584,12 +30592,21 @@ async function withTimeout(operation, ms, onTimeout) {
|
|
|
30584
30592
|
|
|
30585
30593
|
// src/mcp_lattice/McpLatticeManager.ts
|
|
30586
30594
|
var realClientFactory = ({ mcpServers }) => new MultiServerMCPClient({ mcpServers });
|
|
30595
|
+
function extractRawCall(tool68) {
|
|
30596
|
+
const rawCall = tool68._call;
|
|
30597
|
+
if (typeof rawCall === "function") return rawCall.bind(tool68);
|
|
30598
|
+
return async (...args) => {
|
|
30599
|
+
const invoke = tool68.invoke.bind(tool68);
|
|
30600
|
+
return invoke(args[0], args[2]);
|
|
30601
|
+
};
|
|
30602
|
+
}
|
|
30587
30603
|
var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
30588
30604
|
constructor() {
|
|
30589
30605
|
super(...arguments);
|
|
30590
30606
|
this.runtimes = /* @__PURE__ */ new Map();
|
|
30591
30607
|
this.clientFactory = realClientFactory;
|
|
30592
30608
|
this.healthCheckInFlight = false;
|
|
30609
|
+
this.reconnectPromises = /* @__PURE__ */ new Map();
|
|
30593
30610
|
}
|
|
30594
30611
|
static getInstance() {
|
|
30595
30612
|
if (!_McpLatticeManager._instance) {
|
|
@@ -30847,6 +30864,64 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
30847
30864
|
rt.attempt = 0;
|
|
30848
30865
|
await this.reconnectRuntime(rt);
|
|
30849
30866
|
}
|
|
30867
|
+
/**
|
|
30868
|
+
* Single-flight a forced reconnect per `(tenantId, serverKey)` so concurrent
|
|
30869
|
+
* tool calls that all hit the same dead session reconnect once, not once each.
|
|
30870
|
+
*/
|
|
30871
|
+
reconnectShared(rt) {
|
|
30872
|
+
const key5 = this.compositeKey(rt.id.tenantId, rt.id.serverKey);
|
|
30873
|
+
const existing = this.reconnectPromises.get(key5);
|
|
30874
|
+
if (existing) return existing;
|
|
30875
|
+
const work = this.reconnectServer(rt.id.tenantId, rt.id.serverKey).finally(() => {
|
|
30876
|
+
if (this.reconnectPromises.get(key5) === work) this.reconnectPromises.delete(key5);
|
|
30877
|
+
});
|
|
30878
|
+
this.reconnectPromises.set(key5, work);
|
|
30879
|
+
return work;
|
|
30880
|
+
}
|
|
30881
|
+
/**
|
|
30882
|
+
* Wrap a raw MCP tool so a call landing on a torn-down session
|
|
30883
|
+
* (`Not connected` / `Connection closed` / session expiry) transparently
|
|
30884
|
+
* forces a reconnect and retries once against the fresh client, instead of
|
|
30885
|
+
* failing the surrounding run. Non-connection errors propagate untouched.
|
|
30886
|
+
*/
|
|
30887
|
+
wrapToolForResilience(rt, raw) {
|
|
30888
|
+
const call = extractRawCall(raw);
|
|
30889
|
+
return new DynamicStructuredTool2({
|
|
30890
|
+
name: raw.name,
|
|
30891
|
+
description: raw.description,
|
|
30892
|
+
schema: raw.schema,
|
|
30893
|
+
responseFormat: raw.responseFormat,
|
|
30894
|
+
defaultConfig: raw.defaultConfig,
|
|
30895
|
+
metadata: raw.metadata,
|
|
30896
|
+
returnDirect: raw.returnDirect,
|
|
30897
|
+
func: async (...args) => this.invokeResilient(rt, raw.name, call, args)
|
|
30898
|
+
});
|
|
30899
|
+
}
|
|
30900
|
+
async invokeResilient(rt, toolName2, call, args) {
|
|
30901
|
+
try {
|
|
30902
|
+
await this.ensureConnected(rt.id.tenantId, rt.id.serverKey);
|
|
30903
|
+
return await call(...args);
|
|
30904
|
+
} catch (error) {
|
|
30905
|
+
if (!isMcpConnectionError(error) || !this.isActive(rt)) throw error;
|
|
30906
|
+
console.warn(
|
|
30907
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: tool "${toolName2}" hit a dead session; reconnecting and retrying once`,
|
|
30908
|
+
error instanceof Error ? error.message : error
|
|
30909
|
+
);
|
|
30910
|
+
try {
|
|
30911
|
+
await this.reconnectShared(rt);
|
|
30912
|
+
} catch (reconnectError) {
|
|
30913
|
+
console.warn(
|
|
30914
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: reconnect for tool "${toolName2}" failed`,
|
|
30915
|
+
reconnectError instanceof Error ? reconnectError.message : reconnectError
|
|
30916
|
+
);
|
|
30917
|
+
throw error;
|
|
30918
|
+
}
|
|
30919
|
+
const fresh = await this.getRawTools(rt.id.tenantId, rt.id.serverKey);
|
|
30920
|
+
const match = fresh.find((t) => t.name === toolName2);
|
|
30921
|
+
if (!match) throw error;
|
|
30922
|
+
return await extractRawCall(match)(...args);
|
|
30923
|
+
}
|
|
30924
|
+
}
|
|
30850
30925
|
async checkHealth() {
|
|
30851
30926
|
if (this.healthCheckInFlight) return;
|
|
30852
30927
|
this.healthCheckInFlight = true;
|
|
@@ -30865,8 +30940,12 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
30865
30940
|
await withTimeout(session.listTools(), HEALTH_CHECK_TIMEOUT_MS, async () => {
|
|
30866
30941
|
});
|
|
30867
30942
|
if (!this.isActive(rt) || rt.state !== "connected") continue;
|
|
30868
|
-
} catch {
|
|
30943
|
+
} catch (error) {
|
|
30869
30944
|
if (this.isActive(rt) && rt.state === "connected") {
|
|
30945
|
+
console.warn(
|
|
30946
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: health check failed; scheduling reconnect`,
|
|
30947
|
+
error instanceof Error ? error.message : error
|
|
30948
|
+
);
|
|
30870
30949
|
rt.state = "failed";
|
|
30871
30950
|
this.scheduleReconnect(rt);
|
|
30872
30951
|
}
|
|
@@ -31065,15 +31144,16 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
31065
31144
|
const metaByName = new Map(metaList.map((m) => [m.name, m.meta]));
|
|
31066
31145
|
this.unregisterServerTools(tenantId2, serverKey);
|
|
31067
31146
|
const keys = [];
|
|
31068
|
-
for (const
|
|
31069
|
-
if (rt.selectedTools && !rt.selectedTools.includes(
|
|
31070
|
-
const meta = metaByName.get(
|
|
31147
|
+
for (const tool68 of tools) {
|
|
31148
|
+
if (rt.selectedTools && !rt.selectedTools.includes(tool68.name)) continue;
|
|
31149
|
+
const meta = metaByName.get(tool68.name);
|
|
31071
31150
|
const rawVisibility = meta?.ui?.visibility;
|
|
31072
31151
|
const visibility = Array.isArray(rawVisibility) ? rawVisibility : typeof rawVisibility === "string" ? [rawVisibility] : void 0;
|
|
31073
31152
|
if (visibility && !visibility.includes("model")) continue;
|
|
31074
31153
|
const ref = extractAppsRef(meta, serverKey);
|
|
31075
|
-
const
|
|
31076
|
-
const
|
|
31154
|
+
const resilient = this.wrapToolForResilience(rt, tool68);
|
|
31155
|
+
const registered = ref ? wrapMcpToolWithUi(resilient, ref) : resilient;
|
|
31156
|
+
const toolKey = _McpLatticeManager.buildToolKey(serverKey, tool68.name);
|
|
31077
31157
|
try {
|
|
31078
31158
|
toolLatticeManager.registerExistingToolWithTenant(tenantId2, toolKey, registered);
|
|
31079
31159
|
keys.push(toolKey);
|
|
@@ -31141,6 +31221,7 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
31141
31221
|
}
|
|
31142
31222
|
}
|
|
31143
31223
|
this.runtimes.clear();
|
|
31224
|
+
this.reconnectPromises.clear();
|
|
31144
31225
|
}
|
|
31145
31226
|
};
|
|
31146
31227
|
var mcpManager = McpLatticeManager.getInstance();
|
|
@@ -35240,7 +35321,7 @@ function snapshotDate(value) {
|
|
|
35240
35321
|
|
|
35241
35322
|
// src/services/TaskLifecycleService.ts
|
|
35242
35323
|
import { createHash as createHash6 } from "crypto";
|
|
35243
|
-
import { parseTaskBeliefState, replaceTaskBeliefState,
|
|
35324
|
+
import { parseTaskBeliefState, replaceTaskBeliefState, taskBeliefStatesEqual } from "@axiom-lattice/protocols";
|
|
35244
35325
|
|
|
35245
35326
|
// src/middlewares/taskBelief.ts
|
|
35246
35327
|
import { createHash as createHash5 } from "crypto";
|
|
@@ -35352,14 +35433,6 @@ async function applyBeliefImpacts(taskStore, owner, impacts) {
|
|
|
35352
35433
|
}
|
|
35353
35434
|
return { description: current.description ?? "", task: current };
|
|
35354
35435
|
}
|
|
35355
|
-
function parseExternalDependency(value) {
|
|
35356
|
-
const row = snapshotExactRecord7(value, ["type", "summary", "requestedAt", "dependencyTaskIds"]);
|
|
35357
|
-
const ids = snapshotExactArray2(row?.dependencyTaskIds);
|
|
35358
|
-
if (!row || row.type !== "external_dependency" || typeof row.summary !== "string" || !row.summary.trim() || typeof row.requestedAt !== "string" || !Number.isFinite(Date.parse(row.requestedAt)) || !ids || ids.length === 0 || ids.some((id) => typeof id !== "string" || !id.trim())) return void 0;
|
|
35359
|
-
const trimmed = ids.map((id) => id.trim());
|
|
35360
|
-
if (new Set(trimmed).size !== trimmed.length) return void 0;
|
|
35361
|
-
return { type: "external_dependency", summary: row.summary, requestedAt: row.requestedAt, dependencyTaskIds: trimmed };
|
|
35362
|
-
}
|
|
35363
35436
|
function unsupportedTaskStatus() {
|
|
35364
35437
|
return failure2(
|
|
35365
35438
|
"TASK_STATUS_UNSUPPORTED",
|
|
@@ -35658,9 +35731,6 @@ var TaskLifecycleService = class {
|
|
|
35658
35731
|
if (interruption && typeof interruption === "object" && interruption.type === "review_required") {
|
|
35659
35732
|
return failure2("REVIEW_APPROVAL_REQUIRED", "Review interruption requires explicit approval or rejection.");
|
|
35660
35733
|
}
|
|
35661
|
-
if (interruption && typeof interruption === "object" && interruption.type === "external_dependency" && !parseExternalDependency(interruption)) {
|
|
35662
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "Stored external dependency interruption is malformed.");
|
|
35663
|
-
}
|
|
35664
35734
|
const previousInterruption = interruption && typeof interruption === "object" ? interruption : {};
|
|
35665
35735
|
const resumeKey = this.resumeEventKey(task);
|
|
35666
35736
|
const audit = { eventKey: resumeKey, previousInterruption };
|
|
@@ -35841,6 +35911,108 @@ var TaskLifecycleService = class {
|
|
|
35841
35911
|
detail: { previousStatus: "failed" }
|
|
35842
35912
|
});
|
|
35843
35913
|
}
|
|
35914
|
+
/**
|
|
35915
|
+
* Reopens a terminal agent task by returning it to in_progress.
|
|
35916
|
+
*
|
|
35917
|
+
* @param input Task, actor, and optional thread.
|
|
35918
|
+
* @returns Structured lifecycle result. `completed` and `cancelled` tasks
|
|
35919
|
+
* reopen to `in_progress`; an already-`in_progress` task is acknowledged
|
|
35920
|
+
* without mutation; any other status or a lost CAS yields
|
|
35921
|
+
* `TASK_STATUS_CONFLICT`.
|
|
35922
|
+
* @remarks This is the single reverse edge of the terminal-irreversibility
|
|
35923
|
+
* relaxation. It records the status change only; re-dispatch is owned by
|
|
35924
|
+
* the application layer and is never triggered here.
|
|
35925
|
+
*/
|
|
35926
|
+
async reopenTask(input) {
|
|
35927
|
+
return this.transitionAgentTask({
|
|
35928
|
+
...input,
|
|
35929
|
+
targetStatus: "in_progress",
|
|
35930
|
+
expectedStatuses: ["completed", "cancelled"],
|
|
35931
|
+
updates: { status: "in_progress", failureReason: null, result: null },
|
|
35932
|
+
summary: "Task reopened",
|
|
35933
|
+
detail: { type: "reopen" }
|
|
35934
|
+
});
|
|
35935
|
+
}
|
|
35936
|
+
/**
|
|
35937
|
+
* Transfers a human-authored task's ownership to a chosen Agent before dispatch.
|
|
35938
|
+
*
|
|
35939
|
+
* @param input Task, actor, destination Agent, and optional Task Thread.
|
|
35940
|
+
* @returns Structured result with the reassigned owner and an `owner_assigned` audit.
|
|
35941
|
+
* @remarks Only tasks with `context.source === "user"` can be assigned this way.
|
|
35942
|
+
* Repeated assignment to the same owner is idempotent (repair-writes the audit
|
|
35943
|
+
* without a CAS). This changes owner only, never status, so it publishes no
|
|
35944
|
+
* Project lifecycle notification.
|
|
35945
|
+
*/
|
|
35946
|
+
async assignOwner(input) {
|
|
35947
|
+
let task;
|
|
35948
|
+
try {
|
|
35949
|
+
task = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
35950
|
+
} catch {
|
|
35951
|
+
return failure2("TASK_STORE_READ_FAILED", "Failed to read task lifecycle state.");
|
|
35952
|
+
}
|
|
35953
|
+
if (!task) return failure2("TASK_NOT_FOUND", "Task was not found.");
|
|
35954
|
+
if (task.context?.source !== "user") {
|
|
35955
|
+
return failure2("TASK_NOT_HUMAN_MANAGED", "Only user-authored tasks can be assigned to an Agent.");
|
|
35956
|
+
}
|
|
35957
|
+
const storedThreadId = typeof task.context?.thread_id === "string" && task.context.thread_id.length > 0 ? task.context.thread_id : void 0;
|
|
35958
|
+
const effectiveThreadId = storedThreadId ?? input.threadId;
|
|
35959
|
+
const detail = { type: "owner_assigned", fromOwnerType: task.ownerType, toOwnerId: input.ownerId };
|
|
35960
|
+
if (task.ownerType === "agent" && task.ownerId === input.ownerId && (input.threadId === void 0 || storedThreadId === input.threadId)) {
|
|
35961
|
+
const eventKey2 = this.statusEventKey(task, "owner_assigned", detail);
|
|
35962
|
+
const event2 = await this.writeStatusEvent(
|
|
35963
|
+
task,
|
|
35964
|
+
input.actor,
|
|
35965
|
+
effectiveThreadId,
|
|
35966
|
+
"activity",
|
|
35967
|
+
"Task owner assigned",
|
|
35968
|
+
detail,
|
|
35969
|
+
eventKey2
|
|
35970
|
+
);
|
|
35971
|
+
return {
|
|
35972
|
+
success: true,
|
|
35973
|
+
task,
|
|
35974
|
+
mutated: false,
|
|
35975
|
+
eventKey: event2.eventKey,
|
|
35976
|
+
...event2.warning ? { warnings: [event2.warning] } : {}
|
|
35977
|
+
};
|
|
35978
|
+
}
|
|
35979
|
+
const context = { ...task.context ?? {} };
|
|
35980
|
+
if (input.threadId && !storedThreadId) context.thread_id = input.threadId;
|
|
35981
|
+
let updated;
|
|
35982
|
+
try {
|
|
35983
|
+
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
35984
|
+
input.tenantId,
|
|
35985
|
+
input.taskId,
|
|
35986
|
+
{ ownerType: "agent", ownerId: input.ownerId, context },
|
|
35987
|
+
[task.status],
|
|
35988
|
+
task.updatedAt
|
|
35989
|
+
);
|
|
35990
|
+
} catch {
|
|
35991
|
+
return failure2(
|
|
35992
|
+
"TASK_STORE_WRITE_FAILED",
|
|
35993
|
+
"Failed to assign the task owner.",
|
|
35994
|
+
"The store rejected the write."
|
|
35995
|
+
);
|
|
35996
|
+
}
|
|
35997
|
+
if (!updated) return failure2("TASK_STATUS_CONFLICT", "Task changed concurrently.");
|
|
35998
|
+
const eventKey = this.statusEventKey(updated, "owner_assigned", detail);
|
|
35999
|
+
const event = await this.writeStatusEvent(
|
|
36000
|
+
updated,
|
|
36001
|
+
input.actor,
|
|
36002
|
+
effectiveThreadId,
|
|
36003
|
+
"activity",
|
|
36004
|
+
"Task owner assigned",
|
|
36005
|
+
detail,
|
|
36006
|
+
eventKey
|
|
36007
|
+
);
|
|
36008
|
+
return {
|
|
36009
|
+
success: true,
|
|
36010
|
+
task: updated,
|
|
36011
|
+
mutated: true,
|
|
36012
|
+
eventKey: event.eventKey,
|
|
36013
|
+
...event.warning ? { warnings: [event.warning] } : {}
|
|
36014
|
+
};
|
|
36015
|
+
}
|
|
35844
36016
|
/** Atomically cancels a nonterminal agent task and records an idempotent status event. */
|
|
35845
36017
|
async cancelTask(input) {
|
|
35846
36018
|
return this.transitionAgentTask({
|
|
@@ -35921,19 +36093,7 @@ var TaskLifecycleService = class {
|
|
|
35921
36093
|
async interruptTask(input) {
|
|
35922
36094
|
const summary = input.summary.trim();
|
|
35923
36095
|
if (!summary) return failure2("MISSING_INTERRUPTION_SUMMARY", "Agent interruption requires a nonblank summary.");
|
|
35924
|
-
if (input.type !== "external_dependency" && input.dependencyTaskIds !== void 0) {
|
|
35925
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "dependencyTaskIds are only valid for external dependencies.");
|
|
35926
|
-
}
|
|
35927
36096
|
const requestedAt = this.now().toISOString();
|
|
35928
|
-
const external = input.type === "external_dependency" ? parseExternalDependency({
|
|
35929
|
-
type: input.type,
|
|
35930
|
-
summary,
|
|
35931
|
-
requestedAt,
|
|
35932
|
-
dependencyTaskIds: input.dependencyTaskIds
|
|
35933
|
-
}) : void 0;
|
|
35934
|
-
if (input.type === "external_dependency" && !external) {
|
|
35935
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependencies require exact, unique nonblank task IDs.");
|
|
35936
|
-
}
|
|
35937
36097
|
let task;
|
|
35938
36098
|
try {
|
|
35939
36099
|
task = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
@@ -35947,29 +36107,17 @@ var TaskLifecycleService = class {
|
|
|
35947
36107
|
if (threadFailure) return threadFailure;
|
|
35948
36108
|
const currentInterruption = task.context?.interruption;
|
|
35949
36109
|
if (task.status === "interrupted" && currentInterruption && typeof currentInterruption === "object") {
|
|
35950
|
-
|
|
35951
|
-
if (input.type === "external_dependency") {
|
|
35952
|
-
if (!external || !storedExternal || storedExternal.summary !== external.summary || canonicalJson(storedExternal.dependencyTaskIds) !== canonicalJson(external.dependencyTaskIds)) {
|
|
35953
|
-
return failure2(
|
|
35954
|
-
"TASK_STATUS_CONFLICT",
|
|
35955
|
-
"Task is already interrupted by a different or malformed external dependency.",
|
|
35956
|
-
"Use manage_task get to inspect the existing interruption in task context.interruption."
|
|
35957
|
-
);
|
|
35958
|
-
}
|
|
35959
|
-
} else if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
|
|
36110
|
+
if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
|
|
35960
36111
|
return failure2(
|
|
35961
36112
|
"TASK_STATUS_CONFLICT",
|
|
35962
36113
|
"Task is already interrupted by a different request.",
|
|
35963
36114
|
"Use manage_task get to inspect the existing interruption, or resume it first."
|
|
35964
36115
|
);
|
|
35965
36116
|
}
|
|
35966
|
-
const detail =
|
|
36117
|
+
const detail = currentInterruption;
|
|
35967
36118
|
const eventKey2 = this.statusEventKey(task, "interrupted", detail);
|
|
35968
36119
|
const event2 = await this.writeStatusEvent(task, input.actor, input.threadId, "interrupted", summary, detail, eventKey2);
|
|
35969
36120
|
const warnings2 = event2.warning ? [event2.warning] : [];
|
|
35970
|
-
if (storedExternal && task.workspaceId && task.projectId) {
|
|
35971
|
-
return this.finishExternalDependencyInterruption(task, input, storedExternal, event2, warnings2, false);
|
|
35972
|
-
}
|
|
35973
36121
|
return {
|
|
35974
36122
|
success: true,
|
|
35975
36123
|
task,
|
|
@@ -35985,11 +36133,7 @@ var TaskLifecycleService = class {
|
|
|
35985
36133
|
"Only pending or in_progress tasks can be interrupted. Use manage_task get to check the current status."
|
|
35986
36134
|
);
|
|
35987
36135
|
}
|
|
35988
|
-
|
|
35989
|
-
const dependencyFailure = await this.validateExternalDependencies(task, external.dependencyTaskIds);
|
|
35990
|
-
if (dependencyFailure) return dependencyFailure;
|
|
35991
|
-
}
|
|
35992
|
-
const interruption = external ? { ...external } : { type: input.type, summary, requestedAt };
|
|
36136
|
+
const interruption = { type: input.type, summary, requestedAt };
|
|
35993
36137
|
let updated;
|
|
35994
36138
|
try {
|
|
35995
36139
|
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(input.tenantId, input.taskId, {
|
|
@@ -36011,9 +36155,6 @@ var TaskLifecycleService = class {
|
|
|
36011
36155
|
const eventKey = this.statusEventKey(updated, "interrupted", interruption);
|
|
36012
36156
|
const event = await this.writeStatusEvent(updated, input.actor, input.threadId, "interrupted", summary, interruption, eventKey);
|
|
36013
36157
|
const warnings = event.warning ? [event.warning] : await this.notifyWinningTransition(updated, "interrupted", event);
|
|
36014
|
-
if (external && updated.workspaceId && updated.projectId) {
|
|
36015
|
-
return this.finishExternalDependencyInterruption(updated, input, external, event, warnings, true);
|
|
36016
|
-
}
|
|
36017
36158
|
return {
|
|
36018
36159
|
success: true,
|
|
36019
36160
|
task: updated,
|
|
@@ -37252,7 +37393,9 @@ var TaskLifecycleService = class {
|
|
|
37252
37393
|
};
|
|
37253
37394
|
}
|
|
37254
37395
|
if (!input.expectedStatuses.includes(task.status)) return failure2("TASK_STATUS_CONFLICT", "Task status cannot make this transition.");
|
|
37255
|
-
const
|
|
37396
|
+
const clearedContext = clearInterruptionContext(task.context);
|
|
37397
|
+
const withThread = input.threadId && task.context?.thread_id === void 0 ? { ...clearedContext ?? {}, thread_id: input.threadId } : clearedContext;
|
|
37398
|
+
const updates = { ...input.updates, context: withThread };
|
|
37256
37399
|
let updated;
|
|
37257
37400
|
try {
|
|
37258
37401
|
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
@@ -37340,85 +37483,6 @@ var TaskLifecycleService = class {
|
|
|
37340
37483
|
return [{ code: "LIFECYCLE_NOTIFICATION_FAILED", taskId: task.id, eventKey: event.eventKey }];
|
|
37341
37484
|
}
|
|
37342
37485
|
}
|
|
37343
|
-
async validateExternalDependencies(task, dependencyTaskIds) {
|
|
37344
|
-
const declared = new Set(task.dependencies ?? []);
|
|
37345
|
-
if (dependencyTaskIds.some((id) => id === task.id || !declared.has(id))) {
|
|
37346
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependency IDs must be declared non-self dependencies.");
|
|
37347
|
-
}
|
|
37348
|
-
try {
|
|
37349
|
-
for (const id of dependencyTaskIds) {
|
|
37350
|
-
const dependency = await this.deps.taskStore.getById(task.tenantId, id);
|
|
37351
|
-
if (!dependency || dependency.workspaceId !== task.workspaceId || dependency.projectId !== task.projectId || dependency.status === "completed") {
|
|
37352
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependencies must exist, remain incomplete, and share exact scope.");
|
|
37353
|
-
}
|
|
37354
|
-
}
|
|
37355
|
-
} catch {
|
|
37356
|
-
return failure2("TASK_STORE_READ_FAILED", "Failed to validate external dependencies.");
|
|
37357
|
-
}
|
|
37358
|
-
return void 0;
|
|
37359
|
-
}
|
|
37360
|
-
async externalDependencyReadiness(task, dependencyTaskIds) {
|
|
37361
|
-
try {
|
|
37362
|
-
for (const id of dependencyTaskIds) {
|
|
37363
|
-
const dependency = await this.deps.taskStore.getById(task.tenantId, id);
|
|
37364
|
-
if (!dependency || dependency.workspaceId !== task.workspaceId || dependency.projectId !== task.projectId || dependency.status !== "completed") return { kind: "blocked" };
|
|
37365
|
-
}
|
|
37366
|
-
return { kind: "ready" };
|
|
37367
|
-
} catch {
|
|
37368
|
-
return {
|
|
37369
|
-
kind: "error",
|
|
37370
|
-
warning: { code: "DEPENDENCY_READ_FAILED", taskId: task.id }
|
|
37371
|
-
};
|
|
37372
|
-
}
|
|
37373
|
-
}
|
|
37374
|
-
async finishExternalDependencyInterruption(task, input, interruption, event, warnings, mutated) {
|
|
37375
|
-
if (event.warning) {
|
|
37376
|
-
return { success: true, task, mutated, eventKey: event.eventKey, warnings };
|
|
37377
|
-
}
|
|
37378
|
-
const readiness = await this.externalDependencyReadiness(task, interruption.dependencyTaskIds);
|
|
37379
|
-
if (readiness.kind === "blocked") {
|
|
37380
|
-
return { success: true, task, mutated, eventKey: event.eventKey, ...warnings.length ? { warnings } : {} };
|
|
37381
|
-
}
|
|
37382
|
-
if (readiness.kind === "error") {
|
|
37383
|
-
return {
|
|
37384
|
-
success: true,
|
|
37385
|
-
task,
|
|
37386
|
-
mutated,
|
|
37387
|
-
eventKey: event.eventKey,
|
|
37388
|
-
warnings: [...warnings, { ...readiness.warning, eventKey: event.eventKey }]
|
|
37389
|
-
};
|
|
37390
|
-
}
|
|
37391
|
-
const resumed = await this.resumeInterruption({
|
|
37392
|
-
tenantId: input.tenantId,
|
|
37393
|
-
taskId: input.taskId,
|
|
37394
|
-
actor: input.actor,
|
|
37395
|
-
threadId: input.threadId
|
|
37396
|
-
});
|
|
37397
|
-
if (resumed.success) {
|
|
37398
|
-
const combined = [...warnings, ...resumed.warnings ?? []];
|
|
37399
|
-
return {
|
|
37400
|
-
...resumed,
|
|
37401
|
-
mutated: mutated || resumed.mutated,
|
|
37402
|
-
...combined.length ? { warnings: combined } : {}
|
|
37403
|
-
};
|
|
37404
|
-
}
|
|
37405
|
-
let current;
|
|
37406
|
-
try {
|
|
37407
|
-
current = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
37408
|
-
} catch {
|
|
37409
|
-
return resumed;
|
|
37410
|
-
}
|
|
37411
|
-
if (current?.status === "in_progress" && (!current.context?.thread_id || current.context?.thread_id === input.threadId)) {
|
|
37412
|
-
return {
|
|
37413
|
-
success: true,
|
|
37414
|
-
task: current,
|
|
37415
|
-
mutated,
|
|
37416
|
-
eventKey: event.eventKey,
|
|
37417
|
-
...warnings.length ? { warnings } : {}
|
|
37418
|
-
};
|
|
37419
|
-
}
|
|
37420
|
-
return resumed;
|
|
37421
|
-
}
|
|
37422
37486
|
async clearAuditMarker(task, key5) {
|
|
37423
37487
|
const context = withoutContextKey(task.context, key5);
|
|
37424
37488
|
try {
|
|
@@ -38862,10 +38926,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
|
|
|
38862
38926
|
lockIdentity
|
|
38863
38927
|
);
|
|
38864
38928
|
let result2 = pluginSkill.definition.content;
|
|
38865
|
-
const
|
|
38866
|
-
if (
|
|
38929
|
+
const resources2 = Object.entries(pluginSkill.definition.resources ?? {});
|
|
38930
|
+
if (resources2.length > 0) {
|
|
38867
38931
|
result2 += "\n\n---\n\n**Resources** (synced to the sandbox; use `read_file` to access):\n";
|
|
38868
|
-
for (const [resourcePath, resource] of
|
|
38932
|
+
for (const [resourcePath, resource] of resources2) {
|
|
38869
38933
|
result2 += `- ${resourcePath} (mime type: ${resource.mimeType ?? "not specified"})
|
|
38870
38934
|
`;
|
|
38871
38935
|
}
|
|
@@ -38892,10 +38956,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
|
|
|
38892
38956
|
`/root/.agents/skills/${input.skill_name}/resources`,
|
|
38893
38957
|
{ recursive: false }
|
|
38894
38958
|
);
|
|
38895
|
-
const
|
|
38896
|
-
if (
|
|
38959
|
+
const resources2 = resourcesResult.files.map((f) => f.path.split("/").pop()).filter(Boolean);
|
|
38960
|
+
if (resources2.length > 0) {
|
|
38897
38961
|
result += "\n\n---\n\n**Resources** (use `read_file` tool to access):\n";
|
|
38898
|
-
|
|
38962
|
+
resources2.forEach((r) => {
|
|
38899
38963
|
result += `- ${r}
|
|
38900
38964
|
`;
|
|
38901
38965
|
});
|
|
@@ -39217,1554 +39281,13 @@ var skillPlugin = {
|
|
|
39217
39281
|
})
|
|
39218
39282
|
};
|
|
39219
39283
|
|
|
39220
|
-
// src/middlewares/
|
|
39284
|
+
// src/middlewares/collectionMiddleware.ts
|
|
39221
39285
|
import { createMiddleware as createMiddleware20 } from "langchain";
|
|
39222
39286
|
|
|
39223
|
-
// src/tool_lattice/
|
|
39287
|
+
// src/tool_lattice/collection/list_collections.ts
|
|
39224
39288
|
import z57 from "zod";
|
|
39225
39289
|
import { tool as tool51 } from "langchain";
|
|
39226
39290
|
|
|
39227
|
-
// src/tool_lattice/semantic_metrics/types.ts
|
|
39228
|
-
function readToolRunConfig(exeConfig) {
|
|
39229
|
-
return exeConfig?.configurable?.runConfig;
|
|
39230
|
-
}
|
|
39231
|
-
function resolveDatasourceId(input, exeConfig) {
|
|
39232
|
-
const id = input.datasourceId ?? readToolRunConfig(exeConfig)?.metricsDataSource?.datasourceId;
|
|
39233
|
-
if (id === void 0 || id === null || id === "") {
|
|
39234
|
-
throw new Error("datasourceId is required (provide it or set runConfig.metricsDataSource.datasourceId)");
|
|
39235
|
-
}
|
|
39236
|
-
return Number(id);
|
|
39237
|
-
}
|
|
39238
|
-
function assertDatasourceSelected(scope, datasourceId) {
|
|
39239
|
-
if (scope.unrestricted) return;
|
|
39240
|
-
if (!scope.ids.includes(datasourceId)) {
|
|
39241
|
-
throw new Error(
|
|
39242
|
-
`DATASOURCE_NOT_SELECTED: datasource ${datasourceId} is not in the effective scope [${scope.ids.join(", ")}]`
|
|
39243
|
-
);
|
|
39244
|
-
}
|
|
39245
|
-
}
|
|
39246
|
-
function effectiveDatasourceScope(connectionScope) {
|
|
39247
|
-
return connectionScope.length > 0 ? { unrestricted: false, ids: [...connectionScope] } : { unrestricted: true, ids: [] };
|
|
39248
|
-
}
|
|
39249
|
-
var DDL_DML_KEYWORDS = [
|
|
39250
|
-
"insert",
|
|
39251
|
-
"update",
|
|
39252
|
-
"delete",
|
|
39253
|
-
"drop",
|
|
39254
|
-
"alter",
|
|
39255
|
-
"create",
|
|
39256
|
-
"truncate",
|
|
39257
|
-
"grant",
|
|
39258
|
-
"revoke",
|
|
39259
|
-
"merge",
|
|
39260
|
-
"replace",
|
|
39261
|
-
"upsert"
|
|
39262
|
-
];
|
|
39263
|
-
var DDL_DML_RE = new RegExp(`\\b(?:${DDL_DML_KEYWORDS.join("|")})\\b`, "i");
|
|
39264
|
-
var SELECT_INTO_RE = /\bselect\b[\s\S]*?\binto\b/i;
|
|
39265
|
-
function validateSql(sql) {
|
|
39266
|
-
const trimmed = sql.trim();
|
|
39267
|
-
if (!trimmed) {
|
|
39268
|
-
return { ok: false, reason: "SQL is empty" };
|
|
39269
|
-
}
|
|
39270
|
-
const withoutComments = trimmed.replace(/--[^\n]*/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
39271
|
-
const statements = withoutComments.split(";").map((s) => s.trim()).filter(Boolean);
|
|
39272
|
-
if (statements.length > 1) {
|
|
39273
|
-
return { ok: false, reason: "Multiple statements are not allowed" };
|
|
39274
|
-
}
|
|
39275
|
-
const firstKeyword = withoutComments.trim().split(/\s+/)[0].toLowerCase();
|
|
39276
|
-
if (firstKeyword !== "select" && firstKeyword !== "with") {
|
|
39277
|
-
return { ok: false, reason: `Only SELECT or WITH queries are allowed (got "${firstKeyword}")` };
|
|
39278
|
-
}
|
|
39279
|
-
if (SELECT_INTO_RE.test(withoutComments)) {
|
|
39280
|
-
return { ok: false, reason: "SELECT INTO is not allowed (creates a table)" };
|
|
39281
|
-
}
|
|
39282
|
-
if (DDL_DML_RE.test(withoutComments)) {
|
|
39283
|
-
return { ok: false, reason: "Only read-only queries are allowed (DML/DDL detected)" };
|
|
39284
|
-
}
|
|
39285
|
-
return { ok: true };
|
|
39286
|
-
}
|
|
39287
|
-
|
|
39288
|
-
// src/tool_lattice/semantic_metrics/SemanticMetricsV2Client.ts
|
|
39289
|
-
var NO_CONNECTION_HINT = "No semantic-metrics connection is configured for this tenant. Add a connection of type 'semantic-metrics' for the tenant, then select it (connections) or enable connectAll in the agent's middleware config.";
|
|
39290
|
-
async function resolveMetricsClientFromSelector(selector, scope, connectionKey) {
|
|
39291
|
-
let resolved;
|
|
39292
|
-
try {
|
|
39293
|
-
resolved = await resolvePluginConnections(selector.connectionType, selector, scope);
|
|
39294
|
-
} catch (error) {
|
|
39295
|
-
if (error instanceof Error && error.message === "ConnectionStore not configured") {
|
|
39296
|
-
throw new Error(NO_CONNECTION_HINT);
|
|
39297
|
-
}
|
|
39298
|
-
throw error;
|
|
39299
|
-
}
|
|
39300
|
-
const available = resolved.map((c) => c.key).join(", ");
|
|
39301
|
-
if (resolved.length === 0) {
|
|
39302
|
-
throw new Error(NO_CONNECTION_HINT);
|
|
39303
|
-
}
|
|
39304
|
-
const key5 = connectionKey?.trim() || (resolved.length === 1 ? resolved[0].key : "");
|
|
39305
|
-
if (!key5) {
|
|
39306
|
-
throw new Error(
|
|
39307
|
-
`connectionKey is required. Available connections: ${available}`
|
|
39308
|
-
);
|
|
39309
|
-
}
|
|
39310
|
-
const entry = resolved.find((c) => c.key === key5);
|
|
39311
|
-
if (!entry) {
|
|
39312
|
-
throw new Error(`Connection "${key5}" not found. Available connections: ${available}`);
|
|
39313
|
-
}
|
|
39314
|
-
const config = entry.config;
|
|
39315
|
-
return new SemanticMetricsV2Client(config);
|
|
39316
|
-
}
|
|
39317
|
-
var SemanticMetricsV2Client = class {
|
|
39318
|
-
/**
|
|
39319
|
-
* @param config - Connection configuration (server URL, optional API key and headers).
|
|
39320
|
-
*/
|
|
39321
|
-
constructor(config) {
|
|
39322
|
-
this.config = config;
|
|
39323
|
-
this.baseUrl = config.serverUrl.replace(/\/$/, "");
|
|
39324
|
-
}
|
|
39325
|
-
/**
|
|
39326
|
-
* Build default request headers: `Accept: application/json`, custom headers,
|
|
39327
|
-
* and a Bearer `Authorization` header when an API key is configured.
|
|
39328
|
-
*
|
|
39329
|
-
* @returns Merged headers.
|
|
39330
|
-
*/
|
|
39331
|
-
getHeaders() {
|
|
39332
|
-
const headers = {
|
|
39333
|
-
Accept: "application/json",
|
|
39334
|
-
...this.config.headers ?? {}
|
|
39335
|
-
};
|
|
39336
|
-
if (this.config.apiKey) {
|
|
39337
|
-
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
39338
|
-
}
|
|
39339
|
-
return headers;
|
|
39340
|
-
}
|
|
39341
|
-
/**
|
|
39342
|
-
* Numeric selected resource ids of this connection (normalized).
|
|
39343
|
-
*
|
|
39344
|
-
* Reads `selectedEntities` — the standard connection resource-selection
|
|
39345
|
-
* field written by the connection UI (`connection.discover` + selection).
|
|
39346
|
-
*
|
|
39347
|
-
* @returns The selected resource ids; empty when unrestricted.
|
|
39348
|
-
*/
|
|
39349
|
-
getSelectedEntities() {
|
|
39350
|
-
const raw = this.config.selectedEntities;
|
|
39351
|
-
if (!Array.isArray(raw)) return [];
|
|
39352
|
-
return raw.map((v) => Number(v)).filter((n) => Number.isFinite(n));
|
|
39353
|
-
}
|
|
39354
|
-
/**
|
|
39355
|
-
* Perform a JSON request against the base URL.
|
|
39356
|
-
*
|
|
39357
|
-
* The Metrics Server wraps every response as `{ code, message, data }`. A
|
|
39358
|
-
* `code` of 200 resolves to `data`; any other `code` throws a business error
|
|
39359
|
-
* carrying the server message (regardless of HTTP status). Non-envelope
|
|
39360
|
-
* bodies are returned as-is.
|
|
39361
|
-
*
|
|
39362
|
-
* @param path - Path appended to the base URL (must start with `/`).
|
|
39363
|
-
* @param init - Optional `fetch` init overrides (method, body, per-call headers).
|
|
39364
|
-
* @returns The unwrapped `data` payload of the response envelope.
|
|
39365
|
-
* @throws When the server returns a non-200 `code`, or the HTTP response is not OK.
|
|
39366
|
-
*/
|
|
39367
|
-
async request(path8, init = {}) {
|
|
39368
|
-
const response = await fetch(`${this.baseUrl}${path8}`, {
|
|
39369
|
-
...init,
|
|
39370
|
-
method: init.method ?? "GET",
|
|
39371
|
-
headers: { ...this.getHeaders(), ...init.headers ?? {} }
|
|
39372
|
-
});
|
|
39373
|
-
const text = await response.text().catch(() => "");
|
|
39374
|
-
const parsed = this.parseBody(text);
|
|
39375
|
-
if (parsed?.envelope === true) {
|
|
39376
|
-
if (parsed.code !== 200) {
|
|
39377
|
-
throw new Error(`API ${parsed.code}: ${parsed.message || "Unknown error"}`);
|
|
39378
|
-
}
|
|
39379
|
-
return parsed.data;
|
|
39380
|
-
}
|
|
39381
|
-
if (!response.ok) {
|
|
39382
|
-
throw new Error(`HTTP ${response.status}: ${text || response.statusText}`);
|
|
39383
|
-
}
|
|
39384
|
-
return parsed?.value ?? void 0;
|
|
39385
|
-
}
|
|
39386
|
-
/**
|
|
39387
|
-
* Parse a response body text. Detects the server envelope `{ code, message, data }`.
|
|
39388
|
-
*
|
|
39389
|
-
* @param text - Raw response body text.
|
|
39390
|
-
* @returns `{ envelope: true, code, message, data }` for an envelope body,
|
|
39391
|
-
* `{ envelope: false, value }` for anything else (or `{ envelope: false }` when empty/invalid).
|
|
39392
|
-
*/
|
|
39393
|
-
parseBody(text) {
|
|
39394
|
-
if (!text.trim()) return { envelope: false };
|
|
39395
|
-
try {
|
|
39396
|
-
const value = JSON.parse(text);
|
|
39397
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
39398
|
-
const record = value;
|
|
39399
|
-
if (typeof record.code === "number") {
|
|
39400
|
-
return {
|
|
39401
|
-
envelope: true,
|
|
39402
|
-
code: record.code,
|
|
39403
|
-
message: typeof record.message === "string" ? record.message : void 0,
|
|
39404
|
-
data: record.data
|
|
39405
|
-
};
|
|
39406
|
-
}
|
|
39407
|
-
}
|
|
39408
|
-
return { envelope: false, value };
|
|
39409
|
-
} catch {
|
|
39410
|
-
return { envelope: false, value: text };
|
|
39411
|
-
}
|
|
39412
|
-
}
|
|
39413
|
-
/**
|
|
39414
|
-
* POST a JSON body to a path.
|
|
39415
|
-
*
|
|
39416
|
-
* @param path - Path appended to the base URL.
|
|
39417
|
-
* @param body - Payload serialized as JSON.
|
|
39418
|
-
* @returns Parsed JSON response body.
|
|
39419
|
-
*/
|
|
39420
|
-
post(path8, body) {
|
|
39421
|
-
return this.request(path8, {
|
|
39422
|
-
method: "POST",
|
|
39423
|
-
headers: { "Content-Type": "application/json" },
|
|
39424
|
-
body: JSON.stringify(body)
|
|
39425
|
-
});
|
|
39426
|
-
}
|
|
39427
|
-
/**
|
|
39428
|
-
* PUT a JSON body to a path.
|
|
39429
|
-
*
|
|
39430
|
-
* @param path - Path appended to the base URL.
|
|
39431
|
-
* @param body - Payload serialized as JSON.
|
|
39432
|
-
* @returns Parsed JSON response body.
|
|
39433
|
-
*/
|
|
39434
|
-
put(path8, body) {
|
|
39435
|
-
return this.request(path8, {
|
|
39436
|
-
method: "PUT",
|
|
39437
|
-
headers: { "Content-Type": "application/json" },
|
|
39438
|
-
body: JSON.stringify(body)
|
|
39439
|
-
});
|
|
39440
|
-
}
|
|
39441
|
-
/**
|
|
39442
|
-
* List all datasources.
|
|
39443
|
-
*
|
|
39444
|
-
* @returns Parsed JSON response body.
|
|
39445
|
-
*/
|
|
39446
|
-
listDatasources() {
|
|
39447
|
-
return this.request("/datasources");
|
|
39448
|
-
}
|
|
39449
|
-
/**
|
|
39450
|
-
* Get table grants for a datasource.
|
|
39451
|
-
*
|
|
39452
|
-
* @param datasourceId - Datasource identifier.
|
|
39453
|
-
* @returns Parsed JSON response body.
|
|
39454
|
-
*/
|
|
39455
|
-
getTableGrants(datasourceId) {
|
|
39456
|
-
return this.request(`/datasources/${encodeURIComponent(datasourceId)}/table-grants`);
|
|
39457
|
-
}
|
|
39458
|
-
/**
|
|
39459
|
-
* Run a read-only SQL query against a datasource.
|
|
39460
|
-
*
|
|
39461
|
-
* @param datasourceId - Datasource identifier.
|
|
39462
|
-
* @param input - Query input: `sql` (SELECT/WITH only), optional `params`, `maxRows`, `debug`.
|
|
39463
|
-
* @returns Parsed JSON response body.
|
|
39464
|
-
* @throws When `sql` fails read-only validation (rejected before any fetch).
|
|
39465
|
-
*/
|
|
39466
|
-
async queryDatasource(datasourceId, input) {
|
|
39467
|
-
const validation = validateSql(input.sql);
|
|
39468
|
-
if (!validation.ok) throw new Error(`SQL_NOT_ALLOWED: ${validation.reason}`);
|
|
39469
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/query`, input);
|
|
39470
|
-
}
|
|
39471
|
-
/**
|
|
39472
|
-
* Test a datasource connection.
|
|
39473
|
-
*
|
|
39474
|
-
* @param datasourceId - Datasource identifier.
|
|
39475
|
-
* @returns Parsed JSON response body.
|
|
39476
|
-
*/
|
|
39477
|
-
testDatasource(datasourceId) {
|
|
39478
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/test`, {});
|
|
39479
|
-
}
|
|
39480
|
-
/**
|
|
39481
|
-
* Get connection-pool status for a datasource.
|
|
39482
|
-
*
|
|
39483
|
-
* @param datasourceId - Datasource identifier.
|
|
39484
|
-
* @returns Parsed JSON response body.
|
|
39485
|
-
*/
|
|
39486
|
-
getPoolStatus(datasourceId) {
|
|
39487
|
-
return this.request(`/datasources/${encodeURIComponent(datasourceId)}/pool`);
|
|
39488
|
-
}
|
|
39489
|
-
/**
|
|
39490
|
-
* List table metadata for a datasource, auto-paginating.
|
|
39491
|
-
*
|
|
39492
|
-
* The server pages this collection (`page`/`pageSize`, default page size 20),
|
|
39493
|
-
* so requests aggregate every page into one `{ items, total }` result.
|
|
39494
|
-
*
|
|
39495
|
-
* @param datasourceId - Datasource identifier.
|
|
39496
|
-
* @returns `{ items: [...], total }` covering all pages.
|
|
39497
|
-
*/
|
|
39498
|
-
async listTables(datasourceId) {
|
|
39499
|
-
return this.listMetaPage(`/datasources/${encodeURIComponent(datasourceId)}/meta/tables`);
|
|
39500
|
-
}
|
|
39501
|
-
/**
|
|
39502
|
-
* Shared pagination walk for the paged meta collections (`{items,total,page,pageSize}`).
|
|
39503
|
-
*
|
|
39504
|
-
* @param basePath - Collection path (tables or metrics).
|
|
39505
|
-
* @returns `{ items, total }` aggregated across all pages.
|
|
39506
|
-
*/
|
|
39507
|
-
async listMetaPage(basePath) {
|
|
39508
|
-
const pageSize = 100;
|
|
39509
|
-
const items = [];
|
|
39510
|
-
let total = Number.POSITIVE_INFINITY;
|
|
39511
|
-
for (let page = 1; items.length < total; page += 1) {
|
|
39512
|
-
const body = await this.request(`${basePath}?page=${page}&pageSize=${pageSize}`);
|
|
39513
|
-
const record = body !== null && typeof body === "object" ? body : {};
|
|
39514
|
-
const batch = Array.isArray(record.items) ? record.items : [];
|
|
39515
|
-
items.push(...batch);
|
|
39516
|
-
total = typeof record.total === "number" ? record.total : items.length;
|
|
39517
|
-
if (batch.length === 0) break;
|
|
39518
|
-
}
|
|
39519
|
-
return { items, total: items.length };
|
|
39520
|
-
}
|
|
39521
|
-
/**
|
|
39522
|
-
* Get metadata for a single table.
|
|
39523
|
-
*
|
|
39524
|
-
* @param datasourceId - Datasource identifier.
|
|
39525
|
-
* @param tableKey - Table key.
|
|
39526
|
-
* @returns Parsed JSON response body.
|
|
39527
|
-
*/
|
|
39528
|
-
getTable(datasourceId, tableKey) {
|
|
39529
|
-
return this.request(
|
|
39530
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`
|
|
39531
|
-
);
|
|
39532
|
-
}
|
|
39533
|
-
/**
|
|
39534
|
-
* Create a table definition for a datasource.
|
|
39535
|
-
*
|
|
39536
|
-
* @param datasourceId - Datasource identifier.
|
|
39537
|
-
* @param payload - Table definition payload.
|
|
39538
|
-
* @returns Parsed JSON response body.
|
|
39539
|
-
*/
|
|
39540
|
-
createTable(datasourceId, payload) {
|
|
39541
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/meta/tables`, payload);
|
|
39542
|
-
}
|
|
39543
|
-
/**
|
|
39544
|
-
* Update a table definition for a datasource.
|
|
39545
|
-
*
|
|
39546
|
-
* @param datasourceId - Datasource identifier.
|
|
39547
|
-
* @param tableKey - Table key.
|
|
39548
|
-
* @param payload - Table definition payload.
|
|
39549
|
-
* @returns Parsed JSON response body.
|
|
39550
|
-
*/
|
|
39551
|
-
/**
|
|
39552
|
-
* Update a published table meta via read-modify-write.
|
|
39553
|
-
*
|
|
39554
|
-
* The server's PUT replaces the whole payload, so the current payload is
|
|
39555
|
-
* fetched first and the incoming fields are merged on top; fields not
|
|
39556
|
-
* mentioned are preserved.
|
|
39557
|
-
*/
|
|
39558
|
-
async updateTable(datasourceId, tableKey, payload) {
|
|
39559
|
-
const existing = await this.readMetaPayload(`${this.baseUrl}/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`);
|
|
39560
|
-
return this.put(
|
|
39561
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`,
|
|
39562
|
-
{ payload: { ...existing, ...payload } }
|
|
39563
|
-
);
|
|
39564
|
-
}
|
|
39565
|
-
/**
|
|
39566
|
-
* List metric definitions for a datasource.
|
|
39567
|
-
*
|
|
39568
|
-
* @param datasourceId - Datasource identifier.
|
|
39569
|
-
* @returns Parsed JSON response body.
|
|
39570
|
-
*/
|
|
39571
|
-
/**
|
|
39572
|
-
* List metric metadata for a datasource, auto-paginating.
|
|
39573
|
-
*
|
|
39574
|
-
* The server pages this collection (`page`/`pageSize`, default page size 20),
|
|
39575
|
-
* so requests aggregate every page into one `{ items, total }` result.
|
|
39576
|
-
*
|
|
39577
|
-
* @param datasourceId - Datasource identifier.
|
|
39578
|
-
* @returns `{ items: [...], total }` covering all pages.
|
|
39579
|
-
*/
|
|
39580
|
-
async listMetrics(datasourceId) {
|
|
39581
|
-
return this.listMetaPage(`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics`);
|
|
39582
|
-
}
|
|
39583
|
-
/**
|
|
39584
|
-
* Get a single metric definition.
|
|
39585
|
-
*
|
|
39586
|
-
* @param datasourceId - Datasource identifier.
|
|
39587
|
-
* @param metricKey - Metric key.
|
|
39588
|
-
* @returns Parsed JSON response body.
|
|
39589
|
-
*/
|
|
39590
|
-
getMetric(datasourceId, metricKey) {
|
|
39591
|
-
return this.request(
|
|
39592
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`
|
|
39593
|
-
);
|
|
39594
|
-
}
|
|
39595
|
-
/**
|
|
39596
|
-
* Create a metric definition for a datasource.
|
|
39597
|
-
*
|
|
39598
|
-
* @param datasourceId - Datasource identifier.
|
|
39599
|
-
* @param payload - Metric definition payload.
|
|
39600
|
-
* @returns Parsed JSON response body.
|
|
39601
|
-
*/
|
|
39602
|
-
createMetric(datasourceId, payload) {
|
|
39603
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics`, payload);
|
|
39604
|
-
}
|
|
39605
|
-
/**
|
|
39606
|
-
* Update a metric definition for a datasource.
|
|
39607
|
-
*
|
|
39608
|
-
* @param datasourceId - Datasource identifier.
|
|
39609
|
-
* @param metricKey - Metric key.
|
|
39610
|
-
* @param payload - Metric definition payload.
|
|
39611
|
-
* @returns Parsed JSON response body.
|
|
39612
|
-
*/
|
|
39613
|
-
/**
|
|
39614
|
-
* Update a published metric meta via read-modify-write.
|
|
39615
|
-
*
|
|
39616
|
-
* The server's PUT replaces the whole payload, so the current payload is
|
|
39617
|
-
* fetched first and the incoming fields are merged on top; fields not
|
|
39618
|
-
* mentioned are preserved.
|
|
39619
|
-
*/
|
|
39620
|
-
async updateMetric(datasourceId, metricKey, payload) {
|
|
39621
|
-
const existing = await this.readMetaPayload(`${this.baseUrl}/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`);
|
|
39622
|
-
return this.put(
|
|
39623
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`,
|
|
39624
|
-
{ payload: { ...existing, ...payload } }
|
|
39625
|
-
);
|
|
39626
|
-
}
|
|
39627
|
-
/**
|
|
39628
|
-
* Fetch the current `payload` object of a published meta entry.
|
|
39629
|
-
*
|
|
39630
|
-
* The single-entry read returns `{ code, data: [entry] }` (already unwrapped
|
|
39631
|
-
* to the array by {@link request}); the payload lives on the first entry.
|
|
39632
|
-
*
|
|
39633
|
-
* @param absoluteUrl - Full URL of the single-entry meta read.
|
|
39634
|
-
* @returns The stored payload object (empty when none exists).
|
|
39635
|
-
*/
|
|
39636
|
-
async readMetaPayload(absoluteUrl) {
|
|
39637
|
-
const response = await fetch(absoluteUrl, { headers: this.getHeaders() });
|
|
39638
|
-
const text = await response.text().catch(() => "");
|
|
39639
|
-
if (!response.ok) {
|
|
39640
|
-
throw new Error(`HTTP ${response.status}: ${text || response.statusText}`);
|
|
39641
|
-
}
|
|
39642
|
-
const parsed = this.parseBody(text);
|
|
39643
|
-
const data = parsed?.envelope === true ? parsed.data : parsed?.value;
|
|
39644
|
-
const entry = Array.isArray(data) ? data[0] : data;
|
|
39645
|
-
const payload = entry?.payload;
|
|
39646
|
-
return payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
39647
|
-
}
|
|
39648
|
-
/**
|
|
39649
|
-
* Get runtime metadata for a datasource.
|
|
39650
|
-
*
|
|
39651
|
-
* @param datasourceId - Datasource identifier.
|
|
39652
|
-
* @returns Parsed JSON response body.
|
|
39653
|
-
*/
|
|
39654
|
-
getRuntimeMeta(datasourceId) {
|
|
39655
|
-
return this.request(`/datasources/${encodeURIComponent(datasourceId)}/meta`);
|
|
39656
|
-
}
|
|
39657
|
-
/**
|
|
39658
|
-
* Run a metrics query.
|
|
39659
|
-
*
|
|
39660
|
-
* @param request - Metrics query request payload.
|
|
39661
|
-
* @returns Parsed JSON response body.
|
|
39662
|
-
*/
|
|
39663
|
-
queryMetrics(request) {
|
|
39664
|
-
return this.post("/metrics/query", request);
|
|
39665
|
-
}
|
|
39666
|
-
/**
|
|
39667
|
-
* Run an ad-hoc custom SQL query, validated as read-only before sending.
|
|
39668
|
-
*
|
|
39669
|
-
* @param request - Request with `datasourceId`, `customSql` (SELECT/WITH only),
|
|
39670
|
-
* and optional `limit` / `debug`.
|
|
39671
|
-
* @returns Parsed JSON response body.
|
|
39672
|
-
* @throws When `customSql` fails read-only validation (rejected before any fetch).
|
|
39673
|
-
*/
|
|
39674
|
-
async customSql(request) {
|
|
39675
|
-
const validation = validateSql(request.customSql);
|
|
39676
|
-
if (!validation.ok) throw new Error(`SQL_NOT_ALLOWED: ${validation.reason}`);
|
|
39677
|
-
return this.post("/metrics/query", request);
|
|
39678
|
-
}
|
|
39679
|
-
};
|
|
39680
|
-
|
|
39681
|
-
// src/tool_lattice/semantic_metrics/metrics_datasource_tool.ts
|
|
39682
|
-
var DESCRIPTION = `PHYSICAL LAYER EXPLORATION \u2014 the only tool for probing raw datasource structure (Builder/Admin only; business agents do not need it).
|
|
39683
|
-
|
|
39684
|
-
OWNS: discovering datasources, reading table-grants (the exploration boundary for this tenant), and running read-only SQL (SELECT/WITH only) to inspect physical tables, columns, sample rows, and value distributions. Also: per-datasource connection test and pool status.
|
|
39685
|
-
|
|
39686
|
-
DOES NOT OWN:
|
|
39687
|
-
- Published semantic assets (table meta / metric meta) \u2192 use metrics_meta_tool.
|
|
39688
|
-
- Runtime meta and business metric queries \u2192 use metrics_runtime_tool.
|
|
39689
|
-
|
|
39690
|
-
USE WHEN: starting a modeling task \u2014 \`list_datasources\` is always the FIRST step: it returns the datasource ids that every other action and tool requires (get_grants, query_sql here; read_semantic_catalog, query_metrics in metrics_runtime_tool; the meta actions in metrics_meta_tool). Read grants next, then probe tables, columns, samples, and distributions within the grant. If a field's business meaning is unclear, probe sample values and distributions here before publishing anything.
|
|
39691
|
-
|
|
39692
|
-
COMMON MISTAKES (do not):
|
|
39693
|
-
- Do not answer business metric questions here (e.g. "monthly sales by region") \u2014 that is metrics_runtime_tool \`query\` against published metrics, NOT this tool's \`query_sql\` (physical-table SQL).
|
|
39694
|
-
- Do not read or publish semantic meta through this tool \u2014 metrics_meta_tool owns the semantic layer.
|
|
39695
|
-
- Do not probe tables outside the tenant's table-grants; un-granted probes are rejected and break the exploration boundary.
|
|
39696
|
-
- Do not attempt writes \u2014 SQL is validated read-only and rejected before sending.`;
|
|
39697
|
-
function createMetricsDatasourceTool(params) {
|
|
39698
|
-
const { connectionType, connections, connectAll } = params;
|
|
39699
|
-
return tool51(
|
|
39700
|
-
async (input, exeConfig) => {
|
|
39701
|
-
try {
|
|
39702
|
-
const client = await resolveMetricsClientFromSelector(
|
|
39703
|
-
{ connectionType, connections, connectAll },
|
|
39704
|
-
readToolRunConfig(exeConfig) ?? {},
|
|
39705
|
-
input.connectionKey
|
|
39706
|
-
);
|
|
39707
|
-
const scope = effectiveDatasourceScope(client.getSelectedEntities());
|
|
39708
|
-
switch (input.action) {
|
|
39709
|
-
case "list_datasources": {
|
|
39710
|
-
const result = await client.listDatasources();
|
|
39711
|
-
const filtered = scope.unrestricted ? result : result.filter((d) => scope.ids.includes(Number(d.id)));
|
|
39712
|
-
const safe = filtered.map((d) => ({
|
|
39713
|
-
id: d.id,
|
|
39714
|
-
name: d.name,
|
|
39715
|
-
sourceType: d.sourceType,
|
|
39716
|
-
description: d.description,
|
|
39717
|
-
statusLabel: d.statusLabel
|
|
39718
|
-
}));
|
|
39719
|
-
return JSON.stringify(safe, null, 2);
|
|
39720
|
-
}
|
|
39721
|
-
case "get_grants": {
|
|
39722
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39723
|
-
assertDatasourceSelected(scope, ds);
|
|
39724
|
-
const result = await client.getTableGrants(ds);
|
|
39725
|
-
return JSON.stringify(result, null, 2);
|
|
39726
|
-
}
|
|
39727
|
-
case "query_sql": {
|
|
39728
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39729
|
-
assertDatasourceSelected(scope, ds);
|
|
39730
|
-
if (!input.sql) throw new Error("sql is required for the 'query_sql' action");
|
|
39731
|
-
const result = await client.queryDatasource(ds, {
|
|
39732
|
-
sql: input.sql,
|
|
39733
|
-
params: input.params,
|
|
39734
|
-
maxRows: input.maxRows
|
|
39735
|
-
});
|
|
39736
|
-
return JSON.stringify(result, null, 2);
|
|
39737
|
-
}
|
|
39738
|
-
case "test_connection": {
|
|
39739
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39740
|
-
assertDatasourceSelected(scope, ds);
|
|
39741
|
-
const result = await client.testDatasource(ds);
|
|
39742
|
-
return JSON.stringify(result, null, 2);
|
|
39743
|
-
}
|
|
39744
|
-
case "pool_status": {
|
|
39745
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39746
|
-
assertDatasourceSelected(scope, ds);
|
|
39747
|
-
const result = await client.getPoolStatus(ds);
|
|
39748
|
-
return JSON.stringify(result, null, 2);
|
|
39749
|
-
}
|
|
39750
|
-
}
|
|
39751
|
-
} catch (error) {
|
|
39752
|
-
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
39753
|
-
}
|
|
39754
|
-
},
|
|
39755
|
-
{
|
|
39756
|
-
name: "metrics_datasource_tool",
|
|
39757
|
-
description: DESCRIPTION,
|
|
39758
|
-
schema: z57.object({
|
|
39759
|
-
action: z57.enum(["list_datasources", "get_grants", "query_sql", "test_connection", "pool_status"]).describe(
|
|
39760
|
-
"list_datasources: list datasources \u2014 ALWAYS call this first to obtain the datasource id used by every other action and tool; get_grants: read table-grants; query_sql: run read-only SQL against PHYSICAL tables (note: this is query_sql, NOT the semantic 'query' action of metrics_runtime_tool); test_connection: test the datasource; pool_status: connection-pool status"
|
|
39761
|
-
),
|
|
39762
|
-
connectionKey: z57.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
|
|
39763
|
-
datasourceId: z57.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (required for all actions except list_datasources; optional if set in runConfig.metricsDataSource)"),
|
|
39764
|
-
sql: z57.string().optional().describe("Read-only SQL (SELECT/WITH only). Required for the query action. Metadata templates \u2014 PostgreSQL/SQL Server columns: select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position; HANA columns: select column_name, data_type_name from table_columns where schema_name = :schemaName and table_name = :tableName order by position; distributions: select <dim>, count(*) as row_count from <table> group by <dim> order by row_count desc limit :maxRows"),
|
|
39765
|
-
params: z57.record(z57.union([z57.string(), z57.number(), z57.boolean()])).optional().describe("Named :param values for the SQL"),
|
|
39766
|
-
maxRows: z57.number().optional().describe("Max rows to return")
|
|
39767
|
-
})
|
|
39768
|
-
}
|
|
39769
|
-
);
|
|
39770
|
-
}
|
|
39771
|
-
|
|
39772
|
-
// src/tool_lattice/semantic_metrics/metrics_meta_tool.ts
|
|
39773
|
-
import z58 from "zod";
|
|
39774
|
-
import { tool as tool52 } from "langchain";
|
|
39775
|
-
var DESCRIPTION2 = `SEMANTIC ASSET REGISTRY (Builder/Admin only) \u2014 the only tool for reading and publishing the runtime's semantic layer: table meta (meta/tables) and metric meta (meta/metrics).
|
|
39776
|
-
|
|
39777
|
-
OWNS: listing published tables and metrics, reading one by objectKey, publishing a semantic table (create_table: columns tagged with role dimension|measure), publishing a metric (create_metric: a metric_index payload then a metric_detail payload using the SQL-free calculation DSL), and correcting published assets (update_table / update_metric).
|
|
39778
|
-
|
|
39779
|
-
DOES NOT OWN:
|
|
39780
|
-
- Running queries or reading the aggregated runtime view \u2192 metrics_runtime_tool (get_meta / query / custom_sql).
|
|
39781
|
-
- Probing physical tables, columns, grants, or samples \u2192 metrics_datasource_tool.
|
|
39782
|
-
|
|
39783
|
-
USE WHEN: physical exploration is done and the model has been proposed and confirmed by the user \u2014 to publish the semantic table and metrics, or to correct published assets afterwards.
|
|
39784
|
-
|
|
39785
|
-
COMMON MISTAKES (do not):
|
|
39786
|
-
- Do not call get_meta here \u2014 that action belongs to metrics_runtime_tool, not this tool.
|
|
39787
|
-
- Do not try to "query numbers" through this tool \u2014 list/read actions return definitions only; use metrics_runtime_tool query for data.
|
|
39788
|
-
- Do not publish a metric whose sourceTable has no published table meta, or whose dimensions are not published columns with role dimension \u2014 the server will reject it.
|
|
39789
|
-
- The builder assistant must load the semantic-metrics-modeling skill and pass modelingSkillLoaded: true on write actions; no removal actions are exposed on purpose.`;
|
|
39790
|
-
var MODELING_SKILL_NAME = "semantic-metrics-modeling";
|
|
39791
|
-
var BUILDER_ASSISTANT_ID = "semantic-metrics-builder";
|
|
39792
|
-
function requireModelingSkillLoaded(action, input, exeConfig) {
|
|
39793
|
-
const isWriteAction = action === "create_table" || action === "update_table" || action === "create_metric" || action === "update_metric";
|
|
39794
|
-
if (!isWriteAction) return void 0;
|
|
39795
|
-
const runConfig = readToolRunConfig(exeConfig);
|
|
39796
|
-
const assistantId = runConfig?.assistant_id;
|
|
39797
|
-
if (assistantId === BUILDER_ASSISTANT_ID && input.modelingSkillLoaded !== true) {
|
|
39798
|
-
return JSON.stringify({
|
|
39799
|
-
success: false,
|
|
39800
|
-
error: `Load the '${MODELING_SKILL_NAME}' skill before publishing meta.`
|
|
39801
|
-
});
|
|
39802
|
-
}
|
|
39803
|
-
return void 0;
|
|
39804
|
-
}
|
|
39805
|
-
function actionRequiresPayload(action) {
|
|
39806
|
-
return action === "create_table" || action === "update_table" || action === "create_metric" || action === "update_metric";
|
|
39807
|
-
}
|
|
39808
|
-
function createMetricsMetaTool(params) {
|
|
39809
|
-
const { connectionType, connections, connectAll } = params;
|
|
39810
|
-
return tool52(
|
|
39811
|
-
async (input, exeConfig) => {
|
|
39812
|
-
try {
|
|
39813
|
-
const guardError = requireModelingSkillLoaded(input.action, input, exeConfig);
|
|
39814
|
-
if (guardError !== void 0) return guardError;
|
|
39815
|
-
const client = await resolveMetricsClientFromSelector(
|
|
39816
|
-
{ connectionType, connections, connectAll },
|
|
39817
|
-
readToolRunConfig(exeConfig) ?? {},
|
|
39818
|
-
input.connectionKey
|
|
39819
|
-
);
|
|
39820
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39821
|
-
assertDatasourceSelected(effectiveDatasourceScope(client.getSelectedEntities()), ds);
|
|
39822
|
-
if (actionRequiresPayload(input.action) && input.payload === void 0) {
|
|
39823
|
-
throw new Error(`payload is required for ${input.action}`);
|
|
39824
|
-
}
|
|
39825
|
-
const payload = input.payload ?? {};
|
|
39826
|
-
switch (input.action) {
|
|
39827
|
-
case "list_tables": {
|
|
39828
|
-
return JSON.stringify(await client.listTables(ds), null, 2);
|
|
39829
|
-
}
|
|
39830
|
-
case "read_table_meta": {
|
|
39831
|
-
if (!input.objectKey) throw new Error("objectKey is required for read_table_meta");
|
|
39832
|
-
return JSON.stringify(await client.getTable(ds, input.objectKey), null, 2);
|
|
39833
|
-
}
|
|
39834
|
-
case "create_table": {
|
|
39835
|
-
return JSON.stringify(await client.createTable(ds, payload), null, 2);
|
|
39836
|
-
}
|
|
39837
|
-
case "update_table": {
|
|
39838
|
-
if (!input.objectKey) throw new Error("objectKey is required for update_table");
|
|
39839
|
-
return JSON.stringify(await client.updateTable(ds, input.objectKey, payload), null, 2);
|
|
39840
|
-
}
|
|
39841
|
-
case "list_metrics": {
|
|
39842
|
-
return JSON.stringify(await client.listMetrics(ds), null, 2);
|
|
39843
|
-
}
|
|
39844
|
-
case "read_metric_meta": {
|
|
39845
|
-
if (!input.objectKey) throw new Error("objectKey is required for read_metric_meta");
|
|
39846
|
-
return JSON.stringify(await client.getMetric(ds, input.objectKey), null, 2);
|
|
39847
|
-
}
|
|
39848
|
-
case "create_metric": {
|
|
39849
|
-
return JSON.stringify(await client.createMetric(ds, payload), null, 2);
|
|
39850
|
-
}
|
|
39851
|
-
case "update_metric": {
|
|
39852
|
-
if (!input.objectKey) throw new Error("objectKey is required for update_metric");
|
|
39853
|
-
return JSON.stringify(await client.updateMetric(ds, input.objectKey, payload), null, 2);
|
|
39854
|
-
}
|
|
39855
|
-
}
|
|
39856
|
-
} catch (error) {
|
|
39857
|
-
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
39858
|
-
}
|
|
39859
|
-
},
|
|
39860
|
-
{
|
|
39861
|
-
name: "metrics_meta_tool",
|
|
39862
|
-
description: DESCRIPTION2,
|
|
39863
|
-
schema: z58.object({
|
|
39864
|
-
action: z58.enum([
|
|
39865
|
-
"list_tables",
|
|
39866
|
-
"read_table_meta",
|
|
39867
|
-
"create_table",
|
|
39868
|
-
"update_table",
|
|
39869
|
-
"list_metrics",
|
|
39870
|
-
"read_metric_meta",
|
|
39871
|
-
"create_metric",
|
|
39872
|
-
"update_metric"
|
|
39873
|
-
]).describe(
|
|
39874
|
-
"Actions ONLY in this meta tool (runtime query actions like get_meta/query belong to metrics_runtime_tool): list_tables/list_metrics (browse published assets), read_table_meta/read_metric_meta (details by objectKey), create_table/create_metric (publish), update_table/update_metric (correct)"
|
|
39875
|
-
),
|
|
39876
|
-
connectionKey: z58.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
|
|
39877
|
-
datasourceId: z58.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (optional if set in runConfig.metricsDataSource)"),
|
|
39878
|
-
objectKey: z58.string().optional().describe("Semantic table/metric key (required for read_table_meta/update_table/read_metric_meta/update_metric)"),
|
|
39879
|
-
payload: z58.record(z58.unknown()).optional().describe("Meta payload (required for create/update actions; objectType/objectKey/status/payload/accessGrant)"),
|
|
39880
|
-
modelingSkillLoaded: z58.literal(true).optional().describe("Set true after loading the semantic-metrics-modeling skill (required for the builder assistant on write actions)")
|
|
39881
|
-
})
|
|
39882
|
-
}
|
|
39883
|
-
);
|
|
39884
|
-
}
|
|
39885
|
-
|
|
39886
|
-
// src/tool_lattice/semantic_metrics/metrics_runtime_tool.ts
|
|
39887
|
-
import z59 from "zod";
|
|
39888
|
-
import { tool as tool53 } from "langchain";
|
|
39889
|
-
var DESCRIPTION3 = `RUNTIME QUERY SURFACE \u2014 read what is published and answer business questions with numbers. Business agents use ONLY this tool; Builder agents also use it to verify freshly published metrics.
|
|
39890
|
-
|
|
39891
|
-
OWNS: list_datasources (self-contained datasource discovery \u2014 redacted output, the first step before anything else), read_semantic_catalog (the published semantic model for a datasource: tables, metrics, dimensions, filters) and query_metrics (the semantic metric query: metrics / groupBy / filters / orderBy / limit \u2014 the server generates the SQL, so there is no free-form SQL here).
|
|
39892
|
-
|
|
39893
|
-
DOES NOT OWN:
|
|
39894
|
-
- Publishing or correcting semantic tables/metrics \u2192 metrics_meta_tool (create_table/update_table/create_metric/update_metric/list_tables/read_table_meta/list_metrics/read_metric_meta).
|
|
39895
|
-
- Physical exploration of raw tables, grants, or samples \u2192 metrics_datasource_tool (query_sql).
|
|
39896
|
-
- Free-form custom SQL \u2014 intentionally not provided; use query against published metrics.
|
|
39897
|
-
|
|
39898
|
-
USE WHEN: read_semantic_catalog to see what is published before asking numbers; query_metrics to answer a business question from already-published metrics (Business) or to verify a just-published metric against its acceptance evidence (Builder).
|
|
39899
|
-
|
|
39900
|
-
COMMON MISTAKES (do not):
|
|
39901
|
-
- Do not call meta-tool actions here (create_table / update_table / create_metric / update_metric / list_tables / read_table_meta / list_metrics / read_metric_meta) \u2014 they live in metrics_meta_tool and will fail schema validation here.
|
|
39902
|
-
- Do not look for a custom-SQL action \u2014 there is none; explore physical data with metrics_datasource_tool query_sql, and query business numbers with the semantic query action.
|
|
39903
|
-
- Metrics and dimensions in query_metrics must already be published; querying an unpublished metric fails with "not found in catalog".`;
|
|
39904
|
-
function createMetricsRuntimeTool(params) {
|
|
39905
|
-
const { connectionType, connections, connectAll } = params;
|
|
39906
|
-
return tool53(
|
|
39907
|
-
async (input, exeConfig) => {
|
|
39908
|
-
try {
|
|
39909
|
-
const client = await resolveMetricsClientFromSelector(
|
|
39910
|
-
{ connectionType, connections, connectAll },
|
|
39911
|
-
readToolRunConfig(exeConfig) ?? {},
|
|
39912
|
-
input.connectionKey
|
|
39913
|
-
);
|
|
39914
|
-
const scope = effectiveDatasourceScope(client.getSelectedEntities());
|
|
39915
|
-
switch (input.action) {
|
|
39916
|
-
case "list_datasources": {
|
|
39917
|
-
const result = await client.listDatasources();
|
|
39918
|
-
const filtered = scope.unrestricted ? result : result.filter((d) => scope.ids.includes(Number(d.id)));
|
|
39919
|
-
const safe = filtered.map((d) => ({
|
|
39920
|
-
id: d.id,
|
|
39921
|
-
name: d.name,
|
|
39922
|
-
sourceType: d.sourceType,
|
|
39923
|
-
description: d.description,
|
|
39924
|
-
statusLabel: d.statusLabel
|
|
39925
|
-
}));
|
|
39926
|
-
return JSON.stringify(safe, null, 2);
|
|
39927
|
-
}
|
|
39928
|
-
case "read_semantic_catalog": {
|
|
39929
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39930
|
-
assertDatasourceSelected(scope, ds);
|
|
39931
|
-
return JSON.stringify(await client.getRuntimeMeta(ds), null, 2);
|
|
39932
|
-
}
|
|
39933
|
-
case "query_metrics": {
|
|
39934
|
-
if (!input.query) throw new Error("query is required for the 'query_metrics' action");
|
|
39935
|
-
const bodyDatasourceId = input.query.datasourceId;
|
|
39936
|
-
if (bodyDatasourceId !== void 0) {
|
|
39937
|
-
assertDatasourceSelected(scope, Number(bodyDatasourceId));
|
|
39938
|
-
}
|
|
39939
|
-
return JSON.stringify(await client.queryMetrics(input.query), null, 2);
|
|
39940
|
-
}
|
|
39941
|
-
}
|
|
39942
|
-
} catch (error) {
|
|
39943
|
-
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
39944
|
-
}
|
|
39945
|
-
},
|
|
39946
|
-
{
|
|
39947
|
-
name: "metrics_runtime_tool",
|
|
39948
|
-
description: DESCRIPTION3,
|
|
39949
|
-
schema: z59.object({
|
|
39950
|
-
action: z59.enum(["list_datasources", "read_semantic_catalog", "query_metrics"]).describe(
|
|
39951
|
-
"Actions ONLY in this runtime tool: list_datasources (list available datasources \u2014 ALWAYS call this first to obtain the datasourceId; output is redacted to non-sensitive fields), read_semantic_catalog (read the published semantic model: tables, metrics, dimensions), query_metrics (run a semantic metric query \u2014 the only way to get business numbers). Do NOT put meta-tool actions (list_tables/read_table_meta/create_table/update_table/list_metrics/read_metric_meta/create_metric/update_metric) here"
|
|
39952
|
-
),
|
|
39953
|
-
connectionKey: z59.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
|
|
39954
|
-
datasourceId: z59.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (required for read_semantic_catalog; optional if set in runConfig.metricsDataSource)"),
|
|
39955
|
-
query: z59.record(z59.unknown()).optional().describe('Semantic metric query request. Required for the query_metrics action, e.g. { datasourceId: 15, metrics: ["sell_in_nes"], groupBy: ["sales_team"], filters: [{ dimension: "posting_year", operator: "GTE", values: [2024] }], limit: 10 }')
|
|
39956
|
-
})
|
|
39957
|
-
}
|
|
39958
|
-
);
|
|
39959
|
-
}
|
|
39960
|
-
|
|
39961
|
-
// src/middlewares/semanticMetricsModelingSkill.ts
|
|
39962
|
-
var CONTENT = `---
|
|
39963
|
-
name: semantic-metrics-modeling
|
|
39964
|
-
description: Builder policy for turning a granted datasource into published semantic tables and metrics. Defines the orchestrator/worker contract \u2014 the orchestrator agrees goals, proposes the model, plans persistent tasks, and delegates execution to general-purpose workers with self-contained briefs; workers execute one bound brief each. Governs goal agreement, delegation, FEP verification, belief-state reconciliation, and continuous refinement until acceptance evidence is met.
|
|
39965
|
-
---
|
|
39966
|
-
|
|
39967
|
-
# Semantic Metrics Modeling
|
|
39968
|
-
|
|
39969
|
-
You are the Semantic Metrics Builder. You turn physical datasource tables into reusable
|
|
39970
|
-
**semantic tables** and **business metrics** on a Metrics Server (\`/api/v1\`). Work is
|
|
39971
|
-
governed, observable, and continuously refined \u2014 never a one-shot guess.
|
|
39972
|
-
|
|
39973
|
-
You always operate in exactly ONE of two roles:
|
|
39974
|
-
|
|
39975
|
-
- **Orchestrator** (default; no \`## Bound Task\` section in your context): you face the
|
|
39976
|
-
user. You agree the Goal Model, propose the model, plan persistent tasks, dispatch
|
|
39977
|
-
execution to workers, reconcile belief, and own every user interaction.
|
|
39978
|
-
- **Worker** (your context contains a \`## Bound Task\` section naming you executor of one
|
|
39979
|
-
task): you execute that task's brief only. See **Worker mode** \u2014 its rules override the
|
|
39980
|
-
orchestrator policy.
|
|
39981
|
-
|
|
39982
|
-
## Goal Model
|
|
39983
|
-
|
|
39984
|
-
Before any exploration or publishing, agree with the user on:
|
|
39985
|
-
- **Real goal**: the business outcome (which metrics, for what decision), not just "make a table".
|
|
39986
|
-
- **Consumer**: who reads the result and how.
|
|
39987
|
-
- **Usable state**: observable conditions that make the published meta useful.
|
|
39988
|
-
- **Scope**: which datasource/tables, and what is explicitly out of scope.
|
|
39989
|
-
- **Acceptance evidence**: objective criteria (e.g. "metric \`sell_in_nes\` returns sane monthly
|
|
39990
|
-
totals for 2024") used to decide success. Verbatim acceptance evidence is required later by
|
|
39991
|
-
the Verify dispatch \u2014 record it exactly.
|
|
39992
|
-
Do not guess material goals, consumers, or acceptance evidence.
|
|
39993
|
-
|
|
39994
|
-
**Vague requests** (e.g. "build the metric layer") \u2014 do not act and do not ask blind questions.
|
|
39995
|
-
First run cheap read-only observations (\`list_datasources\`, \`get_grants\`, \`list_metrics\`) to
|
|
39996
|
-
see what is authorized and already published, then ask focused questions that carry that
|
|
39997
|
-
context and offer concrete options (which datasource/tables, which business questions, extend
|
|
39998
|
-
existing metrics or build new). Every clarification question must include enough context and
|
|
39999
|
-
options for the user to answer in one step. Only after the user picks a direction does the
|
|
40000
|
-
Goal Model become confirmable \u2014 record it, create the task, and proceed to the workflow.
|
|
40001
|
-
|
|
40002
|
-
## Target model and quality bar
|
|
40003
|
-
|
|
40004
|
-
Your goal is a specific, verifiable artifact, not "some tables and metrics".
|
|
40005
|
-
|
|
40006
|
-
**Target shape** \u2014 one delivery is:
|
|
40007
|
-
- a published \`table_view_detail\` meta per logical table, with every column tagged
|
|
40008
|
-
\`role\` (dimension | measure) and a business-readable \`label\`;
|
|
40009
|
-
- a \`metric_index\` + \`metric_detail\` pair per metric, using the SQL-free \`calculation\` DSL;
|
|
40010
|
-
- the set, taken together, answers the user's concrete business question.
|
|
40011
|
-
|
|
40012
|
-
**Publish gate (self-check every metric before create)** \u2014 if any fails, do **not** publish; go
|
|
40013
|
-
explore or ask the user:
|
|
40014
|
-
1. measure: an aggregation is chosen **and** its business meaning is confirmed (net/gross, currency, dedupe or not);
|
|
40015
|
-
2. dimension: has a business meaning and a grain (day/month/year/\u2026);
|
|
40016
|
-
3. \`displayName\`/\`label\` are business-readable;
|
|
40017
|
-
4. the metric answers one concrete question from the user's stated goal;
|
|
40018
|
-
5. a runtime \`query\` returns numbers consistent with the confirmed meaning.
|
|
40019
|
-
|
|
40020
|
-
**Intent gaps first** \u2014 before diving into exploration, list the inputs you still need to meet the
|
|
40021
|
-
quality bar (business meaning, grain, target metric list, table scope, consumer) and ask for them
|
|
40022
|
-
explicitly. Exploration and user questions are both driven by this target shape and quality bar:
|
|
40023
|
-
missing business meaning \u2192 ask; unclear field semantics \u2192 probe or ask; right shape but it does not
|
|
40024
|
-
answer the business question \u2192 do not publish.
|
|
40025
|
-
|
|
40026
|
-
## FEP Loop
|
|
40027
|
-
|
|
40028
|
-
Apply this loop to every step (explore, publish table, publish metric, verify):
|
|
40029
|
-
**OBSERVE \u2192 HYPOTHESIZE \u2192 ACT \u2192 VERIFY \u2192 DECIDE \u2192 RECONCILE**
|
|
40030
|
-
|
|
40031
|
-
- **Observe**: current state, grants, published meta, and decision-relevant uncertainty.
|
|
40032
|
-
- **Hypothesize**: what evidence should appear if your model is right, and how each outcome changes the decision.
|
|
40033
|
-
- **Act**: one proportional action \u2014 no more than necessary.
|
|
40034
|
-
- **Verify**: compare the observed result (e.g. a runtime \`query\`) against the prediction.
|
|
40035
|
-
- **Decide**: classify as **RETAIN** (confirmed), **REVERT** (rejected), or **INCONCLUSIVE**.
|
|
40036
|
-
- **Reconcile**: update the belief state and plan, then repeat while decision-relevant action remains.
|
|
40037
|
-
|
|
40038
|
-
The orchestrator applies the loop **between dispatches** (each observation updates the plan
|
|
40039
|
-
before the next brief is written). A worker applies it **inside its brief**.
|
|
40040
|
-
|
|
40041
|
-
Renew user approval when a foundational assumption or the goal changes.
|
|
40042
|
-
|
|
40043
|
-
## Orchestrator: Task Policy
|
|
40044
|
-
|
|
40045
|
-
You are an orchestrator, not the hands. Exactly five duties:
|
|
40046
|
-
|
|
40047
|
-
1. **Goal Model agreement** \u2014 including cheap read-only observation for vague requests
|
|
40048
|
-
(\`list_datasources\`, \`get_grants\`, \`list_metrics\`). This is your ONLY inline datasource
|
|
40049
|
-
access; do not use \`write_todos\`.
|
|
40050
|
-
2. **Propose the model** and get user approval.
|
|
40051
|
-
3. **Task tree** \u2014 parent task = contract + \`## Belief State\`; child tasks = independently
|
|
40052
|
-
verifiable outcomes (explore / publish-table / publish-metric / verify), one per dispatch.
|
|
40053
|
-
See the \`task-definition\` skill for \`manage_task\` operation details.
|
|
40054
|
-
4. **Dispatch and collect** \u2014 \`task { taskId, agentId: "general-purpose" }\`; read the
|
|
40055
|
-
observation; record the \`executionResultId\` on the child task with \`manage_task update\` or
|
|
40056
|
-
\`add_activity\`; reconcile \`## Belief State\`.
|
|
40057
|
-
5. **HITL** \u2014 every \`ask_user_to_clarify\` is yours. Workers never ask the user.
|
|
40058
|
-
|
|
40059
|
-
Hard rules:
|
|
40060
|
-
- Never run exploration SQL inline. Never build or publish payloads inline (sole exception:
|
|
40061
|
-
the Publish/Verify inline fallback below).
|
|
40062
|
-
- **Belief State: you are the sole writer.** Workers return findings in their results; you
|
|
40063
|
-
update \`## Belief State\` via \`manage_task update\` on the parent task. Workers never touch it.
|
|
40064
|
-
- **Dispatch serially** \u2014 one worker at a time; reconcile belief before writing the next brief.
|
|
40065
|
-
- **Distinguish dispatch failure from worker outcome**: a dispatch failure is a tool-level
|
|
40066
|
-
error where the worker never ran. A worker returning INCONCLUSIVE or failed is a normal FEP
|
|
40067
|
-
input \u2014 reconcile it, never treat it as a dispatch failure.
|
|
40068
|
-
|
|
40069
|
-
Dispatch failure handling (worker never ran, tool error):
|
|
40070
|
-
1. Retry the dispatch once (recreate the child task if the store reports it unusable).
|
|
40071
|
-
2. **Explore: never execute inline.** If the retry fails, stop and ask the user via
|
|
40072
|
-
\`ask_user_to_clarify\` (report what is blocked and why).
|
|
40073
|
-
3. **Publish/Verify: after a failed retry you MAY execute inline** to preserve delivery \u2014
|
|
40074
|
-
the payload decisions are already in your context. Follow the same gate self-check as a
|
|
40075
|
-
worker would.
|
|
40076
|
-
|
|
40077
|
-
## Delegation Protocol
|
|
40078
|
-
|
|
40079
|
-
Mechanics every brief must be designed around:
|
|
40080
|
-
|
|
40081
|
-
- A worker sees ONLY: its task title + description, the parent task's description, and the
|
|
40082
|
-
results of completed dependency tasks. It does NOT see this conversation.
|
|
40083
|
-
- Therefore **every brief is self-contained**: all decisions, boundaries, and evidence travel
|
|
40084
|
-
inside the task description.
|
|
40085
|
-
- Dispatch is synchronous: \`task { taskId, agentId: "general-purpose" }\` returns an
|
|
40086
|
-
observation (the worker's final message, truncated at ~8k chars) and an
|
|
40087
|
-
\`executionResultId\`. Record the id on the child task (\`manage_task update\`/\`add_activity\`).
|
|
40088
|
-
- The worker settles its own task (\`set_status\` with \`result\`/\`failureReason\`). Read both the
|
|
40089
|
-
observation and the task result before reconciling.
|
|
40090
|
-
|
|
40091
|
-
Write briefs as field checklists adapted to the situation \u2014 decisions and evidence, not prose.
|
|
40092
|
-
The worker assembles payloads from the reference sections of this skill; the brief carries the
|
|
40093
|
-
approved decisions, never full payload JSON.
|
|
40094
|
-
|
|
40095
|
-
### Explore brief (\`Explore <schema>.<table> for <goal>\`)
|
|
40096
|
-
|
|
40097
|
-
Required fields:
|
|
40098
|
-
1. Datasource: serverKey/connectionKey + datasourceId (and \`runConfig.metricsDataSource\` preset if present).
|
|
40099
|
-
2. Grant boundary: the allowed schema + table pattern from \`get_grants\`, verbatim; never probe outside it.
|
|
40100
|
-
3. Target table(s): schema-qualified names; one brief per table.
|
|
40101
|
-
4. Question list: per column (or column group) \u2014 business meaning candidates, expected role
|
|
40102
|
-
(dimension | measure | time), net/gross, grain.
|
|
40103
|
-
5. Method: read-only SELECT/WITH only; use the \`references/metadata-sql.md\` templates
|
|
40104
|
-
(columns, sample rows, value distribution); cap sample size (e.g. \u22641000 rows, \u226450 groups).
|
|
40105
|
-
Prefer targeted queries over bulk catalog dumps. A large single read (e.g. full
|
|
40106
|
-
\`read_semantic_catalog\` detail) is allowed \u2014 your isolation protects the orchestrator's
|
|
40107
|
-
context \u2014 but findings must be compressed to conclusion level.
|
|
40108
|
-
6. Output contract: structured findings \u2014 per column: observed type, sample values,
|
|
40109
|
-
distribution highlights, role candidate + evidence, \`INCONCLUSIVE\` marking for unresolved
|
|
40110
|
-
semantics.
|
|
40111
|
-
7. Invariants: read-only only; grant boundary absolute; never guess \u2014 \`INCONCLUSIVE\` instead.
|
|
40112
|
-
8. Closing: settle the task (\`set_status completed\`, result = findings summary); final message
|
|
40113
|
-
= the structured findings (it becomes the observation).
|
|
40114
|
-
|
|
40115
|
-
### Publish-table brief (\`Publish table meta <objectKey>\`)
|
|
40116
|
-
|
|
40117
|
-
Required fields:
|
|
40118
|
-
1. Approved decisions: full column list (name/type/role/label/description), grain,
|
|
40119
|
-
displayName/docType/shortDesc/sourceSystem/sourceTables.
|
|
40120
|
-
2. Identity: \`objectKey\` (stable, unique per datasource) + \`schemaName.tableName\`.
|
|
40121
|
-
3. Assembly instruction: full \`table_view_detail\` payload per **Publish table meta** below,
|
|
40122
|
-
plus the identity twin (\`table_catalog\`, same \`objectKey\`), plus an EXACT \`accessGrant\`
|
|
40123
|
-
matching the tenant grant.
|
|
40124
|
-
4. Gate self-check: publish gate items 1\u20133 \u2014 do not publish if any fails.
|
|
40125
|
-
5. Publish via \`metrics_meta_tool\` \`create_table\`; then \`get_meta\` to confirm visibility.
|
|
40126
|
-
6. Mistakes: fix with \`update_table\`; never leave a partial publish.
|
|
40127
|
-
7. Invariants: EXACT patternType; every column tagged and labeled.
|
|
40128
|
-
8. Closing: settle the task; final message = receipts (objectKeys + get_meta confirmation).
|
|
40129
|
-
|
|
40130
|
-
### Publish-metric brief (\`Publish metric <objectKey>\`)
|
|
40131
|
-
|
|
40132
|
-
Required fields (per metric):
|
|
40133
|
-
1. Identity: \`objectKey\` = \`metric_name\`, display_name, domain, description, data_type, format.
|
|
40134
|
-
2. Source: schema-qualified \`source.table_view\` (must match the published table meta).
|
|
40135
|
-
3. Calculation: aggregate (\`aggregation\` + \`measure\`, with the confirmed business meaning) or
|
|
40136
|
-
derived (ratio references / formula) \u2014 exactly as approved in Propose the model.
|
|
40137
|
-
4. \`supported_dimensions\`: array of objects \`{dim_id, field_name, label, data_type}\`,
|
|
40138
|
-
including the time dimension.
|
|
40139
|
-
5. \`default_time_context\`: time_dimension + granularity + supported_grains (+ window if requested).
|
|
40140
|
-
6. \`ai_agent_context\`: polarity, synonyms, human_readable_explanation.
|
|
40141
|
-
7. Assembly instruction: \`metric_index\` then \`metric_detail\` in the FULL runtime style per
|
|
40142
|
-
**Publish metric meta** below; publish via \`metrics_meta_tool\` \`create_metric\`.
|
|
40143
|
-
8. Gate self-check + smoke \`query\` (one grouping by the default time grain) + \`get_meta\`
|
|
40144
|
-
receipts; closing = settle the task, final message = receipts.
|
|
40145
|
-
|
|
40146
|
-
### Verify brief (\`Verify <metric> against acceptance evidence\`)
|
|
40147
|
-
|
|
40148
|
-
Required fields:
|
|
40149
|
-
1. Acceptance evidence verbatim (from the Goal Model).
|
|
40150
|
-
2. Queries to run (semantic \`query\` via \`metrics_runtime_tool\`) and the expected shape/values.
|
|
40151
|
-
3. Report contract: PASS/FAIL verdict + actual vs expected; on FAIL include the differences
|
|
40152
|
-
and a suspicion list \u2014 do NOT modify meta (fixes are new Publish tasks).
|
|
40153
|
-
4. Invariants: read-only only.
|
|
40154
|
-
5. Closing: settle the task; final message = the verdict summary.
|
|
40155
|
-
|
|
40156
|
-
### Brief closing (all types)
|
|
40157
|
-
|
|
40158
|
-
- Invariants line: grant boundary + read-only SQL + publish gate before any create.
|
|
40159
|
-
- Result structure: the structured summary the orchestrator expects back.
|
|
40160
|
-
- Finish by settling the task (\`set_status completed\` with result, or \`failed\` with
|
|
40161
|
-
failureReason) and making the final message that structured summary.
|
|
40162
|
-
|
|
40163
|
-
## Worker mode
|
|
40164
|
-
|
|
40165
|
-
Trigger: your context contains \`## Bound Task\`. You are a worker; these rules override the
|
|
40166
|
-
orchestrator policy (Safety and the reference sections still apply):
|
|
40167
|
-
|
|
40168
|
-
- Execute the bound task's brief only. Read the contract with \`manage_task get\`; the task
|
|
40169
|
-
description is authoritative. Load this skill if the bootstrap asks \u2014 you need its payload
|
|
40170
|
-
reference sections.
|
|
40171
|
-
- Do NOT: re-agree the Goal Model, create sibling or child tasks, dispatch \`task\`, call
|
|
40172
|
-
\`ask_user_to_clarify\`, or update the parent task's \`## Belief State\`.
|
|
40173
|
-
- Apply the FEP loop inside the brief; obey the grant boundary and read-only SQL; run the
|
|
40174
|
-
publish gate before any create.
|
|
40175
|
-
- Unclear semantics: mark \`INCONCLUSIVE\` with candidates + evidence in your findings. Never
|
|
40176
|
-
guess, never publish on a guess.
|
|
40177
|
-
- Finish: \`set_status completed\` with a structured result (or \`failed\` with failureReason),
|
|
40178
|
-
and make your final message the structured summary \u2014 it is the observation your
|
|
40179
|
-
orchestrator reads.
|
|
40180
|
-
|
|
40181
|
-
## Belief State (orchestrator-owned)
|
|
40182
|
-
|
|
40183
|
-
The parent task's description carries a \`## Belief State\` section as a Markdown table:
|
|
40184
|
-
|
|
40185
|
-
\`\`\`
|
|
40186
|
-
| Belief Key | Probability | Target | Basis |
|
|
40187
|
-
|---|---|---|---|
|
|
40188
|
-
| sell-in-nes-source-table | 70% | 100% | column \`nes\` probed as numeric measure in grant |
|
|
40189
|
-
\`\`\`
|
|
40190
|
-
|
|
40191
|
-
Rules: belief keys are lowercase kebab-case; probability/target are percentages 0\u2013100% that
|
|
40192
|
-
represent evidence support, not calibrated probability. Only the orchestrator writes this
|
|
40193
|
-
section \u2014 after each dispatch it folds the worker's findings into the table so the parent
|
|
40194
|
-
task always reflects the current evidence.
|
|
40195
|
-
|
|
40196
|
-
## Workflow
|
|
40197
|
-
|
|
40198
|
-
1. **Pick the datasource + cheap observation.** \`metrics_datasource_tool\` action
|
|
40199
|
-
\`list_datasources\`, or the preset \`runConfig.metricsDataSource\` (\`serverKey\`\u2192connectionKey,
|
|
40200
|
-
\`datasourceId\`). Inline, read-only.
|
|
40201
|
-
2. **Agree the Goal Model.** (HITL)
|
|
40202
|
-
3. **Create the parent task** \u2014 contract + \`## Belief State\` (seeded from the Goal Model).
|
|
40203
|
-
4. **Explore by dispatch** \u2014 one Explore brief per table, serial; collect findings; reconcile
|
|
40204
|
-
\`## Belief State\`; collect \`INCONCLUSIVE\` columns.
|
|
40205
|
-
5. **Propose the model** (HITL) \u2014 present table columns (with \`role: dimension | measure\`)
|
|
40206
|
-
and the metrics (aggregate/derived) for approval; include clarify questions for
|
|
40207
|
-
\`INCONCLUSIVE\` columns in the same ask.
|
|
40208
|
-
6. **Publish tables by dispatch** \u2014 one Publish-table brief per table; check receipts.
|
|
40209
|
-
7. **Publish metrics by dispatch** \u2014 one Publish-metric brief per metric; receipts + smoke query.
|
|
40210
|
-
8. **Verify by dispatch** \u2014 Verify brief against acceptance evidence. FAIL \u2192 reconcile
|
|
40211
|
-
belief \u2192 fix decisions \u2192 new Publish task (\`update_table\`/\`update_metric\`) \u2192 re-Verify.
|
|
40212
|
-
PASS \u2192 complete the parent task (result = acceptance evidence met).
|
|
40213
|
-
|
|
40214
|
-
## Explore (reference)
|
|
40215
|
-
|
|
40216
|
-
Read \`table-grants\`, then probe with \`query\`. SQL is validated read-only by the client and the
|
|
40217
|
-
server enforces the grant; un-granted tables return \`TABLE_NOT_GRANTED\`. Prefer the
|
|
40218
|
-
\`references/metadata-sql.md\` templates because dialect varies (PostgreSQL / SQL Server / HANA).
|
|
40219
|
-
If the user provides a data dictionary or sample data file, read it with filesystem and
|
|
40220
|
-
reconcile it against the probed columns.
|
|
40221
|
-
|
|
40222
|
-
## Unclear field semantics
|
|
40223
|
-
|
|
40224
|
-
A probed column name may not reveal its business meaning (e.g. whether \`nes\` is a net amount to
|
|
40225
|
-
sum, a rate to average, or an enum to filter). Publishing meta on a misunderstood field pollutes
|
|
40226
|
-
the runtime and every downstream metric that depends on it, and delete is not available. Treat this
|
|
40227
|
-
as FEP **INCONCLUSIVE** \u2014 never guess, and never publish on an unverified guess.
|
|
40228
|
-
|
|
40229
|
-
Resolve in order of increasing cost (inside the Explore brief):
|
|
40230
|
-
1. **Probe sample values and distribution** (\`query\`, templates in \`references/metadata-sql.md\`):
|
|
40231
|
-
- numbers in (0,1) or clustered near 100 \u2192 likely a ratio/percentage \u2192 dimension or \`avg\`, rarely \`sum\`;
|
|
40232
|
-
- large additive amounts (currency, counts) \u2192 measure with \`sum\`;
|
|
40233
|
-
- small enumerations (year 2023/2024, 0/1 flags, codes) \u2192 dimension.
|
|
40234
|
-
The share of zeros/negatives and the value scale usually disambiguate semantics.
|
|
40235
|
-
2. **Read user-provided docs**: if the user supplied a data dictionary or sample file, read it via
|
|
40236
|
-
filesystem and reconcile it against the probed columns.
|
|
40237
|
-
3. **Cross-field correlation**: compare the unclear field with fields whose semantics are confirmed.
|
|
40238
|
-
|
|
40239
|
-
If evidence is still INCONCLUSIVE:
|
|
40240
|
-
- Do **not** publish meta that depends on the unclear field.
|
|
40241
|
-
- The worker marks the column \`INCONCLUSIVE\` (candidates + evidence) in its findings; the
|
|
40242
|
-
**orchestrator** lists it with candidate interpretations in the **Propose the model** step
|
|
40243
|
-
and asks the user to confirm its semantics (role, value meaning, net/gross) via
|
|
40244
|
-
\`ask_user_to_clarify\`. The user does not need to see the table \u2014 probed schema, samples, and
|
|
40245
|
-
candidates are enough.
|
|
40246
|
-
- The orchestrator records a low-probability belief entry (e.g.
|
|
40247
|
-
\`| sales-nes-semantics | 40% | 100% | user must confirm role / net amount |\`) so verify/refine
|
|
40248
|
-
can revisit it later instead of assuming it is settled.
|
|
40249
|
-
|
|
40250
|
-
## Publish table meta (\`create_table\`)
|
|
40251
|
-
|
|
40252
|
-
Publish the authoritative shape below (objectType \`table_view_detail\`, with an EXACT accessGrant):
|
|
40253
|
-
|
|
40254
|
-
\`\`\`json
|
|
40255
|
-
{
|
|
40256
|
-
"objectType": "table_view_detail",
|
|
40257
|
-
"objectKey": "hankel_view_sales_summary",
|
|
40258
|
-
"status": 1,
|
|
40259
|
-
"payload": {
|
|
40260
|
-
"schemaName": "public",
|
|
40261
|
-
"tableName": "hankel_view_sales_summary",
|
|
40262
|
-
"displayName": "Hankel Sales Summary",
|
|
40263
|
-
"docType": "Sales Summary",
|
|
40264
|
-
"docTypeEn": "Sales Summary",
|
|
40265
|
-
"shortDesc": "Sales-level progress summary.",
|
|
40266
|
-
"grain": "canonical_sales_name",
|
|
40267
|
-
"sourceSystem": "Hankel Run for Gold",
|
|
40268
|
-
"sourceTables": ["hankel_project_opportunity_lines", "hankel_new_order_lines"],
|
|
40269
|
-
"columns": [
|
|
40270
|
-
{ "name": "canonical_sales_name", "label": "Canonical Sales Name", "type": "string", "role": "dimension", "description": "Standardized sales name used for grouping." },
|
|
40271
|
-
{ "name": "nes", "label": "NES", "type": "number", "role": "measure", "description": "Net external sales amount." },
|
|
40272
|
-
{ "name": "report_cutoff_date", "label": "Report Cutoff Date", "type": "date", "role": "time", "description": "Cutoff date of the report snapshot." }
|
|
40273
|
-
]
|
|
40274
|
-
},
|
|
40275
|
-
"accessGrant": {
|
|
40276
|
-
"schemaName": "public",
|
|
40277
|
-
"tablePattern": "hankel_view_sales_summary",
|
|
40278
|
-
"patternType": "EXACT",
|
|
40279
|
-
"caseSensitive": false,
|
|
40280
|
-
"status": 1
|
|
40281
|
-
}
|
|
40282
|
-
}
|
|
40283
|
-
\`\`\`
|
|
40284
|
-
|
|
40285
|
-
Design rules:
|
|
40286
|
-
- \`objectKey\` is stable and unique per datasource (the view/table key).
|
|
40287
|
-
- \`columns[].role\` has THREE values: \`dimension\` (grouping/filtering), \`measure\` (aggregated numbers), \`time\` (the report cutoff/snapshot date used by default_time_context).
|
|
40288
|
-
- Give every column a business \`description\`.
|
|
40289
|
-
- Lineage fields (\`docType\`, \`shortDesc\`, \`grain\`, \`sourceSystem\`, \`sourceTables\`) make the asset findable and trustworthy \u2014 fill them from exploration evidence.
|
|
40290
|
-
- Runtime table publication uses \`patternType: "EXACT"\` (\`PREFIX\` is only for datasource-level exploration scopes).
|
|
40291
|
-
- For each semantic table also publish the identity twin: the same body with \`objectType: "table_catalog"\` and the same \`objectKey\` (same or richer payload).
|
|
40292
|
-
|
|
40293
|
-
## Publish metric meta (\`create_metric\`)
|
|
40294
|
-
|
|
40295
|
-
Two steps for the same \`objectKey\`.
|
|
40296
|
-
|
|
40297
|
-
### 3a. Metric index (for lists/search)
|
|
40298
|
-
|
|
40299
|
-
\`\`\`json
|
|
40300
|
-
{
|
|
40301
|
-
"objectType": "metric_index",
|
|
40302
|
-
"objectKey": "sell_in_nes",
|
|
40303
|
-
"status": 1,
|
|
40304
|
-
"payload": {
|
|
40305
|
-
"metric_name": "sell_in_nes",
|
|
40306
|
-
"display_name": "Sell-in NES",
|
|
40307
|
-
"domain": "sales",
|
|
40308
|
-
"short_desc": "Net external sales amount from distributor sell-in rows.",
|
|
40309
|
-
"search_keywords": ["sell in", "nes", "net external sales"],
|
|
40310
|
-
"source_type": "cdp_postgres",
|
|
40311
|
-
"source": { "table_view": "public.hankel_distr_sell_in" }
|
|
40312
|
-
}
|
|
40313
|
-
}
|
|
40314
|
-
\`\`\`
|
|
40315
|
-
|
|
40316
|
-
\`search_keywords\` drive metric retrieval for natural-language questions \u2014 include business synonyms.
|
|
40317
|
-
|
|
40318
|
-
### 3b. Metric detail (the calculation)
|
|
40319
|
-
|
|
40320
|
-
IMPORTANT \u2014 runtime schema requirement: the Metrics Server query runtime only recognizes metrics
|
|
40321
|
-
published in the FULL runtime style below (the same shape as existing working metrics, with
|
|
40322
|
-
snake_case fields like \`metric_name\`, \`source.table_view\`, \`supported_dimensions\` objects, and
|
|
40323
|
-
\`default_time_context\`). A minimal \`{name, sourceTable, calculation, dimensions}\` payload is
|
|
40324
|
-
accepted by the publish API but is NOT queryable \u2014 querying it returns 403 "not authorized".
|
|
40325
|
-
|
|
40326
|
-
Aggregate metric (full runtime style):
|
|
40327
|
-
|
|
40328
|
-
\`\`\`json
|
|
40329
|
-
{
|
|
40330
|
-
"objectType": "metric_detail",
|
|
40331
|
-
"objectKey": "sell_in_nes",
|
|
40332
|
-
"status": 1,
|
|
40333
|
-
"payload": {
|
|
40334
|
-
"metric_name": "sell_in_nes",
|
|
40335
|
-
"display_name": "Sell-in NES",
|
|
40336
|
-
"domain": "sales",
|
|
40337
|
-
"description": "Net external sales amount from distributor sell-in rows.",
|
|
40338
|
-
"data_type": "numeric",
|
|
40339
|
-
"format": "currency",
|
|
40340
|
-
"source_type": "cdp_postgres",
|
|
40341
|
-
"source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
|
|
40342
|
-
"calculation": { "type": "aggregate", "aggregation": "sum", "measure": "nes" },
|
|
40343
|
-
"supported_dimensions": [
|
|
40344
|
-
{ "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" },
|
|
40345
|
-
{ "dim_id": "sales_team", "field_name": "sales_team", "label": "Sales Team", "data_type": "string" }
|
|
40346
|
-
],
|
|
40347
|
-
"default_time_context": {
|
|
40348
|
-
"time_dimension": "posting_date",
|
|
40349
|
-
"label": "Posting date",
|
|
40350
|
-
"granularity": "month",
|
|
40351
|
-
"window": "YTD",
|
|
40352
|
-
"supported_grains": ["month", "year"]
|
|
40353
|
-
},
|
|
40354
|
-
"ai_agent_context": {
|
|
40355
|
-
"polarity": "positive",
|
|
40356
|
-
"synonyms": ["sell in", "nes", "net external sales"],
|
|
40357
|
-
"human_readable_explanation": "Higher sell-in NES means more goods purchased from the distributor."
|
|
40358
|
-
}
|
|
40359
|
-
}
|
|
40360
|
-
}
|
|
40361
|
-
\`\`\`
|
|
40362
|
-
|
|
40363
|
-
Derived ratio metric (references two aggregate metrics):
|
|
40364
|
-
|
|
40365
|
-
\`\`\`json
|
|
40366
|
-
{
|
|
40367
|
-
"objectType": "metric_detail",
|
|
40368
|
-
"objectKey": "gross_margin_rate",
|
|
40369
|
-
"status": 1,
|
|
40370
|
-
"payload": {
|
|
40371
|
-
"metric_name": "gross_margin_rate",
|
|
40372
|
-
"display_name": "Gross Margin Rate",
|
|
40373
|
-
"description": "Gross margin divided by sell-in NES.",
|
|
40374
|
-
"domain": "sales",
|
|
40375
|
-
"data_type": "numeric",
|
|
40376
|
-
"format": "percent",
|
|
40377
|
-
"source_type": "cdp_postgres",
|
|
40378
|
-
"source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
|
|
40379
|
-
"calculation": { "type": "derived", "operator": "ratio", "numerator": "gross_margin", "denominator": "sell_in_nes" },
|
|
40380
|
-
"supported_dimensions": [
|
|
40381
|
-
{ "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" }
|
|
40382
|
-
],
|
|
40383
|
-
"default_time_context": { "time_dimension": "posting_date", "granularity": "month", "supported_grains": ["month", "year"] }
|
|
40384
|
-
}
|
|
40385
|
-
}
|
|
40386
|
-
\`\`\`
|
|
40387
|
-
|
|
40388
|
-
Design rules:
|
|
40389
|
-
- \`objectKey\` unique per datasource (index and detail share it).
|
|
40390
|
-
- \`payload.metric_name\` must equal \`objectKey\`.
|
|
40391
|
-
- \`source.table_view\` must be schema-qualified and match the published table meta's physical table.
|
|
40392
|
-
- \`supported_dimensions\` is an array of OBJECTS ({dim_id, field_name, label, data_type}); include the time dimension too; each must be a published column of that table meta.
|
|
40393
|
-
- \`calculation.type: "aggregate"\` = one measure + aggregation (sum/avg/count/min/max/count_distinct).
|
|
40394
|
-
- \`calculation.type: "derived"\` operator \`ratio\` references existing metric objectKeys (numerator/denominator); a \`formula\` variant takes an expression of metric names, numbers, parentheses, and + - * / \u2014 referenced metrics must share the same source.table_view.
|
|
40395
|
-
- \`default_time_context\` (\`time_dimension\` + \`granularity\` + \`supported_grains\`, optionally \`window\`) is required by the query runtime; its \`time_dimension\` must appear in supported_dimensions.
|
|
40396
|
-
- \`ai_agent_context\` (\`polarity\`, \`synonyms\`, \`human_readable_explanation\`) improves natural-language metric retrieval \u2014 always provide it.
|
|
40397
|
-
- One semantic query can only combine metrics sharing the same source.table_view; groupBy values must be dim_ids or time-grain expressions like \`posting_date__month\`.
|
|
40398
|
-
- Do not inline raw SQL for new DB-backed metrics (complex logic belongs in a view).
|
|
40399
|
-
- Use \`update_metric\` / \`update_table\` to correct mistakes; no removal actions are exposed.
|
|
40400
|
-
|
|
40401
|
-
## Verify and refine
|
|
40402
|
-
|
|
40403
|
-
- Verify is **dispatched** (Verify brief). The worker runs \`get_meta\` \u2192 confirms the table and
|
|
40404
|
-
metric are visible, then \`query\`es the metric against acceptance evidence.
|
|
40405
|
-
- On FAIL the worker reports differences; the **orchestrator** applies the FEP reconcile:
|
|
40406
|
-
update \`## Belief State\`, fix the decisions, and dispatch a new Publish task
|
|
40407
|
-
(\`update_table\`/\`update_metric\`) \u2014 then re-Verify \u2014 until acceptance evidence is met.
|
|
40408
|
-
|
|
40409
|
-
## Troubleshooting
|
|
40410
|
-
|
|
40411
|
-
| Symptom | Cause / fix |
|
|
40412
|
-
|---|---|
|
|
40413
|
-
| \`TABLE_NOT_GRANTED\` | SQL referenced a table outside the tenant grant; pick an in-grant table |
|
|
40414
|
-
| metric create fails: sourceTable missing | publish the table meta first |
|
|
40415
|
-
| metric create fails: unknown dimension | publish the dimension column with \`role: dimension\` |
|
|
40416
|
-
| derived metric create fails | numerator/denominator metrics don't exist yet \u2014 publish them first |
|
|
40417
|
-
| datasource \`query\` rejected | SQL was not read-only (SELECT/WITH only) or multi-statement |
|
|
40418
|
-
| \`403 Metric is not authorized\` on query_metrics | the metric meta is not in the queryable runtime schema (e.g. missing \`source.table_view\` / \`supported_dimensions\` / \`default_time_context\`) or genuinely unauthorized \u2014 re-publish with the full runtime payload and verify; never retry blindly |
|
|
40419
|
-
| worker observation truncated | findings exceeded ~8k chars; worker must keep the final message a compact structured summary |
|
|
40420
|
-
| dispatch failed (tool error) | retry once; Explore never goes inline \u2014 ask the user; Publish/Verify may go inline after the failed retry |
|
|
40421
|
-
|
|
40422
|
-
## Safety
|
|
40423
|
-
|
|
40424
|
-
- Only query tables that match the tenant's \`table-grants\`.
|
|
40425
|
-
- Never return a full physical-table inventory or reveal whether an un-granted table exists.
|
|
40426
|
-
- SQL is validated read-only; let the server reject anything outside that.
|
|
40427
|
-
`;
|
|
40428
|
-
var resources = {
|
|
40429
|
-
"references/metadata-sql.md": {
|
|
40430
|
-
content: `# Datasource exploration SQL templates (read-only)
|
|
40431
|
-
|
|
40432
|
-
Pick the block matching the server's database. These run through the datasource \`query\` action;
|
|
40433
|
-
the SQL is validated read-only.
|
|
40434
|
-
|
|
40435
|
-
## PostgreSQL
|
|
40436
|
-
- Tables: \`select table_schema, table_name from information_schema.tables where table_schema not in ('pg_catalog','information_schema') order by table_schema, table_name\`
|
|
40437
|
-
- Columns: \`select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position\`
|
|
40438
|
-
- Sample: \`select * from :schemaName.:tableName limit :maxRows\` \u2014 pass a concrete table, not a bound param, if the server does not support binding identifiers.
|
|
40439
|
-
|
|
40440
|
-
## SQL Server
|
|
40441
|
-
- Tables: \`select table_schema, table_name from information_schema.tables order by table_schema, table_name\`
|
|
40442
|
-
- Columns: \`select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position\`
|
|
40443
|
-
|
|
40444
|
-
## HANA
|
|
40445
|
-
- Tables: \`select schema_name, table_name from sys.tables where schema_name = :schemaName order by table_name\`
|
|
40446
|
-
- Columns: \`select column_name, data_type_name from table_columns where schema_name = :schemaName and table_name = :tableName order by position\`
|
|
40447
|
-
|
|
40448
|
-
## Value distribution (any dialect)
|
|
40449
|
-
\`select <dim>, count(*) as row_count from <table> group by <dim> order by row_count desc limit :maxRows\`
|
|
40450
|
-
`
|
|
40451
|
-
},
|
|
40452
|
-
"examples/table-meta.json": {
|
|
40453
|
-
content: `{
|
|
40454
|
-
"objectType": "table_view_detail",
|
|
40455
|
-
"objectKey": "hankel_distr_sell_in",
|
|
40456
|
-
"status": 1,
|
|
40457
|
-
"payload": {
|
|
40458
|
-
"schemaName": "public",
|
|
40459
|
-
"tableName": "hankel_distr_sell_in",
|
|
40460
|
-
"displayName": "Hankel Distributor Sell In",
|
|
40461
|
-
"description": "Distributor sell-in transaction rows for the Hankel tenant.",
|
|
40462
|
-
"columns": [
|
|
40463
|
-
{ "name": "posting_year", "label": "Posting Year", "type": "number", "role": "dimension" },
|
|
40464
|
-
{ "name": "posting_month", "label": "Posting Month", "type": "number", "role": "dimension" },
|
|
40465
|
-
{ "name": "sales_team", "label": "Sales Team", "type": "string", "role": "dimension" },
|
|
40466
|
-
{ "name": "region", "label": "Region", "type": "string", "role": "dimension" },
|
|
40467
|
-
{ "name": "nes", "label": "Net External Sales", "type": "number", "role": "measure" },
|
|
40468
|
-
{ "name": "gross_margin", "label": "Gross Margin", "type": "number", "role": "measure" }
|
|
40469
|
-
]
|
|
40470
|
-
}
|
|
40471
|
-
}
|
|
40472
|
-
`
|
|
40473
|
-
},
|
|
40474
|
-
"examples/metric-aggregate.json": {
|
|
40475
|
-
content: `{
|
|
40476
|
-
"objectType": "metric_detail",
|
|
40477
|
-
"objectKey": "sell_in_nes",
|
|
40478
|
-
"status": 1,
|
|
40479
|
-
"payload": {
|
|
40480
|
-
"metric_name": "sell_in_nes",
|
|
40481
|
-
"display_name": "Sell-in NES",
|
|
40482
|
-
"domain": "sales",
|
|
40483
|
-
"description": "Net external sales amount from distributor sell-in rows.",
|
|
40484
|
-
"data_type": "numeric",
|
|
40485
|
-
"format": "currency",
|
|
40486
|
-
"source_type": "cdp_postgres",
|
|
40487
|
-
"source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
|
|
40488
|
-
"calculation": { "type": "aggregate", "aggregation": "sum", "measure": "nes" },
|
|
40489
|
-
"supported_dimensions": [
|
|
40490
|
-
{ "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" },
|
|
40491
|
-
{ "dim_id": "sales_team", "field_name": "sales_team", "label": "Sales Team", "data_type": "string" },
|
|
40492
|
-
{ "dim_id": "posting_date", "field_name": "posting_date", "label": "Posting Date", "data_type": "string" }
|
|
40493
|
-
],
|
|
40494
|
-
"default_time_context": {
|
|
40495
|
-
"time_dimension": "posting_date",
|
|
40496
|
-
"label": "Posting date",
|
|
40497
|
-
"granularity": "month",
|
|
40498
|
-
"window": "YTD",
|
|
40499
|
-
"supported_grains": ["month", "year"]
|
|
40500
|
-
},
|
|
40501
|
-
"ai_agent_context": {
|
|
40502
|
-
"polarity": "positive",
|
|
40503
|
-
"synonyms": ["sell in", "nes", "net external sales"],
|
|
40504
|
-
"human_readable_explanation": "Higher sell-in NES means more goods purchased from the distributor."
|
|
40505
|
-
}
|
|
40506
|
-
}
|
|
40507
|
-
}
|
|
40508
|
-
`
|
|
40509
|
-
},
|
|
40510
|
-
"examples/metric-derived.json": {
|
|
40511
|
-
content: `{
|
|
40512
|
-
"objectType": "metric_detail",
|
|
40513
|
-
"objectKey": "gross_margin_rate",
|
|
40514
|
-
"status": 1,
|
|
40515
|
-
"payload": {
|
|
40516
|
-
"metric_name": "gross_margin_rate",
|
|
40517
|
-
"display_name": "Gross Margin Rate",
|
|
40518
|
-
"domain": "sales",
|
|
40519
|
-
"description": "Gross margin divided by sell-in NES.",
|
|
40520
|
-
"data_type": "numeric",
|
|
40521
|
-
"format": "percent",
|
|
40522
|
-
"source_type": "cdp_postgres",
|
|
40523
|
-
"source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
|
|
40524
|
-
"calculation": { "type": "derived", "operator": "ratio", "numerator": "gross_margin", "denominator": "sell_in_nes" },
|
|
40525
|
-
"supported_dimensions": [
|
|
40526
|
-
{ "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" },
|
|
40527
|
-
{ "dim_id": "posting_date", "field_name": "posting_date", "label": "Posting Date", "data_type": "string" }
|
|
40528
|
-
],
|
|
40529
|
-
"default_time_context": {
|
|
40530
|
-
"time_dimension": "posting_date",
|
|
40531
|
-
"label": "Posting date",
|
|
40532
|
-
"granularity": "month",
|
|
40533
|
-
"supported_grains": ["month", "year"]
|
|
40534
|
-
},
|
|
40535
|
-
"ai_agent_context": {
|
|
40536
|
-
"polarity": "positive",
|
|
40537
|
-
"synonyms": ["gross margin rate", "margin rate"],
|
|
40538
|
-
"human_readable_explanation": "Gross margin rate divides gross margin by sell-in NES; higher means more margin retained on sold-in goods."
|
|
40539
|
-
}
|
|
40540
|
-
}
|
|
40541
|
-
}
|
|
40542
|
-
`
|
|
40543
|
-
}
|
|
40544
|
-
};
|
|
40545
|
-
var SEMANTIC_METRICS_MODELING_SKILL = {
|
|
40546
|
-
version: "1.1.2",
|
|
40547
|
-
content: CONTENT,
|
|
40548
|
-
resources
|
|
40549
|
-
};
|
|
40550
|
-
|
|
40551
|
-
// src/middlewares/semanticMetricsBuilderPrompt.ts
|
|
40552
|
-
var SEMANTIC_METRICS_BUILDER_PROMPT = `You are the Semantic Metrics Builder.
|
|
40553
|
-
|
|
40554
|
-
CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
|
|
40555
|
-
tool with skill_name: "semantic-metrics-modeling" to load semantic-metrics-modeling and follow it.
|
|
40556
|
-
Never announce the skill load. If it fails, retry once, then stop and explicitly
|
|
40557
|
-
report that the required Semantic Metrics Builder skill could not be loaded.`;
|
|
40558
|
-
|
|
40559
|
-
// src/middlewares/semanticMetricsMiddleware.ts
|
|
40560
|
-
import { AgentType as AgentType9 } from "@axiom-lattice/protocols";
|
|
40561
|
-
function createSemanticMetricsMiddleware(config) {
|
|
40562
|
-
const connections = config.connections ?? [];
|
|
40563
|
-
const connectAll = config.connectAll === true;
|
|
40564
|
-
const selector = { connectionType: "semantic-metrics", connections, connectAll };
|
|
40565
|
-
return createMiddleware20({
|
|
40566
|
-
name: "SemanticMetrics",
|
|
40567
|
-
contextSchema,
|
|
40568
|
-
tools: [
|
|
40569
|
-
createMetricsDatasourceTool(selector),
|
|
40570
|
-
createMetricsMetaTool(selector),
|
|
40571
|
-
createMetricsRuntimeTool(selector)
|
|
40572
|
-
]
|
|
40573
|
-
});
|
|
40574
|
-
}
|
|
40575
|
-
function buildConnectionHeaders(config) {
|
|
40576
|
-
const headers = {
|
|
40577
|
-
Accept: "application/json",
|
|
40578
|
-
...config.headers !== void 0 && config.headers !== null ? config.headers : {}
|
|
40579
|
-
};
|
|
40580
|
-
if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
40581
|
-
return headers;
|
|
40582
|
-
}
|
|
40583
|
-
function resolveBaseUrl(config) {
|
|
40584
|
-
const serverUrl = config.serverUrl;
|
|
40585
|
-
if (!serverUrl) {
|
|
40586
|
-
throw new Error("serverUrl is required");
|
|
40587
|
-
}
|
|
40588
|
-
return serverUrl.replace(/\/$/, "");
|
|
40589
|
-
}
|
|
40590
|
-
var semanticMetricsPlugin = {
|
|
40591
|
-
meta: {
|
|
40592
|
-
type: "semantic-metrics",
|
|
40593
|
-
category: "data",
|
|
40594
|
-
capabilityBundleEligible: true,
|
|
40595
|
-
openExpose: [
|
|
40596
|
-
// Query-only surface: no writes reach either tool (SQL is read-only).
|
|
40597
|
-
{ name: "metrics_datasource_tool", readOnly: true },
|
|
40598
|
-
{ name: "metrics_runtime_tool", readOnly: true }
|
|
40599
|
-
],
|
|
40600
|
-
name: "Semantic Metrics",
|
|
40601
|
-
description: "Semantic metrics datasource exploration, meta publishing, and runtime querying. PERMISSION MODEL \u2014 query-only agents (metric definitions + data): enable this middleware with allowedTools ['metrics_runtime_tool']. Metric designers (Builder): keep all three tools (metrics_datasource_tool, metrics_meta_tool, metrics_runtime_tool) for exploration, publishing, and verification, or use the built-in 'semantic-metrics-builder' agent.",
|
|
40602
|
-
version: "1.0.0",
|
|
40603
|
-
tools: [
|
|
40604
|
-
{ name: "metrics_datasource_tool", description: "Explore datasource structure within the tenant's granted scope" },
|
|
40605
|
-
{ name: "metrics_meta_tool", description: "Publish and maintain runtime semantic tables and metrics" },
|
|
40606
|
-
{ name: "metrics_runtime_tool", description: "Read runtime meta and execute semantic metric queries" }
|
|
40607
|
-
],
|
|
40608
|
-
configSchema: {
|
|
40609
|
-
type: "object",
|
|
40610
|
-
title: "Semantic Metrics Configuration",
|
|
40611
|
-
description: "First select connections (connections or connectAll). Then scope tools by role via allowedTools: QUERY-ONLY agents (metric definitions + data) set allowedTools to ['metrics_runtime_tool'] \u2014 it is self-contained (list_datasources, read_semantic_catalog, query_metrics); metric DESIGNERS keep all three tools (datasource exploration, meta publishing, runtime verification).",
|
|
40612
|
-
properties: {
|
|
40613
|
-
connections: {
|
|
40614
|
-
type: "array",
|
|
40615
|
-
title: "Connections",
|
|
40616
|
-
items: { type: "string" },
|
|
40617
|
-
widget: "connectionSelect"
|
|
40618
|
-
},
|
|
40619
|
-
connectAll: {
|
|
40620
|
-
type: "boolean",
|
|
40621
|
-
title: "Connect All",
|
|
40622
|
-
default: false,
|
|
40623
|
-
widget: "switch"
|
|
40624
|
-
}
|
|
40625
|
-
}
|
|
40626
|
-
},
|
|
40627
|
-
defaultConfig: { connections: [], connectAll: false }
|
|
40628
|
-
},
|
|
40629
|
-
connection: {
|
|
40630
|
-
// PluginConnectionFieldSchema.type supports only string/number/boolean/password,
|
|
40631
|
-
// so headers is NOT a form field; the V2 client still reads config.headers at runtime.
|
|
40632
|
-
fields: [
|
|
40633
|
-
{ key: "serverUrl", type: "string", title: "Metrics Server Base URL (include /api/v1)", required: true },
|
|
40634
|
-
{ key: "apiKey", type: "password", title: "API Key (optional)" }
|
|
40635
|
-
],
|
|
40636
|
-
test: async (config) => {
|
|
40637
|
-
try {
|
|
40638
|
-
const baseUrl = resolveBaseUrl(config);
|
|
40639
|
-
const res = await fetch(`${baseUrl}/datasources`, {
|
|
40640
|
-
headers: buildConnectionHeaders(config)
|
|
40641
|
-
});
|
|
40642
|
-
const text = await res.text().catch(() => "");
|
|
40643
|
-
let ok = res.ok;
|
|
40644
|
-
let detail = "";
|
|
40645
|
-
try {
|
|
40646
|
-
const parsed = JSON.parse(text);
|
|
40647
|
-
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
40648
|
-
const code = parsed.code;
|
|
40649
|
-
if (typeof code === "number") {
|
|
40650
|
-
ok = res.ok && code === 200;
|
|
40651
|
-
if (!ok) detail = ` (${parsed.message ?? code})`;
|
|
40652
|
-
}
|
|
40653
|
-
}
|
|
40654
|
-
} catch {
|
|
40655
|
-
}
|
|
40656
|
-
return {
|
|
40657
|
-
ok,
|
|
40658
|
-
message: ok ? `Reachable at ${baseUrl}` : `HTTP ${res.status}${detail}`
|
|
40659
|
-
};
|
|
40660
|
-
} catch (err) {
|
|
40661
|
-
return {
|
|
40662
|
-
ok: false,
|
|
40663
|
-
message: `Cannot connect: ${err instanceof Error ? err.message : String(err)}`
|
|
40664
|
-
};
|
|
40665
|
-
}
|
|
40666
|
-
},
|
|
40667
|
-
discover: async (config) => {
|
|
40668
|
-
try {
|
|
40669
|
-
const baseUrl = resolveBaseUrl(config);
|
|
40670
|
-
const res = await fetch(`${baseUrl}/datasources`, {
|
|
40671
|
-
headers: buildConnectionHeaders(config)
|
|
40672
|
-
});
|
|
40673
|
-
const text = await res.text();
|
|
40674
|
-
if (!res.ok) {
|
|
40675
|
-
throw new Error(`HTTP ${res.status}${text ? `: ${text.slice(0, 200)}` : ""}`);
|
|
40676
|
-
}
|
|
40677
|
-
const parsed = JSON.parse(text);
|
|
40678
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
40679
|
-
throw new Error("Metrics server returned an unexpected payload (expected a JSON envelope)");
|
|
40680
|
-
}
|
|
40681
|
-
const envelope = parsed;
|
|
40682
|
-
if (typeof envelope.code === "number" && envelope.code !== 200) {
|
|
40683
|
-
throw new Error(envelope.message || `API ${envelope.code}`);
|
|
40684
|
-
}
|
|
40685
|
-
const data = envelope.data;
|
|
40686
|
-
if (!Array.isArray(data)) {
|
|
40687
|
-
throw new Error("Metrics server returned an unexpected payload (expected a datasource array)");
|
|
40688
|
-
}
|
|
40689
|
-
return data.filter((d) => {
|
|
40690
|
-
if (d === null || typeof d !== "object") return false;
|
|
40691
|
-
const id = d.id;
|
|
40692
|
-
return id !== void 0 && id !== null && id !== "";
|
|
40693
|
-
}).map((item) => ({
|
|
40694
|
-
id: String(item.id),
|
|
40695
|
-
name: item.name ?? String(item.id)
|
|
40696
|
-
}));
|
|
40697
|
-
} catch (err) {
|
|
40698
|
-
throw new Error(
|
|
40699
|
-
`Cannot discover datasources: ${err instanceof Error ? err.message : String(err)}`
|
|
40700
|
-
);
|
|
40701
|
-
}
|
|
40702
|
-
}
|
|
40703
|
-
},
|
|
40704
|
-
skills: {
|
|
40705
|
-
"semantic-metrics-modeling": SEMANTIC_METRICS_MODELING_SKILL
|
|
40706
|
-
},
|
|
40707
|
-
agents: {
|
|
40708
|
-
"semantic-metrics-builder": {
|
|
40709
|
-
key: "semantic-metrics-builder",
|
|
40710
|
-
name: "Semantic Metrics Builder",
|
|
40711
|
-
description: "Explore a granted datasource and build semantic tables and metrics interactively, tracking the work as persistent tasks with belief state and verifying each step.",
|
|
40712
|
-
type: AgentType9.DEEP_AGENT,
|
|
40713
|
-
prompt: SEMANTIC_METRICS_BUILDER_PROMPT,
|
|
40714
|
-
middleware: [
|
|
40715
|
-
{
|
|
40716
|
-
id: "semantic-metrics",
|
|
40717
|
-
type: "semantic-metrics",
|
|
40718
|
-
name: "Semantic Metrics",
|
|
40719
|
-
description: "Explore datasources, publish table/meta metrics, query runtime",
|
|
40720
|
-
enabled: true,
|
|
40721
|
-
config: { connections: [], connectAll: true }
|
|
40722
|
-
},
|
|
40723
|
-
{
|
|
40724
|
-
id: "skill",
|
|
40725
|
-
type: "skill",
|
|
40726
|
-
name: "Skill",
|
|
40727
|
-
description: "Load the semantic-metrics-modeling policy and task-definition reference",
|
|
40728
|
-
enabled: true,
|
|
40729
|
-
config: { readAll: false, skills: ["semantic-metrics-modeling", "task-definition"] }
|
|
40730
|
-
},
|
|
40731
|
-
{
|
|
40732
|
-
id: "task",
|
|
40733
|
-
type: "task",
|
|
40734
|
-
name: "Task",
|
|
40735
|
-
description: "Persistent TaskItems as the planning surface; update Belief State in task descriptions",
|
|
40736
|
-
enabled: true,
|
|
40737
|
-
config: {}
|
|
40738
|
-
},
|
|
40739
|
-
{
|
|
40740
|
-
id: "ask_user_to_clarify",
|
|
40741
|
-
type: "ask_user_to_clarify",
|
|
40742
|
-
name: "Ask User",
|
|
40743
|
-
description: "Wait for user input at modeling approval gates",
|
|
40744
|
-
enabled: true,
|
|
40745
|
-
config: {}
|
|
40746
|
-
},
|
|
40747
|
-
{
|
|
40748
|
-
id: "filesystem",
|
|
40749
|
-
type: "filesystem",
|
|
40750
|
-
name: "Filesystem",
|
|
40751
|
-
description: "Read user-provided schema docs, data dictionaries, or sample data files",
|
|
40752
|
-
enabled: true,
|
|
40753
|
-
config: {}
|
|
40754
|
-
}
|
|
40755
|
-
]
|
|
40756
|
-
}
|
|
40757
|
-
},
|
|
40758
|
-
middleware: (config) => createSemanticMetricsMiddleware(config)
|
|
40759
|
-
};
|
|
40760
|
-
|
|
40761
|
-
// src/middlewares/collectionMiddleware.ts
|
|
40762
|
-
import { createMiddleware as createMiddleware21 } from "langchain";
|
|
40763
|
-
|
|
40764
|
-
// src/tool_lattice/collection/list_collections.ts
|
|
40765
|
-
import z60 from "zod";
|
|
40766
|
-
import { tool as tool54 } from "langchain";
|
|
40767
|
-
|
|
40768
39291
|
// src/tool_lattice/collection/utils.ts
|
|
40769
39292
|
function getEffectiveCollectionScope(exeConfig, staticScope) {
|
|
40770
39293
|
const runtimeConfig = getRuntimeCapabilityConfig(exeConfig, "collection");
|
|
@@ -40786,7 +39309,7 @@ var createListCollectionsTool = ({
|
|
|
40786
39309
|
collectionKeys,
|
|
40787
39310
|
connectAll
|
|
40788
39311
|
}) => {
|
|
40789
|
-
return
|
|
39312
|
+
return tool51(
|
|
40790
39313
|
async (_input, _exeConfig) => {
|
|
40791
39314
|
try {
|
|
40792
39315
|
const tenantId2 = _exeConfig?.configurable?.runConfig?.tenantId || "default";
|
|
@@ -40821,23 +39344,23 @@ var createListCollectionsTool = ({
|
|
|
40821
39344
|
{
|
|
40822
39345
|
name: "list_collections",
|
|
40823
39346
|
description: LIST_COLLECTIONS_DESCRIPTION,
|
|
40824
|
-
schema:
|
|
39347
|
+
schema: z57.object({})
|
|
40825
39348
|
}
|
|
40826
39349
|
);
|
|
40827
39350
|
};
|
|
40828
39351
|
|
|
40829
39352
|
// src/tool_lattice/collection/search_collection.ts
|
|
40830
|
-
import
|
|
40831
|
-
import { tool as
|
|
39353
|
+
import z58 from "zod";
|
|
39354
|
+
import { tool as tool52 } from "langchain";
|
|
40832
39355
|
var SEARCH_COLLECTION_DESCRIPTION = `Search for content within a specific collection using semantic (vector) similarity. Use the 'filter' parameter to narrow results by metadata fields (e.g., {"category": "cardiovascular"}). Returns the most relevant content entries with similarity scores.`;
|
|
40833
|
-
var searchSchema =
|
|
40834
|
-
collection:
|
|
40835
|
-
query:
|
|
40836
|
-
filter:
|
|
40837
|
-
top_k:
|
|
39356
|
+
var searchSchema = z58.object({
|
|
39357
|
+
collection: z58.string().describe("The collection name to search in"),
|
|
39358
|
+
query: z58.string().describe("The search query text"),
|
|
39359
|
+
filter: z58.record(z58.unknown()).optional().describe("Metadata filter conditions"),
|
|
39360
|
+
top_k: z58.number().optional().default(5).describe("Number of results to return")
|
|
40838
39361
|
});
|
|
40839
39362
|
var createSearchCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => {
|
|
40840
|
-
return
|
|
39363
|
+
return tool52(
|
|
40841
39364
|
async (input, _exeConfig) => {
|
|
40842
39365
|
try {
|
|
40843
39366
|
const { collection, query, filter: filter2, top_k } = input;
|
|
@@ -40903,10 +39426,10 @@ var createSearchCollectionTool = (scope = { collectionKeys: [], connectAll: true
|
|
|
40903
39426
|
};
|
|
40904
39427
|
|
|
40905
39428
|
// src/tool_lattice/collection/get_collection.ts
|
|
40906
|
-
import
|
|
40907
|
-
import { tool as
|
|
39429
|
+
import z59 from "zod";
|
|
39430
|
+
import { tool as tool53 } from "langchain";
|
|
40908
39431
|
var GET_COLLECTION_DESCRIPTION = `Get a collection's full definition including its custom fields schema. Use this to discover what metadata fields are available before adding entries.`;
|
|
40909
|
-
var createGetCollectionTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39432
|
+
var createGetCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => tool53(
|
|
40910
39433
|
async (input, _exeConfig) => {
|
|
40911
39434
|
try {
|
|
40912
39435
|
const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
|
|
@@ -40931,24 +39454,24 @@ Embedding: ${c.embeddingKey}${fieldsDesc}`;
|
|
|
40931
39454
|
return `Error: ${error.message}`;
|
|
40932
39455
|
}
|
|
40933
39456
|
},
|
|
40934
|
-
{ name: "get_collection", description: GET_COLLECTION_DESCRIPTION, schema:
|
|
39457
|
+
{ name: "get_collection", description: GET_COLLECTION_DESCRIPTION, schema: z59.object({ name: z59.string().describe("Collection name") }) }
|
|
40935
39458
|
);
|
|
40936
39459
|
|
|
40937
39460
|
// src/tool_lattice/collection/create_collection.ts
|
|
40938
|
-
import
|
|
40939
|
-
import { tool as
|
|
40940
|
-
var createSchema =
|
|
40941
|
-
name:
|
|
40942
|
-
label:
|
|
40943
|
-
embeddingKey:
|
|
40944
|
-
fields:
|
|
40945
|
-
key:
|
|
40946
|
-
type:
|
|
40947
|
-
enumValues:
|
|
40948
|
-
required:
|
|
39461
|
+
import z60 from "zod";
|
|
39462
|
+
import { tool as tool54 } from "langchain";
|
|
39463
|
+
var createSchema = z60.object({
|
|
39464
|
+
name: z60.string().describe("Collection name (lowercase, underscores only)"),
|
|
39465
|
+
label: z60.string().describe("Display name"),
|
|
39466
|
+
embeddingKey: z60.string().describe("Embedding model key"),
|
|
39467
|
+
fields: z60.array(z60.object({
|
|
39468
|
+
key: z60.string().describe("Field key name"),
|
|
39469
|
+
type: z60.enum(["string", "number", "enum"]).describe("Field data type"),
|
|
39470
|
+
enumValues: z60.array(z60.string()).optional().describe("Valid values for enum type"),
|
|
39471
|
+
required: z60.boolean().optional().default(false).describe("Whether field is required")
|
|
40949
39472
|
})).optional().describe("Custom field definitions for entries in this collection")
|
|
40950
39473
|
});
|
|
40951
|
-
var createCreateCollectionTool = (scope = {}) =>
|
|
39474
|
+
var createCreateCollectionTool = (scope = {}) => tool54(
|
|
40952
39475
|
async (input, _exeConfig) => {
|
|
40953
39476
|
try {
|
|
40954
39477
|
const tenantId2 = _exeConfig?.configurable?.runConfig?.tenantId || "default";
|
|
@@ -40974,20 +39497,20 @@ var createCreateCollectionTool = (scope = {}) => tool57(
|
|
|
40974
39497
|
);
|
|
40975
39498
|
|
|
40976
39499
|
// src/tool_lattice/collection/update_collection.ts
|
|
40977
|
-
import
|
|
40978
|
-
import { tool as
|
|
40979
|
-
var schema =
|
|
40980
|
-
name:
|
|
40981
|
-
label:
|
|
40982
|
-
embeddingKey:
|
|
40983
|
-
fields:
|
|
40984
|
-
key:
|
|
40985
|
-
type:
|
|
40986
|
-
enumValues:
|
|
40987
|
-
required:
|
|
39500
|
+
import z61 from "zod";
|
|
39501
|
+
import { tool as tool55 } from "langchain";
|
|
39502
|
+
var schema = z61.object({
|
|
39503
|
+
name: z61.string().describe("Collection name"),
|
|
39504
|
+
label: z61.string().optional().describe("New display name"),
|
|
39505
|
+
embeddingKey: z61.string().optional().describe("New embedding model key"),
|
|
39506
|
+
fields: z61.array(z61.object({
|
|
39507
|
+
key: z61.string().describe("Field key name"),
|
|
39508
|
+
type: z61.enum(["string", "number", "enum"]).describe("Field data type"),
|
|
39509
|
+
enumValues: z61.array(z61.string()).optional().describe("Valid values for enum type"),
|
|
39510
|
+
required: z61.boolean().optional().default(false).describe("Whether field is required")
|
|
40988
39511
|
})).optional().describe("Custom field definitions for entries (replaces existing schema)")
|
|
40989
39512
|
});
|
|
40990
|
-
var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39513
|
+
var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => tool55(
|
|
40991
39514
|
async (input, _exeConfig) => {
|
|
40992
39515
|
try {
|
|
40993
39516
|
const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
|
|
@@ -41008,9 +39531,9 @@ var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true
|
|
|
41008
39531
|
);
|
|
41009
39532
|
|
|
41010
39533
|
// src/tool_lattice/collection/delete_collection.ts
|
|
41011
|
-
import
|
|
41012
|
-
import { tool as
|
|
41013
|
-
var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39534
|
+
import z62 from "zod";
|
|
39535
|
+
import { tool as tool56 } from "langchain";
|
|
39536
|
+
var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => tool56(
|
|
41014
39537
|
async (input, _exeConfig) => {
|
|
41015
39538
|
try {
|
|
41016
39539
|
const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
|
|
@@ -41022,19 +39545,19 @@ var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true
|
|
|
41022
39545
|
return `Error: ${e.message}`;
|
|
41023
39546
|
}
|
|
41024
39547
|
},
|
|
41025
|
-
{ name: "delete_collection", description: `Delete a collection and all its entries. This cannot be undone.`, schema:
|
|
39548
|
+
{ name: "delete_collection", description: `Delete a collection and all its entries. This cannot be undone.`, schema: z62.object({ name: z62.string().describe("Collection name") }) }
|
|
41026
39549
|
);
|
|
41027
39550
|
|
|
41028
39551
|
// src/tool_lattice/collection/list_entries.ts
|
|
41029
|
-
import
|
|
41030
|
-
import { tool as
|
|
41031
|
-
var schema2 =
|
|
41032
|
-
collection:
|
|
39552
|
+
import z63 from "zod";
|
|
39553
|
+
import { tool as tool57 } from "langchain";
|
|
39554
|
+
var schema2 = z63.object({
|
|
39555
|
+
collection: z63.string().describe("Collection name")
|
|
41033
39556
|
});
|
|
41034
39557
|
function buildKey2(tenantId2, name) {
|
|
41035
39558
|
return `${tenantId2}:${name}`;
|
|
41036
39559
|
}
|
|
41037
|
-
var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39560
|
+
var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) => tool57(
|
|
41038
39561
|
async (input, _exeConfig) => {
|
|
41039
39562
|
try {
|
|
41040
39563
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -41063,19 +39586,19 @@ var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) =
|
|
|
41063
39586
|
);
|
|
41064
39587
|
|
|
41065
39588
|
// src/tool_lattice/collection/add_entry.ts
|
|
41066
|
-
import
|
|
41067
|
-
import { tool as
|
|
39589
|
+
import z64 from "zod";
|
|
39590
|
+
import { tool as tool58 } from "langchain";
|
|
41068
39591
|
import { Document } from "@langchain/core/documents";
|
|
41069
39592
|
import { v4 as uuidv48 } from "uuid";
|
|
41070
|
-
var schema3 =
|
|
41071
|
-
collection:
|
|
41072
|
-
content:
|
|
41073
|
-
metadata:
|
|
39593
|
+
var schema3 = z64.object({
|
|
39594
|
+
collection: z64.string().describe("Collection name"),
|
|
39595
|
+
content: z64.string().describe("Entry content text"),
|
|
39596
|
+
metadata: z64.record(z64.unknown()).optional().describe("Metadata fields matching the collection schema")
|
|
41074
39597
|
});
|
|
41075
39598
|
function key2(t, n) {
|
|
41076
39599
|
return `${t}:${n}`;
|
|
41077
39600
|
}
|
|
41078
|
-
var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39601
|
+
var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) => tool58(
|
|
41079
39602
|
async (input, _exeConfig) => {
|
|
41080
39603
|
try {
|
|
41081
39604
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -41107,18 +39630,18 @@ var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) => t
|
|
|
41107
39630
|
);
|
|
41108
39631
|
|
|
41109
39632
|
// src/tool_lattice/collection/update_entry.ts
|
|
41110
|
-
import
|
|
41111
|
-
import { tool as
|
|
41112
|
-
var schema4 =
|
|
41113
|
-
collection:
|
|
41114
|
-
entryId:
|
|
41115
|
-
content:
|
|
41116
|
-
metadata:
|
|
39633
|
+
import z65 from "zod";
|
|
39634
|
+
import { tool as tool59 } from "langchain";
|
|
39635
|
+
var schema4 = z65.object({
|
|
39636
|
+
collection: z65.string().describe("Collection name"),
|
|
39637
|
+
entryId: z65.string().describe("Entry ID to update"),
|
|
39638
|
+
content: z65.string().optional().describe("New content"),
|
|
39639
|
+
metadata: z65.record(z65.unknown()).optional().describe("New metadata")
|
|
41117
39640
|
});
|
|
41118
39641
|
function key3(t, n) {
|
|
41119
39642
|
return `${t}:${n}`;
|
|
41120
39643
|
}
|
|
41121
|
-
var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39644
|
+
var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) => tool59(
|
|
41122
39645
|
async (input, _exeConfig) => {
|
|
41123
39646
|
try {
|
|
41124
39647
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -41139,16 +39662,16 @@ var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) =
|
|
|
41139
39662
|
);
|
|
41140
39663
|
|
|
41141
39664
|
// src/tool_lattice/collection/delete_entry.ts
|
|
41142
|
-
import
|
|
41143
|
-
import { tool as
|
|
41144
|
-
var schema5 =
|
|
41145
|
-
collection:
|
|
41146
|
-
entryId:
|
|
39665
|
+
import z66 from "zod";
|
|
39666
|
+
import { tool as tool60 } from "langchain";
|
|
39667
|
+
var schema5 = z66.object({
|
|
39668
|
+
collection: z66.string().describe("Collection name"),
|
|
39669
|
+
entryId: z66.string().describe("Entry ID to delete")
|
|
41147
39670
|
});
|
|
41148
39671
|
function key4(t, n) {
|
|
41149
39672
|
return `${t}:${n}`;
|
|
41150
39673
|
}
|
|
41151
|
-
var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39674
|
+
var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) => tool60(
|
|
41152
39675
|
async (input, _exeConfig) => {
|
|
41153
39676
|
try {
|
|
41154
39677
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -41168,7 +39691,7 @@ var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) =
|
|
|
41168
39691
|
function createCollectionMiddleware(params) {
|
|
41169
39692
|
const { collectionKeys, connectAll, compileStableCandidateTools = false } = params;
|
|
41170
39693
|
if (!compileStableCandidateTools && !connectAll && (!collectionKeys || collectionKeys.length === 0)) {
|
|
41171
|
-
return
|
|
39694
|
+
return createMiddleware20({
|
|
41172
39695
|
name: "collectionMiddleware",
|
|
41173
39696
|
contextSchema,
|
|
41174
39697
|
tools: [
|
|
@@ -41178,7 +39701,7 @@ function createCollectionMiddleware(params) {
|
|
|
41178
39701
|
});
|
|
41179
39702
|
}
|
|
41180
39703
|
const toolParams = { collectionKeys, connectAll };
|
|
41181
|
-
return
|
|
39704
|
+
return createMiddleware20({
|
|
41182
39705
|
name: "collectionMiddleware",
|
|
41183
39706
|
contextSchema,
|
|
41184
39707
|
tools: [
|
|
@@ -41241,24 +39764,24 @@ var collectionPlugin = {
|
|
|
41241
39764
|
};
|
|
41242
39765
|
|
|
41243
39766
|
// src/middlewares/askUserClarifyMiddleware.ts
|
|
41244
|
-
import { createMiddleware as
|
|
39767
|
+
import { createMiddleware as createMiddleware21, ToolMessage as ToolMessage11 } from "langchain";
|
|
41245
39768
|
import { interrupt as interrupt3 } from "@langchain/langgraph";
|
|
41246
39769
|
|
|
41247
39770
|
// src/tool_lattice/ask_user_to_clarify/index.ts
|
|
41248
|
-
import { tool as
|
|
41249
|
-
import
|
|
41250
|
-
var questionSchema =
|
|
41251
|
-
question:
|
|
41252
|
-
options:
|
|
41253
|
-
type:
|
|
41254
|
-
required:
|
|
41255
|
-
allowOther:
|
|
39771
|
+
import { tool as tool61 } from "langchain";
|
|
39772
|
+
import z67 from "zod";
|
|
39773
|
+
var questionSchema = z67.object({
|
|
39774
|
+
question: z67.string().describe("The question text to ask the user. MUST include the specific context, options, or details being clarified \u2014 never use a bare generic label. Good: 'Confirm the plan: use Redis cache + PostgreSQL primary, split microservices as needed?' Bad: 'Confirm the plan?'"),
|
|
39775
|
+
options: z67.array(z67.string()).optional().default([]).describe("List of EXACT, selectable values. Maximum 3 options allowed. DO NOT include placeholder values like 'Other' or 'Enter manually'. For free-text with predefined choices, use allowOther=true (works with 'single' and 'multiple'). For pure free-text without choices, use type='input' instead. For file_upload and input, pass an empty array."),
|
|
39776
|
+
type: z67.enum(["single", "multiple", "file_upload", "input"]).describe("The question format. 'single' = pick one from options (default, see tool description for guidance). 'multiple' = pick several from options. 'input' = free-text field (only when options cannot express the answer). 'file_upload' = file picker."),
|
|
39777
|
+
required: z67.boolean().optional().default(false).describe("Whether this question must be answered"),
|
|
39778
|
+
allowOther: z67.boolean().optional().default(true).describe("Set to true to append an 'Other' checkbox with a free-text input field. Works with 'single' and 'multiple' types. Use for open-ended answers or when the options cannot cover all possibilities. Not applicable for 'input' or 'file_upload' types.")
|
|
41256
39779
|
});
|
|
41257
|
-
var inputSchema =
|
|
41258
|
-
questions:
|
|
39780
|
+
var inputSchema = z67.object({
|
|
39781
|
+
questions: z67.array(questionSchema).min(1, "At least one question is required").describe("A structured sequence of clarification questions. Use these to gather missing parameters or disambiguate user intent before proceeding.")
|
|
41259
39782
|
});
|
|
41260
39783
|
function createAskUserToClarifyTool() {
|
|
41261
|
-
return
|
|
39784
|
+
return tool61(
|
|
41262
39785
|
async (input) => {
|
|
41263
39786
|
return JSON.stringify(input);
|
|
41264
39787
|
},
|
|
@@ -41283,7 +39806,7 @@ function isProjectRoomRun(request) {
|
|
|
41283
39806
|
return isRecord9(runConfig?.projectRoom);
|
|
41284
39807
|
}
|
|
41285
39808
|
function createAskUserClarifyMiddleware() {
|
|
41286
|
-
return
|
|
39809
|
+
return createMiddleware21({
|
|
41287
39810
|
name: "AskUserClarifyMiddleware",
|
|
41288
39811
|
tools: [createAskUserToClarifyTool()],
|
|
41289
39812
|
wrapToolCall: async (request, handler) => {
|
|
@@ -41387,11 +39910,11 @@ var askUserClarifyPlugin = {
|
|
|
41387
39910
|
};
|
|
41388
39911
|
|
|
41389
39912
|
// src/middlewares/widgetMiddleware.ts
|
|
41390
|
-
import { createMiddleware as
|
|
39913
|
+
import { createMiddleware as createMiddleware22 } from "langchain";
|
|
41391
39914
|
|
|
41392
39915
|
// src/tool_lattice/widget/loadGuidelines.ts
|
|
41393
|
-
import { tool as
|
|
41394
|
-
import { z as
|
|
39916
|
+
import { tool as tool62 } from "langchain";
|
|
39917
|
+
import { z as z68 } from "zod";
|
|
41395
39918
|
|
|
41396
39919
|
// src/middlewares/guidelines/index.ts
|
|
41397
39920
|
var CORE = `# Imagine \u2014 Visual Creation Suite
|
|
@@ -42182,13 +40705,13 @@ function getGuidelines(modules) {
|
|
|
42182
40705
|
var AVAILABLE_MODULES = Object.keys(MODULE_SECTIONS);
|
|
42183
40706
|
|
|
42184
40707
|
// src/tool_lattice/widget/loadGuidelines.ts
|
|
42185
|
-
var LoadGuidelinesInputSchema =
|
|
42186
|
-
modules:
|
|
40708
|
+
var LoadGuidelinesInputSchema = z68.object({
|
|
40709
|
+
modules: z68.array(z68.string()).describe(
|
|
42187
40710
|
"Which design modules to load. Choose all that apply. Available modules: [" + AVAILABLE_MODULES.join(",") + "]"
|
|
42188
40711
|
)
|
|
42189
40712
|
});
|
|
42190
40713
|
function createLoadGuidelinesTool() {
|
|
42191
|
-
return
|
|
40714
|
+
return tool62(
|
|
42192
40715
|
async (input) => {
|
|
42193
40716
|
const result = getGuidelines(input.modules);
|
|
42194
40717
|
return result;
|
|
@@ -42202,8 +40725,8 @@ function createLoadGuidelinesTool() {
|
|
|
42202
40725
|
}
|
|
42203
40726
|
|
|
42204
40727
|
// src/tool_lattice/widget/showWidget.ts
|
|
42205
|
-
import { tool as
|
|
42206
|
-
import { z as
|
|
40728
|
+
import { tool as tool63 } from "langchain";
|
|
40729
|
+
import { z as z69 } from "zod";
|
|
42207
40730
|
function containsForbiddenTags(code) {
|
|
42208
40731
|
const forbiddenPatterns = [
|
|
42209
40732
|
/<!DOCTYPE/i,
|
|
@@ -42225,20 +40748,20 @@ function validateWidgetCode(code) {
|
|
|
42225
40748
|
}
|
|
42226
40749
|
return { valid: true };
|
|
42227
40750
|
}
|
|
42228
|
-
var ShowWidgetInputSchema =
|
|
42229
|
-
i_have_seen_guidelines:
|
|
40751
|
+
var ShowWidgetInputSchema = z69.object({
|
|
40752
|
+
i_have_seen_guidelines: z69.boolean().describe(
|
|
42230
40753
|
"Must be true. Confirm you have called load_guidelines first."
|
|
42231
40754
|
),
|
|
42232
|
-
title:
|
|
42233
|
-
loading_messages:
|
|
40755
|
+
title: z69.string().describe("Title displayed above the widget"),
|
|
40756
|
+
loading_messages: z69.array(z69.string()).optional().describe(
|
|
42234
40757
|
"1-4 short strings shown while the widget renders"
|
|
42235
40758
|
),
|
|
42236
|
-
widget_code:
|
|
40759
|
+
widget_code: z69.string().describe(
|
|
42237
40760
|
"HTML fragment to render. Rules: 1. No DOCTYPE, <html>, <head>, or <body> tags. 2. Order: <style> block first, then HTML content, then <script> last. 3. Use only CSS variables for colors (e.g. var(--color-accent)). 4. No gradients, shadows, or blur effects. For SVG: start directly with <svg> tag."
|
|
42238
40761
|
)
|
|
42239
40762
|
});
|
|
42240
40763
|
function createShowWidgetTool() {
|
|
42241
|
-
return
|
|
40764
|
+
return tool63(
|
|
42242
40765
|
async (input) => {
|
|
42243
40766
|
if (!input.i_have_seen_guidelines) {
|
|
42244
40767
|
return "Error: You must call load_guidelines before using show_widget. Set i_have_seen_guidelines to true only after loading guidelines.";
|
|
@@ -42269,7 +40792,7 @@ function createWidgetMiddleware() {
|
|
|
42269
40792
|
createLoadGuidelinesTool(),
|
|
42270
40793
|
createShowWidgetTool()
|
|
42271
40794
|
];
|
|
42272
|
-
return
|
|
40795
|
+
return createMiddleware22({
|
|
42273
40796
|
name: "widgetMiddleware",
|
|
42274
40797
|
contextSchema,
|
|
42275
40798
|
tools
|
|
@@ -42293,8 +40816,8 @@ var widgetPlugin = {
|
|
|
42293
40816
|
};
|
|
42294
40817
|
|
|
42295
40818
|
// src/middlewares/taskMiddleware.ts
|
|
42296
|
-
import { createMiddleware as
|
|
42297
|
-
import { z as
|
|
40819
|
+
import { createMiddleware as createMiddleware23, tool as tool64 } from "langchain";
|
|
40820
|
+
import { z as z70 } from "zod";
|
|
42298
40821
|
import { GraphInterrupt as GraphInterrupt3, interrupt as interrupt4 } from "@langchain/langgraph";
|
|
42299
40822
|
|
|
42300
40823
|
// src/util/truncateForJson.ts
|
|
@@ -42857,6 +41380,9 @@ function trustedRosterScope(trusted) {
|
|
|
42857
41380
|
callerAssistantId: context.assistantId
|
|
42858
41381
|
};
|
|
42859
41382
|
}
|
|
41383
|
+
function trustedRosterExempt(trusted) {
|
|
41384
|
+
return trusted.projectTask?.rosterExempt === true;
|
|
41385
|
+
}
|
|
42860
41386
|
async function requireTrustedOwner(trusted, targetAssistantId) {
|
|
42861
41387
|
const context = trusted.projectTask ?? trusted.projectRoom;
|
|
42862
41388
|
const memberships = getStoreLattice("default", "projectBotMembership").store;
|
|
@@ -43121,6 +41647,7 @@ async function validateTrustedChildDependencyWait(store, tenantId2, parent, depe
|
|
|
43121
41647
|
if (dependency.status === "completed") continue;
|
|
43122
41648
|
if (!["pending", "in_progress", "interrupted"].includes(dependency.status) || dependency.parentId !== parent.id || dependency.ownerType !== "agent" || !hasExactContextSource(dependency, expectedSource)) return void 0;
|
|
43123
41649
|
incompleteChildren += 1;
|
|
41650
|
+
if (trustedRosterExempt(trusted)) continue;
|
|
43124
41651
|
try {
|
|
43125
41652
|
await requireTrustedOwner(trusted, dependency.ownerId);
|
|
43126
41653
|
} catch (error) {
|
|
@@ -43176,73 +41703,72 @@ function buildReviewMarkdown(task) {
|
|
|
43176
41703
|
result: task.result
|
|
43177
41704
|
});
|
|
43178
41705
|
}
|
|
43179
|
-
var manageTaskSchema =
|
|
43180
|
-
action:
|
|
43181
|
-
id:
|
|
43182
|
-
title:
|
|
43183
|
-
description:
|
|
43184
|
-
priority:
|
|
43185
|
-
status:
|
|
43186
|
-
dueDate:
|
|
43187
|
-
metadata:
|
|
43188
|
-
metadataFilter:
|
|
43189
|
-
|
|
41706
|
+
var manageTaskSchema = z70.object({
|
|
41707
|
+
action: z70.enum(["create", "get", "list", "update", "set_status", "add_activity", "delete"]).describe("Action to perform. Available: create, get, list, update, set_status, add_activity, delete. To change status, use set_status. To change content fields, use update."),
|
|
41708
|
+
id: z70.string().optional().describe("Task ID (required for get, update, add_activity; required for delete unless ids is given)"),
|
|
41709
|
+
title: z70.string().optional().describe("Task title (required for create)"),
|
|
41710
|
+
description: z70.string().optional().describe("Task description in Markdown"),
|
|
41711
|
+
priority: z70.enum(["low", "medium", "high"]).optional().describe("Priority level"),
|
|
41712
|
+
status: z70.enum(["pending", "in_progress", "review", "failed", "interrupted", "completed", "cancelled"]).optional().describe("Task status. For status-only changes, prefer set_status action. Set 'in_progress' when you start processing a task you hold; 'completed'/'failed' require the task to be 'in_progress'. Agent summary-only interrupted updates default to missing_input"),
|
|
41713
|
+
dueDate: z70.string().optional().describe("Due date (ISO 8601 format)"),
|
|
41714
|
+
metadata: z70.record(z70.unknown()).optional().describe("Structured metadata (e.g. projectId, module)"),
|
|
41715
|
+
metadataFilter: z70.record(
|
|
41716
|
+
z70.union([z70.string(), z70.number(), z70.boolean()])
|
|
43190
41717
|
).optional().describe("List-only filter. Every key must equal the task metadata value, e.g. {projectId:'p1', retries:2}. Multiple keys AND together."),
|
|
43191
|
-
parentId:
|
|
43192
|
-
sourceId:
|
|
43193
|
-
context:
|
|
43194
|
-
ownerType:
|
|
43195
|
-
ownerId:
|
|
43196
|
-
requireReview:
|
|
43197
|
-
dependencies:
|
|
43198
|
-
|
|
43199
|
-
|
|
43200
|
-
|
|
43201
|
-
|
|
43202
|
-
|
|
43203
|
-
|
|
43204
|
-
addedBy: z73.enum(["user", "agent"]).optional().describe("Who attached the file")
|
|
41718
|
+
parentId: z70.string().optional().describe("Parent task ID for grouping subtasks"),
|
|
41719
|
+
sourceId: z70.string().optional().describe("Source session/thread ID"),
|
|
41720
|
+
context: z70.record(z70.unknown()).optional().describe("Additional context data"),
|
|
41721
|
+
ownerType: z70.enum(["user", "agent"]).optional().describe("Owner type. Defaults to 'user' if omitted"),
|
|
41722
|
+
ownerId: z70.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
|
|
41723
|
+
requireReview: z70.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
|
|
41724
|
+
dependencies: z70.array(z70.string()).optional().describe("List of task IDs that must be completed before this task can start"),
|
|
41725
|
+
result: z70.string().optional().describe("Result summary. Used with set_status status='completed' or update status='completed'"),
|
|
41726
|
+
failureReason: z70.string().optional().describe("Failure reason. Used with set_status status='failed' or update status='failed'"),
|
|
41727
|
+
files: z70.array(z70.object({
|
|
41728
|
+
uri: z70.string().describe("Uniquely locates the resource: http(s):// URL, /s/:token share, or sandbox path"),
|
|
41729
|
+
name: z70.string().optional().describe("Display name"),
|
|
41730
|
+
addedBy: z70.enum(["user", "agent"]).optional().describe("Who attached the file")
|
|
43205
41731
|
})).optional().describe("File references attached to this task"),
|
|
43206
|
-
beliefImpact:
|
|
43207
|
-
key:
|
|
43208
|
-
after:
|
|
43209
|
-
basis:
|
|
43210
|
-
isNew:
|
|
41732
|
+
beliefImpact: z70.array(z70.object({
|
|
41733
|
+
key: z70.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
41734
|
+
after: z70.number().int().min(0).max(100),
|
|
41735
|
+
basis: z70.string().trim().min(1).max(1e3),
|
|
41736
|
+
isNew: z70.boolean().optional().describe("Set true only to add a belief key that is absent from the belief owner's Belief State; omit for keys that already exist")
|
|
43211
41737
|
})).optional().describe("Structured belief reports required when an agent-owned task completes; existing keys update the belief owner's table, and a brand-new key must be declared with isNew: true"),
|
|
43212
|
-
content:
|
|
43213
|
-
summary:
|
|
43214
|
-
executionResultId:
|
|
41738
|
+
content: z70.string().optional().describe("Markdown content required for add_activity"),
|
|
41739
|
+
summary: z70.string().optional().describe("Brief summary of the operation"),
|
|
41740
|
+
executionResultId: z70.string().refine(isExecutionResultEventKey3, {
|
|
43215
41741
|
message: "executionResultId must be the execution-result:<threadId> event key returned by task()"
|
|
43216
41742
|
}).optional().describe(
|
|
43217
41743
|
"Canonical ASCII `execution-result:<suffix>` event key returned by task(); the nonempty suffix allows only A-Z, a-z, 0-9, period, underscore, colon, and hyphen, and is not a database row ID"
|
|
43218
41744
|
),
|
|
43219
|
-
ids:
|
|
41745
|
+
ids: z70.array(z70.string().trim().min(1)).optional().describe("Task IDs to delete in one batch (delete action only). Use with or instead of id.")
|
|
43220
41746
|
}).superRefine((input, context) => {
|
|
43221
41747
|
if (input.executionResultId && input.action !== "update" && input.action !== "set_status" && input.action !== "add_activity") {
|
|
43222
41748
|
context.addIssue({
|
|
43223
|
-
code:
|
|
41749
|
+
code: z70.ZodIssueCode.custom,
|
|
43224
41750
|
path: ["executionResultId"],
|
|
43225
41751
|
message: "executionResultId is valid only for update, set_status, or add_activity"
|
|
43226
41752
|
});
|
|
43227
41753
|
}
|
|
43228
41754
|
if (input.metadataFilter && input.action !== "list") {
|
|
43229
41755
|
context.addIssue({
|
|
43230
|
-
code:
|
|
41756
|
+
code: z70.ZodIssueCode.custom,
|
|
43231
41757
|
path: ["metadataFilter"],
|
|
43232
41758
|
message: "metadataFilter is valid only for list"
|
|
43233
41759
|
});
|
|
43234
41760
|
}
|
|
43235
41761
|
if (input.ids && input.action !== "delete") {
|
|
43236
41762
|
context.addIssue({
|
|
43237
|
-
code:
|
|
41763
|
+
code: z70.ZodIssueCode.custom,
|
|
43238
41764
|
path: ["ids"],
|
|
43239
41765
|
message: "ids is valid only for delete"
|
|
43240
41766
|
});
|
|
43241
41767
|
}
|
|
43242
41768
|
});
|
|
43243
|
-
var startTaskSchema =
|
|
43244
|
-
taskId:
|
|
43245
|
-
agentId:
|
|
41769
|
+
var startTaskSchema = z70.object({
|
|
41770
|
+
taskId: z70.string().trim().min(1).describe("ID of the persisted TaskItem to start"),
|
|
41771
|
+
agentId: z70.string().trim().min(1).describe(
|
|
43246
41772
|
`ID of the Agent that should execute the task. Use "general-purpose" to run the caller's own capabilities as an isolated worker.`
|
|
43247
41773
|
)
|
|
43248
41774
|
});
|
|
@@ -43364,7 +41890,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43364
41890
|
const workspaceId = trustedScope?.workspaceId ?? rc.workspaceId;
|
|
43365
41891
|
const projectId = trustedScope?.projectId ?? rc.projectId;
|
|
43366
41892
|
const revalidateCaller = async () => {
|
|
43367
|
-
if (!trustedProject) return void 0;
|
|
41893
|
+
if (!trustedProject || trustedRosterExempt(trustedProject)) return void 0;
|
|
43368
41894
|
try {
|
|
43369
41895
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
43370
41896
|
} catch (error) {
|
|
@@ -43372,7 +41898,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43372
41898
|
}
|
|
43373
41899
|
return void 0;
|
|
43374
41900
|
};
|
|
43375
|
-
if (trustedProject) {
|
|
41901
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
43376
41902
|
try {
|
|
43377
41903
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
43378
41904
|
} catch (error) {
|
|
@@ -43405,10 +41931,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
43405
41931
|
if (trustedProject) {
|
|
43406
41932
|
const snapshot = taskMutationSnapshot(existing);
|
|
43407
41933
|
if (!snapshot) return trustedContextError();
|
|
43408
|
-
|
|
43409
|
-
|
|
43410
|
-
|
|
43411
|
-
|
|
41934
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
41935
|
+
try {
|
|
41936
|
+
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
41937
|
+
} catch (error) {
|
|
41938
|
+
return projectPolicyError(error);
|
|
41939
|
+
}
|
|
43412
41940
|
}
|
|
43413
41941
|
deleted = await store.deleteIfSnapshot(tenantId2, id, snapshot);
|
|
43414
41942
|
} else {
|
|
@@ -43461,13 +41989,15 @@ function createTaskMiddleware(options = {}) {
|
|
|
43461
41989
|
"Target Project task owner is not active in the exact roster."
|
|
43462
41990
|
));
|
|
43463
41991
|
}
|
|
43464
|
-
|
|
43465
|
-
|
|
43466
|
-
|
|
43467
|
-
|
|
43468
|
-
|
|
43469
|
-
|
|
43470
|
-
|
|
41992
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
41993
|
+
try {
|
|
41994
|
+
await requireTrustedOwner(trustedProject, ownerId);
|
|
41995
|
+
} catch (error) {
|
|
41996
|
+
return projectPolicyError(error instanceof ProjectTaskOwnerPolicyError ? error : new ProjectTaskOwnerPolicyError(
|
|
41997
|
+
"PROJECT_TASK_OWNER_INACTIVE",
|
|
41998
|
+
"Target Project task owner is not active in the exact roster."
|
|
41999
|
+
));
|
|
42000
|
+
}
|
|
43471
42001
|
}
|
|
43472
42002
|
}
|
|
43473
42003
|
if (effectiveOwnerType === "agent" && (input.result !== void 0 || input.failureReason !== void 0)) {
|
|
@@ -43515,10 +42045,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
43515
42045
|
)) return trustedContextError("Parent or dependency task changed before creation.");
|
|
43516
42046
|
const callerError = await revalidateCaller();
|
|
43517
42047
|
if (callerError) return callerError;
|
|
43518
|
-
|
|
43519
|
-
|
|
43520
|
-
|
|
43521
|
-
|
|
42048
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
42049
|
+
try {
|
|
42050
|
+
await requireTrustedOwner(trustedProject, ownerId);
|
|
42051
|
+
} catch (error) {
|
|
42052
|
+
return projectPolicyError(error);
|
|
42053
|
+
}
|
|
43522
42054
|
}
|
|
43523
42055
|
}
|
|
43524
42056
|
return store.create({
|
|
@@ -43776,18 +42308,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
43776
42308
|
return trustedFailure;
|
|
43777
42309
|
}
|
|
43778
42310
|
}
|
|
43779
|
-
if (trustedProject && input.dependencyTaskIds !== void 0) {
|
|
43780
|
-
const interruption = input.context?.interruption;
|
|
43781
|
-
const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
43782
|
-
if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
|
|
43783
|
-
taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
|
|
43784
|
-
return JSON.stringify({
|
|
43785
|
-
success: false,
|
|
43786
|
-
code: "INVALID_EXTERNAL_DEPENDENCY",
|
|
43787
|
-
error: "dependencyTaskIds are only valid for external dependency interruptions."
|
|
43788
|
-
});
|
|
43789
|
-
}
|
|
43790
|
-
}
|
|
43791
42311
|
if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
|
|
43792
42312
|
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_VIA_DISPATCH_REQUIRED", {
|
|
43793
42313
|
inputOwnerType: input.ownerType,
|
|
@@ -43979,7 +42499,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43979
42499
|
return trustedContextError("Parent or dependency task changed before update.");
|
|
43980
42500
|
}
|
|
43981
42501
|
}
|
|
43982
|
-
if (trustedProject) {
|
|
42502
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
43983
42503
|
try {
|
|
43984
42504
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
43985
42505
|
} catch (error) {
|
|
@@ -44019,7 +42539,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
44019
42539
|
const workItemSummary = input.summary;
|
|
44020
42540
|
let activityWarnings;
|
|
44021
42541
|
try {
|
|
44022
|
-
if (trustedProject) {
|
|
42542
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
44023
42543
|
try {
|
|
44024
42544
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
44025
42545
|
} catch (error) {
|
|
@@ -44104,18 +42624,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
44104
42624
|
return trustedFailure;
|
|
44105
42625
|
}
|
|
44106
42626
|
}
|
|
44107
|
-
if (trustedProject && input.dependencyTaskIds !== void 0) {
|
|
44108
|
-
const interruption = input.context?.interruption;
|
|
44109
|
-
const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
44110
|
-
if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
|
|
44111
|
-
taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
|
|
44112
|
-
return JSON.stringify({
|
|
44113
|
-
success: false,
|
|
44114
|
-
code: "INVALID_EXTERNAL_DEPENDENCY",
|
|
44115
|
-
error: "dependencyTaskIds are only valid for external dependency interruptions."
|
|
44116
|
-
});
|
|
44117
|
-
}
|
|
44118
|
-
}
|
|
44119
42627
|
if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
|
|
44120
42628
|
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_VIA_DISPATCH_REQUIRED", {});
|
|
44121
42629
|
return JSON.stringify({
|
|
@@ -44197,11 +42705,11 @@ function createTaskMiddleware(options = {}) {
|
|
|
44197
42705
|
const interruption = input.context?.interruption;
|
|
44198
42706
|
const explicitType = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
44199
42707
|
const type = explicitType ?? "missing_input";
|
|
44200
|
-
if (type !== "missing_input" && type !== "
|
|
42708
|
+
if (type !== "missing_input" && type !== "user_decision") {
|
|
44201
42709
|
return JSON.stringify({
|
|
44202
42710
|
success: false,
|
|
44203
42711
|
code: "INVALID_INTERRUPTION_TYPE",
|
|
44204
|
-
error: "Agent interruption type must be missing_input
|
|
42712
|
+
error: "Agent interruption type must be missing_input or user_decision."
|
|
44205
42713
|
});
|
|
44206
42714
|
}
|
|
44207
42715
|
await validateExecutionResult();
|
|
@@ -44213,8 +42721,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
44213
42721
|
type,
|
|
44214
42722
|
summary: input.summary ?? "",
|
|
44215
42723
|
actor,
|
|
44216
|
-
threadId: statusThreadId
|
|
44217
|
-
dependencyTaskIds: input.dependencyTaskIds
|
|
42724
|
+
threadId: statusThreadId
|
|
44218
42725
|
});
|
|
44219
42726
|
return lifecycleMutationResponse(interrupted);
|
|
44220
42727
|
}
|
|
@@ -44617,12 +43124,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
44617
43124
|
...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
|
|
44618
43125
|
}));
|
|
44619
43126
|
};
|
|
44620
|
-
return
|
|
43127
|
+
return createMiddleware23({
|
|
44621
43128
|
name: "TaskMiddleware",
|
|
44622
43129
|
contextSchema,
|
|
44623
43130
|
// Persisted between invocations (ADRs: the run↔task binding survives turns).
|
|
44624
|
-
stateSchema:
|
|
44625
|
-
taskId:
|
|
43131
|
+
stateSchema: z70.object({
|
|
43132
|
+
taskId: z70.string().default("")
|
|
44626
43133
|
}),
|
|
44627
43134
|
// CLAIM: a run that holds a task moves it to in_progress (idempotent).
|
|
44628
43135
|
beforeAgent: async (state, runtime) => {
|
|
@@ -44732,7 +43239,7 @@ ${TASK_CONVERGENCE_GUIDANCE}
|
|
|
44732
43239
|
});
|
|
44733
43240
|
},
|
|
44734
43241
|
tools: [
|
|
44735
|
-
|
|
43242
|
+
tool64(
|
|
44736
43243
|
handleManageTask,
|
|
44737
43244
|
{
|
|
44738
43245
|
name: "manage_task",
|
|
@@ -44778,7 +43285,7 @@ to an expert \u2014 never re-dispatch the task you are processing.`,
|
|
|
44778
43285
|
schema: manageTaskSchema
|
|
44779
43286
|
}
|
|
44780
43287
|
),
|
|
44781
|
-
|
|
43288
|
+
tool64(handleStartTask, {
|
|
44782
43289
|
name: "task",
|
|
44783
43290
|
description: `Start a persisted TaskItem with any existing Agent in a fresh isolated thread. Use this to delegate work \u2014 dispatch a subtask you created to the agent that should execute it; never re-dispatch the task you are currently processing (give the expert a child task instead). Pass agentId "general-purpose" for the general-purpose worker \u2014 ${DEFAULT_GENERAL_PURPOSE_DESCRIPTION} It has access to all the caller's tools, model, and middleware, so use it for general-purpose subtasks, to isolate context and token usage, and whenever no specialized agent fits. The target does NOT need task-management tools: it runs and returns an observation plus an executionResultId, and the caller passes that executionResultId to the manage_task update or add_activity that interprets and records it. A project task instead returns a managed result (success:true, managed:true) because the project-lifecycle queue owns execution.`,
|
|
44784
43291
|
schema: startTaskSchema
|
|
@@ -44922,8 +43429,7 @@ canonical Belief State:
|
|
|
44922
43429
|
};
|
|
44923
43430
|
|
|
44924
43431
|
// src/middlewares/documentLearningMiddleware.ts
|
|
44925
|
-
import {
|
|
44926
|
-
import { createMiddleware as createMiddleware25 } from "langchain";
|
|
43432
|
+
import { createMiddleware as createMiddleware24 } from "langchain";
|
|
44927
43433
|
|
|
44928
43434
|
// src/middlewares/documentLearningSkills.ts
|
|
44929
43435
|
var LEARN_CAPABILITY_SKILL = `---
|
|
@@ -45162,20 +43668,11 @@ patterns discovered, recommendations. Include validation coverage: user-sample N
|
|
|
45162
43668
|
`;
|
|
45163
43669
|
|
|
45164
43670
|
// src/middlewares/documentLearningMiddleware.ts
|
|
45165
|
-
var createDocumentLearningMiddleware = () =>
|
|
43671
|
+
var createDocumentLearningMiddleware = () => createMiddleware24({
|
|
45166
43672
|
name: "DocumentLearningMiddleware",
|
|
45167
43673
|
contextSchema,
|
|
45168
43674
|
tools: []
|
|
45169
43675
|
});
|
|
45170
|
-
var DOCUMENT_LEARNER_SYSTEM_PROMPT = `You are a capability learning specialist.
|
|
45171
|
-
|
|
45172
|
-
CRITICAL FIRST ACTION \u2014 before any response about the task:
|
|
45173
|
-
1. Call the \`skill\` tool with skill_name: "agent-architecture" to load the
|
|
45174
|
-
authoritative Charter.
|
|
45175
|
-
2. Call the \`skill\` tool with skill_name: "document-learning-learn-capability" to
|
|
45176
|
-
load the source-to-capability workflow.
|
|
45177
|
-
Never announce that you will follow a skill. Load both in this order and follow
|
|
45178
|
-
their content. If either load fails, retry it once, then report the failure.`;
|
|
45179
43676
|
var documentLearningPlugin = {
|
|
45180
43677
|
meta: {
|
|
45181
43678
|
type: "document-learning",
|
|
@@ -45184,92 +43681,6 @@ var documentLearningPlugin = {
|
|
|
45184
43681
|
description: "\u4ECE\u6587\u6863\u4E2D\u5B66\u4E60\u77E5\u8BC6\uFF0C\u81EA\u52A8\u6784\u5EFA\u6280\u80FD\u4F53\u7CFB\u548C\u8BC4\u6D4B\u3002 Learn knowledge from documents and build structured skill systems with evaluations.",
|
|
45185
43682
|
recommends: ["skill", "eval"]
|
|
45186
43683
|
},
|
|
45187
|
-
agents: {
|
|
45188
|
-
"document-learner": {
|
|
45189
|
-
key: "document-learner",
|
|
45190
|
-
name: "Document Learning Agent",
|
|
45191
|
-
description: "Read documents and build structured skill systems with evaluations. Use this agent when you need to extract knowledge from documents and turn it into reusable, testable agent skills.",
|
|
45192
|
-
type: AgentType10.DEEP_AGENT,
|
|
45193
|
-
prompt: DOCUMENT_LEARNER_SYSTEM_PROMPT,
|
|
45194
|
-
subAgents: ["document-parser-benchmark"],
|
|
45195
|
-
tools: [
|
|
45196
|
-
"invoke_agent",
|
|
45197
|
-
"list_agents",
|
|
45198
|
-
"create_agent",
|
|
45199
|
-
"update_agent",
|
|
45200
|
-
"delete_agent",
|
|
45201
|
-
"get_agent",
|
|
45202
|
-
"list_tools",
|
|
45203
|
-
"list_middleware_types"
|
|
45204
|
-
],
|
|
45205
|
-
middleware: [
|
|
45206
|
-
{
|
|
45207
|
-
id: "skill",
|
|
45208
|
-
type: "skill",
|
|
45209
|
-
name: "Skill",
|
|
45210
|
-
description: "Skill creation and loading",
|
|
45211
|
-
enabled: true,
|
|
45212
|
-
config: { readAll: true }
|
|
45213
|
-
},
|
|
45214
|
-
{
|
|
45215
|
-
id: "document-learning",
|
|
45216
|
-
type: "document-learning",
|
|
45217
|
-
name: "Document Learning",
|
|
45218
|
-
description: "Source-to-capability learning workflow",
|
|
45219
|
-
enabled: true,
|
|
45220
|
-
config: {}
|
|
45221
|
-
},
|
|
45222
|
-
{
|
|
45223
|
-
id: "eval",
|
|
45224
|
-
type: "eval",
|
|
45225
|
-
name: "Eval",
|
|
45226
|
-
description: "Evaluation design and execution",
|
|
45227
|
-
enabled: true,
|
|
45228
|
-
config: {}
|
|
45229
|
-
},
|
|
45230
|
-
{
|
|
45231
|
-
id: "task",
|
|
45232
|
-
type: "task",
|
|
45233
|
-
name: "Task",
|
|
45234
|
-
description: "Training process tracking with approval gates",
|
|
45235
|
-
enabled: true,
|
|
45236
|
-
config: {}
|
|
45237
|
-
},
|
|
45238
|
-
{
|
|
45239
|
-
id: "widget",
|
|
45240
|
-
type: "widget",
|
|
45241
|
-
name: "Widget",
|
|
45242
|
-
description: "Visualize benchmark results and eval dashboards",
|
|
45243
|
-
enabled: true,
|
|
45244
|
-
config: {}
|
|
45245
|
-
},
|
|
45246
|
-
{
|
|
45247
|
-
id: "ask_user_to_clarify",
|
|
45248
|
-
type: "ask_user_to_clarify",
|
|
45249
|
-
name: "Ask User",
|
|
45250
|
-
description: "Wait for user input at approval gates",
|
|
45251
|
-
enabled: true,
|
|
45252
|
-
config: {}
|
|
45253
|
-
},
|
|
45254
|
-
{
|
|
45255
|
-
id: "filesystem",
|
|
45256
|
-
type: "filesystem",
|
|
45257
|
-
name: "Filesystem",
|
|
45258
|
-
description: "Read documents, write skill files",
|
|
45259
|
-
enabled: true,
|
|
45260
|
-
config: {}
|
|
45261
|
-
},
|
|
45262
|
-
{
|
|
45263
|
-
id: "document-parser",
|
|
45264
|
-
type: "document-parser",
|
|
45265
|
-
name: "Document Parser",
|
|
45266
|
-
description: "Parse documents with the chosen engine",
|
|
45267
|
-
enabled: true,
|
|
45268
|
-
config: { connectAll: true }
|
|
45269
|
-
}
|
|
45270
|
-
]
|
|
45271
|
-
}
|
|
45272
|
-
},
|
|
45273
43684
|
skills: {
|
|
45274
43685
|
"document-learning-learn-capability": {
|
|
45275
43686
|
version: "1.0.0",
|
|
@@ -45280,12 +43691,12 @@ var documentLearningPlugin = {
|
|
|
45280
43691
|
};
|
|
45281
43692
|
|
|
45282
43693
|
// src/middlewares/documentParserMiddleware.ts
|
|
45283
|
-
import { createMiddleware as
|
|
43694
|
+
import { createMiddleware as createMiddleware25 } from "langchain";
|
|
45284
43695
|
|
|
45285
43696
|
// src/tool_lattice/document_parser/index.ts
|
|
45286
43697
|
import * as path7 from "path";
|
|
45287
|
-
import
|
|
45288
|
-
import { tool as
|
|
43698
|
+
import z71 from "zod";
|
|
43699
|
+
import { tool as tool65 } from "langchain";
|
|
45289
43700
|
var PARSE_DOCUMENT_DESCRIPTION = `Parse a document file (docx, pdf) into structured Markdown using a remote document parsing service.
|
|
45290
43701
|
This tool handles the full pipeline internally: file upload \u2192 document parsing \u2192 polling until complete \u2192 download result \u2192 save to filesystem.
|
|
45291
43702
|
|
|
@@ -45408,7 +43819,7 @@ function createParseDocumentTool({
|
|
|
45408
43819
|
baseUrl = "",
|
|
45409
43820
|
apiKey = ""
|
|
45410
43821
|
}) {
|
|
45411
|
-
return
|
|
43822
|
+
return tool65(
|
|
45412
43823
|
async (input, exe_config) => {
|
|
45413
43824
|
try {
|
|
45414
43825
|
const runConfig = exe_config?.configurable?.runConfig ?? { assistant_id: "", thread_id: "" };
|
|
@@ -45479,17 +43890,17 @@ function createParseDocumentTool({
|
|
|
45479
43890
|
{
|
|
45480
43891
|
name: "parse_document",
|
|
45481
43892
|
description: PARSE_DOCUMENT_DESCRIPTION,
|
|
45482
|
-
schema:
|
|
45483
|
-
file_path:
|
|
43893
|
+
schema: z71.object({
|
|
43894
|
+
file_path: z71.string().describe(
|
|
45484
43895
|
'Absolute path to the document file. Must point to an existing .docx or .pdf file. Example: "/project/reports/contract.docx". The file must be accessible from the current workspace.'
|
|
45485
43896
|
),
|
|
45486
|
-
engine:
|
|
43897
|
+
engine: z71.string().describe(
|
|
45487
43898
|
'Parsing engine to use. Available options: "textin" (recommended, works with local files, supports docx/pdf), "datalab" (alternative engine for docx/pdf), "mineru" (requires public URL, use only if textin/datalab fail), "paddleocr_remote" (PaddleOCR, good for scanned documents), "qwen_ocr" (OCR-focused, best for image-heavy PDFs).'
|
|
45488
43899
|
),
|
|
45489
|
-
output_path:
|
|
43900
|
+
output_path: z71.string().optional().describe(
|
|
45490
43901
|
'Path to save the parsed result. If not specified, the input extension is replaced with .md. Example: "/project/report.docx" becomes "/project/report.md". Parent directories are created automatically.'
|
|
45491
43902
|
),
|
|
45492
|
-
output_format:
|
|
43903
|
+
output_format: z71.enum(["markdown", "json"]).optional().default("markdown").describe(
|
|
45493
43904
|
'Output format. "markdown": structured Markdown with tables, headers, formatting preserved (recommended). "json": raw JSON output from the parsing engine (for programmatic use).'
|
|
45494
43905
|
)
|
|
45495
43906
|
})
|
|
@@ -45498,7 +43909,7 @@ function createParseDocumentTool({
|
|
|
45498
43909
|
}
|
|
45499
43910
|
|
|
45500
43911
|
// src/middlewares/documentParserMiddleware.ts
|
|
45501
|
-
import { AgentType as
|
|
43912
|
+
import { AgentType as AgentType9 } from "@axiom-lattice/protocols";
|
|
45502
43913
|
|
|
45503
43914
|
// src/middlewares/documentBenchmarkWorkflow.ts
|
|
45504
43915
|
var DOCUMENT_PARSER_BENCHMARK_YAML = `name: document-parser-benchmark
|
|
@@ -45907,7 +44318,7 @@ def main() -> None:
|
|
|
45907
44318
|
if __name__ == "__main__":
|
|
45908
44319
|
main()
|
|
45909
44320
|
`;
|
|
45910
|
-
var
|
|
44321
|
+
var resources = {
|
|
45911
44322
|
"references/api_reference.md": { mimeType: "text/markdown", content: `# API reference
|
|
45912
44323
|
|
|
45913
44324
|
The supported command-line form is 'markitdown input -o output.md'. The Python API uses 'MarkItDown().convert(path)' upstream, but this runtime prefers the installed CLI and does not provide direct Python SDK LLM calls. Use local conversion for local files and keep output as Markdown.` },
|
|
@@ -45936,7 +44347,7 @@ Single file: 'markitdown input -o output.md'. Ordinary directory: 'scripts/batch
|
|
|
45936
44347
|
var DOCUMENT_PARSER_MARKITDOWN_SKILL = {
|
|
45937
44348
|
version: "1.1.0",
|
|
45938
44349
|
content: MARKITDOWN_SKILL_CONTENT,
|
|
45939
|
-
resources
|
|
44350
|
+
resources
|
|
45940
44351
|
};
|
|
45941
44352
|
|
|
45942
44353
|
// src/middlewares/documentParserMiddleware.ts
|
|
@@ -45945,12 +44356,29 @@ function createDocumentParserMiddleware(config) {
|
|
|
45945
44356
|
const baseUrl = config.baseUrl || "";
|
|
45946
44357
|
const apiKey = config.apiKey || "";
|
|
45947
44358
|
const connections = Array.isArray(config.connections) ? config.connections.filter((key5) => typeof key5 === "string") : [];
|
|
45948
|
-
return
|
|
44359
|
+
return createMiddleware25({
|
|
45949
44360
|
name: "DocumentParser",
|
|
45950
44361
|
contextSchema,
|
|
45951
44362
|
tools: [createParseDocumentTool({ connectAll, connections, baseUrl, apiKey })]
|
|
45952
44363
|
});
|
|
45953
44364
|
}
|
|
44365
|
+
var DOCUMENT_PARSER_SYSTEM_PROMPT = `You are the Document Parser. Turn documents (pdf, docx, images, spreadsheets, and similar) into clean Markdown.
|
|
44366
|
+
|
|
44367
|
+
CRITICAL FIRST ACTION: call the \`skill\` tool with skill_name: "document-parser-markitdown" and follow it. Never announce skill loads.
|
|
44368
|
+
|
|
44369
|
+
DEFAULT \u2014 local MarkItDown:
|
|
44370
|
+
- Single file: run \`markitdown <input> -o <output.md>\` via shell.
|
|
44371
|
+
- Batch or literature collections: use the scripts bundled in the skill.
|
|
44372
|
+
- After converting, verify the output is non-empty and its structure/tables are intact, then report the exact input -> output paths.
|
|
44373
|
+
|
|
44374
|
+
ESCALATION \u2014 remote parse_document:
|
|
44375
|
+
- Call parse_document only when local conversion fails, the format is unsupported, the output is empty or materially incomplete, the structure is badly damaged, OCR quality is inadequate, or the user explicitly asks for professional parsing.
|
|
44376
|
+
- When the user is unsatisfied with quality, use ask_user_to_clarify to ask whether to switch to a remote engine, and recommend one engine based on the observed file features and the user's feedback. If the user names an engine, use it.
|
|
44377
|
+
|
|
44378
|
+
BENCHMARK:
|
|
44379
|
+
- Only when the user explicitly asks to compare engines. Confirm with ask_user_to_clarify first, then delegate to the document-parser-benchmark subagent. Never benchmark by default.
|
|
44380
|
+
|
|
44381
|
+
Report only what you actually produced; never claim success without inspecting the output file.`;
|
|
45954
44382
|
var documentParserPlugin = {
|
|
45955
44383
|
meta: {
|
|
45956
44384
|
type: "document-parser",
|
|
@@ -46021,9 +44449,59 @@ var documentParserPlugin = {
|
|
|
46021
44449
|
},
|
|
46022
44450
|
middleware: (config) => createDocumentParserMiddleware(config),
|
|
46023
44451
|
agents: {
|
|
44452
|
+
"document-parser": {
|
|
44453
|
+
key: "document-parser",
|
|
44454
|
+
type: AgentType9.DEEP_AGENT,
|
|
44455
|
+
name: "Document Parser",
|
|
44456
|
+
description: "Parse documents (pdf, docx, images, spreadsheets) into clean Markdown. Defaults to local MarkItDown; escalates to remote engines only when quality or format needs it; runs engine benchmarking only on explicit request.",
|
|
44457
|
+
prompt: DOCUMENT_PARSER_SYSTEM_PROMPT,
|
|
44458
|
+
subAgents: ["document-parser-benchmark"],
|
|
44459
|
+
middleware: [
|
|
44460
|
+
{
|
|
44461
|
+
id: "skill",
|
|
44462
|
+
type: "skill",
|
|
44463
|
+
name: "Skill",
|
|
44464
|
+
description: "Load the local MarkItDown parsing procedure",
|
|
44465
|
+
enabled: true,
|
|
44466
|
+
config: { readAll: true }
|
|
44467
|
+
},
|
|
44468
|
+
{
|
|
44469
|
+
id: "filesystem",
|
|
44470
|
+
type: "filesystem",
|
|
44471
|
+
name: "Filesystem",
|
|
44472
|
+
description: "Read source documents and write Markdown output",
|
|
44473
|
+
enabled: true,
|
|
44474
|
+
config: { vmIsolation: "project" }
|
|
44475
|
+
},
|
|
44476
|
+
{
|
|
44477
|
+
id: "code_eval",
|
|
44478
|
+
type: "code_eval",
|
|
44479
|
+
name: "Code Runner",
|
|
44480
|
+
description: "Run the markitdown CLI and bundled conversion scripts",
|
|
44481
|
+
enabled: true,
|
|
44482
|
+
config: { vmIsolation: "project" }
|
|
44483
|
+
},
|
|
44484
|
+
{
|
|
44485
|
+
id: "document-parser",
|
|
44486
|
+
type: "document-parser",
|
|
44487
|
+
name: "Document Parser",
|
|
44488
|
+
description: "Remote parse_document fallback for hard documents",
|
|
44489
|
+
enabled: true,
|
|
44490
|
+
config: { connectAll: true }
|
|
44491
|
+
},
|
|
44492
|
+
{
|
|
44493
|
+
id: "ask_user_to_clarify",
|
|
44494
|
+
type: "ask_user_to_clarify",
|
|
44495
|
+
name: "Ask User",
|
|
44496
|
+
description: "Confirm engine switches and benchmark runs",
|
|
44497
|
+
enabled: true,
|
|
44498
|
+
config: {}
|
|
44499
|
+
}
|
|
44500
|
+
]
|
|
44501
|
+
},
|
|
46024
44502
|
"document-parser-benchmark": {
|
|
46025
44503
|
key: "document-parser-benchmark",
|
|
46026
|
-
type:
|
|
44504
|
+
type: AgentType9.WORKFLOW,
|
|
46027
44505
|
name: "Document Parser Benchmark",
|
|
46028
44506
|
description: "Benchmark document parsing engines. Parses a document with 5 engines in parallel, scores results, and produces a ranking report. Use this when you need to evaluate which parsing engine works best for a given document.",
|
|
46029
44507
|
prompt: "Benchmark document parsing engines: parse with 5 engines, score, and rank results.",
|
|
@@ -46063,11 +44541,11 @@ import { createHash as createHash7 } from "crypto";
|
|
|
46063
44541
|
import {
|
|
46064
44542
|
descriptorDataValue as descriptorDataValue2,
|
|
46065
44543
|
parseTrustedRunContext as parseTrustedRunContext3,
|
|
46066
|
-
snapshotExactArray as
|
|
46067
|
-
snapshotExactRecord as
|
|
44544
|
+
snapshotExactArray as snapshotExactArray2,
|
|
44545
|
+
snapshotExactRecord as snapshotExactRecord7
|
|
46068
44546
|
} from "@axiom-lattice/protocols";
|
|
46069
|
-
import { createMiddleware as
|
|
46070
|
-
import { z as
|
|
44547
|
+
import { createMiddleware as createMiddleware26, tool as tool66 } from "langchain";
|
|
44548
|
+
import { z as z72 } from "zod";
|
|
46071
44549
|
var PROJECT_ROOM_CONTEXT_REQUIRED = "PROJECT_ROOM_CONTEXT_REQUIRED";
|
|
46072
44550
|
var PROJECT_ROOM_POST_FAILED = "PROJECT_ROOM_POST_FAILED";
|
|
46073
44551
|
var PROJECT_ROOM_ROSTER_FAILED = "PROJECT_ROOM_ROSTER_FAILED";
|
|
@@ -46087,10 +44565,10 @@ var ROSTER_FAILED = JSON.stringify({
|
|
|
46087
44565
|
error: PROJECT_ROOM_ROSTER_FAILED,
|
|
46088
44566
|
message: PROJECT_ROOM_ROSTER_FAILED_MESSAGE
|
|
46089
44567
|
});
|
|
46090
|
-
var postSchema =
|
|
46091
|
-
text:
|
|
44568
|
+
var postSchema = z72.object({
|
|
44569
|
+
text: z72.string().trim().min(1).max(2e4)
|
|
46092
44570
|
}).strict();
|
|
46093
|
-
var listSchema =
|
|
44571
|
+
var listSchema = z72.object({}).strict();
|
|
46094
44572
|
function ownDataValue2(record, key5) {
|
|
46095
44573
|
if (typeof record !== "object" || record === null || Array.isArray(record)) return void 0;
|
|
46096
44574
|
try {
|
|
@@ -46112,7 +44590,7 @@ function readTrustedRoomScope(config) {
|
|
|
46112
44590
|
}
|
|
46113
44591
|
function exactValues2(value, required, optional = []) {
|
|
46114
44592
|
try {
|
|
46115
|
-
return
|
|
44593
|
+
return snapshotExactRecord7(value, required, optional);
|
|
46116
44594
|
} catch {
|
|
46117
44595
|
return void 0;
|
|
46118
44596
|
}
|
|
@@ -46148,7 +44626,7 @@ function snapshotMembership3(value) {
|
|
|
46148
44626
|
return { ...values, joinedAt, updatedAt };
|
|
46149
44627
|
}
|
|
46150
44628
|
function snapshotRows(value) {
|
|
46151
|
-
return
|
|
44629
|
+
return snapshotExactArray2(value) ?? [];
|
|
46152
44630
|
}
|
|
46153
44631
|
async function hasActiveCurrentMembership(scope) {
|
|
46154
44632
|
const memberships = getStoreLattice("default", "projectBotMembership").store;
|
|
@@ -46157,10 +44635,10 @@ async function hasActiveCurrentMembership(scope) {
|
|
|
46157
44635
|
return true;
|
|
46158
44636
|
}
|
|
46159
44637
|
function createProjectRoomMiddleware() {
|
|
46160
|
-
return
|
|
44638
|
+
return createMiddleware26({
|
|
46161
44639
|
name: "ProjectRoomMiddleware",
|
|
46162
44640
|
tools: [
|
|
46163
|
-
|
|
44641
|
+
tool66(async (input, config) => {
|
|
46164
44642
|
const { text } = input;
|
|
46165
44643
|
const scope = readTrustedRoomScope(config);
|
|
46166
44644
|
if (!scope) return CONTEXT_REQUIRED;
|
|
@@ -46191,7 +44669,7 @@ function createProjectRoomMiddleware() {
|
|
|
46191
44669
|
description: "Post a text reply to the current trusted Project Room message",
|
|
46192
44670
|
schema: postSchema
|
|
46193
44671
|
}),
|
|
46194
|
-
|
|
44672
|
+
tool66(async (_input, config) => {
|
|
46195
44673
|
const scope = readTrustedRoomScope(config);
|
|
46196
44674
|
if (!scope) return CONTEXT_REQUIRED;
|
|
46197
44675
|
try {
|
|
@@ -46233,9 +44711,9 @@ var projectRoomPlugin = {
|
|
|
46233
44711
|
};
|
|
46234
44712
|
|
|
46235
44713
|
// src/middlewares/sandboxPluginsMiddleware.ts
|
|
46236
|
-
import { createMiddleware as
|
|
46237
|
-
import { z as
|
|
46238
|
-
import { AgentType as
|
|
44714
|
+
import { createMiddleware as createMiddleware27, tool as tool67 } from "langchain";
|
|
44715
|
+
import { z as z73 } from "zod";
|
|
44716
|
+
import { AgentType as AgentType10 } from "@axiom-lattice/protocols";
|
|
46239
44717
|
|
|
46240
44718
|
// src/middlewares/sandboxPluginsSkills.ts
|
|
46241
44719
|
var PLUGIN_JSON_TEMPLATE = `{
|
|
@@ -46956,16 +45434,16 @@ function tenantIdFrom(exeConfig) {
|
|
|
46956
45434
|
const c = exeConfig;
|
|
46957
45435
|
return c?.configurable?.runConfig?.tenantId ?? "default";
|
|
46958
45436
|
}
|
|
46959
|
-
var managePluginSchema =
|
|
46960
|
-
action:
|
|
46961
|
-
type:
|
|
46962
|
-
manifest:
|
|
46963
|
-
handlers:
|
|
46964
|
-
target:
|
|
46965
|
-
kind:
|
|
46966
|
-
name:
|
|
46967
|
-
input:
|
|
46968
|
-
connectionKey:
|
|
45437
|
+
var managePluginSchema = z73.object({
|
|
45438
|
+
action: z73.enum(["list", "get", "validate", "create", "update", "delete", "reload", "test"]),
|
|
45439
|
+
type: z73.string().optional(),
|
|
45440
|
+
manifest: z73.record(z73.unknown()).optional(),
|
|
45441
|
+
handlers: z73.record(z73.string()).optional(),
|
|
45442
|
+
target: z73.object({
|
|
45443
|
+
kind: z73.enum(["tool", "connection-test", "connection-discover"]),
|
|
45444
|
+
name: z73.string().optional(),
|
|
45445
|
+
input: z73.unknown().optional(),
|
|
45446
|
+
connectionKey: z73.string().optional()
|
|
46969
45447
|
}).optional()
|
|
46970
45448
|
});
|
|
46971
45449
|
var sandboxPluginsPlugin = {
|
|
@@ -46985,7 +45463,7 @@ var sandboxPluginsPlugin = {
|
|
|
46985
45463
|
key: "plugin-builder",
|
|
46986
45464
|
name: "Plugin Builder",
|
|
46987
45465
|
description: "Author and manage tenant plugins in the shared sandbox: clarify goal, inputs/outputs, credentials, and whether a UI is needed; then write the manifest and JS handlers, add an optional HTML MCP App UI, and validate/test with the manage_plugin tool.",
|
|
46988
|
-
type:
|
|
45466
|
+
type: AgentType10.DEEP_AGENT,
|
|
46989
45467
|
prompt: PLUGIN_BUILDER_PROMPT,
|
|
46990
45468
|
middleware: [
|
|
46991
45469
|
{
|
|
@@ -47039,10 +45517,10 @@ var sandboxPluginsPlugin = {
|
|
|
47039
45517
|
]
|
|
47040
45518
|
}
|
|
47041
45519
|
},
|
|
47042
|
-
middleware: () =>
|
|
45520
|
+
middleware: () => createMiddleware27({
|
|
47043
45521
|
name: "SandboxPluginsMiddleware",
|
|
47044
45522
|
tools: [
|
|
47045
|
-
|
|
45523
|
+
tool67(
|
|
47046
45524
|
async (input, exeConfig) => {
|
|
47047
45525
|
const tenantId2 = tenantIdFrom(exeConfig);
|
|
47048
45526
|
const catalog2 = getSandboxPluginCatalog();
|
|
@@ -47183,7 +45661,6 @@ var BUILTIN_PLUGINS = [
|
|
|
47183
45661
|
sqlPlugin,
|
|
47184
45662
|
skillPlugin,
|
|
47185
45663
|
metricsPlugin,
|
|
47186
|
-
semanticMetricsPlugin,
|
|
47187
45664
|
askUserClarifyPlugin,
|
|
47188
45665
|
widgetPlugin,
|
|
47189
45666
|
clawPlugin,
|
|
@@ -47815,7 +46292,6 @@ export {
|
|
|
47815
46292
|
createSandboxProvider,
|
|
47816
46293
|
createSandboxResolver,
|
|
47817
46294
|
createSchedulerMiddleware,
|
|
47818
|
-
createSemanticMetricsMiddleware,
|
|
47819
46295
|
createSharePayload,
|
|
47820
46296
|
createTaskExecutionService,
|
|
47821
46297
|
createTaskLifecycleService,
|
|
@@ -47899,6 +46375,7 @@ export {
|
|
|
47899
46375
|
invokeWithRetry,
|
|
47900
46376
|
isBuiltInSkill,
|
|
47901
46377
|
isDirectRoom,
|
|
46378
|
+
isMcpConnectionError,
|
|
47902
46379
|
isPluginSkillAuthorizedInSandbox,
|
|
47903
46380
|
isPluginSkillManagedInSandbox,
|
|
47904
46381
|
isUsingDefaultKey,
|
|
@@ -47921,7 +46398,6 @@ export {
|
|
|
47921
46398
|
parallelLimit,
|
|
47922
46399
|
parseCronExpression,
|
|
47923
46400
|
parseDirectRoomType,
|
|
47924
|
-
parseExternalDependency,
|
|
47925
46401
|
parseJudgeVerdict,
|
|
47926
46402
|
parsePackSize,
|
|
47927
46403
|
parseQueuedExecutionMode,
|
|
@@ -47974,7 +46450,6 @@ export {
|
|
|
47974
46450
|
sandboxLatticeManager,
|
|
47975
46451
|
sanitizeToolCallId,
|
|
47976
46452
|
scheduleLatticeManager,
|
|
47977
|
-
semanticMetricsPlugin,
|
|
47978
46453
|
serializePluginMeta,
|
|
47979
46454
|
serializeTaskMutationSuccess,
|
|
47980
46455
|
serializeTaskNormalizationFallback,
|