@axiom-lattice/core 5.0.0 → 6.1.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 +273 -24
- package/dist/index.d.ts +273 -24
- package/dist/index.js +671 -285
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +666 -284
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -50,6 +50,17 @@ var ModelLattice = class extends BaseChatModel {
|
|
|
50
50
|
this.config = config;
|
|
51
51
|
this.llm = this.initChatModel(config);
|
|
52
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* 返回构造时使用的配置
|
|
55
|
+
*
|
|
56
|
+
* 供调用方(如 models 控制器)读取 apiKey 是否存在、以及展示元数据,
|
|
57
|
+
* 避免反射读取私有字段。
|
|
58
|
+
*
|
|
59
|
+
* @returns 构造时传入的 LLMConfig
|
|
60
|
+
*/
|
|
61
|
+
getConfig() {
|
|
62
|
+
return this.config;
|
|
63
|
+
}
|
|
53
64
|
/**
|
|
54
65
|
* 返回模型类型
|
|
55
66
|
*/
|
|
@@ -189,6 +200,9 @@ var ModelLattice = class extends BaseChatModel {
|
|
|
189
200
|
maxRetries: config.maxRetries || 2,
|
|
190
201
|
streaming: config.streaming,
|
|
191
202
|
reasoning: { effort: "none" },
|
|
203
|
+
// Responses API and Chat Completions are different paths with different
|
|
204
|
+
// request fields; an endpoint that supports only one rejects the other.
|
|
205
|
+
...config.useResponsesApi ? { useResponsesApi: true } : {},
|
|
192
206
|
apiKey: config.apiKey || process.env[config.apiKeyEnvName || "OPENAI_API_KEY"],
|
|
193
207
|
configuration: {
|
|
194
208
|
baseURL: config.baseURL
|
|
@@ -279,9 +293,74 @@ var ModelLatticeManager = class _ModelLatticeManager extends BaseLatticeManager
|
|
|
279
293
|
getLatticeKeys() {
|
|
280
294
|
return this.keys();
|
|
281
295
|
}
|
|
296
|
+
// ========== 租户维度 API ==========
|
|
297
|
+
// 键由基类拼装为 models:{tenantId}:{key}。注意 "default" 租户的键与旧版
|
|
298
|
+
// key-only API 完全一致(models:default:{key}),因此对该租户是逐字节兼容的。
|
|
299
|
+
/**
|
|
300
|
+
* 以租户维度注册模型Lattice
|
|
301
|
+
*
|
|
302
|
+
* 同名 key 采用「后写覆盖」语义:先移除再注册,避免基类重复注册时抛错。
|
|
303
|
+
*
|
|
304
|
+
* @param tenantId 租户ID
|
|
305
|
+
* @param key Lattice键名
|
|
306
|
+
* @param config 模型配置
|
|
307
|
+
*/
|
|
308
|
+
registerLatticeWithTenant(tenantId2, key5, config) {
|
|
309
|
+
const client = new ModelLattice(config);
|
|
310
|
+
const modelLattice = {
|
|
311
|
+
key: key5,
|
|
312
|
+
client
|
|
313
|
+
};
|
|
314
|
+
if (this.hasWithTenant(tenantId2, key5)) {
|
|
315
|
+
this.removeWithTenant(tenantId2, key5);
|
|
316
|
+
}
|
|
317
|
+
this.registerWithTenant(tenantId2, key5, modelLattice);
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 获取指定租户的模型Lattice
|
|
321
|
+
* @param tenantId 租户ID
|
|
322
|
+
* @param key Lattice键名
|
|
323
|
+
*/
|
|
324
|
+
getModelLatticeWithTenant(tenantId2, key5) {
|
|
325
|
+
return this.getWithTenant(tenantId2, key5);
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* 检查指定租户的模型Lattice是否存在
|
|
329
|
+
* @param tenantId 租户ID
|
|
330
|
+
* @param key Lattice键名
|
|
331
|
+
*/
|
|
332
|
+
hasLatticeWithTenant(tenantId2, key5) {
|
|
333
|
+
return this.hasWithTenant(tenantId2, key5);
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* 获取指定租户的所有模型Lattice
|
|
337
|
+
* @param tenantId 租户ID
|
|
338
|
+
*/
|
|
339
|
+
getAllLatticesByTenant(tenantId2) {
|
|
340
|
+
return this.getAllByTenant(tenantId2);
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* 获取指定租户的所有模型键名
|
|
344
|
+
*
|
|
345
|
+
* 只返回键名,不构造 Lattice 对象数组,适合仅需判断存在性的调用方。
|
|
346
|
+
*
|
|
347
|
+
* @param tenantId 租户ID
|
|
348
|
+
*/
|
|
349
|
+
getLatticeKeysByTenant(tenantId2) {
|
|
350
|
+
return this.keysByTenant(tenantId2);
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* 移除指定租户的模型Lattice
|
|
354
|
+
* @param tenantId 租户ID
|
|
355
|
+
* @param key Lattice键名
|
|
356
|
+
*/
|
|
357
|
+
removeLatticeWithTenant(tenantId2, key5) {
|
|
358
|
+
return this.removeWithTenant(tenantId2, key5);
|
|
359
|
+
}
|
|
282
360
|
};
|
|
283
361
|
var modelLatticeManager = ModelLatticeManager.getInstance();
|
|
284
362
|
var registerModelLattice = (key5, config) => modelLatticeManager.registerLattice(key5, config);
|
|
363
|
+
var registerModelLatticeForTenant = (tenantId2, key5, config) => modelLatticeManager.registerLatticeWithTenant(tenantId2, key5, config);
|
|
285
364
|
var getModelLattice = (key5) => modelLatticeManager.getModelLattice(key5);
|
|
286
365
|
|
|
287
366
|
// src/tool_lattice/get_current_date_time/index.ts
|
|
@@ -2013,6 +2092,240 @@ var InMemoryMcpServerConfigStore = class {
|
|
|
2013
2092
|
}
|
|
2014
2093
|
};
|
|
2015
2094
|
|
|
2095
|
+
// src/store_lattice/InMemoryModelProviderStore.ts
|
|
2096
|
+
var InMemoryModelProviderStore = class {
|
|
2097
|
+
constructor() {
|
|
2098
|
+
this.providers = /* @__PURE__ */ new Map();
|
|
2099
|
+
this.models = /* @__PURE__ */ new Map();
|
|
2100
|
+
}
|
|
2101
|
+
/**
|
|
2102
|
+
* Get composite key for providers
|
|
2103
|
+
*/
|
|
2104
|
+
getProviderKey(tenantId2, id) {
|
|
2105
|
+
return `${tenantId2}:${id}`;
|
|
2106
|
+
}
|
|
2107
|
+
/**
|
|
2108
|
+
* Get composite key for snapshot models
|
|
2109
|
+
*/
|
|
2110
|
+
getModelKey(tenantId2, providerId, modelId) {
|
|
2111
|
+
return `${tenantId2}:${providerId}:${modelId}`;
|
|
2112
|
+
}
|
|
2113
|
+
/**
|
|
2114
|
+
* Get all provider configurations for a tenant
|
|
2115
|
+
*/
|
|
2116
|
+
async listProviders(tenantId2) {
|
|
2117
|
+
return Array.from(this.providers.values()).filter(
|
|
2118
|
+
(provider) => provider.tenantId === tenantId2
|
|
2119
|
+
);
|
|
2120
|
+
}
|
|
2121
|
+
/**
|
|
2122
|
+
* Get a provider configuration by ID
|
|
2123
|
+
*/
|
|
2124
|
+
async getProviderById(tenantId2, id) {
|
|
2125
|
+
return this.providers.get(this.getProviderKey(tenantId2, id)) || null;
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Get a provider configuration by business name
|
|
2129
|
+
*/
|
|
2130
|
+
async getProviderByName(tenantId2, name) {
|
|
2131
|
+
const providers = await this.listProviders(tenantId2);
|
|
2132
|
+
return providers.find((provider) => provider.name === name) || null;
|
|
2133
|
+
}
|
|
2134
|
+
/**
|
|
2135
|
+
* Create a new provider configuration
|
|
2136
|
+
*/
|
|
2137
|
+
async createProvider(tenantId2, id, data) {
|
|
2138
|
+
const now = /* @__PURE__ */ new Date();
|
|
2139
|
+
const entry = {
|
|
2140
|
+
id,
|
|
2141
|
+
tenantId: tenantId2,
|
|
2142
|
+
name: data.name,
|
|
2143
|
+
displayName: data.displayName,
|
|
2144
|
+
protocol: data.protocol,
|
|
2145
|
+
apiStyle: data.apiStyle ?? "chat-completions",
|
|
2146
|
+
// Phase 1 pins the LLM provider: the UI does not offer a choice, and some
|
|
2147
|
+
// initChatModel branches hardcode their own baseURL and would silently
|
|
2148
|
+
// ignore the tenant's (see ADR-138 decision 7b).
|
|
2149
|
+
llmProvider: "openai",
|
|
2150
|
+
baseURL: data.baseURL,
|
|
2151
|
+
apiKey: data.apiKey || void 0,
|
|
2152
|
+
apiKeyHint: data.apiKey ? data.apiKey.slice(-4) : void 0,
|
|
2153
|
+
enabled: data.enabled ?? true,
|
|
2154
|
+
status: "unknown",
|
|
2155
|
+
createdAt: now,
|
|
2156
|
+
updatedAt: now
|
|
2157
|
+
};
|
|
2158
|
+
this.providers.set(this.getProviderKey(tenantId2, id), entry);
|
|
2159
|
+
return entry;
|
|
2160
|
+
}
|
|
2161
|
+
/**
|
|
2162
|
+
* Update an existing provider configuration.
|
|
2163
|
+
* An omitted or empty `apiKey` leaves the stored key untouched.
|
|
2164
|
+
*/
|
|
2165
|
+
async updateProvider(tenantId2, id, updates) {
|
|
2166
|
+
const key5 = this.getProviderKey(tenantId2, id);
|
|
2167
|
+
const existing = this.providers.get(key5);
|
|
2168
|
+
if (!existing) {
|
|
2169
|
+
return null;
|
|
2170
|
+
}
|
|
2171
|
+
const hasNewApiKey = Boolean(updates.apiKey);
|
|
2172
|
+
const clearsApiKey = updates.clearApiKey === true;
|
|
2173
|
+
const updated = {
|
|
2174
|
+
...existing,
|
|
2175
|
+
name: updates.name ?? existing.name,
|
|
2176
|
+
displayName: updates.displayName !== void 0 ? updates.displayName : existing.displayName,
|
|
2177
|
+
protocol: updates.protocol ?? existing.protocol,
|
|
2178
|
+
apiStyle: updates.apiStyle ?? existing.apiStyle,
|
|
2179
|
+
baseURL: updates.baseURL ?? existing.baseURL,
|
|
2180
|
+
apiKey: clearsApiKey ? void 0 : hasNewApiKey ? updates.apiKey : existing.apiKey,
|
|
2181
|
+
apiKeyHint: clearsApiKey ? void 0 : hasNewApiKey ? updates.apiKey?.slice(-4) : existing.apiKeyHint,
|
|
2182
|
+
enabled: updates.enabled ?? existing.enabled,
|
|
2183
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2184
|
+
};
|
|
2185
|
+
this.providers.set(key5, updated);
|
|
2186
|
+
return updated;
|
|
2187
|
+
}
|
|
2188
|
+
/**
|
|
2189
|
+
* Delete a provider configuration and its model snapshot
|
|
2190
|
+
*/
|
|
2191
|
+
async deleteProvider(tenantId2, id) {
|
|
2192
|
+
await this.deleteModelsByProvider(tenantId2, id);
|
|
2193
|
+
return this.providers.delete(this.getProviderKey(tenantId2, id));
|
|
2194
|
+
}
|
|
2195
|
+
/**
|
|
2196
|
+
* Record the outcome of a discovery attempt
|
|
2197
|
+
*/
|
|
2198
|
+
async markProviderStatus(tenantId2, id, status, lastError, discoveredAt) {
|
|
2199
|
+
const key5 = this.getProviderKey(tenantId2, id);
|
|
2200
|
+
const existing = this.providers.get(key5);
|
|
2201
|
+
if (!existing) {
|
|
2202
|
+
return;
|
|
2203
|
+
}
|
|
2204
|
+
this.providers.set(key5, {
|
|
2205
|
+
...existing,
|
|
2206
|
+
status,
|
|
2207
|
+
lastError: status === "ok" ? void 0 : lastError,
|
|
2208
|
+
lastDiscoveredAt: discoveredAt ?? existing.lastDiscoveredAt,
|
|
2209
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
2210
|
+
});
|
|
2211
|
+
}
|
|
2212
|
+
/**
|
|
2213
|
+
* List snapshot models for a tenant
|
|
2214
|
+
*/
|
|
2215
|
+
async listModels(tenantId2, providerId) {
|
|
2216
|
+
return Array.from(this.models.values()).filter(
|
|
2217
|
+
(model) => model.tenantId === tenantId2 && (providerId === void 0 || model.providerId === providerId)
|
|
2218
|
+
);
|
|
2219
|
+
}
|
|
2220
|
+
/**
|
|
2221
|
+
* Get a single snapshot model.
|
|
2222
|
+
* Keyed by provider as well as model id, since two providers in the same
|
|
2223
|
+
* tenant may expose the same upstream model id.
|
|
2224
|
+
*/
|
|
2225
|
+
async getModel(tenantId2, providerId, modelId) {
|
|
2226
|
+
return this.models.get(this.getModelKey(tenantId2, providerId, modelId)) || null;
|
|
2227
|
+
}
|
|
2228
|
+
/**
|
|
2229
|
+
* Replace a provider's model snapshot with the result of one discovery.
|
|
2230
|
+
*
|
|
2231
|
+
* Model ids are scoped per provider, so the same upstream id may appear
|
|
2232
|
+
* under several providers in one tenant — each is an independent model.
|
|
2233
|
+
*
|
|
2234
|
+
* Models the upstream no longer offers are removed; models that survive keep
|
|
2235
|
+
* the tenant's enable/disable choice rather than being reset.
|
|
2236
|
+
*/
|
|
2237
|
+
async replaceProviderModels(tenantId2, providerId, models) {
|
|
2238
|
+
const previous = await this.listModels(tenantId2, providerId);
|
|
2239
|
+
const previousById = new Map(
|
|
2240
|
+
previous.map((model) => [model.modelId, model])
|
|
2241
|
+
);
|
|
2242
|
+
const incomingIds = new Set(models.map((model) => model.id));
|
|
2243
|
+
for (const model of previous) {
|
|
2244
|
+
if (!incomingIds.has(model.modelId)) {
|
|
2245
|
+
this.models.delete(
|
|
2246
|
+
this.getModelKey(tenantId2, providerId, model.modelId)
|
|
2247
|
+
);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
const now = /* @__PURE__ */ new Date();
|
|
2251
|
+
const upserted = [];
|
|
2252
|
+
for (const model of models) {
|
|
2253
|
+
const existing = previousById.get(model.id);
|
|
2254
|
+
const entry = {
|
|
2255
|
+
id: `${providerId}:${model.id}`,
|
|
2256
|
+
tenantId: tenantId2,
|
|
2257
|
+
providerId,
|
|
2258
|
+
modelId: model.id,
|
|
2259
|
+
displayName: model.displayName,
|
|
2260
|
+
ownedBy: model.ownedBy,
|
|
2261
|
+
upstreamCreatedAt: model.createdAt ? new Date(model.createdAt) : void 0,
|
|
2262
|
+
// An explicit `enabled` from the caller wins; discovery omits it and
|
|
2263
|
+
// the tenant's earlier choice is preserved.
|
|
2264
|
+
enabled: model.enabled ?? existing?.enabled ?? true,
|
|
2265
|
+
// Unlike `enabled`, this is not preserved: a model present in the list
|
|
2266
|
+
// the caller just read is, by definition, no longer stale. Only an
|
|
2267
|
+
// explicit flag marks one.
|
|
2268
|
+
stale: model.stale ?? false,
|
|
2269
|
+
discoveredAt: now
|
|
2270
|
+
};
|
|
2271
|
+
this.models.set(this.getModelKey(tenantId2, providerId, model.id), entry);
|
|
2272
|
+
upserted.push(model.id);
|
|
2273
|
+
}
|
|
2274
|
+
return upserted;
|
|
2275
|
+
}
|
|
2276
|
+
/**
|
|
2277
|
+
* Enable or disable a single snapshot model
|
|
2278
|
+
*/
|
|
2279
|
+
async setModelEnabled(tenantId2, providerId, modelId, enabled) {
|
|
2280
|
+
const key5 = this.getModelKey(tenantId2, providerId, modelId);
|
|
2281
|
+
const existing = this.models.get(key5);
|
|
2282
|
+
if (!existing) {
|
|
2283
|
+
return null;
|
|
2284
|
+
}
|
|
2285
|
+
const updated = {
|
|
2286
|
+
...existing,
|
|
2287
|
+
enabled
|
|
2288
|
+
};
|
|
2289
|
+
this.models.set(key5, updated);
|
|
2290
|
+
return updated;
|
|
2291
|
+
}
|
|
2292
|
+
/**
|
|
2293
|
+
* Delete every snapshot model belonging to a provider
|
|
2294
|
+
*/
|
|
2295
|
+
async deleteModelsByProvider(tenantId2, providerId) {
|
|
2296
|
+
let deleted = 0;
|
|
2297
|
+
for (const [key5, model] of Array.from(this.models.entries())) {
|
|
2298
|
+
if (model.tenantId === tenantId2 && model.providerId === providerId) {
|
|
2299
|
+
this.models.delete(key5);
|
|
2300
|
+
deleted += 1;
|
|
2301
|
+
}
|
|
2302
|
+
}
|
|
2303
|
+
return deleted;
|
|
2304
|
+
}
|
|
2305
|
+
/**
|
|
2306
|
+
* Clear all providers and models (useful for testing)
|
|
2307
|
+
*/
|
|
2308
|
+
clear() {
|
|
2309
|
+
this.providers.clear();
|
|
2310
|
+
this.models.clear();
|
|
2311
|
+
}
|
|
2312
|
+
/**
|
|
2313
|
+
* Clear providers and models for a specific tenant
|
|
2314
|
+
*/
|
|
2315
|
+
clearByTenant(tenantId2) {
|
|
2316
|
+
for (const [key5, provider] of Array.from(this.providers.entries())) {
|
|
2317
|
+
if (provider.tenantId === tenantId2) {
|
|
2318
|
+
this.providers.delete(key5);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
for (const [key5, model] of Array.from(this.models.entries())) {
|
|
2322
|
+
if (model.tenantId === tenantId2) {
|
|
2323
|
+
this.models.delete(key5);
|
|
2324
|
+
}
|
|
2325
|
+
}
|
|
2326
|
+
}
|
|
2327
|
+
};
|
|
2328
|
+
|
|
2016
2329
|
// src/store_lattice/InMemoryAgentWebAppStore.ts
|
|
2017
2330
|
import { randomUUID } from "crypto";
|
|
2018
2331
|
function cloneAppearance(appearance) {
|
|
@@ -4501,6 +4814,7 @@ var defaultProjectStore = new InMemoryProjectStore(defaultCapabilityBundleCoordi
|
|
|
4501
4814
|
var defaultDatabaseConfigStore = new InMemoryDatabaseConfigStore();
|
|
4502
4815
|
var defaultMetricsServerConfigStore = new InMemoryMetricsServerConfigStore();
|
|
4503
4816
|
var defaultMcpServerConfigStore = new InMemoryMcpServerConfigStore();
|
|
4817
|
+
var defaultModelProviderStore = new InMemoryModelProviderStore();
|
|
4504
4818
|
var defaultAgentWebAppStore = new InMemoryAgentWebAppStore();
|
|
4505
4819
|
var defaultCapabilityBundleStore = new InMemoryCapabilityBundleStore(defaultProjectStore, defaultCapabilityBundleCoordinator);
|
|
4506
4820
|
var defaultProjectRoomCoordinator = new InMemoryProjectRoomCoordinator();
|
|
@@ -4522,6 +4836,7 @@ storeLatticeManager.registerLattice("default", "project", defaultProjectStore);
|
|
|
4522
4836
|
storeLatticeManager.registerLattice("default", "database", defaultDatabaseConfigStore);
|
|
4523
4837
|
storeLatticeManager.registerLattice("default", "metrics", defaultMetricsServerConfigStore);
|
|
4524
4838
|
storeLatticeManager.registerLattice("default", "mcp", defaultMcpServerConfigStore);
|
|
4839
|
+
storeLatticeManager.registerLattice("default", "modelProvider", defaultModelProviderStore);
|
|
4525
4840
|
storeLatticeManager.registerLattice("default", "agentWebApp", defaultAgentWebAppStore);
|
|
4526
4841
|
storeLatticeManager.registerLattice("default", "capabilityBundle", defaultCapabilityBundleStore);
|
|
4527
4842
|
storeLatticeManager.registerLattice("default", "projectRoom", defaultProjectRoomStore);
|
|
@@ -28847,7 +29162,7 @@ var agentArchitectConfig = {
|
|
|
28847
29162
|
"delete_agent",
|
|
28848
29163
|
"manage_binding"
|
|
28849
29164
|
],
|
|
28850
|
-
subAgents: ["document-parser-benchmark"],
|
|
29165
|
+
subAgents: ["document-parser", "document-parser-benchmark"],
|
|
28851
29166
|
middleware: [
|
|
28852
29167
|
{
|
|
28853
29168
|
id: "filesystem",
|
|
@@ -30552,6 +30867,7 @@ async function removeCollectionVectorStore(name, tenantId2) {
|
|
|
30552
30867
|
|
|
30553
30868
|
// src/mcp_lattice/McpLatticeManager.ts
|
|
30554
30869
|
import { MultiServerMCPClient } from "@langchain/mcp-adapters";
|
|
30870
|
+
import { DynamicStructuredTool as DynamicStructuredTool2 } from "@langchain/core/tools";
|
|
30555
30871
|
|
|
30556
30872
|
// src/mcp_lattice/reconnectPolicy.ts
|
|
30557
30873
|
var DEFAULT_CONNECT_TIMEOUT_MS = 15e3;
|
|
@@ -30560,6 +30876,13 @@ var DEFAULT_DELAY_MS = 1e3;
|
|
|
30560
30876
|
var MAX_BACKOFF_MS = 3e4;
|
|
30561
30877
|
var HEALTH_CHECK_INTERVAL_MS = 3e4;
|
|
30562
30878
|
var HEALTH_CHECK_TIMEOUT_MS = 5e3;
|
|
30879
|
+
function isMcpConnectionError(error) {
|
|
30880
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
30881
|
+
if (!message) return false;
|
|
30882
|
+
return /not connected|connection closed|session not found|no session|maximum reconnection/i.test(
|
|
30883
|
+
message
|
|
30884
|
+
);
|
|
30885
|
+
}
|
|
30563
30886
|
function nextBackoffDelay(attempt, base = DEFAULT_DELAY_MS, max = MAX_BACKOFF_MS) {
|
|
30564
30887
|
if (attempt <= 0) return base;
|
|
30565
30888
|
return Math.min(base * Math.pow(2, attempt - 1), max);
|
|
@@ -30584,12 +30907,21 @@ async function withTimeout(operation, ms, onTimeout) {
|
|
|
30584
30907
|
|
|
30585
30908
|
// src/mcp_lattice/McpLatticeManager.ts
|
|
30586
30909
|
var realClientFactory = ({ mcpServers }) => new MultiServerMCPClient({ mcpServers });
|
|
30910
|
+
function extractRawCall(tool68) {
|
|
30911
|
+
const rawCall = tool68._call;
|
|
30912
|
+
if (typeof rawCall === "function") return rawCall.bind(tool68);
|
|
30913
|
+
return async (...args) => {
|
|
30914
|
+
const invoke = tool68.invoke.bind(tool68);
|
|
30915
|
+
return invoke(args[0], args[2]);
|
|
30916
|
+
};
|
|
30917
|
+
}
|
|
30587
30918
|
var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
30588
30919
|
constructor() {
|
|
30589
30920
|
super(...arguments);
|
|
30590
30921
|
this.runtimes = /* @__PURE__ */ new Map();
|
|
30591
30922
|
this.clientFactory = realClientFactory;
|
|
30592
30923
|
this.healthCheckInFlight = false;
|
|
30924
|
+
this.reconnectPromises = /* @__PURE__ */ new Map();
|
|
30593
30925
|
}
|
|
30594
30926
|
static getInstance() {
|
|
30595
30927
|
if (!_McpLatticeManager._instance) {
|
|
@@ -30847,6 +31179,64 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
30847
31179
|
rt.attempt = 0;
|
|
30848
31180
|
await this.reconnectRuntime(rt);
|
|
30849
31181
|
}
|
|
31182
|
+
/**
|
|
31183
|
+
* Single-flight a forced reconnect per `(tenantId, serverKey)` so concurrent
|
|
31184
|
+
* tool calls that all hit the same dead session reconnect once, not once each.
|
|
31185
|
+
*/
|
|
31186
|
+
reconnectShared(rt) {
|
|
31187
|
+
const key5 = this.compositeKey(rt.id.tenantId, rt.id.serverKey);
|
|
31188
|
+
const existing = this.reconnectPromises.get(key5);
|
|
31189
|
+
if (existing) return existing;
|
|
31190
|
+
const work = this.reconnectServer(rt.id.tenantId, rt.id.serverKey).finally(() => {
|
|
31191
|
+
if (this.reconnectPromises.get(key5) === work) this.reconnectPromises.delete(key5);
|
|
31192
|
+
});
|
|
31193
|
+
this.reconnectPromises.set(key5, work);
|
|
31194
|
+
return work;
|
|
31195
|
+
}
|
|
31196
|
+
/**
|
|
31197
|
+
* Wrap a raw MCP tool so a call landing on a torn-down session
|
|
31198
|
+
* (`Not connected` / `Connection closed` / session expiry) transparently
|
|
31199
|
+
* forces a reconnect and retries once against the fresh client, instead of
|
|
31200
|
+
* failing the surrounding run. Non-connection errors propagate untouched.
|
|
31201
|
+
*/
|
|
31202
|
+
wrapToolForResilience(rt, raw) {
|
|
31203
|
+
const call = extractRawCall(raw);
|
|
31204
|
+
return new DynamicStructuredTool2({
|
|
31205
|
+
name: raw.name,
|
|
31206
|
+
description: raw.description,
|
|
31207
|
+
schema: raw.schema,
|
|
31208
|
+
responseFormat: raw.responseFormat,
|
|
31209
|
+
defaultConfig: raw.defaultConfig,
|
|
31210
|
+
metadata: raw.metadata,
|
|
31211
|
+
returnDirect: raw.returnDirect,
|
|
31212
|
+
func: async (...args) => this.invokeResilient(rt, raw.name, call, args)
|
|
31213
|
+
});
|
|
31214
|
+
}
|
|
31215
|
+
async invokeResilient(rt, toolName2, call, args) {
|
|
31216
|
+
try {
|
|
31217
|
+
await this.ensureConnected(rt.id.tenantId, rt.id.serverKey);
|
|
31218
|
+
return await call(...args);
|
|
31219
|
+
} catch (error) {
|
|
31220
|
+
if (!isMcpConnectionError(error) || !this.isActive(rt)) throw error;
|
|
31221
|
+
console.warn(
|
|
31222
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: tool "${toolName2}" hit a dead session; reconnecting and retrying once`,
|
|
31223
|
+
error instanceof Error ? error.message : error
|
|
31224
|
+
);
|
|
31225
|
+
try {
|
|
31226
|
+
await this.reconnectShared(rt);
|
|
31227
|
+
} catch (reconnectError) {
|
|
31228
|
+
console.warn(
|
|
31229
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: reconnect for tool "${toolName2}" failed`,
|
|
31230
|
+
reconnectError instanceof Error ? reconnectError.message : reconnectError
|
|
31231
|
+
);
|
|
31232
|
+
throw error;
|
|
31233
|
+
}
|
|
31234
|
+
const fresh = await this.getRawTools(rt.id.tenantId, rt.id.serverKey);
|
|
31235
|
+
const match = fresh.find((t) => t.name === toolName2);
|
|
31236
|
+
if (!match) throw error;
|
|
31237
|
+
return await extractRawCall(match)(...args);
|
|
31238
|
+
}
|
|
31239
|
+
}
|
|
30850
31240
|
async checkHealth() {
|
|
30851
31241
|
if (this.healthCheckInFlight) return;
|
|
30852
31242
|
this.healthCheckInFlight = true;
|
|
@@ -30865,8 +31255,12 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
30865
31255
|
await withTimeout(session.listTools(), HEALTH_CHECK_TIMEOUT_MS, async () => {
|
|
30866
31256
|
});
|
|
30867
31257
|
if (!this.isActive(rt) || rt.state !== "connected") continue;
|
|
30868
|
-
} catch {
|
|
31258
|
+
} catch (error) {
|
|
30869
31259
|
if (this.isActive(rt) && rt.state === "connected") {
|
|
31260
|
+
console.warn(
|
|
31261
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: health check failed; scheduling reconnect`,
|
|
31262
|
+
error instanceof Error ? error.message : error
|
|
31263
|
+
);
|
|
30870
31264
|
rt.state = "failed";
|
|
30871
31265
|
this.scheduleReconnect(rt);
|
|
30872
31266
|
}
|
|
@@ -31072,7 +31466,8 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
31072
31466
|
const visibility = Array.isArray(rawVisibility) ? rawVisibility : typeof rawVisibility === "string" ? [rawVisibility] : void 0;
|
|
31073
31467
|
if (visibility && !visibility.includes("model")) continue;
|
|
31074
31468
|
const ref = extractAppsRef(meta, serverKey);
|
|
31075
|
-
const
|
|
31469
|
+
const resilient = this.wrapToolForResilience(rt, tool68);
|
|
31470
|
+
const registered = ref ? wrapMcpToolWithUi(resilient, ref) : resilient;
|
|
31076
31471
|
const toolKey = _McpLatticeManager.buildToolKey(serverKey, tool68.name);
|
|
31077
31472
|
try {
|
|
31078
31473
|
toolLatticeManager.registerExistingToolWithTenant(tenantId2, toolKey, registered);
|
|
@@ -31141,6 +31536,7 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
31141
31536
|
}
|
|
31142
31537
|
}
|
|
31143
31538
|
this.runtimes.clear();
|
|
31539
|
+
this.reconnectPromises.clear();
|
|
31144
31540
|
}
|
|
31145
31541
|
};
|
|
31146
31542
|
var mcpManager = McpLatticeManager.getInstance();
|
|
@@ -34291,13 +34687,16 @@ var LatticeEvalProject = class {
|
|
|
34291
34687
|
constructor(project, onCaseComplete) {
|
|
34292
34688
|
this.suites = /* @__PURE__ */ new Map();
|
|
34293
34689
|
this.project = project;
|
|
34294
|
-
const
|
|
34690
|
+
const tenantId2 = this.project.lattice_server_config.tenant_id || "default";
|
|
34691
|
+
const judgeModelKey = resolveJudgeModelKey(
|
|
34692
|
+
this.project.judge_agent_config.modelKey,
|
|
34693
|
+
modelLatticeManager
|
|
34694
|
+
);
|
|
34295
34695
|
if (!modelLatticeManager.hasLattice(judgeModelKey)) {
|
|
34296
34696
|
throw new Error(
|
|
34297
34697
|
`Judge model "${judgeModelKey}" not found. Register it first or provide a valid modelKey.`
|
|
34298
34698
|
);
|
|
34299
34699
|
}
|
|
34300
|
-
const tenantId2 = this.project.lattice_server_config.tenant_id || "default";
|
|
34301
34700
|
this.judgeAgentKey = `${this.project.projectName}_judge_agent`;
|
|
34302
34701
|
const judgeAgentConfig = {
|
|
34303
34702
|
key: this.judgeAgentKey,
|
|
@@ -35240,7 +35639,7 @@ function snapshotDate(value) {
|
|
|
35240
35639
|
|
|
35241
35640
|
// src/services/TaskLifecycleService.ts
|
|
35242
35641
|
import { createHash as createHash6 } from "crypto";
|
|
35243
|
-
import { parseTaskBeliefState, replaceTaskBeliefState,
|
|
35642
|
+
import { parseTaskBeliefState, replaceTaskBeliefState, taskBeliefStatesEqual } from "@axiom-lattice/protocols";
|
|
35244
35643
|
|
|
35245
35644
|
// src/middlewares/taskBelief.ts
|
|
35246
35645
|
import { createHash as createHash5 } from "crypto";
|
|
@@ -35352,14 +35751,6 @@ async function applyBeliefImpacts(taskStore, owner, impacts) {
|
|
|
35352
35751
|
}
|
|
35353
35752
|
return { description: current.description ?? "", task: current };
|
|
35354
35753
|
}
|
|
35355
|
-
function parseExternalDependency(value) {
|
|
35356
|
-
const row = snapshotExactRecord7(value, ["type", "summary", "requestedAt", "dependencyTaskIds"]);
|
|
35357
|
-
const ids = snapshotExactArray2(row?.dependencyTaskIds);
|
|
35358
|
-
if (!row || row.type !== "external_dependency" || typeof row.summary !== "string" || !row.summary.trim() || typeof row.requestedAt !== "string" || !Number.isFinite(Date.parse(row.requestedAt)) || !ids || ids.length === 0 || ids.some((id) => typeof id !== "string" || !id.trim())) return void 0;
|
|
35359
|
-
const trimmed = ids.map((id) => id.trim());
|
|
35360
|
-
if (new Set(trimmed).size !== trimmed.length) return void 0;
|
|
35361
|
-
return { type: "external_dependency", summary: row.summary, requestedAt: row.requestedAt, dependencyTaskIds: trimmed };
|
|
35362
|
-
}
|
|
35363
35754
|
function unsupportedTaskStatus() {
|
|
35364
35755
|
return failure2(
|
|
35365
35756
|
"TASK_STATUS_UNSUPPORTED",
|
|
@@ -35658,9 +36049,6 @@ var TaskLifecycleService = class {
|
|
|
35658
36049
|
if (interruption && typeof interruption === "object" && interruption.type === "review_required") {
|
|
35659
36050
|
return failure2("REVIEW_APPROVAL_REQUIRED", "Review interruption requires explicit approval or rejection.");
|
|
35660
36051
|
}
|
|
35661
|
-
if (interruption && typeof interruption === "object" && interruption.type === "external_dependency" && !parseExternalDependency(interruption)) {
|
|
35662
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "Stored external dependency interruption is malformed.");
|
|
35663
|
-
}
|
|
35664
36052
|
const previousInterruption = interruption && typeof interruption === "object" ? interruption : {};
|
|
35665
36053
|
const resumeKey = this.resumeEventKey(task);
|
|
35666
36054
|
const audit = { eventKey: resumeKey, previousInterruption };
|
|
@@ -35841,6 +36229,108 @@ var TaskLifecycleService = class {
|
|
|
35841
36229
|
detail: { previousStatus: "failed" }
|
|
35842
36230
|
});
|
|
35843
36231
|
}
|
|
36232
|
+
/**
|
|
36233
|
+
* Reopens a terminal agent task by returning it to in_progress.
|
|
36234
|
+
*
|
|
36235
|
+
* @param input Task, actor, and optional thread.
|
|
36236
|
+
* @returns Structured lifecycle result. `completed` and `cancelled` tasks
|
|
36237
|
+
* reopen to `in_progress`; an already-`in_progress` task is acknowledged
|
|
36238
|
+
* without mutation; any other status or a lost CAS yields
|
|
36239
|
+
* `TASK_STATUS_CONFLICT`.
|
|
36240
|
+
* @remarks This is the single reverse edge of the terminal-irreversibility
|
|
36241
|
+
* relaxation. It records the status change only; re-dispatch is owned by
|
|
36242
|
+
* the application layer and is never triggered here.
|
|
36243
|
+
*/
|
|
36244
|
+
async reopenTask(input) {
|
|
36245
|
+
return this.transitionAgentTask({
|
|
36246
|
+
...input,
|
|
36247
|
+
targetStatus: "in_progress",
|
|
36248
|
+
expectedStatuses: ["completed", "cancelled"],
|
|
36249
|
+
updates: { status: "in_progress", failureReason: null, result: null },
|
|
36250
|
+
summary: "Task reopened",
|
|
36251
|
+
detail: { type: "reopen" }
|
|
36252
|
+
});
|
|
36253
|
+
}
|
|
36254
|
+
/**
|
|
36255
|
+
* Transfers a human-authored task's ownership to a chosen Agent before dispatch.
|
|
36256
|
+
*
|
|
36257
|
+
* @param input Task, actor, destination Agent, and optional Task Thread.
|
|
36258
|
+
* @returns Structured result with the reassigned owner and an `owner_assigned` audit.
|
|
36259
|
+
* @remarks Only tasks with `context.source === "user"` can be assigned this way.
|
|
36260
|
+
* Repeated assignment to the same owner is idempotent (repair-writes the audit
|
|
36261
|
+
* without a CAS). This changes owner only, never status, so it publishes no
|
|
36262
|
+
* Project lifecycle notification.
|
|
36263
|
+
*/
|
|
36264
|
+
async assignOwner(input) {
|
|
36265
|
+
let task;
|
|
36266
|
+
try {
|
|
36267
|
+
task = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
36268
|
+
} catch {
|
|
36269
|
+
return failure2("TASK_STORE_READ_FAILED", "Failed to read task lifecycle state.");
|
|
36270
|
+
}
|
|
36271
|
+
if (!task) return failure2("TASK_NOT_FOUND", "Task was not found.");
|
|
36272
|
+
if (task.context?.source !== "user") {
|
|
36273
|
+
return failure2("TASK_NOT_HUMAN_MANAGED", "Only user-authored tasks can be assigned to an Agent.");
|
|
36274
|
+
}
|
|
36275
|
+
const storedThreadId = typeof task.context?.thread_id === "string" && task.context.thread_id.length > 0 ? task.context.thread_id : void 0;
|
|
36276
|
+
const effectiveThreadId = storedThreadId ?? input.threadId;
|
|
36277
|
+
const detail = { type: "owner_assigned", fromOwnerType: task.ownerType, toOwnerId: input.ownerId };
|
|
36278
|
+
if (task.ownerType === "agent" && task.ownerId === input.ownerId && (input.threadId === void 0 || storedThreadId === input.threadId)) {
|
|
36279
|
+
const eventKey2 = this.statusEventKey(task, "owner_assigned", detail);
|
|
36280
|
+
const event2 = await this.writeStatusEvent(
|
|
36281
|
+
task,
|
|
36282
|
+
input.actor,
|
|
36283
|
+
effectiveThreadId,
|
|
36284
|
+
"activity",
|
|
36285
|
+
"Task owner assigned",
|
|
36286
|
+
detail,
|
|
36287
|
+
eventKey2
|
|
36288
|
+
);
|
|
36289
|
+
return {
|
|
36290
|
+
success: true,
|
|
36291
|
+
task,
|
|
36292
|
+
mutated: false,
|
|
36293
|
+
eventKey: event2.eventKey,
|
|
36294
|
+
...event2.warning ? { warnings: [event2.warning] } : {}
|
|
36295
|
+
};
|
|
36296
|
+
}
|
|
36297
|
+
const context = { ...task.context ?? {} };
|
|
36298
|
+
if (input.threadId && !storedThreadId) context.thread_id = input.threadId;
|
|
36299
|
+
let updated;
|
|
36300
|
+
try {
|
|
36301
|
+
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
36302
|
+
input.tenantId,
|
|
36303
|
+
input.taskId,
|
|
36304
|
+
{ ownerType: "agent", ownerId: input.ownerId, context },
|
|
36305
|
+
[task.status],
|
|
36306
|
+
task.updatedAt
|
|
36307
|
+
);
|
|
36308
|
+
} catch {
|
|
36309
|
+
return failure2(
|
|
36310
|
+
"TASK_STORE_WRITE_FAILED",
|
|
36311
|
+
"Failed to assign the task owner.",
|
|
36312
|
+
"The store rejected the write."
|
|
36313
|
+
);
|
|
36314
|
+
}
|
|
36315
|
+
if (!updated) return failure2("TASK_STATUS_CONFLICT", "Task changed concurrently.");
|
|
36316
|
+
const eventKey = this.statusEventKey(updated, "owner_assigned", detail);
|
|
36317
|
+
const event = await this.writeStatusEvent(
|
|
36318
|
+
updated,
|
|
36319
|
+
input.actor,
|
|
36320
|
+
effectiveThreadId,
|
|
36321
|
+
"activity",
|
|
36322
|
+
"Task owner assigned",
|
|
36323
|
+
detail,
|
|
36324
|
+
eventKey
|
|
36325
|
+
);
|
|
36326
|
+
return {
|
|
36327
|
+
success: true,
|
|
36328
|
+
task: updated,
|
|
36329
|
+
mutated: true,
|
|
36330
|
+
eventKey: event.eventKey,
|
|
36331
|
+
...event.warning ? { warnings: [event.warning] } : {}
|
|
36332
|
+
};
|
|
36333
|
+
}
|
|
35844
36334
|
/** Atomically cancels a nonterminal agent task and records an idempotent status event. */
|
|
35845
36335
|
async cancelTask(input) {
|
|
35846
36336
|
return this.transitionAgentTask({
|
|
@@ -35921,19 +36411,7 @@ var TaskLifecycleService = class {
|
|
|
35921
36411
|
async interruptTask(input) {
|
|
35922
36412
|
const summary = input.summary.trim();
|
|
35923
36413
|
if (!summary) return failure2("MISSING_INTERRUPTION_SUMMARY", "Agent interruption requires a nonblank summary.");
|
|
35924
|
-
if (input.type !== "external_dependency" && input.dependencyTaskIds !== void 0) {
|
|
35925
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "dependencyTaskIds are only valid for external dependencies.");
|
|
35926
|
-
}
|
|
35927
36414
|
const requestedAt = this.now().toISOString();
|
|
35928
|
-
const external = input.type === "external_dependency" ? parseExternalDependency({
|
|
35929
|
-
type: input.type,
|
|
35930
|
-
summary,
|
|
35931
|
-
requestedAt,
|
|
35932
|
-
dependencyTaskIds: input.dependencyTaskIds
|
|
35933
|
-
}) : void 0;
|
|
35934
|
-
if (input.type === "external_dependency" && !external) {
|
|
35935
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependencies require exact, unique nonblank task IDs.");
|
|
35936
|
-
}
|
|
35937
36415
|
let task;
|
|
35938
36416
|
try {
|
|
35939
36417
|
task = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
@@ -35947,29 +36425,17 @@ var TaskLifecycleService = class {
|
|
|
35947
36425
|
if (threadFailure) return threadFailure;
|
|
35948
36426
|
const currentInterruption = task.context?.interruption;
|
|
35949
36427
|
if (task.status === "interrupted" && currentInterruption && typeof currentInterruption === "object") {
|
|
35950
|
-
|
|
35951
|
-
if (input.type === "external_dependency") {
|
|
35952
|
-
if (!external || !storedExternal || storedExternal.summary !== external.summary || canonicalJson(storedExternal.dependencyTaskIds) !== canonicalJson(external.dependencyTaskIds)) {
|
|
35953
|
-
return failure2(
|
|
35954
|
-
"TASK_STATUS_CONFLICT",
|
|
35955
|
-
"Task is already interrupted by a different or malformed external dependency.",
|
|
35956
|
-
"Use manage_task get to inspect the existing interruption in task context.interruption."
|
|
35957
|
-
);
|
|
35958
|
-
}
|
|
35959
|
-
} else if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
|
|
36428
|
+
if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
|
|
35960
36429
|
return failure2(
|
|
35961
36430
|
"TASK_STATUS_CONFLICT",
|
|
35962
36431
|
"Task is already interrupted by a different request.",
|
|
35963
36432
|
"Use manage_task get to inspect the existing interruption, or resume it first."
|
|
35964
36433
|
);
|
|
35965
36434
|
}
|
|
35966
|
-
const detail =
|
|
36435
|
+
const detail = currentInterruption;
|
|
35967
36436
|
const eventKey2 = this.statusEventKey(task, "interrupted", detail);
|
|
35968
36437
|
const event2 = await this.writeStatusEvent(task, input.actor, input.threadId, "interrupted", summary, detail, eventKey2);
|
|
35969
36438
|
const warnings2 = event2.warning ? [event2.warning] : [];
|
|
35970
|
-
if (storedExternal && task.workspaceId && task.projectId) {
|
|
35971
|
-
return this.finishExternalDependencyInterruption(task, input, storedExternal, event2, warnings2, false);
|
|
35972
|
-
}
|
|
35973
36439
|
return {
|
|
35974
36440
|
success: true,
|
|
35975
36441
|
task,
|
|
@@ -35985,11 +36451,7 @@ var TaskLifecycleService = class {
|
|
|
35985
36451
|
"Only pending or in_progress tasks can be interrupted. Use manage_task get to check the current status."
|
|
35986
36452
|
);
|
|
35987
36453
|
}
|
|
35988
|
-
|
|
35989
|
-
const dependencyFailure = await this.validateExternalDependencies(task, external.dependencyTaskIds);
|
|
35990
|
-
if (dependencyFailure) return dependencyFailure;
|
|
35991
|
-
}
|
|
35992
|
-
const interruption = external ? { ...external } : { type: input.type, summary, requestedAt };
|
|
36454
|
+
const interruption = { type: input.type, summary, requestedAt };
|
|
35993
36455
|
let updated;
|
|
35994
36456
|
try {
|
|
35995
36457
|
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(input.tenantId, input.taskId, {
|
|
@@ -36011,9 +36473,6 @@ var TaskLifecycleService = class {
|
|
|
36011
36473
|
const eventKey = this.statusEventKey(updated, "interrupted", interruption);
|
|
36012
36474
|
const event = await this.writeStatusEvent(updated, input.actor, input.threadId, "interrupted", summary, interruption, eventKey);
|
|
36013
36475
|
const warnings = event.warning ? [event.warning] : await this.notifyWinningTransition(updated, "interrupted", event);
|
|
36014
|
-
if (external && updated.workspaceId && updated.projectId) {
|
|
36015
|
-
return this.finishExternalDependencyInterruption(updated, input, external, event, warnings, true);
|
|
36016
|
-
}
|
|
36017
36476
|
return {
|
|
36018
36477
|
success: true,
|
|
36019
36478
|
task: updated,
|
|
@@ -37252,7 +37711,9 @@ var TaskLifecycleService = class {
|
|
|
37252
37711
|
};
|
|
37253
37712
|
}
|
|
37254
37713
|
if (!input.expectedStatuses.includes(task.status)) return failure2("TASK_STATUS_CONFLICT", "Task status cannot make this transition.");
|
|
37255
|
-
const
|
|
37714
|
+
const clearedContext = clearInterruptionContext(task.context);
|
|
37715
|
+
const withThread = input.threadId && task.context?.thread_id === void 0 ? { ...clearedContext ?? {}, thread_id: input.threadId } : clearedContext;
|
|
37716
|
+
const updates = { ...input.updates, context: withThread };
|
|
37256
37717
|
let updated;
|
|
37257
37718
|
try {
|
|
37258
37719
|
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
@@ -37340,85 +37801,6 @@ var TaskLifecycleService = class {
|
|
|
37340
37801
|
return [{ code: "LIFECYCLE_NOTIFICATION_FAILED", taskId: task.id, eventKey: event.eventKey }];
|
|
37341
37802
|
}
|
|
37342
37803
|
}
|
|
37343
|
-
async validateExternalDependencies(task, dependencyTaskIds) {
|
|
37344
|
-
const declared = new Set(task.dependencies ?? []);
|
|
37345
|
-
if (dependencyTaskIds.some((id) => id === task.id || !declared.has(id))) {
|
|
37346
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependency IDs must be declared non-self dependencies.");
|
|
37347
|
-
}
|
|
37348
|
-
try {
|
|
37349
|
-
for (const id of dependencyTaskIds) {
|
|
37350
|
-
const dependency = await this.deps.taskStore.getById(task.tenantId, id);
|
|
37351
|
-
if (!dependency || dependency.workspaceId !== task.workspaceId || dependency.projectId !== task.projectId || dependency.status === "completed") {
|
|
37352
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependencies must exist, remain incomplete, and share exact scope.");
|
|
37353
|
-
}
|
|
37354
|
-
}
|
|
37355
|
-
} catch {
|
|
37356
|
-
return failure2("TASK_STORE_READ_FAILED", "Failed to validate external dependencies.");
|
|
37357
|
-
}
|
|
37358
|
-
return void 0;
|
|
37359
|
-
}
|
|
37360
|
-
async externalDependencyReadiness(task, dependencyTaskIds) {
|
|
37361
|
-
try {
|
|
37362
|
-
for (const id of dependencyTaskIds) {
|
|
37363
|
-
const dependency = await this.deps.taskStore.getById(task.tenantId, id);
|
|
37364
|
-
if (!dependency || dependency.workspaceId !== task.workspaceId || dependency.projectId !== task.projectId || dependency.status !== "completed") return { kind: "blocked" };
|
|
37365
|
-
}
|
|
37366
|
-
return { kind: "ready" };
|
|
37367
|
-
} catch {
|
|
37368
|
-
return {
|
|
37369
|
-
kind: "error",
|
|
37370
|
-
warning: { code: "DEPENDENCY_READ_FAILED", taskId: task.id }
|
|
37371
|
-
};
|
|
37372
|
-
}
|
|
37373
|
-
}
|
|
37374
|
-
async finishExternalDependencyInterruption(task, input, interruption, event, warnings, mutated) {
|
|
37375
|
-
if (event.warning) {
|
|
37376
|
-
return { success: true, task, mutated, eventKey: event.eventKey, warnings };
|
|
37377
|
-
}
|
|
37378
|
-
const readiness = await this.externalDependencyReadiness(task, interruption.dependencyTaskIds);
|
|
37379
|
-
if (readiness.kind === "blocked") {
|
|
37380
|
-
return { success: true, task, mutated, eventKey: event.eventKey, ...warnings.length ? { warnings } : {} };
|
|
37381
|
-
}
|
|
37382
|
-
if (readiness.kind === "error") {
|
|
37383
|
-
return {
|
|
37384
|
-
success: true,
|
|
37385
|
-
task,
|
|
37386
|
-
mutated,
|
|
37387
|
-
eventKey: event.eventKey,
|
|
37388
|
-
warnings: [...warnings, { ...readiness.warning, eventKey: event.eventKey }]
|
|
37389
|
-
};
|
|
37390
|
-
}
|
|
37391
|
-
const resumed = await this.resumeInterruption({
|
|
37392
|
-
tenantId: input.tenantId,
|
|
37393
|
-
taskId: input.taskId,
|
|
37394
|
-
actor: input.actor,
|
|
37395
|
-
threadId: input.threadId
|
|
37396
|
-
});
|
|
37397
|
-
if (resumed.success) {
|
|
37398
|
-
const combined = [...warnings, ...resumed.warnings ?? []];
|
|
37399
|
-
return {
|
|
37400
|
-
...resumed,
|
|
37401
|
-
mutated: mutated || resumed.mutated,
|
|
37402
|
-
...combined.length ? { warnings: combined } : {}
|
|
37403
|
-
};
|
|
37404
|
-
}
|
|
37405
|
-
let current;
|
|
37406
|
-
try {
|
|
37407
|
-
current = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
37408
|
-
} catch {
|
|
37409
|
-
return resumed;
|
|
37410
|
-
}
|
|
37411
|
-
if (current?.status === "in_progress" && (!current.context?.thread_id || current.context?.thread_id === input.threadId)) {
|
|
37412
|
-
return {
|
|
37413
|
-
success: true,
|
|
37414
|
-
task: current,
|
|
37415
|
-
mutated,
|
|
37416
|
-
eventKey: event.eventKey,
|
|
37417
|
-
...warnings.length ? { warnings } : {}
|
|
37418
|
-
};
|
|
37419
|
-
}
|
|
37420
|
-
return resumed;
|
|
37421
|
-
}
|
|
37422
37804
|
async clearAuditMarker(task, key5) {
|
|
37423
37805
|
const context = withoutContextKey(task.context, key5);
|
|
37424
37806
|
try {
|
|
@@ -38664,6 +39046,47 @@ function clearEncryptionKeyCache() {
|
|
|
38664
39046
|
keyValidated = false;
|
|
38665
39047
|
}
|
|
38666
39048
|
|
|
39049
|
+
// src/util/safeUpstreamUrl.ts
|
|
39050
|
+
var UnsafeUpstreamUrlError = class extends Error {
|
|
39051
|
+
constructor(reason, message, statusCode = 400) {
|
|
39052
|
+
super(message);
|
|
39053
|
+
this.reason = reason;
|
|
39054
|
+
this.statusCode = statusCode;
|
|
39055
|
+
this.name = "UnsafeUpstreamUrlError";
|
|
39056
|
+
}
|
|
39057
|
+
};
|
|
39058
|
+
async function assertSafeUpstreamUrl(raw) {
|
|
39059
|
+
let url;
|
|
39060
|
+
try {
|
|
39061
|
+
url = new URL(raw);
|
|
39062
|
+
} catch {
|
|
39063
|
+
throw new UnsafeUpstreamUrlError(
|
|
39064
|
+
"INVALID_BASE_URL",
|
|
39065
|
+
"Base URL is not a valid URL"
|
|
39066
|
+
);
|
|
39067
|
+
}
|
|
39068
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
39069
|
+
throw new UnsafeUpstreamUrlError(
|
|
39070
|
+
"UNSUPPORTED_SCHEME",
|
|
39071
|
+
"Base URL must use http or https"
|
|
39072
|
+
);
|
|
39073
|
+
}
|
|
39074
|
+
if (url.username.length > 0 || url.password.length > 0) {
|
|
39075
|
+
throw new UnsafeUpstreamUrlError(
|
|
39076
|
+
"CREDENTIALS_IN_URL",
|
|
39077
|
+
"Base URL must not embed credentials; configure the API key separately"
|
|
39078
|
+
);
|
|
39079
|
+
}
|
|
39080
|
+
const hostname = url.hostname.replace(/^\[/, "").replace(/\]$/, "");
|
|
39081
|
+
if (hostname.length === 0) {
|
|
39082
|
+
throw new UnsafeUpstreamUrlError(
|
|
39083
|
+
"INVALID_BASE_URL",
|
|
39084
|
+
"Base URL must include a host"
|
|
39085
|
+
);
|
|
39086
|
+
}
|
|
39087
|
+
return { url };
|
|
39088
|
+
}
|
|
39089
|
+
|
|
38667
39090
|
// src/middlewares/skillMiddleware.ts
|
|
38668
39091
|
import { createMiddleware as createMiddleware19 } from "langchain";
|
|
38669
39092
|
|
|
@@ -41316,6 +41739,9 @@ function trustedRosterScope(trusted) {
|
|
|
41316
41739
|
callerAssistantId: context.assistantId
|
|
41317
41740
|
};
|
|
41318
41741
|
}
|
|
41742
|
+
function trustedRosterExempt(trusted) {
|
|
41743
|
+
return trusted.projectTask?.rosterExempt === true;
|
|
41744
|
+
}
|
|
41319
41745
|
async function requireTrustedOwner(trusted, targetAssistantId) {
|
|
41320
41746
|
const context = trusted.projectTask ?? trusted.projectRoom;
|
|
41321
41747
|
const memberships = getStoreLattice("default", "projectBotMembership").store;
|
|
@@ -41580,6 +42006,7 @@ async function validateTrustedChildDependencyWait(store, tenantId2, parent, depe
|
|
|
41580
42006
|
if (dependency.status === "completed") continue;
|
|
41581
42007
|
if (!["pending", "in_progress", "interrupted"].includes(dependency.status) || dependency.parentId !== parent.id || dependency.ownerType !== "agent" || !hasExactContextSource(dependency, expectedSource)) return void 0;
|
|
41582
42008
|
incompleteChildren += 1;
|
|
42009
|
+
if (trustedRosterExempt(trusted)) continue;
|
|
41583
42010
|
try {
|
|
41584
42011
|
await requireTrustedOwner(trusted, dependency.ownerId);
|
|
41585
42012
|
} catch (error) {
|
|
@@ -41654,7 +42081,6 @@ var manageTaskSchema = z70.object({
|
|
|
41654
42081
|
ownerId: z70.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
|
|
41655
42082
|
requireReview: z70.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
|
|
41656
42083
|
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
42084
|
result: z70.string().optional().describe("Result summary. Used with set_status status='completed' or update status='completed'"),
|
|
41659
42085
|
failureReason: z70.string().optional().describe("Failure reason. Used with set_status status='failed' or update status='failed'"),
|
|
41660
42086
|
files: z70.array(z70.object({
|
|
@@ -41823,7 +42249,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
41823
42249
|
const workspaceId = trustedScope?.workspaceId ?? rc.workspaceId;
|
|
41824
42250
|
const projectId = trustedScope?.projectId ?? rc.projectId;
|
|
41825
42251
|
const revalidateCaller = async () => {
|
|
41826
|
-
if (!trustedProject) return void 0;
|
|
42252
|
+
if (!trustedProject || trustedRosterExempt(trustedProject)) return void 0;
|
|
41827
42253
|
try {
|
|
41828
42254
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
41829
42255
|
} catch (error) {
|
|
@@ -41831,7 +42257,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
41831
42257
|
}
|
|
41832
42258
|
return void 0;
|
|
41833
42259
|
};
|
|
41834
|
-
if (trustedProject) {
|
|
42260
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
41835
42261
|
try {
|
|
41836
42262
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
41837
42263
|
} catch (error) {
|
|
@@ -41864,10 +42290,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
41864
42290
|
if (trustedProject) {
|
|
41865
42291
|
const snapshot = taskMutationSnapshot(existing);
|
|
41866
42292
|
if (!snapshot) return trustedContextError();
|
|
41867
|
-
|
|
41868
|
-
|
|
41869
|
-
|
|
41870
|
-
|
|
42293
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
42294
|
+
try {
|
|
42295
|
+
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
42296
|
+
} catch (error) {
|
|
42297
|
+
return projectPolicyError(error);
|
|
42298
|
+
}
|
|
41871
42299
|
}
|
|
41872
42300
|
deleted = await store.deleteIfSnapshot(tenantId2, id, snapshot);
|
|
41873
42301
|
} else {
|
|
@@ -41920,13 +42348,15 @@ function createTaskMiddleware(options = {}) {
|
|
|
41920
42348
|
"Target Project task owner is not active in the exact roster."
|
|
41921
42349
|
));
|
|
41922
42350
|
}
|
|
41923
|
-
|
|
41924
|
-
|
|
41925
|
-
|
|
41926
|
-
|
|
41927
|
-
|
|
41928
|
-
|
|
41929
|
-
|
|
42351
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
42352
|
+
try {
|
|
42353
|
+
await requireTrustedOwner(trustedProject, ownerId);
|
|
42354
|
+
} catch (error) {
|
|
42355
|
+
return projectPolicyError(error instanceof ProjectTaskOwnerPolicyError ? error : new ProjectTaskOwnerPolicyError(
|
|
42356
|
+
"PROJECT_TASK_OWNER_INACTIVE",
|
|
42357
|
+
"Target Project task owner is not active in the exact roster."
|
|
42358
|
+
));
|
|
42359
|
+
}
|
|
41930
42360
|
}
|
|
41931
42361
|
}
|
|
41932
42362
|
if (effectiveOwnerType === "agent" && (input.result !== void 0 || input.failureReason !== void 0)) {
|
|
@@ -41974,10 +42404,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
41974
42404
|
)) return trustedContextError("Parent or dependency task changed before creation.");
|
|
41975
42405
|
const callerError = await revalidateCaller();
|
|
41976
42406
|
if (callerError) return callerError;
|
|
41977
|
-
|
|
41978
|
-
|
|
41979
|
-
|
|
41980
|
-
|
|
42407
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
42408
|
+
try {
|
|
42409
|
+
await requireTrustedOwner(trustedProject, ownerId);
|
|
42410
|
+
} catch (error) {
|
|
42411
|
+
return projectPolicyError(error);
|
|
42412
|
+
}
|
|
41981
42413
|
}
|
|
41982
42414
|
}
|
|
41983
42415
|
return store.create({
|
|
@@ -42235,18 +42667,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
42235
42667
|
return trustedFailure;
|
|
42236
42668
|
}
|
|
42237
42669
|
}
|
|
42238
|
-
if (trustedProject && input.dependencyTaskIds !== void 0) {
|
|
42239
|
-
const interruption = input.context?.interruption;
|
|
42240
|
-
const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
42241
|
-
if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
|
|
42242
|
-
taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
|
|
42243
|
-
return JSON.stringify({
|
|
42244
|
-
success: false,
|
|
42245
|
-
code: "INVALID_EXTERNAL_DEPENDENCY",
|
|
42246
|
-
error: "dependencyTaskIds are only valid for external dependency interruptions."
|
|
42247
|
-
});
|
|
42248
|
-
}
|
|
42249
|
-
}
|
|
42250
42670
|
if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
|
|
42251
42671
|
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_VIA_DISPATCH_REQUIRED", {
|
|
42252
42672
|
inputOwnerType: input.ownerType,
|
|
@@ -42438,7 +42858,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
42438
42858
|
return trustedContextError("Parent or dependency task changed before update.");
|
|
42439
42859
|
}
|
|
42440
42860
|
}
|
|
42441
|
-
if (trustedProject) {
|
|
42861
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
42442
42862
|
try {
|
|
42443
42863
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
42444
42864
|
} catch (error) {
|
|
@@ -42478,7 +42898,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
42478
42898
|
const workItemSummary = input.summary;
|
|
42479
42899
|
let activityWarnings;
|
|
42480
42900
|
try {
|
|
42481
|
-
if (trustedProject) {
|
|
42901
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
42482
42902
|
try {
|
|
42483
42903
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
42484
42904
|
} catch (error) {
|
|
@@ -42563,18 +42983,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
42563
42983
|
return trustedFailure;
|
|
42564
42984
|
}
|
|
42565
42985
|
}
|
|
42566
|
-
if (trustedProject && input.dependencyTaskIds !== void 0) {
|
|
42567
|
-
const interruption = input.context?.interruption;
|
|
42568
|
-
const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
42569
|
-
if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
|
|
42570
|
-
taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
|
|
42571
|
-
return JSON.stringify({
|
|
42572
|
-
success: false,
|
|
42573
|
-
code: "INVALID_EXTERNAL_DEPENDENCY",
|
|
42574
|
-
error: "dependencyTaskIds are only valid for external dependency interruptions."
|
|
42575
|
-
});
|
|
42576
|
-
}
|
|
42577
|
-
}
|
|
42578
42986
|
if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
|
|
42579
42987
|
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_VIA_DISPATCH_REQUIRED", {});
|
|
42580
42988
|
return JSON.stringify({
|
|
@@ -42656,11 +43064,11 @@ function createTaskMiddleware(options = {}) {
|
|
|
42656
43064
|
const interruption = input.context?.interruption;
|
|
42657
43065
|
const explicitType = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
42658
43066
|
const type = explicitType ?? "missing_input";
|
|
42659
|
-
if (type !== "missing_input" && type !== "
|
|
43067
|
+
if (type !== "missing_input" && type !== "user_decision") {
|
|
42660
43068
|
return JSON.stringify({
|
|
42661
43069
|
success: false,
|
|
42662
43070
|
code: "INVALID_INTERRUPTION_TYPE",
|
|
42663
|
-
error: "Agent interruption type must be missing_input
|
|
43071
|
+
error: "Agent interruption type must be missing_input or user_decision."
|
|
42664
43072
|
});
|
|
42665
43073
|
}
|
|
42666
43074
|
await validateExecutionResult();
|
|
@@ -42672,8 +43080,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
42672
43080
|
type,
|
|
42673
43081
|
summary: input.summary ?? "",
|
|
42674
43082
|
actor,
|
|
42675
|
-
threadId: statusThreadId
|
|
42676
|
-
dependencyTaskIds: input.dependencyTaskIds
|
|
43083
|
+
threadId: statusThreadId
|
|
42677
43084
|
});
|
|
42678
43085
|
return lifecycleMutationResponse(interrupted);
|
|
42679
43086
|
}
|
|
@@ -43381,7 +43788,6 @@ canonical Belief State:
|
|
|
43381
43788
|
};
|
|
43382
43789
|
|
|
43383
43790
|
// src/middlewares/documentLearningMiddleware.ts
|
|
43384
|
-
import { AgentType as AgentType9 } from "@axiom-lattice/protocols";
|
|
43385
43791
|
import { createMiddleware as createMiddleware24 } from "langchain";
|
|
43386
43792
|
|
|
43387
43793
|
// src/middlewares/documentLearningSkills.ts
|
|
@@ -43626,15 +44032,6 @@ var createDocumentLearningMiddleware = () => createMiddleware24({
|
|
|
43626
44032
|
contextSchema,
|
|
43627
44033
|
tools: []
|
|
43628
44034
|
});
|
|
43629
|
-
var DOCUMENT_LEARNER_SYSTEM_PROMPT = `You are a capability learning specialist.
|
|
43630
|
-
|
|
43631
|
-
CRITICAL FIRST ACTION \u2014 before any response about the task:
|
|
43632
|
-
1. Call the \`skill\` tool with skill_name: "agent-architecture" to load the
|
|
43633
|
-
authoritative Charter.
|
|
43634
|
-
2. Call the \`skill\` tool with skill_name: "document-learning-learn-capability" to
|
|
43635
|
-
load the source-to-capability workflow.
|
|
43636
|
-
Never announce that you will follow a skill. Load both in this order and follow
|
|
43637
|
-
their content. If either load fails, retry it once, then report the failure.`;
|
|
43638
44035
|
var documentLearningPlugin = {
|
|
43639
44036
|
meta: {
|
|
43640
44037
|
type: "document-learning",
|
|
@@ -43643,92 +44040,6 @@ var documentLearningPlugin = {
|
|
|
43643
44040
|
description: "\u4ECE\u6587\u6863\u4E2D\u5B66\u4E60\u77E5\u8BC6\uFF0C\u81EA\u52A8\u6784\u5EFA\u6280\u80FD\u4F53\u7CFB\u548C\u8BC4\u6D4B\u3002 Learn knowledge from documents and build structured skill systems with evaluations.",
|
|
43644
44041
|
recommends: ["skill", "eval"]
|
|
43645
44042
|
},
|
|
43646
|
-
agents: {
|
|
43647
|
-
"document-learner": {
|
|
43648
|
-
key: "document-learner",
|
|
43649
|
-
name: "Document Learning Agent",
|
|
43650
|
-
description: "Read documents and build structured skill systems with evaluations. Use this agent when you need to extract knowledge from documents and turn it into reusable, testable agent skills.",
|
|
43651
|
-
type: AgentType9.DEEP_AGENT,
|
|
43652
|
-
prompt: DOCUMENT_LEARNER_SYSTEM_PROMPT,
|
|
43653
|
-
subAgents: ["document-parser-benchmark"],
|
|
43654
|
-
tools: [
|
|
43655
|
-
"invoke_agent",
|
|
43656
|
-
"list_agents",
|
|
43657
|
-
"create_agent",
|
|
43658
|
-
"update_agent",
|
|
43659
|
-
"delete_agent",
|
|
43660
|
-
"get_agent",
|
|
43661
|
-
"list_tools",
|
|
43662
|
-
"list_middleware_types"
|
|
43663
|
-
],
|
|
43664
|
-
middleware: [
|
|
43665
|
-
{
|
|
43666
|
-
id: "skill",
|
|
43667
|
-
type: "skill",
|
|
43668
|
-
name: "Skill",
|
|
43669
|
-
description: "Skill creation and loading",
|
|
43670
|
-
enabled: true,
|
|
43671
|
-
config: { readAll: true }
|
|
43672
|
-
},
|
|
43673
|
-
{
|
|
43674
|
-
id: "document-learning",
|
|
43675
|
-
type: "document-learning",
|
|
43676
|
-
name: "Document Learning",
|
|
43677
|
-
description: "Source-to-capability learning workflow",
|
|
43678
|
-
enabled: true,
|
|
43679
|
-
config: {}
|
|
43680
|
-
},
|
|
43681
|
-
{
|
|
43682
|
-
id: "eval",
|
|
43683
|
-
type: "eval",
|
|
43684
|
-
name: "Eval",
|
|
43685
|
-
description: "Evaluation design and execution",
|
|
43686
|
-
enabled: true,
|
|
43687
|
-
config: {}
|
|
43688
|
-
},
|
|
43689
|
-
{
|
|
43690
|
-
id: "task",
|
|
43691
|
-
type: "task",
|
|
43692
|
-
name: "Task",
|
|
43693
|
-
description: "Training process tracking with approval gates",
|
|
43694
|
-
enabled: true,
|
|
43695
|
-
config: {}
|
|
43696
|
-
},
|
|
43697
|
-
{
|
|
43698
|
-
id: "widget",
|
|
43699
|
-
type: "widget",
|
|
43700
|
-
name: "Widget",
|
|
43701
|
-
description: "Visualize benchmark results and eval dashboards",
|
|
43702
|
-
enabled: true,
|
|
43703
|
-
config: {}
|
|
43704
|
-
},
|
|
43705
|
-
{
|
|
43706
|
-
id: "ask_user_to_clarify",
|
|
43707
|
-
type: "ask_user_to_clarify",
|
|
43708
|
-
name: "Ask User",
|
|
43709
|
-
description: "Wait for user input at approval gates",
|
|
43710
|
-
enabled: true,
|
|
43711
|
-
config: {}
|
|
43712
|
-
},
|
|
43713
|
-
{
|
|
43714
|
-
id: "filesystem",
|
|
43715
|
-
type: "filesystem",
|
|
43716
|
-
name: "Filesystem",
|
|
43717
|
-
description: "Read documents, write skill files",
|
|
43718
|
-
enabled: true,
|
|
43719
|
-
config: {}
|
|
43720
|
-
},
|
|
43721
|
-
{
|
|
43722
|
-
id: "document-parser",
|
|
43723
|
-
type: "document-parser",
|
|
43724
|
-
name: "Document Parser",
|
|
43725
|
-
description: "Parse documents with the chosen engine",
|
|
43726
|
-
enabled: true,
|
|
43727
|
-
config: { connectAll: true }
|
|
43728
|
-
}
|
|
43729
|
-
]
|
|
43730
|
-
}
|
|
43731
|
-
},
|
|
43732
44043
|
skills: {
|
|
43733
44044
|
"document-learning-learn-capability": {
|
|
43734
44045
|
version: "1.0.0",
|
|
@@ -43957,7 +44268,7 @@ function createParseDocumentTool({
|
|
|
43957
44268
|
}
|
|
43958
44269
|
|
|
43959
44270
|
// src/middlewares/documentParserMiddleware.ts
|
|
43960
|
-
import { AgentType as
|
|
44271
|
+
import { AgentType as AgentType9 } from "@axiom-lattice/protocols";
|
|
43961
44272
|
|
|
43962
44273
|
// src/middlewares/documentBenchmarkWorkflow.ts
|
|
43963
44274
|
var DOCUMENT_PARSER_BENCHMARK_YAML = `name: document-parser-benchmark
|
|
@@ -44410,6 +44721,23 @@ function createDocumentParserMiddleware(config) {
|
|
|
44410
44721
|
tools: [createParseDocumentTool({ connectAll, connections, baseUrl, apiKey })]
|
|
44411
44722
|
});
|
|
44412
44723
|
}
|
|
44724
|
+
var DOCUMENT_PARSER_SYSTEM_PROMPT = `You are the Document Parser. Turn documents (pdf, docx, images, spreadsheets, and similar) into clean Markdown.
|
|
44725
|
+
|
|
44726
|
+
CRITICAL FIRST ACTION: call the \`skill\` tool with skill_name: "document-parser-markitdown" and follow it. Never announce skill loads.
|
|
44727
|
+
|
|
44728
|
+
DEFAULT \u2014 local MarkItDown:
|
|
44729
|
+
- Single file: run \`markitdown <input> -o <output.md>\` via shell.
|
|
44730
|
+
- Batch or literature collections: use the scripts bundled in the skill.
|
|
44731
|
+
- After converting, verify the output is non-empty and its structure/tables are intact, then report the exact input -> output paths.
|
|
44732
|
+
|
|
44733
|
+
ESCALATION \u2014 remote parse_document:
|
|
44734
|
+
- Call parse_document only when local conversion fails, the format is unsupported, the output is empty or materially incomplete, the structure is badly damaged, OCR quality is inadequate, or the user explicitly asks for professional parsing.
|
|
44735
|
+
- When the user is unsatisfied with quality, use ask_user_to_clarify to ask whether to switch to a remote engine, and recommend one engine based on the observed file features and the user's feedback. If the user names an engine, use it.
|
|
44736
|
+
|
|
44737
|
+
BENCHMARK:
|
|
44738
|
+
- Only when the user explicitly asks to compare engines. Confirm with ask_user_to_clarify first, then delegate to the document-parser-benchmark subagent. Never benchmark by default.
|
|
44739
|
+
|
|
44740
|
+
Report only what you actually produced; never claim success without inspecting the output file.`;
|
|
44413
44741
|
var documentParserPlugin = {
|
|
44414
44742
|
meta: {
|
|
44415
44743
|
type: "document-parser",
|
|
@@ -44480,9 +44808,59 @@ var documentParserPlugin = {
|
|
|
44480
44808
|
},
|
|
44481
44809
|
middleware: (config) => createDocumentParserMiddleware(config),
|
|
44482
44810
|
agents: {
|
|
44811
|
+
"document-parser": {
|
|
44812
|
+
key: "document-parser",
|
|
44813
|
+
type: AgentType9.DEEP_AGENT,
|
|
44814
|
+
name: "Document Parser",
|
|
44815
|
+
description: "Parse documents (pdf, docx, images, spreadsheets) into clean Markdown. Defaults to local MarkItDown; escalates to remote engines only when quality or format needs it; runs engine benchmarking only on explicit request.",
|
|
44816
|
+
prompt: DOCUMENT_PARSER_SYSTEM_PROMPT,
|
|
44817
|
+
subAgents: ["document-parser-benchmark"],
|
|
44818
|
+
middleware: [
|
|
44819
|
+
{
|
|
44820
|
+
id: "skill",
|
|
44821
|
+
type: "skill",
|
|
44822
|
+
name: "Skill",
|
|
44823
|
+
description: "Load the local MarkItDown parsing procedure",
|
|
44824
|
+
enabled: true,
|
|
44825
|
+
config: { readAll: true }
|
|
44826
|
+
},
|
|
44827
|
+
{
|
|
44828
|
+
id: "filesystem",
|
|
44829
|
+
type: "filesystem",
|
|
44830
|
+
name: "Filesystem",
|
|
44831
|
+
description: "Read source documents and write Markdown output",
|
|
44832
|
+
enabled: true,
|
|
44833
|
+
config: { vmIsolation: "project" }
|
|
44834
|
+
},
|
|
44835
|
+
{
|
|
44836
|
+
id: "code_eval",
|
|
44837
|
+
type: "code_eval",
|
|
44838
|
+
name: "Code Runner",
|
|
44839
|
+
description: "Run the markitdown CLI and bundled conversion scripts",
|
|
44840
|
+
enabled: true,
|
|
44841
|
+
config: { vmIsolation: "project" }
|
|
44842
|
+
},
|
|
44843
|
+
{
|
|
44844
|
+
id: "document-parser",
|
|
44845
|
+
type: "document-parser",
|
|
44846
|
+
name: "Document Parser",
|
|
44847
|
+
description: "Remote parse_document fallback for hard documents",
|
|
44848
|
+
enabled: true,
|
|
44849
|
+
config: { connectAll: true }
|
|
44850
|
+
},
|
|
44851
|
+
{
|
|
44852
|
+
id: "ask_user_to_clarify",
|
|
44853
|
+
type: "ask_user_to_clarify",
|
|
44854
|
+
name: "Ask User",
|
|
44855
|
+
description: "Confirm engine switches and benchmark runs",
|
|
44856
|
+
enabled: true,
|
|
44857
|
+
config: {}
|
|
44858
|
+
}
|
|
44859
|
+
]
|
|
44860
|
+
},
|
|
44483
44861
|
"document-parser-benchmark": {
|
|
44484
44862
|
key: "document-parser-benchmark",
|
|
44485
|
-
type:
|
|
44863
|
+
type: AgentType9.WORKFLOW,
|
|
44486
44864
|
name: "Document Parser Benchmark",
|
|
44487
44865
|
description: "Benchmark document parsing engines. Parses a document with 5 engines in parallel, scores results, and produces a ranking report. Use this when you need to evaluate which parsing engine works best for a given document.",
|
|
44488
44866
|
prompt: "Benchmark document parsing engines: parse with 5 engines, score, and rank results.",
|
|
@@ -44522,8 +44900,8 @@ import { createHash as createHash7 } from "crypto";
|
|
|
44522
44900
|
import {
|
|
44523
44901
|
descriptorDataValue as descriptorDataValue2,
|
|
44524
44902
|
parseTrustedRunContext as parseTrustedRunContext3,
|
|
44525
|
-
snapshotExactArray as
|
|
44526
|
-
snapshotExactRecord as
|
|
44903
|
+
snapshotExactArray as snapshotExactArray2,
|
|
44904
|
+
snapshotExactRecord as snapshotExactRecord7
|
|
44527
44905
|
} from "@axiom-lattice/protocols";
|
|
44528
44906
|
import { createMiddleware as createMiddleware26, tool as tool66 } from "langchain";
|
|
44529
44907
|
import { z as z72 } from "zod";
|
|
@@ -44571,7 +44949,7 @@ function readTrustedRoomScope(config) {
|
|
|
44571
44949
|
}
|
|
44572
44950
|
function exactValues2(value, required, optional = []) {
|
|
44573
44951
|
try {
|
|
44574
|
-
return
|
|
44952
|
+
return snapshotExactRecord7(value, required, optional);
|
|
44575
44953
|
} catch {
|
|
44576
44954
|
return void 0;
|
|
44577
44955
|
}
|
|
@@ -44607,7 +44985,7 @@ function snapshotMembership3(value) {
|
|
|
44607
44985
|
return { ...values, joinedAt, updatedAt };
|
|
44608
44986
|
}
|
|
44609
44987
|
function snapshotRows(value) {
|
|
44610
|
-
return
|
|
44988
|
+
return snapshotExactArray2(value) ?? [];
|
|
44611
44989
|
}
|
|
44612
44990
|
async function hasActiveCurrentMembership(scope) {
|
|
44613
44991
|
const memberships = getStoreLattice("default", "projectBotMembership").store;
|
|
@@ -44694,7 +45072,7 @@ var projectRoomPlugin = {
|
|
|
44694
45072
|
// src/middlewares/sandboxPluginsMiddleware.ts
|
|
44695
45073
|
import { createMiddleware as createMiddleware27, tool as tool67 } from "langchain";
|
|
44696
45074
|
import { z as z73 } from "zod";
|
|
44697
|
-
import { AgentType as
|
|
45075
|
+
import { AgentType as AgentType10 } from "@axiom-lattice/protocols";
|
|
44698
45076
|
|
|
44699
45077
|
// src/middlewares/sandboxPluginsSkills.ts
|
|
44700
45078
|
var PLUGIN_JSON_TEMPLATE = `{
|
|
@@ -45444,7 +45822,7 @@ var sandboxPluginsPlugin = {
|
|
|
45444
45822
|
key: "plugin-builder",
|
|
45445
45823
|
name: "Plugin Builder",
|
|
45446
45824
|
description: "Author and manage tenant plugins in the shared sandbox: clarify goal, inputs/outputs, credentials, and whether a UI is needed; then write the manifest and JS handlers, add an optional HTML MCP App UI, and validate/test with the manage_plugin tool.",
|
|
45447
|
-
type:
|
|
45825
|
+
type: AgentType10.DEEP_AGENT,
|
|
45448
45826
|
prompt: PLUGIN_BUILDER_PROMPT,
|
|
45449
45827
|
middleware: [
|
|
45450
45828
|
{
|
|
@@ -46124,6 +46502,7 @@ export {
|
|
|
46124
46502
|
InMemoryDatabaseConfigStore,
|
|
46125
46503
|
InMemoryMailboxStore,
|
|
46126
46504
|
InMemoryMenuStore,
|
|
46505
|
+
InMemoryModelProviderStore,
|
|
46127
46506
|
InMemoryOpenAuditStore,
|
|
46128
46507
|
InMemoryProjectBotMembershipStore,
|
|
46129
46508
|
InMemoryProjectMembershipStore,
|
|
@@ -46217,6 +46596,7 @@ export {
|
|
|
46217
46596
|
ThreadStatus2 as ThreadStatus,
|
|
46218
46597
|
TokenCache,
|
|
46219
46598
|
ToolLatticeManager,
|
|
46599
|
+
UnsafeUpstreamUrlError,
|
|
46220
46600
|
VectorStoreLatticeManager,
|
|
46221
46601
|
VectorStoreProviderManager,
|
|
46222
46602
|
VolumeFilesystem,
|
|
@@ -46225,6 +46605,7 @@ export {
|
|
|
46225
46605
|
agentLatticeManager,
|
|
46226
46606
|
appendReconciliationWarning,
|
|
46227
46607
|
appendUiFence,
|
|
46608
|
+
assertSafeUpstreamUrl,
|
|
46228
46609
|
buildGrepResultsDict,
|
|
46229
46610
|
buildInput,
|
|
46230
46611
|
buildNamedVolumeName,
|
|
@@ -46356,6 +46737,7 @@ export {
|
|
|
46356
46737
|
invokeWithRetry,
|
|
46357
46738
|
isBuiltInSkill,
|
|
46358
46739
|
isDirectRoom,
|
|
46740
|
+
isMcpConnectionError,
|
|
46359
46741
|
isPluginSkillAuthorizedInSandbox,
|
|
46360
46742
|
isPluginSkillManagedInSandbox,
|
|
46361
46743
|
isUsingDefaultKey,
|
|
@@ -46378,7 +46760,6 @@ export {
|
|
|
46378
46760
|
parallelLimit,
|
|
46379
46761
|
parseCronExpression,
|
|
46380
46762
|
parseDirectRoomType,
|
|
46381
|
-
parseExternalDependency,
|
|
46382
46763
|
parseJudgeVerdict,
|
|
46383
46764
|
parsePackSize,
|
|
46384
46765
|
parseQueuedExecutionMode,
|
|
@@ -46407,6 +46788,7 @@ export {
|
|
|
46407
46788
|
registerExistingToolWithTenant,
|
|
46408
46789
|
registerLoggerLattice,
|
|
46409
46790
|
registerModelLattice,
|
|
46791
|
+
registerModelLatticeForTenant,
|
|
46410
46792
|
registerQueueLattice,
|
|
46411
46793
|
registerSTTModelLattice,
|
|
46412
46794
|
registerSandboxProviderType,
|