@axiom-lattice/core 4.3.0 → 5.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 +172 -69
- package/dist/index.d.ts +172 -69
- package/dist/index.js +1096 -2012
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1043 -1961
- 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 [];
|
|
@@ -11238,7 +11238,7 @@ function readLoopBreakerConfig(env = process.env) {
|
|
|
11238
11238
|
return {
|
|
11239
11239
|
repeatWarn: parse(env.AGENT_REPEATED_TOOL_CALL_WARN, 3),
|
|
11240
11240
|
repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP, 5),
|
|
11241
|
-
runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT,
|
|
11241
|
+
runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT, 300),
|
|
11242
11242
|
skillRunLimit: parse(env.AGENT_SKILL_CALL_RUN_LIMIT, 8)
|
|
11243
11243
|
};
|
|
11244
11244
|
}
|
|
@@ -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);
|
|
@@ -14938,6 +14938,41 @@ var AgentManager = class _AgentManager {
|
|
|
14938
14938
|
}
|
|
14939
14939
|
};
|
|
14940
14940
|
|
|
14941
|
+
// src/services/TaskExecutionContext.ts
|
|
14942
|
+
var DELEGATED_WORKER_SCOPE_TOKEN = Symbol("delegated-worker-scope");
|
|
14943
|
+
var delegatedWorkerScopeSecret = Object.freeze({});
|
|
14944
|
+
function createDelegatedWorkerRunConfig(taskId) {
|
|
14945
|
+
return {
|
|
14946
|
+
taskId,
|
|
14947
|
+
delegatedTaskId: taskId,
|
|
14948
|
+
taskExecutionRole: "worker",
|
|
14949
|
+
execution: { taskId },
|
|
14950
|
+
[DELEGATED_WORKER_SCOPE_TOKEN]: delegatedWorkerScopeSecret
|
|
14951
|
+
};
|
|
14952
|
+
}
|
|
14953
|
+
function getDelegatedTaskId(runConfig) {
|
|
14954
|
+
return runConfig[DELEGATED_WORKER_SCOPE_TOKEN] === delegatedWorkerScopeSecret && runConfig.taskExecutionRole === "worker" && typeof runConfig.taskId === "string" && runConfig.taskId.trim() !== "" && typeof runConfig.delegatedTaskId === "string" && runConfig.taskId === runConfig.delegatedTaskId ? runConfig.taskId : void 0;
|
|
14955
|
+
}
|
|
14956
|
+
function hasDelegatedWorkerToken(runConfig) {
|
|
14957
|
+
return Object.prototype.hasOwnProperty.call(runConfig, DELEGATED_WORKER_SCOPE_TOKEN);
|
|
14958
|
+
}
|
|
14959
|
+
function preserveDelegatedWorkerContext(source, target) {
|
|
14960
|
+
const delegatedTaskId = getDelegatedTaskId(source);
|
|
14961
|
+
if (!delegatedTaskId) return;
|
|
14962
|
+
target.taskId = delegatedTaskId;
|
|
14963
|
+
target.delegatedTaskId = delegatedTaskId;
|
|
14964
|
+
target.taskExecutionRole = "worker";
|
|
14965
|
+
target.execution = { taskId: delegatedTaskId };
|
|
14966
|
+
target[DELEGATED_WORKER_SCOPE_TOKEN] = delegatedWorkerScopeSecret;
|
|
14967
|
+
}
|
|
14968
|
+
function stripDelegatedWorkerContext(target) {
|
|
14969
|
+
delete target.taskId;
|
|
14970
|
+
delete target.delegatedTaskId;
|
|
14971
|
+
delete target.taskExecutionRole;
|
|
14972
|
+
delete target.execution;
|
|
14973
|
+
delete target[DELEGATED_WORKER_SCOPE_TOKEN];
|
|
14974
|
+
}
|
|
14975
|
+
|
|
14941
14976
|
// src/agent_worker/agent_worker_graph.ts
|
|
14942
14977
|
var AgentWorkerState = Annotation.Root({
|
|
14943
14978
|
// Input parameters
|
|
@@ -14962,6 +14997,13 @@ var AgentWorkerState = Annotation.Root({
|
|
|
14962
14997
|
reducer: (x, y) => y ?? x,
|
|
14963
14998
|
default: () => void 0
|
|
14964
14999
|
}),
|
|
15000
|
+
// Optional persistent TaskItem binding. Rebuilt into an authentic delegated
|
|
15001
|
+
// worker scope on every execute (the in-process scope symbol cannot survive
|
|
15002
|
+
// LangGraph checkpointing, so it is re-derived from this plain task id).
|
|
15003
|
+
taskId: Annotation({
|
|
15004
|
+
reducer: (x, y) => y ?? x,
|
|
15005
|
+
default: () => ""
|
|
15006
|
+
}),
|
|
14965
15007
|
// Execution result
|
|
14966
15008
|
result: Annotation({
|
|
14967
15009
|
reducer: (x, y) => y ?? x,
|
|
@@ -14979,14 +15021,15 @@ var AgentWorkerState = Annotation.Root({
|
|
|
14979
15021
|
})
|
|
14980
15022
|
});
|
|
14981
15023
|
async function executeNode(state) {
|
|
14982
|
-
const { assistant_id, thread_id, input, command2, runConfig } = state;
|
|
15024
|
+
const { assistant_id, thread_id, input, command2, runConfig, taskId } = state;
|
|
15025
|
+
const effectiveRunConfig = taskId ? { ...runConfig ?? {}, ...createDelegatedWorkerRunConfig(taskId) } : runConfig;
|
|
14983
15026
|
const callParams = {
|
|
14984
15027
|
assistant_id,
|
|
14985
15028
|
"x-tenant-id": runConfig?.tenantId,
|
|
14986
15029
|
thread_id,
|
|
14987
15030
|
input,
|
|
14988
15031
|
command: command2,
|
|
14989
|
-
runConfig
|
|
15032
|
+
runConfig: effectiveRunConfig
|
|
14990
15033
|
};
|
|
14991
15034
|
const result = await AgentManager.getInstance().callAgentInQueue(
|
|
14992
15035
|
callParams,
|
|
@@ -15736,8 +15779,8 @@ function validateCapability(value, index) {
|
|
|
15736
15779
|
fieldPath: `/capabilities/${index}/allowedTools`
|
|
15737
15780
|
});
|
|
15738
15781
|
}
|
|
15739
|
-
for (const [toolIndex,
|
|
15740
|
-
if (typeof
|
|
15782
|
+
for (const [toolIndex, tool68] of capability.allowedTools.entries()) {
|
|
15783
|
+
if (typeof tool68 !== "string") {
|
|
15741
15784
|
throw new CapabilityBundleValidationError(
|
|
15742
15785
|
"CAPABILITY_BUNDLE_INVALID_CAPABILITY",
|
|
15743
15786
|
"allowedTools entries must be strings",
|
|
@@ -15751,10 +15794,10 @@ function validateCapability(value, index) {
|
|
|
15751
15794
|
fieldPath: `/capabilities/${index}/allowedTools`
|
|
15752
15795
|
});
|
|
15753
15796
|
}
|
|
15754
|
-
const toolNames = new Set(plugin.meta.tools.map((
|
|
15755
|
-
for (const [toolIndex,
|
|
15756
|
-
if (typeof
|
|
15757
|
-
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)}'`, {
|
|
15758
15801
|
capabilityType,
|
|
15759
15802
|
fieldPath: `/capabilities/${index}/allowedTools/${toolIndex}`
|
|
15760
15803
|
});
|
|
@@ -16237,7 +16280,7 @@ function applyStaticCeiling(capabilities, staticMiddleware) {
|
|
|
16237
16280
|
const projectTools = capability.allowedTools;
|
|
16238
16281
|
const staticTools = ceiling.allowedTools;
|
|
16239
16282
|
const effectiveStaticTools = staticTools?.length === 0 ? void 0 : staticTools;
|
|
16240
|
-
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));
|
|
16241
16284
|
runtime[capability.type] = structuredClone({
|
|
16242
16285
|
...capability,
|
|
16243
16286
|
config: applyStaticResourceCeiling(capability, ceiling),
|
|
@@ -16337,38 +16380,6 @@ var CapabilityRuntimeResolver = class {
|
|
|
16337
16380
|
}
|
|
16338
16381
|
};
|
|
16339
16382
|
|
|
16340
|
-
// src/services/TaskExecutionContext.ts
|
|
16341
|
-
var DELEGATED_WORKER_SCOPE_TOKEN = Symbol("delegated-worker-scope");
|
|
16342
|
-
var delegatedWorkerScopeSecret = Object.freeze({});
|
|
16343
|
-
function createDelegatedWorkerRunConfig(taskId) {
|
|
16344
|
-
return {
|
|
16345
|
-
taskId,
|
|
16346
|
-
delegatedTaskId: taskId,
|
|
16347
|
-
taskExecutionRole: "worker",
|
|
16348
|
-
[DELEGATED_WORKER_SCOPE_TOKEN]: delegatedWorkerScopeSecret
|
|
16349
|
-
};
|
|
16350
|
-
}
|
|
16351
|
-
function getDelegatedTaskId(runConfig) {
|
|
16352
|
-
return runConfig[DELEGATED_WORKER_SCOPE_TOKEN] === delegatedWorkerScopeSecret && runConfig.taskExecutionRole === "worker" && typeof runConfig.taskId === "string" && runConfig.taskId.trim() !== "" && typeof runConfig.delegatedTaskId === "string" && runConfig.taskId === runConfig.delegatedTaskId ? runConfig.taskId : void 0;
|
|
16353
|
-
}
|
|
16354
|
-
function hasDelegatedWorkerToken(runConfig) {
|
|
16355
|
-
return Object.prototype.hasOwnProperty.call(runConfig, DELEGATED_WORKER_SCOPE_TOKEN);
|
|
16356
|
-
}
|
|
16357
|
-
function preserveDelegatedWorkerContext(source, target) {
|
|
16358
|
-
const delegatedTaskId = getDelegatedTaskId(source);
|
|
16359
|
-
if (!delegatedTaskId) return;
|
|
16360
|
-
target.taskId = delegatedTaskId;
|
|
16361
|
-
target.delegatedTaskId = delegatedTaskId;
|
|
16362
|
-
target.taskExecutionRole = "worker";
|
|
16363
|
-
target[DELEGATED_WORKER_SCOPE_TOKEN] = delegatedWorkerScopeSecret;
|
|
16364
|
-
}
|
|
16365
|
-
function stripDelegatedWorkerContext(target) {
|
|
16366
|
-
delete target.taskId;
|
|
16367
|
-
delete target.delegatedTaskId;
|
|
16368
|
-
delete target.taskExecutionRole;
|
|
16369
|
-
delete target[DELEGATED_WORKER_SCOPE_TOKEN];
|
|
16370
|
-
}
|
|
16371
|
-
|
|
16372
16383
|
// src/services/TrustedAgentDispatchCapability.ts
|
|
16373
16384
|
var TRUSTED_AGENT_DISPATCH = Symbol("axiom.trustedAgentDispatch");
|
|
16374
16385
|
|
|
@@ -16532,8 +16543,22 @@ function sanitizeCallerRunConfig(value, preserveDelegatedContext = true) {
|
|
|
16532
16543
|
} else {
|
|
16533
16544
|
stripDelegatedWorkerContext(callerRunConfig);
|
|
16534
16545
|
}
|
|
16546
|
+
preserveExecutionBinding(value, callerRunConfig);
|
|
16535
16547
|
return callerRunConfig;
|
|
16536
16548
|
}
|
|
16549
|
+
function preserveExecutionBinding(source, target) {
|
|
16550
|
+
if (typeof source !== "object" || source === null || Array.isArray(source)) return;
|
|
16551
|
+
const execution = descriptorDataValue(Object.getOwnPropertyDescriptor(source, "execution"))?.value;
|
|
16552
|
+
if (typeof execution !== "object" || execution === null || Array.isArray(execution)) return;
|
|
16553
|
+
const taskId = descriptorDataValue(Object.getOwnPropertyDescriptor(execution, "taskId"))?.value;
|
|
16554
|
+
if (typeof taskId !== "string" || taskId.trim() === "") return;
|
|
16555
|
+
Object.defineProperty(target, "execution", {
|
|
16556
|
+
value: { taskId },
|
|
16557
|
+
enumerable: true,
|
|
16558
|
+
configurable: true,
|
|
16559
|
+
writable: true
|
|
16560
|
+
});
|
|
16561
|
+
}
|
|
16537
16562
|
function sanitizeExecutionRunConfig(value) {
|
|
16538
16563
|
return cloneRunConfig(value, false);
|
|
16539
16564
|
}
|
|
@@ -16653,6 +16678,7 @@ function checkpointCapabilityRevision(state) {
|
|
|
16653
16678
|
}
|
|
16654
16679
|
var QUEUE_PROCESSOR_RETRY_BASE_MS = 100;
|
|
16655
16680
|
var QUEUE_PROCESSOR_MAX_RETRIES = 3;
|
|
16681
|
+
var AGENT_RECURSION_LIMIT = 1e3;
|
|
16656
16682
|
function hasExactKeys(record, required, optional = []) {
|
|
16657
16683
|
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
16658
16684
|
return required.every((key5) => Object.prototype.hasOwnProperty.call(record, key5)) && Reflect.ownKeys(record).every((key5) => typeof key5 === "string" && allowed.has(key5));
|
|
@@ -16705,7 +16731,7 @@ var Agent = class {
|
|
|
16705
16731
|
...executionRunConfig,
|
|
16706
16732
|
runConfig: executionRunConfig
|
|
16707
16733
|
},
|
|
16708
|
-
recursionLimit:
|
|
16734
|
+
recursionLimit: AGENT_RECURSION_LIMIT,
|
|
16709
16735
|
signal
|
|
16710
16736
|
}
|
|
16711
16737
|
);
|
|
@@ -16780,7 +16806,7 @@ var Agent = class {
|
|
|
16780
16806
|
},
|
|
16781
16807
|
streamMode: ["updates", "messages"],
|
|
16782
16808
|
subgraphs: false,
|
|
16783
|
-
recursionLimit:
|
|
16809
|
+
recursionLimit: AGENT_RECURSION_LIMIT,
|
|
16784
16810
|
signal
|
|
16785
16811
|
}
|
|
16786
16812
|
);
|
|
@@ -17278,6 +17304,15 @@ var Agent = class {
|
|
|
17278
17304
|
configurable: true,
|
|
17279
17305
|
writable: true
|
|
17280
17306
|
});
|
|
17307
|
+
const trustedTaskId = parsed.projectTask?.taskId;
|
|
17308
|
+
if (trustedTaskId) {
|
|
17309
|
+
Object.defineProperty(base, "execution", {
|
|
17310
|
+
value: { taskId: trustedTaskId },
|
|
17311
|
+
enumerable: true,
|
|
17312
|
+
configurable: true,
|
|
17313
|
+
writable: true
|
|
17314
|
+
});
|
|
17315
|
+
}
|
|
17281
17316
|
return base;
|
|
17282
17317
|
}
|
|
17283
17318
|
getHumanPendingContent(message) {
|
|
@@ -17481,7 +17516,7 @@ var Agent = class {
|
|
|
17481
17516
|
...executionRunConfig,
|
|
17482
17517
|
runConfig: executionRunConfig
|
|
17483
17518
|
},
|
|
17484
|
-
recursionLimit:
|
|
17519
|
+
recursionLimit: AGENT_RECURSION_LIMIT,
|
|
17485
17520
|
signal
|
|
17486
17521
|
}
|
|
17487
17522
|
);
|
|
@@ -17592,7 +17627,7 @@ var Agent = class {
|
|
|
17592
17627
|
},
|
|
17593
17628
|
streamMode: ["updates", "messages"],
|
|
17594
17629
|
subgraphs: false,
|
|
17595
|
-
recursionLimit:
|
|
17630
|
+
recursionLimit: AGENT_RECURSION_LIMIT,
|
|
17596
17631
|
signal
|
|
17597
17632
|
}
|
|
17598
17633
|
);
|
|
@@ -18349,6 +18384,20 @@ var agentInstanceManager = AgentInstanceManager.getInstance();
|
|
|
18349
18384
|
var DEFAULT_SUBAGENT_PROMPT = "In order to complete the objective that the user asks of you, you have access to a number of standard tools.";
|
|
18350
18385
|
var EXCLUDED_STATE_KEYS = ["messages", "todos", "jumpTo"];
|
|
18351
18386
|
var DEFAULT_GENERAL_PURPOSE_DESCRIPTION = "General-purpose agent for researching complex questions, searching for files and content, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you. This agent has access to all tools as the main agent.";
|
|
18387
|
+
function createGeneralPurposeAgent(options) {
|
|
18388
|
+
const middleware = [...options.middleware];
|
|
18389
|
+
if (options.interruptOn) {
|
|
18390
|
+
middleware.push(humanInTheLoopMiddleware({ interruptOn: options.interruptOn }));
|
|
18391
|
+
}
|
|
18392
|
+
return createAgent2({
|
|
18393
|
+
model: options.model,
|
|
18394
|
+
systemPrompt: DEFAULT_SUBAGENT_PROMPT,
|
|
18395
|
+
tools: options.tools,
|
|
18396
|
+
middleware,
|
|
18397
|
+
checkpointer: getCheckpointSaver("default"),
|
|
18398
|
+
name: "general-purpose"
|
|
18399
|
+
});
|
|
18400
|
+
}
|
|
18352
18401
|
function getTaskToolDescription(subagentDescriptions) {
|
|
18353
18402
|
return subagentDescriptions.length > 0 ? `
|
|
18354
18403
|
Launch an ephemeral subagent to handle complex, multi-step independent tasks with isolated context windows.
|
|
@@ -18528,21 +18577,12 @@ function getSubagents(options) {
|
|
|
18528
18577
|
const agents = {};
|
|
18529
18578
|
const subagentDescriptions = [];
|
|
18530
18579
|
if (generalPurposeAgent) {
|
|
18531
|
-
|
|
18532
|
-
if (defaultInterruptOn) {
|
|
18533
|
-
generalPurposeMiddleware.push(
|
|
18534
|
-
humanInTheLoopMiddleware({ interruptOn: defaultInterruptOn })
|
|
18535
|
-
);
|
|
18536
|
-
}
|
|
18537
|
-
const generalPurposeSubagent = createAgent2({
|
|
18580
|
+
agents["general-purpose"] = createGeneralPurposeAgent({
|
|
18538
18581
|
model: defaultModel,
|
|
18539
|
-
systemPrompt: DEFAULT_SUBAGENT_PROMPT,
|
|
18540
18582
|
tools: defaultTools,
|
|
18541
|
-
middleware:
|
|
18542
|
-
|
|
18543
|
-
name: "general-purpose"
|
|
18583
|
+
middleware: defaultSubagentMiddleware,
|
|
18584
|
+
interruptOn: defaultInterruptOn
|
|
18544
18585
|
});
|
|
18545
|
-
agents["general-purpose"] = generalPurposeSubagent;
|
|
18546
18586
|
subagentDescriptions.push(
|
|
18547
18587
|
`- general-purpose: ${DEFAULT_GENERAL_PURPOSE_DESCRIPTION}`
|
|
18548
18588
|
);
|
|
@@ -21987,6 +22027,7 @@ ${BASE_PROMPT}` : BASE_PROMPT;
|
|
|
21987
22027
|
}
|
|
21988
22028
|
|
|
21989
22029
|
// src/agent_lattice/builders/DeepAgentGraphBuilder.ts
|
|
22030
|
+
import { AgentType as AgentType2 } from "@axiom-lattice/protocols";
|
|
21990
22031
|
var DeepAgentGraphBuilder = class {
|
|
21991
22032
|
/**
|
|
21992
22033
|
* 构建Deep Agent Graph
|
|
@@ -21999,7 +22040,7 @@ var DeepAgentGraphBuilder = class {
|
|
|
21999
22040
|
const tools = params.tools.map((t) => {
|
|
22000
22041
|
const toolClient = getToolClientWithTenant(params.tenantId ?? "default", t.key);
|
|
22001
22042
|
return toolClient;
|
|
22002
|
-
}).filter((
|
|
22043
|
+
}).filter((tool68) => tool68 !== void 0);
|
|
22003
22044
|
const subagents = await Promise.all(params.subAgents.map(async (sa) => {
|
|
22004
22045
|
if (sa.client) {
|
|
22005
22046
|
return {
|
|
@@ -22035,6 +22076,28 @@ var DeepAgentGraphBuilder = class {
|
|
|
22035
22076
|
backend: filesystemBackend,
|
|
22036
22077
|
middleware: middlewares
|
|
22037
22078
|
});
|
|
22079
|
+
if (middlewares.some((candidate) => candidate.name === "TaskMiddleware") && agentLattice.config.key) {
|
|
22080
|
+
const tenantId2 = params.tenantId ?? "default";
|
|
22081
|
+
const generalPurposeKey = `${agentLattice.config.key}-general-purpose`;
|
|
22082
|
+
if (!agentLatticeManager.hasAgentLatticeWithTenant(tenantId2, generalPurposeKey)) {
|
|
22083
|
+
const generalPurposeAgent = createGeneralPurposeAgent({
|
|
22084
|
+
model: params.model,
|
|
22085
|
+
tools,
|
|
22086
|
+
middleware: middlewares
|
|
22087
|
+
});
|
|
22088
|
+
agentLatticeManager.registerWithTenant(tenantId2, generalPurposeKey, {
|
|
22089
|
+
config: {
|
|
22090
|
+
key: generalPurposeKey,
|
|
22091
|
+
name: "general-purpose",
|
|
22092
|
+
description: DEFAULT_GENERAL_PURPOSE_DESCRIPTION,
|
|
22093
|
+
type: AgentType2.REACT,
|
|
22094
|
+
prompt: DEFAULT_SUBAGENT_PROMPT,
|
|
22095
|
+
tenantId: tenantId2
|
|
22096
|
+
},
|
|
22097
|
+
client: generalPurposeAgent
|
|
22098
|
+
});
|
|
22099
|
+
}
|
|
22100
|
+
}
|
|
22038
22101
|
return deepAgent;
|
|
22039
22102
|
}
|
|
22040
22103
|
};
|
|
@@ -23625,7 +23688,7 @@ var TeamAgentGraphBuilder = class {
|
|
|
23625
23688
|
const tools = params.tools.map((t) => {
|
|
23626
23689
|
const toolClient = getToolClientWithTenant(params.tenantId ?? "default", t.key);
|
|
23627
23690
|
return toolClient;
|
|
23628
|
-
}).filter((
|
|
23691
|
+
}).filter((tool68) => tool68 !== void 0);
|
|
23629
23692
|
const teammates = params.subAgents.map((sa) => {
|
|
23630
23693
|
const baseConfig = sa.config;
|
|
23631
23694
|
return {
|
|
@@ -23982,10 +24045,10 @@ _A2ARemoteClient.MAX_CACHED_TASKS = 100;
|
|
|
23982
24045
|
var A2ARemoteClient = _A2ARemoteClient;
|
|
23983
24046
|
|
|
23984
24047
|
// src/agent_lattice/builders/RemoteAgentGraphBuilder.ts
|
|
23985
|
-
import { AgentType as
|
|
24048
|
+
import { AgentType as AgentType3 } from "@axiom-lattice/protocols";
|
|
23986
24049
|
var RemoteAgentGraphBuilder = class {
|
|
23987
24050
|
async build(agentLattice, params) {
|
|
23988
|
-
if (agentLattice.config.type !==
|
|
24051
|
+
if (agentLattice.config.type !== AgentType3.A2A_REMOTE) {
|
|
23989
24052
|
throw new Error(
|
|
23990
24053
|
`RemoteAgentGraphBuilder received wrong agent type: ${agentLattice.config.type}`
|
|
23991
24054
|
);
|
|
@@ -24755,9 +24818,15 @@ For human judgment, use the actual HITL payload \`status: "interrupted"\` plus
|
|
|
24755
24818
|
handled by the configured HITL lifecycle; \`review_required\` is not a task status.
|
|
24756
24819
|
|
|
24757
24820
|
Create the active parent and each started subtask as records: \`manage_task
|
|
24758
|
-
create\` always persists \`pending\`.
|
|
24759
|
-
|
|
24760
|
-
|
|
24821
|
+
create\` always persists \`pending\`. **Process the task you were assigned in this
|
|
24822
|
+
run: set it \`in_progress\` with \`manage_task set_status\` when you start (a
|
|
24823
|
+
dispatched task is claimed automatically by the engine).** To bring
|
|
24824
|
+
in a more suitable expert, create a subtask (\`pending\`) and dispatch THAT with
|
|
24825
|
+
\`task { taskId, agentId }\` (a specialist, or agentId "general-purpose" to run your
|
|
24826
|
+
own capabilities in an isolated run). **Never re-dispatch the task you are
|
|
24827
|
+
currently processing** \u2014 delegating to an expert means giving them a child task,
|
|
24828
|
+
not handing over your own. Report the outcome with \`set_status completed\` (result
|
|
24829
|
+
+ beliefImpact), \`failed\`, or \`interrupted\`. Use \`pending\` only for future or
|
|
24761
24830
|
dependency-blocked work.
|
|
24762
24831
|
Before marking the parent completed, call \`list(parentId)\`: every child must
|
|
24763
24832
|
be completed or cancelled, while a failed or interrupted child blocks completion
|
|
@@ -26048,34 +26117,24 @@ Renew HITL approval when a foundational assumption or authority boundary changes
|
|
|
26048
26117
|
|
|
26049
26118
|
## Skill Loading Policy
|
|
26050
26119
|
|
|
26051
|
-
Visible in <available_skills> does not mean loaded.
|
|
26052
|
-
|
|
26053
|
-
|
|
26054
|
-
|
|
26055
|
-
|
|
26056
|
-
- [[
|
|
26057
|
-
|
|
26058
|
-
|
|
26059
|
-
|
|
26060
|
-
|
|
26061
|
-
|
|
26062
|
-
-
|
|
26063
|
-
|
|
26064
|
-
-
|
|
26065
|
-
|
|
26066
|
-
|
|
26067
|
-
|
|
26068
|
-
|
|
26069
|
-
- Placing or authoring knowledge files (company vs project level) \u2192 [[knowledge-management]]
|
|
26070
|
-
|
|
26071
|
-
If a Tier 2 load fails, retry once, then stop and tell the user which
|
|
26072
|
-
capability is unavailable. Do not improvise the scenario from partial knowledge.
|
|
26073
|
-
|
|
26074
|
-
### Tier 3 \u2014 Reference (load on demand, never preload)
|
|
26075
|
-
Deep details reachable through wiki-links inside loaded skills, and plugin
|
|
26076
|
-
skills outside this chain (for example task-definition for non-architect
|
|
26077
|
-
agents, or sandbox-plugins-authoring for the \`plugin-builder\` agent). Load one
|
|
26078
|
-
only when the current step actually needs it.
|
|
26120
|
+
Visible in <available_skills> does not mean loaded. Load a skill only when the
|
|
26121
|
+
current step actually requires its procedure \u2014 one at a time, never preloaded.
|
|
26122
|
+
Do not load skills speculatively or to "see what exists": inspect existing
|
|
26123
|
+
assets with a bounded read-only survey, not by loading skill content.
|
|
26124
|
+
|
|
26125
|
+
- [[agent-architecture]] (this skill) \u2014 loaded at session start by the bootstrap
|
|
26126
|
+
prompt; it is the shared policy and router.
|
|
26127
|
+
- [[task-tracking]] \u2014 load right before your first \`manage_task\` call; Task
|
|
26128
|
+
management is the planning surface (gated again under Architect Task Policy).
|
|
26129
|
+
- Procedure skills \u2014 [[agent-build]], [[design-workflow]],
|
|
26130
|
+
[[document-learning-learn-capability]], [[eval-verify]], [[completion-gate]],
|
|
26131
|
+
[[review-agent]], [[knowledge-management]]: load the ONE that owns the step you
|
|
26132
|
+
are about to perform, immediately before performing it. Never preload the chain.
|
|
26133
|
+
- Reference and plugin skills (deep wiki-links, task-definition, sandbox authoring,
|
|
26134
|
+
and any plugin skills): load only when the current step needs them; never preload.
|
|
26135
|
+
|
|
26136
|
+
Loading a skill is a tool call, not a plan. If a required load fails, retry once,
|
|
26137
|
+
then stop and tell the user which capability is unavailable.
|
|
26079
26138
|
|
|
26080
26139
|
## Agent Forms and Routing
|
|
26081
26140
|
- **Capability** (\`react\`) for bounded direct work: [[agent-build]]
|
|
@@ -26088,9 +26147,19 @@ only when the current step actually needs it.
|
|
|
26088
26147
|
- **Tenant plugin** (sandbox-authored tool + optional HTML UI) \u2192 use the \`plugin-builder\` agent, or load [[sandbox-plugins-authoring]].
|
|
26089
26148
|
|
|
26090
26149
|
## Architect Task Policy
|
|
26091
|
-
The Agent Architect
|
|
26092
|
-
|
|
26150
|
+
The Agent Architect MUST use persistent TaskItems as its single working surface;
|
|
26151
|
+
Architect must not use \`write_todos\` for independently verifiable outcomes, and
|
|
26152
|
+
working without a corresponding TaskItem is a policy violation.
|
|
26153
|
+
Create a persistent child only for an independently verifiable
|
|
26093
26154
|
outcome; tool calls and file reads are actions inside the active Task.
|
|
26155
|
+
**Each task is your evidence ledger**: its Acceptance Criteria + Belief State define
|
|
26156
|
+
what counts as evidence, the work runs inside your own run (eval / \`invoke_agent\` for
|
|
26157
|
+
subject agents) and produces that evidence, and the parent completes only when the
|
|
26158
|
+
evidence is sufficient. Process the task you were assigned in this run; set it
|
|
26159
|
+
\`in_progress\` with \`manage_task set_status\` when you start. Delegate a subtask only
|
|
26160
|
+
when it belongs to another agent \u2014 create it (\`pending\`) and dispatch it with
|
|
26161
|
+
\`task { taskId, agentId }\`. To exercise a designed/subject agent, use eval /
|
|
26162
|
+
\`invoke_agent\` inside your own run instead of \`task\` dispatch.
|
|
26094
26163
|
**MANDATORY: before your first \`manage_task\` call in this session, load
|
|
26095
26164
|
[[task-tracking]] with the \`skill\` tool.** Do not create, update, or transition
|
|
26096
26165
|
any Task until it is loaded. If the load fails, retry once, then tell the user
|
|
@@ -26161,11 +26230,11 @@ When a room request is actionable work, decide between two paths:
|
|
|
26161
26230
|
\`assistantId\`, then dispatch it with
|
|
26162
26231
|
\`task { taskId, agentId: <bot assistantId> }\` so the specialist actually runs
|
|
26163
26232
|
(creating the task alone starts nothing). \`task\` transfers the task owner to
|
|
26164
|
-
\`agentId\` and
|
|
26165
|
-
|
|
26166
|
-
\`
|
|
26167
|
-
acceptance criteria in the task description so the assigned bot can
|
|
26168
|
-
own work.
|
|
26233
|
+
\`agentId\` and runs it in an isolated thread; the target does not need task
|
|
26234
|
+
tools \u2014 if it has \`manage_task\` it records status itself, otherwise reconcile
|
|
26235
|
+
its returned \`executionResultId\` with \`manage_task\` update. State the expected output
|
|
26236
|
+
and acceptance criteria in the task description so the assigned bot can
|
|
26237
|
+
verify its own work.
|
|
26169
26238
|
|
|
26170
26239
|
## Discovering bots
|
|
26171
26240
|
Before delegating, call \`list_room_roster\` to see the active room bots and their
|
|
@@ -26316,9 +26385,15 @@ criteria are truly met \u2014 never as a workaround.
|
|
|
26316
26385
|
uncertainties, with no required minimum and a maximum of seven:
|
|
26317
26386
|
\`manage_task create(title: <goal>, description: <contract + Belief State>, ownerType: "agent")\`
|
|
26318
26387
|
\`create\` always yields a \`pending\` record \u2014 it never starts execution. Record
|
|
26319
|
-
the returned parent task id, then
|
|
26320
|
-
\`
|
|
26321
|
-
\`
|
|
26388
|
+
the returned parent task id, then **process it in this run**, setting it
|
|
26389
|
+
\`in_progress\` with \`manage_task set_status\` when you start. To decompose, create each subtask
|
|
26390
|
+
with \`manage_task create\` (\`pending\`) and delegate it with \`task { taskId,
|
|
26391
|
+
agentId }\` to the agent that should execute it (a specialist, or
|
|
26392
|
+
"general-purpose" for your own capabilities). The executor does not need
|
|
26393
|
+
\`manage_task\`: it returns an observation and \`executionResultId\`, and the caller
|
|
26394
|
+
records the outcome with \`manage_task\`. To exercise a subject application agent,
|
|
26395
|
+
use eval cases / \`invoke_agent\` inside your own run \u2014 \`task\` dispatch is
|
|
26396
|
+
delegation of persistent work, not an evaluation mechanism.
|
|
26322
26397
|
- **Create a subtask for a verifiable result**, not per phase: identify its
|
|
26323
26398
|
deliverable, define observable acceptance criteria and required evidence, and
|
|
26324
26399
|
state positive and negative result branches under Targets / Expected Impact
|
|
@@ -26343,10 +26418,15 @@ ${TASK_BELIEF_REFERENCE_EXAMPLE}
|
|
|
26343
26418
|
|
|
26344
26419
|
## Status discipline \u2014 MANDATORY
|
|
26345
26420
|
|
|
26421
|
+
- Execution ownership: process the task you were assigned in this run; set it
|
|
26422
|
+
\`in_progress\` with \`manage_task set_status\` when you start. To involve a more
|
|
26423
|
+
suitable expert, create a subtask and dispatch it with \`task { taskId, agentId }\`
|
|
26424
|
+
\u2014 never re-dispatch the task you are processing. Report the outcome with
|
|
26425
|
+
\`set_status completed\` (result + beliefImpact), \`failed\`, or \`interrupted\`.
|
|
26346
26426
|
- All status transitions go through \`manage_task set_status\` (with
|
|
26347
26427
|
\`result\` on completed, \`failureReason\` on failed). \`update\` is for
|
|
26348
26428
|
content fields only and rejects a status field.
|
|
26349
|
-
- A
|
|
26429
|
+
- A task is \`completed\` ONLY when its work is actually finished.
|
|
26350
26430
|
While fixing eval failures, keep it \`in_progress\` \u2014 never mark
|
|
26351
26431
|
\`completed\` as a workaround (the state machine rejects illegal
|
|
26352
26432
|
transitions).
|
|
@@ -26946,6 +27026,11 @@ its evidence projection, not an independent source of goals or expectations.
|
|
|
26946
27026
|
touching any eval project. An eval project created without a real, confirmed
|
|
26947
27027
|
subject is a hard error. If the agent is only planned (not yet materialized),
|
|
26948
27028
|
evaluation must wait until materialization returns its id.
|
|
27029
|
+
- **Exercise the subject through eval \u2014 never through \`task\` dispatch.** The
|
|
27030
|
+
subject agent is invoked by eval cases / \`invoke_agent\`; do NOT create a
|
|
27031
|
+
TaskItem assigned to the subject and dispatch it. \`task\` is for delegated
|
|
27032
|
+
execution of persistent work, not an evaluation mechanism. Use eval cases to
|
|
27033
|
+
measure the subject; keep \`task\` dispatch for executors running real work.
|
|
26949
27034
|
- **Check existence before creating; reuse is the rule, creation is the exception.**
|
|
26950
27035
|
Project names are unique per tenant. 1) Name it exactly \`eval-{agent-id}\`.
|
|
26951
27036
|
2) \`read_eval list_projects({ name: "eval-{agent-id}" })\` \u2014 a name-scoped lookup,
|
|
@@ -27933,7 +28018,7 @@ var InMemoryMenuStore = class {
|
|
|
27933
28018
|
// src/agent_lattice/agentArchitectTools.ts
|
|
27934
28019
|
import z52 from "zod";
|
|
27935
28020
|
import { v4 as v43 } from "uuid";
|
|
27936
|
-
import { AgentType as
|
|
28021
|
+
import { AgentType as AgentType4 } from "@axiom-lattice/protocols";
|
|
27937
28022
|
function getTenantId2(exeConfig) {
|
|
27938
28023
|
const runConfig = exeConfig?.configurable?.runConfig || {};
|
|
27939
28024
|
return runConfig.tenantId || "default";
|
|
@@ -27983,7 +28068,7 @@ function getStringMetadata(config) {
|
|
|
27983
28068
|
}
|
|
27984
28069
|
function isUndecidedLearningPlaceholder(config) {
|
|
27985
28070
|
const metadata = getStringMetadata(config);
|
|
27986
|
-
return config.type ===
|
|
28071
|
+
return config.type === AgentType4.REACT && metadata.learningPlaceholder === "true" && metadata.architectureStatus === "undecided";
|
|
27987
28072
|
}
|
|
27988
28073
|
function requireSkillDeclaration(skillLoaded) {
|
|
27989
28074
|
if (skillLoaded !== true) {
|
|
@@ -27995,7 +28080,7 @@ function requireSkillDeclaration(skillLoaded) {
|
|
|
27995
28080
|
return void 0;
|
|
27996
28081
|
}
|
|
27997
28082
|
async function validateAgentReferences(input, tenantId2) {
|
|
27998
|
-
const availableTools = getAvailableTools(tenantId2).map((
|
|
28083
|
+
const availableTools = getAvailableTools(tenantId2).map((tool68) => tool68.key);
|
|
27999
28084
|
const availableMiddlewareTypes = getAvailableMiddlewareTypes();
|
|
28000
28085
|
const availableCustomMiddlewareKeys = CustomMiddlewareRegistry.list().filter(
|
|
28001
28086
|
(key5) => CustomMiddlewareRegistry.get(key5) !== void 0
|
|
@@ -28136,7 +28221,7 @@ registerToolLattice(
|
|
|
28136
28221
|
key: id,
|
|
28137
28222
|
name: input.name,
|
|
28138
28223
|
description: input.description || "",
|
|
28139
|
-
type: input.type === "deep_agent" ?
|
|
28224
|
+
type: input.type === "deep_agent" ? AgentType4.DEEP_AGENT : AgentType4.REACT,
|
|
28140
28225
|
prompt: input.prompt,
|
|
28141
28226
|
...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
|
|
28142
28227
|
...input.middleware && input.middleware.length > 0 ? { middleware: input.middleware } : {},
|
|
@@ -28193,7 +28278,7 @@ registerToolLattice(
|
|
|
28193
28278
|
key: id,
|
|
28194
28279
|
name: input.name,
|
|
28195
28280
|
description: input.description || "",
|
|
28196
|
-
type:
|
|
28281
|
+
type: AgentType4.WORKFLOW,
|
|
28197
28282
|
prompt: input.description || `Workflow: ${input.name}`,
|
|
28198
28283
|
workflowYaml: input.yaml,
|
|
28199
28284
|
...input.tools && input.tools.length > 0 ? { tools: input.tools } : {},
|
|
@@ -28230,7 +28315,7 @@ registerToolLattice(
|
|
|
28230
28315
|
return JSON.stringify({ error: `Agent '${input.id}' not found` });
|
|
28231
28316
|
}
|
|
28232
28317
|
const graphDef = agent.graphDefinition;
|
|
28233
|
-
if (!graphDef || graphDef.type !==
|
|
28318
|
+
if (!graphDef || graphDef.type !== AgentType4.WORKFLOW) {
|
|
28234
28319
|
return JSON.stringify({ error: `Agent '${input.id}' is not a workflow agent` });
|
|
28235
28320
|
}
|
|
28236
28321
|
const yaml = graphDef.workflowYaml;
|
|
@@ -28345,7 +28430,7 @@ registerToolLattice(
|
|
|
28345
28430
|
return JSON.stringify({ error: `Agent '${input.id}' not found` });
|
|
28346
28431
|
}
|
|
28347
28432
|
const existingConfig = existing.graphDefinition || {};
|
|
28348
|
-
const isWorkflow = existingConfig.type ===
|
|
28433
|
+
const isWorkflow = existingConfig.type === AgentType4.WORKFLOW;
|
|
28349
28434
|
const isPlaceholder = isUndecidedLearningPlaceholder(existingConfig);
|
|
28350
28435
|
if (!isWorkflow && !isPlaceholder) {
|
|
28351
28436
|
console.log(`[update_workflow] ERROR: not a workflow agent: ${input.id}`);
|
|
@@ -28361,7 +28446,7 @@ registerToolLattice(
|
|
|
28361
28446
|
const mergedConfig = {
|
|
28362
28447
|
...existingConfig,
|
|
28363
28448
|
...isPlaceholder ? {
|
|
28364
|
-
type:
|
|
28449
|
+
type: AgentType4.WORKFLOW,
|
|
28365
28450
|
workflowYaml: input.yaml,
|
|
28366
28451
|
metadata: {
|
|
28367
28452
|
...getStringMetadata(existingConfig),
|
|
@@ -28467,14 +28552,14 @@ registerToolLattice(
|
|
|
28467
28552
|
const mergedConfig = { ...existingConfig, ...input.config };
|
|
28468
28553
|
const isPlaceholder = isUndecidedLearningPlaceholder(existingConfigRecord);
|
|
28469
28554
|
const materializedType = input.config.type;
|
|
28470
|
-
const isMaterializingPlaceholder = isPlaceholder && (materializedType ===
|
|
28555
|
+
const isMaterializingPlaceholder = isPlaceholder && (materializedType === AgentType4.REACT || materializedType === AgentType4.DEEP_AGENT);
|
|
28471
28556
|
if (isMaterializingPlaceholder) {
|
|
28472
28557
|
mergedConfig.metadata = {
|
|
28473
28558
|
...getStringMetadata(existingConfigRecord),
|
|
28474
28559
|
...input.config.metadata ?? {},
|
|
28475
28560
|
learningPlaceholder: "false",
|
|
28476
28561
|
architectureStatus: "materialized",
|
|
28477
|
-
architectureForm: materializedType ===
|
|
28562
|
+
architectureForm: materializedType === AgentType4.DEEP_AGENT ? "orchestra" : "capability"
|
|
28478
28563
|
};
|
|
28479
28564
|
} else if (isPlaceholder && input.config.metadata !== void 0) {
|
|
28480
28565
|
const metadata = {
|
|
@@ -28724,100 +28809,20 @@ import { AgentType as AgentType5 } from "@axiom-lattice/protocols";
|
|
|
28724
28809
|
// src/agent_lattice/agentArchitectPrompt.ts
|
|
28725
28810
|
var AGENT_ARCHITECT_PROMPT = `You are the Agent Architect.
|
|
28726
28811
|
|
|
28727
|
-
|
|
28728
|
-
|
|
28729
|
-
|
|
28730
|
-
|
|
28731
|
-
|
|
28732
|
-
|
|
28733
|
-
explicitly report that the required skill could not be loaded.`;
|
|
28734
|
-
|
|
28735
|
-
// src/agent_lattice/agentReviewerConfig.ts
|
|
28736
|
-
import { AgentType as AgentType4 } from "@axiom-lattice/protocols";
|
|
28737
|
-
|
|
28738
|
-
// src/agent_lattice/agentReviewerPrompt.ts
|
|
28739
|
-
var AGENT_REVIEWER_PROMPT = `# Agent Reviewer
|
|
28740
|
-
|
|
28741
|
-
You are an **Agent Reviewer** \u2014 a quality assurance specialist for AI agents. Your job is to review agent configurations for correctness and test them by invoking them with realistic messages.
|
|
28812
|
+
Your working surface is persistent **TaskItems**. Every independently verifiable
|
|
28813
|
+
outcome MUST be a TaskItem created and kept truthful through \`manage_task\`; do NOT
|
|
28814
|
+
keep a separate todo list \u2014 the TaskItem is your only planning and evidence surface.
|
|
28815
|
+
Gather evidence through tasks, and treat the parent as done only when its
|
|
28816
|
+
acceptance evidence is sufficient. If the \`task\` tools are unavailable, stop and
|
|
28817
|
+
report that task management is unavailable instead of working around it.
|
|
28742
28818
|
|
|
28743
|
-
|
|
28744
|
-
|
|
28745
|
-
|
|
28746
|
-
|
|
28747
|
-
|
|
28748
|
-
|
|
28749
|
-
|
|
28750
|
-
## Your Workflow
|
|
28751
|
-
|
|
28752
|
-
### When asked to review an agent:
|
|
28753
|
-
|
|
28754
|
-
1. Call **get_agent** to fetch the agent's config
|
|
28755
|
-
2. Review the configuration for:
|
|
28756
|
-
- **Completeness** \u2014 Are name, description, prompt present? Is the prompt clear and actionable?
|
|
28757
|
-
- **Tool validity** \u2014 Do the referenced tools exist? Call **list_tools** to verify.
|
|
28758
|
-
- **Middleware correctness** \u2014 Is every middleware entry complete (id, type, name, description, enabled, config)?
|
|
28759
|
-
- **Sub-agent references** \u2014 Do referenced sub-agent IDs exist? Call **list_agents** to verify.
|
|
28760
|
-
- **Type consistency** \u2014 Does the agent type match its configuration shape? (e.g., PROCESSING must have edges, DEEP_AGENT may have subAgents)
|
|
28761
|
-
3. Report your findings clearly. For each issue, state:
|
|
28762
|
-
- Severity (ERROR / WARNING / INFO)
|
|
28763
|
-
- What the problem is
|
|
28764
|
-
- How to fix it
|
|
28765
|
-
|
|
28766
|
-
### When asked to test an agent:
|
|
28767
|
-
|
|
28768
|
-
1. Call **get_agent** to understand the agent's purpose and expected behavior
|
|
28769
|
-
2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
|
|
28770
|
-
3. Call **invoke_agent(id, message)** to send the test message
|
|
28771
|
-
4. Analyze the response:
|
|
28772
|
-
- **If result.__interrupt__ is present** (an array of interrupt objects): The agent hit a human-in-the-loop interrupt (e.g., ask_user_to_clarify or interrupt() in a workflow). This is NOT an error \u2014 it means the agent paused execution waiting for user feedback. Each interrupt has a value (the question/request) and optionally an id. Report this as: "The agent successfully paused and is waiting for user input: <describe the interrupt value>." The messages array may contain the agent's output up to the point of interruption.
|
|
28773
|
-
- **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
|
|
28774
|
-
- Did the agent understand the request?
|
|
28775
|
-
- Was the response relevant and accurate?
|
|
28776
|
-
- Did the agent use the right tools?
|
|
28777
|
-
- Were there any errors or unexpected behaviors?
|
|
28778
|
-
- **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
|
|
28779
|
-
5. Report your findings with the agent's actual response
|
|
28780
|
-
|
|
28781
|
-
### When results are wrong:
|
|
28782
|
-
|
|
28783
|
-
If the agent's response is incorrect or unexpected:
|
|
28784
|
-
1. Point out specifically what went wrong
|
|
28785
|
-
2. Suggest what might need to change in the prompt or middleware config
|
|
28786
|
-
3. Offer to re-test after fixes are applied
|
|
28787
|
-
|
|
28788
|
-
## Important Rules
|
|
28789
|
-
|
|
28790
|
-
- **Always use invoke_agent for testing.** This is the ONLY way to test \u2014 it spawns a fresh agent context isolated from all other conversations.
|
|
28791
|
-
- **Be specific in your feedback.** Say "the agent failed to call the sql tool because the middleware config is missing databaseKeys" not "the agent didn't work."
|
|
28792
|
-
- **One agent at a time.** Focus on one agent per review or test request. Don't try to review multiple agents simultaneously.
|
|
28793
|
-
- **Be concise but thorough.** Cover all the checks, but present findings clearly without fluff.
|
|
28794
|
-
`;
|
|
28795
|
-
|
|
28796
|
-
// src/agent_lattice/agentReviewerConfig.ts
|
|
28797
|
-
var AGENT_REVIEWER_KEY = "agent-reviewer";
|
|
28798
|
-
var agentReviewerConfig = {
|
|
28799
|
-
key: AGENT_REVIEWER_KEY,
|
|
28800
|
-
name: "Agent Reviewer",
|
|
28801
|
-
description: "Review and test AI agents. Use this agent to check agent configurations for correctness and to test agents by invoking them with realistic messages.",
|
|
28802
|
-
type: AgentType4.REACT,
|
|
28803
|
-
prompt: AGENT_REVIEWER_PROMPT,
|
|
28804
|
-
tools: [
|
|
28805
|
-
"invoke_agent",
|
|
28806
|
-
"get_agent",
|
|
28807
|
-
"list_agents",
|
|
28808
|
-
"list_tools"
|
|
28809
|
-
],
|
|
28810
|
-
middleware: [
|
|
28811
|
-
{
|
|
28812
|
-
id: "widget",
|
|
28813
|
-
type: "widget",
|
|
28814
|
-
name: "Widget",
|
|
28815
|
-
description: "Render interactive HTML widgets and SVG diagrams",
|
|
28816
|
-
enabled: true,
|
|
28817
|
-
config: {}
|
|
28818
|
-
}
|
|
28819
|
-
]
|
|
28820
|
-
};
|
|
28819
|
+
CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
|
|
28820
|
+
tool with skill_name: "agent-architecture" to load the shared policy and router,
|
|
28821
|
+
and follow it. Load every OTHER skill only when the current step actually
|
|
28822
|
+
requires its procedure \u2014 one at a time, never preloaded. Load "task-tracking"
|
|
28823
|
+
right before your first \`manage_task\` call. Never announce skill loads. If a
|
|
28824
|
+
required load fails, retry once, then stop and explicitly report that the
|
|
28825
|
+
required skill could not be loaded.`;
|
|
28821
28826
|
|
|
28822
28827
|
// src/agent_lattice/agentArchitectConfig.ts
|
|
28823
28828
|
var AGENT_ARCHITECT_KEY = "agent-architect";
|
|
@@ -28843,7 +28848,6 @@ var agentArchitectConfig = {
|
|
|
28843
28848
|
"manage_binding"
|
|
28844
28849
|
],
|
|
28845
28850
|
subAgents: ["document-parser-benchmark"],
|
|
28846
|
-
internalSubAgents: [agentReviewerConfig],
|
|
28847
28851
|
middleware: [
|
|
28848
28852
|
{
|
|
28849
28853
|
id: "filesystem",
|
|
@@ -28928,9 +28932,96 @@ var agentArchitectConfig = {
|
|
|
28928
28932
|
]
|
|
28929
28933
|
};
|
|
28930
28934
|
|
|
28931
|
-
// src/agent_lattice/
|
|
28935
|
+
// src/agent_lattice/agentReviewerConfig.ts
|
|
28932
28936
|
import { AgentType as AgentType6 } from "@axiom-lattice/protocols";
|
|
28933
28937
|
|
|
28938
|
+
// src/agent_lattice/agentReviewerPrompt.ts
|
|
28939
|
+
var AGENT_REVIEWER_PROMPT = `# Agent Reviewer
|
|
28940
|
+
|
|
28941
|
+
You are an **Agent Reviewer** \u2014 a quality assurance specialist for AI agents. Your job is to review agent configurations for correctness and test them by invoking them with realistic messages.
|
|
28942
|
+
|
|
28943
|
+
## Your Tools
|
|
28944
|
+
|
|
28945
|
+
- **get_agent** \u2014 Fetch an agent's full configuration
|
|
28946
|
+
- **list_agents** \u2014 List all agents in the workspace
|
|
28947
|
+
- **list_tools** \u2014 List all available tools that can be assigned to agents
|
|
28948
|
+
- **invoke_agent** \u2014 Test an agent by sending a message and getting its response. This spawns a completely fresh agent context \u2014 clean, isolated, and realistic.
|
|
28949
|
+
|
|
28950
|
+
## Your Workflow
|
|
28951
|
+
|
|
28952
|
+
### When asked to review an agent:
|
|
28953
|
+
|
|
28954
|
+
1. Call **get_agent** to fetch the agent's config
|
|
28955
|
+
2. Review the configuration for:
|
|
28956
|
+
- **Completeness** \u2014 Are name, description, prompt present? Is the prompt clear and actionable?
|
|
28957
|
+
- **Tool validity** \u2014 Do the referenced tools exist? Call **list_tools** to verify.
|
|
28958
|
+
- **Middleware correctness** \u2014 Is every middleware entry complete (id, type, name, description, enabled, config)?
|
|
28959
|
+
- **Sub-agent references** \u2014 Do referenced sub-agent IDs exist? Call **list_agents** to verify.
|
|
28960
|
+
- **Type consistency** \u2014 Does the agent type match its configuration shape? (e.g., PROCESSING must have edges, DEEP_AGENT may have subAgents)
|
|
28961
|
+
3. Report your findings clearly. For each issue, state:
|
|
28962
|
+
- Severity (ERROR / WARNING / INFO)
|
|
28963
|
+
- What the problem is
|
|
28964
|
+
- How to fix it
|
|
28965
|
+
|
|
28966
|
+
### When asked to test an agent:
|
|
28967
|
+
|
|
28968
|
+
1. Call **get_agent** to understand the agent's purpose and expected behavior
|
|
28969
|
+
2. Craft a realistic test message that exercises the agent's core responsibility \u2014 what would a real user say?
|
|
28970
|
+
3. Call **invoke_agent(id, message)** to send the test message
|
|
28971
|
+
4. Analyze the response:
|
|
28972
|
+
- **If result.__interrupt__ is present** (an array of interrupt objects): The agent hit a human-in-the-loop interrupt (e.g., ask_user_to_clarify or interrupt() in a workflow). This is NOT an error \u2014 it means the agent paused execution waiting for user feedback. Each interrupt has a value (the question/request) and optionally an id. Report this as: "The agent successfully paused and is waiting for user input: <describe the interrupt value>." The messages array may contain the agent's output up to the point of interruption.
|
|
28973
|
+
- **Otherwise, result.messages contains the agent's output**: The agent completed without interruption. Check:
|
|
28974
|
+
- Did the agent understand the request?
|
|
28975
|
+
- Was the response relevant and accurate?
|
|
28976
|
+
- Did the agent use the right tools?
|
|
28977
|
+
- Were there any errors or unexpected behaviors?
|
|
28978
|
+
- **If result.error is present**: The invocation itself failed (agent not found, compilation error, etc.). Report the error clearly.
|
|
28979
|
+
5. Report your findings with the agent's actual response
|
|
28980
|
+
|
|
28981
|
+
### When results are wrong:
|
|
28982
|
+
|
|
28983
|
+
If the agent's response is incorrect or unexpected:
|
|
28984
|
+
1. Point out specifically what went wrong
|
|
28985
|
+
2. Suggest what might need to change in the prompt or middleware config
|
|
28986
|
+
3. Offer to re-test after fixes are applied
|
|
28987
|
+
|
|
28988
|
+
## Important Rules
|
|
28989
|
+
|
|
28990
|
+
- **Always use invoke_agent for testing.** This is the ONLY way to test \u2014 it spawns a fresh agent context isolated from all other conversations.
|
|
28991
|
+
- **Be specific in your feedback.** Say "the agent failed to call the sql tool because the middleware config is missing databaseKeys" not "the agent didn't work."
|
|
28992
|
+
- **One agent at a time.** Focus on one agent per review or test request. Don't try to review multiple agents simultaneously.
|
|
28993
|
+
- **Be concise but thorough.** Cover all the checks, but present findings clearly without fluff.
|
|
28994
|
+
`;
|
|
28995
|
+
|
|
28996
|
+
// src/agent_lattice/agentReviewerConfig.ts
|
|
28997
|
+
var AGENT_REVIEWER_KEY = "agent-reviewer";
|
|
28998
|
+
var agentReviewerConfig = {
|
|
28999
|
+
key: AGENT_REVIEWER_KEY,
|
|
29000
|
+
name: "Agent Reviewer",
|
|
29001
|
+
description: "Review and test AI agents. Use this agent to check agent configurations for correctness and to test agents by invoking them with realistic messages.",
|
|
29002
|
+
type: AgentType6.REACT,
|
|
29003
|
+
prompt: AGENT_REVIEWER_PROMPT,
|
|
29004
|
+
tools: [
|
|
29005
|
+
"invoke_agent",
|
|
29006
|
+
"get_agent",
|
|
29007
|
+
"list_agents",
|
|
29008
|
+
"list_tools"
|
|
29009
|
+
],
|
|
29010
|
+
middleware: [
|
|
29011
|
+
{
|
|
29012
|
+
id: "widget",
|
|
29013
|
+
type: "widget",
|
|
29014
|
+
name: "Widget",
|
|
29015
|
+
description: "Render interactive HTML widgets and SVG diagrams",
|
|
29016
|
+
enabled: true,
|
|
29017
|
+
config: {}
|
|
29018
|
+
}
|
|
29019
|
+
]
|
|
29020
|
+
};
|
|
29021
|
+
|
|
29022
|
+
// src/agent_lattice/roomCoordinatorConfig.ts
|
|
29023
|
+
import { AgentType as AgentType7 } from "@axiom-lattice/protocols";
|
|
29024
|
+
|
|
28934
29025
|
// src/agent_lattice/roomCoordinatorPrompt.ts
|
|
28935
29026
|
var ROOM_COORDINATOR_PROMPT = `You are the Room Coordinator. CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\` tool with skill_name: "room-coordination" to load room-coordination and follow it. Never announce the skill load. If it fails, retry once, then stop and explicitly report that the required room-coordination skill could not be loaded.`;
|
|
28936
29027
|
|
|
@@ -28940,7 +29031,7 @@ var roomCoordinatorConfig = {
|
|
|
28940
29031
|
key: ROOM_COORDINATOR_KEY,
|
|
28941
29032
|
name: "Room Coordinator",
|
|
28942
29033
|
description: "Manages project room conversations: replies when no bot is mentioned, coordinates room members, and organizes project work.",
|
|
28943
|
-
type:
|
|
29034
|
+
type: AgentType7.DEEP_AGENT,
|
|
28944
29035
|
prompt: ROOM_COORDINATOR_PROMPT,
|
|
28945
29036
|
tools: [],
|
|
28946
29037
|
middleware: [
|
|
@@ -29575,17 +29666,6 @@ var getAgentClient = (tenantId2, key5, options) => agentLatticeManager.initializ
|
|
|
29575
29666
|
var getAgentClientAsync = async (tenantId2, key5, options) => agentLatticeManager.initializeClientAsync(tenantId2, key5, options);
|
|
29576
29667
|
var createAgentClientFromAgentLattice = async (agentLattice, options) => await agentLatticeManager.createAgentClientFromConfig(agentLattice, options);
|
|
29577
29668
|
|
|
29578
|
-
// src/agent_lattice/taskCapability.ts
|
|
29579
|
-
function agentHasManagedTaskCapability(config) {
|
|
29580
|
-
const middleware = config?.middleware;
|
|
29581
|
-
const taskMiddleware = Array.isArray(middleware) ? middleware.find((entry) => entry?.type === "task" && entry?.enabled === true) : void 0;
|
|
29582
|
-
if (!taskMiddleware) {
|
|
29583
|
-
return false;
|
|
29584
|
-
}
|
|
29585
|
-
const allowedTools = taskMiddleware.allowedTools;
|
|
29586
|
-
return allowedTools === void 0 || Array.isArray(allowedTools) && (allowedTools.length === 0 || allowedTools.includes("manage_task"));
|
|
29587
|
-
}
|
|
29588
|
-
|
|
29589
29669
|
// src/vectorstore_lattice/VectorStoreLatticeManager.ts
|
|
29590
29670
|
var VectorStoreLatticeManager = class _VectorStoreLatticeManager extends BaseLatticeManager {
|
|
29591
29671
|
/**
|
|
@@ -30985,15 +31065,15 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
30985
31065
|
const metaByName = new Map(metaList.map((m) => [m.name, m.meta]));
|
|
30986
31066
|
this.unregisterServerTools(tenantId2, serverKey);
|
|
30987
31067
|
const keys = [];
|
|
30988
|
-
for (const
|
|
30989
|
-
if (rt.selectedTools && !rt.selectedTools.includes(
|
|
30990
|
-
const meta = metaByName.get(
|
|
31068
|
+
for (const tool68 of tools) {
|
|
31069
|
+
if (rt.selectedTools && !rt.selectedTools.includes(tool68.name)) continue;
|
|
31070
|
+
const meta = metaByName.get(tool68.name);
|
|
30991
31071
|
const rawVisibility = meta?.ui?.visibility;
|
|
30992
31072
|
const visibility = Array.isArray(rawVisibility) ? rawVisibility : typeof rawVisibility === "string" ? [rawVisibility] : void 0;
|
|
30993
31073
|
if (visibility && !visibility.includes("model")) continue;
|
|
30994
31074
|
const ref = extractAppsRef(meta, serverKey);
|
|
30995
|
-
const registered = ref ? wrapMcpToolWithUi(
|
|
30996
|
-
const toolKey = _McpLatticeManager.buildToolKey(serverKey,
|
|
31075
|
+
const registered = ref ? wrapMcpToolWithUi(tool68, ref) : tool68;
|
|
31076
|
+
const toolKey = _McpLatticeManager.buildToolKey(serverKey, tool68.name);
|
|
30997
31077
|
try {
|
|
30998
31078
|
toolLatticeManager.registerExistingToolWithTenant(tenantId2, toolKey, registered);
|
|
30999
31079
|
keys.push(toolKey);
|
|
@@ -34167,7 +34247,7 @@ var LatticeEvalSuite = class {
|
|
|
34167
34247
|
};
|
|
34168
34248
|
|
|
34169
34249
|
// src/eval_lattice/LatticeEvalProject.ts
|
|
34170
|
-
import { AgentType as
|
|
34250
|
+
import { AgentType as AgentType8 } from "@axiom-lattice/protocols";
|
|
34171
34251
|
import { HumanMessage as HumanMessage6 } from "@langchain/core/messages";
|
|
34172
34252
|
import { v4 as uuidv47 } from "uuid";
|
|
34173
34253
|
var DEFAULT_CALIBRATION_PROBES = [
|
|
@@ -34223,7 +34303,7 @@ var LatticeEvalProject = class {
|
|
|
34223
34303
|
key: this.judgeAgentKey,
|
|
34224
34304
|
name: `Judge agent for ${this.project.projectName}`,
|
|
34225
34305
|
description: "Judge agent for evaluating Lattice test cases",
|
|
34226
|
-
type:
|
|
34306
|
+
type: AgentType8.REACT,
|
|
34227
34307
|
prompt: "",
|
|
34228
34308
|
modelKey: judgeModelKey
|
|
34229
34309
|
};
|
|
@@ -37578,6 +37658,33 @@ function createTaskRunBridge(deps) {
|
|
|
37578
37658
|
transitioned: true
|
|
37579
37659
|
};
|
|
37580
37660
|
}
|
|
37661
|
+
if (task.status === "interrupted" || task.status === "failed") {
|
|
37662
|
+
if (task.ownerType !== "agent") {
|
|
37663
|
+
return {
|
|
37664
|
+
success: false,
|
|
37665
|
+
code: "AGENT_TASK_REQUIRED",
|
|
37666
|
+
error: "Lifecycle transitions only support agent tasks."
|
|
37667
|
+
};
|
|
37668
|
+
}
|
|
37669
|
+
const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({ tenantId: tenantId2, taskId: task.id, actor, threadId }) : await deps.lifecycle.retryTask({ tenantId: tenantId2, taskId: task.id, actor, threadId });
|
|
37670
|
+
if (!result.success) {
|
|
37671
|
+
return {
|
|
37672
|
+
success: false,
|
|
37673
|
+
code: result.code,
|
|
37674
|
+
error: result.error,
|
|
37675
|
+
...result.hint !== void 0 ? { hint: result.hint } : {},
|
|
37676
|
+
...result.retryable !== void 0 ? { retryable: result.retryable } : {},
|
|
37677
|
+
...result.warnings !== void 0 ? { warnings: result.warnings } : {}
|
|
37678
|
+
};
|
|
37679
|
+
}
|
|
37680
|
+
return {
|
|
37681
|
+
success: true,
|
|
37682
|
+
task: result.task,
|
|
37683
|
+
warnings: result.warnings ?? [],
|
|
37684
|
+
mutated: true,
|
|
37685
|
+
transitioned: true
|
|
37686
|
+
};
|
|
37687
|
+
}
|
|
37581
37688
|
return { success: true, task, warnings, mutated: false, transitioned: false };
|
|
37582
37689
|
},
|
|
37583
37690
|
async settleRun(input) {
|
|
@@ -37731,48 +37838,18 @@ async function prepareTaskDispatch(deps, input) {
|
|
|
37731
37838
|
}
|
|
37732
37839
|
};
|
|
37733
37840
|
}
|
|
37734
|
-
if (task.status !== "pending") {
|
|
37841
|
+
if (task.status !== "pending" && task.status !== "interrupted" && task.status !== "failed") {
|
|
37735
37842
|
return {
|
|
37736
37843
|
kind: "failure",
|
|
37737
37844
|
failure: {
|
|
37738
37845
|
success: false,
|
|
37739
37846
|
code: "TASK_NOT_DISPATCHABLE",
|
|
37740
|
-
error: "Only a `pending` task can be dispatched.",
|
|
37741
|
-
hint: `This task is '${task.status}'.
|
|
37847
|
+
error: "Only a `pending`, `interrupted`, or `failed` task can be dispatched.",
|
|
37848
|
+
hint: `This task is '${task.status}'. A \`pending\` task starts, an \`interrupted\` task resumes, and a \`failed\` task retries. A task already \`in_progress\` is held by a live run; terminal tasks cannot be dispatched.`,
|
|
37742
37849
|
taskId: task.id
|
|
37743
37850
|
}
|
|
37744
37851
|
};
|
|
37745
37852
|
}
|
|
37746
|
-
if (deps.resolveTaskCapability) {
|
|
37747
|
-
let targetCapable;
|
|
37748
|
-
try {
|
|
37749
|
-
targetCapable = await deps.resolveTaskCapability(input.tenantId, input.agentId);
|
|
37750
|
-
} catch (error) {
|
|
37751
|
-
return {
|
|
37752
|
-
kind: "failure",
|
|
37753
|
-
failure: {
|
|
37754
|
-
success: false,
|
|
37755
|
-
code: "AGENT_RESOLUTION_FAILED",
|
|
37756
|
-
error: errorMessage(error),
|
|
37757
|
-
taskId: task.id,
|
|
37758
|
-
agentId: input.agentId
|
|
37759
|
-
}
|
|
37760
|
-
};
|
|
37761
|
-
}
|
|
37762
|
-
if (!targetCapable) {
|
|
37763
|
-
return {
|
|
37764
|
-
kind: "failure",
|
|
37765
|
-
failure: {
|
|
37766
|
-
success: false,
|
|
37767
|
-
code: "TASK_DELEGATE_TARGET_NOT_CAPABLE",
|
|
37768
|
-
taskId: task.id,
|
|
37769
|
-
agentId: input.agentId,
|
|
37770
|
-
error: `Agent '${input.agentId}' cannot manage tasks, so a dispatched TaskItem could never be completed.`,
|
|
37771
|
-
hint: "Delegate to an agent with the `task` middleware (exposes `manage_task`), or do the work inline and update the task with `manage_task set_status`."
|
|
37772
|
-
}
|
|
37773
|
-
};
|
|
37774
|
-
}
|
|
37775
|
-
}
|
|
37776
37853
|
const managedAuthority = executionAuthorityRegistry.resolve(task);
|
|
37777
37854
|
if (managedAuthority) {
|
|
37778
37855
|
if (managedAuthority.onManagedStart) {
|
|
@@ -38184,6 +38261,7 @@ function toJsonSafeValue(value) {
|
|
|
38184
38261
|
}
|
|
38185
38262
|
|
|
38186
38263
|
// src/services/TaskExecutionService.ts
|
|
38264
|
+
import { GraphInterrupt as GraphInterrupt2 } from "@langchain/langgraph";
|
|
38187
38265
|
function persistedExecutionObservation(item, attempted) {
|
|
38188
38266
|
const detail = item.detail;
|
|
38189
38267
|
const persistedObservation = toJsonSafeValue(detail?.observation);
|
|
@@ -38230,9 +38308,10 @@ function createTaskExecutionService(deps) {
|
|
|
38230
38308
|
const run = async (plan) => {
|
|
38231
38309
|
const { tenantId: tenantId2, agentId, actor, parent, completedDependencies } = plan;
|
|
38232
38310
|
let task = plan.task;
|
|
38311
|
+
const persistedThreadId = (task.status === "interrupted" || task.status === "failed") && typeof task.context?.thread_id === "string" && task.context.thread_id.trim() !== "" ? task.context.thread_id : void 0;
|
|
38233
38312
|
let threadId;
|
|
38234
38313
|
try {
|
|
38235
|
-
threadId = (deps.createThreadId ?? randomUUID8)();
|
|
38314
|
+
threadId = persistedThreadId ?? (deps.createThreadId ?? randomUUID8)();
|
|
38236
38315
|
} catch (error) {
|
|
38237
38316
|
return {
|
|
38238
38317
|
success: false,
|
|
@@ -38271,12 +38350,12 @@ function createTaskExecutionService(deps) {
|
|
|
38271
38350
|
task = transfer.task;
|
|
38272
38351
|
}
|
|
38273
38352
|
const warnings = [];
|
|
38274
|
-
if (task.status === "pending") {
|
|
38353
|
+
if (task.status === "pending" || task.status === "interrupted" || task.status === "failed") {
|
|
38275
38354
|
const begun = await bridge.beginRun({
|
|
38276
38355
|
tenantId: tenantId2,
|
|
38277
38356
|
task,
|
|
38278
38357
|
actor,
|
|
38279
|
-
threadId
|
|
38358
|
+
threadId
|
|
38280
38359
|
});
|
|
38281
38360
|
if (!begun.success) return { ...begun, taskId: task.id };
|
|
38282
38361
|
if (!begun.mutated || !begun.transitioned) {
|
|
@@ -38305,6 +38384,19 @@ function createTaskExecutionService(deps) {
|
|
|
38305
38384
|
try {
|
|
38306
38385
|
observation = toJsonSafeValue(await deps.invokeAgent(invocation));
|
|
38307
38386
|
} catch (error) {
|
|
38387
|
+
if (error instanceof GraphInterrupt2) {
|
|
38388
|
+
try {
|
|
38389
|
+
await bridge.settleRun({
|
|
38390
|
+
tenantId: tenantId2,
|
|
38391
|
+
task,
|
|
38392
|
+
actor,
|
|
38393
|
+
threadId,
|
|
38394
|
+
outcome: { kind: "interrupted", summary: "Awaiting user input" }
|
|
38395
|
+
});
|
|
38396
|
+
} catch {
|
|
38397
|
+
}
|
|
38398
|
+
throw error;
|
|
38399
|
+
}
|
|
38308
38400
|
const normalizationError = error instanceof JsonSafeValueError;
|
|
38309
38401
|
const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
|
|
38310
38402
|
const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
|
|
@@ -38435,6 +38527,76 @@ function createTaskExecutionService(deps) {
|
|
|
38435
38527
|
};
|
|
38436
38528
|
}
|
|
38437
38529
|
|
|
38530
|
+
// src/services/TaskRunRegistry.ts
|
|
38531
|
+
var TaskRunRegistry = class {
|
|
38532
|
+
constructor() {
|
|
38533
|
+
this.live = /* @__PURE__ */ new Set();
|
|
38534
|
+
}
|
|
38535
|
+
/** Marks a task as currently held by a live run. */
|
|
38536
|
+
register(taskId) {
|
|
38537
|
+
this.live.add(taskId);
|
|
38538
|
+
}
|
|
38539
|
+
/** Removes a task once its run has ended. */
|
|
38540
|
+
unregister(taskId) {
|
|
38541
|
+
this.live.delete(taskId);
|
|
38542
|
+
}
|
|
38543
|
+
/** Reports whether a task is currently held by a live run. */
|
|
38544
|
+
isLive(taskId) {
|
|
38545
|
+
return this.live.has(taskId);
|
|
38546
|
+
}
|
|
38547
|
+
/** Returns a snapshot of the live task ids (diagnostics/tests). */
|
|
38548
|
+
snapshot() {
|
|
38549
|
+
return [...this.live];
|
|
38550
|
+
}
|
|
38551
|
+
/** Clears all live entries (tests / process teardown). */
|
|
38552
|
+
clear() {
|
|
38553
|
+
this.live.clear();
|
|
38554
|
+
}
|
|
38555
|
+
};
|
|
38556
|
+
var taskRunRegistry = new TaskRunRegistry();
|
|
38557
|
+
async function reconcileStaleTaskRuns(input) {
|
|
38558
|
+
const registry4 = input.registry ?? taskRunRegistry;
|
|
38559
|
+
const converged = [];
|
|
38560
|
+
for (const task of input.tasks) {
|
|
38561
|
+
if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
|
|
38562
|
+
const result = await input.lifecycle.interruptTask({
|
|
38563
|
+
tenantId: task.tenantId,
|
|
38564
|
+
taskId: task.id,
|
|
38565
|
+
actor: input.actor,
|
|
38566
|
+
type: "missing_input",
|
|
38567
|
+
summary: "Run is no longer executing this task (no_executor)"
|
|
38568
|
+
});
|
|
38569
|
+
if (result.success) converged.push(task.id);
|
|
38570
|
+
}
|
|
38571
|
+
return { converged };
|
|
38572
|
+
}
|
|
38573
|
+
async function reconcileTenantTaskRuns(input) {
|
|
38574
|
+
const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
|
|
38575
|
+
const candidates = input.include ? tasks.filter(input.include) : tasks;
|
|
38576
|
+
return reconcileStaleTaskRuns({
|
|
38577
|
+
tasks: candidates,
|
|
38578
|
+
actor: input.actor,
|
|
38579
|
+
lifecycle: input.lifecycle,
|
|
38580
|
+
...input.registry ? { registry: input.registry } : {}
|
|
38581
|
+
});
|
|
38582
|
+
}
|
|
38583
|
+
async function reconcileAllTenantTaskRuns(input) {
|
|
38584
|
+
const tenants = await input.tenantStore.listTenants();
|
|
38585
|
+
const converged = [];
|
|
38586
|
+
for (const tenant of tenants) {
|
|
38587
|
+
const result = await reconcileTenantTaskRuns({
|
|
38588
|
+
tenantId: tenant.id,
|
|
38589
|
+
actor: input.actor,
|
|
38590
|
+
taskStore: input.taskStore,
|
|
38591
|
+
lifecycle: input.lifecycle,
|
|
38592
|
+
...input.registry ? { registry: input.registry } : {},
|
|
38593
|
+
...input.include ? { include: input.include } : {}
|
|
38594
|
+
});
|
|
38595
|
+
converged.push(...result.converged);
|
|
38596
|
+
}
|
|
38597
|
+
return { converged };
|
|
38598
|
+
}
|
|
38599
|
+
|
|
38438
38600
|
// src/index.ts
|
|
38439
38601
|
import * as Protocols from "@axiom-lattice/protocols";
|
|
38440
38602
|
|
|
@@ -38700,10 +38862,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
|
|
|
38700
38862
|
lockIdentity
|
|
38701
38863
|
);
|
|
38702
38864
|
let result2 = pluginSkill.definition.content;
|
|
38703
|
-
const
|
|
38704
|
-
if (
|
|
38865
|
+
const resources2 = Object.entries(pluginSkill.definition.resources ?? {});
|
|
38866
|
+
if (resources2.length > 0) {
|
|
38705
38867
|
result2 += "\n\n---\n\n**Resources** (synced to the sandbox; use `read_file` to access):\n";
|
|
38706
|
-
for (const [resourcePath, resource] of
|
|
38868
|
+
for (const [resourcePath, resource] of resources2) {
|
|
38707
38869
|
result2 += `- ${resourcePath} (mime type: ${resource.mimeType ?? "not specified"})
|
|
38708
38870
|
`;
|
|
38709
38871
|
}
|
|
@@ -38730,10 +38892,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
|
|
|
38730
38892
|
`/root/.agents/skills/${input.skill_name}/resources`,
|
|
38731
38893
|
{ recursive: false }
|
|
38732
38894
|
);
|
|
38733
|
-
const
|
|
38734
|
-
if (
|
|
38895
|
+
const resources2 = resourcesResult.files.map((f) => f.path.split("/").pop()).filter(Boolean);
|
|
38896
|
+
if (resources2.length > 0) {
|
|
38735
38897
|
result += "\n\n---\n\n**Resources** (use `read_file` tool to access):\n";
|
|
38736
|
-
|
|
38898
|
+
resources2.forEach((r) => {
|
|
38737
38899
|
result += `- ${r}
|
|
38738
38900
|
`;
|
|
38739
38901
|
});
|
|
@@ -39055,1368 +39217,13 @@ var skillPlugin = {
|
|
|
39055
39217
|
})
|
|
39056
39218
|
};
|
|
39057
39219
|
|
|
39058
|
-
// src/middlewares/
|
|
39220
|
+
// src/middlewares/collectionMiddleware.ts
|
|
39059
39221
|
import { createMiddleware as createMiddleware20 } from "langchain";
|
|
39060
39222
|
|
|
39061
|
-
// src/tool_lattice/
|
|
39223
|
+
// src/tool_lattice/collection/list_collections.ts
|
|
39062
39224
|
import z57 from "zod";
|
|
39063
39225
|
import { tool as tool51 } from "langchain";
|
|
39064
39226
|
|
|
39065
|
-
// src/tool_lattice/semantic_metrics/types.ts
|
|
39066
|
-
function readToolRunConfig(exeConfig) {
|
|
39067
|
-
return exeConfig?.configurable?.runConfig;
|
|
39068
|
-
}
|
|
39069
|
-
function resolveDatasourceId(input, exeConfig) {
|
|
39070
|
-
const id = input.datasourceId ?? readToolRunConfig(exeConfig)?.metricsDataSource?.datasourceId;
|
|
39071
|
-
if (id === void 0 || id === null || id === "") {
|
|
39072
|
-
throw new Error("datasourceId is required (provide it or set runConfig.metricsDataSource.datasourceId)");
|
|
39073
|
-
}
|
|
39074
|
-
return Number(id);
|
|
39075
|
-
}
|
|
39076
|
-
function assertDatasourceSelected(scope, datasourceId) {
|
|
39077
|
-
if (scope.unrestricted) return;
|
|
39078
|
-
if (!scope.ids.includes(datasourceId)) {
|
|
39079
|
-
throw new Error(
|
|
39080
|
-
`DATASOURCE_NOT_SELECTED: datasource ${datasourceId} is not in the effective scope [${scope.ids.join(", ")}]`
|
|
39081
|
-
);
|
|
39082
|
-
}
|
|
39083
|
-
}
|
|
39084
|
-
function effectiveDatasourceScope(connectionScope) {
|
|
39085
|
-
return connectionScope.length > 0 ? { unrestricted: false, ids: [...connectionScope] } : { unrestricted: true, ids: [] };
|
|
39086
|
-
}
|
|
39087
|
-
var DDL_DML_KEYWORDS = [
|
|
39088
|
-
"insert",
|
|
39089
|
-
"update",
|
|
39090
|
-
"delete",
|
|
39091
|
-
"drop",
|
|
39092
|
-
"alter",
|
|
39093
|
-
"create",
|
|
39094
|
-
"truncate",
|
|
39095
|
-
"grant",
|
|
39096
|
-
"revoke",
|
|
39097
|
-
"merge",
|
|
39098
|
-
"replace",
|
|
39099
|
-
"upsert"
|
|
39100
|
-
];
|
|
39101
|
-
var DDL_DML_RE = new RegExp(`\\b(?:${DDL_DML_KEYWORDS.join("|")})\\b`, "i");
|
|
39102
|
-
var SELECT_INTO_RE = /\bselect\b[\s\S]*?\binto\b/i;
|
|
39103
|
-
function validateSql(sql) {
|
|
39104
|
-
const trimmed = sql.trim();
|
|
39105
|
-
if (!trimmed) {
|
|
39106
|
-
return { ok: false, reason: "SQL is empty" };
|
|
39107
|
-
}
|
|
39108
|
-
const withoutComments = trimmed.replace(/--[^\n]*/g, " ").replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
39109
|
-
const statements = withoutComments.split(";").map((s) => s.trim()).filter(Boolean);
|
|
39110
|
-
if (statements.length > 1) {
|
|
39111
|
-
return { ok: false, reason: "Multiple statements are not allowed" };
|
|
39112
|
-
}
|
|
39113
|
-
const firstKeyword = withoutComments.trim().split(/\s+/)[0].toLowerCase();
|
|
39114
|
-
if (firstKeyword !== "select" && firstKeyword !== "with") {
|
|
39115
|
-
return { ok: false, reason: `Only SELECT or WITH queries are allowed (got "${firstKeyword}")` };
|
|
39116
|
-
}
|
|
39117
|
-
if (SELECT_INTO_RE.test(withoutComments)) {
|
|
39118
|
-
return { ok: false, reason: "SELECT INTO is not allowed (creates a table)" };
|
|
39119
|
-
}
|
|
39120
|
-
if (DDL_DML_RE.test(withoutComments)) {
|
|
39121
|
-
return { ok: false, reason: "Only read-only queries are allowed (DML/DDL detected)" };
|
|
39122
|
-
}
|
|
39123
|
-
return { ok: true };
|
|
39124
|
-
}
|
|
39125
|
-
|
|
39126
|
-
// src/tool_lattice/semantic_metrics/SemanticMetricsV2Client.ts
|
|
39127
|
-
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.";
|
|
39128
|
-
async function resolveMetricsClientFromSelector(selector, scope, connectionKey) {
|
|
39129
|
-
let resolved;
|
|
39130
|
-
try {
|
|
39131
|
-
resolved = await resolvePluginConnections(selector.connectionType, selector, scope);
|
|
39132
|
-
} catch (error) {
|
|
39133
|
-
if (error instanceof Error && error.message === "ConnectionStore not configured") {
|
|
39134
|
-
throw new Error(NO_CONNECTION_HINT);
|
|
39135
|
-
}
|
|
39136
|
-
throw error;
|
|
39137
|
-
}
|
|
39138
|
-
const available = resolved.map((c) => c.key).join(", ");
|
|
39139
|
-
if (resolved.length === 0) {
|
|
39140
|
-
throw new Error(NO_CONNECTION_HINT);
|
|
39141
|
-
}
|
|
39142
|
-
const key5 = connectionKey?.trim() || (resolved.length === 1 ? resolved[0].key : "");
|
|
39143
|
-
if (!key5) {
|
|
39144
|
-
throw new Error(
|
|
39145
|
-
`connectionKey is required. Available connections: ${available}`
|
|
39146
|
-
);
|
|
39147
|
-
}
|
|
39148
|
-
const entry = resolved.find((c) => c.key === key5);
|
|
39149
|
-
if (!entry) {
|
|
39150
|
-
throw new Error(`Connection "${key5}" not found. Available connections: ${available}`);
|
|
39151
|
-
}
|
|
39152
|
-
const config = entry.config;
|
|
39153
|
-
return new SemanticMetricsV2Client(config);
|
|
39154
|
-
}
|
|
39155
|
-
var SemanticMetricsV2Client = class {
|
|
39156
|
-
/**
|
|
39157
|
-
* @param config - Connection configuration (server URL, optional API key and headers).
|
|
39158
|
-
*/
|
|
39159
|
-
constructor(config) {
|
|
39160
|
-
this.config = config;
|
|
39161
|
-
this.baseUrl = config.serverUrl.replace(/\/$/, "");
|
|
39162
|
-
}
|
|
39163
|
-
/**
|
|
39164
|
-
* Build default request headers: `Accept: application/json`, custom headers,
|
|
39165
|
-
* and a Bearer `Authorization` header when an API key is configured.
|
|
39166
|
-
*
|
|
39167
|
-
* @returns Merged headers.
|
|
39168
|
-
*/
|
|
39169
|
-
getHeaders() {
|
|
39170
|
-
const headers = {
|
|
39171
|
-
Accept: "application/json",
|
|
39172
|
-
...this.config.headers ?? {}
|
|
39173
|
-
};
|
|
39174
|
-
if (this.config.apiKey) {
|
|
39175
|
-
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
39176
|
-
}
|
|
39177
|
-
return headers;
|
|
39178
|
-
}
|
|
39179
|
-
/**
|
|
39180
|
-
* Numeric selected resource ids of this connection (normalized).
|
|
39181
|
-
*
|
|
39182
|
-
* Reads `selectedEntities` — the standard connection resource-selection
|
|
39183
|
-
* field written by the connection UI (`connection.discover` + selection).
|
|
39184
|
-
*
|
|
39185
|
-
* @returns The selected resource ids; empty when unrestricted.
|
|
39186
|
-
*/
|
|
39187
|
-
getSelectedEntities() {
|
|
39188
|
-
const raw = this.config.selectedEntities;
|
|
39189
|
-
if (!Array.isArray(raw)) return [];
|
|
39190
|
-
return raw.map((v) => Number(v)).filter((n) => Number.isFinite(n));
|
|
39191
|
-
}
|
|
39192
|
-
/**
|
|
39193
|
-
* Perform a JSON request against the base URL.
|
|
39194
|
-
*
|
|
39195
|
-
* The Metrics Server wraps every response as `{ code, message, data }`. A
|
|
39196
|
-
* `code` of 200 resolves to `data`; any other `code` throws a business error
|
|
39197
|
-
* carrying the server message (regardless of HTTP status). Non-envelope
|
|
39198
|
-
* bodies are returned as-is.
|
|
39199
|
-
*
|
|
39200
|
-
* @param path - Path appended to the base URL (must start with `/`).
|
|
39201
|
-
* @param init - Optional `fetch` init overrides (method, body, per-call headers).
|
|
39202
|
-
* @returns The unwrapped `data` payload of the response envelope.
|
|
39203
|
-
* @throws When the server returns a non-200 `code`, or the HTTP response is not OK.
|
|
39204
|
-
*/
|
|
39205
|
-
async request(path8, init = {}) {
|
|
39206
|
-
const response = await fetch(`${this.baseUrl}${path8}`, {
|
|
39207
|
-
...init,
|
|
39208
|
-
method: init.method ?? "GET",
|
|
39209
|
-
headers: { ...this.getHeaders(), ...init.headers ?? {} }
|
|
39210
|
-
});
|
|
39211
|
-
const text = await response.text().catch(() => "");
|
|
39212
|
-
const parsed = this.parseBody(text);
|
|
39213
|
-
if (parsed?.envelope === true) {
|
|
39214
|
-
if (parsed.code !== 200) {
|
|
39215
|
-
throw new Error(`API ${parsed.code}: ${parsed.message || "Unknown error"}`);
|
|
39216
|
-
}
|
|
39217
|
-
return parsed.data;
|
|
39218
|
-
}
|
|
39219
|
-
if (!response.ok) {
|
|
39220
|
-
throw new Error(`HTTP ${response.status}: ${text || response.statusText}`);
|
|
39221
|
-
}
|
|
39222
|
-
return parsed?.value ?? void 0;
|
|
39223
|
-
}
|
|
39224
|
-
/**
|
|
39225
|
-
* Parse a response body text. Detects the server envelope `{ code, message, data }`.
|
|
39226
|
-
*
|
|
39227
|
-
* @param text - Raw response body text.
|
|
39228
|
-
* @returns `{ envelope: true, code, message, data }` for an envelope body,
|
|
39229
|
-
* `{ envelope: false, value }` for anything else (or `{ envelope: false }` when empty/invalid).
|
|
39230
|
-
*/
|
|
39231
|
-
parseBody(text) {
|
|
39232
|
-
if (!text.trim()) return { envelope: false };
|
|
39233
|
-
try {
|
|
39234
|
-
const value = JSON.parse(text);
|
|
39235
|
-
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
39236
|
-
const record = value;
|
|
39237
|
-
if (typeof record.code === "number") {
|
|
39238
|
-
return {
|
|
39239
|
-
envelope: true,
|
|
39240
|
-
code: record.code,
|
|
39241
|
-
message: typeof record.message === "string" ? record.message : void 0,
|
|
39242
|
-
data: record.data
|
|
39243
|
-
};
|
|
39244
|
-
}
|
|
39245
|
-
}
|
|
39246
|
-
return { envelope: false, value };
|
|
39247
|
-
} catch {
|
|
39248
|
-
return { envelope: false, value: text };
|
|
39249
|
-
}
|
|
39250
|
-
}
|
|
39251
|
-
/**
|
|
39252
|
-
* POST a JSON body to a path.
|
|
39253
|
-
*
|
|
39254
|
-
* @param path - Path appended to the base URL.
|
|
39255
|
-
* @param body - Payload serialized as JSON.
|
|
39256
|
-
* @returns Parsed JSON response body.
|
|
39257
|
-
*/
|
|
39258
|
-
post(path8, body) {
|
|
39259
|
-
return this.request(path8, {
|
|
39260
|
-
method: "POST",
|
|
39261
|
-
headers: { "Content-Type": "application/json" },
|
|
39262
|
-
body: JSON.stringify(body)
|
|
39263
|
-
});
|
|
39264
|
-
}
|
|
39265
|
-
/**
|
|
39266
|
-
* PUT a JSON body to a path.
|
|
39267
|
-
*
|
|
39268
|
-
* @param path - Path appended to the base URL.
|
|
39269
|
-
* @param body - Payload serialized as JSON.
|
|
39270
|
-
* @returns Parsed JSON response body.
|
|
39271
|
-
*/
|
|
39272
|
-
put(path8, body) {
|
|
39273
|
-
return this.request(path8, {
|
|
39274
|
-
method: "PUT",
|
|
39275
|
-
headers: { "Content-Type": "application/json" },
|
|
39276
|
-
body: JSON.stringify(body)
|
|
39277
|
-
});
|
|
39278
|
-
}
|
|
39279
|
-
/**
|
|
39280
|
-
* List all datasources.
|
|
39281
|
-
*
|
|
39282
|
-
* @returns Parsed JSON response body.
|
|
39283
|
-
*/
|
|
39284
|
-
listDatasources() {
|
|
39285
|
-
return this.request("/datasources");
|
|
39286
|
-
}
|
|
39287
|
-
/**
|
|
39288
|
-
* Get table grants for a datasource.
|
|
39289
|
-
*
|
|
39290
|
-
* @param datasourceId - Datasource identifier.
|
|
39291
|
-
* @returns Parsed JSON response body.
|
|
39292
|
-
*/
|
|
39293
|
-
getTableGrants(datasourceId) {
|
|
39294
|
-
return this.request(`/datasources/${encodeURIComponent(datasourceId)}/table-grants`);
|
|
39295
|
-
}
|
|
39296
|
-
/**
|
|
39297
|
-
* Run a read-only SQL query against a datasource.
|
|
39298
|
-
*
|
|
39299
|
-
* @param datasourceId - Datasource identifier.
|
|
39300
|
-
* @param input - Query input: `sql` (SELECT/WITH only), optional `params`, `maxRows`, `debug`.
|
|
39301
|
-
* @returns Parsed JSON response body.
|
|
39302
|
-
* @throws When `sql` fails read-only validation (rejected before any fetch).
|
|
39303
|
-
*/
|
|
39304
|
-
async queryDatasource(datasourceId, input) {
|
|
39305
|
-
const validation = validateSql(input.sql);
|
|
39306
|
-
if (!validation.ok) throw new Error(`SQL_NOT_ALLOWED: ${validation.reason}`);
|
|
39307
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/query`, input);
|
|
39308
|
-
}
|
|
39309
|
-
/**
|
|
39310
|
-
* Test a datasource connection.
|
|
39311
|
-
*
|
|
39312
|
-
* @param datasourceId - Datasource identifier.
|
|
39313
|
-
* @returns Parsed JSON response body.
|
|
39314
|
-
*/
|
|
39315
|
-
testDatasource(datasourceId) {
|
|
39316
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/test`, {});
|
|
39317
|
-
}
|
|
39318
|
-
/**
|
|
39319
|
-
* Get connection-pool status for a datasource.
|
|
39320
|
-
*
|
|
39321
|
-
* @param datasourceId - Datasource identifier.
|
|
39322
|
-
* @returns Parsed JSON response body.
|
|
39323
|
-
*/
|
|
39324
|
-
getPoolStatus(datasourceId) {
|
|
39325
|
-
return this.request(`/datasources/${encodeURIComponent(datasourceId)}/pool`);
|
|
39326
|
-
}
|
|
39327
|
-
/**
|
|
39328
|
-
* List table metadata for a datasource, auto-paginating.
|
|
39329
|
-
*
|
|
39330
|
-
* The server pages this collection (`page`/`pageSize`, default page size 20),
|
|
39331
|
-
* so requests aggregate every page into one `{ items, total }` result.
|
|
39332
|
-
*
|
|
39333
|
-
* @param datasourceId - Datasource identifier.
|
|
39334
|
-
* @returns `{ items: [...], total }` covering all pages.
|
|
39335
|
-
*/
|
|
39336
|
-
async listTables(datasourceId) {
|
|
39337
|
-
return this.listMetaPage(`/datasources/${encodeURIComponent(datasourceId)}/meta/tables`);
|
|
39338
|
-
}
|
|
39339
|
-
/**
|
|
39340
|
-
* Shared pagination walk for the paged meta collections (`{items,total,page,pageSize}`).
|
|
39341
|
-
*
|
|
39342
|
-
* @param basePath - Collection path (tables or metrics).
|
|
39343
|
-
* @returns `{ items, total }` aggregated across all pages.
|
|
39344
|
-
*/
|
|
39345
|
-
async listMetaPage(basePath) {
|
|
39346
|
-
const pageSize = 100;
|
|
39347
|
-
const items = [];
|
|
39348
|
-
let total = Number.POSITIVE_INFINITY;
|
|
39349
|
-
for (let page = 1; items.length < total; page += 1) {
|
|
39350
|
-
const body = await this.request(`${basePath}?page=${page}&pageSize=${pageSize}`);
|
|
39351
|
-
const record = body !== null && typeof body === "object" ? body : {};
|
|
39352
|
-
const batch = Array.isArray(record.items) ? record.items : [];
|
|
39353
|
-
items.push(...batch);
|
|
39354
|
-
total = typeof record.total === "number" ? record.total : items.length;
|
|
39355
|
-
if (batch.length === 0) break;
|
|
39356
|
-
}
|
|
39357
|
-
return { items, total: items.length };
|
|
39358
|
-
}
|
|
39359
|
-
/**
|
|
39360
|
-
* Get metadata for a single table.
|
|
39361
|
-
*
|
|
39362
|
-
* @param datasourceId - Datasource identifier.
|
|
39363
|
-
* @param tableKey - Table key.
|
|
39364
|
-
* @returns Parsed JSON response body.
|
|
39365
|
-
*/
|
|
39366
|
-
getTable(datasourceId, tableKey) {
|
|
39367
|
-
return this.request(
|
|
39368
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`
|
|
39369
|
-
);
|
|
39370
|
-
}
|
|
39371
|
-
/**
|
|
39372
|
-
* Create a table definition for a datasource.
|
|
39373
|
-
*
|
|
39374
|
-
* @param datasourceId - Datasource identifier.
|
|
39375
|
-
* @param payload - Table definition payload.
|
|
39376
|
-
* @returns Parsed JSON response body.
|
|
39377
|
-
*/
|
|
39378
|
-
createTable(datasourceId, payload) {
|
|
39379
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/meta/tables`, payload);
|
|
39380
|
-
}
|
|
39381
|
-
/**
|
|
39382
|
-
* Update a table definition for a datasource.
|
|
39383
|
-
*
|
|
39384
|
-
* @param datasourceId - Datasource identifier.
|
|
39385
|
-
* @param tableKey - Table key.
|
|
39386
|
-
* @param payload - Table definition payload.
|
|
39387
|
-
* @returns Parsed JSON response body.
|
|
39388
|
-
*/
|
|
39389
|
-
/**
|
|
39390
|
-
* Update a published table meta via read-modify-write.
|
|
39391
|
-
*
|
|
39392
|
-
* The server's PUT replaces the whole payload, so the current payload is
|
|
39393
|
-
* fetched first and the incoming fields are merged on top; fields not
|
|
39394
|
-
* mentioned are preserved.
|
|
39395
|
-
*/
|
|
39396
|
-
async updateTable(datasourceId, tableKey, payload) {
|
|
39397
|
-
const existing = await this.readMetaPayload(`${this.baseUrl}/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`);
|
|
39398
|
-
return this.put(
|
|
39399
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/tables/${encodeURIComponent(tableKey)}`,
|
|
39400
|
-
{ payload: { ...existing, ...payload } }
|
|
39401
|
-
);
|
|
39402
|
-
}
|
|
39403
|
-
/**
|
|
39404
|
-
* List metric definitions for a datasource.
|
|
39405
|
-
*
|
|
39406
|
-
* @param datasourceId - Datasource identifier.
|
|
39407
|
-
* @returns Parsed JSON response body.
|
|
39408
|
-
*/
|
|
39409
|
-
/**
|
|
39410
|
-
* List metric metadata for a datasource, auto-paginating.
|
|
39411
|
-
*
|
|
39412
|
-
* The server pages this collection (`page`/`pageSize`, default page size 20),
|
|
39413
|
-
* so requests aggregate every page into one `{ items, total }` result.
|
|
39414
|
-
*
|
|
39415
|
-
* @param datasourceId - Datasource identifier.
|
|
39416
|
-
* @returns `{ items: [...], total }` covering all pages.
|
|
39417
|
-
*/
|
|
39418
|
-
async listMetrics(datasourceId) {
|
|
39419
|
-
return this.listMetaPage(`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics`);
|
|
39420
|
-
}
|
|
39421
|
-
/**
|
|
39422
|
-
* Get a single metric definition.
|
|
39423
|
-
*
|
|
39424
|
-
* @param datasourceId - Datasource identifier.
|
|
39425
|
-
* @param metricKey - Metric key.
|
|
39426
|
-
* @returns Parsed JSON response body.
|
|
39427
|
-
*/
|
|
39428
|
-
getMetric(datasourceId, metricKey) {
|
|
39429
|
-
return this.request(
|
|
39430
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`
|
|
39431
|
-
);
|
|
39432
|
-
}
|
|
39433
|
-
/**
|
|
39434
|
-
* Create a metric definition for a datasource.
|
|
39435
|
-
*
|
|
39436
|
-
* @param datasourceId - Datasource identifier.
|
|
39437
|
-
* @param payload - Metric definition payload.
|
|
39438
|
-
* @returns Parsed JSON response body.
|
|
39439
|
-
*/
|
|
39440
|
-
createMetric(datasourceId, payload) {
|
|
39441
|
-
return this.post(`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics`, payload);
|
|
39442
|
-
}
|
|
39443
|
-
/**
|
|
39444
|
-
* Update a metric definition for a datasource.
|
|
39445
|
-
*
|
|
39446
|
-
* @param datasourceId - Datasource identifier.
|
|
39447
|
-
* @param metricKey - Metric key.
|
|
39448
|
-
* @param payload - Metric definition payload.
|
|
39449
|
-
* @returns Parsed JSON response body.
|
|
39450
|
-
*/
|
|
39451
|
-
/**
|
|
39452
|
-
* Update a published metric meta via read-modify-write.
|
|
39453
|
-
*
|
|
39454
|
-
* The server's PUT replaces the whole payload, so the current payload is
|
|
39455
|
-
* fetched first and the incoming fields are merged on top; fields not
|
|
39456
|
-
* mentioned are preserved.
|
|
39457
|
-
*/
|
|
39458
|
-
async updateMetric(datasourceId, metricKey, payload) {
|
|
39459
|
-
const existing = await this.readMetaPayload(`${this.baseUrl}/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`);
|
|
39460
|
-
return this.put(
|
|
39461
|
-
`/datasources/${encodeURIComponent(datasourceId)}/meta/metrics/${encodeURIComponent(metricKey)}`,
|
|
39462
|
-
{ payload: { ...existing, ...payload } }
|
|
39463
|
-
);
|
|
39464
|
-
}
|
|
39465
|
-
/**
|
|
39466
|
-
* Fetch the current `payload` object of a published meta entry.
|
|
39467
|
-
*
|
|
39468
|
-
* The single-entry read returns `{ code, data: [entry] }` (already unwrapped
|
|
39469
|
-
* to the array by {@link request}); the payload lives on the first entry.
|
|
39470
|
-
*
|
|
39471
|
-
* @param absoluteUrl - Full URL of the single-entry meta read.
|
|
39472
|
-
* @returns The stored payload object (empty when none exists).
|
|
39473
|
-
*/
|
|
39474
|
-
async readMetaPayload(absoluteUrl) {
|
|
39475
|
-
const response = await fetch(absoluteUrl, { headers: this.getHeaders() });
|
|
39476
|
-
const text = await response.text().catch(() => "");
|
|
39477
|
-
if (!response.ok) {
|
|
39478
|
-
throw new Error(`HTTP ${response.status}: ${text || response.statusText}`);
|
|
39479
|
-
}
|
|
39480
|
-
const parsed = this.parseBody(text);
|
|
39481
|
-
const data = parsed?.envelope === true ? parsed.data : parsed?.value;
|
|
39482
|
-
const entry = Array.isArray(data) ? data[0] : data;
|
|
39483
|
-
const payload = entry?.payload;
|
|
39484
|
-
return payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
39485
|
-
}
|
|
39486
|
-
/**
|
|
39487
|
-
* Get runtime metadata for a datasource.
|
|
39488
|
-
*
|
|
39489
|
-
* @param datasourceId - Datasource identifier.
|
|
39490
|
-
* @returns Parsed JSON response body.
|
|
39491
|
-
*/
|
|
39492
|
-
getRuntimeMeta(datasourceId) {
|
|
39493
|
-
return this.request(`/datasources/${encodeURIComponent(datasourceId)}/meta`);
|
|
39494
|
-
}
|
|
39495
|
-
/**
|
|
39496
|
-
* Run a metrics query.
|
|
39497
|
-
*
|
|
39498
|
-
* @param request - Metrics query request payload.
|
|
39499
|
-
* @returns Parsed JSON response body.
|
|
39500
|
-
*/
|
|
39501
|
-
queryMetrics(request) {
|
|
39502
|
-
return this.post("/metrics/query", request);
|
|
39503
|
-
}
|
|
39504
|
-
/**
|
|
39505
|
-
* Run an ad-hoc custom SQL query, validated as read-only before sending.
|
|
39506
|
-
*
|
|
39507
|
-
* @param request - Request with `datasourceId`, `customSql` (SELECT/WITH only),
|
|
39508
|
-
* and optional `limit` / `debug`.
|
|
39509
|
-
* @returns Parsed JSON response body.
|
|
39510
|
-
* @throws When `customSql` fails read-only validation (rejected before any fetch).
|
|
39511
|
-
*/
|
|
39512
|
-
async customSql(request) {
|
|
39513
|
-
const validation = validateSql(request.customSql);
|
|
39514
|
-
if (!validation.ok) throw new Error(`SQL_NOT_ALLOWED: ${validation.reason}`);
|
|
39515
|
-
return this.post("/metrics/query", request);
|
|
39516
|
-
}
|
|
39517
|
-
};
|
|
39518
|
-
|
|
39519
|
-
// src/tool_lattice/semantic_metrics/metrics_datasource_tool.ts
|
|
39520
|
-
var DESCRIPTION = `PHYSICAL LAYER EXPLORATION \u2014 the only tool for probing raw datasource structure (Builder/Admin only; business agents do not need it).
|
|
39521
|
-
|
|
39522
|
-
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.
|
|
39523
|
-
|
|
39524
|
-
DOES NOT OWN:
|
|
39525
|
-
- Published semantic assets (table meta / metric meta) \u2192 use metrics_meta_tool.
|
|
39526
|
-
- Runtime meta and business metric queries \u2192 use metrics_runtime_tool.
|
|
39527
|
-
|
|
39528
|
-
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.
|
|
39529
|
-
|
|
39530
|
-
COMMON MISTAKES (do not):
|
|
39531
|
-
- 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).
|
|
39532
|
-
- Do not read or publish semantic meta through this tool \u2014 metrics_meta_tool owns the semantic layer.
|
|
39533
|
-
- Do not probe tables outside the tenant's table-grants; un-granted probes are rejected and break the exploration boundary.
|
|
39534
|
-
- Do not attempt writes \u2014 SQL is validated read-only and rejected before sending.`;
|
|
39535
|
-
function createMetricsDatasourceTool(params) {
|
|
39536
|
-
const { connectionType, connections, connectAll } = params;
|
|
39537
|
-
return tool51(
|
|
39538
|
-
async (input, exeConfig) => {
|
|
39539
|
-
try {
|
|
39540
|
-
const client = await resolveMetricsClientFromSelector(
|
|
39541
|
-
{ connectionType, connections, connectAll },
|
|
39542
|
-
readToolRunConfig(exeConfig) ?? {},
|
|
39543
|
-
input.connectionKey
|
|
39544
|
-
);
|
|
39545
|
-
const scope = effectiveDatasourceScope(client.getSelectedEntities());
|
|
39546
|
-
switch (input.action) {
|
|
39547
|
-
case "list_datasources": {
|
|
39548
|
-
const result = await client.listDatasources();
|
|
39549
|
-
const filtered = scope.unrestricted ? result : result.filter((d) => scope.ids.includes(Number(d.id)));
|
|
39550
|
-
const safe = filtered.map((d) => ({
|
|
39551
|
-
id: d.id,
|
|
39552
|
-
name: d.name,
|
|
39553
|
-
sourceType: d.sourceType,
|
|
39554
|
-
description: d.description,
|
|
39555
|
-
statusLabel: d.statusLabel
|
|
39556
|
-
}));
|
|
39557
|
-
return JSON.stringify(safe, null, 2);
|
|
39558
|
-
}
|
|
39559
|
-
case "get_grants": {
|
|
39560
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39561
|
-
assertDatasourceSelected(scope, ds);
|
|
39562
|
-
const result = await client.getTableGrants(ds);
|
|
39563
|
-
return JSON.stringify(result, null, 2);
|
|
39564
|
-
}
|
|
39565
|
-
case "query_sql": {
|
|
39566
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39567
|
-
assertDatasourceSelected(scope, ds);
|
|
39568
|
-
if (!input.sql) throw new Error("sql is required for the 'query_sql' action");
|
|
39569
|
-
const result = await client.queryDatasource(ds, {
|
|
39570
|
-
sql: input.sql,
|
|
39571
|
-
params: input.params,
|
|
39572
|
-
maxRows: input.maxRows
|
|
39573
|
-
});
|
|
39574
|
-
return JSON.stringify(result, null, 2);
|
|
39575
|
-
}
|
|
39576
|
-
case "test_connection": {
|
|
39577
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39578
|
-
assertDatasourceSelected(scope, ds);
|
|
39579
|
-
const result = await client.testDatasource(ds);
|
|
39580
|
-
return JSON.stringify(result, null, 2);
|
|
39581
|
-
}
|
|
39582
|
-
case "pool_status": {
|
|
39583
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39584
|
-
assertDatasourceSelected(scope, ds);
|
|
39585
|
-
const result = await client.getPoolStatus(ds);
|
|
39586
|
-
return JSON.stringify(result, null, 2);
|
|
39587
|
-
}
|
|
39588
|
-
}
|
|
39589
|
-
} catch (error) {
|
|
39590
|
-
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
39591
|
-
}
|
|
39592
|
-
},
|
|
39593
|
-
{
|
|
39594
|
-
name: "metrics_datasource_tool",
|
|
39595
|
-
description: DESCRIPTION,
|
|
39596
|
-
schema: z57.object({
|
|
39597
|
-
action: z57.enum(["list_datasources", "get_grants", "query_sql", "test_connection", "pool_status"]).describe(
|
|
39598
|
-
"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"
|
|
39599
|
-
),
|
|
39600
|
-
connectionKey: z57.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
|
|
39601
|
-
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)"),
|
|
39602
|
-
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"),
|
|
39603
|
-
params: z57.record(z57.union([z57.string(), z57.number(), z57.boolean()])).optional().describe("Named :param values for the SQL"),
|
|
39604
|
-
maxRows: z57.number().optional().describe("Max rows to return")
|
|
39605
|
-
})
|
|
39606
|
-
}
|
|
39607
|
-
);
|
|
39608
|
-
}
|
|
39609
|
-
|
|
39610
|
-
// src/tool_lattice/semantic_metrics/metrics_meta_tool.ts
|
|
39611
|
-
import z58 from "zod";
|
|
39612
|
-
import { tool as tool52 } from "langchain";
|
|
39613
|
-
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).
|
|
39614
|
-
|
|
39615
|
-
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).
|
|
39616
|
-
|
|
39617
|
-
DOES NOT OWN:
|
|
39618
|
-
- Running queries or reading the aggregated runtime view \u2192 metrics_runtime_tool (get_meta / query / custom_sql).
|
|
39619
|
-
- Probing physical tables, columns, grants, or samples \u2192 metrics_datasource_tool.
|
|
39620
|
-
|
|
39621
|
-
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.
|
|
39622
|
-
|
|
39623
|
-
COMMON MISTAKES (do not):
|
|
39624
|
-
- Do not call get_meta here \u2014 that action belongs to metrics_runtime_tool, not this tool.
|
|
39625
|
-
- Do not try to "query numbers" through this tool \u2014 list/read actions return definitions only; use metrics_runtime_tool query for data.
|
|
39626
|
-
- 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.
|
|
39627
|
-
- The builder assistant must load the semantic-metrics-modeling skill and pass modelingSkillLoaded: true on write actions; no removal actions are exposed on purpose.`;
|
|
39628
|
-
var MODELING_SKILL_NAME = "semantic-metrics-modeling";
|
|
39629
|
-
var BUILDER_ASSISTANT_ID = "semantic-metrics-builder";
|
|
39630
|
-
function requireModelingSkillLoaded(action, input, exeConfig) {
|
|
39631
|
-
const isWriteAction = action === "create_table" || action === "update_table" || action === "create_metric" || action === "update_metric";
|
|
39632
|
-
if (!isWriteAction) return void 0;
|
|
39633
|
-
const runConfig = readToolRunConfig(exeConfig);
|
|
39634
|
-
const assistantId = runConfig?.assistant_id;
|
|
39635
|
-
if (assistantId === BUILDER_ASSISTANT_ID && input.modelingSkillLoaded !== true) {
|
|
39636
|
-
return JSON.stringify({
|
|
39637
|
-
success: false,
|
|
39638
|
-
error: `Load the '${MODELING_SKILL_NAME}' skill before publishing meta.`
|
|
39639
|
-
});
|
|
39640
|
-
}
|
|
39641
|
-
return void 0;
|
|
39642
|
-
}
|
|
39643
|
-
function actionRequiresPayload(action) {
|
|
39644
|
-
return action === "create_table" || action === "update_table" || action === "create_metric" || action === "update_metric";
|
|
39645
|
-
}
|
|
39646
|
-
function createMetricsMetaTool(params) {
|
|
39647
|
-
const { connectionType, connections, connectAll } = params;
|
|
39648
|
-
return tool52(
|
|
39649
|
-
async (input, exeConfig) => {
|
|
39650
|
-
try {
|
|
39651
|
-
const guardError = requireModelingSkillLoaded(input.action, input, exeConfig);
|
|
39652
|
-
if (guardError !== void 0) return guardError;
|
|
39653
|
-
const client = await resolveMetricsClientFromSelector(
|
|
39654
|
-
{ connectionType, connections, connectAll },
|
|
39655
|
-
readToolRunConfig(exeConfig) ?? {},
|
|
39656
|
-
input.connectionKey
|
|
39657
|
-
);
|
|
39658
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39659
|
-
assertDatasourceSelected(effectiveDatasourceScope(client.getSelectedEntities()), ds);
|
|
39660
|
-
if (actionRequiresPayload(input.action) && input.payload === void 0) {
|
|
39661
|
-
throw new Error(`payload is required for ${input.action}`);
|
|
39662
|
-
}
|
|
39663
|
-
const payload = input.payload ?? {};
|
|
39664
|
-
switch (input.action) {
|
|
39665
|
-
case "list_tables": {
|
|
39666
|
-
return JSON.stringify(await client.listTables(ds), null, 2);
|
|
39667
|
-
}
|
|
39668
|
-
case "read_table_meta": {
|
|
39669
|
-
if (!input.objectKey) throw new Error("objectKey is required for read_table_meta");
|
|
39670
|
-
return JSON.stringify(await client.getTable(ds, input.objectKey), null, 2);
|
|
39671
|
-
}
|
|
39672
|
-
case "create_table": {
|
|
39673
|
-
return JSON.stringify(await client.createTable(ds, payload), null, 2);
|
|
39674
|
-
}
|
|
39675
|
-
case "update_table": {
|
|
39676
|
-
if (!input.objectKey) throw new Error("objectKey is required for update_table");
|
|
39677
|
-
return JSON.stringify(await client.updateTable(ds, input.objectKey, payload), null, 2);
|
|
39678
|
-
}
|
|
39679
|
-
case "list_metrics": {
|
|
39680
|
-
return JSON.stringify(await client.listMetrics(ds), null, 2);
|
|
39681
|
-
}
|
|
39682
|
-
case "read_metric_meta": {
|
|
39683
|
-
if (!input.objectKey) throw new Error("objectKey is required for read_metric_meta");
|
|
39684
|
-
return JSON.stringify(await client.getMetric(ds, input.objectKey), null, 2);
|
|
39685
|
-
}
|
|
39686
|
-
case "create_metric": {
|
|
39687
|
-
return JSON.stringify(await client.createMetric(ds, payload), null, 2);
|
|
39688
|
-
}
|
|
39689
|
-
case "update_metric": {
|
|
39690
|
-
if (!input.objectKey) throw new Error("objectKey is required for update_metric");
|
|
39691
|
-
return JSON.stringify(await client.updateMetric(ds, input.objectKey, payload), null, 2);
|
|
39692
|
-
}
|
|
39693
|
-
}
|
|
39694
|
-
} catch (error) {
|
|
39695
|
-
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
39696
|
-
}
|
|
39697
|
-
},
|
|
39698
|
-
{
|
|
39699
|
-
name: "metrics_meta_tool",
|
|
39700
|
-
description: DESCRIPTION2,
|
|
39701
|
-
schema: z58.object({
|
|
39702
|
-
action: z58.enum([
|
|
39703
|
-
"list_tables",
|
|
39704
|
-
"read_table_meta",
|
|
39705
|
-
"create_table",
|
|
39706
|
-
"update_table",
|
|
39707
|
-
"list_metrics",
|
|
39708
|
-
"read_metric_meta",
|
|
39709
|
-
"create_metric",
|
|
39710
|
-
"update_metric"
|
|
39711
|
-
]).describe(
|
|
39712
|
-
"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)"
|
|
39713
|
-
),
|
|
39714
|
-
connectionKey: z58.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
|
|
39715
|
-
datasourceId: z58.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (optional if set in runConfig.metricsDataSource)"),
|
|
39716
|
-
objectKey: z58.string().optional().describe("Semantic table/metric key (required for read_table_meta/update_table/read_metric_meta/update_metric)"),
|
|
39717
|
-
payload: z58.record(z58.unknown()).optional().describe("Meta payload (required for create/update actions; objectType/objectKey/status/payload/accessGrant)"),
|
|
39718
|
-
modelingSkillLoaded: z58.literal(true).optional().describe("Set true after loading the semantic-metrics-modeling skill (required for the builder assistant on write actions)")
|
|
39719
|
-
})
|
|
39720
|
-
}
|
|
39721
|
-
);
|
|
39722
|
-
}
|
|
39723
|
-
|
|
39724
|
-
// src/tool_lattice/semantic_metrics/metrics_runtime_tool.ts
|
|
39725
|
-
import z59 from "zod";
|
|
39726
|
-
import { tool as tool53 } from "langchain";
|
|
39727
|
-
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.
|
|
39728
|
-
|
|
39729
|
-
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).
|
|
39730
|
-
|
|
39731
|
-
DOES NOT OWN:
|
|
39732
|
-
- 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).
|
|
39733
|
-
- Physical exploration of raw tables, grants, or samples \u2192 metrics_datasource_tool (query_sql).
|
|
39734
|
-
- Free-form custom SQL \u2014 intentionally not provided; use query against published metrics.
|
|
39735
|
-
|
|
39736
|
-
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).
|
|
39737
|
-
|
|
39738
|
-
COMMON MISTAKES (do not):
|
|
39739
|
-
- 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.
|
|
39740
|
-
- 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.
|
|
39741
|
-
- Metrics and dimensions in query_metrics must already be published; querying an unpublished metric fails with "not found in catalog".`;
|
|
39742
|
-
function createMetricsRuntimeTool(params) {
|
|
39743
|
-
const { connectionType, connections, connectAll } = params;
|
|
39744
|
-
return tool53(
|
|
39745
|
-
async (input, exeConfig) => {
|
|
39746
|
-
try {
|
|
39747
|
-
const client = await resolveMetricsClientFromSelector(
|
|
39748
|
-
{ connectionType, connections, connectAll },
|
|
39749
|
-
readToolRunConfig(exeConfig) ?? {},
|
|
39750
|
-
input.connectionKey
|
|
39751
|
-
);
|
|
39752
|
-
const scope = effectiveDatasourceScope(client.getSelectedEntities());
|
|
39753
|
-
switch (input.action) {
|
|
39754
|
-
case "list_datasources": {
|
|
39755
|
-
const result = await client.listDatasources();
|
|
39756
|
-
const filtered = scope.unrestricted ? result : result.filter((d) => scope.ids.includes(Number(d.id)));
|
|
39757
|
-
const safe = filtered.map((d) => ({
|
|
39758
|
-
id: d.id,
|
|
39759
|
-
name: d.name,
|
|
39760
|
-
sourceType: d.sourceType,
|
|
39761
|
-
description: d.description,
|
|
39762
|
-
statusLabel: d.statusLabel
|
|
39763
|
-
}));
|
|
39764
|
-
return JSON.stringify(safe, null, 2);
|
|
39765
|
-
}
|
|
39766
|
-
case "read_semantic_catalog": {
|
|
39767
|
-
const ds = resolveDatasourceId(input, exeConfig);
|
|
39768
|
-
assertDatasourceSelected(scope, ds);
|
|
39769
|
-
return JSON.stringify(await client.getRuntimeMeta(ds), null, 2);
|
|
39770
|
-
}
|
|
39771
|
-
case "query_metrics": {
|
|
39772
|
-
if (!input.query) throw new Error("query is required for the 'query_metrics' action");
|
|
39773
|
-
const bodyDatasourceId = input.query.datasourceId;
|
|
39774
|
-
if (bodyDatasourceId !== void 0) {
|
|
39775
|
-
assertDatasourceSelected(scope, Number(bodyDatasourceId));
|
|
39776
|
-
}
|
|
39777
|
-
return JSON.stringify(await client.queryMetrics(input.query), null, 2);
|
|
39778
|
-
}
|
|
39779
|
-
}
|
|
39780
|
-
} catch (error) {
|
|
39781
|
-
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
39782
|
-
}
|
|
39783
|
-
},
|
|
39784
|
-
{
|
|
39785
|
-
name: "metrics_runtime_tool",
|
|
39786
|
-
description: DESCRIPTION3,
|
|
39787
|
-
schema: z59.object({
|
|
39788
|
-
action: z59.enum(["list_datasources", "read_semantic_catalog", "query_metrics"]).describe(
|
|
39789
|
-
"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"
|
|
39790
|
-
),
|
|
39791
|
-
connectionKey: z59.string().optional().describe("Connection key. Omit when only one semantic-metrics connection exists"),
|
|
39792
|
-
datasourceId: z59.coerce.number().optional().describe("Numeric datasource id, e.g. 15 (required for read_semantic_catalog; optional if set in runConfig.metricsDataSource)"),
|
|
39793
|
-
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 }')
|
|
39794
|
-
})
|
|
39795
|
-
}
|
|
39796
|
-
);
|
|
39797
|
-
}
|
|
39798
|
-
|
|
39799
|
-
// src/middlewares/semanticMetricsModelingSkill.ts
|
|
39800
|
-
var CONTENT = `---
|
|
39801
|
-
name: semantic-metrics-modeling
|
|
39802
|
-
description: Builder policy for turning a granted datasource into published semantic tables and metrics. Governs goal agreement, FEP verification, persistent-task tracking, belief-state updates, and continuous refinement until acceptance evidence is met.
|
|
39803
|
-
---
|
|
39804
|
-
|
|
39805
|
-
# Semantic Metrics Modeling
|
|
39806
|
-
|
|
39807
|
-
You are the Semantic Metrics Builder. You turn physical datasource tables into reusable
|
|
39808
|
-
**semantic tables** and **business metrics** on a Metrics Server (\`/api/v1\`). Work is
|
|
39809
|
-
governed, observable, and continuously refined \u2014 never a one-shot guess.
|
|
39810
|
-
|
|
39811
|
-
## Goal Model
|
|
39812
|
-
|
|
39813
|
-
Before any exploration or publishing, agree with the user on:
|
|
39814
|
-
- **Real goal**: the business outcome (which metrics, for what decision), not just "make a table".
|
|
39815
|
-
- **Consumer**: who reads the result and how.
|
|
39816
|
-
- **Usable state**: observable conditions that make the published meta useful.
|
|
39817
|
-
- **Scope**: which datasource/tables, and what is explicitly out of scope.
|
|
39818
|
-
- **Acceptance evidence**: objective criteria (e.g. "metric \`sell_in_nes\` returns sane monthly
|
|
39819
|
-
totals for 2024") used to decide success.
|
|
39820
|
-
Do not guess material goals, consumers, or acceptance evidence.
|
|
39821
|
-
|
|
39822
|
-
**Vague requests** (e.g. "build the metric layer") \u2014 do not act and do not ask blind questions.
|
|
39823
|
-
First run cheap read-only observations (\`list_datasources\`, \`get_grants\`, \`list_tables\`,
|
|
39824
|
-
\`list_metrics\`) to see what is authorized and already published, then ask focused questions that
|
|
39825
|
-
carry that context and offer concrete options (which datasource/tables, which business questions,
|
|
39826
|
-
extend existing metrics or build new). Every clarification question must include enough context and
|
|
39827
|
-
options for the user to answer in one step. Only after the user picks a direction does the Goal
|
|
39828
|
-
Model become confirmable \u2014 record it, create the task, and proceed to the workflow.
|
|
39829
|
-
|
|
39830
|
-
## Target model and quality bar
|
|
39831
|
-
|
|
39832
|
-
Your goal is a specific, verifiable artifact, not "some tables and metrics".
|
|
39833
|
-
|
|
39834
|
-
**Target shape** \u2014 one delivery is:
|
|
39835
|
-
- a published \`table_view_detail\` meta per logical table, with every column tagged
|
|
39836
|
-
\`role\` (dimension | measure) and a business-readable \`label\`;
|
|
39837
|
-
- a \`metric_index\` + \`metric_detail\` pair per metric, using the SQL-free \`calculation\` DSL;
|
|
39838
|
-
- the set, taken together, answers the user's concrete business question.
|
|
39839
|
-
|
|
39840
|
-
**Publish gate (self-check every metric before create)** \u2014 if any fails, do **not** publish; go
|
|
39841
|
-
explore or ask the user:
|
|
39842
|
-
1. measure: an aggregation is chosen **and** its business meaning is confirmed (net/gross, currency, dedupe or not);
|
|
39843
|
-
2. dimension: has a business meaning and a grain (day/month/year/\u2026);
|
|
39844
|
-
3. \`displayName\`/\`label\` are business-readable;
|
|
39845
|
-
4. the metric answers one concrete question from the user's stated goal;
|
|
39846
|
-
5. a runtime \`query\` returns numbers consistent with the confirmed meaning.
|
|
39847
|
-
|
|
39848
|
-
**Intent gaps first** \u2014 before diving into exploration, list the inputs you still need to meet the
|
|
39849
|
-
quality bar (business meaning, grain, target metric list, table scope, consumer) and ask for them
|
|
39850
|
-
explicitly. Exploration and user questions are both driven by this target shape and quality bar:
|
|
39851
|
-
missing business meaning \u2192 ask; unclear field semantics \u2192 probe or ask; right shape but it does not
|
|
39852
|
-
answer the business question \u2192 do not publish.
|
|
39853
|
-
|
|
39854
|
-
## FEP Loop
|
|
39855
|
-
|
|
39856
|
-
Apply this loop to every step (explore, publish table, publish metric, verify):
|
|
39857
|
-
**OBSERVE \u2192 HYPOTHESIZE \u2192 ACT \u2192 VERIFY \u2192 DECIDE \u2192 RECONCILE**
|
|
39858
|
-
|
|
39859
|
-
- **Observe**: current state, grants, published meta, and decision-relevant uncertainty.
|
|
39860
|
-
- **Hypothesize**: what evidence should appear if your model is right, and how each outcome changes the decision.
|
|
39861
|
-
- **Act**: one proportional action \u2014 no more than necessary.
|
|
39862
|
-
- **Verify**: compare the observed result (e.g. a runtime \`query\`) against the prediction.
|
|
39863
|
-
- **Decide**: classify as **RETAIN** (confirmed), **REVERT** (rejected), or **INCONCLUSIVE**.
|
|
39864
|
-
- **Reconcile**: update the belief state and plan, then repeat while decision-relevant action remains.
|
|
39865
|
-
|
|
39866
|
-
Renew user approval when a foundational assumption or the goal changes.
|
|
39867
|
-
|
|
39868
|
-
## Task Policy
|
|
39869
|
-
|
|
39870
|
-
Use persistent TaskItems as your planning surface. Do not use \`write_todos\`. Create a child task
|
|
39871
|
-
only for an independently verifiable outcome (e.g. "publish table meta for \`hankel_distr_sell_in\`").
|
|
39872
|
-
Exploration queries and tool calls are activities inside the active task. See the
|
|
39873
|
-
\`task-definition\` skill for \`manage_task\` operation details.
|
|
39874
|
-
|
|
39875
|
-
## Belief State
|
|
39876
|
-
|
|
39877
|
-
Record your modeling beliefs in the active task's description under a \`## Belief State\` section as
|
|
39878
|
-
a Markdown table:
|
|
39879
|
-
|
|
39880
|
-
\`\`\`
|
|
39881
|
-
| Belief Key | Probability | Target | Basis |
|
|
39882
|
-
|---|---|---|---|
|
|
39883
|
-
| sell-in-nes-source-table | 70% | 100% | column \`nes\` probed as numeric measure in grant |
|
|
39884
|
-
\`\`\`
|
|
39885
|
-
|
|
39886
|
-
Rules: belief keys are lowercase kebab-case; probability/target are percentages 0\u2013100% that
|
|
39887
|
-
represent evidence support, not calibrated probability. Update this section each FEP reconcile so
|
|
39888
|
-
the task always reflects the current evidence.
|
|
39889
|
-
|
|
39890
|
-
## Workflow
|
|
39891
|
-
|
|
39892
|
-
1. **Pick the datasource.** \`metrics_datasource_tool\` action \`list_datasources\`, or the preset
|
|
39893
|
-
\`runConfig.metricsDataSource\` (\`serverKey\`\u2192connectionKey, \`datasourceId\`).
|
|
39894
|
-
2. **Read the boundary.** \`get_grants\` \u2192 note the allowed schema + table pattern. Never probe outside it.
|
|
39895
|
-
3. **Explore within the grant.** \`query\` with read-only SQL. Use the templates in
|
|
39896
|
-
\`references/metadata-sql.md\`; if the user supplied schema docs or sample files, read them first
|
|
39897
|
-
via filesystem to reduce querying.
|
|
39898
|
-
4. **Propose the model.** Present the table columns (with \`role: dimension | measure\`) and the
|
|
39899
|
-
metrics (aggregate/derived) for approval before publishing.
|
|
39900
|
-
5. **Publish the semantic table.** \`metrics_meta_tool\` \`create_table\`.
|
|
39901
|
-
6. **Publish the metric.** \`metrics_meta_tool\` \`create_metric\` \u2014 \`metric_index\` then \`metric_detail\`
|
|
39902
|
-
using the SQL-free \`calculation\` DSL.
|
|
39903
|
-
7. **Verify.** \`metrics_runtime_tool\` \`get_meta\`, then \`query\` the metric against acceptance evidence.
|
|
39904
|
-
|
|
39905
|
-
## 1. Explore
|
|
39906
|
-
|
|
39907
|
-
Read \`table-grants\`, then probe with \`query\`. SQL is validated read-only by the client and the
|
|
39908
|
-
server enforces the grant; un-granted tables return \`TABLE_NOT_GRANTED\`. Prefer the
|
|
39909
|
-
\`references/metadata-sql.md\` templates because dialect varies (PostgreSQL / SQL Server / HANA).
|
|
39910
|
-
If the user provides a data dictionary or sample data file, read it with filesystem and reconcile it
|
|
39911
|
-
against the probed columns.
|
|
39912
|
-
|
|
39913
|
-
## Unclear field semantics
|
|
39914
|
-
|
|
39915
|
-
A probed column name may not reveal its business meaning (e.g. whether \`nes\` is a net amount to
|
|
39916
|
-
sum, a rate to average, or an enum to filter). Publishing meta on a misunderstood field pollutes
|
|
39917
|
-
the runtime and every downstream metric that depends on it, and delete is not available. Treat this
|
|
39918
|
-
as FEP **INCONCLUSIVE** \u2014 never guess, and never publish on an unverified guess.
|
|
39919
|
-
|
|
39920
|
-
Resolve in order of increasing cost:
|
|
39921
|
-
1. **Probe sample values and distribution** (\`query\`, templates in \`references/metadata-sql.md\`):
|
|
39922
|
-
- numbers in (0,1) or clustered near 100 \u2192 likely a ratio/percentage \u2192 dimension or \`avg\`, rarely \`sum\`;
|
|
39923
|
-
- large additive amounts (currency, counts) \u2192 measure with \`sum\`;
|
|
39924
|
-
- small enumerations (year 2023/2024, 0/1 flags, codes) \u2192 dimension.
|
|
39925
|
-
The share of zeros/negatives and the value scale usually disambiguate semantics.
|
|
39926
|
-
2. **Read user-provided docs**: if the user supplied a data dictionary or sample file, read it via
|
|
39927
|
-
filesystem and reconcile it against the probed columns.
|
|
39928
|
-
3. **Cross-field correlation**: compare the unclear field with fields whose semantics are confirmed.
|
|
39929
|
-
|
|
39930
|
-
If evidence is still INCONCLUSIVE:
|
|
39931
|
-
- Do **not** publish meta that depends on the unclear field.
|
|
39932
|
-
- List the field with its candidate interpretations in the **Propose the model** step and ask the
|
|
39933
|
-
user to confirm its semantics (role, value meaning, net/gross) via ask_user_to_clarify. The user
|
|
39934
|
-
does not need to see the table \u2014 your probed schema, samples, and candidates are enough.
|
|
39935
|
-
- Record a low-probability belief entry (e.g.
|
|
39936
|
-
\`| sales-nes-semantics | 40% | 100% | user must confirm role / net amount |\`) so verify/refine can
|
|
39937
|
-
revisit it later instead of assuming it is settled.
|
|
39938
|
-
|
|
39939
|
-
## 2. Publish table meta (\`create_table\`)
|
|
39940
|
-
|
|
39941
|
-
Publish the authoritative shape below (objectType \`table_view_detail\`, with an EXACT accessGrant):
|
|
39942
|
-
|
|
39943
|
-
\`\`\`json
|
|
39944
|
-
{
|
|
39945
|
-
"objectType": "table_view_detail",
|
|
39946
|
-
"objectKey": "hankel_view_sales_summary",
|
|
39947
|
-
"status": 1,
|
|
39948
|
-
"payload": {
|
|
39949
|
-
"schemaName": "public",
|
|
39950
|
-
"tableName": "hankel_view_sales_summary",
|
|
39951
|
-
"displayName": "Hankel Sales Summary",
|
|
39952
|
-
"docType": "Sales Summary",
|
|
39953
|
-
"docTypeEn": "Sales Summary",
|
|
39954
|
-
"shortDesc": "Sales-level progress summary.",
|
|
39955
|
-
"grain": "canonical_sales_name",
|
|
39956
|
-
"sourceSystem": "Hankel Run for Gold",
|
|
39957
|
-
"sourceTables": ["hankel_project_opportunity_lines", "hankel_new_order_lines"],
|
|
39958
|
-
"columns": [
|
|
39959
|
-
{ "name": "canonical_sales_name", "label": "Canonical Sales Name", "type": "string", "role": "dimension", "description": "Standardized sales name used for grouping." },
|
|
39960
|
-
{ "name": "nes", "label": "NES", "type": "number", "role": "measure", "description": "Net external sales amount." },
|
|
39961
|
-
{ "name": "report_cutoff_date", "label": "Report Cutoff Date", "type": "date", "role": "time", "description": "Cutoff date of the report snapshot." }
|
|
39962
|
-
]
|
|
39963
|
-
},
|
|
39964
|
-
"accessGrant": {
|
|
39965
|
-
"schemaName": "public",
|
|
39966
|
-
"tablePattern": "hankel_view_sales_summary",
|
|
39967
|
-
"patternType": "EXACT",
|
|
39968
|
-
"caseSensitive": false,
|
|
39969
|
-
"status": 1
|
|
39970
|
-
}
|
|
39971
|
-
}
|
|
39972
|
-
\`\`\`
|
|
39973
|
-
|
|
39974
|
-
Design rules:
|
|
39975
|
-
- \`objectKey\` is stable and unique per datasource (the view/table key).
|
|
39976
|
-
- \`columns[].role\` has THREE values: \`dimension\` (grouping/filtering), \`measure\` (aggregated numbers), \`time\` (the report cutoff/snapshot date used by default_time_context).
|
|
39977
|
-
- Give every column a business \`description\`.
|
|
39978
|
-
- Lineage fields (\`docType\`, \`shortDesc\`, \`grain\`, \`sourceSystem\`, \`sourceTables\`) make the asset findable and trustworthy \u2014 fill them from exploration evidence.
|
|
39979
|
-
- Runtime table publication uses \`patternType: "EXACT"\` (\`PREFIX\` is only for datasource-level exploration scopes).
|
|
39980
|
-
- For each semantic table also publish the identity twin: the same body with \`objectType: "table_catalog"\` and the same \`objectKey\` (same or richer payload).
|
|
39981
|
-
|
|
39982
|
-
## 3. Publish metric meta (\`create_metric\`)
|
|
39983
|
-
|
|
39984
|
-
Two steps for the same \`objectKey\`.
|
|
39985
|
-
|
|
39986
|
-
### 3a. Metric index (for lists/search)
|
|
39987
|
-
|
|
39988
|
-
\`\`\`json
|
|
39989
|
-
{
|
|
39990
|
-
"objectType": "metric_index",
|
|
39991
|
-
"objectKey": "sell_in_nes",
|
|
39992
|
-
"status": 1,
|
|
39993
|
-
"payload": {
|
|
39994
|
-
"metric_name": "sell_in_nes",
|
|
39995
|
-
"display_name": "Sell-in NES",
|
|
39996
|
-
"domain": "sales",
|
|
39997
|
-
"short_desc": "Net external sales amount from distributor sell-in rows.",
|
|
39998
|
-
"search_keywords": ["sell in", "nes", "net external sales"],
|
|
39999
|
-
"source_type": "cdp_postgres",
|
|
40000
|
-
"source": { "table_view": "public.hankel_distr_sell_in" }
|
|
40001
|
-
}
|
|
40002
|
-
}
|
|
40003
|
-
\`\`\`
|
|
40004
|
-
|
|
40005
|
-
\`search_keywords\` drive metric retrieval for natural-language questions \u2014 include business synonyms.
|
|
40006
|
-
|
|
40007
|
-
### 3b. Metric detail (the calculation)
|
|
40008
|
-
|
|
40009
|
-
IMPORTANT \u2014 runtime schema requirement: the Metrics Server query runtime only recognizes metrics
|
|
40010
|
-
published in the FULL runtime style below (the same shape as existing working metrics, with
|
|
40011
|
-
snake_case fields like \`metric_name\`, \`source.table_view\`, \`supported_dimensions\` objects, and
|
|
40012
|
-
\`default_time_context\`). A minimal \`{name, sourceTable, calculation, dimensions}\` payload is
|
|
40013
|
-
accepted by the publish API but is NOT queryable \u2014 querying it returns 403 "not authorized".
|
|
40014
|
-
|
|
40015
|
-
Aggregate metric (full runtime style):
|
|
40016
|
-
|
|
40017
|
-
\`\`\`json
|
|
40018
|
-
{
|
|
40019
|
-
"objectType": "metric_detail",
|
|
40020
|
-
"objectKey": "sell_in_nes",
|
|
40021
|
-
"status": 1,
|
|
40022
|
-
"payload": {
|
|
40023
|
-
"metric_name": "sell_in_nes",
|
|
40024
|
-
"display_name": "Sell-in NES",
|
|
40025
|
-
"domain": "sales",
|
|
40026
|
-
"description": "Net external sales amount from distributor sell-in rows.",
|
|
40027
|
-
"data_type": "numeric",
|
|
40028
|
-
"format": "currency",
|
|
40029
|
-
"source_type": "cdp_postgres",
|
|
40030
|
-
"source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
|
|
40031
|
-
"calculation": { "type": "aggregate", "aggregation": "sum", "measure": "nes" },
|
|
40032
|
-
"supported_dimensions": [
|
|
40033
|
-
{ "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" },
|
|
40034
|
-
{ "dim_id": "sales_team", "field_name": "sales_team", "label": "Sales Team", "data_type": "string" }
|
|
40035
|
-
],
|
|
40036
|
-
"default_time_context": {
|
|
40037
|
-
"time_dimension": "posting_date",
|
|
40038
|
-
"label": "Posting date",
|
|
40039
|
-
"granularity": "month",
|
|
40040
|
-
"window": "YTD",
|
|
40041
|
-
"supported_grains": ["month", "year"]
|
|
40042
|
-
},
|
|
40043
|
-
"ai_agent_context": {
|
|
40044
|
-
"polarity": "positive",
|
|
40045
|
-
"synonyms": ["sell in", "nes", "net external sales"],
|
|
40046
|
-
"human_readable_explanation": "Higher sell-in NES means more goods purchased from the distributor."
|
|
40047
|
-
}
|
|
40048
|
-
}
|
|
40049
|
-
}
|
|
40050
|
-
\`\`\`
|
|
40051
|
-
|
|
40052
|
-
Derived ratio metric (references two aggregate metrics):
|
|
40053
|
-
|
|
40054
|
-
\`\`\`json
|
|
40055
|
-
{
|
|
40056
|
-
"objectType": "metric_detail",
|
|
40057
|
-
"objectKey": "gross_margin_rate",
|
|
40058
|
-
"status": 1,
|
|
40059
|
-
"payload": {
|
|
40060
|
-
"metric_name": "gross_margin_rate",
|
|
40061
|
-
"display_name": "Gross Margin Rate",
|
|
40062
|
-
"description": "Gross margin divided by sell-in NES.",
|
|
40063
|
-
"domain": "sales",
|
|
40064
|
-
"data_type": "numeric",
|
|
40065
|
-
"format": "percent",
|
|
40066
|
-
"source_type": "cdp_postgres",
|
|
40067
|
-
"source": { "table_view": "public.hankel_distr_sell_in", "base_filters": [] },
|
|
40068
|
-
"calculation": { "type": "derived", "operator": "ratio", "numerator": "gross_margin", "denominator": "sell_in_nes" },
|
|
40069
|
-
"supported_dimensions": [
|
|
40070
|
-
{ "dim_id": "posting_year", "field_name": "posting_year", "label": "Posting Year", "data_type": "number" }
|
|
40071
|
-
],
|
|
40072
|
-
"default_time_context": { "time_dimension": "posting_date", "granularity": "month", "supported_grains": ["month", "year"] }
|
|
40073
|
-
}
|
|
40074
|
-
}
|
|
40075
|
-
\`\`\`
|
|
40076
|
-
|
|
40077
|
-
Design rules:
|
|
40078
|
-
- \`objectKey\` unique per datasource (index and detail share it).
|
|
40079
|
-
- \`payload.metric_name\` must equal \`objectKey\`.
|
|
40080
|
-
- \`source.table_view\` must be schema-qualified and match the published table meta's physical table.
|
|
40081
|
-
- \`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.
|
|
40082
|
-
- \`calculation.type: "aggregate"\` = one measure + aggregation (sum/avg/count/min/max/count_distinct).
|
|
40083
|
-
- \`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.
|
|
40084
|
-
- \`default_time_context\` (\`time_dimension\` + \`granularity\` + \`supported_grains\`, optionally \`window\`) is required by the query runtime; its \`time_dimension\` must appear in supported_dimensions.
|
|
40085
|
-
- \`ai_agent_context\` (\`polarity\`, \`synonyms\`, \`human_readable_explanation\`) improves natural-language metric retrieval \u2014 always provide it.
|
|
40086
|
-
- 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\`.
|
|
40087
|
-
- Do not inline raw SQL for new DB-backed metrics (complex logic belongs in a view).
|
|
40088
|
-
- Use \`update_metric\` / \`update_table\` to correct mistakes; no removal actions are exposed.
|
|
40089
|
-
|
|
40090
|
-
## 4. Verify and refine
|
|
40091
|
-
|
|
40092
|
-
- \`get_meta\` \u2192 confirm the table and metric are visible.
|
|
40093
|
-
- \`query\` the metric against the acceptance evidence. On failure, apply the FEP reconcile: update the
|
|
40094
|
-
\`## Belief State\`, fix the meta, and retry \u2014 until acceptance evidence is met.
|
|
40095
|
-
|
|
40096
|
-
## Troubleshooting
|
|
40097
|
-
|
|
40098
|
-
| Symptom | Cause / fix |
|
|
40099
|
-
|---|---|
|
|
40100
|
-
| \`TABLE_NOT_GRANTED\` | SQL referenced a table outside the tenant grant; pick an in-grant table |
|
|
40101
|
-
| metric create fails: sourceTable missing | publish the table meta first |
|
|
40102
|
-
| metric create fails: unknown dimension | publish the dimension column with \`role: dimension\` |
|
|
40103
|
-
| derived metric create fails | numerator/denominator metrics don't exist yet \u2014 publish them first |
|
|
40104
|
-
| datasource \`query\` rejected | SQL was not read-only (SELECT/WITH only) or multi-statement |
|
|
40105
|
-
| \`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 |
|
|
40106
|
-
|
|
40107
|
-
## Safety
|
|
40108
|
-
|
|
40109
|
-
- Only query tables that match the tenant's \`table-grants\`.
|
|
40110
|
-
- Never return a full physical-table inventory or reveal whether an un-granted table exists.
|
|
40111
|
-
- SQL is validated read-only; let the server reject anything outside that.
|
|
40112
|
-
`;
|
|
40113
|
-
var resources = {
|
|
40114
|
-
"references/metadata-sql.md": {
|
|
40115
|
-
content: `# Datasource exploration SQL templates (read-only)
|
|
40116
|
-
|
|
40117
|
-
Pick the block matching the server's database. These run through the datasource \`query\` action;
|
|
40118
|
-
the SQL is validated read-only.
|
|
40119
|
-
|
|
40120
|
-
## PostgreSQL
|
|
40121
|
-
- 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\`
|
|
40122
|
-
- Columns: \`select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position\`
|
|
40123
|
-
- Sample: \`select * from :schemaName.:tableName limit :maxRows\` \u2014 pass a concrete table, not a bound param, if the server does not support binding identifiers.
|
|
40124
|
-
|
|
40125
|
-
## SQL Server
|
|
40126
|
-
- Tables: \`select table_schema, table_name from information_schema.tables order by table_schema, table_name\`
|
|
40127
|
-
- Columns: \`select column_name, data_type from information_schema.columns where table_schema = :schemaName and table_name = :tableName order by ordinal_position\`
|
|
40128
|
-
|
|
40129
|
-
## HANA
|
|
40130
|
-
- Tables: \`select schema_name, table_name from sys.tables where schema_name = :schemaName order by table_name\`
|
|
40131
|
-
- Columns: \`select column_name, data_type_name from table_columns where schema_name = :schemaName and table_name = :tableName order by position\`
|
|
40132
|
-
|
|
40133
|
-
## Value distribution (any dialect)
|
|
40134
|
-
\`select <dim>, count(*) as row_count from <table> group by <dim> order by row_count desc limit :maxRows\`
|
|
40135
|
-
`
|
|
40136
|
-
},
|
|
40137
|
-
"examples/table-meta.json": {
|
|
40138
|
-
content: `{
|
|
40139
|
-
"objectType": "table_view_detail",
|
|
40140
|
-
"objectKey": "hankel_distr_sell_in",
|
|
40141
|
-
"status": 1,
|
|
40142
|
-
"payload": {
|
|
40143
|
-
"schemaName": "public",
|
|
40144
|
-
"tableName": "hankel_distr_sell_in",
|
|
40145
|
-
"displayName": "Hankel Distributor Sell In",
|
|
40146
|
-
"description": "Distributor sell-in transaction rows for the Hankel tenant.",
|
|
40147
|
-
"columns": [
|
|
40148
|
-
{ "name": "posting_year", "label": "Posting Year", "type": "number", "role": "dimension" },
|
|
40149
|
-
{ "name": "posting_month", "label": "Posting Month", "type": "number", "role": "dimension" },
|
|
40150
|
-
{ "name": "sales_team", "label": "Sales Team", "type": "string", "role": "dimension" },
|
|
40151
|
-
{ "name": "region", "label": "Region", "type": "string", "role": "dimension" },
|
|
40152
|
-
{ "name": "nes", "label": "Net External Sales", "type": "number", "role": "measure" },
|
|
40153
|
-
{ "name": "gross_margin", "label": "Gross Margin", "type": "number", "role": "measure" }
|
|
40154
|
-
]
|
|
40155
|
-
}
|
|
40156
|
-
}
|
|
40157
|
-
`
|
|
40158
|
-
},
|
|
40159
|
-
"examples/metric-aggregate.json": {
|
|
40160
|
-
content: `{
|
|
40161
|
-
"objectType": "metric_detail",
|
|
40162
|
-
"objectKey": "hankel_sell_in_nes",
|
|
40163
|
-
"status": 1,
|
|
40164
|
-
"payload": {
|
|
40165
|
-
"name": "hankel_sell_in_nes",
|
|
40166
|
-
"displayName": "Sell-in NES",
|
|
40167
|
-
"description": "Net external sales amount from distributor sell-in rows.",
|
|
40168
|
-
"sourceTable": "hankel_distr_sell_in",
|
|
40169
|
-
"calculation": { "type": "aggregate", "aggregation": "sum", "measure": "nes" },
|
|
40170
|
-
"dimensions": ["posting_year", "posting_month", "sales_team", "region"]
|
|
40171
|
-
}
|
|
40172
|
-
}
|
|
40173
|
-
`
|
|
40174
|
-
},
|
|
40175
|
-
"examples/metric-derived.json": {
|
|
40176
|
-
content: `{
|
|
40177
|
-
"objectType": "metric_detail",
|
|
40178
|
-
"objectKey": "hankel_gross_margin_rate",
|
|
40179
|
-
"status": 1,
|
|
40180
|
-
"payload": {
|
|
40181
|
-
"name": "hankel_gross_margin_rate",
|
|
40182
|
-
"displayName": "Gross Margin Rate",
|
|
40183
|
-
"description": "Gross margin divided by sell-in NES.",
|
|
40184
|
-
"sourceTable": "hankel_distr_sell_in",
|
|
40185
|
-
"calculation": {
|
|
40186
|
-
"type": "derived",
|
|
40187
|
-
"operator": "ratio",
|
|
40188
|
-
"numerator": "hankel_gross_margin",
|
|
40189
|
-
"denominator": "hankel_sell_in_nes"
|
|
40190
|
-
},
|
|
40191
|
-
"dimensions": ["posting_year", "sales_team", "region"]
|
|
40192
|
-
}
|
|
40193
|
-
}
|
|
40194
|
-
`
|
|
40195
|
-
}
|
|
40196
|
-
};
|
|
40197
|
-
var SEMANTIC_METRICS_MODELING_SKILL = {
|
|
40198
|
-
version: "1.0.0",
|
|
40199
|
-
content: CONTENT,
|
|
40200
|
-
resources
|
|
40201
|
-
};
|
|
40202
|
-
|
|
40203
|
-
// src/middlewares/semanticMetricsBuilderPrompt.ts
|
|
40204
|
-
var SEMANTIC_METRICS_BUILDER_PROMPT = `You are the Semantic Metrics Builder.
|
|
40205
|
-
|
|
40206
|
-
CRITICAL FIRST ACTION: Before any response or other action, call the \`skill\`
|
|
40207
|
-
tool with skill_name: "semantic-metrics-modeling" to load semantic-metrics-modeling and follow it.
|
|
40208
|
-
Never announce the skill load. If it fails, retry once, then stop and explicitly
|
|
40209
|
-
report that the required Semantic Metrics Builder skill could not be loaded.`;
|
|
40210
|
-
|
|
40211
|
-
// src/middlewares/semanticMetricsMiddleware.ts
|
|
40212
|
-
import { AgentType as AgentType8 } from "@axiom-lattice/protocols";
|
|
40213
|
-
function createSemanticMetricsMiddleware(config) {
|
|
40214
|
-
const connections = config.connections ?? [];
|
|
40215
|
-
const connectAll = config.connectAll === true;
|
|
40216
|
-
const selector = { connectionType: "semantic-metrics", connections, connectAll };
|
|
40217
|
-
return createMiddleware20({
|
|
40218
|
-
name: "SemanticMetrics",
|
|
40219
|
-
contextSchema,
|
|
40220
|
-
tools: [
|
|
40221
|
-
createMetricsDatasourceTool(selector),
|
|
40222
|
-
createMetricsMetaTool(selector),
|
|
40223
|
-
createMetricsRuntimeTool(selector)
|
|
40224
|
-
]
|
|
40225
|
-
});
|
|
40226
|
-
}
|
|
40227
|
-
function buildConnectionHeaders(config) {
|
|
40228
|
-
const headers = {
|
|
40229
|
-
Accept: "application/json",
|
|
40230
|
-
...config.headers !== void 0 && config.headers !== null ? config.headers : {}
|
|
40231
|
-
};
|
|
40232
|
-
if (config.apiKey) headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
40233
|
-
return headers;
|
|
40234
|
-
}
|
|
40235
|
-
function resolveBaseUrl(config) {
|
|
40236
|
-
const serverUrl = config.serverUrl;
|
|
40237
|
-
if (!serverUrl) {
|
|
40238
|
-
throw new Error("serverUrl is required");
|
|
40239
|
-
}
|
|
40240
|
-
return serverUrl.replace(/\/$/, "");
|
|
40241
|
-
}
|
|
40242
|
-
var semanticMetricsPlugin = {
|
|
40243
|
-
meta: {
|
|
40244
|
-
type: "semantic-metrics",
|
|
40245
|
-
category: "data",
|
|
40246
|
-
capabilityBundleEligible: true,
|
|
40247
|
-
openExpose: [
|
|
40248
|
-
// Query-only surface: no writes reach either tool (SQL is read-only).
|
|
40249
|
-
{ name: "metrics_datasource_tool", readOnly: true },
|
|
40250
|
-
{ name: "metrics_runtime_tool", readOnly: true }
|
|
40251
|
-
],
|
|
40252
|
-
name: "Semantic Metrics",
|
|
40253
|
-
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.",
|
|
40254
|
-
version: "1.0.0",
|
|
40255
|
-
tools: [
|
|
40256
|
-
{ name: "metrics_datasource_tool", description: "Explore datasource structure within the tenant's granted scope" },
|
|
40257
|
-
{ name: "metrics_meta_tool", description: "Publish and maintain runtime semantic tables and metrics" },
|
|
40258
|
-
{ name: "metrics_runtime_tool", description: "Read runtime meta and execute semantic metric queries" }
|
|
40259
|
-
],
|
|
40260
|
-
configSchema: {
|
|
40261
|
-
type: "object",
|
|
40262
|
-
title: "Semantic Metrics Configuration",
|
|
40263
|
-
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).",
|
|
40264
|
-
properties: {
|
|
40265
|
-
connections: {
|
|
40266
|
-
type: "array",
|
|
40267
|
-
title: "Connections",
|
|
40268
|
-
items: { type: "string" },
|
|
40269
|
-
widget: "connectionSelect"
|
|
40270
|
-
},
|
|
40271
|
-
connectAll: {
|
|
40272
|
-
type: "boolean",
|
|
40273
|
-
title: "Connect All",
|
|
40274
|
-
default: false,
|
|
40275
|
-
widget: "switch"
|
|
40276
|
-
}
|
|
40277
|
-
}
|
|
40278
|
-
},
|
|
40279
|
-
defaultConfig: { connections: [], connectAll: false }
|
|
40280
|
-
},
|
|
40281
|
-
connection: {
|
|
40282
|
-
// PluginConnectionFieldSchema.type supports only string/number/boolean/password,
|
|
40283
|
-
// so headers is NOT a form field; the V2 client still reads config.headers at runtime.
|
|
40284
|
-
fields: [
|
|
40285
|
-
{ key: "serverUrl", type: "string", title: "Metrics Server Base URL (include /api/v1)", required: true },
|
|
40286
|
-
{ key: "apiKey", type: "password", title: "API Key (optional)" }
|
|
40287
|
-
],
|
|
40288
|
-
test: async (config) => {
|
|
40289
|
-
try {
|
|
40290
|
-
const baseUrl = resolveBaseUrl(config);
|
|
40291
|
-
const res = await fetch(`${baseUrl}/datasources`, {
|
|
40292
|
-
headers: buildConnectionHeaders(config)
|
|
40293
|
-
});
|
|
40294
|
-
const text = await res.text().catch(() => "");
|
|
40295
|
-
let ok = res.ok;
|
|
40296
|
-
let detail = "";
|
|
40297
|
-
try {
|
|
40298
|
-
const parsed = JSON.parse(text);
|
|
40299
|
-
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
40300
|
-
const code = parsed.code;
|
|
40301
|
-
if (typeof code === "number") {
|
|
40302
|
-
ok = res.ok && code === 200;
|
|
40303
|
-
if (!ok) detail = ` (${parsed.message ?? code})`;
|
|
40304
|
-
}
|
|
40305
|
-
}
|
|
40306
|
-
} catch {
|
|
40307
|
-
}
|
|
40308
|
-
return {
|
|
40309
|
-
ok,
|
|
40310
|
-
message: ok ? `Reachable at ${baseUrl}` : `HTTP ${res.status}${detail}`
|
|
40311
|
-
};
|
|
40312
|
-
} catch (err) {
|
|
40313
|
-
return {
|
|
40314
|
-
ok: false,
|
|
40315
|
-
message: `Cannot connect: ${err instanceof Error ? err.message : String(err)}`
|
|
40316
|
-
};
|
|
40317
|
-
}
|
|
40318
|
-
},
|
|
40319
|
-
discover: async (config) => {
|
|
40320
|
-
try {
|
|
40321
|
-
const baseUrl = resolveBaseUrl(config);
|
|
40322
|
-
const res = await fetch(`${baseUrl}/datasources`, {
|
|
40323
|
-
headers: buildConnectionHeaders(config)
|
|
40324
|
-
});
|
|
40325
|
-
const text = await res.text();
|
|
40326
|
-
if (!res.ok) {
|
|
40327
|
-
throw new Error(`HTTP ${res.status}${text ? `: ${text.slice(0, 200)}` : ""}`);
|
|
40328
|
-
}
|
|
40329
|
-
const parsed = JSON.parse(text);
|
|
40330
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
40331
|
-
throw new Error("Metrics server returned an unexpected payload (expected a JSON envelope)");
|
|
40332
|
-
}
|
|
40333
|
-
const envelope = parsed;
|
|
40334
|
-
if (typeof envelope.code === "number" && envelope.code !== 200) {
|
|
40335
|
-
throw new Error(envelope.message || `API ${envelope.code}`);
|
|
40336
|
-
}
|
|
40337
|
-
const data = envelope.data;
|
|
40338
|
-
if (!Array.isArray(data)) {
|
|
40339
|
-
throw new Error("Metrics server returned an unexpected payload (expected a datasource array)");
|
|
40340
|
-
}
|
|
40341
|
-
return data.filter((d) => {
|
|
40342
|
-
if (d === null || typeof d !== "object") return false;
|
|
40343
|
-
const id = d.id;
|
|
40344
|
-
return id !== void 0 && id !== null && id !== "";
|
|
40345
|
-
}).map((item) => ({
|
|
40346
|
-
id: String(item.id),
|
|
40347
|
-
name: item.name ?? String(item.id)
|
|
40348
|
-
}));
|
|
40349
|
-
} catch (err) {
|
|
40350
|
-
throw new Error(
|
|
40351
|
-
`Cannot discover datasources: ${err instanceof Error ? err.message : String(err)}`
|
|
40352
|
-
);
|
|
40353
|
-
}
|
|
40354
|
-
}
|
|
40355
|
-
},
|
|
40356
|
-
skills: {
|
|
40357
|
-
"semantic-metrics-modeling": SEMANTIC_METRICS_MODELING_SKILL
|
|
40358
|
-
},
|
|
40359
|
-
agents: {
|
|
40360
|
-
"semantic-metrics-builder": {
|
|
40361
|
-
key: "semantic-metrics-builder",
|
|
40362
|
-
name: "Semantic Metrics Builder",
|
|
40363
|
-
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.",
|
|
40364
|
-
type: AgentType8.DEEP_AGENT,
|
|
40365
|
-
prompt: SEMANTIC_METRICS_BUILDER_PROMPT,
|
|
40366
|
-
middleware: [
|
|
40367
|
-
{
|
|
40368
|
-
id: "semantic-metrics",
|
|
40369
|
-
type: "semantic-metrics",
|
|
40370
|
-
name: "Semantic Metrics",
|
|
40371
|
-
description: "Explore datasources, publish table/meta metrics, query runtime",
|
|
40372
|
-
enabled: true,
|
|
40373
|
-
config: { connections: [], connectAll: true }
|
|
40374
|
-
},
|
|
40375
|
-
{
|
|
40376
|
-
id: "skill",
|
|
40377
|
-
type: "skill",
|
|
40378
|
-
name: "Skill",
|
|
40379
|
-
description: "Load the semantic-metrics-modeling policy and task-definition reference",
|
|
40380
|
-
enabled: true,
|
|
40381
|
-
config: { readAll: false, skills: ["semantic-metrics-modeling", "task-definition"] }
|
|
40382
|
-
},
|
|
40383
|
-
{
|
|
40384
|
-
id: "task",
|
|
40385
|
-
type: "task",
|
|
40386
|
-
name: "Task",
|
|
40387
|
-
description: "Persistent TaskItems as the planning surface; update Belief State in task descriptions",
|
|
40388
|
-
enabled: true,
|
|
40389
|
-
config: {}
|
|
40390
|
-
},
|
|
40391
|
-
{
|
|
40392
|
-
id: "ask_user_to_clarify",
|
|
40393
|
-
type: "ask_user_to_clarify",
|
|
40394
|
-
name: "Ask User",
|
|
40395
|
-
description: "Wait for user input at modeling approval gates",
|
|
40396
|
-
enabled: true,
|
|
40397
|
-
config: {}
|
|
40398
|
-
},
|
|
40399
|
-
{
|
|
40400
|
-
id: "filesystem",
|
|
40401
|
-
type: "filesystem",
|
|
40402
|
-
name: "Filesystem",
|
|
40403
|
-
description: "Read user-provided schema docs, data dictionaries, or sample data files",
|
|
40404
|
-
enabled: true,
|
|
40405
|
-
config: {}
|
|
40406
|
-
}
|
|
40407
|
-
]
|
|
40408
|
-
}
|
|
40409
|
-
},
|
|
40410
|
-
middleware: (config) => createSemanticMetricsMiddleware(config)
|
|
40411
|
-
};
|
|
40412
|
-
|
|
40413
|
-
// src/middlewares/collectionMiddleware.ts
|
|
40414
|
-
import { createMiddleware as createMiddleware21 } from "langchain";
|
|
40415
|
-
|
|
40416
|
-
// src/tool_lattice/collection/list_collections.ts
|
|
40417
|
-
import z60 from "zod";
|
|
40418
|
-
import { tool as tool54 } from "langchain";
|
|
40419
|
-
|
|
40420
39227
|
// src/tool_lattice/collection/utils.ts
|
|
40421
39228
|
function getEffectiveCollectionScope(exeConfig, staticScope) {
|
|
40422
39229
|
const runtimeConfig = getRuntimeCapabilityConfig(exeConfig, "collection");
|
|
@@ -40438,7 +39245,7 @@ var createListCollectionsTool = ({
|
|
|
40438
39245
|
collectionKeys,
|
|
40439
39246
|
connectAll
|
|
40440
39247
|
}) => {
|
|
40441
|
-
return
|
|
39248
|
+
return tool51(
|
|
40442
39249
|
async (_input, _exeConfig) => {
|
|
40443
39250
|
try {
|
|
40444
39251
|
const tenantId2 = _exeConfig?.configurable?.runConfig?.tenantId || "default";
|
|
@@ -40473,23 +39280,23 @@ var createListCollectionsTool = ({
|
|
|
40473
39280
|
{
|
|
40474
39281
|
name: "list_collections",
|
|
40475
39282
|
description: LIST_COLLECTIONS_DESCRIPTION,
|
|
40476
|
-
schema:
|
|
39283
|
+
schema: z57.object({})
|
|
40477
39284
|
}
|
|
40478
39285
|
);
|
|
40479
39286
|
};
|
|
40480
39287
|
|
|
40481
39288
|
// src/tool_lattice/collection/search_collection.ts
|
|
40482
|
-
import
|
|
40483
|
-
import { tool as
|
|
39289
|
+
import z58 from "zod";
|
|
39290
|
+
import { tool as tool52 } from "langchain";
|
|
40484
39291
|
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.`;
|
|
40485
|
-
var searchSchema =
|
|
40486
|
-
collection:
|
|
40487
|
-
query:
|
|
40488
|
-
filter:
|
|
40489
|
-
top_k:
|
|
39292
|
+
var searchSchema = z58.object({
|
|
39293
|
+
collection: z58.string().describe("The collection name to search in"),
|
|
39294
|
+
query: z58.string().describe("The search query text"),
|
|
39295
|
+
filter: z58.record(z58.unknown()).optional().describe("Metadata filter conditions"),
|
|
39296
|
+
top_k: z58.number().optional().default(5).describe("Number of results to return")
|
|
40490
39297
|
});
|
|
40491
39298
|
var createSearchCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => {
|
|
40492
|
-
return
|
|
39299
|
+
return tool52(
|
|
40493
39300
|
async (input, _exeConfig) => {
|
|
40494
39301
|
try {
|
|
40495
39302
|
const { collection, query, filter: filter2, top_k } = input;
|
|
@@ -40555,10 +39362,10 @@ var createSearchCollectionTool = (scope = { collectionKeys: [], connectAll: true
|
|
|
40555
39362
|
};
|
|
40556
39363
|
|
|
40557
39364
|
// src/tool_lattice/collection/get_collection.ts
|
|
40558
|
-
import
|
|
40559
|
-
import { tool as
|
|
39365
|
+
import z59 from "zod";
|
|
39366
|
+
import { tool as tool53 } from "langchain";
|
|
40560
39367
|
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.`;
|
|
40561
|
-
var createGetCollectionTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39368
|
+
var createGetCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => tool53(
|
|
40562
39369
|
async (input, _exeConfig) => {
|
|
40563
39370
|
try {
|
|
40564
39371
|
const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
|
|
@@ -40583,24 +39390,24 @@ Embedding: ${c.embeddingKey}${fieldsDesc}`;
|
|
|
40583
39390
|
return `Error: ${error.message}`;
|
|
40584
39391
|
}
|
|
40585
39392
|
},
|
|
40586
|
-
{ name: "get_collection", description: GET_COLLECTION_DESCRIPTION, schema:
|
|
39393
|
+
{ name: "get_collection", description: GET_COLLECTION_DESCRIPTION, schema: z59.object({ name: z59.string().describe("Collection name") }) }
|
|
40587
39394
|
);
|
|
40588
39395
|
|
|
40589
39396
|
// src/tool_lattice/collection/create_collection.ts
|
|
40590
|
-
import
|
|
40591
|
-
import { tool as
|
|
40592
|
-
var createSchema =
|
|
40593
|
-
name:
|
|
40594
|
-
label:
|
|
40595
|
-
embeddingKey:
|
|
40596
|
-
fields:
|
|
40597
|
-
key:
|
|
40598
|
-
type:
|
|
40599
|
-
enumValues:
|
|
40600
|
-
required:
|
|
39397
|
+
import z60 from "zod";
|
|
39398
|
+
import { tool as tool54 } from "langchain";
|
|
39399
|
+
var createSchema = z60.object({
|
|
39400
|
+
name: z60.string().describe("Collection name (lowercase, underscores only)"),
|
|
39401
|
+
label: z60.string().describe("Display name"),
|
|
39402
|
+
embeddingKey: z60.string().describe("Embedding model key"),
|
|
39403
|
+
fields: z60.array(z60.object({
|
|
39404
|
+
key: z60.string().describe("Field key name"),
|
|
39405
|
+
type: z60.enum(["string", "number", "enum"]).describe("Field data type"),
|
|
39406
|
+
enumValues: z60.array(z60.string()).optional().describe("Valid values for enum type"),
|
|
39407
|
+
required: z60.boolean().optional().default(false).describe("Whether field is required")
|
|
40601
39408
|
})).optional().describe("Custom field definitions for entries in this collection")
|
|
40602
39409
|
});
|
|
40603
|
-
var createCreateCollectionTool = (scope = {}) =>
|
|
39410
|
+
var createCreateCollectionTool = (scope = {}) => tool54(
|
|
40604
39411
|
async (input, _exeConfig) => {
|
|
40605
39412
|
try {
|
|
40606
39413
|
const tenantId2 = _exeConfig?.configurable?.runConfig?.tenantId || "default";
|
|
@@ -40626,20 +39433,20 @@ var createCreateCollectionTool = (scope = {}) => tool57(
|
|
|
40626
39433
|
);
|
|
40627
39434
|
|
|
40628
39435
|
// src/tool_lattice/collection/update_collection.ts
|
|
40629
|
-
import
|
|
40630
|
-
import { tool as
|
|
40631
|
-
var schema =
|
|
40632
|
-
name:
|
|
40633
|
-
label:
|
|
40634
|
-
embeddingKey:
|
|
40635
|
-
fields:
|
|
40636
|
-
key:
|
|
40637
|
-
type:
|
|
40638
|
-
enumValues:
|
|
40639
|
-
required:
|
|
39436
|
+
import z61 from "zod";
|
|
39437
|
+
import { tool as tool55 } from "langchain";
|
|
39438
|
+
var schema = z61.object({
|
|
39439
|
+
name: z61.string().describe("Collection name"),
|
|
39440
|
+
label: z61.string().optional().describe("New display name"),
|
|
39441
|
+
embeddingKey: z61.string().optional().describe("New embedding model key"),
|
|
39442
|
+
fields: z61.array(z61.object({
|
|
39443
|
+
key: z61.string().describe("Field key name"),
|
|
39444
|
+
type: z61.enum(["string", "number", "enum"]).describe("Field data type"),
|
|
39445
|
+
enumValues: z61.array(z61.string()).optional().describe("Valid values for enum type"),
|
|
39446
|
+
required: z61.boolean().optional().default(false).describe("Whether field is required")
|
|
40640
39447
|
})).optional().describe("Custom field definitions for entries (replaces existing schema)")
|
|
40641
39448
|
});
|
|
40642
|
-
var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39449
|
+
var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => tool55(
|
|
40643
39450
|
async (input, _exeConfig) => {
|
|
40644
39451
|
try {
|
|
40645
39452
|
const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
|
|
@@ -40660,9 +39467,9 @@ var createUpdateCollectionTool = (scope = { collectionKeys: [], connectAll: true
|
|
|
40660
39467
|
);
|
|
40661
39468
|
|
|
40662
39469
|
// src/tool_lattice/collection/delete_collection.ts
|
|
40663
|
-
import
|
|
40664
|
-
import { tool as
|
|
40665
|
-
var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39470
|
+
import z62 from "zod";
|
|
39471
|
+
import { tool as tool56 } from "langchain";
|
|
39472
|
+
var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true }) => tool56(
|
|
40666
39473
|
async (input, _exeConfig) => {
|
|
40667
39474
|
try {
|
|
40668
39475
|
const scopeError = validateCollectionScope(input.name, _exeConfig, scope);
|
|
@@ -40674,19 +39481,19 @@ var createDeleteCollectionTool = (scope = { collectionKeys: [], connectAll: true
|
|
|
40674
39481
|
return `Error: ${e.message}`;
|
|
40675
39482
|
}
|
|
40676
39483
|
},
|
|
40677
|
-
{ name: "delete_collection", description: `Delete a collection and all its entries. This cannot be undone.`, schema:
|
|
39484
|
+
{ name: "delete_collection", description: `Delete a collection and all its entries. This cannot be undone.`, schema: z62.object({ name: z62.string().describe("Collection name") }) }
|
|
40678
39485
|
);
|
|
40679
39486
|
|
|
40680
39487
|
// src/tool_lattice/collection/list_entries.ts
|
|
40681
|
-
import
|
|
40682
|
-
import { tool as
|
|
40683
|
-
var schema2 =
|
|
40684
|
-
collection:
|
|
39488
|
+
import z63 from "zod";
|
|
39489
|
+
import { tool as tool57 } from "langchain";
|
|
39490
|
+
var schema2 = z63.object({
|
|
39491
|
+
collection: z63.string().describe("Collection name")
|
|
40685
39492
|
});
|
|
40686
39493
|
function buildKey2(tenantId2, name) {
|
|
40687
39494
|
return `${tenantId2}:${name}`;
|
|
40688
39495
|
}
|
|
40689
|
-
var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39496
|
+
var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) => tool57(
|
|
40690
39497
|
async (input, _exeConfig) => {
|
|
40691
39498
|
try {
|
|
40692
39499
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -40715,19 +39522,19 @@ var createListEntriesTool = (scope = { collectionKeys: [], connectAll: true }) =
|
|
|
40715
39522
|
);
|
|
40716
39523
|
|
|
40717
39524
|
// src/tool_lattice/collection/add_entry.ts
|
|
40718
|
-
import
|
|
40719
|
-
import { tool as
|
|
39525
|
+
import z64 from "zod";
|
|
39526
|
+
import { tool as tool58 } from "langchain";
|
|
40720
39527
|
import { Document } from "@langchain/core/documents";
|
|
40721
39528
|
import { v4 as uuidv48 } from "uuid";
|
|
40722
|
-
var schema3 =
|
|
40723
|
-
collection:
|
|
40724
|
-
content:
|
|
40725
|
-
metadata:
|
|
39529
|
+
var schema3 = z64.object({
|
|
39530
|
+
collection: z64.string().describe("Collection name"),
|
|
39531
|
+
content: z64.string().describe("Entry content text"),
|
|
39532
|
+
metadata: z64.record(z64.unknown()).optional().describe("Metadata fields matching the collection schema")
|
|
40726
39533
|
});
|
|
40727
39534
|
function key2(t, n) {
|
|
40728
39535
|
return `${t}:${n}`;
|
|
40729
39536
|
}
|
|
40730
|
-
var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39537
|
+
var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) => tool58(
|
|
40731
39538
|
async (input, _exeConfig) => {
|
|
40732
39539
|
try {
|
|
40733
39540
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -40759,18 +39566,18 @@ var createAddEntryTool = (scope = { collectionKeys: [], connectAll: true }) => t
|
|
|
40759
39566
|
);
|
|
40760
39567
|
|
|
40761
39568
|
// src/tool_lattice/collection/update_entry.ts
|
|
40762
|
-
import
|
|
40763
|
-
import { tool as
|
|
40764
|
-
var schema4 =
|
|
40765
|
-
collection:
|
|
40766
|
-
entryId:
|
|
40767
|
-
content:
|
|
40768
|
-
metadata:
|
|
39569
|
+
import z65 from "zod";
|
|
39570
|
+
import { tool as tool59 } from "langchain";
|
|
39571
|
+
var schema4 = z65.object({
|
|
39572
|
+
collection: z65.string().describe("Collection name"),
|
|
39573
|
+
entryId: z65.string().describe("Entry ID to update"),
|
|
39574
|
+
content: z65.string().optional().describe("New content"),
|
|
39575
|
+
metadata: z65.record(z65.unknown()).optional().describe("New metadata")
|
|
40769
39576
|
});
|
|
40770
39577
|
function key3(t, n) {
|
|
40771
39578
|
return `${t}:${n}`;
|
|
40772
39579
|
}
|
|
40773
|
-
var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39580
|
+
var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) => tool59(
|
|
40774
39581
|
async (input, _exeConfig) => {
|
|
40775
39582
|
try {
|
|
40776
39583
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -40791,16 +39598,16 @@ var createUpdateEntryTool = (scope = { collectionKeys: [], connectAll: true }) =
|
|
|
40791
39598
|
);
|
|
40792
39599
|
|
|
40793
39600
|
// src/tool_lattice/collection/delete_entry.ts
|
|
40794
|
-
import
|
|
40795
|
-
import { tool as
|
|
40796
|
-
var schema5 =
|
|
40797
|
-
collection:
|
|
40798
|
-
entryId:
|
|
39601
|
+
import z66 from "zod";
|
|
39602
|
+
import { tool as tool60 } from "langchain";
|
|
39603
|
+
var schema5 = z66.object({
|
|
39604
|
+
collection: z66.string().describe("Collection name"),
|
|
39605
|
+
entryId: z66.string().describe("Entry ID to delete")
|
|
40799
39606
|
});
|
|
40800
39607
|
function key4(t, n) {
|
|
40801
39608
|
return `${t}:${n}`;
|
|
40802
39609
|
}
|
|
40803
|
-
var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) =>
|
|
39610
|
+
var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) => tool60(
|
|
40804
39611
|
async (input, _exeConfig) => {
|
|
40805
39612
|
try {
|
|
40806
39613
|
const scopeError = validateCollectionScope(input.collection, _exeConfig, scope);
|
|
@@ -40820,7 +39627,7 @@ var createDeleteEntryTool = (scope = { collectionKeys: [], connectAll: true }) =
|
|
|
40820
39627
|
function createCollectionMiddleware(params) {
|
|
40821
39628
|
const { collectionKeys, connectAll, compileStableCandidateTools = false } = params;
|
|
40822
39629
|
if (!compileStableCandidateTools && !connectAll && (!collectionKeys || collectionKeys.length === 0)) {
|
|
40823
|
-
return
|
|
39630
|
+
return createMiddleware20({
|
|
40824
39631
|
name: "collectionMiddleware",
|
|
40825
39632
|
contextSchema,
|
|
40826
39633
|
tools: [
|
|
@@ -40830,7 +39637,7 @@ function createCollectionMiddleware(params) {
|
|
|
40830
39637
|
});
|
|
40831
39638
|
}
|
|
40832
39639
|
const toolParams = { collectionKeys, connectAll };
|
|
40833
|
-
return
|
|
39640
|
+
return createMiddleware20({
|
|
40834
39641
|
name: "collectionMiddleware",
|
|
40835
39642
|
contextSchema,
|
|
40836
39643
|
tools: [
|
|
@@ -40893,24 +39700,24 @@ var collectionPlugin = {
|
|
|
40893
39700
|
};
|
|
40894
39701
|
|
|
40895
39702
|
// src/middlewares/askUserClarifyMiddleware.ts
|
|
40896
|
-
import { createMiddleware as
|
|
39703
|
+
import { createMiddleware as createMiddleware21, ToolMessage as ToolMessage11 } from "langchain";
|
|
40897
39704
|
import { interrupt as interrupt3 } from "@langchain/langgraph";
|
|
40898
39705
|
|
|
40899
39706
|
// src/tool_lattice/ask_user_to_clarify/index.ts
|
|
40900
|
-
import { tool as
|
|
40901
|
-
import
|
|
40902
|
-
var questionSchema =
|
|
40903
|
-
question:
|
|
40904
|
-
options:
|
|
40905
|
-
type:
|
|
40906
|
-
required:
|
|
40907
|
-
allowOther:
|
|
39707
|
+
import { tool as tool61 } from "langchain";
|
|
39708
|
+
import z67 from "zod";
|
|
39709
|
+
var questionSchema = z67.object({
|
|
39710
|
+
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?'"),
|
|
39711
|
+
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."),
|
|
39712
|
+
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."),
|
|
39713
|
+
required: z67.boolean().optional().default(false).describe("Whether this question must be answered"),
|
|
39714
|
+
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.")
|
|
40908
39715
|
});
|
|
40909
|
-
var inputSchema =
|
|
40910
|
-
questions:
|
|
39716
|
+
var inputSchema = z67.object({
|
|
39717
|
+
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.")
|
|
40911
39718
|
});
|
|
40912
39719
|
function createAskUserToClarifyTool() {
|
|
40913
|
-
return
|
|
39720
|
+
return tool61(
|
|
40914
39721
|
async (input) => {
|
|
40915
39722
|
return JSON.stringify(input);
|
|
40916
39723
|
},
|
|
@@ -40935,7 +39742,7 @@ function isProjectRoomRun(request) {
|
|
|
40935
39742
|
return isRecord9(runConfig?.projectRoom);
|
|
40936
39743
|
}
|
|
40937
39744
|
function createAskUserClarifyMiddleware() {
|
|
40938
|
-
return
|
|
39745
|
+
return createMiddleware21({
|
|
40939
39746
|
name: "AskUserClarifyMiddleware",
|
|
40940
39747
|
tools: [createAskUserToClarifyTool()],
|
|
40941
39748
|
wrapToolCall: async (request, handler) => {
|
|
@@ -41039,11 +39846,11 @@ var askUserClarifyPlugin = {
|
|
|
41039
39846
|
};
|
|
41040
39847
|
|
|
41041
39848
|
// src/middlewares/widgetMiddleware.ts
|
|
41042
|
-
import { createMiddleware as
|
|
39849
|
+
import { createMiddleware as createMiddleware22 } from "langchain";
|
|
41043
39850
|
|
|
41044
39851
|
// src/tool_lattice/widget/loadGuidelines.ts
|
|
41045
|
-
import { tool as
|
|
41046
|
-
import { z as
|
|
39852
|
+
import { tool as tool62 } from "langchain";
|
|
39853
|
+
import { z as z68 } from "zod";
|
|
41047
39854
|
|
|
41048
39855
|
// src/middlewares/guidelines/index.ts
|
|
41049
39856
|
var CORE = `# Imagine \u2014 Visual Creation Suite
|
|
@@ -41834,13 +40641,13 @@ function getGuidelines(modules) {
|
|
|
41834
40641
|
var AVAILABLE_MODULES = Object.keys(MODULE_SECTIONS);
|
|
41835
40642
|
|
|
41836
40643
|
// src/tool_lattice/widget/loadGuidelines.ts
|
|
41837
|
-
var LoadGuidelinesInputSchema =
|
|
41838
|
-
modules:
|
|
40644
|
+
var LoadGuidelinesInputSchema = z68.object({
|
|
40645
|
+
modules: z68.array(z68.string()).describe(
|
|
41839
40646
|
"Which design modules to load. Choose all that apply. Available modules: [" + AVAILABLE_MODULES.join(",") + "]"
|
|
41840
40647
|
)
|
|
41841
40648
|
});
|
|
41842
40649
|
function createLoadGuidelinesTool() {
|
|
41843
|
-
return
|
|
40650
|
+
return tool62(
|
|
41844
40651
|
async (input) => {
|
|
41845
40652
|
const result = getGuidelines(input.modules);
|
|
41846
40653
|
return result;
|
|
@@ -41854,8 +40661,8 @@ function createLoadGuidelinesTool() {
|
|
|
41854
40661
|
}
|
|
41855
40662
|
|
|
41856
40663
|
// src/tool_lattice/widget/showWidget.ts
|
|
41857
|
-
import { tool as
|
|
41858
|
-
import { z as
|
|
40664
|
+
import { tool as tool63 } from "langchain";
|
|
40665
|
+
import { z as z69 } from "zod";
|
|
41859
40666
|
function containsForbiddenTags(code) {
|
|
41860
40667
|
const forbiddenPatterns = [
|
|
41861
40668
|
/<!DOCTYPE/i,
|
|
@@ -41877,20 +40684,20 @@ function validateWidgetCode(code) {
|
|
|
41877
40684
|
}
|
|
41878
40685
|
return { valid: true };
|
|
41879
40686
|
}
|
|
41880
|
-
var ShowWidgetInputSchema =
|
|
41881
|
-
i_have_seen_guidelines:
|
|
40687
|
+
var ShowWidgetInputSchema = z69.object({
|
|
40688
|
+
i_have_seen_guidelines: z69.boolean().describe(
|
|
41882
40689
|
"Must be true. Confirm you have called load_guidelines first."
|
|
41883
40690
|
),
|
|
41884
|
-
title:
|
|
41885
|
-
loading_messages:
|
|
40691
|
+
title: z69.string().describe("Title displayed above the widget"),
|
|
40692
|
+
loading_messages: z69.array(z69.string()).optional().describe(
|
|
41886
40693
|
"1-4 short strings shown while the widget renders"
|
|
41887
40694
|
),
|
|
41888
|
-
widget_code:
|
|
40695
|
+
widget_code: z69.string().describe(
|
|
41889
40696
|
"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."
|
|
41890
40697
|
)
|
|
41891
40698
|
});
|
|
41892
40699
|
function createShowWidgetTool() {
|
|
41893
|
-
return
|
|
40700
|
+
return tool63(
|
|
41894
40701
|
async (input) => {
|
|
41895
40702
|
if (!input.i_have_seen_guidelines) {
|
|
41896
40703
|
return "Error: You must call load_guidelines before using show_widget. Set i_have_seen_guidelines to true only after loading guidelines.";
|
|
@@ -41921,7 +40728,7 @@ function createWidgetMiddleware() {
|
|
|
41921
40728
|
createLoadGuidelinesTool(),
|
|
41922
40729
|
createShowWidgetTool()
|
|
41923
40730
|
];
|
|
41924
|
-
return
|
|
40731
|
+
return createMiddleware22({
|
|
41925
40732
|
name: "widgetMiddleware",
|
|
41926
40733
|
contextSchema,
|
|
41927
40734
|
tools
|
|
@@ -41945,9 +40752,67 @@ var widgetPlugin = {
|
|
|
41945
40752
|
};
|
|
41946
40753
|
|
|
41947
40754
|
// src/middlewares/taskMiddleware.ts
|
|
41948
|
-
import { createMiddleware as
|
|
41949
|
-
import { z as
|
|
41950
|
-
import { GraphInterrupt as
|
|
40755
|
+
import { createMiddleware as createMiddleware23, tool as tool64 } from "langchain";
|
|
40756
|
+
import { z as z70 } from "zod";
|
|
40757
|
+
import { GraphInterrupt as GraphInterrupt3, interrupt as interrupt4 } from "@langchain/langgraph";
|
|
40758
|
+
|
|
40759
|
+
// src/util/truncateForJson.ts
|
|
40760
|
+
var TRUNCATION_MARKER = "...[truncated]";
|
|
40761
|
+
function truncateString(value, cap) {
|
|
40762
|
+
if (value.length <= cap) return value;
|
|
40763
|
+
const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
|
|
40764
|
+
return value.slice(0, budget) + TRUNCATION_MARKER;
|
|
40765
|
+
}
|
|
40766
|
+
function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
|
|
40767
|
+
if (typeof value === "string") return truncateString(value, maxStringLength);
|
|
40768
|
+
if (value === null || typeof value !== "object") return value;
|
|
40769
|
+
if (depth >= maxDepth) return "[truncated:max-depth]";
|
|
40770
|
+
if (seen.has(value)) return "[Circular]";
|
|
40771
|
+
seen.add(value);
|
|
40772
|
+
try {
|
|
40773
|
+
if (value instanceof Date) return value.toISOString();
|
|
40774
|
+
if (Array.isArray(value)) {
|
|
40775
|
+
const limit2 = Math.min(value.length, maxEntries);
|
|
40776
|
+
const output2 = [];
|
|
40777
|
+
for (let index = 0; index < limit2; index += 1) {
|
|
40778
|
+
output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
|
|
40779
|
+
}
|
|
40780
|
+
if (value.length > limit2) output2.push("[truncated:entries]");
|
|
40781
|
+
return output2;
|
|
40782
|
+
}
|
|
40783
|
+
const record = value;
|
|
40784
|
+
const output = {};
|
|
40785
|
+
const keys = Object.keys(record);
|
|
40786
|
+
const limit = Math.min(keys.length, maxEntries);
|
|
40787
|
+
for (let index = 0; index < limit; index += 1) {
|
|
40788
|
+
const key5 = keys[index];
|
|
40789
|
+
output[truncateString(key5, maxStringLength)] = truncateValue(
|
|
40790
|
+
record[key5],
|
|
40791
|
+
depth + 1,
|
|
40792
|
+
maxDepth,
|
|
40793
|
+
maxEntries,
|
|
40794
|
+
maxStringLength,
|
|
40795
|
+
seen
|
|
40796
|
+
);
|
|
40797
|
+
}
|
|
40798
|
+
if (keys.length > limit) output["[truncated]"] = true;
|
|
40799
|
+
return output;
|
|
40800
|
+
} finally {
|
|
40801
|
+
seen.delete(value);
|
|
40802
|
+
}
|
|
40803
|
+
}
|
|
40804
|
+
function truncateForJson(value, options = {}) {
|
|
40805
|
+
return truncateValue(
|
|
40806
|
+
value,
|
|
40807
|
+
0,
|
|
40808
|
+
options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
|
|
40809
|
+
options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
|
|
40810
|
+
options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
|
|
40811
|
+
/* @__PURE__ */ new WeakSet()
|
|
40812
|
+
);
|
|
40813
|
+
}
|
|
40814
|
+
|
|
40815
|
+
// src/middlewares/taskMiddleware.ts
|
|
41951
40816
|
import {
|
|
41952
40817
|
isExecutionResultEventKey as isExecutionResultEventKey3,
|
|
41953
40818
|
parseTaskBeliefState as parseTaskBeliefState2,
|
|
@@ -42277,6 +41142,132 @@ function getRuntimeActor2(runConfig) {
|
|
|
42277
41142
|
if (runConfig.user_id) return `user:${String(runConfig.user_id)}`;
|
|
42278
41143
|
return void 0;
|
|
42279
41144
|
}
|
|
41145
|
+
function readRuntimeRunConfig(source) {
|
|
41146
|
+
const s = source;
|
|
41147
|
+
const rc = s?.context?.runConfig ?? s?.configurable?.runConfig;
|
|
41148
|
+
return rc && typeof rc === "object" && !Array.isArray(rc) ? rc : {};
|
|
41149
|
+
}
|
|
41150
|
+
function readExecutionTaskId(runConfig) {
|
|
41151
|
+
const execution = runConfig.execution;
|
|
41152
|
+
if (!execution || typeof execution !== "object" || Array.isArray(execution)) return void 0;
|
|
41153
|
+
const value = execution.taskId;
|
|
41154
|
+
return typeof value === "string" && value.trim() !== "" ? value : void 0;
|
|
41155
|
+
}
|
|
41156
|
+
function renderTaskBinding(taskId) {
|
|
41157
|
+
return `
|
|
41158
|
+
|
|
41159
|
+
## Bound Task
|
|
41160
|
+
|
|
41161
|
+
You are executing task \`${taskId}\`. Read its contract with \`manage_task get\`, update it as you work, and complete it when done.
|
|
41162
|
+
`;
|
|
41163
|
+
}
|
|
41164
|
+
function createBoundTaskLifecycle() {
|
|
41165
|
+
return createTaskLifecycleService({ taskStore: getTaskStore(), workItemStore: getTaskWorkItemStore() });
|
|
41166
|
+
}
|
|
41167
|
+
function createBoundTaskBridge() {
|
|
41168
|
+
return createTaskRunBridge({ lifecycle: createBoundTaskLifecycle() });
|
|
41169
|
+
}
|
|
41170
|
+
function isResumableInterruption(interruption) {
|
|
41171
|
+
if (!interruption || typeof interruption !== "object" || Array.isArray(interruption)) return false;
|
|
41172
|
+
const type = interruption.type;
|
|
41173
|
+
return type === "missing_input" || type === "user_decision";
|
|
41174
|
+
}
|
|
41175
|
+
var TASK_WORKER_OBSERVATION_MAX_CHARS = 8192;
|
|
41176
|
+
function snapshotMessages(state) {
|
|
41177
|
+
if (!state || typeof state !== "object") return [];
|
|
41178
|
+
const values = state.values;
|
|
41179
|
+
if (!values || typeof values !== "object") return [];
|
|
41180
|
+
const messages = values.messages;
|
|
41181
|
+
return Array.isArray(messages) ? messages : [];
|
|
41182
|
+
}
|
|
41183
|
+
function messageText(value) {
|
|
41184
|
+
if (typeof value === "string") return value;
|
|
41185
|
+
if (!Array.isArray(value)) return void 0;
|
|
41186
|
+
return value.flatMap((part) => {
|
|
41187
|
+
if (typeof part === "string") return [part];
|
|
41188
|
+
if (part && typeof part === "object" && typeof part.text === "string") {
|
|
41189
|
+
return [part.text];
|
|
41190
|
+
}
|
|
41191
|
+
return [];
|
|
41192
|
+
}).join("");
|
|
41193
|
+
}
|
|
41194
|
+
function lastAssistantText(source) {
|
|
41195
|
+
const messages = Array.isArray(source) ? source : source && typeof source === "object" && Array.isArray(source.messages) ? source.messages : snapshotMessages(source);
|
|
41196
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
41197
|
+
const message = messages[index];
|
|
41198
|
+
if (!message || typeof message !== "object") continue;
|
|
41199
|
+
const role = message.role ?? message.type;
|
|
41200
|
+
if (role !== "ai" && role !== "assistant") continue;
|
|
41201
|
+
const text = messageText(message.content);
|
|
41202
|
+
if (text !== void 0) return text;
|
|
41203
|
+
}
|
|
41204
|
+
return void 0;
|
|
41205
|
+
}
|
|
41206
|
+
function boundedWorkerObservation(result, state) {
|
|
41207
|
+
const text = lastAssistantText(state) ?? lastAssistantText(result) ?? "";
|
|
41208
|
+
return {
|
|
41209
|
+
status: "completed",
|
|
41210
|
+
output: truncateForJson(text, { maxStringLength: TASK_WORKER_OBSERVATION_MAX_CHARS })
|
|
41211
|
+
};
|
|
41212
|
+
}
|
|
41213
|
+
var EXECUTOR_CACHE_TTL_MS = 3e4;
|
|
41214
|
+
var executorCache = /* @__PURE__ */ new Map();
|
|
41215
|
+
function executorString(value) {
|
|
41216
|
+
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
41217
|
+
}
|
|
41218
|
+
async function renderAvailableExecutors(rc, tenantId2) {
|
|
41219
|
+
const authority = classifyTaskAuthority(rc);
|
|
41220
|
+
const governed = authority.kind === "projectRoom" || authority.kind === "projectTask";
|
|
41221
|
+
const projectId = governed ? (authority.trusted.projectTask ?? authority.trusted.projectRoom)?.projectId : void 0;
|
|
41222
|
+
const cacheKey = `${tenantId2}:${governed ? `project:${projectId ?? ""}` : "ordinary"}`;
|
|
41223
|
+
const cached = executorCache.get(cacheKey);
|
|
41224
|
+
const now = Date.now();
|
|
41225
|
+
if (cached && now - cached.at < EXECUTOR_CACHE_TTL_MS) return cached.text;
|
|
41226
|
+
const lines = [];
|
|
41227
|
+
try {
|
|
41228
|
+
if (governed && projectId) {
|
|
41229
|
+
const store = getStoreLattice("default", "projectBotMembership").store;
|
|
41230
|
+
if (typeof store.list === "function") {
|
|
41231
|
+
const bots = await store.list(tenantId2, projectId);
|
|
41232
|
+
for (const bot of (Array.isArray(bots) ? bots : []).slice(0, 40)) {
|
|
41233
|
+
const row = bot;
|
|
41234
|
+
if (row.status !== "active") continue;
|
|
41235
|
+
const id = executorString(row.assistantId);
|
|
41236
|
+
if (!id) continue;
|
|
41237
|
+
const title = executorString(row.title);
|
|
41238
|
+
const responsibility = executorString(row.responsibility);
|
|
41239
|
+
lines.push(`- ${id}${title ? ` \u2014 ${title}` : ""}${responsibility ? ` (${responsibility})` : ""}`);
|
|
41240
|
+
}
|
|
41241
|
+
}
|
|
41242
|
+
} else {
|
|
41243
|
+
const configs = await agentLatticeManager.getAllAgentConfigsByTenant(tenantId2);
|
|
41244
|
+
for (const config of configs.slice(0, 40)) {
|
|
41245
|
+
const row = config;
|
|
41246
|
+
const id = executorString(row.key);
|
|
41247
|
+
if (!id) continue;
|
|
41248
|
+
const name = executorString(row.name);
|
|
41249
|
+
const description = executorString(row.description);
|
|
41250
|
+
lines.push(`- ${id}${name ? ` \u2014 ${name}` : ""}${description ? ` (${description.slice(0, 120)})` : ""}`);
|
|
41251
|
+
}
|
|
41252
|
+
}
|
|
41253
|
+
} catch {
|
|
41254
|
+
}
|
|
41255
|
+
if (lines.length === 0) {
|
|
41256
|
+
executorCache.set(cacheKey, { at: now, text: "" });
|
|
41257
|
+
return "";
|
|
41258
|
+
}
|
|
41259
|
+
const header = governed ? "## Available task executors (Project roster)" : "## Available task executors";
|
|
41260
|
+
const text = `
|
|
41261
|
+
|
|
41262
|
+
${header}
|
|
41263
|
+
|
|
41264
|
+
Dispatch \`task\` only to an executor that has the tools the work needs (for example \`update_agent\`/\`create_agent\` for materialization). Never dispatch to the subject agent you are building. Use \`general-purpose\` to run your own capabilities.
|
|
41265
|
+
|
|
41266
|
+
${lines.join("\n")}
|
|
41267
|
+
`;
|
|
41268
|
+
executorCache.set(cacheKey, { at: now, text });
|
|
41269
|
+
return text;
|
|
41270
|
+
}
|
|
42280
41271
|
function delegatedTaskScopeError(taskId) {
|
|
42281
41272
|
return JSON.stringify({
|
|
42282
41273
|
success: false,
|
|
@@ -42644,65 +41635,75 @@ function buildReviewMarkdown(task) {
|
|
|
42644
41635
|
result: task.result
|
|
42645
41636
|
});
|
|
42646
41637
|
}
|
|
42647
|
-
var manageTaskSchema =
|
|
42648
|
-
action:
|
|
42649
|
-
id:
|
|
42650
|
-
title:
|
|
42651
|
-
description:
|
|
42652
|
-
priority:
|
|
42653
|
-
status:
|
|
42654
|
-
dueDate:
|
|
42655
|
-
metadata:
|
|
42656
|
-
metadataFilter:
|
|
42657
|
-
|
|
41638
|
+
var manageTaskSchema = z70.object({
|
|
41639
|
+
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."),
|
|
41640
|
+
id: z70.string().optional().describe("Task ID (required for get, update, add_activity; required for delete unless ids is given)"),
|
|
41641
|
+
title: z70.string().optional().describe("Task title (required for create)"),
|
|
41642
|
+
description: z70.string().optional().describe("Task description in Markdown"),
|
|
41643
|
+
priority: z70.enum(["low", "medium", "high"]).optional().describe("Priority level"),
|
|
41644
|
+
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"),
|
|
41645
|
+
dueDate: z70.string().optional().describe("Due date (ISO 8601 format)"),
|
|
41646
|
+
metadata: z70.record(z70.unknown()).optional().describe("Structured metadata (e.g. projectId, module)"),
|
|
41647
|
+
metadataFilter: z70.record(
|
|
41648
|
+
z70.union([z70.string(), z70.number(), z70.boolean()])
|
|
42658
41649
|
).optional().describe("List-only filter. Every key must equal the task metadata value, e.g. {projectId:'p1', retries:2}. Multiple keys AND together."),
|
|
42659
|
-
parentId:
|
|
42660
|
-
sourceId:
|
|
42661
|
-
context:
|
|
42662
|
-
ownerType:
|
|
42663
|
-
ownerId:
|
|
42664
|
-
requireReview:
|
|
42665
|
-
dependencies:
|
|
42666
|
-
dependencyTaskIds:
|
|
42667
|
-
result:
|
|
42668
|
-
failureReason:
|
|
42669
|
-
files:
|
|
42670
|
-
uri:
|
|
42671
|
-
name:
|
|
42672
|
-
addedBy:
|
|
41650
|
+
parentId: z70.string().optional().describe("Parent task ID for grouping subtasks"),
|
|
41651
|
+
sourceId: z70.string().optional().describe("Source session/thread ID"),
|
|
41652
|
+
context: z70.record(z70.unknown()).optional().describe("Additional context data"),
|
|
41653
|
+
ownerType: z70.enum(["user", "agent"]).optional().describe("Owner type. Defaults to 'user' if omitted"),
|
|
41654
|
+
ownerId: z70.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
|
|
41655
|
+
requireReview: z70.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
|
|
41656
|
+
dependencies: z70.array(z70.string()).optional().describe("List of task IDs that must be completed before this task can start"),
|
|
41657
|
+
dependencyTaskIds: z70.array(z70.string().trim().min(1)).optional().describe("Exact blocking task IDs required for an external_dependency interruption"),
|
|
41658
|
+
result: z70.string().optional().describe("Result summary. Used with set_status status='completed' or update status='completed'"),
|
|
41659
|
+
failureReason: z70.string().optional().describe("Failure reason. Used with set_status status='failed' or update status='failed'"),
|
|
41660
|
+
files: z70.array(z70.object({
|
|
41661
|
+
uri: z70.string().describe("Uniquely locates the resource: http(s):// URL, /s/:token share, or sandbox path"),
|
|
41662
|
+
name: z70.string().optional().describe("Display name"),
|
|
41663
|
+
addedBy: z70.enum(["user", "agent"]).optional().describe("Who attached the file")
|
|
42673
41664
|
})).optional().describe("File references attached to this task"),
|
|
42674
|
-
beliefImpact:
|
|
42675
|
-
key:
|
|
42676
|
-
after:
|
|
42677
|
-
basis:
|
|
42678
|
-
isNew:
|
|
41665
|
+
beliefImpact: z70.array(z70.object({
|
|
41666
|
+
key: z70.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/),
|
|
41667
|
+
after: z70.number().int().min(0).max(100),
|
|
41668
|
+
basis: z70.string().trim().min(1).max(1e3),
|
|
41669
|
+
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")
|
|
42679
41670
|
})).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"),
|
|
42680
|
-
content:
|
|
42681
|
-
summary:
|
|
42682
|
-
executionResultId:
|
|
41671
|
+
content: z70.string().optional().describe("Markdown content required for add_activity"),
|
|
41672
|
+
summary: z70.string().optional().describe("Brief summary of the operation"),
|
|
41673
|
+
executionResultId: z70.string().refine(isExecutionResultEventKey3, {
|
|
42683
41674
|
message: "executionResultId must be the execution-result:<threadId> event key returned by task()"
|
|
42684
41675
|
}).optional().describe(
|
|
42685
41676
|
"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"
|
|
42686
|
-
)
|
|
41677
|
+
),
|
|
41678
|
+
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.")
|
|
42687
41679
|
}).superRefine((input, context) => {
|
|
42688
41680
|
if (input.executionResultId && input.action !== "update" && input.action !== "set_status" && input.action !== "add_activity") {
|
|
42689
41681
|
context.addIssue({
|
|
42690
|
-
code:
|
|
41682
|
+
code: z70.ZodIssueCode.custom,
|
|
42691
41683
|
path: ["executionResultId"],
|
|
42692
41684
|
message: "executionResultId is valid only for update, set_status, or add_activity"
|
|
42693
41685
|
});
|
|
42694
41686
|
}
|
|
42695
41687
|
if (input.metadataFilter && input.action !== "list") {
|
|
42696
41688
|
context.addIssue({
|
|
42697
|
-
code:
|
|
41689
|
+
code: z70.ZodIssueCode.custom,
|
|
42698
41690
|
path: ["metadataFilter"],
|
|
42699
41691
|
message: "metadataFilter is valid only for list"
|
|
42700
41692
|
});
|
|
42701
41693
|
}
|
|
41694
|
+
if (input.ids && input.action !== "delete") {
|
|
41695
|
+
context.addIssue({
|
|
41696
|
+
code: z70.ZodIssueCode.custom,
|
|
41697
|
+
path: ["ids"],
|
|
41698
|
+
message: "ids is valid only for delete"
|
|
41699
|
+
});
|
|
41700
|
+
}
|
|
42702
41701
|
});
|
|
42703
|
-
var startTaskSchema =
|
|
42704
|
-
taskId:
|
|
42705
|
-
agentId:
|
|
41702
|
+
var startTaskSchema = z70.object({
|
|
41703
|
+
taskId: z70.string().trim().min(1).describe("ID of the persisted TaskItem to start"),
|
|
41704
|
+
agentId: z70.string().trim().min(1).describe(
|
|
41705
|
+
`ID of the Agent that should execute the task. Use "general-purpose" to run the caller's own capabilities as an isolated worker.`
|
|
41706
|
+
)
|
|
42706
41707
|
});
|
|
42707
41708
|
function mergeTaskUpdateWarnings(existing, added) {
|
|
42708
41709
|
const warnings = [...existing ?? [], ...added ?? []];
|
|
@@ -42839,6 +41840,49 @@ function createTaskMiddleware(options = {}) {
|
|
|
42839
41840
|
}
|
|
42840
41841
|
const ownerId = input.ownerId || trustedScope?.assistantId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
|
|
42841
41842
|
const store = getTaskStore();
|
|
41843
|
+
const deleteOneTask = async (id) => {
|
|
41844
|
+
if (delegatedTaskId && id !== delegatedTaskId) {
|
|
41845
|
+
return delegatedTaskScopeError(delegatedTaskId);
|
|
41846
|
+
}
|
|
41847
|
+
const existing = await store.getById(tenantId2, id);
|
|
41848
|
+
if (!existing) {
|
|
41849
|
+
return JSON.stringify({
|
|
41850
|
+
success: false,
|
|
41851
|
+
code: "TASK_NOT_FOUND",
|
|
41852
|
+
error: `Task '${id}' was not found.`,
|
|
41853
|
+
hint: "Use manage_task list to see available tasks and their correct IDs."
|
|
41854
|
+
});
|
|
41855
|
+
}
|
|
41856
|
+
if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
|
|
41857
|
+
return taskScopeAccessError(id);
|
|
41858
|
+
}
|
|
41859
|
+
if (trustedProject?.projectTask) {
|
|
41860
|
+
const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
|
|
41861
|
+
if (trustedFailure) return trustedFailure;
|
|
41862
|
+
}
|
|
41863
|
+
let deleted;
|
|
41864
|
+
if (trustedProject) {
|
|
41865
|
+
const snapshot = taskMutationSnapshot(existing);
|
|
41866
|
+
if (!snapshot) return trustedContextError();
|
|
41867
|
+
try {
|
|
41868
|
+
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
41869
|
+
} catch (error) {
|
|
41870
|
+
return projectPolicyError(error);
|
|
41871
|
+
}
|
|
41872
|
+
deleted = await store.deleteIfSnapshot(tenantId2, id, snapshot);
|
|
41873
|
+
} else {
|
|
41874
|
+
deleted = await store.delete(tenantId2, id);
|
|
41875
|
+
}
|
|
41876
|
+
if (!deleted) {
|
|
41877
|
+
return JSON.stringify({
|
|
41878
|
+
success: false,
|
|
41879
|
+
code: "TASK_DELETE_FAILED",
|
|
41880
|
+
error: `Task '${id}' was not found or could not be deleted.`,
|
|
41881
|
+
hint: "Use manage_task list to verify the task exists and you have access to it."
|
|
41882
|
+
});
|
|
41883
|
+
}
|
|
41884
|
+
return JSON.stringify({ success: true, message: `Task '${id}' deleted` });
|
|
41885
|
+
};
|
|
42842
41886
|
switch (input.action) {
|
|
42843
41887
|
case "create": {
|
|
42844
41888
|
if (delegatedTaskId && input.parentId !== delegatedTaskId) {
|
|
@@ -42994,9 +42038,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
42994
42038
|
hint: "Pass the task ID you want to retrieve"
|
|
42995
42039
|
});
|
|
42996
42040
|
}
|
|
42997
|
-
if (delegatedTaskId && input.id !== delegatedTaskId) {
|
|
42998
|
-
return delegatedTaskScopeError(delegatedTaskId);
|
|
42999
|
-
}
|
|
43000
42041
|
const task = await store.getById(tenantId2, input.id);
|
|
43001
42042
|
if (!task) {
|
|
43002
42043
|
return JSON.stringify({
|
|
@@ -43042,25 +42083,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
43042
42083
|
});
|
|
43043
42084
|
}
|
|
43044
42085
|
case "list": {
|
|
43045
|
-
if (delegatedTaskId) {
|
|
43046
|
-
const delegatedTask = await store.getById(tenantId2, delegatedTaskId);
|
|
43047
|
-
if (!delegatedTask || !taskMatchesRuntimeScope3(delegatedTask, workspaceId, projectId)) {
|
|
43048
|
-
return serializeTaskReadResponse({ success: true, data: [], count: 0 });
|
|
43049
|
-
}
|
|
43050
|
-
const children = await store.list({
|
|
43051
|
-
tenantId: tenantId2,
|
|
43052
|
-
workspaceId,
|
|
43053
|
-
projectId,
|
|
43054
|
-
parentId: delegatedTaskId,
|
|
43055
|
-
metadata: input.metadataFilter
|
|
43056
|
-
});
|
|
43057
|
-
const scopedChildren = children.filter((child) => child.id !== delegatedTaskId && child.parentId === delegatedTaskId && exactScopeMatch(child, delegatedTask));
|
|
43058
|
-
return serializeTaskReadResponse({
|
|
43059
|
-
success: true,
|
|
43060
|
-
data: [delegatedTask, ...scopedChildren],
|
|
43061
|
-
count: scopedChildren.length + 1
|
|
43062
|
-
});
|
|
43063
|
-
}
|
|
43064
42086
|
const filter2 = {
|
|
43065
42087
|
tenantId: tenantId2,
|
|
43066
42088
|
ownerType: input.ownerType,
|
|
@@ -43655,41 +42677,31 @@ function createTaskMiddleware(options = {}) {
|
|
|
43655
42677
|
});
|
|
43656
42678
|
return lifecycleMutationResponse(interrupted);
|
|
43657
42679
|
}
|
|
43658
|
-
if (lifecycle && input.status === "in_progress"
|
|
43659
|
-
await validateExecutionResult();
|
|
43660
|
-
const callerError = await revalidateCaller();
|
|
43661
|
-
if (callerError) return callerError;
|
|
43662
|
-
const resumed = await lifecycle.resumeInterruption({
|
|
43663
|
-
tenantId: tenantId2,
|
|
43664
|
-
taskId: input.id,
|
|
43665
|
-
actor,
|
|
43666
|
-
threadId: statusThreadId
|
|
43667
|
-
});
|
|
43668
|
-
return lifecycleMutationResponse(resumed);
|
|
43669
|
-
}
|
|
43670
|
-
if (lifecycle && input.status === "in_progress" && existing.status === "pending") {
|
|
43671
|
-
await validateExecutionResult();
|
|
42680
|
+
if (lifecycle && input.status === "in_progress") {
|
|
43672
42681
|
const callerError = await revalidateCaller();
|
|
43673
42682
|
if (callerError) return callerError;
|
|
43674
|
-
|
|
43675
|
-
|
|
43676
|
-
|
|
43677
|
-
|
|
43678
|
-
|
|
43679
|
-
|
|
43680
|
-
|
|
43681
|
-
|
|
43682
|
-
|
|
43683
|
-
|
|
43684
|
-
|
|
43685
|
-
|
|
43686
|
-
|
|
42683
|
+
if (existing.status === "interrupted") {
|
|
42684
|
+
return lifecycleMutationResponse(await lifecycle.resumeInterruption({
|
|
42685
|
+
tenantId: tenantId2,
|
|
42686
|
+
taskId: input.id,
|
|
42687
|
+
actor,
|
|
42688
|
+
threadId: statusThreadId
|
|
42689
|
+
}));
|
|
42690
|
+
}
|
|
42691
|
+
if (existing.status === "failed") {
|
|
42692
|
+
return lifecycleMutationResponse(await lifecycle.retryTask({
|
|
42693
|
+
tenantId: tenantId2,
|
|
42694
|
+
taskId: input.id,
|
|
42695
|
+
actor,
|
|
42696
|
+
threadId: statusThreadId
|
|
42697
|
+
}));
|
|
42698
|
+
}
|
|
42699
|
+
return lifecycleMutationResponse(await lifecycle.startTask({
|
|
43687
42700
|
tenantId: tenantId2,
|
|
43688
42701
|
taskId: input.id,
|
|
43689
42702
|
actor,
|
|
43690
42703
|
threadId: statusThreadId
|
|
43691
|
-
});
|
|
43692
|
-
return lifecycleMutationResponse(retried);
|
|
42704
|
+
}));
|
|
43693
42705
|
}
|
|
43694
42706
|
const effectiveRequireReview = existing.requireReview === true || input.requireReview === true;
|
|
43695
42707
|
const candidateReviewInterruption = input.status === "interrupted" && input.context?.interruption && typeof input.context.interruption === "object" && input.context.interruption.type === "review_required" && !!input.result?.trim();
|
|
@@ -43758,7 +42770,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43758
42770
|
try {
|
|
43759
42771
|
response = await interrupt4(buildReviewMarkdown(submitted.task));
|
|
43760
42772
|
} catch (error) {
|
|
43761
|
-
if (error instanceof
|
|
42773
|
+
if (error instanceof GraphInterrupt3) throw error;
|
|
43762
42774
|
return lifecycleMutationResponse(submitted, { code: "REVIEW_REQUIRED" });
|
|
43763
42775
|
}
|
|
43764
42776
|
if (response?.action === "approve") {
|
|
@@ -43870,54 +42882,49 @@ function createTaskMiddleware(options = {}) {
|
|
|
43870
42882
|
return successfulTaskResponse(input.id, updatedStatus, true);
|
|
43871
42883
|
}
|
|
43872
42884
|
case "delete": {
|
|
43873
|
-
|
|
43874
|
-
|
|
43875
|
-
|
|
43876
|
-
|
|
43877
|
-
|
|
43878
|
-
|
|
43879
|
-
|
|
43880
|
-
|
|
43881
|
-
|
|
43882
|
-
|
|
43883
|
-
|
|
43884
|
-
if (!existing) {
|
|
43885
|
-
return JSON.stringify({
|
|
43886
|
-
success: false,
|
|
43887
|
-
code: "TASK_NOT_FOUND",
|
|
43888
|
-
error: `Task '${input.id}' was not found.`,
|
|
43889
|
-
hint: "Use manage_task list to see available tasks and their correct IDs."
|
|
43890
|
-
});
|
|
43891
|
-
}
|
|
43892
|
-
if (!taskMatchesRuntimeScope3(existing, workspaceId, projectId)) {
|
|
43893
|
-
return taskScopeAccessError(input.id);
|
|
43894
|
-
}
|
|
43895
|
-
if (trustedProject?.projectTask) {
|
|
43896
|
-
const trustedFailure = trustedTaskContextFailure(existing, trustedProject.projectTask);
|
|
43897
|
-
if (trustedFailure) return trustedFailure;
|
|
42885
|
+
const missingTargetError = JSON.stringify({
|
|
42886
|
+
success: false,
|
|
42887
|
+
error: "id or ids is required for delete action",
|
|
42888
|
+
hint: "Pass the task ID(s) you want to delete"
|
|
42889
|
+
});
|
|
42890
|
+
const requestedIds = input.ids && input.ids.length > 0 ? [.../* @__PURE__ */ new Set([...input.id ? [input.id] : [], ...input.ids])] : void 0;
|
|
42891
|
+
if (requestedIds === void 0) {
|
|
42892
|
+
if (!input.id) {
|
|
42893
|
+
return missingTargetError;
|
|
42894
|
+
}
|
|
42895
|
+
return deleteOneTask(input.id);
|
|
43898
42896
|
}
|
|
43899
|
-
|
|
43900
|
-
|
|
43901
|
-
|
|
43902
|
-
|
|
42897
|
+
const deletedIds = [];
|
|
42898
|
+
const failed = [];
|
|
42899
|
+
for (const id of requestedIds) {
|
|
42900
|
+
let raw;
|
|
43903
42901
|
try {
|
|
43904
|
-
await
|
|
42902
|
+
raw = await deleteOneTask(id);
|
|
43905
42903
|
} catch (error) {
|
|
43906
|
-
|
|
42904
|
+
failed.push({
|
|
42905
|
+
id,
|
|
42906
|
+
code: "TASK_DELETE_FAILED",
|
|
42907
|
+
error: error instanceof Error ? error.message : String(error)
|
|
42908
|
+
});
|
|
42909
|
+
continue;
|
|
42910
|
+
}
|
|
42911
|
+
const result = JSON.parse(raw);
|
|
42912
|
+
if (result.success) {
|
|
42913
|
+
deletedIds.push(id);
|
|
42914
|
+
} else {
|
|
42915
|
+
failed.push({
|
|
42916
|
+
id,
|
|
42917
|
+
...result.code ? { code: result.code } : {},
|
|
42918
|
+
error: result.error ?? `Task '${id}' could not be deleted.`
|
|
42919
|
+
});
|
|
43907
42920
|
}
|
|
43908
|
-
deleted = await store.deleteIfSnapshot(tenantId2, input.id, snapshot);
|
|
43909
|
-
} else {
|
|
43910
|
-
deleted = await store.delete(tenantId2, input.id);
|
|
43911
|
-
}
|
|
43912
|
-
if (!deleted) {
|
|
43913
|
-
return JSON.stringify({
|
|
43914
|
-
success: false,
|
|
43915
|
-
code: "TASK_DELETE_FAILED",
|
|
43916
|
-
error: `Task '${input.id}' was not found or could not be deleted.`,
|
|
43917
|
-
hint: "Use manage_task list to verify the task exists and you have access to it."
|
|
43918
|
-
});
|
|
43919
42921
|
}
|
|
43920
|
-
return JSON.stringify({
|
|
42922
|
+
return JSON.stringify({
|
|
42923
|
+
success: failed.length === 0,
|
|
42924
|
+
deleted: deletedIds,
|
|
42925
|
+
failed,
|
|
42926
|
+
summary: `${deletedIds.length} of ${requestedIds.length} deleted`
|
|
42927
|
+
});
|
|
43921
42928
|
}
|
|
43922
42929
|
default:
|
|
43923
42930
|
return JSON.stringify({
|
|
@@ -44032,23 +43039,29 @@ function createTaskMiddleware(options = {}) {
|
|
|
44032
43039
|
error: "Runtime actor identity is required for persistent task execution"
|
|
44033
43040
|
});
|
|
44034
43041
|
}
|
|
43042
|
+
const callerAssistantId = rc.assistant_id;
|
|
43043
|
+
const agentId = input.agentId === "general-purpose" && callerAssistantId ? `${callerAssistantId}-general-purpose` : input.agentId;
|
|
44035
43044
|
const service2 = createTaskExecutionService({
|
|
44036
43045
|
taskStore: getTaskStore(),
|
|
44037
43046
|
workItemStore: getTaskWorkItemStore(),
|
|
44038
|
-
resolveAgent: async (targetTenantId,
|
|
44039
|
-
resolveTaskCapability: async (targetTenantId, agentId) => agentHasManagedTaskCapability(
|
|
44040
|
-
(await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId))?.config
|
|
44041
|
-
),
|
|
43047
|
+
resolveAgent: async (targetTenantId, agentId2) => !!await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId2),
|
|
44042
43048
|
invokeAgent: async (invocation) => {
|
|
44043
|
-
const
|
|
44044
|
-
tenant_id: invocation.tenantId,
|
|
43049
|
+
const workerResult = await agentWorkerGraph.invoke({
|
|
44045
43050
|
assistant_id: invocation.agentId,
|
|
44046
43051
|
thread_id: invocation.threadId,
|
|
44047
|
-
|
|
44048
|
-
|
|
44049
|
-
|
|
43052
|
+
input: { message: invocation.message },
|
|
43053
|
+
runConfig: {
|
|
43054
|
+
...rc,
|
|
43055
|
+
assistant_id: invocation.agentId,
|
|
43056
|
+
thread_id: invocation.threadId,
|
|
43057
|
+
taskId: invocation.taskId,
|
|
43058
|
+
tenantId: invocation.tenantId,
|
|
43059
|
+
workspaceId: invocation.workspaceId,
|
|
43060
|
+
projectId: invocation.projectId
|
|
43061
|
+
}
|
|
44050
43062
|
});
|
|
44051
|
-
|
|
43063
|
+
const finalState = workerResult?.finalState;
|
|
43064
|
+
return boundedWorkerObservation(finalState, void 0);
|
|
44052
43065
|
}
|
|
44053
43066
|
});
|
|
44054
43067
|
const trustedCaller = authority.kind === "projectTask" || authority.kind === "projectRoom" ? authority.trusted.projectTask ?? authority.trusted.projectRoom : void 0;
|
|
@@ -44057,15 +43070,75 @@ function createTaskMiddleware(options = {}) {
|
|
|
44057
43070
|
workspaceId: rc.workspaceId,
|
|
44058
43071
|
projectId: rc.projectId,
|
|
44059
43072
|
taskId: input.taskId,
|
|
44060
|
-
agentId
|
|
43073
|
+
agentId,
|
|
44061
43074
|
actor,
|
|
44062
43075
|
callerThreadId: rc.thread_id,
|
|
44063
43076
|
...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
|
|
44064
43077
|
}));
|
|
44065
43078
|
};
|
|
44066
|
-
return
|
|
43079
|
+
return createMiddleware23({
|
|
44067
43080
|
name: "TaskMiddleware",
|
|
44068
43081
|
contextSchema,
|
|
43082
|
+
// Persisted between invocations (ADRs: the run↔task binding survives turns).
|
|
43083
|
+
stateSchema: z70.object({
|
|
43084
|
+
taskId: z70.string().default("")
|
|
43085
|
+
}),
|
|
43086
|
+
// CLAIM: a run that holds a task moves it to in_progress (idempotent).
|
|
43087
|
+
beforeAgent: async (state, runtime) => {
|
|
43088
|
+
const rc = readRuntimeRunConfig(runtime);
|
|
43089
|
+
const bound = typeof state?.taskId === "string" ? state.taskId : "";
|
|
43090
|
+
const taskId = bound || readExecutionTaskId(rc) || "";
|
|
43091
|
+
if (!taskId) return {};
|
|
43092
|
+
if (!taskId) return {};
|
|
43093
|
+
const tenantId2 = rc.tenantId || "default";
|
|
43094
|
+
const threadId = runtime?.configurable?.thread_id;
|
|
43095
|
+
const task = await getTaskStore().getById(tenantId2, taskId);
|
|
43096
|
+
if (!task) return {};
|
|
43097
|
+
const runWorkspaceId = typeof rc.workspaceId === "string" ? rc.workspaceId : void 0;
|
|
43098
|
+
const runProjectId = typeof rc.projectId === "string" ? rc.projectId : void 0;
|
|
43099
|
+
if (task.workspaceId && task.workspaceId !== runWorkspaceId) return {};
|
|
43100
|
+
if (task.projectId && task.projectId !== runProjectId) return {};
|
|
43101
|
+
if (task.status === "completed" || task.status === "failed" || task.status === "cancelled") {
|
|
43102
|
+
return bound ? {} : { taskId };
|
|
43103
|
+
}
|
|
43104
|
+
taskRunRegistry.register(taskId);
|
|
43105
|
+
if (task.status === "pending") {
|
|
43106
|
+
await createBoundTaskBridge().beginRun({
|
|
43107
|
+
tenantId: tenantId2,
|
|
43108
|
+
task,
|
|
43109
|
+
actor: getRuntimeActor2(rc) ?? "system",
|
|
43110
|
+
...threadId ? { threadId } : {}
|
|
43111
|
+
});
|
|
43112
|
+
} else if (task.status === "interrupted" && isResumableInterruption(task.context?.interruption)) {
|
|
43113
|
+
await createBoundTaskLifecycle().resumeInterruption({
|
|
43114
|
+
tenantId: tenantId2,
|
|
43115
|
+
taskId: task.id,
|
|
43116
|
+
actor: getRuntimeActor2(rc) ?? "system",
|
|
43117
|
+
...threadId ? { threadId } : {}
|
|
43118
|
+
});
|
|
43119
|
+
}
|
|
43120
|
+
return bound ? {} : { taskId };
|
|
43121
|
+
},
|
|
43122
|
+
// SETTLE: a run that ends without a lifecycle transition converges the task.
|
|
43123
|
+
afterAgent: async (state, runtime) => {
|
|
43124
|
+
const taskId = typeof state?.taskId === "string" ? state.taskId : "";
|
|
43125
|
+
if (!taskId) return {};
|
|
43126
|
+
const rc = readRuntimeRunConfig(runtime);
|
|
43127
|
+
const tenantId2 = rc.tenantId || "default";
|
|
43128
|
+
const threadId = runtime?.configurable?.thread_id;
|
|
43129
|
+
const task = await getTaskStore().getById(tenantId2, taskId);
|
|
43130
|
+
if (task?.status === "in_progress" && task.context?.thread_id === threadId) {
|
|
43131
|
+
await createBoundTaskBridge().settleRun({
|
|
43132
|
+
tenantId: tenantId2,
|
|
43133
|
+
task,
|
|
43134
|
+
actor: getRuntimeActor2(rc) ?? "system",
|
|
43135
|
+
...threadId ? { threadId } : {},
|
|
43136
|
+
outcome: { kind: "interrupted", summary: "Run ended without a task lifecycle transition" }
|
|
43137
|
+
});
|
|
43138
|
+
}
|
|
43139
|
+
taskRunRegistry.unregister(taskId);
|
|
43140
|
+
return {};
|
|
43141
|
+
},
|
|
44069
43142
|
wrapModelCall: async (request, handler) => {
|
|
44070
43143
|
const taskPrompt = `## Task Management
|
|
44071
43144
|
|
|
@@ -44074,8 +43147,11 @@ ongoing record of a GOAL and its ACCEPTANCE CRITERIA.
|
|
|
44074
43147
|
|
|
44075
43148
|
### When to create a task
|
|
44076
43149
|
- Agent-owned work is multi-step and needs a persistent contract and plan ->
|
|
44077
|
-
create the parent task FIRST (a \`pending\` record), then
|
|
44078
|
-
|
|
43150
|
+
create the parent task FIRST (a \`pending\` record), then process it in this run;
|
|
43151
|
+
mark it \`in_progress\` with \`manage_task set_status\` when you start, and
|
|
43152
|
+
\`completed\` when the acceptance criteria are met. To bring in an
|
|
43153
|
+
expert, create a subtask and dispatch it with \`task { taskId, agentId }\` \u2014 never
|
|
43154
|
+
re-dispatch the task you are processing.
|
|
44079
43155
|
- Persistence is useful for resumption, review, or visibility across the
|
|
44080
43156
|
independently verifiable business results.
|
|
44081
43157
|
|
|
@@ -44105,13 +43181,17 @@ ${TASK_CONVERGENCE_GUIDANCE}
|
|
|
44105
43181
|
- No params: ownerType defaults to "user" with current user's ID
|
|
44106
43182
|
- ownerType="agent": auto-fills ownerId from current agent (subtask for yourself)
|
|
44107
43183
|
- Explicit ownerId: assign to a specific agent or user`;
|
|
43184
|
+
const boundTaskId = request.state?.taskId;
|
|
43185
|
+
const binding = typeof boundTaskId === "string" && boundTaskId ? renderTaskBinding(boundTaskId) : "";
|
|
43186
|
+
const rc = readRuntimeRunConfig(request.runtime);
|
|
43187
|
+
const executors = await renderAvailableExecutors(rc, rc.tenantId || "default");
|
|
44108
43188
|
return handler({
|
|
44109
43189
|
...request,
|
|
44110
|
-
systemPrompt: taskPrompt + "\n\n" + (request.systemPrompt ?? "")
|
|
43190
|
+
systemPrompt: taskPrompt + binding + executors + "\n\n" + (request.systemPrompt ?? "")
|
|
44111
43191
|
});
|
|
44112
43192
|
},
|
|
44113
43193
|
tools: [
|
|
44114
|
-
|
|
43194
|
+
tool64(
|
|
44115
43195
|
handleManageTask,
|
|
44116
43196
|
{
|
|
44117
43197
|
name: "manage_task",
|
|
@@ -44132,15 +43212,14 @@ ${TASK_CONVERGENCE_GUIDANCE}
|
|
|
44132
43212
|
- update: Update a task's content fields (title/description/priority/dueDate/metadata/parentId/sourceId/context/ownerId/result/failureReason/requireReview/dependencies/files)
|
|
44133
43213
|
Status changes can also be done here, but use set_status for a simpler dedicated status update.
|
|
44134
43214
|
- set_status: Change a task's status (id and status required). Use this when you only need to change the status.
|
|
44135
|
-
|
|
44136
|
-
|
|
44137
|
-
To mark complete: set_status with status='completed', result='...'
|
|
43215
|
+
Start processing a task you hold: set_status with status='in_progress' (the engine binds it to this run's thread).
|
|
43216
|
+
To mark complete: set_status with status='completed', result='...' (the task must be in_progress)
|
|
44138
43217
|
To mark failed: set_status with status='failed', failureReason='...'
|
|
44139
43218
|
To pause for input: set_status with status='interrupted', summary='what is needed'
|
|
44140
|
-
|
|
43219
|
+
Valid status values: pending, in_progress, review, failed, interrupted, completed, cancelled.
|
|
44141
43220
|
set_status only changes the record; it never dispatches execution (only the \`task\` tool does).
|
|
44142
43221
|
- add_activity: Add a Markdown activity without changing task fields or status (id and content required)
|
|
44143
|
-
- delete: Delete
|
|
43222
|
+
- delete: Delete one task by id, or a batch with ids (best-effort per id; returns deleted/failed lists). At least one of id/ids is required.
|
|
44144
43223
|
|
|
44145
43224
|
## Agent completion beliefs
|
|
44146
43225
|
Completing an agent-owned task MAY include a beliefImpact array reporting which
|
|
@@ -44151,14 +43230,16 @@ Report existing keys directly; set 'isNew: true' to add a key the owner does not
|
|
|
44151
43230
|
track yet. Belief is evidence metadata: it never blocks a completion, and an
|
|
44152
43231
|
unmatched or malformed entry is recorded without changing the owner's table.
|
|
44153
43232
|
Create always persists a pending record \u2014 a supplied status is coerced and no
|
|
44154
|
-
execution is dispatched.
|
|
44155
|
-
|
|
43233
|
+
execution is dispatched. When you start processing a task you hold, set it
|
|
43234
|
+
\`in_progress\` with \`manage_task set_status\`; a dispatched task is claimed
|
|
43235
|
+
automatically by the engine. Use \`task { taskId, agentId }\` to delegate a subtask
|
|
43236
|
+
to an expert \u2014 never re-dispatch the task you are processing.`,
|
|
44156
43237
|
schema: manageTaskSchema
|
|
44157
43238
|
}
|
|
44158
43239
|
),
|
|
44159
|
-
|
|
43240
|
+
tool64(handleStartTask, {
|
|
44160
43241
|
name: "task",
|
|
44161
|
-
description:
|
|
43242
|
+
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.`,
|
|
44162
43243
|
schema: startTaskSchema
|
|
44163
43244
|
})
|
|
44164
43245
|
]
|
|
@@ -44301,7 +43382,7 @@ canonical Belief State:
|
|
|
44301
43382
|
|
|
44302
43383
|
// src/middlewares/documentLearningMiddleware.ts
|
|
44303
43384
|
import { AgentType as AgentType9 } from "@axiom-lattice/protocols";
|
|
44304
|
-
import { createMiddleware as
|
|
43385
|
+
import { createMiddleware as createMiddleware24 } from "langchain";
|
|
44305
43386
|
|
|
44306
43387
|
// src/middlewares/documentLearningSkills.ts
|
|
44307
43388
|
var LEARN_CAPABILITY_SKILL = `---
|
|
@@ -44540,7 +43621,7 @@ patterns discovered, recommendations. Include validation coverage: user-sample N
|
|
|
44540
43621
|
`;
|
|
44541
43622
|
|
|
44542
43623
|
// src/middlewares/documentLearningMiddleware.ts
|
|
44543
|
-
var createDocumentLearningMiddleware = () =>
|
|
43624
|
+
var createDocumentLearningMiddleware = () => createMiddleware24({
|
|
44544
43625
|
name: "DocumentLearningMiddleware",
|
|
44545
43626
|
contextSchema,
|
|
44546
43627
|
tools: []
|
|
@@ -44658,12 +43739,12 @@ var documentLearningPlugin = {
|
|
|
44658
43739
|
};
|
|
44659
43740
|
|
|
44660
43741
|
// src/middlewares/documentParserMiddleware.ts
|
|
44661
|
-
import { createMiddleware as
|
|
43742
|
+
import { createMiddleware as createMiddleware25 } from "langchain";
|
|
44662
43743
|
|
|
44663
43744
|
// src/tool_lattice/document_parser/index.ts
|
|
44664
43745
|
import * as path7 from "path";
|
|
44665
|
-
import
|
|
44666
|
-
import { tool as
|
|
43746
|
+
import z71 from "zod";
|
|
43747
|
+
import { tool as tool65 } from "langchain";
|
|
44667
43748
|
var PARSE_DOCUMENT_DESCRIPTION = `Parse a document file (docx, pdf) into structured Markdown using a remote document parsing service.
|
|
44668
43749
|
This tool handles the full pipeline internally: file upload \u2192 document parsing \u2192 polling until complete \u2192 download result \u2192 save to filesystem.
|
|
44669
43750
|
|
|
@@ -44786,7 +43867,7 @@ function createParseDocumentTool({
|
|
|
44786
43867
|
baseUrl = "",
|
|
44787
43868
|
apiKey = ""
|
|
44788
43869
|
}) {
|
|
44789
|
-
return
|
|
43870
|
+
return tool65(
|
|
44790
43871
|
async (input, exe_config) => {
|
|
44791
43872
|
try {
|
|
44792
43873
|
const runConfig = exe_config?.configurable?.runConfig ?? { assistant_id: "", thread_id: "" };
|
|
@@ -44857,17 +43938,17 @@ function createParseDocumentTool({
|
|
|
44857
43938
|
{
|
|
44858
43939
|
name: "parse_document",
|
|
44859
43940
|
description: PARSE_DOCUMENT_DESCRIPTION,
|
|
44860
|
-
schema:
|
|
44861
|
-
file_path:
|
|
43941
|
+
schema: z71.object({
|
|
43942
|
+
file_path: z71.string().describe(
|
|
44862
43943
|
'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.'
|
|
44863
43944
|
),
|
|
44864
|
-
engine:
|
|
43945
|
+
engine: z71.string().describe(
|
|
44865
43946
|
'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).'
|
|
44866
43947
|
),
|
|
44867
|
-
output_path:
|
|
43948
|
+
output_path: z71.string().optional().describe(
|
|
44868
43949
|
'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.'
|
|
44869
43950
|
),
|
|
44870
|
-
output_format:
|
|
43951
|
+
output_format: z71.enum(["markdown", "json"]).optional().default("markdown").describe(
|
|
44871
43952
|
'Output format. "markdown": structured Markdown with tables, headers, formatting preserved (recommended). "json": raw JSON output from the parsing engine (for programmatic use).'
|
|
44872
43953
|
)
|
|
44873
43954
|
})
|
|
@@ -45285,7 +44366,7 @@ def main() -> None:
|
|
|
45285
44366
|
if __name__ == "__main__":
|
|
45286
44367
|
main()
|
|
45287
44368
|
`;
|
|
45288
|
-
var
|
|
44369
|
+
var resources = {
|
|
45289
44370
|
"references/api_reference.md": { mimeType: "text/markdown", content: `# API reference
|
|
45290
44371
|
|
|
45291
44372
|
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.` },
|
|
@@ -45314,7 +44395,7 @@ Single file: 'markitdown input -o output.md'. Ordinary directory: 'scripts/batch
|
|
|
45314
44395
|
var DOCUMENT_PARSER_MARKITDOWN_SKILL = {
|
|
45315
44396
|
version: "1.1.0",
|
|
45316
44397
|
content: MARKITDOWN_SKILL_CONTENT,
|
|
45317
|
-
resources
|
|
44398
|
+
resources
|
|
45318
44399
|
};
|
|
45319
44400
|
|
|
45320
44401
|
// src/middlewares/documentParserMiddleware.ts
|
|
@@ -45323,7 +44404,7 @@ function createDocumentParserMiddleware(config) {
|
|
|
45323
44404
|
const baseUrl = config.baseUrl || "";
|
|
45324
44405
|
const apiKey = config.apiKey || "";
|
|
45325
44406
|
const connections = Array.isArray(config.connections) ? config.connections.filter((key5) => typeof key5 === "string") : [];
|
|
45326
|
-
return
|
|
44407
|
+
return createMiddleware25({
|
|
45327
44408
|
name: "DocumentParser",
|
|
45328
44409
|
contextSchema,
|
|
45329
44410
|
tools: [createParseDocumentTool({ connectAll, connections, baseUrl, apiKey })]
|
|
@@ -45444,8 +44525,8 @@ import {
|
|
|
45444
44525
|
snapshotExactArray as snapshotExactArray3,
|
|
45445
44526
|
snapshotExactRecord as snapshotExactRecord8
|
|
45446
44527
|
} from "@axiom-lattice/protocols";
|
|
45447
|
-
import { createMiddleware as
|
|
45448
|
-
import { z as
|
|
44528
|
+
import { createMiddleware as createMiddleware26, tool as tool66 } from "langchain";
|
|
44529
|
+
import { z as z72 } from "zod";
|
|
45449
44530
|
var PROJECT_ROOM_CONTEXT_REQUIRED = "PROJECT_ROOM_CONTEXT_REQUIRED";
|
|
45450
44531
|
var PROJECT_ROOM_POST_FAILED = "PROJECT_ROOM_POST_FAILED";
|
|
45451
44532
|
var PROJECT_ROOM_ROSTER_FAILED = "PROJECT_ROOM_ROSTER_FAILED";
|
|
@@ -45465,10 +44546,10 @@ var ROSTER_FAILED = JSON.stringify({
|
|
|
45465
44546
|
error: PROJECT_ROOM_ROSTER_FAILED,
|
|
45466
44547
|
message: PROJECT_ROOM_ROSTER_FAILED_MESSAGE
|
|
45467
44548
|
});
|
|
45468
|
-
var postSchema =
|
|
45469
|
-
text:
|
|
44549
|
+
var postSchema = z72.object({
|
|
44550
|
+
text: z72.string().trim().min(1).max(2e4)
|
|
45470
44551
|
}).strict();
|
|
45471
|
-
var listSchema =
|
|
44552
|
+
var listSchema = z72.object({}).strict();
|
|
45472
44553
|
function ownDataValue2(record, key5) {
|
|
45473
44554
|
if (typeof record !== "object" || record === null || Array.isArray(record)) return void 0;
|
|
45474
44555
|
try {
|
|
@@ -45535,10 +44616,10 @@ async function hasActiveCurrentMembership(scope) {
|
|
|
45535
44616
|
return true;
|
|
45536
44617
|
}
|
|
45537
44618
|
function createProjectRoomMiddleware() {
|
|
45538
|
-
return
|
|
44619
|
+
return createMiddleware26({
|
|
45539
44620
|
name: "ProjectRoomMiddleware",
|
|
45540
44621
|
tools: [
|
|
45541
|
-
|
|
44622
|
+
tool66(async (input, config) => {
|
|
45542
44623
|
const { text } = input;
|
|
45543
44624
|
const scope = readTrustedRoomScope(config);
|
|
45544
44625
|
if (!scope) return CONTEXT_REQUIRED;
|
|
@@ -45569,7 +44650,7 @@ function createProjectRoomMiddleware() {
|
|
|
45569
44650
|
description: "Post a text reply to the current trusted Project Room message",
|
|
45570
44651
|
schema: postSchema
|
|
45571
44652
|
}),
|
|
45572
|
-
|
|
44653
|
+
tool66(async (_input, config) => {
|
|
45573
44654
|
const scope = readTrustedRoomScope(config);
|
|
45574
44655
|
if (!scope) return CONTEXT_REQUIRED;
|
|
45575
44656
|
try {
|
|
@@ -45611,8 +44692,8 @@ var projectRoomPlugin = {
|
|
|
45611
44692
|
};
|
|
45612
44693
|
|
|
45613
44694
|
// src/middlewares/sandboxPluginsMiddleware.ts
|
|
45614
|
-
import { createMiddleware as
|
|
45615
|
-
import { z as
|
|
44695
|
+
import { createMiddleware as createMiddleware27, tool as tool67 } from "langchain";
|
|
44696
|
+
import { z as z73 } from "zod";
|
|
45616
44697
|
import { AgentType as AgentType11 } from "@axiom-lattice/protocols";
|
|
45617
44698
|
|
|
45618
44699
|
// src/middlewares/sandboxPluginsSkills.ts
|
|
@@ -46334,16 +45415,16 @@ function tenantIdFrom(exeConfig) {
|
|
|
46334
45415
|
const c = exeConfig;
|
|
46335
45416
|
return c?.configurable?.runConfig?.tenantId ?? "default";
|
|
46336
45417
|
}
|
|
46337
|
-
var managePluginSchema =
|
|
46338
|
-
action:
|
|
46339
|
-
type:
|
|
46340
|
-
manifest:
|
|
46341
|
-
handlers:
|
|
46342
|
-
target:
|
|
46343
|
-
kind:
|
|
46344
|
-
name:
|
|
46345
|
-
input:
|
|
46346
|
-
connectionKey:
|
|
45418
|
+
var managePluginSchema = z73.object({
|
|
45419
|
+
action: z73.enum(["list", "get", "validate", "create", "update", "delete", "reload", "test"]),
|
|
45420
|
+
type: z73.string().optional(),
|
|
45421
|
+
manifest: z73.record(z73.unknown()).optional(),
|
|
45422
|
+
handlers: z73.record(z73.string()).optional(),
|
|
45423
|
+
target: z73.object({
|
|
45424
|
+
kind: z73.enum(["tool", "connection-test", "connection-discover"]),
|
|
45425
|
+
name: z73.string().optional(),
|
|
45426
|
+
input: z73.unknown().optional(),
|
|
45427
|
+
connectionKey: z73.string().optional()
|
|
46347
45428
|
}).optional()
|
|
46348
45429
|
});
|
|
46349
45430
|
var sandboxPluginsPlugin = {
|
|
@@ -46417,10 +45498,10 @@ var sandboxPluginsPlugin = {
|
|
|
46417
45498
|
]
|
|
46418
45499
|
}
|
|
46419
45500
|
},
|
|
46420
|
-
middleware: () =>
|
|
45501
|
+
middleware: () => createMiddleware27({
|
|
46421
45502
|
name: "SandboxPluginsMiddleware",
|
|
46422
45503
|
tools: [
|
|
46423
|
-
|
|
45504
|
+
tool67(
|
|
46424
45505
|
async (input, exeConfig) => {
|
|
46425
45506
|
const tenantId2 = tenantIdFrom(exeConfig);
|
|
46426
45507
|
const catalog2 = getSandboxPluginCatalog();
|
|
@@ -46561,7 +45642,6 @@ var BUILTIN_PLUGINS = [
|
|
|
46561
45642
|
sqlPlugin,
|
|
46562
45643
|
skillPlugin,
|
|
46563
45644
|
metricsPlugin,
|
|
46564
|
-
semanticMetricsPlugin,
|
|
46565
45645
|
askUserClarifyPlugin,
|
|
46566
45646
|
widgetPlugin,
|
|
46567
45647
|
clawPlugin,
|
|
@@ -47129,6 +46209,7 @@ export {
|
|
|
47129
46209
|
TaskLifecycleNotifier,
|
|
47130
46210
|
TaskLifecycleService,
|
|
47131
46211
|
TaskRunBridgeStoresRequiredError,
|
|
46212
|
+
TaskRunRegistry,
|
|
47132
46213
|
TaskStatus,
|
|
47133
46214
|
TeamAgentGraphBuilder,
|
|
47134
46215
|
TenantPluginCatalog,
|
|
@@ -47140,7 +46221,6 @@ export {
|
|
|
47140
46221
|
VectorStoreProviderManager,
|
|
47141
46222
|
VolumeFilesystem,
|
|
47142
46223
|
abortWorkflowRun,
|
|
47143
|
-
agentHasManagedTaskCapability,
|
|
47144
46224
|
agentInstanceManager,
|
|
47145
46225
|
agentLatticeManager,
|
|
47146
46226
|
appendReconciliationWarning,
|
|
@@ -47193,7 +46273,6 @@ export {
|
|
|
47193
46273
|
createSandboxProvider,
|
|
47194
46274
|
createSandboxResolver,
|
|
47195
46275
|
createSchedulerMiddleware,
|
|
47196
|
-
createSemanticMetricsMiddleware,
|
|
47197
46276
|
createSharePayload,
|
|
47198
46277
|
createTaskExecutionService,
|
|
47199
46278
|
createTaskLifecycleService,
|
|
@@ -47315,6 +46394,9 @@ export {
|
|
|
47315
46394
|
projectTaskAdmissionNotifier,
|
|
47316
46395
|
queueLatticeManager,
|
|
47317
46396
|
readLoopBreakerConfig,
|
|
46397
|
+
reconcileAllTenantTaskRuns,
|
|
46398
|
+
reconcileStaleTaskRuns,
|
|
46399
|
+
reconcileTenantTaskRuns,
|
|
47318
46400
|
registerAgentLattice,
|
|
47319
46401
|
registerAgentLatticeWithTenant,
|
|
47320
46402
|
registerAgentLattices,
|
|
@@ -47349,7 +46431,6 @@ export {
|
|
|
47349
46431
|
sandboxLatticeManager,
|
|
47350
46432
|
sanitizeToolCallId,
|
|
47351
46433
|
scheduleLatticeManager,
|
|
47352
|
-
semanticMetricsPlugin,
|
|
47353
46434
|
serializePluginMeta,
|
|
47354
46435
|
serializeTaskMutationSuccess,
|
|
47355
46436
|
serializeTaskNormalizationFallback,
|
|
@@ -47363,6 +46444,7 @@ export {
|
|
|
47363
46444
|
storeLatticeManager,
|
|
47364
46445
|
sttModelLatticeManager,
|
|
47365
46446
|
taskLifecycleNotifier,
|
|
46447
|
+
taskRunRegistry,
|
|
47366
46448
|
toJsonSchema,
|
|
47367
46449
|
toSafeStateExpr,
|
|
47368
46450
|
toolLatticeManager,
|