@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.js
CHANGED
|
@@ -1662,6 +1662,7 @@ __export(index_exports, {
|
|
|
1662
1662
|
InMemoryDatabaseConfigStore: () => InMemoryDatabaseConfigStore,
|
|
1663
1663
|
InMemoryMailboxStore: () => InMemoryMailboxStore,
|
|
1664
1664
|
InMemoryMenuStore: () => InMemoryMenuStore,
|
|
1665
|
+
InMemoryModelProviderStore: () => InMemoryModelProviderStore,
|
|
1665
1666
|
InMemoryOpenAuditStore: () => InMemoryOpenAuditStore,
|
|
1666
1667
|
InMemoryProjectBotMembershipStore: () => InMemoryProjectBotMembershipStore,
|
|
1667
1668
|
InMemoryProjectMembershipStore: () => InMemoryProjectMembershipStore,
|
|
@@ -1755,6 +1756,7 @@ __export(index_exports, {
|
|
|
1755
1756
|
ThreadStatus: () => ThreadStatus2,
|
|
1756
1757
|
TokenCache: () => TokenCache,
|
|
1757
1758
|
ToolLatticeManager: () => ToolLatticeManager,
|
|
1759
|
+
UnsafeUpstreamUrlError: () => UnsafeUpstreamUrlError,
|
|
1758
1760
|
VectorStoreLatticeManager: () => VectorStoreLatticeManager,
|
|
1759
1761
|
VectorStoreProviderManager: () => VectorStoreProviderManager,
|
|
1760
1762
|
VolumeFilesystem: () => VolumeFilesystem,
|
|
@@ -1763,6 +1765,7 @@ __export(index_exports, {
|
|
|
1763
1765
|
agentLatticeManager: () => agentLatticeManager,
|
|
1764
1766
|
appendReconciliationWarning: () => appendReconciliationWarning,
|
|
1765
1767
|
appendUiFence: () => appendUiFence,
|
|
1768
|
+
assertSafeUpstreamUrl: () => assertSafeUpstreamUrl,
|
|
1766
1769
|
buildGrepResultsDict: () => buildGrepResultsDict,
|
|
1767
1770
|
buildInput: () => buildInput,
|
|
1768
1771
|
buildNamedVolumeName: () => buildNamedVolumeName,
|
|
@@ -1894,6 +1897,7 @@ __export(index_exports, {
|
|
|
1894
1897
|
invokeWithRetry: () => invokeWithRetry,
|
|
1895
1898
|
isBuiltInSkill: () => isBuiltInSkill,
|
|
1896
1899
|
isDirectRoom: () => isDirectRoom,
|
|
1900
|
+
isMcpConnectionError: () => isMcpConnectionError,
|
|
1897
1901
|
isPluginSkillAuthorizedInSandbox: () => isPluginSkillAuthorizedInSandbox,
|
|
1898
1902
|
isPluginSkillManagedInSandbox: () => isPluginSkillManagedInSandbox,
|
|
1899
1903
|
isUsingDefaultKey: () => isUsingDefaultKey,
|
|
@@ -1916,7 +1920,6 @@ __export(index_exports, {
|
|
|
1916
1920
|
parallelLimit: () => parallelLimit,
|
|
1917
1921
|
parseCronExpression: () => parseCronExpression,
|
|
1918
1922
|
parseDirectRoomType: () => parseDirectRoomType,
|
|
1919
|
-
parseExternalDependency: () => parseExternalDependency,
|
|
1920
1923
|
parseJudgeVerdict: () => parseJudgeVerdict,
|
|
1921
1924
|
parsePackSize: () => parsePackSize,
|
|
1922
1925
|
parseQueuedExecutionMode: () => import_protocols2.parseQueuedExecutionMode,
|
|
@@ -1945,6 +1948,7 @@ __export(index_exports, {
|
|
|
1945
1948
|
registerExistingToolWithTenant: () => registerExistingToolWithTenant,
|
|
1946
1949
|
registerLoggerLattice: () => registerLoggerLattice,
|
|
1947
1950
|
registerModelLattice: () => registerModelLattice,
|
|
1951
|
+
registerModelLatticeForTenant: () => registerModelLatticeForTenant,
|
|
1948
1952
|
registerQueueLattice: () => registerQueueLattice,
|
|
1949
1953
|
registerSTTModelLattice: () => registerSTTModelLattice,
|
|
1950
1954
|
registerSandboxProviderType: () => registerSandboxProviderType,
|
|
@@ -2026,6 +2030,17 @@ var ModelLattice = class extends import_chat_models.BaseChatModel {
|
|
|
2026
2030
|
this.config = config;
|
|
2027
2031
|
this.llm = this.initChatModel(config);
|
|
2028
2032
|
}
|
|
2033
|
+
/**
|
|
2034
|
+
* 返回构造时使用的配置
|
|
2035
|
+
*
|
|
2036
|
+
* 供调用方(如 models 控制器)读取 apiKey 是否存在、以及展示元数据,
|
|
2037
|
+
* 避免反射读取私有字段。
|
|
2038
|
+
*
|
|
2039
|
+
* @returns 构造时传入的 LLMConfig
|
|
2040
|
+
*/
|
|
2041
|
+
getConfig() {
|
|
2042
|
+
return this.config;
|
|
2043
|
+
}
|
|
2029
2044
|
/**
|
|
2030
2045
|
* 返回模型类型
|
|
2031
2046
|
*/
|
|
@@ -2165,6 +2180,9 @@ var ModelLattice = class extends import_chat_models.BaseChatModel {
|
|
|
2165
2180
|
maxRetries: config.maxRetries || 2,
|
|
2166
2181
|
streaming: config.streaming,
|
|
2167
2182
|
reasoning: { effort: "none" },
|
|
2183
|
+
// Responses API and Chat Completions are different paths with different
|
|
2184
|
+
// request fields; an endpoint that supports only one rejects the other.
|
|
2185
|
+
...config.useResponsesApi ? { useResponsesApi: true } : {},
|
|
2168
2186
|
apiKey: config.apiKey || process.env[config.apiKeyEnvName || "OPENAI_API_KEY"],
|
|
2169
2187
|
configuration: {
|
|
2170
2188
|
baseURL: config.baseURL
|
|
@@ -2255,9 +2273,74 @@ var ModelLatticeManager = class _ModelLatticeManager extends BaseLatticeManager
|
|
|
2255
2273
|
getLatticeKeys() {
|
|
2256
2274
|
return this.keys();
|
|
2257
2275
|
}
|
|
2276
|
+
// ========== 租户维度 API ==========
|
|
2277
|
+
// 键由基类拼装为 models:{tenantId}:{key}。注意 "default" 租户的键与旧版
|
|
2278
|
+
// key-only API 完全一致(models:default:{key}),因此对该租户是逐字节兼容的。
|
|
2279
|
+
/**
|
|
2280
|
+
* 以租户维度注册模型Lattice
|
|
2281
|
+
*
|
|
2282
|
+
* 同名 key 采用「后写覆盖」语义:先移除再注册,避免基类重复注册时抛错。
|
|
2283
|
+
*
|
|
2284
|
+
* @param tenantId 租户ID
|
|
2285
|
+
* @param key Lattice键名
|
|
2286
|
+
* @param config 模型配置
|
|
2287
|
+
*/
|
|
2288
|
+
registerLatticeWithTenant(tenantId2, key5, config) {
|
|
2289
|
+
const client = new ModelLattice(config);
|
|
2290
|
+
const modelLattice = {
|
|
2291
|
+
key: key5,
|
|
2292
|
+
client
|
|
2293
|
+
};
|
|
2294
|
+
if (this.hasWithTenant(tenantId2, key5)) {
|
|
2295
|
+
this.removeWithTenant(tenantId2, key5);
|
|
2296
|
+
}
|
|
2297
|
+
this.registerWithTenant(tenantId2, key5, modelLattice);
|
|
2298
|
+
}
|
|
2299
|
+
/**
|
|
2300
|
+
* 获取指定租户的模型Lattice
|
|
2301
|
+
* @param tenantId 租户ID
|
|
2302
|
+
* @param key Lattice键名
|
|
2303
|
+
*/
|
|
2304
|
+
getModelLatticeWithTenant(tenantId2, key5) {
|
|
2305
|
+
return this.getWithTenant(tenantId2, key5);
|
|
2306
|
+
}
|
|
2307
|
+
/**
|
|
2308
|
+
* 检查指定租户的模型Lattice是否存在
|
|
2309
|
+
* @param tenantId 租户ID
|
|
2310
|
+
* @param key Lattice键名
|
|
2311
|
+
*/
|
|
2312
|
+
hasLatticeWithTenant(tenantId2, key5) {
|
|
2313
|
+
return this.hasWithTenant(tenantId2, key5);
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* 获取指定租户的所有模型Lattice
|
|
2317
|
+
* @param tenantId 租户ID
|
|
2318
|
+
*/
|
|
2319
|
+
getAllLatticesByTenant(tenantId2) {
|
|
2320
|
+
return this.getAllByTenant(tenantId2);
|
|
2321
|
+
}
|
|
2322
|
+
/**
|
|
2323
|
+
* 获取指定租户的所有模型键名
|
|
2324
|
+
*
|
|
2325
|
+
* 只返回键名,不构造 Lattice 对象数组,适合仅需判断存在性的调用方。
|
|
2326
|
+
*
|
|
2327
|
+
* @param tenantId 租户ID
|
|
2328
|
+
*/
|
|
2329
|
+
getLatticeKeysByTenant(tenantId2) {
|
|
2330
|
+
return this.keysByTenant(tenantId2);
|
|
2331
|
+
}
|
|
2332
|
+
/**
|
|
2333
|
+
* 移除指定租户的模型Lattice
|
|
2334
|
+
* @param tenantId 租户ID
|
|
2335
|
+
* @param key Lattice键名
|
|
2336
|
+
*/
|
|
2337
|
+
removeLatticeWithTenant(tenantId2, key5) {
|
|
2338
|
+
return this.removeWithTenant(tenantId2, key5);
|
|
2339
|
+
}
|
|
2258
2340
|
};
|
|
2259
2341
|
var modelLatticeManager = ModelLatticeManager.getInstance();
|
|
2260
2342
|
var registerModelLattice = (key5, config) => modelLatticeManager.registerLattice(key5, config);
|
|
2343
|
+
var registerModelLatticeForTenant = (tenantId2, key5, config) => modelLatticeManager.registerLatticeWithTenant(tenantId2, key5, config);
|
|
2261
2344
|
var getModelLattice = (key5) => modelLatticeManager.getModelLattice(key5);
|
|
2262
2345
|
|
|
2263
2346
|
// src/tool_lattice/get_current_date_time/index.ts
|
|
@@ -3993,6 +4076,240 @@ var InMemoryMcpServerConfigStore = class {
|
|
|
3993
4076
|
}
|
|
3994
4077
|
};
|
|
3995
4078
|
|
|
4079
|
+
// src/store_lattice/InMemoryModelProviderStore.ts
|
|
4080
|
+
var InMemoryModelProviderStore = class {
|
|
4081
|
+
constructor() {
|
|
4082
|
+
this.providers = /* @__PURE__ */ new Map();
|
|
4083
|
+
this.models = /* @__PURE__ */ new Map();
|
|
4084
|
+
}
|
|
4085
|
+
/**
|
|
4086
|
+
* Get composite key for providers
|
|
4087
|
+
*/
|
|
4088
|
+
getProviderKey(tenantId2, id) {
|
|
4089
|
+
return `${tenantId2}:${id}`;
|
|
4090
|
+
}
|
|
4091
|
+
/**
|
|
4092
|
+
* Get composite key for snapshot models
|
|
4093
|
+
*/
|
|
4094
|
+
getModelKey(tenantId2, providerId, modelId) {
|
|
4095
|
+
return `${tenantId2}:${providerId}:${modelId}`;
|
|
4096
|
+
}
|
|
4097
|
+
/**
|
|
4098
|
+
* Get all provider configurations for a tenant
|
|
4099
|
+
*/
|
|
4100
|
+
async listProviders(tenantId2) {
|
|
4101
|
+
return Array.from(this.providers.values()).filter(
|
|
4102
|
+
(provider) => provider.tenantId === tenantId2
|
|
4103
|
+
);
|
|
4104
|
+
}
|
|
4105
|
+
/**
|
|
4106
|
+
* Get a provider configuration by ID
|
|
4107
|
+
*/
|
|
4108
|
+
async getProviderById(tenantId2, id) {
|
|
4109
|
+
return this.providers.get(this.getProviderKey(tenantId2, id)) || null;
|
|
4110
|
+
}
|
|
4111
|
+
/**
|
|
4112
|
+
* Get a provider configuration by business name
|
|
4113
|
+
*/
|
|
4114
|
+
async getProviderByName(tenantId2, name) {
|
|
4115
|
+
const providers = await this.listProviders(tenantId2);
|
|
4116
|
+
return providers.find((provider) => provider.name === name) || null;
|
|
4117
|
+
}
|
|
4118
|
+
/**
|
|
4119
|
+
* Create a new provider configuration
|
|
4120
|
+
*/
|
|
4121
|
+
async createProvider(tenantId2, id, data) {
|
|
4122
|
+
const now = /* @__PURE__ */ new Date();
|
|
4123
|
+
const entry = {
|
|
4124
|
+
id,
|
|
4125
|
+
tenantId: tenantId2,
|
|
4126
|
+
name: data.name,
|
|
4127
|
+
displayName: data.displayName,
|
|
4128
|
+
protocol: data.protocol,
|
|
4129
|
+
apiStyle: data.apiStyle ?? "chat-completions",
|
|
4130
|
+
// Phase 1 pins the LLM provider: the UI does not offer a choice, and some
|
|
4131
|
+
// initChatModel branches hardcode their own baseURL and would silently
|
|
4132
|
+
// ignore the tenant's (see ADR-138 decision 7b).
|
|
4133
|
+
llmProvider: "openai",
|
|
4134
|
+
baseURL: data.baseURL,
|
|
4135
|
+
apiKey: data.apiKey || void 0,
|
|
4136
|
+
apiKeyHint: data.apiKey ? data.apiKey.slice(-4) : void 0,
|
|
4137
|
+
enabled: data.enabled ?? true,
|
|
4138
|
+
status: "unknown",
|
|
4139
|
+
createdAt: now,
|
|
4140
|
+
updatedAt: now
|
|
4141
|
+
};
|
|
4142
|
+
this.providers.set(this.getProviderKey(tenantId2, id), entry);
|
|
4143
|
+
return entry;
|
|
4144
|
+
}
|
|
4145
|
+
/**
|
|
4146
|
+
* Update an existing provider configuration.
|
|
4147
|
+
* An omitted or empty `apiKey` leaves the stored key untouched.
|
|
4148
|
+
*/
|
|
4149
|
+
async updateProvider(tenantId2, id, updates) {
|
|
4150
|
+
const key5 = this.getProviderKey(tenantId2, id);
|
|
4151
|
+
const existing = this.providers.get(key5);
|
|
4152
|
+
if (!existing) {
|
|
4153
|
+
return null;
|
|
4154
|
+
}
|
|
4155
|
+
const hasNewApiKey = Boolean(updates.apiKey);
|
|
4156
|
+
const clearsApiKey = updates.clearApiKey === true;
|
|
4157
|
+
const updated = {
|
|
4158
|
+
...existing,
|
|
4159
|
+
name: updates.name ?? existing.name,
|
|
4160
|
+
displayName: updates.displayName !== void 0 ? updates.displayName : existing.displayName,
|
|
4161
|
+
protocol: updates.protocol ?? existing.protocol,
|
|
4162
|
+
apiStyle: updates.apiStyle ?? existing.apiStyle,
|
|
4163
|
+
baseURL: updates.baseURL ?? existing.baseURL,
|
|
4164
|
+
apiKey: clearsApiKey ? void 0 : hasNewApiKey ? updates.apiKey : existing.apiKey,
|
|
4165
|
+
apiKeyHint: clearsApiKey ? void 0 : hasNewApiKey ? updates.apiKey?.slice(-4) : existing.apiKeyHint,
|
|
4166
|
+
enabled: updates.enabled ?? existing.enabled,
|
|
4167
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
4168
|
+
};
|
|
4169
|
+
this.providers.set(key5, updated);
|
|
4170
|
+
return updated;
|
|
4171
|
+
}
|
|
4172
|
+
/**
|
|
4173
|
+
* Delete a provider configuration and its model snapshot
|
|
4174
|
+
*/
|
|
4175
|
+
async deleteProvider(tenantId2, id) {
|
|
4176
|
+
await this.deleteModelsByProvider(tenantId2, id);
|
|
4177
|
+
return this.providers.delete(this.getProviderKey(tenantId2, id));
|
|
4178
|
+
}
|
|
4179
|
+
/**
|
|
4180
|
+
* Record the outcome of a discovery attempt
|
|
4181
|
+
*/
|
|
4182
|
+
async markProviderStatus(tenantId2, id, status, lastError, discoveredAt) {
|
|
4183
|
+
const key5 = this.getProviderKey(tenantId2, id);
|
|
4184
|
+
const existing = this.providers.get(key5);
|
|
4185
|
+
if (!existing) {
|
|
4186
|
+
return;
|
|
4187
|
+
}
|
|
4188
|
+
this.providers.set(key5, {
|
|
4189
|
+
...existing,
|
|
4190
|
+
status,
|
|
4191
|
+
lastError: status === "ok" ? void 0 : lastError,
|
|
4192
|
+
lastDiscoveredAt: discoveredAt ?? existing.lastDiscoveredAt,
|
|
4193
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
4194
|
+
});
|
|
4195
|
+
}
|
|
4196
|
+
/**
|
|
4197
|
+
* List snapshot models for a tenant
|
|
4198
|
+
*/
|
|
4199
|
+
async listModels(tenantId2, providerId) {
|
|
4200
|
+
return Array.from(this.models.values()).filter(
|
|
4201
|
+
(model) => model.tenantId === tenantId2 && (providerId === void 0 || model.providerId === providerId)
|
|
4202
|
+
);
|
|
4203
|
+
}
|
|
4204
|
+
/**
|
|
4205
|
+
* Get a single snapshot model.
|
|
4206
|
+
* Keyed by provider as well as model id, since two providers in the same
|
|
4207
|
+
* tenant may expose the same upstream model id.
|
|
4208
|
+
*/
|
|
4209
|
+
async getModel(tenantId2, providerId, modelId) {
|
|
4210
|
+
return this.models.get(this.getModelKey(tenantId2, providerId, modelId)) || null;
|
|
4211
|
+
}
|
|
4212
|
+
/**
|
|
4213
|
+
* Replace a provider's model snapshot with the result of one discovery.
|
|
4214
|
+
*
|
|
4215
|
+
* Model ids are scoped per provider, so the same upstream id may appear
|
|
4216
|
+
* under several providers in one tenant — each is an independent model.
|
|
4217
|
+
*
|
|
4218
|
+
* Models the upstream no longer offers are removed; models that survive keep
|
|
4219
|
+
* the tenant's enable/disable choice rather than being reset.
|
|
4220
|
+
*/
|
|
4221
|
+
async replaceProviderModels(tenantId2, providerId, models) {
|
|
4222
|
+
const previous = await this.listModels(tenantId2, providerId);
|
|
4223
|
+
const previousById = new Map(
|
|
4224
|
+
previous.map((model) => [model.modelId, model])
|
|
4225
|
+
);
|
|
4226
|
+
const incomingIds = new Set(models.map((model) => model.id));
|
|
4227
|
+
for (const model of previous) {
|
|
4228
|
+
if (!incomingIds.has(model.modelId)) {
|
|
4229
|
+
this.models.delete(
|
|
4230
|
+
this.getModelKey(tenantId2, providerId, model.modelId)
|
|
4231
|
+
);
|
|
4232
|
+
}
|
|
4233
|
+
}
|
|
4234
|
+
const now = /* @__PURE__ */ new Date();
|
|
4235
|
+
const upserted = [];
|
|
4236
|
+
for (const model of models) {
|
|
4237
|
+
const existing = previousById.get(model.id);
|
|
4238
|
+
const entry = {
|
|
4239
|
+
id: `${providerId}:${model.id}`,
|
|
4240
|
+
tenantId: tenantId2,
|
|
4241
|
+
providerId,
|
|
4242
|
+
modelId: model.id,
|
|
4243
|
+
displayName: model.displayName,
|
|
4244
|
+
ownedBy: model.ownedBy,
|
|
4245
|
+
upstreamCreatedAt: model.createdAt ? new Date(model.createdAt) : void 0,
|
|
4246
|
+
// An explicit `enabled` from the caller wins; discovery omits it and
|
|
4247
|
+
// the tenant's earlier choice is preserved.
|
|
4248
|
+
enabled: model.enabled ?? existing?.enabled ?? true,
|
|
4249
|
+
// Unlike `enabled`, this is not preserved: a model present in the list
|
|
4250
|
+
// the caller just read is, by definition, no longer stale. Only an
|
|
4251
|
+
// explicit flag marks one.
|
|
4252
|
+
stale: model.stale ?? false,
|
|
4253
|
+
discoveredAt: now
|
|
4254
|
+
};
|
|
4255
|
+
this.models.set(this.getModelKey(tenantId2, providerId, model.id), entry);
|
|
4256
|
+
upserted.push(model.id);
|
|
4257
|
+
}
|
|
4258
|
+
return upserted;
|
|
4259
|
+
}
|
|
4260
|
+
/**
|
|
4261
|
+
* Enable or disable a single snapshot model
|
|
4262
|
+
*/
|
|
4263
|
+
async setModelEnabled(tenantId2, providerId, modelId, enabled) {
|
|
4264
|
+
const key5 = this.getModelKey(tenantId2, providerId, modelId);
|
|
4265
|
+
const existing = this.models.get(key5);
|
|
4266
|
+
if (!existing) {
|
|
4267
|
+
return null;
|
|
4268
|
+
}
|
|
4269
|
+
const updated = {
|
|
4270
|
+
...existing,
|
|
4271
|
+
enabled
|
|
4272
|
+
};
|
|
4273
|
+
this.models.set(key5, updated);
|
|
4274
|
+
return updated;
|
|
4275
|
+
}
|
|
4276
|
+
/**
|
|
4277
|
+
* Delete every snapshot model belonging to a provider
|
|
4278
|
+
*/
|
|
4279
|
+
async deleteModelsByProvider(tenantId2, providerId) {
|
|
4280
|
+
let deleted = 0;
|
|
4281
|
+
for (const [key5, model] of Array.from(this.models.entries())) {
|
|
4282
|
+
if (model.tenantId === tenantId2 && model.providerId === providerId) {
|
|
4283
|
+
this.models.delete(key5);
|
|
4284
|
+
deleted += 1;
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
return deleted;
|
|
4288
|
+
}
|
|
4289
|
+
/**
|
|
4290
|
+
* Clear all providers and models (useful for testing)
|
|
4291
|
+
*/
|
|
4292
|
+
clear() {
|
|
4293
|
+
this.providers.clear();
|
|
4294
|
+
this.models.clear();
|
|
4295
|
+
}
|
|
4296
|
+
/**
|
|
4297
|
+
* Clear providers and models for a specific tenant
|
|
4298
|
+
*/
|
|
4299
|
+
clearByTenant(tenantId2) {
|
|
4300
|
+
for (const [key5, provider] of Array.from(this.providers.entries())) {
|
|
4301
|
+
if (provider.tenantId === tenantId2) {
|
|
4302
|
+
this.providers.delete(key5);
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
for (const [key5, model] of Array.from(this.models.entries())) {
|
|
4306
|
+
if (model.tenantId === tenantId2) {
|
|
4307
|
+
this.models.delete(key5);
|
|
4308
|
+
}
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
};
|
|
4312
|
+
|
|
3996
4313
|
// src/store_lattice/InMemoryAgentWebAppStore.ts
|
|
3997
4314
|
var import_crypto = require("crypto");
|
|
3998
4315
|
function cloneAppearance(appearance) {
|
|
@@ -6473,6 +6790,7 @@ var defaultProjectStore = new InMemoryProjectStore(defaultCapabilityBundleCoordi
|
|
|
6473
6790
|
var defaultDatabaseConfigStore = new InMemoryDatabaseConfigStore();
|
|
6474
6791
|
var defaultMetricsServerConfigStore = new InMemoryMetricsServerConfigStore();
|
|
6475
6792
|
var defaultMcpServerConfigStore = new InMemoryMcpServerConfigStore();
|
|
6793
|
+
var defaultModelProviderStore = new InMemoryModelProviderStore();
|
|
6476
6794
|
var defaultAgentWebAppStore = new InMemoryAgentWebAppStore();
|
|
6477
6795
|
var defaultCapabilityBundleStore = new InMemoryCapabilityBundleStore(defaultProjectStore, defaultCapabilityBundleCoordinator);
|
|
6478
6796
|
var defaultProjectRoomCoordinator = new InMemoryProjectRoomCoordinator();
|
|
@@ -6494,6 +6812,7 @@ storeLatticeManager.registerLattice("default", "project", defaultProjectStore);
|
|
|
6494
6812
|
storeLatticeManager.registerLattice("default", "database", defaultDatabaseConfigStore);
|
|
6495
6813
|
storeLatticeManager.registerLattice("default", "metrics", defaultMetricsServerConfigStore);
|
|
6496
6814
|
storeLatticeManager.registerLattice("default", "mcp", defaultMcpServerConfigStore);
|
|
6815
|
+
storeLatticeManager.registerLattice("default", "modelProvider", defaultModelProviderStore);
|
|
6497
6816
|
storeLatticeManager.registerLattice("default", "agentWebApp", defaultAgentWebAppStore);
|
|
6498
6817
|
storeLatticeManager.registerLattice("default", "capabilityBundle", defaultCapabilityBundleStore);
|
|
6499
6818
|
storeLatticeManager.registerLattice("default", "projectRoom", defaultProjectRoomStore);
|
|
@@ -30804,7 +31123,7 @@ var agentArchitectConfig = {
|
|
|
30804
31123
|
"delete_agent",
|
|
30805
31124
|
"manage_binding"
|
|
30806
31125
|
],
|
|
30807
|
-
subAgents: ["document-parser-benchmark"],
|
|
31126
|
+
subAgents: ["document-parser", "document-parser-benchmark"],
|
|
30808
31127
|
middleware: [
|
|
30809
31128
|
{
|
|
30810
31129
|
id: "filesystem",
|
|
@@ -32513,6 +32832,7 @@ async function removeCollectionVectorStore(name, tenantId2) {
|
|
|
32513
32832
|
|
|
32514
32833
|
// src/mcp_lattice/McpLatticeManager.ts
|
|
32515
32834
|
var import_mcp_adapters = require("@langchain/mcp-adapters");
|
|
32835
|
+
var import_tools3 = require("@langchain/core/tools");
|
|
32516
32836
|
init_BaseLatticeManager();
|
|
32517
32837
|
|
|
32518
32838
|
// src/mcp_lattice/reconnectPolicy.ts
|
|
@@ -32522,6 +32842,13 @@ var DEFAULT_DELAY_MS = 1e3;
|
|
|
32522
32842
|
var MAX_BACKOFF_MS = 3e4;
|
|
32523
32843
|
var HEALTH_CHECK_INTERVAL_MS = 3e4;
|
|
32524
32844
|
var HEALTH_CHECK_TIMEOUT_MS = 5e3;
|
|
32845
|
+
function isMcpConnectionError(error) {
|
|
32846
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "";
|
|
32847
|
+
if (!message) return false;
|
|
32848
|
+
return /not connected|connection closed|session not found|no session|maximum reconnection/i.test(
|
|
32849
|
+
message
|
|
32850
|
+
);
|
|
32851
|
+
}
|
|
32525
32852
|
function nextBackoffDelay(attempt, base = DEFAULT_DELAY_MS, max = MAX_BACKOFF_MS) {
|
|
32526
32853
|
if (attempt <= 0) return base;
|
|
32527
32854
|
return Math.min(base * Math.pow(2, attempt - 1), max);
|
|
@@ -32546,12 +32873,21 @@ async function withTimeout2(operation, ms, onTimeout) {
|
|
|
32546
32873
|
|
|
32547
32874
|
// src/mcp_lattice/McpLatticeManager.ts
|
|
32548
32875
|
var realClientFactory = ({ mcpServers }) => new import_mcp_adapters.MultiServerMCPClient({ mcpServers });
|
|
32876
|
+
function extractRawCall(tool68) {
|
|
32877
|
+
const rawCall = tool68._call;
|
|
32878
|
+
if (typeof rawCall === "function") return rawCall.bind(tool68);
|
|
32879
|
+
return async (...args) => {
|
|
32880
|
+
const invoke = tool68.invoke.bind(tool68);
|
|
32881
|
+
return invoke(args[0], args[2]);
|
|
32882
|
+
};
|
|
32883
|
+
}
|
|
32549
32884
|
var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
32550
32885
|
constructor() {
|
|
32551
32886
|
super(...arguments);
|
|
32552
32887
|
this.runtimes = /* @__PURE__ */ new Map();
|
|
32553
32888
|
this.clientFactory = realClientFactory;
|
|
32554
32889
|
this.healthCheckInFlight = false;
|
|
32890
|
+
this.reconnectPromises = /* @__PURE__ */ new Map();
|
|
32555
32891
|
}
|
|
32556
32892
|
static getInstance() {
|
|
32557
32893
|
if (!_McpLatticeManager._instance) {
|
|
@@ -32809,6 +33145,64 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
32809
33145
|
rt.attempt = 0;
|
|
32810
33146
|
await this.reconnectRuntime(rt);
|
|
32811
33147
|
}
|
|
33148
|
+
/**
|
|
33149
|
+
* Single-flight a forced reconnect per `(tenantId, serverKey)` so concurrent
|
|
33150
|
+
* tool calls that all hit the same dead session reconnect once, not once each.
|
|
33151
|
+
*/
|
|
33152
|
+
reconnectShared(rt) {
|
|
33153
|
+
const key5 = this.compositeKey(rt.id.tenantId, rt.id.serverKey);
|
|
33154
|
+
const existing = this.reconnectPromises.get(key5);
|
|
33155
|
+
if (existing) return existing;
|
|
33156
|
+
const work = this.reconnectServer(rt.id.tenantId, rt.id.serverKey).finally(() => {
|
|
33157
|
+
if (this.reconnectPromises.get(key5) === work) this.reconnectPromises.delete(key5);
|
|
33158
|
+
});
|
|
33159
|
+
this.reconnectPromises.set(key5, work);
|
|
33160
|
+
return work;
|
|
33161
|
+
}
|
|
33162
|
+
/**
|
|
33163
|
+
* Wrap a raw MCP tool so a call landing on a torn-down session
|
|
33164
|
+
* (`Not connected` / `Connection closed` / session expiry) transparently
|
|
33165
|
+
* forces a reconnect and retries once against the fresh client, instead of
|
|
33166
|
+
* failing the surrounding run. Non-connection errors propagate untouched.
|
|
33167
|
+
*/
|
|
33168
|
+
wrapToolForResilience(rt, raw) {
|
|
33169
|
+
const call = extractRawCall(raw);
|
|
33170
|
+
return new import_tools3.DynamicStructuredTool({
|
|
33171
|
+
name: raw.name,
|
|
33172
|
+
description: raw.description,
|
|
33173
|
+
schema: raw.schema,
|
|
33174
|
+
responseFormat: raw.responseFormat,
|
|
33175
|
+
defaultConfig: raw.defaultConfig,
|
|
33176
|
+
metadata: raw.metadata,
|
|
33177
|
+
returnDirect: raw.returnDirect,
|
|
33178
|
+
func: async (...args) => this.invokeResilient(rt, raw.name, call, args)
|
|
33179
|
+
});
|
|
33180
|
+
}
|
|
33181
|
+
async invokeResilient(rt, toolName2, call, args) {
|
|
33182
|
+
try {
|
|
33183
|
+
await this.ensureConnected(rt.id.tenantId, rt.id.serverKey);
|
|
33184
|
+
return await call(...args);
|
|
33185
|
+
} catch (error) {
|
|
33186
|
+
if (!isMcpConnectionError(error) || !this.isActive(rt)) throw error;
|
|
33187
|
+
console.warn(
|
|
33188
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: tool "${toolName2}" hit a dead session; reconnecting and retrying once`,
|
|
33189
|
+
error instanceof Error ? error.message : error
|
|
33190
|
+
);
|
|
33191
|
+
try {
|
|
33192
|
+
await this.reconnectShared(rt);
|
|
33193
|
+
} catch (reconnectError) {
|
|
33194
|
+
console.warn(
|
|
33195
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: reconnect for tool "${toolName2}" failed`,
|
|
33196
|
+
reconnectError instanceof Error ? reconnectError.message : reconnectError
|
|
33197
|
+
);
|
|
33198
|
+
throw error;
|
|
33199
|
+
}
|
|
33200
|
+
const fresh = await this.getRawTools(rt.id.tenantId, rt.id.serverKey);
|
|
33201
|
+
const match = fresh.find((t) => t.name === toolName2);
|
|
33202
|
+
if (!match) throw error;
|
|
33203
|
+
return await extractRawCall(match)(...args);
|
|
33204
|
+
}
|
|
33205
|
+
}
|
|
32812
33206
|
async checkHealth() {
|
|
32813
33207
|
if (this.healthCheckInFlight) return;
|
|
32814
33208
|
this.healthCheckInFlight = true;
|
|
@@ -32827,8 +33221,12 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
32827
33221
|
await withTimeout2(session.listTools(), HEALTH_CHECK_TIMEOUT_MS, async () => {
|
|
32828
33222
|
});
|
|
32829
33223
|
if (!this.isActive(rt) || rt.state !== "connected") continue;
|
|
32830
|
-
} catch {
|
|
33224
|
+
} catch (error) {
|
|
32831
33225
|
if (this.isActive(rt) && rt.state === "connected") {
|
|
33226
|
+
console.warn(
|
|
33227
|
+
`[MCP] ${rt.id.tenantId}/${rt.id.serverKey}: health check failed; scheduling reconnect`,
|
|
33228
|
+
error instanceof Error ? error.message : error
|
|
33229
|
+
);
|
|
32832
33230
|
rt.state = "failed";
|
|
32833
33231
|
this.scheduleReconnect(rt);
|
|
32834
33232
|
}
|
|
@@ -33034,7 +33432,8 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
33034
33432
|
const visibility = Array.isArray(rawVisibility) ? rawVisibility : typeof rawVisibility === "string" ? [rawVisibility] : void 0;
|
|
33035
33433
|
if (visibility && !visibility.includes("model")) continue;
|
|
33036
33434
|
const ref = extractAppsRef(meta, serverKey);
|
|
33037
|
-
const
|
|
33435
|
+
const resilient = this.wrapToolForResilience(rt, tool68);
|
|
33436
|
+
const registered = ref ? wrapMcpToolWithUi(resilient, ref) : resilient;
|
|
33038
33437
|
const toolKey = _McpLatticeManager.buildToolKey(serverKey, tool68.name);
|
|
33039
33438
|
try {
|
|
33040
33439
|
toolLatticeManager.registerExistingToolWithTenant(tenantId2, toolKey, registered);
|
|
@@ -33103,6 +33502,7 @@ var McpLatticeManager = class _McpLatticeManager extends BaseLatticeManager {
|
|
|
33103
33502
|
}
|
|
33104
33503
|
}
|
|
33105
33504
|
this.runtimes.clear();
|
|
33505
|
+
this.reconnectPromises.clear();
|
|
33106
33506
|
}
|
|
33107
33507
|
};
|
|
33108
33508
|
var mcpManager = McpLatticeManager.getInstance();
|
|
@@ -36253,13 +36653,16 @@ var LatticeEvalProject = class {
|
|
|
36253
36653
|
constructor(project, onCaseComplete) {
|
|
36254
36654
|
this.suites = /* @__PURE__ */ new Map();
|
|
36255
36655
|
this.project = project;
|
|
36256
|
-
const
|
|
36656
|
+
const tenantId2 = this.project.lattice_server_config.tenant_id || "default";
|
|
36657
|
+
const judgeModelKey = resolveJudgeModelKey(
|
|
36658
|
+
this.project.judge_agent_config.modelKey,
|
|
36659
|
+
modelLatticeManager
|
|
36660
|
+
);
|
|
36257
36661
|
if (!modelLatticeManager.hasLattice(judgeModelKey)) {
|
|
36258
36662
|
throw new Error(
|
|
36259
36663
|
`Judge model "${judgeModelKey}" not found. Register it first or provide a valid modelKey.`
|
|
36260
36664
|
);
|
|
36261
36665
|
}
|
|
36262
|
-
const tenantId2 = this.project.lattice_server_config.tenant_id || "default";
|
|
36263
36666
|
this.judgeAgentKey = `${this.project.projectName}_judge_agent`;
|
|
36264
36667
|
const judgeAgentConfig = {
|
|
36265
36668
|
key: this.judgeAgentKey,
|
|
@@ -37314,14 +37717,6 @@ async function applyBeliefImpacts(taskStore, owner, impacts) {
|
|
|
37314
37717
|
}
|
|
37315
37718
|
return { description: current.description ?? "", task: current };
|
|
37316
37719
|
}
|
|
37317
|
-
function parseExternalDependency(value) {
|
|
37318
|
-
const row = (0, import_protocols31.snapshotExactRecord)(value, ["type", "summary", "requestedAt", "dependencyTaskIds"]);
|
|
37319
|
-
const ids = (0, import_protocols31.snapshotExactArray)(row?.dependencyTaskIds);
|
|
37320
|
-
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;
|
|
37321
|
-
const trimmed = ids.map((id) => id.trim());
|
|
37322
|
-
if (new Set(trimmed).size !== trimmed.length) return void 0;
|
|
37323
|
-
return { type: "external_dependency", summary: row.summary, requestedAt: row.requestedAt, dependencyTaskIds: trimmed };
|
|
37324
|
-
}
|
|
37325
37720
|
function unsupportedTaskStatus() {
|
|
37326
37721
|
return failure2(
|
|
37327
37722
|
"TASK_STATUS_UNSUPPORTED",
|
|
@@ -37620,9 +38015,6 @@ var TaskLifecycleService = class {
|
|
|
37620
38015
|
if (interruption && typeof interruption === "object" && interruption.type === "review_required") {
|
|
37621
38016
|
return failure2("REVIEW_APPROVAL_REQUIRED", "Review interruption requires explicit approval or rejection.");
|
|
37622
38017
|
}
|
|
37623
|
-
if (interruption && typeof interruption === "object" && interruption.type === "external_dependency" && !parseExternalDependency(interruption)) {
|
|
37624
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "Stored external dependency interruption is malformed.");
|
|
37625
|
-
}
|
|
37626
38018
|
const previousInterruption = interruption && typeof interruption === "object" ? interruption : {};
|
|
37627
38019
|
const resumeKey = this.resumeEventKey(task);
|
|
37628
38020
|
const audit = { eventKey: resumeKey, previousInterruption };
|
|
@@ -37803,6 +38195,108 @@ var TaskLifecycleService = class {
|
|
|
37803
38195
|
detail: { previousStatus: "failed" }
|
|
37804
38196
|
});
|
|
37805
38197
|
}
|
|
38198
|
+
/**
|
|
38199
|
+
* Reopens a terminal agent task by returning it to in_progress.
|
|
38200
|
+
*
|
|
38201
|
+
* @param input Task, actor, and optional thread.
|
|
38202
|
+
* @returns Structured lifecycle result. `completed` and `cancelled` tasks
|
|
38203
|
+
* reopen to `in_progress`; an already-`in_progress` task is acknowledged
|
|
38204
|
+
* without mutation; any other status or a lost CAS yields
|
|
38205
|
+
* `TASK_STATUS_CONFLICT`.
|
|
38206
|
+
* @remarks This is the single reverse edge of the terminal-irreversibility
|
|
38207
|
+
* relaxation. It records the status change only; re-dispatch is owned by
|
|
38208
|
+
* the application layer and is never triggered here.
|
|
38209
|
+
*/
|
|
38210
|
+
async reopenTask(input) {
|
|
38211
|
+
return this.transitionAgentTask({
|
|
38212
|
+
...input,
|
|
38213
|
+
targetStatus: "in_progress",
|
|
38214
|
+
expectedStatuses: ["completed", "cancelled"],
|
|
38215
|
+
updates: { status: "in_progress", failureReason: null, result: null },
|
|
38216
|
+
summary: "Task reopened",
|
|
38217
|
+
detail: { type: "reopen" }
|
|
38218
|
+
});
|
|
38219
|
+
}
|
|
38220
|
+
/**
|
|
38221
|
+
* Transfers a human-authored task's ownership to a chosen Agent before dispatch.
|
|
38222
|
+
*
|
|
38223
|
+
* @param input Task, actor, destination Agent, and optional Task Thread.
|
|
38224
|
+
* @returns Structured result with the reassigned owner and an `owner_assigned` audit.
|
|
38225
|
+
* @remarks Only tasks with `context.source === "user"` can be assigned this way.
|
|
38226
|
+
* Repeated assignment to the same owner is idempotent (repair-writes the audit
|
|
38227
|
+
* without a CAS). This changes owner only, never status, so it publishes no
|
|
38228
|
+
* Project lifecycle notification.
|
|
38229
|
+
*/
|
|
38230
|
+
async assignOwner(input) {
|
|
38231
|
+
let task;
|
|
38232
|
+
try {
|
|
38233
|
+
task = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
38234
|
+
} catch {
|
|
38235
|
+
return failure2("TASK_STORE_READ_FAILED", "Failed to read task lifecycle state.");
|
|
38236
|
+
}
|
|
38237
|
+
if (!task) return failure2("TASK_NOT_FOUND", "Task was not found.");
|
|
38238
|
+
if (task.context?.source !== "user") {
|
|
38239
|
+
return failure2("TASK_NOT_HUMAN_MANAGED", "Only user-authored tasks can be assigned to an Agent.");
|
|
38240
|
+
}
|
|
38241
|
+
const storedThreadId = typeof task.context?.thread_id === "string" && task.context.thread_id.length > 0 ? task.context.thread_id : void 0;
|
|
38242
|
+
const effectiveThreadId = storedThreadId ?? input.threadId;
|
|
38243
|
+
const detail = { type: "owner_assigned", fromOwnerType: task.ownerType, toOwnerId: input.ownerId };
|
|
38244
|
+
if (task.ownerType === "agent" && task.ownerId === input.ownerId && (input.threadId === void 0 || storedThreadId === input.threadId)) {
|
|
38245
|
+
const eventKey2 = this.statusEventKey(task, "owner_assigned", detail);
|
|
38246
|
+
const event2 = await this.writeStatusEvent(
|
|
38247
|
+
task,
|
|
38248
|
+
input.actor,
|
|
38249
|
+
effectiveThreadId,
|
|
38250
|
+
"activity",
|
|
38251
|
+
"Task owner assigned",
|
|
38252
|
+
detail,
|
|
38253
|
+
eventKey2
|
|
38254
|
+
);
|
|
38255
|
+
return {
|
|
38256
|
+
success: true,
|
|
38257
|
+
task,
|
|
38258
|
+
mutated: false,
|
|
38259
|
+
eventKey: event2.eventKey,
|
|
38260
|
+
...event2.warning ? { warnings: [event2.warning] } : {}
|
|
38261
|
+
};
|
|
38262
|
+
}
|
|
38263
|
+
const context = { ...task.context ?? {} };
|
|
38264
|
+
if (input.threadId && !storedThreadId) context.thread_id = input.threadId;
|
|
38265
|
+
let updated;
|
|
38266
|
+
try {
|
|
38267
|
+
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
38268
|
+
input.tenantId,
|
|
38269
|
+
input.taskId,
|
|
38270
|
+
{ ownerType: "agent", ownerId: input.ownerId, context },
|
|
38271
|
+
[task.status],
|
|
38272
|
+
task.updatedAt
|
|
38273
|
+
);
|
|
38274
|
+
} catch {
|
|
38275
|
+
return failure2(
|
|
38276
|
+
"TASK_STORE_WRITE_FAILED",
|
|
38277
|
+
"Failed to assign the task owner.",
|
|
38278
|
+
"The store rejected the write."
|
|
38279
|
+
);
|
|
38280
|
+
}
|
|
38281
|
+
if (!updated) return failure2("TASK_STATUS_CONFLICT", "Task changed concurrently.");
|
|
38282
|
+
const eventKey = this.statusEventKey(updated, "owner_assigned", detail);
|
|
38283
|
+
const event = await this.writeStatusEvent(
|
|
38284
|
+
updated,
|
|
38285
|
+
input.actor,
|
|
38286
|
+
effectiveThreadId,
|
|
38287
|
+
"activity",
|
|
38288
|
+
"Task owner assigned",
|
|
38289
|
+
detail,
|
|
38290
|
+
eventKey
|
|
38291
|
+
);
|
|
38292
|
+
return {
|
|
38293
|
+
success: true,
|
|
38294
|
+
task: updated,
|
|
38295
|
+
mutated: true,
|
|
38296
|
+
eventKey: event.eventKey,
|
|
38297
|
+
...event.warning ? { warnings: [event.warning] } : {}
|
|
38298
|
+
};
|
|
38299
|
+
}
|
|
37806
38300
|
/** Atomically cancels a nonterminal agent task and records an idempotent status event. */
|
|
37807
38301
|
async cancelTask(input) {
|
|
37808
38302
|
return this.transitionAgentTask({
|
|
@@ -37883,19 +38377,7 @@ var TaskLifecycleService = class {
|
|
|
37883
38377
|
async interruptTask(input) {
|
|
37884
38378
|
const summary = input.summary.trim();
|
|
37885
38379
|
if (!summary) return failure2("MISSING_INTERRUPTION_SUMMARY", "Agent interruption requires a nonblank summary.");
|
|
37886
|
-
if (input.type !== "external_dependency" && input.dependencyTaskIds !== void 0) {
|
|
37887
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "dependencyTaskIds are only valid for external dependencies.");
|
|
37888
|
-
}
|
|
37889
38380
|
const requestedAt = this.now().toISOString();
|
|
37890
|
-
const external = input.type === "external_dependency" ? parseExternalDependency({
|
|
37891
|
-
type: input.type,
|
|
37892
|
-
summary,
|
|
37893
|
-
requestedAt,
|
|
37894
|
-
dependencyTaskIds: input.dependencyTaskIds
|
|
37895
|
-
}) : void 0;
|
|
37896
|
-
if (input.type === "external_dependency" && !external) {
|
|
37897
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependencies require exact, unique nonblank task IDs.");
|
|
37898
|
-
}
|
|
37899
38381
|
let task;
|
|
37900
38382
|
try {
|
|
37901
38383
|
task = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
@@ -37909,29 +38391,17 @@ var TaskLifecycleService = class {
|
|
|
37909
38391
|
if (threadFailure) return threadFailure;
|
|
37910
38392
|
const currentInterruption = task.context?.interruption;
|
|
37911
38393
|
if (task.status === "interrupted" && currentInterruption && typeof currentInterruption === "object") {
|
|
37912
|
-
|
|
37913
|
-
if (input.type === "external_dependency") {
|
|
37914
|
-
if (!external || !storedExternal || storedExternal.summary !== external.summary || canonicalJson(storedExternal.dependencyTaskIds) !== canonicalJson(external.dependencyTaskIds)) {
|
|
37915
|
-
return failure2(
|
|
37916
|
-
"TASK_STATUS_CONFLICT",
|
|
37917
|
-
"Task is already interrupted by a different or malformed external dependency.",
|
|
37918
|
-
"Use manage_task get to inspect the existing interruption in task context.interruption."
|
|
37919
|
-
);
|
|
37920
|
-
}
|
|
37921
|
-
} else if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
|
|
38394
|
+
if (currentInterruption.type !== input.type || currentInterruption.summary !== summary) {
|
|
37922
38395
|
return failure2(
|
|
37923
38396
|
"TASK_STATUS_CONFLICT",
|
|
37924
38397
|
"Task is already interrupted by a different request.",
|
|
37925
38398
|
"Use manage_task get to inspect the existing interruption, or resume it first."
|
|
37926
38399
|
);
|
|
37927
38400
|
}
|
|
37928
|
-
const detail =
|
|
38401
|
+
const detail = currentInterruption;
|
|
37929
38402
|
const eventKey2 = this.statusEventKey(task, "interrupted", detail);
|
|
37930
38403
|
const event2 = await this.writeStatusEvent(task, input.actor, input.threadId, "interrupted", summary, detail, eventKey2);
|
|
37931
38404
|
const warnings2 = event2.warning ? [event2.warning] : [];
|
|
37932
|
-
if (storedExternal && task.workspaceId && task.projectId) {
|
|
37933
|
-
return this.finishExternalDependencyInterruption(task, input, storedExternal, event2, warnings2, false);
|
|
37934
|
-
}
|
|
37935
38405
|
return {
|
|
37936
38406
|
success: true,
|
|
37937
38407
|
task,
|
|
@@ -37947,11 +38417,7 @@ var TaskLifecycleService = class {
|
|
|
37947
38417
|
"Only pending or in_progress tasks can be interrupted. Use manage_task get to check the current status."
|
|
37948
38418
|
);
|
|
37949
38419
|
}
|
|
37950
|
-
|
|
37951
|
-
const dependencyFailure = await this.validateExternalDependencies(task, external.dependencyTaskIds);
|
|
37952
|
-
if (dependencyFailure) return dependencyFailure;
|
|
37953
|
-
}
|
|
37954
|
-
const interruption = external ? { ...external } : { type: input.type, summary, requestedAt };
|
|
38420
|
+
const interruption = { type: input.type, summary, requestedAt };
|
|
37955
38421
|
let updated;
|
|
37956
38422
|
try {
|
|
37957
38423
|
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(input.tenantId, input.taskId, {
|
|
@@ -37973,9 +38439,6 @@ var TaskLifecycleService = class {
|
|
|
37973
38439
|
const eventKey = this.statusEventKey(updated, "interrupted", interruption);
|
|
37974
38440
|
const event = await this.writeStatusEvent(updated, input.actor, input.threadId, "interrupted", summary, interruption, eventKey);
|
|
37975
38441
|
const warnings = event.warning ? [event.warning] : await this.notifyWinningTransition(updated, "interrupted", event);
|
|
37976
|
-
if (external && updated.workspaceId && updated.projectId) {
|
|
37977
|
-
return this.finishExternalDependencyInterruption(updated, input, external, event, warnings, true);
|
|
37978
|
-
}
|
|
37979
38442
|
return {
|
|
37980
38443
|
success: true,
|
|
37981
38444
|
task: updated,
|
|
@@ -39214,7 +39677,9 @@ var TaskLifecycleService = class {
|
|
|
39214
39677
|
};
|
|
39215
39678
|
}
|
|
39216
39679
|
if (!input.expectedStatuses.includes(task.status)) return failure2("TASK_STATUS_CONFLICT", "Task status cannot make this transition.");
|
|
39217
|
-
const
|
|
39680
|
+
const clearedContext = clearInterruptionContext(task.context);
|
|
39681
|
+
const withThread = input.threadId && task.context?.thread_id === void 0 ? { ...clearedContext ?? {}, thread_id: input.threadId } : clearedContext;
|
|
39682
|
+
const updates = { ...input.updates, context: withThread };
|
|
39218
39683
|
let updated;
|
|
39219
39684
|
try {
|
|
39220
39685
|
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
@@ -39302,85 +39767,6 @@ var TaskLifecycleService = class {
|
|
|
39302
39767
|
return [{ code: "LIFECYCLE_NOTIFICATION_FAILED", taskId: task.id, eventKey: event.eventKey }];
|
|
39303
39768
|
}
|
|
39304
39769
|
}
|
|
39305
|
-
async validateExternalDependencies(task, dependencyTaskIds) {
|
|
39306
|
-
const declared = new Set(task.dependencies ?? []);
|
|
39307
|
-
if (dependencyTaskIds.some((id) => id === task.id || !declared.has(id))) {
|
|
39308
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependency IDs must be declared non-self dependencies.");
|
|
39309
|
-
}
|
|
39310
|
-
try {
|
|
39311
|
-
for (const id of dependencyTaskIds) {
|
|
39312
|
-
const dependency = await this.deps.taskStore.getById(task.tenantId, id);
|
|
39313
|
-
if (!dependency || dependency.workspaceId !== task.workspaceId || dependency.projectId !== task.projectId || dependency.status === "completed") {
|
|
39314
|
-
return failure2("INVALID_EXTERNAL_DEPENDENCY", "External dependencies must exist, remain incomplete, and share exact scope.");
|
|
39315
|
-
}
|
|
39316
|
-
}
|
|
39317
|
-
} catch {
|
|
39318
|
-
return failure2("TASK_STORE_READ_FAILED", "Failed to validate external dependencies.");
|
|
39319
|
-
}
|
|
39320
|
-
return void 0;
|
|
39321
|
-
}
|
|
39322
|
-
async externalDependencyReadiness(task, dependencyTaskIds) {
|
|
39323
|
-
try {
|
|
39324
|
-
for (const id of dependencyTaskIds) {
|
|
39325
|
-
const dependency = await this.deps.taskStore.getById(task.tenantId, id);
|
|
39326
|
-
if (!dependency || dependency.workspaceId !== task.workspaceId || dependency.projectId !== task.projectId || dependency.status !== "completed") return { kind: "blocked" };
|
|
39327
|
-
}
|
|
39328
|
-
return { kind: "ready" };
|
|
39329
|
-
} catch {
|
|
39330
|
-
return {
|
|
39331
|
-
kind: "error",
|
|
39332
|
-
warning: { code: "DEPENDENCY_READ_FAILED", taskId: task.id }
|
|
39333
|
-
};
|
|
39334
|
-
}
|
|
39335
|
-
}
|
|
39336
|
-
async finishExternalDependencyInterruption(task, input, interruption, event, warnings, mutated) {
|
|
39337
|
-
if (event.warning) {
|
|
39338
|
-
return { success: true, task, mutated, eventKey: event.eventKey, warnings };
|
|
39339
|
-
}
|
|
39340
|
-
const readiness = await this.externalDependencyReadiness(task, interruption.dependencyTaskIds);
|
|
39341
|
-
if (readiness.kind === "blocked") {
|
|
39342
|
-
return { success: true, task, mutated, eventKey: event.eventKey, ...warnings.length ? { warnings } : {} };
|
|
39343
|
-
}
|
|
39344
|
-
if (readiness.kind === "error") {
|
|
39345
|
-
return {
|
|
39346
|
-
success: true,
|
|
39347
|
-
task,
|
|
39348
|
-
mutated,
|
|
39349
|
-
eventKey: event.eventKey,
|
|
39350
|
-
warnings: [...warnings, { ...readiness.warning, eventKey: event.eventKey }]
|
|
39351
|
-
};
|
|
39352
|
-
}
|
|
39353
|
-
const resumed = await this.resumeInterruption({
|
|
39354
|
-
tenantId: input.tenantId,
|
|
39355
|
-
taskId: input.taskId,
|
|
39356
|
-
actor: input.actor,
|
|
39357
|
-
threadId: input.threadId
|
|
39358
|
-
});
|
|
39359
|
-
if (resumed.success) {
|
|
39360
|
-
const combined = [...warnings, ...resumed.warnings ?? []];
|
|
39361
|
-
return {
|
|
39362
|
-
...resumed,
|
|
39363
|
-
mutated: mutated || resumed.mutated,
|
|
39364
|
-
...combined.length ? { warnings: combined } : {}
|
|
39365
|
-
};
|
|
39366
|
-
}
|
|
39367
|
-
let current;
|
|
39368
|
-
try {
|
|
39369
|
-
current = await this.deps.taskStore.getById(input.tenantId, input.taskId);
|
|
39370
|
-
} catch {
|
|
39371
|
-
return resumed;
|
|
39372
|
-
}
|
|
39373
|
-
if (current?.status === "in_progress" && (!current.context?.thread_id || current.context?.thread_id === input.threadId)) {
|
|
39374
|
-
return {
|
|
39375
|
-
success: true,
|
|
39376
|
-
task: current,
|
|
39377
|
-
mutated,
|
|
39378
|
-
eventKey: event.eventKey,
|
|
39379
|
-
...warnings.length ? { warnings } : {}
|
|
39380
|
-
};
|
|
39381
|
-
}
|
|
39382
|
-
return resumed;
|
|
39383
|
-
}
|
|
39384
39770
|
async clearAuditMarker(task, key5) {
|
|
39385
39771
|
const context = withoutContextKey(task.context, key5);
|
|
39386
39772
|
try {
|
|
@@ -40626,6 +41012,47 @@ function clearEncryptionKeyCache() {
|
|
|
40626
41012
|
keyValidated = false;
|
|
40627
41013
|
}
|
|
40628
41014
|
|
|
41015
|
+
// src/util/safeUpstreamUrl.ts
|
|
41016
|
+
var UnsafeUpstreamUrlError = class extends Error {
|
|
41017
|
+
constructor(reason, message, statusCode = 400) {
|
|
41018
|
+
super(message);
|
|
41019
|
+
this.reason = reason;
|
|
41020
|
+
this.statusCode = statusCode;
|
|
41021
|
+
this.name = "UnsafeUpstreamUrlError";
|
|
41022
|
+
}
|
|
41023
|
+
};
|
|
41024
|
+
async function assertSafeUpstreamUrl(raw) {
|
|
41025
|
+
let url;
|
|
41026
|
+
try {
|
|
41027
|
+
url = new URL(raw);
|
|
41028
|
+
} catch {
|
|
41029
|
+
throw new UnsafeUpstreamUrlError(
|
|
41030
|
+
"INVALID_BASE_URL",
|
|
41031
|
+
"Base URL is not a valid URL"
|
|
41032
|
+
);
|
|
41033
|
+
}
|
|
41034
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
41035
|
+
throw new UnsafeUpstreamUrlError(
|
|
41036
|
+
"UNSUPPORTED_SCHEME",
|
|
41037
|
+
"Base URL must use http or https"
|
|
41038
|
+
);
|
|
41039
|
+
}
|
|
41040
|
+
if (url.username.length > 0 || url.password.length > 0) {
|
|
41041
|
+
throw new UnsafeUpstreamUrlError(
|
|
41042
|
+
"CREDENTIALS_IN_URL",
|
|
41043
|
+
"Base URL must not embed credentials; configure the API key separately"
|
|
41044
|
+
);
|
|
41045
|
+
}
|
|
41046
|
+
const hostname = url.hostname.replace(/^\[/, "").replace(/\]$/, "");
|
|
41047
|
+
if (hostname.length === 0) {
|
|
41048
|
+
throw new UnsafeUpstreamUrlError(
|
|
41049
|
+
"INVALID_BASE_URL",
|
|
41050
|
+
"Base URL must include a host"
|
|
41051
|
+
);
|
|
41052
|
+
}
|
|
41053
|
+
return { url };
|
|
41054
|
+
}
|
|
41055
|
+
|
|
40629
41056
|
// src/middlewares/skillMiddleware.ts
|
|
40630
41057
|
var import_langchain66 = require("langchain");
|
|
40631
41058
|
|
|
@@ -43273,6 +43700,9 @@ function trustedRosterScope(trusted) {
|
|
|
43273
43700
|
callerAssistantId: context.assistantId
|
|
43274
43701
|
};
|
|
43275
43702
|
}
|
|
43703
|
+
function trustedRosterExempt(trusted) {
|
|
43704
|
+
return trusted.projectTask?.rosterExempt === true;
|
|
43705
|
+
}
|
|
43276
43706
|
async function requireTrustedOwner(trusted, targetAssistantId) {
|
|
43277
43707
|
const context = trusted.projectTask ?? trusted.projectRoom;
|
|
43278
43708
|
const memberships = getStoreLattice("default", "projectBotMembership").store;
|
|
@@ -43537,6 +43967,7 @@ async function validateTrustedChildDependencyWait(store, tenantId2, parent, depe
|
|
|
43537
43967
|
if (dependency.status === "completed") continue;
|
|
43538
43968
|
if (!["pending", "in_progress", "interrupted"].includes(dependency.status) || dependency.parentId !== parent.id || dependency.ownerType !== "agent" || !hasExactContextSource(dependency, expectedSource)) return void 0;
|
|
43539
43969
|
incompleteChildren += 1;
|
|
43970
|
+
if (trustedRosterExempt(trusted)) continue;
|
|
43540
43971
|
try {
|
|
43541
43972
|
await requireTrustedOwner(trusted, dependency.ownerId);
|
|
43542
43973
|
} catch (error) {
|
|
@@ -43611,7 +44042,6 @@ var manageTaskSchema = import_zod68.z.object({
|
|
|
43611
44042
|
ownerId: import_zod68.z.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
|
|
43612
44043
|
requireReview: import_zod68.z.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
|
|
43613
44044
|
dependencies: import_zod68.z.array(import_zod68.z.string()).optional().describe("List of task IDs that must be completed before this task can start"),
|
|
43614
|
-
dependencyTaskIds: import_zod68.z.array(import_zod68.z.string().trim().min(1)).optional().describe("Exact blocking task IDs required for an external_dependency interruption"),
|
|
43615
44045
|
result: import_zod68.z.string().optional().describe("Result summary. Used with set_status status='completed' or update status='completed'"),
|
|
43616
44046
|
failureReason: import_zod68.z.string().optional().describe("Failure reason. Used with set_status status='failed' or update status='failed'"),
|
|
43617
44047
|
files: import_zod68.z.array(import_zod68.z.object({
|
|
@@ -43780,7 +44210,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43780
44210
|
const workspaceId = trustedScope?.workspaceId ?? rc.workspaceId;
|
|
43781
44211
|
const projectId = trustedScope?.projectId ?? rc.projectId;
|
|
43782
44212
|
const revalidateCaller = async () => {
|
|
43783
|
-
if (!trustedProject) return void 0;
|
|
44213
|
+
if (!trustedProject || trustedRosterExempt(trustedProject)) return void 0;
|
|
43784
44214
|
try {
|
|
43785
44215
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
43786
44216
|
} catch (error) {
|
|
@@ -43788,7 +44218,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43788
44218
|
}
|
|
43789
44219
|
return void 0;
|
|
43790
44220
|
};
|
|
43791
|
-
if (trustedProject) {
|
|
44221
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
43792
44222
|
try {
|
|
43793
44223
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
43794
44224
|
} catch (error) {
|
|
@@ -43821,10 +44251,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
43821
44251
|
if (trustedProject) {
|
|
43822
44252
|
const snapshot = taskMutationSnapshot(existing);
|
|
43823
44253
|
if (!snapshot) return trustedContextError();
|
|
43824
|
-
|
|
43825
|
-
|
|
43826
|
-
|
|
43827
|
-
|
|
44254
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
44255
|
+
try {
|
|
44256
|
+
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
44257
|
+
} catch (error) {
|
|
44258
|
+
return projectPolicyError(error);
|
|
44259
|
+
}
|
|
43828
44260
|
}
|
|
43829
44261
|
deleted = await store.deleteIfSnapshot(tenantId2, id, snapshot);
|
|
43830
44262
|
} else {
|
|
@@ -43877,13 +44309,15 @@ function createTaskMiddleware(options = {}) {
|
|
|
43877
44309
|
"Target Project task owner is not active in the exact roster."
|
|
43878
44310
|
));
|
|
43879
44311
|
}
|
|
43880
|
-
|
|
43881
|
-
|
|
43882
|
-
|
|
43883
|
-
|
|
43884
|
-
|
|
43885
|
-
|
|
43886
|
-
|
|
44312
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
44313
|
+
try {
|
|
44314
|
+
await requireTrustedOwner(trustedProject, ownerId);
|
|
44315
|
+
} catch (error) {
|
|
44316
|
+
return projectPolicyError(error instanceof ProjectTaskOwnerPolicyError ? error : new ProjectTaskOwnerPolicyError(
|
|
44317
|
+
"PROJECT_TASK_OWNER_INACTIVE",
|
|
44318
|
+
"Target Project task owner is not active in the exact roster."
|
|
44319
|
+
));
|
|
44320
|
+
}
|
|
43887
44321
|
}
|
|
43888
44322
|
}
|
|
43889
44323
|
if (effectiveOwnerType === "agent" && (input.result !== void 0 || input.failureReason !== void 0)) {
|
|
@@ -43931,10 +44365,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
43931
44365
|
)) return trustedContextError("Parent or dependency task changed before creation.");
|
|
43932
44366
|
const callerError = await revalidateCaller();
|
|
43933
44367
|
if (callerError) return callerError;
|
|
43934
|
-
|
|
43935
|
-
|
|
43936
|
-
|
|
43937
|
-
|
|
44368
|
+
if (!trustedRosterExempt(trustedProject)) {
|
|
44369
|
+
try {
|
|
44370
|
+
await requireTrustedOwner(trustedProject, ownerId);
|
|
44371
|
+
} catch (error) {
|
|
44372
|
+
return projectPolicyError(error);
|
|
44373
|
+
}
|
|
43938
44374
|
}
|
|
43939
44375
|
}
|
|
43940
44376
|
return store.create({
|
|
@@ -44192,18 +44628,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
44192
44628
|
return trustedFailure;
|
|
44193
44629
|
}
|
|
44194
44630
|
}
|
|
44195
|
-
if (trustedProject && input.dependencyTaskIds !== void 0) {
|
|
44196
|
-
const interruption = input.context?.interruption;
|
|
44197
|
-
const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
44198
|
-
if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
|
|
44199
|
-
taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
|
|
44200
|
-
return JSON.stringify({
|
|
44201
|
-
success: false,
|
|
44202
|
-
code: "INVALID_EXTERNAL_DEPENDENCY",
|
|
44203
|
-
error: "dependencyTaskIds are only valid for external dependency interruptions."
|
|
44204
|
-
});
|
|
44205
|
-
}
|
|
44206
|
-
}
|
|
44207
44631
|
if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
|
|
44208
44632
|
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_VIA_DISPATCH_REQUIRED", {
|
|
44209
44633
|
inputOwnerType: input.ownerType,
|
|
@@ -44395,7 +44819,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
44395
44819
|
return trustedContextError("Parent or dependency task changed before update.");
|
|
44396
44820
|
}
|
|
44397
44821
|
}
|
|
44398
|
-
if (trustedProject) {
|
|
44822
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
44399
44823
|
try {
|
|
44400
44824
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
44401
44825
|
} catch (error) {
|
|
@@ -44435,7 +44859,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
44435
44859
|
const workItemSummary = input.summary;
|
|
44436
44860
|
let activityWarnings;
|
|
44437
44861
|
try {
|
|
44438
|
-
if (trustedProject) {
|
|
44862
|
+
if (trustedProject && !trustedRosterExempt(trustedProject)) {
|
|
44439
44863
|
try {
|
|
44440
44864
|
await createProjectTaskOwnerPolicy().requireCaller(trustedRosterScope(trustedProject));
|
|
44441
44865
|
} catch (error) {
|
|
@@ -44520,18 +44944,6 @@ function createTaskMiddleware(options = {}) {
|
|
|
44520
44944
|
return trustedFailure;
|
|
44521
44945
|
}
|
|
44522
44946
|
}
|
|
44523
|
-
if (trustedProject && input.dependencyTaskIds !== void 0) {
|
|
44524
|
-
const interruption = input.context?.interruption;
|
|
44525
|
-
const interruptionType2 = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
44526
|
-
if (input.status !== "interrupted" || interruptionType2 !== "external_dependency") {
|
|
44527
|
-
taskUpdateBlocked(input.id, "INVALID_EXTERNAL_DEPENDENCY", {});
|
|
44528
|
-
return JSON.stringify({
|
|
44529
|
-
success: false,
|
|
44530
|
-
code: "INVALID_EXTERNAL_DEPENDENCY",
|
|
44531
|
-
error: "dependencyTaskIds are only valid for external dependency interruptions."
|
|
44532
|
-
});
|
|
44533
|
-
}
|
|
44534
|
-
}
|
|
44535
44947
|
if (trustedProject && (input.ownerType !== void 0 && input.ownerType !== existing.ownerType || input.ownerId !== void 0 && input.ownerId !== existing.ownerId)) {
|
|
44536
44948
|
taskUpdateBlocked(input.id, "TASK_OWNERSHIP_VIA_DISPATCH_REQUIRED", {});
|
|
44537
44949
|
return JSON.stringify({
|
|
@@ -44613,11 +45025,11 @@ function createTaskMiddleware(options = {}) {
|
|
|
44613
45025
|
const interruption = input.context?.interruption;
|
|
44614
45026
|
const explicitType = interruption && typeof interruption === "object" ? interruption.type : void 0;
|
|
44615
45027
|
const type = explicitType ?? "missing_input";
|
|
44616
|
-
if (type !== "missing_input" && type !== "
|
|
45028
|
+
if (type !== "missing_input" && type !== "user_decision") {
|
|
44617
45029
|
return JSON.stringify({
|
|
44618
45030
|
success: false,
|
|
44619
45031
|
code: "INVALID_INTERRUPTION_TYPE",
|
|
44620
|
-
error: "Agent interruption type must be missing_input
|
|
45032
|
+
error: "Agent interruption type must be missing_input or user_decision."
|
|
44621
45033
|
});
|
|
44622
45034
|
}
|
|
44623
45035
|
await validateExecutionResult();
|
|
@@ -44629,8 +45041,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
44629
45041
|
type,
|
|
44630
45042
|
summary: input.summary ?? "",
|
|
44631
45043
|
actor,
|
|
44632
|
-
threadId: statusThreadId
|
|
44633
|
-
dependencyTaskIds: input.dependencyTaskIds
|
|
45044
|
+
threadId: statusThreadId
|
|
44634
45045
|
});
|
|
44635
45046
|
return lifecycleMutationResponse(interrupted);
|
|
44636
45047
|
}
|
|
@@ -45338,7 +45749,6 @@ canonical Belief State:
|
|
|
45338
45749
|
};
|
|
45339
45750
|
|
|
45340
45751
|
// src/middlewares/documentLearningMiddleware.ts
|
|
45341
|
-
var import_protocols34 = require("@axiom-lattice/protocols");
|
|
45342
45752
|
var import_langchain84 = require("langchain");
|
|
45343
45753
|
|
|
45344
45754
|
// src/middlewares/documentLearningSkills.ts
|
|
@@ -45583,15 +45993,6 @@ var createDocumentLearningMiddleware = () => (0, import_langchain84.createMiddle
|
|
|
45583
45993
|
contextSchema,
|
|
45584
45994
|
tools: []
|
|
45585
45995
|
});
|
|
45586
|
-
var DOCUMENT_LEARNER_SYSTEM_PROMPT = `You are a capability learning specialist.
|
|
45587
|
-
|
|
45588
|
-
CRITICAL FIRST ACTION \u2014 before any response about the task:
|
|
45589
|
-
1. Call the \`skill\` tool with skill_name: "agent-architecture" to load the
|
|
45590
|
-
authoritative Charter.
|
|
45591
|
-
2. Call the \`skill\` tool with skill_name: "document-learning-learn-capability" to
|
|
45592
|
-
load the source-to-capability workflow.
|
|
45593
|
-
Never announce that you will follow a skill. Load both in this order and follow
|
|
45594
|
-
their content. If either load fails, retry it once, then report the failure.`;
|
|
45595
45996
|
var documentLearningPlugin = {
|
|
45596
45997
|
meta: {
|
|
45597
45998
|
type: "document-learning",
|
|
@@ -45600,92 +46001,6 @@ var documentLearningPlugin = {
|
|
|
45600
46001
|
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.",
|
|
45601
46002
|
recommends: ["skill", "eval"]
|
|
45602
46003
|
},
|
|
45603
|
-
agents: {
|
|
45604
|
-
"document-learner": {
|
|
45605
|
-
key: "document-learner",
|
|
45606
|
-
name: "Document Learning Agent",
|
|
45607
|
-
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.",
|
|
45608
|
-
type: import_protocols34.AgentType.DEEP_AGENT,
|
|
45609
|
-
prompt: DOCUMENT_LEARNER_SYSTEM_PROMPT,
|
|
45610
|
-
subAgents: ["document-parser-benchmark"],
|
|
45611
|
-
tools: [
|
|
45612
|
-
"invoke_agent",
|
|
45613
|
-
"list_agents",
|
|
45614
|
-
"create_agent",
|
|
45615
|
-
"update_agent",
|
|
45616
|
-
"delete_agent",
|
|
45617
|
-
"get_agent",
|
|
45618
|
-
"list_tools",
|
|
45619
|
-
"list_middleware_types"
|
|
45620
|
-
],
|
|
45621
|
-
middleware: [
|
|
45622
|
-
{
|
|
45623
|
-
id: "skill",
|
|
45624
|
-
type: "skill",
|
|
45625
|
-
name: "Skill",
|
|
45626
|
-
description: "Skill creation and loading",
|
|
45627
|
-
enabled: true,
|
|
45628
|
-
config: { readAll: true }
|
|
45629
|
-
},
|
|
45630
|
-
{
|
|
45631
|
-
id: "document-learning",
|
|
45632
|
-
type: "document-learning",
|
|
45633
|
-
name: "Document Learning",
|
|
45634
|
-
description: "Source-to-capability learning workflow",
|
|
45635
|
-
enabled: true,
|
|
45636
|
-
config: {}
|
|
45637
|
-
},
|
|
45638
|
-
{
|
|
45639
|
-
id: "eval",
|
|
45640
|
-
type: "eval",
|
|
45641
|
-
name: "Eval",
|
|
45642
|
-
description: "Evaluation design and execution",
|
|
45643
|
-
enabled: true,
|
|
45644
|
-
config: {}
|
|
45645
|
-
},
|
|
45646
|
-
{
|
|
45647
|
-
id: "task",
|
|
45648
|
-
type: "task",
|
|
45649
|
-
name: "Task",
|
|
45650
|
-
description: "Training process tracking with approval gates",
|
|
45651
|
-
enabled: true,
|
|
45652
|
-
config: {}
|
|
45653
|
-
},
|
|
45654
|
-
{
|
|
45655
|
-
id: "widget",
|
|
45656
|
-
type: "widget",
|
|
45657
|
-
name: "Widget",
|
|
45658
|
-
description: "Visualize benchmark results and eval dashboards",
|
|
45659
|
-
enabled: true,
|
|
45660
|
-
config: {}
|
|
45661
|
-
},
|
|
45662
|
-
{
|
|
45663
|
-
id: "ask_user_to_clarify",
|
|
45664
|
-
type: "ask_user_to_clarify",
|
|
45665
|
-
name: "Ask User",
|
|
45666
|
-
description: "Wait for user input at approval gates",
|
|
45667
|
-
enabled: true,
|
|
45668
|
-
config: {}
|
|
45669
|
-
},
|
|
45670
|
-
{
|
|
45671
|
-
id: "filesystem",
|
|
45672
|
-
type: "filesystem",
|
|
45673
|
-
name: "Filesystem",
|
|
45674
|
-
description: "Read documents, write skill files",
|
|
45675
|
-
enabled: true,
|
|
45676
|
-
config: {}
|
|
45677
|
-
},
|
|
45678
|
-
{
|
|
45679
|
-
id: "document-parser",
|
|
45680
|
-
type: "document-parser",
|
|
45681
|
-
name: "Document Parser",
|
|
45682
|
-
description: "Parse documents with the chosen engine",
|
|
45683
|
-
enabled: true,
|
|
45684
|
-
config: { connectAll: true }
|
|
45685
|
-
}
|
|
45686
|
-
]
|
|
45687
|
-
}
|
|
45688
|
-
},
|
|
45689
46004
|
skills: {
|
|
45690
46005
|
"document-learning-learn-capability": {
|
|
45691
46006
|
version: "1.0.0",
|
|
@@ -45914,7 +46229,7 @@ function createParseDocumentTool({
|
|
|
45914
46229
|
}
|
|
45915
46230
|
|
|
45916
46231
|
// src/middlewares/documentParserMiddleware.ts
|
|
45917
|
-
var
|
|
46232
|
+
var import_protocols34 = require("@axiom-lattice/protocols");
|
|
45918
46233
|
|
|
45919
46234
|
// src/middlewares/documentBenchmarkWorkflow.ts
|
|
45920
46235
|
var DOCUMENT_PARSER_BENCHMARK_YAML = `name: document-parser-benchmark
|
|
@@ -46367,6 +46682,23 @@ function createDocumentParserMiddleware(config) {
|
|
|
46367
46682
|
tools: [createParseDocumentTool({ connectAll, connections, baseUrl, apiKey })]
|
|
46368
46683
|
});
|
|
46369
46684
|
}
|
|
46685
|
+
var DOCUMENT_PARSER_SYSTEM_PROMPT = `You are the Document Parser. Turn documents (pdf, docx, images, spreadsheets, and similar) into clean Markdown.
|
|
46686
|
+
|
|
46687
|
+
CRITICAL FIRST ACTION: call the \`skill\` tool with skill_name: "document-parser-markitdown" and follow it. Never announce skill loads.
|
|
46688
|
+
|
|
46689
|
+
DEFAULT \u2014 local MarkItDown:
|
|
46690
|
+
- Single file: run \`markitdown <input> -o <output.md>\` via shell.
|
|
46691
|
+
- Batch or literature collections: use the scripts bundled in the skill.
|
|
46692
|
+
- After converting, verify the output is non-empty and its structure/tables are intact, then report the exact input -> output paths.
|
|
46693
|
+
|
|
46694
|
+
ESCALATION \u2014 remote parse_document:
|
|
46695
|
+
- 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.
|
|
46696
|
+
- 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.
|
|
46697
|
+
|
|
46698
|
+
BENCHMARK:
|
|
46699
|
+
- 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.
|
|
46700
|
+
|
|
46701
|
+
Report only what you actually produced; never claim success without inspecting the output file.`;
|
|
46370
46702
|
var documentParserPlugin = {
|
|
46371
46703
|
meta: {
|
|
46372
46704
|
type: "document-parser",
|
|
@@ -46437,9 +46769,59 @@ var documentParserPlugin = {
|
|
|
46437
46769
|
},
|
|
46438
46770
|
middleware: (config) => createDocumentParserMiddleware(config),
|
|
46439
46771
|
agents: {
|
|
46772
|
+
"document-parser": {
|
|
46773
|
+
key: "document-parser",
|
|
46774
|
+
type: import_protocols34.AgentType.DEEP_AGENT,
|
|
46775
|
+
name: "Document Parser",
|
|
46776
|
+
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.",
|
|
46777
|
+
prompt: DOCUMENT_PARSER_SYSTEM_PROMPT,
|
|
46778
|
+
subAgents: ["document-parser-benchmark"],
|
|
46779
|
+
middleware: [
|
|
46780
|
+
{
|
|
46781
|
+
id: "skill",
|
|
46782
|
+
type: "skill",
|
|
46783
|
+
name: "Skill",
|
|
46784
|
+
description: "Load the local MarkItDown parsing procedure",
|
|
46785
|
+
enabled: true,
|
|
46786
|
+
config: { readAll: true }
|
|
46787
|
+
},
|
|
46788
|
+
{
|
|
46789
|
+
id: "filesystem",
|
|
46790
|
+
type: "filesystem",
|
|
46791
|
+
name: "Filesystem",
|
|
46792
|
+
description: "Read source documents and write Markdown output",
|
|
46793
|
+
enabled: true,
|
|
46794
|
+
config: { vmIsolation: "project" }
|
|
46795
|
+
},
|
|
46796
|
+
{
|
|
46797
|
+
id: "code_eval",
|
|
46798
|
+
type: "code_eval",
|
|
46799
|
+
name: "Code Runner",
|
|
46800
|
+
description: "Run the markitdown CLI and bundled conversion scripts",
|
|
46801
|
+
enabled: true,
|
|
46802
|
+
config: { vmIsolation: "project" }
|
|
46803
|
+
},
|
|
46804
|
+
{
|
|
46805
|
+
id: "document-parser",
|
|
46806
|
+
type: "document-parser",
|
|
46807
|
+
name: "Document Parser",
|
|
46808
|
+
description: "Remote parse_document fallback for hard documents",
|
|
46809
|
+
enabled: true,
|
|
46810
|
+
config: { connectAll: true }
|
|
46811
|
+
},
|
|
46812
|
+
{
|
|
46813
|
+
id: "ask_user_to_clarify",
|
|
46814
|
+
type: "ask_user_to_clarify",
|
|
46815
|
+
name: "Ask User",
|
|
46816
|
+
description: "Confirm engine switches and benchmark runs",
|
|
46817
|
+
enabled: true,
|
|
46818
|
+
config: {}
|
|
46819
|
+
}
|
|
46820
|
+
]
|
|
46821
|
+
},
|
|
46440
46822
|
"document-parser-benchmark": {
|
|
46441
46823
|
key: "document-parser-benchmark",
|
|
46442
|
-
type:
|
|
46824
|
+
type: import_protocols34.AgentType.WORKFLOW,
|
|
46443
46825
|
name: "Document Parser Benchmark",
|
|
46444
46826
|
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.",
|
|
46445
46827
|
prompt: "Benchmark document parsing engines: parse with 5 engines, score, and rank results.",
|
|
@@ -46476,7 +46858,7 @@ var documentParserPlugin = {
|
|
|
46476
46858
|
|
|
46477
46859
|
// src/middlewares/projectRoomMiddleware.ts
|
|
46478
46860
|
var import_crypto10 = require("crypto");
|
|
46479
|
-
var
|
|
46861
|
+
var import_protocols35 = require("@axiom-lattice/protocols");
|
|
46480
46862
|
var import_langchain87 = require("langchain");
|
|
46481
46863
|
var import_zod70 = require("zod");
|
|
46482
46864
|
var PROJECT_ROOM_CONTEXT_REQUIRED = "PROJECT_ROOM_CONTEXT_REQUIRED";
|
|
@@ -46506,7 +46888,7 @@ function ownDataValue2(record, key5) {
|
|
|
46506
46888
|
if (typeof record !== "object" || record === null || Array.isArray(record)) return void 0;
|
|
46507
46889
|
try {
|
|
46508
46890
|
const descriptor = Object.getOwnPropertyDescriptor(record, key5);
|
|
46509
|
-
return (0,
|
|
46891
|
+
return (0, import_protocols35.descriptorDataValue)(descriptor)?.value;
|
|
46510
46892
|
} catch {
|
|
46511
46893
|
return void 0;
|
|
46512
46894
|
}
|
|
@@ -46516,14 +46898,14 @@ function readTrustedRoomScope(config) {
|
|
|
46516
46898
|
const runConfig = ownDataValue2(configurable, "runConfig");
|
|
46517
46899
|
const projectRoom = ownDataValue2(runConfig, "projectRoom");
|
|
46518
46900
|
try {
|
|
46519
|
-
return (0,
|
|
46901
|
+
return (0, import_protocols35.parseTrustedRunContext)({ projectRoom }).projectRoom;
|
|
46520
46902
|
} catch {
|
|
46521
46903
|
return void 0;
|
|
46522
46904
|
}
|
|
46523
46905
|
}
|
|
46524
46906
|
function exactValues2(value, required, optional = []) {
|
|
46525
46907
|
try {
|
|
46526
|
-
return (0,
|
|
46908
|
+
return (0, import_protocols35.snapshotExactRecord)(value, required, optional);
|
|
46527
46909
|
} catch {
|
|
46528
46910
|
return void 0;
|
|
46529
46911
|
}
|
|
@@ -46559,7 +46941,7 @@ function snapshotMembership3(value) {
|
|
|
46559
46941
|
return { ...values, joinedAt, updatedAt };
|
|
46560
46942
|
}
|
|
46561
46943
|
function snapshotRows(value) {
|
|
46562
|
-
return (0,
|
|
46944
|
+
return (0, import_protocols35.snapshotExactArray)(value) ?? [];
|
|
46563
46945
|
}
|
|
46564
46946
|
async function hasActiveCurrentMembership(scope) {
|
|
46565
46947
|
const memberships = getStoreLattice("default", "projectBotMembership").store;
|
|
@@ -46646,7 +47028,7 @@ var projectRoomPlugin = {
|
|
|
46646
47028
|
// src/middlewares/sandboxPluginsMiddleware.ts
|
|
46647
47029
|
var import_langchain88 = require("langchain");
|
|
46648
47030
|
var import_zod71 = require("zod");
|
|
46649
|
-
var
|
|
47031
|
+
var import_protocols36 = require("@axiom-lattice/protocols");
|
|
46650
47032
|
|
|
46651
47033
|
// src/middlewares/sandboxPluginsSkills.ts
|
|
46652
47034
|
var PLUGIN_JSON_TEMPLATE = `{
|
|
@@ -47396,7 +47778,7 @@ var sandboxPluginsPlugin = {
|
|
|
47396
47778
|
key: "plugin-builder",
|
|
47397
47779
|
name: "Plugin Builder",
|
|
47398
47780
|
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.",
|
|
47399
|
-
type:
|
|
47781
|
+
type: import_protocols36.AgentType.DEEP_AGENT,
|
|
47400
47782
|
prompt: PLUGIN_BUILDER_PROMPT,
|
|
47401
47783
|
middleware: [
|
|
47402
47784
|
{
|
|
@@ -48084,6 +48466,7 @@ registerBuiltinPlugins();
|
|
|
48084
48466
|
InMemoryDatabaseConfigStore,
|
|
48085
48467
|
InMemoryMailboxStore,
|
|
48086
48468
|
InMemoryMenuStore,
|
|
48469
|
+
InMemoryModelProviderStore,
|
|
48087
48470
|
InMemoryOpenAuditStore,
|
|
48088
48471
|
InMemoryProjectBotMembershipStore,
|
|
48089
48472
|
InMemoryProjectMembershipStore,
|
|
@@ -48177,6 +48560,7 @@ registerBuiltinPlugins();
|
|
|
48177
48560
|
ThreadStatus,
|
|
48178
48561
|
TokenCache,
|
|
48179
48562
|
ToolLatticeManager,
|
|
48563
|
+
UnsafeUpstreamUrlError,
|
|
48180
48564
|
VectorStoreLatticeManager,
|
|
48181
48565
|
VectorStoreProviderManager,
|
|
48182
48566
|
VolumeFilesystem,
|
|
@@ -48185,6 +48569,7 @@ registerBuiltinPlugins();
|
|
|
48185
48569
|
agentLatticeManager,
|
|
48186
48570
|
appendReconciliationWarning,
|
|
48187
48571
|
appendUiFence,
|
|
48572
|
+
assertSafeUpstreamUrl,
|
|
48188
48573
|
buildGrepResultsDict,
|
|
48189
48574
|
buildInput,
|
|
48190
48575
|
buildNamedVolumeName,
|
|
@@ -48316,6 +48701,7 @@ registerBuiltinPlugins();
|
|
|
48316
48701
|
invokeWithRetry,
|
|
48317
48702
|
isBuiltInSkill,
|
|
48318
48703
|
isDirectRoom,
|
|
48704
|
+
isMcpConnectionError,
|
|
48319
48705
|
isPluginSkillAuthorizedInSandbox,
|
|
48320
48706
|
isPluginSkillManagedInSandbox,
|
|
48321
48707
|
isUsingDefaultKey,
|
|
@@ -48338,7 +48724,6 @@ registerBuiltinPlugins();
|
|
|
48338
48724
|
parallelLimit,
|
|
48339
48725
|
parseCronExpression,
|
|
48340
48726
|
parseDirectRoomType,
|
|
48341
|
-
parseExternalDependency,
|
|
48342
48727
|
parseJudgeVerdict,
|
|
48343
48728
|
parsePackSize,
|
|
48344
48729
|
parseQueuedExecutionMode,
|
|
@@ -48367,6 +48752,7 @@ registerBuiltinPlugins();
|
|
|
48367
48752
|
registerExistingToolWithTenant,
|
|
48368
48753
|
registerLoggerLattice,
|
|
48369
48754
|
registerModelLattice,
|
|
48755
|
+
registerModelLatticeForTenant,
|
|
48370
48756
|
registerQueueLattice,
|
|
48371
48757
|
registerSTTModelLattice,
|
|
48372
48758
|
registerSandboxProviderType,
|