@axiom-lattice/core 6.0.0 → 6.1.1
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 +203 -5
- package/dist/index.d.ts +203 -5
- package/dist/index.js +403 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +399 -17
- 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,
|
|
@@ -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);
|
|
@@ -13205,8 +13524,8 @@ function readLoopBreakerConfig(env = process.env) {
|
|
|
13205
13524
|
return Math.floor(parsed);
|
|
13206
13525
|
};
|
|
13207
13526
|
return {
|
|
13208
|
-
repeatWarn: parse(env.AGENT_REPEATED_TOOL_CALL_WARN,
|
|
13209
|
-
repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP,
|
|
13527
|
+
repeatWarn: parse(env.AGENT_REPEATED_TOOL_CALL_WARN, 20),
|
|
13528
|
+
repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP, 25),
|
|
13210
13529
|
runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT, 300),
|
|
13211
13530
|
skillRunLimit: parse(env.AGENT_SKILL_CALL_RUN_LIMIT, 8)
|
|
13212
13531
|
};
|
|
@@ -13229,9 +13548,9 @@ var BREAKER_STATE_SCHEMA = import_zod43.z.object({
|
|
|
13229
13548
|
repeatedToolCallMemberSignatures: import_zod43.z.array(import_zod43.z.string()).default([])
|
|
13230
13549
|
});
|
|
13231
13550
|
function createRepeatedToolCallBreakerMiddleware(options = {}) {
|
|
13232
|
-
const rawWarn = options.warnThreshold ??
|
|
13551
|
+
const rawWarn = options.warnThreshold ?? 20;
|
|
13233
13552
|
const warnThreshold = rawWarn > 0 ? Math.max(2, rawWarn) : 0;
|
|
13234
|
-
const stopThreshold = Math.max(1, options.stopThreshold ??
|
|
13553
|
+
const stopThreshold = Math.max(1, options.stopThreshold ?? 25);
|
|
13235
13554
|
return (0, import_langchain46.createMiddleware)({
|
|
13236
13555
|
name: "RepeatedToolCallBreaker",
|
|
13237
13556
|
stateSchema: BREAKER_STATE_SCHEMA,
|
|
@@ -36334,13 +36653,16 @@ var LatticeEvalProject = class {
|
|
|
36334
36653
|
constructor(project, onCaseComplete) {
|
|
36335
36654
|
this.suites = /* @__PURE__ */ new Map();
|
|
36336
36655
|
this.project = project;
|
|
36337
|
-
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
|
+
);
|
|
36338
36661
|
if (!modelLatticeManager.hasLattice(judgeModelKey)) {
|
|
36339
36662
|
throw new Error(
|
|
36340
36663
|
`Judge model "${judgeModelKey}" not found. Register it first or provide a valid modelKey.`
|
|
36341
36664
|
);
|
|
36342
36665
|
}
|
|
36343
|
-
const tenantId2 = this.project.lattice_server_config.tenant_id || "default";
|
|
36344
36666
|
this.judgeAgentKey = `${this.project.projectName}_judge_agent`;
|
|
36345
36667
|
const judgeAgentConfig = {
|
|
36346
36668
|
key: this.judgeAgentKey,
|
|
@@ -40690,6 +41012,47 @@ function clearEncryptionKeyCache() {
|
|
|
40690
41012
|
keyValidated = false;
|
|
40691
41013
|
}
|
|
40692
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
|
+
|
|
40693
41056
|
// src/middlewares/skillMiddleware.ts
|
|
40694
41057
|
var import_langchain66 = require("langchain");
|
|
40695
41058
|
|
|
@@ -43675,7 +44038,7 @@ var manageTaskSchema = import_zod68.z.object({
|
|
|
43675
44038
|
parentId: import_zod68.z.string().optional().describe("Parent task ID for grouping subtasks"),
|
|
43676
44039
|
sourceId: import_zod68.z.string().optional().describe("Source session/thread ID"),
|
|
43677
44040
|
context: import_zod68.z.record(import_zod68.z.unknown()).optional().describe("Additional context data"),
|
|
43678
|
-
ownerType: import_zod68.z.enum(["user", "agent"]).optional().describe("Owner type. Defaults to
|
|
44041
|
+
ownerType: import_zod68.z.enum(["user", "agent"]).optional().describe("Owner type. Defaults to the runtime actor: agent runtime (no user identity) -> 'agent', user runtime -> 'user'."),
|
|
43679
44042
|
ownerId: import_zod68.z.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
|
|
43680
44043
|
requireReview: import_zod68.z.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
|
|
43681
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"),
|
|
@@ -43862,7 +44225,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
43862
44225
|
return projectPolicyError(error);
|
|
43863
44226
|
}
|
|
43864
44227
|
}
|
|
43865
|
-
const
|
|
44228
|
+
const runtimeOwnerType = rc.user_id ? "user" : rc.assistant_id ? "agent" : "user";
|
|
44229
|
+
const requestedOwnerType = input.ownerType ?? runtimeOwnerType;
|
|
44230
|
+
const ownerId = input.ownerId || trustedScope?.assistantId || (requestedOwnerType === "agent" ? rc.assistant_id : null) || rc.user_id;
|
|
43866
44231
|
const store = getTaskStore();
|
|
43867
44232
|
const deleteOneTask = async (id) => {
|
|
43868
44233
|
if (delegatedTaskId && id !== delegatedTaskId) {
|
|
@@ -43931,7 +44296,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43931
44296
|
createScopeProjectId = createScopeProjectId ?? parentTask.projectId;
|
|
43932
44297
|
}
|
|
43933
44298
|
}
|
|
43934
|
-
const effectiveOwnerType = delegatedTaskId ? "agent" : trustedProject ? "agent" :
|
|
44299
|
+
const effectiveOwnerType = delegatedTaskId ? "agent" : trustedProject ? "agent" : requestedOwnerType;
|
|
43935
44300
|
const effectiveOwnerId = delegatedTaskId ? rc.assistant_id : ownerId;
|
|
43936
44301
|
if (delegatedTaskId && !effectiveOwnerId) {
|
|
43937
44302
|
return delegatedTaskScopeError(delegatedTaskId);
|
|
@@ -43957,6 +44322,14 @@ function createTaskMiddleware(options = {}) {
|
|
|
43957
44322
|
}
|
|
43958
44323
|
}
|
|
43959
44324
|
}
|
|
44325
|
+
if (!delegatedTaskId && (typeof effectiveOwnerId !== "string" || effectiveOwnerId.length === 0)) {
|
|
44326
|
+
return JSON.stringify({
|
|
44327
|
+
success: false,
|
|
44328
|
+
code: "TASK_OWNER_REQUIRED",
|
|
44329
|
+
error: "Cannot resolve task owner: no user or agent identity in this run.",
|
|
44330
|
+
hint: 'Provide an explicit ownerId, or retry with ownerType:"agent" if this run has an agent identity.'
|
|
44331
|
+
});
|
|
44332
|
+
}
|
|
43960
44333
|
if (effectiveOwnerType === "agent" && (input.result !== void 0 || input.failureReason !== void 0)) {
|
|
43961
44334
|
return JSON.stringify({
|
|
43962
44335
|
success: false,
|
|
@@ -45011,13 +45384,22 @@ function createTaskMiddleware(options = {}) {
|
|
|
45011
45384
|
try {
|
|
45012
45385
|
response = await handleManageTaskAction(input, config, validateExecutionResult, markMutation);
|
|
45013
45386
|
} catch (error) {
|
|
45014
|
-
if (
|
|
45387
|
+
if (error instanceof import_langgraph16.GraphInterrupt) throw error;
|
|
45388
|
+
if (error instanceof ExecutionResultNotPendingError) {
|
|
45389
|
+
return JSON.stringify({
|
|
45390
|
+
success: false,
|
|
45391
|
+
code: "EXECUTION_RESULT_NOT_PENDING",
|
|
45392
|
+
taskId: error.taskId,
|
|
45393
|
+
executionResultId: error.executionResultId,
|
|
45394
|
+
error: error.message
|
|
45395
|
+
});
|
|
45396
|
+
}
|
|
45397
|
+
if (input.executionResultId) throw error;
|
|
45015
45398
|
return JSON.stringify({
|
|
45016
45399
|
success: false,
|
|
45017
|
-
code: "
|
|
45018
|
-
|
|
45019
|
-
|
|
45020
|
-
error: error.message
|
|
45400
|
+
code: "TASK_ACTION_FAILED",
|
|
45401
|
+
error: error instanceof Error ? error.message : String(error),
|
|
45402
|
+
hint: "The action did not complete. Fix the input or retry; do not repeat the identical call."
|
|
45021
45403
|
});
|
|
45022
45404
|
}
|
|
45023
45405
|
return reconcileExplicitExecutionResult(
|
|
@@ -45183,8 +45565,8 @@ changes only when acceptance criteria are truly met.
|
|
|
45183
45565
|
${TASK_CONVERGENCE_GUIDANCE}
|
|
45184
45566
|
|
|
45185
45567
|
### Ownership defaults
|
|
45186
|
-
- No params: ownerType defaults to
|
|
45187
|
-
- ownerType="agent": auto-fills ownerId from current agent (subtask for yourself)
|
|
45568
|
+
- No params: ownerType defaults to the runtime actor (user runtime -> current user's ID; agent runtime -> current agent's ID)
|
|
45569
|
+
- ownerType="agent": auto-fills ownerId from the current agent (subtask for yourself)
|
|
45188
45570
|
- Explicit ownerId: assign to a specific agent or user`;
|
|
45189
45571
|
const boundTaskId = request.state?.taskId;
|
|
45190
45572
|
const binding = typeof boundTaskId === "string" && boundTaskId ? renderTaskBinding(boundTaskId) : "";
|
|
@@ -45203,7 +45585,7 @@ ${TASK_CONVERGENCE_GUIDANCE}
|
|
|
45203
45585
|
description: `Manage persistent tasks and their activity timelines for user and agent tasks.
|
|
45204
45586
|
|
|
45205
45587
|
## Owner defaults
|
|
45206
|
-
- No ownerType/ownerId: auto-assigned to current user
|
|
45588
|
+
- No ownerType/ownerId: auto-assigned to the runtime actor (user runtime -> current user; agent runtime -> current agent)
|
|
45207
45589
|
- ownerType="agent" without ownerId: auto-assigned to current agent
|
|
45208
45590
|
- Explicit ownerId: assign to a specific agent (cross-agent delegation)
|
|
45209
45591
|
|
|
@@ -48103,6 +48485,7 @@ registerBuiltinPlugins();
|
|
|
48103
48485
|
InMemoryDatabaseConfigStore,
|
|
48104
48486
|
InMemoryMailboxStore,
|
|
48105
48487
|
InMemoryMenuStore,
|
|
48488
|
+
InMemoryModelProviderStore,
|
|
48106
48489
|
InMemoryOpenAuditStore,
|
|
48107
48490
|
InMemoryProjectBotMembershipStore,
|
|
48108
48491
|
InMemoryProjectMembershipStore,
|
|
@@ -48196,6 +48579,7 @@ registerBuiltinPlugins();
|
|
|
48196
48579
|
ThreadStatus,
|
|
48197
48580
|
TokenCache,
|
|
48198
48581
|
ToolLatticeManager,
|
|
48582
|
+
UnsafeUpstreamUrlError,
|
|
48199
48583
|
VectorStoreLatticeManager,
|
|
48200
48584
|
VectorStoreProviderManager,
|
|
48201
48585
|
VolumeFilesystem,
|
|
@@ -48204,6 +48588,7 @@ registerBuiltinPlugins();
|
|
|
48204
48588
|
agentLatticeManager,
|
|
48205
48589
|
appendReconciliationWarning,
|
|
48206
48590
|
appendUiFence,
|
|
48591
|
+
assertSafeUpstreamUrl,
|
|
48207
48592
|
buildGrepResultsDict,
|
|
48208
48593
|
buildInput,
|
|
48209
48594
|
buildNamedVolumeName,
|
|
@@ -48386,6 +48771,7 @@ registerBuiltinPlugins();
|
|
|
48386
48771
|
registerExistingToolWithTenant,
|
|
48387
48772
|
registerLoggerLattice,
|
|
48388
48773
|
registerModelLattice,
|
|
48774
|
+
registerModelLatticeForTenant,
|
|
48389
48775
|
registerQueueLattice,
|
|
48390
48776
|
registerSTTModelLattice,
|
|
48391
48777
|
registerSandboxProviderType,
|