@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.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, 3),
13209
- repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP, 5),
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 ?? 3;
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 ?? 5);
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 judgeModelKey = resolveJudgeModelKey(this.project.judge_agent_config.modelKey, modelLatticeManager);
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 'user' if omitted"),
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 ownerId = input.ownerId || trustedScope?.assistantId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
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" : input.ownerType || "user";
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 (!(error instanceof ExecutionResultNotPendingError)) throw error;
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: "EXECUTION_RESULT_NOT_PENDING",
45018
- taskId: error.taskId,
45019
- executionResultId: error.executionResultId,
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 "user" with current user's ID
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,