@axiom-lattice/core 6.1.1 → 6.3.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 +875 -47
- package/dist/index.d.ts +875 -47
- package/dist/index.js +1836 -685
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1783 -661
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -2115,7 +2115,7 @@ var InMemoryModelProviderStore = class {
|
|
|
2115
2115
|
*/
|
|
2116
2116
|
async listProviders(tenantId2) {
|
|
2117
2117
|
return Array.from(this.providers.values()).filter(
|
|
2118
|
-
(
|
|
2118
|
+
(provider2) => provider2.tenantId === tenantId2
|
|
2119
2119
|
);
|
|
2120
2120
|
}
|
|
2121
2121
|
/**
|
|
@@ -2129,7 +2129,7 @@ var InMemoryModelProviderStore = class {
|
|
|
2129
2129
|
*/
|
|
2130
2130
|
async getProviderByName(tenantId2, name) {
|
|
2131
2131
|
const providers = await this.listProviders(tenantId2);
|
|
2132
|
-
return providers.find((
|
|
2132
|
+
return providers.find((provider2) => provider2.name === name) || null;
|
|
2133
2133
|
}
|
|
2134
2134
|
/**
|
|
2135
2135
|
* Create a new provider configuration
|
|
@@ -2313,8 +2313,8 @@ var InMemoryModelProviderStore = class {
|
|
|
2313
2313
|
* Clear providers and models for a specific tenant
|
|
2314
2314
|
*/
|
|
2315
2315
|
clearByTenant(tenantId2) {
|
|
2316
|
-
for (const [key5,
|
|
2317
|
-
if (
|
|
2316
|
+
for (const [key5, provider2] of Array.from(this.providers.entries())) {
|
|
2317
|
+
if (provider2.tenantId === tenantId2) {
|
|
2318
2318
|
this.providers.delete(key5);
|
|
2319
2319
|
}
|
|
2320
2320
|
}
|
|
@@ -3190,6 +3190,123 @@ function entryKey(tenantId2, userId, endpoint) {
|
|
|
3190
3190
|
return JSON.stringify([tenantId2, userId, endpoint]);
|
|
3191
3191
|
}
|
|
3192
3192
|
|
|
3193
|
+
// src/store_lattice/InMemoryLeaseStore.ts
|
|
3194
|
+
var InMemoryLeaseStore = class {
|
|
3195
|
+
/**
|
|
3196
|
+
* @param now Injectable clock in epoch milliseconds (tests use a fake clock).
|
|
3197
|
+
*/
|
|
3198
|
+
constructor(now = Date.now) {
|
|
3199
|
+
this.leases = /* @__PURE__ */ new Map();
|
|
3200
|
+
this.now = now;
|
|
3201
|
+
}
|
|
3202
|
+
/** Atomically acquires a free/expired key (or the caller's own key). */
|
|
3203
|
+
async tryAcquire(key5, holder, ttlMs) {
|
|
3204
|
+
const existing = this.leases.get(key5);
|
|
3205
|
+
if (existing && Date.parse(existing.expiresAt) > this.now()) {
|
|
3206
|
+
if (existing.holder !== holder) return false;
|
|
3207
|
+
this.leases.set(key5, { ...existing, expiresAt: new Date(this.now() + ttlMs).toISOString() });
|
|
3208
|
+
return true;
|
|
3209
|
+
}
|
|
3210
|
+
const acquiredAt = existing && existing.holder === holder ? existing.acquiredAt : new Date(this.now()).toISOString();
|
|
3211
|
+
this.leases.set(key5, {
|
|
3212
|
+
key: key5,
|
|
3213
|
+
holder,
|
|
3214
|
+
acquiredAt,
|
|
3215
|
+
expiresAt: new Date(this.now() + ttlMs).toISOString()
|
|
3216
|
+
});
|
|
3217
|
+
return true;
|
|
3218
|
+
}
|
|
3219
|
+
/** Extends a lease only while `holder` still owns it. */
|
|
3220
|
+
async renew(key5, holder, ttlMs) {
|
|
3221
|
+
const existing = this.leases.get(key5);
|
|
3222
|
+
if (!existing || existing.holder !== holder) return false;
|
|
3223
|
+
this.leases.set(key5, { ...existing, expiresAt: new Date(this.now() + ttlMs).toISOString() });
|
|
3224
|
+
return true;
|
|
3225
|
+
}
|
|
3226
|
+
/** Deletes a lease only when `holder` owns it. */
|
|
3227
|
+
async release(key5, holder) {
|
|
3228
|
+
const existing = this.leases.get(key5);
|
|
3229
|
+
if (!existing || existing.holder !== holder) return false;
|
|
3230
|
+
this.leases.delete(key5);
|
|
3231
|
+
return true;
|
|
3232
|
+
}
|
|
3233
|
+
/** Returns the live lease, pruning an expired one. */
|
|
3234
|
+
async get(key5) {
|
|
3235
|
+
const existing = this.leases.get(key5);
|
|
3236
|
+
if (!existing) return null;
|
|
3237
|
+
if (Date.parse(existing.expiresAt) <= this.now()) {
|
|
3238
|
+
this.leases.delete(key5);
|
|
3239
|
+
return null;
|
|
3240
|
+
}
|
|
3241
|
+
return { ...existing };
|
|
3242
|
+
}
|
|
3243
|
+
};
|
|
3244
|
+
|
|
3245
|
+
// src/store_lattice/InMemoryOutboxStore.ts
|
|
3246
|
+
var InMemoryOutboxStore = class {
|
|
3247
|
+
/**
|
|
3248
|
+
* Creates an in-memory outbox store.
|
|
3249
|
+
*
|
|
3250
|
+
* @param now Optional clock override (defaults to the system clock); it stamps
|
|
3251
|
+
* `createdAt` and is used to evaluate age-based retention.
|
|
3252
|
+
*/
|
|
3253
|
+
constructor(now = () => /* @__PURE__ */ new Date()) {
|
|
3254
|
+
this.events = [];
|
|
3255
|
+
this.counter = 0;
|
|
3256
|
+
this.now = now;
|
|
3257
|
+
}
|
|
3258
|
+
/**
|
|
3259
|
+
* Appends one event, assigning the next monotonic id.
|
|
3260
|
+
* @param input Topic, JSON-safe payload, and authoring replica id.
|
|
3261
|
+
* @returns A defensive copy of the stored event.
|
|
3262
|
+
*/
|
|
3263
|
+
async append(input) {
|
|
3264
|
+
const event = {
|
|
3265
|
+
id: String(++this.counter),
|
|
3266
|
+
topic: input.topic,
|
|
3267
|
+
payload: input.payload,
|
|
3268
|
+
originReplicaId: input.originReplicaId,
|
|
3269
|
+
createdAt: this.now().toISOString()
|
|
3270
|
+
};
|
|
3271
|
+
this.events.push(event);
|
|
3272
|
+
return { ...event };
|
|
3273
|
+
}
|
|
3274
|
+
/**
|
|
3275
|
+
* Lists events strictly newer than `cursor`, ascending, bounded by `limit`.
|
|
3276
|
+
* @param cursor Last-seen id, or `null` to read from the start.
|
|
3277
|
+
* @param limit Maximum number of events to return.
|
|
3278
|
+
* @returns Defensive copies of the matching events.
|
|
3279
|
+
*/
|
|
3280
|
+
async listAfter(cursor, limit) {
|
|
3281
|
+
const floor = cursor === null ? 0 : Number(cursor);
|
|
3282
|
+
return this.events.filter((event) => Number(event.id) > floor).slice(0, limit).map((event) => ({ ...event }));
|
|
3283
|
+
}
|
|
3284
|
+
/**
|
|
3285
|
+
* Returns the newest event id.
|
|
3286
|
+
* @returns The last id, or `null` when the log is empty.
|
|
3287
|
+
*/
|
|
3288
|
+
async latestId() {
|
|
3289
|
+
return this.events.length === 0 ? null : this.events[this.events.length - 1].id;
|
|
3290
|
+
}
|
|
3291
|
+
/**
|
|
3292
|
+
* Deletes events older than `olderThanMs`, evaluated against this store's clock.
|
|
3293
|
+
*
|
|
3294
|
+
* @param olderThanMs Age threshold in milliseconds.
|
|
3295
|
+
* @returns The number of events removed.
|
|
3296
|
+
*/
|
|
3297
|
+
async pruneOlderThan(olderThanMs) {
|
|
3298
|
+
const cutoff = this.now().getTime() - olderThanMs;
|
|
3299
|
+
let removed = 0;
|
|
3300
|
+
for (let i = this.events.length - 1; i >= 0; i -= 1) {
|
|
3301
|
+
if (new Date(this.events[i].createdAt).getTime() < cutoff) {
|
|
3302
|
+
this.events.splice(i, 1);
|
|
3303
|
+
removed += 1;
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
return removed;
|
|
3307
|
+
}
|
|
3308
|
+
};
|
|
3309
|
+
|
|
3193
3310
|
// src/store_lattice/InMemoryUserStore.ts
|
|
3194
3311
|
var InMemoryUserStore = class {
|
|
3195
3312
|
constructor() {
|
|
@@ -3396,7 +3513,8 @@ function isMessageContentValue(value) {
|
|
|
3396
3513
|
|
|
3397
3514
|
// src/store_lattice/InMemoryThreadMessageQueueStore.ts
|
|
3398
3515
|
var InMemoryThreadMessageQueueStore = class {
|
|
3399
|
-
constructor() {
|
|
3516
|
+
constructor(now = Date.now) {
|
|
3517
|
+
this.now = now;
|
|
3400
3518
|
this.messages = /* @__PURE__ */ new Map();
|
|
3401
3519
|
this.messageIdCounter = 0;
|
|
3402
3520
|
this.capacityTail = Promise.resolve();
|
|
@@ -3503,6 +3621,36 @@ var InMemoryThreadMessageQueueStore = class {
|
|
|
3503
3621
|
const threadMessages = this.getMessagesForThread(threadId);
|
|
3504
3622
|
return threadMessages.filter((msg) => msg.status === "processing" && this.inScope(msg, scope)).sort((a, b) => (b.priority || 0) - (a.priority || 0) || a.sequence - b.sequence).map(clonePendingMessage);
|
|
3505
3623
|
}
|
|
3624
|
+
async claimPendingMessages(threadId, scope, options) {
|
|
3625
|
+
const threadMessages = this.getMessagesForThread(threadId);
|
|
3626
|
+
const candidates = threadMessages.filter((msg) => (msg.status === "pending" || !msg.status) && this.inScope(msg, scope)).sort((a, b) => (b.priority || 0) - (a.priority || 0) || a.sequence - b.sequence);
|
|
3627
|
+
const limit = options.limit === void 0 ? void 0 : Math.max(0, Math.floor(options.limit));
|
|
3628
|
+
const selected = limit === void 0 ? candidates : candidates.slice(0, limit);
|
|
3629
|
+
const now = this.now();
|
|
3630
|
+
for (const message of selected) {
|
|
3631
|
+
message.status = "processing";
|
|
3632
|
+
message.lockedBy = options.owner;
|
|
3633
|
+
message.lockedAt = new Date(now);
|
|
3634
|
+
message.leaseExpiresAt = new Date(now + options.ttlMs);
|
|
3635
|
+
}
|
|
3636
|
+
return selected.map(clonePendingMessage);
|
|
3637
|
+
}
|
|
3638
|
+
async reclaimExpiredProcessing(threadId, scope) {
|
|
3639
|
+
const messages = this.messages.get(threadId);
|
|
3640
|
+
if (!messages) return 0;
|
|
3641
|
+
const now = this.now();
|
|
3642
|
+
let count = 0;
|
|
3643
|
+
for (const msg of messages) {
|
|
3644
|
+
if (msg.status === "processing" && this.inScope(msg, scope) && msg.leaseExpiresAt !== void 0 && msg.leaseExpiresAt.getTime() <= now) {
|
|
3645
|
+
msg.status = "pending";
|
|
3646
|
+
msg.lockedBy = void 0;
|
|
3647
|
+
msg.lockedAt = void 0;
|
|
3648
|
+
msg.leaseExpiresAt = void 0;
|
|
3649
|
+
count += 1;
|
|
3650
|
+
}
|
|
3651
|
+
}
|
|
3652
|
+
return count;
|
|
3653
|
+
}
|
|
3506
3654
|
async getQueueSize(threadId, scope) {
|
|
3507
3655
|
const pending = await this.getPendingMessages(threadId, scope);
|
|
3508
3656
|
return pending.length;
|
|
@@ -3566,6 +3714,9 @@ var InMemoryThreadMessageQueueStore = class {
|
|
|
3566
3714
|
for (const msg of messages) {
|
|
3567
3715
|
if (msg.status === "processing" && this.inScope(msg, scope)) {
|
|
3568
3716
|
msg.status = "pending";
|
|
3717
|
+
msg.lockedBy = void 0;
|
|
3718
|
+
msg.lockedAt = void 0;
|
|
3719
|
+
msg.leaseExpiresAt = void 0;
|
|
3569
3720
|
count++;
|
|
3570
3721
|
}
|
|
3571
3722
|
}
|
|
@@ -4824,6 +4975,8 @@ var defaultProjectBotMembershipStore = new InMemoryProjectBotMembershipStore(def
|
|
|
4824
4975
|
var defaultProjectRoomMessageStore = new InMemoryProjectRoomMessageStore(defaultProjectRoomCoordinator);
|
|
4825
4976
|
var defaultProjectRoomReadStateStore = new InMemoryProjectRoomReadStateStore();
|
|
4826
4977
|
var defaultUserPushSubscriptionStore = new InMemoryUserPushSubscriptionStore();
|
|
4978
|
+
var defaultLeaseStore = new InMemoryLeaseStore();
|
|
4979
|
+
var defaultOutboxStore = new InMemoryOutboxStore();
|
|
4827
4980
|
storeLatticeManager.registerLattice("default", "thread", defaultThreadStore);
|
|
4828
4981
|
storeLatticeManager.registerLattice(
|
|
4829
4982
|
"default",
|
|
@@ -4845,6 +4998,8 @@ storeLatticeManager.registerLattice("default", "projectBotMembership", defaultPr
|
|
|
4845
4998
|
storeLatticeManager.registerLattice("default", "projectRoomMessage", defaultProjectRoomMessageStore);
|
|
4846
4999
|
storeLatticeManager.registerLattice("default", "projectRoomReadState", defaultProjectRoomReadStateStore);
|
|
4847
5000
|
storeLatticeManager.registerLattice("default", "userPushSubscription", defaultUserPushSubscriptionStore);
|
|
5001
|
+
storeLatticeManager.registerLattice("default", "lease", defaultLeaseStore);
|
|
5002
|
+
storeLatticeManager.registerLattice("default", "outbox", defaultOutboxStore);
|
|
4848
5003
|
var defaultUserStore = new InMemoryUserStore();
|
|
4849
5004
|
var defaultTenantStore = new InMemoryTenantStore();
|
|
4850
5005
|
var defaultUserTenantLinkStore = new InMemoryUserTenantLinkStore();
|
|
@@ -6713,8 +6868,8 @@ var MetricsServerManager = class _MetricsServerManager {
|
|
|
6713
6868
|
} catch {
|
|
6714
6869
|
}
|
|
6715
6870
|
const tenantConfigs = this.configs.get(tenantId2);
|
|
6716
|
-
const
|
|
6717
|
-
if (
|
|
6871
|
+
const cached2 = tenantConfigs?.get(key5);
|
|
6872
|
+
if (cached2) return cached2;
|
|
6718
6873
|
throw new Error(`Metrics server '${key5}' not found for tenant '${tenantId2}'`);
|
|
6719
6874
|
}
|
|
6720
6875
|
/**
|
|
@@ -8024,8 +8179,8 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
|
|
|
8024
8179
|
getLatticeType() {
|
|
8025
8180
|
return "sandbox_manager";
|
|
8026
8181
|
}
|
|
8027
|
-
registerLattice(key5,
|
|
8028
|
-
this.register(key5,
|
|
8182
|
+
registerLattice(key5, provider2) {
|
|
8183
|
+
this.register(key5, provider2);
|
|
8029
8184
|
}
|
|
8030
8185
|
getSandboxLattice(key5) {
|
|
8031
8186
|
const lattice = this.get(key5);
|
|
@@ -8076,8 +8231,8 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
|
|
|
8076
8231
|
return this.getVolumeBackendForPath(config, "/project");
|
|
8077
8232
|
}
|
|
8078
8233
|
async getVolumeBackendForPath(config, filePath) {
|
|
8079
|
-
const
|
|
8080
|
-
if (!
|
|
8234
|
+
const provider2 = this._requireProvider();
|
|
8235
|
+
if (!provider2.createVolumeFsClient) {
|
|
8081
8236
|
console.log(`[getVolumeBackendForPath] provider has no createVolumeFsClient, returning null`);
|
|
8082
8237
|
return null;
|
|
8083
8238
|
}
|
|
@@ -8088,7 +8243,7 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
|
|
|
8088
8243
|
return null;
|
|
8089
8244
|
}
|
|
8090
8245
|
console.log(`[getVolumeBackendForPath] path=${filePath} volume=${mapping.volumeName} prefix=${mapping.pathPrefix}`);
|
|
8091
|
-
const client =
|
|
8246
|
+
const client = provider2.createVolumeFsClient(mapping.volumeName, mapping.pathPrefix);
|
|
8092
8247
|
return new VolumeFilesystem(stripPrefixClient(client, mapping.pathPrefix), mapping.pathPrefix);
|
|
8093
8248
|
}
|
|
8094
8249
|
_resolveVolumeForPath(config, tenantId2, filePath) {
|
|
@@ -8123,35 +8278,35 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
|
|
|
8123
8278
|
};
|
|
8124
8279
|
}
|
|
8125
8280
|
async createSandbox(name, config) {
|
|
8126
|
-
const
|
|
8127
|
-
return
|
|
8281
|
+
const provider2 = this._requireProvider();
|
|
8282
|
+
return provider2.createSandbox(name, config);
|
|
8128
8283
|
}
|
|
8129
8284
|
async getSandbox(name) {
|
|
8130
|
-
const
|
|
8131
|
-
return
|
|
8285
|
+
const provider2 = this._requireProvider();
|
|
8286
|
+
return provider2.getSandbox(name);
|
|
8132
8287
|
}
|
|
8133
8288
|
async stopSandbox(name) {
|
|
8134
|
-
const
|
|
8135
|
-
return
|
|
8289
|
+
const provider2 = this._requireProvider();
|
|
8290
|
+
return provider2.stopSandbox(name);
|
|
8136
8291
|
}
|
|
8137
8292
|
async deleteSandbox(name) {
|
|
8138
|
-
const
|
|
8139
|
-
return
|
|
8293
|
+
const provider2 = this._requireProvider();
|
|
8294
|
+
return provider2.deleteSandbox(name);
|
|
8140
8295
|
}
|
|
8141
8296
|
async listSandboxes() {
|
|
8142
|
-
const
|
|
8143
|
-
return
|
|
8297
|
+
const provider2 = this._requireProvider();
|
|
8298
|
+
return provider2.listSandboxes();
|
|
8144
8299
|
}
|
|
8145
8300
|
_requireProvider() {
|
|
8146
8301
|
const keys = this.keysByTenant("default");
|
|
8147
8302
|
if (keys.length === 0) {
|
|
8148
8303
|
throw new Error("Sandbox provider not configured.");
|
|
8149
8304
|
}
|
|
8150
|
-
const
|
|
8151
|
-
if (!
|
|
8305
|
+
const provider2 = this.get(keys[0]);
|
|
8306
|
+
if (!provider2) {
|
|
8152
8307
|
throw new Error("Sandbox provider not configured.");
|
|
8153
8308
|
}
|
|
8154
|
-
return
|
|
8309
|
+
return provider2;
|
|
8155
8310
|
}
|
|
8156
8311
|
/**
|
|
8157
8312
|
* Returns the first registered (default) sandbox provider.
|
|
@@ -8181,6 +8336,46 @@ import { tool as tool14 } from "langchain";
|
|
|
8181
8336
|
// src/tool_lattice/shell_exec/index.ts
|
|
8182
8337
|
import z17 from "zod";
|
|
8183
8338
|
import { tool as tool15 } from "langchain";
|
|
8339
|
+
|
|
8340
|
+
// src/sandbox_lattice/sandboxOpenCredential.ts
|
|
8341
|
+
var SANDBOX_OPEN_GATEWAY_URL_ENV = "API_GATEWAY_URL";
|
|
8342
|
+
var SANDBOX_OPEN_TOKEN_ENV = "OPEN_API_TOKEN";
|
|
8343
|
+
var provider;
|
|
8344
|
+
var providerErrorHandler;
|
|
8345
|
+
function registerSandboxOpenCredentialProvider(next, options = {}) {
|
|
8346
|
+
provider = next;
|
|
8347
|
+
providerErrorHandler = options.onError;
|
|
8348
|
+
return () => {
|
|
8349
|
+
if (provider === next) {
|
|
8350
|
+
provider = void 0;
|
|
8351
|
+
providerErrorHandler = void 0;
|
|
8352
|
+
}
|
|
8353
|
+
};
|
|
8354
|
+
}
|
|
8355
|
+
async function getSandboxOpenCredential(context) {
|
|
8356
|
+
if (!provider) return void 0;
|
|
8357
|
+
try {
|
|
8358
|
+
return await provider(context);
|
|
8359
|
+
} catch (error) {
|
|
8360
|
+
try {
|
|
8361
|
+
providerErrorHandler?.(error);
|
|
8362
|
+
} catch {
|
|
8363
|
+
}
|
|
8364
|
+
return void 0;
|
|
8365
|
+
}
|
|
8366
|
+
}
|
|
8367
|
+
function buildSandboxOpenEnv(credential) {
|
|
8368
|
+
return `export ${SANDBOX_OPEN_GATEWAY_URL_ENV}=${shellSingleQuote(credential.gatewayUrl)} && export ${SANDBOX_OPEN_TOKEN_ENV}=${shellSingleQuote(credential.token)}`;
|
|
8369
|
+
}
|
|
8370
|
+
function shellSingleQuote(value) {
|
|
8371
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
8372
|
+
}
|
|
8373
|
+
function clearSandboxOpenCredentialProviderForTests() {
|
|
8374
|
+
provider = void 0;
|
|
8375
|
+
providerErrorHandler = void 0;
|
|
8376
|
+
}
|
|
8377
|
+
|
|
8378
|
+
// src/tool_lattice/shell_exec/index.ts
|
|
8184
8379
|
var SHELL_EXEC_DESCRIPTION = `Execute a shell command in the sandbox environment.
|
|
8185
8380
|
|
|
8186
8381
|
Use this to run CLI tools, install packages, inspect files, or perform any operation that requires a shell.
|
|
@@ -8213,8 +8408,19 @@ var createShellExecTool = ({
|
|
|
8213
8408
|
projectId: runConfig.projectId,
|
|
8214
8409
|
vmIsolation
|
|
8215
8410
|
});
|
|
8411
|
+
const tenantId2 = runConfig.tenantId;
|
|
8412
|
+
const credential = tenantId2 ? await getSandboxOpenCredential({
|
|
8413
|
+
tenantId: tenantId2,
|
|
8414
|
+
workspaceId: runConfig.workspaceId,
|
|
8415
|
+
projectId: runConfig.projectId,
|
|
8416
|
+
sandboxName: sandbox.name,
|
|
8417
|
+
assistantId: runConfig.assistant_id || void 0,
|
|
8418
|
+
threadId: runConfig.thread_id || void 0,
|
|
8419
|
+
depth: runConfig.depth
|
|
8420
|
+
}) : void 0;
|
|
8421
|
+
const command = credential ? `${buildSandboxOpenEnv(credential)} && ${input.command}` : input.command;
|
|
8216
8422
|
const executeResult = await sandbox.shell.execCommand({
|
|
8217
|
-
command
|
|
8423
|
+
command,
|
|
8218
8424
|
exec_dir: input.exec_dir,
|
|
8219
8425
|
timeout: input.timeout ?? 300
|
|
8220
8426
|
});
|
|
@@ -12952,13 +13158,23 @@ var SandboxPluginExecutor = class {
|
|
|
12952
13158
|
validateRelativePath(args.handler, "handler");
|
|
12953
13159
|
const pluginDir = `${PLUGINS_ROOT}/${args.manifest.type}`;
|
|
12954
13160
|
const handlerAbs = `${pluginDir}/${args.handler}`;
|
|
13161
|
+
const tenantId2 = args.runConfig?.tenantId ?? args.context.tenantId;
|
|
12955
13162
|
const sandbox = await this.deps.resolveSandbox({
|
|
12956
|
-
tenantId:
|
|
13163
|
+
tenantId: tenantId2,
|
|
12957
13164
|
assistantId: args.runConfig?.assistantId,
|
|
12958
13165
|
threadId: args.runConfig?.threadId,
|
|
12959
13166
|
workspaceId: args.runConfig?.workspaceId,
|
|
12960
13167
|
projectId: args.runConfig?.projectId
|
|
12961
13168
|
});
|
|
13169
|
+
const openCredential = tenantId2 ? await getSandboxOpenCredential({
|
|
13170
|
+
tenantId: tenantId2,
|
|
13171
|
+
workspaceId: args.runConfig?.workspaceId,
|
|
13172
|
+
projectId: args.runConfig?.projectId,
|
|
13173
|
+
sandboxName: sandbox.name,
|
|
13174
|
+
assistantId: args.runConfig?.assistantId,
|
|
13175
|
+
threadId: args.runConfig?.threadId,
|
|
13176
|
+
depth: args.runConfig?.depth
|
|
13177
|
+
}) : void 0;
|
|
12962
13178
|
const timeoutMs = clamp(args.timeoutMs ?? DEFAULT_TIMEOUT_MS, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS);
|
|
12963
13179
|
const cap = clamp(
|
|
12964
13180
|
args.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES,
|
|
@@ -12989,6 +13205,12 @@ var SandboxPluginExecutor = class {
|
|
|
12989
13205
|
envParts.push(`PLUGIN_CONNECTION_FILE=${quotePosixShellArg(connectionFile)}`);
|
|
12990
13206
|
}
|
|
12991
13207
|
envParts.push(`PLUGIN_CONTEXT=${quotePosixShellArg(encode(args.context))}`);
|
|
13208
|
+
if (openCredential) {
|
|
13209
|
+
envParts.push(
|
|
13210
|
+
`${SANDBOX_OPEN_GATEWAY_URL_ENV}=${quotePosixShellArg(openCredential.gatewayUrl)}`
|
|
13211
|
+
);
|
|
13212
|
+
envParts.push(`${SANDBOX_OPEN_TOKEN_ENV}=${quotePosixShellArg(openCredential.token)}`);
|
|
13213
|
+
}
|
|
12992
13214
|
const command = `${envParts.join(" ")} node ${quotePosixShellArg(handlerAbs)}`;
|
|
12993
13215
|
const execResult = await sandbox.shell.execCommand({
|
|
12994
13216
|
command,
|
|
@@ -13940,10 +14162,10 @@ var TenantPluginCatalog = class {
|
|
|
13940
14162
|
candidates.push({ type, dirPath: dir.path, raw, manifestJson, files: dirFiles });
|
|
13941
14163
|
}
|
|
13942
14164
|
const hash = createHash3("sha256").update(hashParts.sort().join("\n")).digest("hex").slice(0, 16);
|
|
13943
|
-
const
|
|
13944
|
-
if (
|
|
13945
|
-
this.cache.set(tenantId2, { value:
|
|
13946
|
-
return
|
|
14165
|
+
const cached2 = this.cache.get(tenantId2)?.value;
|
|
14166
|
+
if (cached2 && cached2.hash === hash) {
|
|
14167
|
+
this.cache.set(tenantId2, { value: cached2, checkedAt: this.now() });
|
|
14168
|
+
return cached2;
|
|
13947
14169
|
}
|
|
13948
14170
|
const plugins = [];
|
|
13949
14171
|
const manifests = {};
|
|
@@ -15304,7 +15526,7 @@ var AgentWorkerState = Annotation.Root({
|
|
|
15304
15526
|
default: () => ({})
|
|
15305
15527
|
}),
|
|
15306
15528
|
command2: Annotation({
|
|
15307
|
-
reducer: (
|
|
15529
|
+
reducer: (_x, y) => y,
|
|
15308
15530
|
default: () => void 0
|
|
15309
15531
|
}),
|
|
15310
15532
|
// RunConfig for passing configuration through the graph
|
|
@@ -15321,12 +15543,12 @@ var AgentWorkerState = Annotation.Root({
|
|
|
15321
15543
|
}),
|
|
15322
15544
|
// Execution result
|
|
15323
15545
|
result: Annotation({
|
|
15324
|
-
reducer: (
|
|
15546
|
+
reducer: (_x, y) => y,
|
|
15325
15547
|
default: () => void 0
|
|
15326
15548
|
}),
|
|
15327
15549
|
// Interrupt data
|
|
15328
15550
|
interruptValue: Annotation({
|
|
15329
|
-
reducer: (
|
|
15551
|
+
reducer: (_x, y) => y,
|
|
15330
15552
|
default: () => void 0
|
|
15331
15553
|
}),
|
|
15332
15554
|
// Final state to return
|
|
@@ -15404,6 +15626,324 @@ function createAgentWorkerGraph() {
|
|
|
15404
15626
|
}
|
|
15405
15627
|
var agentWorkerGraph = createAgentWorkerGraph();
|
|
15406
15628
|
|
|
15629
|
+
// src/util/toJsonSafeValue.ts
|
|
15630
|
+
var CIRCULAR_VALUE = "[Circular]";
|
|
15631
|
+
var REPEATED_VALUE = "[Repeated]";
|
|
15632
|
+
var arrayFrom = Array.from.bind(Array);
|
|
15633
|
+
var arrayIsArray = Array.isArray.bind(Array);
|
|
15634
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
|
|
15635
|
+
var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
|
|
15636
|
+
var objectCreate = Object.create.bind(Object);
|
|
15637
|
+
var objectDefineProperty = Object.defineProperty.bind(Object);
|
|
15638
|
+
var objectIs = Object.is.bind(Object);
|
|
15639
|
+
var reflectGet = Reflect.get.bind(Reflect);
|
|
15640
|
+
var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
|
|
15641
|
+
var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
|
|
15642
|
+
var stringifyJson = JSON.stringify.bind(JSON);
|
|
15643
|
+
var numberIsFinite = Number.isFinite.bind(Number);
|
|
15644
|
+
var numberIsNaN = Number.isNaN.bind(Number);
|
|
15645
|
+
var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
|
|
15646
|
+
var mathMax = Math.max.bind(Math);
|
|
15647
|
+
var dateConstructor = Date;
|
|
15648
|
+
var datePrototype = dateConstructor.prototype;
|
|
15649
|
+
var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
|
|
15650
|
+
var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
|
|
15651
|
+
var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
|
|
15652
|
+
var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
|
|
15653
|
+
var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
|
|
15654
|
+
var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
|
|
15655
|
+
var WeakMapConstructor = WeakMap;
|
|
15656
|
+
var utf8Encoder = new TextEncoder();
|
|
15657
|
+
var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
|
|
15658
|
+
var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
|
|
15659
|
+
var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
|
|
15660
|
+
if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
|
|
15661
|
+
var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
|
|
15662
|
+
var JSON_SAFE_MAX_DEPTH = 32;
|
|
15663
|
+
var JSON_SAFE_MAX_NODES = 1e4;
|
|
15664
|
+
var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
|
|
15665
|
+
var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
|
|
15666
|
+
var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
|
|
15667
|
+
var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
|
|
15668
|
+
var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
|
|
15669
|
+
var JsonSafeValueError = class extends Error {
|
|
15670
|
+
/**
|
|
15671
|
+
* Create a bounded normalization error.
|
|
15672
|
+
*
|
|
15673
|
+
* @param code Stable normalization failure code.
|
|
15674
|
+
* @param message Human-readable bounded failure description.
|
|
15675
|
+
*/
|
|
15676
|
+
constructor(code, message) {
|
|
15677
|
+
super(message);
|
|
15678
|
+
objectDefineProperty(this, "name", {
|
|
15679
|
+
value: "JsonSafeValueError",
|
|
15680
|
+
writable: true,
|
|
15681
|
+
configurable: true
|
|
15682
|
+
});
|
|
15683
|
+
objectDefineProperty(this, "code", {
|
|
15684
|
+
value: code,
|
|
15685
|
+
writable: true,
|
|
15686
|
+
configurable: true
|
|
15687
|
+
});
|
|
15688
|
+
}
|
|
15689
|
+
};
|
|
15690
|
+
function fail(code, message) {
|
|
15691
|
+
throw new JsonSafeValueError(code, message);
|
|
15692
|
+
}
|
|
15693
|
+
function propertyAccess(operation, path8) {
|
|
15694
|
+
try {
|
|
15695
|
+
return operation();
|
|
15696
|
+
} catch {
|
|
15697
|
+
fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe value at ${path8}`);
|
|
15698
|
+
}
|
|
15699
|
+
}
|
|
15700
|
+
function serializedStringBytes(value) {
|
|
15701
|
+
if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
|
|
15702
|
+
fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
|
|
15703
|
+
}
|
|
15704
|
+
return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
|
|
15705
|
+
}
|
|
15706
|
+
function validatePropertyKey(key5) {
|
|
15707
|
+
if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
|
|
15708
|
+
fail(
|
|
15709
|
+
"MAX_STRING_LENGTH",
|
|
15710
|
+
`JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
|
|
15711
|
+
);
|
|
15712
|
+
}
|
|
15713
|
+
}
|
|
15714
|
+
function chargePropertyKey(state, key5) {
|
|
15715
|
+
state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
|
|
15716
|
+
if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
|
|
15717
|
+
fail(
|
|
15718
|
+
"MAX_PROPERTY_KEY_BYTES",
|
|
15719
|
+
`JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
|
|
15720
|
+
);
|
|
15721
|
+
}
|
|
15722
|
+
}
|
|
15723
|
+
function chargeBytes(state, bytes) {
|
|
15724
|
+
state.serializedBytes += bytes;
|
|
15725
|
+
if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
|
|
15726
|
+
fail(
|
|
15727
|
+
"MAX_SERIALIZED_BYTES",
|
|
15728
|
+
`JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
|
|
15729
|
+
);
|
|
15730
|
+
}
|
|
15731
|
+
}
|
|
15732
|
+
function chargeString(state, value) {
|
|
15733
|
+
chargeBytes(state, serializedStringBytes(value));
|
|
15734
|
+
}
|
|
15735
|
+
function objectPropertyPath(path8, key5) {
|
|
15736
|
+
const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
|
|
15737
|
+
return `${path8}[${stringifyJson(boundedKey)}]`;
|
|
15738
|
+
}
|
|
15739
|
+
function convertJsonValue(value, state, depth, inArray, path8) {
|
|
15740
|
+
state.nodes += 1;
|
|
15741
|
+
if (state.nodes > JSON_SAFE_MAX_NODES) {
|
|
15742
|
+
fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
|
|
15743
|
+
}
|
|
15744
|
+
if (typeof value === "string") {
|
|
15745
|
+
chargeString(state, value);
|
|
15746
|
+
return value;
|
|
15747
|
+
}
|
|
15748
|
+
if (value === null) {
|
|
15749
|
+
chargeBytes(state, 4);
|
|
15750
|
+
return value;
|
|
15751
|
+
}
|
|
15752
|
+
if (typeof value === "boolean") {
|
|
15753
|
+
chargeBytes(state, value ? 4 : 5);
|
|
15754
|
+
return value;
|
|
15755
|
+
}
|
|
15756
|
+
if (typeof value === "number") {
|
|
15757
|
+
const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
|
|
15758
|
+
chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
|
|
15759
|
+
return normalized;
|
|
15760
|
+
}
|
|
15761
|
+
if (typeof value === "bigint") {
|
|
15762
|
+
const normalized = bigintToString(value);
|
|
15763
|
+
chargeString(state, normalized);
|
|
15764
|
+
return normalized;
|
|
15765
|
+
}
|
|
15766
|
+
if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
|
|
15767
|
+
if (inArray) chargeBytes(state, 4);
|
|
15768
|
+
return inArray ? null : void 0;
|
|
15769
|
+
}
|
|
15770
|
+
const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
|
|
15771
|
+
if (isDate) {
|
|
15772
|
+
const time = propertyAccess(() => dateGetTime(value), path8);
|
|
15773
|
+
if (numberIsNaN(time)) {
|
|
15774
|
+
chargeBytes(state, 4);
|
|
15775
|
+
return null;
|
|
15776
|
+
}
|
|
15777
|
+
const normalized = propertyAccess(() => dateToISOString(value), path8);
|
|
15778
|
+
chargeString(state, normalized);
|
|
15779
|
+
return normalized;
|
|
15780
|
+
}
|
|
15781
|
+
if (depth > JSON_SAFE_MAX_DEPTH) {
|
|
15782
|
+
fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
|
|
15783
|
+
}
|
|
15784
|
+
const referenceState = weakMapGet(state.references, value);
|
|
15785
|
+
if (referenceState === "visiting") {
|
|
15786
|
+
chargeString(state, CIRCULAR_VALUE);
|
|
15787
|
+
return CIRCULAR_VALUE;
|
|
15788
|
+
}
|
|
15789
|
+
if (referenceState === "visited") {
|
|
15790
|
+
chargeString(state, REPEATED_VALUE);
|
|
15791
|
+
return REPEATED_VALUE;
|
|
15792
|
+
}
|
|
15793
|
+
weakMapSet(state.references, value, "visiting");
|
|
15794
|
+
if (propertyAccess(() => arrayIsArray(value), path8)) {
|
|
15795
|
+
const arrayValue = value;
|
|
15796
|
+
const length = propertyAccess(
|
|
15797
|
+
() => arrayValue.length,
|
|
15798
|
+
path8
|
|
15799
|
+
);
|
|
15800
|
+
if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
|
|
15801
|
+
fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
|
|
15802
|
+
}
|
|
15803
|
+
if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
|
|
15804
|
+
fail(
|
|
15805
|
+
"COLLECTION_TOO_LARGE",
|
|
15806
|
+
`JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
|
|
15807
|
+
);
|
|
15808
|
+
}
|
|
15809
|
+
chargeBytes(state, 2 + mathMax(0, length - 1));
|
|
15810
|
+
const result2 = arrayFrom({ length }, (_, index) => {
|
|
15811
|
+
const entryPath = `${path8}[${index}]`;
|
|
15812
|
+
const hasEntry = propertyAccess(
|
|
15813
|
+
() => hasOwnProperty(arrayValue, index),
|
|
15814
|
+
entryPath
|
|
15815
|
+
);
|
|
15816
|
+
if (!hasEntry) {
|
|
15817
|
+
chargeBytes(state, 4);
|
|
15818
|
+
return null;
|
|
15819
|
+
}
|
|
15820
|
+
const entry = propertyAccess(() => arrayValue[index], entryPath);
|
|
15821
|
+
return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
|
|
15822
|
+
});
|
|
15823
|
+
objectDefineProperty(result2, "toJSON", {
|
|
15824
|
+
value: void 0,
|
|
15825
|
+
configurable: true,
|
|
15826
|
+
writable: true
|
|
15827
|
+
});
|
|
15828
|
+
weakMapSet(state.references, value, "visited");
|
|
15829
|
+
return result2;
|
|
15830
|
+
}
|
|
15831
|
+
const keys = propertyAccess(() => reflectOwnKeys(value), path8);
|
|
15832
|
+
if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
|
|
15833
|
+
fail(
|
|
15834
|
+
"COLLECTION_TOO_LARGE",
|
|
15835
|
+
`JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
|
|
15836
|
+
);
|
|
15837
|
+
}
|
|
15838
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
15839
|
+
const key5 = keys[index];
|
|
15840
|
+
if (typeof key5 !== "string") continue;
|
|
15841
|
+
validatePropertyKey(key5);
|
|
15842
|
+
chargePropertyKey(state, key5);
|
|
15843
|
+
}
|
|
15844
|
+
chargeBytes(state, 2);
|
|
15845
|
+
const result = objectCreate(null);
|
|
15846
|
+
let emittedProperties = 0;
|
|
15847
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
15848
|
+
const key5 = keys[index];
|
|
15849
|
+
const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
|
|
15850
|
+
const descriptor = propertyAccess(
|
|
15851
|
+
() => reflectGetOwnPropertyDescriptor(value, key5),
|
|
15852
|
+
entryPath
|
|
15853
|
+
);
|
|
15854
|
+
if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
|
|
15855
|
+
const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
|
|
15856
|
+
const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
|
|
15857
|
+
if (converted !== void 0) {
|
|
15858
|
+
chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
|
|
15859
|
+
propertyAccess(() => objectDefineProperty(result, key5, {
|
|
15860
|
+
value: converted,
|
|
15861
|
+
enumerable: true,
|
|
15862
|
+
configurable: true,
|
|
15863
|
+
writable: true
|
|
15864
|
+
}), entryPath);
|
|
15865
|
+
emittedProperties += 1;
|
|
15866
|
+
}
|
|
15867
|
+
}
|
|
15868
|
+
weakMapSet(state.references, value, "visited");
|
|
15869
|
+
return result;
|
|
15870
|
+
}
|
|
15871
|
+
function toJsonSafeValue(value) {
|
|
15872
|
+
const state = {
|
|
15873
|
+
nodes: 0,
|
|
15874
|
+
propertyKeyBytes: 0,
|
|
15875
|
+
serializedBytes: 0,
|
|
15876
|
+
references: new WeakMapConstructor()
|
|
15877
|
+
};
|
|
15878
|
+
const converted = convertJsonValue(value, state, 0, false, "$");
|
|
15879
|
+
if (converted === void 0) chargeBytes(state, 4);
|
|
15880
|
+
const result = converted ?? null;
|
|
15881
|
+
const serialized = propertyAccess(() => stringifyJson(result), "$");
|
|
15882
|
+
if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
|
|
15883
|
+
fail(
|
|
15884
|
+
"MAX_SERIALIZED_BYTES",
|
|
15885
|
+
`JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
|
|
15886
|
+
);
|
|
15887
|
+
}
|
|
15888
|
+
return result;
|
|
15889
|
+
}
|
|
15890
|
+
|
|
15891
|
+
// src/util/truncateForJson.ts
|
|
15892
|
+
var TRUNCATION_MARKER = "...[truncated]";
|
|
15893
|
+
function truncateString(value, cap) {
|
|
15894
|
+
if (value.length <= cap) return value;
|
|
15895
|
+
const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
|
|
15896
|
+
return value.slice(0, budget) + TRUNCATION_MARKER;
|
|
15897
|
+
}
|
|
15898
|
+
function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
|
|
15899
|
+
if (typeof value === "string") return truncateString(value, maxStringLength);
|
|
15900
|
+
if (value === null || typeof value !== "object") return value;
|
|
15901
|
+
if (depth >= maxDepth) return "[truncated:max-depth]";
|
|
15902
|
+
if (seen.has(value)) return "[Circular]";
|
|
15903
|
+
seen.add(value);
|
|
15904
|
+
try {
|
|
15905
|
+
if (value instanceof Date) return value.toISOString();
|
|
15906
|
+
if (Array.isArray(value)) {
|
|
15907
|
+
const limit2 = Math.min(value.length, maxEntries);
|
|
15908
|
+
const output2 = [];
|
|
15909
|
+
for (let index = 0; index < limit2; index += 1) {
|
|
15910
|
+
output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
|
|
15911
|
+
}
|
|
15912
|
+
if (value.length > limit2) output2.push("[truncated:entries]");
|
|
15913
|
+
return output2;
|
|
15914
|
+
}
|
|
15915
|
+
const record = value;
|
|
15916
|
+
const output = {};
|
|
15917
|
+
const keys = Object.keys(record);
|
|
15918
|
+
const limit = Math.min(keys.length, maxEntries);
|
|
15919
|
+
for (let index = 0; index < limit; index += 1) {
|
|
15920
|
+
const key5 = keys[index];
|
|
15921
|
+
output[truncateString(key5, maxStringLength)] = truncateValue(
|
|
15922
|
+
record[key5],
|
|
15923
|
+
depth + 1,
|
|
15924
|
+
maxDepth,
|
|
15925
|
+
maxEntries,
|
|
15926
|
+
maxStringLength,
|
|
15927
|
+
seen
|
|
15928
|
+
);
|
|
15929
|
+
}
|
|
15930
|
+
if (keys.length > limit) output["[truncated]"] = true;
|
|
15931
|
+
return output;
|
|
15932
|
+
} finally {
|
|
15933
|
+
seen.delete(value);
|
|
15934
|
+
}
|
|
15935
|
+
}
|
|
15936
|
+
function truncateForJson(value, options = {}) {
|
|
15937
|
+
return truncateValue(
|
|
15938
|
+
value,
|
|
15939
|
+
0,
|
|
15940
|
+
options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
|
|
15941
|
+
options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
|
|
15942
|
+
options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
|
|
15943
|
+
/* @__PURE__ */ new WeakSet()
|
|
15944
|
+
);
|
|
15945
|
+
}
|
|
15946
|
+
|
|
15407
15947
|
// src/services/Agent.ts
|
|
15408
15948
|
import { descriptorDataValue } from "@axiom-lattice/protocols";
|
|
15409
15949
|
import { Command as Command2 } from "@langchain/langgraph";
|
|
@@ -16698,6 +17238,71 @@ var CapabilityRuntimeResolver = class {
|
|
|
16698
17238
|
// src/services/TrustedAgentDispatchCapability.ts
|
|
16699
17239
|
var TRUSTED_AGENT_DISPATCH = Symbol("axiom.trustedAgentDispatch");
|
|
16700
17240
|
|
|
17241
|
+
// src/services/threadRunLease.ts
|
|
17242
|
+
import { randomUUID as randomUUID6 } from "crypto";
|
|
17243
|
+
function threadRunLeaseKey(tenantId2, assistantId, threadId) {
|
|
17244
|
+
return `thread-run:${tenantId2}:${assistantId}:${threadId}`;
|
|
17245
|
+
}
|
|
17246
|
+
async function tryAcquireThreadRun(input) {
|
|
17247
|
+
const key5 = threadRunLeaseKey(input.tenantId, input.assistantId, input.threadId);
|
|
17248
|
+
const holder = `${input.owner}#${randomUUID6()}`;
|
|
17249
|
+
if (!await input.store.tryAcquire(key5, holder, input.ttlMs)) return null;
|
|
17250
|
+
const heartbeatMs = input.heartbeatMs ?? Math.max(1e3, Math.floor(input.ttlMs / 3));
|
|
17251
|
+
let released = false;
|
|
17252
|
+
let lost = false;
|
|
17253
|
+
const heartbeat = setInterval(() => {
|
|
17254
|
+
void input.store.renew(key5, holder, input.ttlMs).then((renewed) => {
|
|
17255
|
+
if (released || renewed || lost) return;
|
|
17256
|
+
lost = true;
|
|
17257
|
+
try {
|
|
17258
|
+
input.onLost?.();
|
|
17259
|
+
} catch {
|
|
17260
|
+
}
|
|
17261
|
+
}).catch(() => void 0);
|
|
17262
|
+
}, heartbeatMs);
|
|
17263
|
+
heartbeat.unref?.();
|
|
17264
|
+
return {
|
|
17265
|
+
get lost() {
|
|
17266
|
+
return lost;
|
|
17267
|
+
},
|
|
17268
|
+
release: async () => {
|
|
17269
|
+
if (released) return;
|
|
17270
|
+
released = true;
|
|
17271
|
+
clearInterval(heartbeat);
|
|
17272
|
+
await input.store.release(key5, holder).catch(() => void 0);
|
|
17273
|
+
}
|
|
17274
|
+
};
|
|
17275
|
+
}
|
|
17276
|
+
async function getThreadRunOwner(input) {
|
|
17277
|
+
let store = input.store;
|
|
17278
|
+
if (!store) {
|
|
17279
|
+
try {
|
|
17280
|
+
store = storeLatticeManager.getStoreLattice("default", "lease").store;
|
|
17281
|
+
} catch {
|
|
17282
|
+
return null;
|
|
17283
|
+
}
|
|
17284
|
+
}
|
|
17285
|
+
try {
|
|
17286
|
+
const record = await store.get(threadRunLeaseKey(input.tenantId, input.assistantId, input.threadId));
|
|
17287
|
+
if (!record) return null;
|
|
17288
|
+
const hash = record.holder.lastIndexOf("#");
|
|
17289
|
+
return hash > 0 ? record.holder.slice(0, hash) : record.holder;
|
|
17290
|
+
} catch {
|
|
17291
|
+
return null;
|
|
17292
|
+
}
|
|
17293
|
+
}
|
|
17294
|
+
|
|
17295
|
+
// src/services/replicaIdentity.ts
|
|
17296
|
+
import os from "os";
|
|
17297
|
+
var cached;
|
|
17298
|
+
function getReplicaId() {
|
|
17299
|
+
cached ?? (cached = process.env.AXIOM_REPLICA_ID?.trim() || `${os.hostname()}:${process.pid}`);
|
|
17300
|
+
return cached;
|
|
17301
|
+
}
|
|
17302
|
+
function resetReplicaIdForTests() {
|
|
17303
|
+
cached = void 0;
|
|
17304
|
+
}
|
|
17305
|
+
|
|
16701
17306
|
// src/services/Agent.ts
|
|
16702
17307
|
var ThreadStatus2 = /* @__PURE__ */ ((ThreadStatus3) => {
|
|
16703
17308
|
ThreadStatus3["IDLE"] = "idle";
|
|
@@ -16945,6 +17550,27 @@ function statusFromSnapshot(state) {
|
|
|
16945
17550
|
if (Array.isArray(state.next) && state.next.length > 0) return "busy" /* BUSY */;
|
|
16946
17551
|
return "idle" /* IDLE */;
|
|
16947
17552
|
}
|
|
17553
|
+
var MAX_EXECUTION_ERROR_LENGTH = 2e3;
|
|
17554
|
+
function executionErrorFromSnapshot(state) {
|
|
17555
|
+
if (!isPlainRecord(state) || !Array.isArray(state.tasks)) return void 0;
|
|
17556
|
+
for (const task of state.tasks) {
|
|
17557
|
+
if (!isPlainRecord(task) || task.error === void 0 || task.error === null) continue;
|
|
17558
|
+
const raw = task.error;
|
|
17559
|
+
const message = typeof raw === "string" ? raw : raw instanceof Error ? raw.message : isPlainRecord(raw) && typeof raw.message === "string" ? raw.message : (() => {
|
|
17560
|
+
try {
|
|
17561
|
+
return JSON.stringify(raw);
|
|
17562
|
+
} catch {
|
|
17563
|
+
return String(raw);
|
|
17564
|
+
}
|
|
17565
|
+
})();
|
|
17566
|
+
if (typeof message !== "string") continue;
|
|
17567
|
+
const trimmed = message.trim();
|
|
17568
|
+
if (trimmed.length === 0) continue;
|
|
17569
|
+
const bounded = truncateForJson(trimmed, { maxStringLength: MAX_EXECUTION_ERROR_LENGTH });
|
|
17570
|
+
if (typeof bounded === "string" && bounded.length > 0) return bounded;
|
|
17571
|
+
}
|
|
17572
|
+
return void 0;
|
|
17573
|
+
}
|
|
16948
17574
|
function freshReply(state, preRunMarker, inputMessageId, consumedInputMessageIds) {
|
|
16949
17575
|
const output = finalAiMessageMarker(state);
|
|
16950
17576
|
if (output?.text === void 0 || output.index <= (preRunMarker?.index ?? -1) || output.totalMessageCount <= (preRunMarker?.totalMessageCount ?? 0)) return void 0;
|
|
@@ -16994,6 +17620,10 @@ function checkpointCapabilityRevision(state) {
|
|
|
16994
17620
|
var QUEUE_PROCESSOR_RETRY_BASE_MS = 100;
|
|
16995
17621
|
var QUEUE_PROCESSOR_MAX_RETRIES = 3;
|
|
16996
17622
|
var AGENT_RECURSION_LIMIT = 1e3;
|
|
17623
|
+
var THREAD_RUN_LEASE_TTL_MS = 6e4;
|
|
17624
|
+
var THREAD_RUN_LEASE_RETRY_BASE_MS = 150;
|
|
17625
|
+
var THREAD_RUN_LEASE_RETRY_CAP_MS = 1500;
|
|
17626
|
+
var THREAD_RUN_LEASE_MAX_RETRIES = 12;
|
|
16997
17627
|
function hasExactKeys(record, required, optional = []) {
|
|
16998
17628
|
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
16999
17629
|
return required.every((key5) => Object.prototype.hasOwnProperty.call(record, key5)) && Reflect.ownKeys(record).every((key5) => typeof key5 === "string" && allowed.has(key5));
|
|
@@ -17023,6 +17653,13 @@ var Agent = class {
|
|
|
17023
17653
|
this.queueProcessorRetryAttempt = 0;
|
|
17024
17654
|
this.queueProcessorGeneration = 0;
|
|
17025
17655
|
this.queueWakeRequested = false;
|
|
17656
|
+
/**
|
|
17657
|
+
* Thread-run ownership lease held while this replica is actively processing
|
|
17658
|
+
* the thread. Acquired non-blockingly in {@link startQueueProcessor}; released
|
|
17659
|
+
* exactly once when the processor definitively stops.
|
|
17660
|
+
*/
|
|
17661
|
+
this.threadRunLease = null;
|
|
17662
|
+
this.threadRunLeaseRetryAttempt = 0;
|
|
17026
17663
|
this.asyncTasks = [];
|
|
17027
17664
|
this.agentExecutor = async ({ input, command, custom_run_config, expected_capability_revision, trusted_run_context }, signal) => {
|
|
17028
17665
|
const { runnable_agent, runConfig } = await this.getLatticeClientAndRuntimeConfig(
|
|
@@ -17139,7 +17776,7 @@ var Agent = class {
|
|
|
17139
17776
|
}
|
|
17140
17777
|
};
|
|
17141
17778
|
this.waitingForQueueEnd = async (signal) => {
|
|
17142
|
-
while (!signal?.aborted) {
|
|
17779
|
+
while (!signal?.aborted && !this.threadRunLease?.lost) {
|
|
17143
17780
|
const pendings = await this.getPendingMessages();
|
|
17144
17781
|
if (pendings.length === 0) {
|
|
17145
17782
|
const state = await this.getCurrentState();
|
|
@@ -17224,7 +17861,7 @@ var Agent = class {
|
|
|
17224
17861
|
state
|
|
17225
17862
|
});
|
|
17226
17863
|
} else if (runStatus === "error" /* ERROR */) {
|
|
17227
|
-
const failureReason = "Agent execution ended in an error state";
|
|
17864
|
+
const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
|
|
17228
17865
|
this.addChunk({
|
|
17229
17866
|
type: "message_failed",
|
|
17230
17867
|
data: { id: humanContent.id, content: failureReason }
|
|
@@ -17337,7 +17974,7 @@ var Agent = class {
|
|
|
17337
17974
|
}
|
|
17338
17975
|
if (runStatus === "busy" /* BUSY */) return;
|
|
17339
17976
|
if (runStatus === "error" /* ERROR */) {
|
|
17340
|
-
const failureReason = "Agent execution ended in an error state";
|
|
17977
|
+
const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
|
|
17341
17978
|
for (const p of collectPendings) {
|
|
17342
17979
|
const messageId = p.content.id;
|
|
17343
17980
|
this.addChunk({
|
|
@@ -17438,7 +18075,7 @@ var Agent = class {
|
|
|
17438
18075
|
});
|
|
17439
18076
|
if (p.execution_mode === "followup") return;
|
|
17440
18077
|
} else if (runStatus === "error" /* ERROR */) {
|
|
17441
|
-
const failureReason = "Agent execution ended in an error state";
|
|
18078
|
+
const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
|
|
17442
18079
|
this.addChunk({
|
|
17443
18080
|
type: "message_failed",
|
|
17444
18081
|
data: { id: humanContent.id, content: failureReason }
|
|
@@ -17745,12 +18382,17 @@ var Agent = class {
|
|
|
17745
18382
|
capabilityRuntimeRevision: capabilityRuntime.revision,
|
|
17746
18383
|
tenantId: this.tenant_id,
|
|
17747
18384
|
workspaceId: this.workspace_id,
|
|
17748
|
-
|
|
18385
|
+
// The propagated project scope must not fabricate `"default"`:
|
|
18386
|
+
// `queue_project_id` is `null` when the run had no project, so an unscoped
|
|
18387
|
+
// run stays unscoped instead of later querying a project that may not
|
|
18388
|
+
// exist. An explicitly passed `"default"` is a real project for some
|
|
18389
|
+
// tenants and is preserved.
|
|
18390
|
+
projectId: this.queue_project_id ?? void 0,
|
|
17749
18391
|
assistant_id: this.assistant_id,
|
|
17750
18392
|
thread_id: this.thread_id,
|
|
17751
18393
|
"x-tenant-id": this.tenant_id,
|
|
17752
18394
|
"x-workspace-id": this.workspace_id,
|
|
17753
|
-
"x-project-id": this.
|
|
18395
|
+
"x-project-id": this.queue_project_id ?? void 0,
|
|
17754
18396
|
"x-thread-id": this.thread_id,
|
|
17755
18397
|
"x-assistant-id": this.assistant_id
|
|
17756
18398
|
};
|
|
@@ -17965,6 +18607,29 @@ var Agent = class {
|
|
|
17965
18607
|
}
|
|
17966
18608
|
return this.queueStore;
|
|
17967
18609
|
}
|
|
18610
|
+
/**
|
|
18611
|
+
* Resolves the shared lease store used to serialize thread runs across
|
|
18612
|
+
* Gateway replicas. Returns `undefined` when no lease store is registered so
|
|
18613
|
+
* single-process deployments keep running unconditionally.
|
|
18614
|
+
*/
|
|
18615
|
+
getLeaseStore() {
|
|
18616
|
+
try {
|
|
18617
|
+
return storeLatticeManager.getStoreLattice("default", "lease").store;
|
|
18618
|
+
} catch {
|
|
18619
|
+
return void 0;
|
|
18620
|
+
}
|
|
18621
|
+
}
|
|
18622
|
+
/**
|
|
18623
|
+
* Releases this replica's thread-run ownership lease, if held.
|
|
18624
|
+
*
|
|
18625
|
+
* @remarks Safe to call from any definitive-stop path; a second call is a
|
|
18626
|
+
* no-op. The handle's unique holder makes a stale release harmless.
|
|
18627
|
+
*/
|
|
18628
|
+
async releaseThreadRunLease() {
|
|
18629
|
+
const lease = this.threadRunLease;
|
|
18630
|
+
this.threadRunLease = null;
|
|
18631
|
+
if (lease) await lease.release();
|
|
18632
|
+
}
|
|
17968
18633
|
getDefaultQueueConfig() {
|
|
17969
18634
|
return {
|
|
17970
18635
|
mode: "collect" /* COLLECT */,
|
|
@@ -17990,6 +18655,8 @@ var Agent = class {
|
|
|
17990
18655
|
*/
|
|
17991
18656
|
stopQueueProcessor() {
|
|
17992
18657
|
this.cancelQueueProcessorRetry();
|
|
18658
|
+
this.cancelThreadRunLeaseRetry();
|
|
18659
|
+
void this.releaseThreadRunLease();
|
|
17993
18660
|
this.clearRecoveryBlock();
|
|
17994
18661
|
this.queueProcessorGeneration += 1;
|
|
17995
18662
|
if (this.abortController) {
|
|
@@ -18095,7 +18762,15 @@ var Agent = class {
|
|
|
18095
18762
|
if (!accepted) throw new Error(`Queue is full (max ${maxSize} messages)`);
|
|
18096
18763
|
if (useMode === "steer" /* STEER */ && !queueMessage.command) {
|
|
18097
18764
|
this.stopQueueProcessor();
|
|
18098
|
-
|
|
18765
|
+
let runStatus;
|
|
18766
|
+
try {
|
|
18767
|
+
runStatus = await this.getRunStatus();
|
|
18768
|
+
} catch {
|
|
18769
|
+
runStatus = void 0;
|
|
18770
|
+
}
|
|
18771
|
+
if (runStatus !== "interrupted" /* INTERRUPTED */) {
|
|
18772
|
+
await store.resetProcessingToPending(this.thread_id, this.queueScope());
|
|
18773
|
+
}
|
|
18099
18774
|
console.log(`[Agent] STEER mode: stopped current processing, reset queue, message ${messageId} will execute next`);
|
|
18100
18775
|
}
|
|
18101
18776
|
} else {
|
|
@@ -18129,16 +18804,50 @@ var Agent = class {
|
|
|
18129
18804
|
startQueueProcessorIfNeeded() {
|
|
18130
18805
|
return this.startQueueProcessor(true);
|
|
18131
18806
|
}
|
|
18132
|
-
startQueueProcessor(freshWakeup) {
|
|
18807
|
+
async startQueueProcessor(freshWakeup) {
|
|
18133
18808
|
this.queueWakeRequested = true;
|
|
18134
18809
|
if (this.queueProcessorPromise) return this.queueProcessorPromise;
|
|
18135
|
-
if (this.queueProcessorRetryTimer) return
|
|
18810
|
+
if (this.queueProcessorRetryTimer) return;
|
|
18136
18811
|
if (freshWakeup && this.queueProcessorRetryAttempt >= QUEUE_PROCESSOR_MAX_RETRIES) {
|
|
18137
18812
|
this.queueProcessorRetryAttempt = 0;
|
|
18138
18813
|
}
|
|
18814
|
+
if (freshWakeup && this.threadRunLeaseRetryAttempt >= THREAD_RUN_LEASE_MAX_RETRIES) {
|
|
18815
|
+
this.threadRunLeaseRetryAttempt = 0;
|
|
18816
|
+
}
|
|
18139
18817
|
this.queueWakeRequested = false;
|
|
18140
|
-
let processorFailed = false;
|
|
18141
18818
|
const processorGeneration = this.queueProcessorGeneration;
|
|
18819
|
+
if (this.threadRunLease?.lost) await this.releaseThreadRunLease();
|
|
18820
|
+
let acquiredLeaseHere = false;
|
|
18821
|
+
if (this.threadRunLease === null) {
|
|
18822
|
+
const leaseStore = this.getLeaseStore();
|
|
18823
|
+
if (leaseStore) {
|
|
18824
|
+
const lease = await tryAcquireThreadRun({
|
|
18825
|
+
store: leaseStore,
|
|
18826
|
+
tenantId: this.tenant_id,
|
|
18827
|
+
assistantId: this.assistant_id,
|
|
18828
|
+
threadId: this.thread_id,
|
|
18829
|
+
owner: getReplicaId(),
|
|
18830
|
+
ttlMs: THREAD_RUN_LEASE_TTL_MS,
|
|
18831
|
+
onLost: () => {
|
|
18832
|
+
console.warn(`[Agent] Thread-run lease lost for thread ${this.thread_id}; aborting the held run`);
|
|
18833
|
+
this.abortController?.abort();
|
|
18834
|
+
}
|
|
18835
|
+
});
|
|
18836
|
+
if (!lease) {
|
|
18837
|
+
this.scheduleThreadRunLeaseRetry();
|
|
18838
|
+
return;
|
|
18839
|
+
}
|
|
18840
|
+
this.threadRunLease = lease;
|
|
18841
|
+
acquiredLeaseHere = true;
|
|
18842
|
+
this.cancelThreadRunLeaseRetry();
|
|
18843
|
+
}
|
|
18844
|
+
}
|
|
18845
|
+
if (this.queueProcessorPromise) return this.queueProcessorPromise;
|
|
18846
|
+
if (this.queueProcessorGeneration !== processorGeneration) {
|
|
18847
|
+
if (acquiredLeaseHere) await this.releaseThreadRunLease();
|
|
18848
|
+
return;
|
|
18849
|
+
}
|
|
18850
|
+
let processorFailed = false;
|
|
18142
18851
|
const processor = this.runQueueProcessor().catch(async (error) => {
|
|
18143
18852
|
processorFailed = true;
|
|
18144
18853
|
console.error(`Queue processing error for thread ${this.thread_id}:`, error);
|
|
@@ -18156,7 +18865,11 @@ var Agent = class {
|
|
|
18156
18865
|
if (this.queueWakeRequested) void this.startQueueProcessor(false);
|
|
18157
18866
|
return;
|
|
18158
18867
|
}
|
|
18159
|
-
if (failed)
|
|
18868
|
+
if (failed) {
|
|
18869
|
+
this.cancelThreadRunLeaseRetry();
|
|
18870
|
+
await this.releaseThreadRunLease();
|
|
18871
|
+
return;
|
|
18872
|
+
}
|
|
18160
18873
|
this.queueProcessorRetryAttempt = 0;
|
|
18161
18874
|
if (this.queueWakeRequested) {
|
|
18162
18875
|
void this.startQueueProcessor(false);
|
|
@@ -18169,7 +18882,11 @@ var Agent = class {
|
|
|
18169
18882
|
void this.startQueueProcessor(false);
|
|
18170
18883
|
return;
|
|
18171
18884
|
}
|
|
18172
|
-
if (pendingMessages.length === 0)
|
|
18885
|
+
if (pendingMessages.length === 0) {
|
|
18886
|
+
this.cancelThreadRunLeaseRetry();
|
|
18887
|
+
await this.releaseThreadRunLease();
|
|
18888
|
+
return;
|
|
18889
|
+
}
|
|
18173
18890
|
const processingMessages = await this.getQueueStore().getProcessingMessages(
|
|
18174
18891
|
this.thread_id,
|
|
18175
18892
|
this.queueScope()
|
|
@@ -18181,12 +18898,20 @@ var Agent = class {
|
|
|
18181
18898
|
}
|
|
18182
18899
|
if (processingMessages.length > 0) {
|
|
18183
18900
|
const runStatus = await this.getRunStatus();
|
|
18184
|
-
if (runStatus === "busy" /* BUSY */ || runStatus === "interrupted" /* INTERRUPTED */)
|
|
18901
|
+
if (runStatus === "busy" /* BUSY */ || runStatus === "interrupted" /* INTERRUPTED */) {
|
|
18902
|
+
this.cancelThreadRunLeaseRetry();
|
|
18903
|
+
await this.releaseThreadRunLease();
|
|
18904
|
+
return;
|
|
18905
|
+
}
|
|
18185
18906
|
}
|
|
18186
18907
|
void this.startQueueProcessor(false);
|
|
18187
18908
|
} catch (error) {
|
|
18188
18909
|
console.error(`Queue processor finalization failed for thread ${this.thread_id}:`, error);
|
|
18189
18910
|
await this.scheduleQueueProcessorRetry(error, generation);
|
|
18911
|
+
if (!this.queueProcessorPromise) {
|
|
18912
|
+
await this.releaseThreadRunLease();
|
|
18913
|
+
this.cancelThreadRunLeaseRetry();
|
|
18914
|
+
}
|
|
18190
18915
|
}
|
|
18191
18916
|
}
|
|
18192
18917
|
async scheduleQueueProcessorRetry(error, generation) {
|
|
@@ -18224,6 +18949,36 @@ var Agent = class {
|
|
|
18224
18949
|
this.queueProcessorRetryAttempt = 0;
|
|
18225
18950
|
this.queueWakeRequested = false;
|
|
18226
18951
|
}
|
|
18952
|
+
/**
|
|
18953
|
+
* Bounded re-attempt after losing the thread-run lease to a peer. Covers the
|
|
18954
|
+
* narrow window where the peer releases the lease without having observed a
|
|
18955
|
+
* just-enqueued message. Bounded so a genuinely long-held thread does not make
|
|
18956
|
+
* this replica poll forever — the owning replica's loop drains new messages.
|
|
18957
|
+
*/
|
|
18958
|
+
scheduleThreadRunLeaseRetry() {
|
|
18959
|
+
if (this.threadRunLeaseRetryTimer || this.threadRunLeaseRetryAttempt >= THREAD_RUN_LEASE_MAX_RETRIES) return;
|
|
18960
|
+
const delay = Math.min(
|
|
18961
|
+
THREAD_RUN_LEASE_RETRY_BASE_MS * 2 ** this.threadRunLeaseRetryAttempt,
|
|
18962
|
+
THREAD_RUN_LEASE_RETRY_CAP_MS
|
|
18963
|
+
);
|
|
18964
|
+
this.threadRunLeaseRetryAttempt += 1;
|
|
18965
|
+
this.threadRunLeaseRetryTimer = setTimeout(() => {
|
|
18966
|
+
this.threadRunLeaseRetryTimer = void 0;
|
|
18967
|
+
void this.startQueueProcessor(false);
|
|
18968
|
+
}, delay);
|
|
18969
|
+
}
|
|
18970
|
+
/**
|
|
18971
|
+
* Clears any pending thread-run lease retry and resets its backoff budget.
|
|
18972
|
+
*
|
|
18973
|
+
* @remarks Called on lease acquisition and on every definitive processor
|
|
18974
|
+
* stop so the next enqueue starts from the base delay. Never called on
|
|
18975
|
+
* continue/re-arm paths, which must preserve the bounded budget.
|
|
18976
|
+
*/
|
|
18977
|
+
cancelThreadRunLeaseRetry() {
|
|
18978
|
+
if (this.threadRunLeaseRetryTimer) clearTimeout(this.threadRunLeaseRetryTimer);
|
|
18979
|
+
this.threadRunLeaseRetryTimer = void 0;
|
|
18980
|
+
this.threadRunLeaseRetryAttempt = 0;
|
|
18981
|
+
}
|
|
18227
18982
|
async runQueueProcessor() {
|
|
18228
18983
|
const store = this.getQueueStore();
|
|
18229
18984
|
const processingMessages = await store.getProcessingMessages(this.thread_id, this.queueScope());
|
|
@@ -18368,6 +19123,38 @@ var Agent = class {
|
|
|
18368
19123
|
console.error(`[Agent] Failed to initialize agent lattice for ${this.assistant_id} (tenant: ${this.tenant_id}):`, error);
|
|
18369
19124
|
throw error;
|
|
18370
19125
|
}
|
|
19126
|
+
let acquiredLeaseHere = false;
|
|
19127
|
+
if (this.threadRunLease === null) {
|
|
19128
|
+
const leaseStore = this.getLeaseStore();
|
|
19129
|
+
if (leaseStore) {
|
|
19130
|
+
const lease = await tryAcquireThreadRun({
|
|
19131
|
+
store: leaseStore,
|
|
19132
|
+
tenantId: this.tenant_id,
|
|
19133
|
+
assistantId: this.assistant_id,
|
|
19134
|
+
threadId: this.thread_id,
|
|
19135
|
+
owner: getReplicaId(),
|
|
19136
|
+
ttlMs: THREAD_RUN_LEASE_TTL_MS,
|
|
19137
|
+
onLost: () => {
|
|
19138
|
+
console.warn(`[Agent] Thread-run lease lost for thread ${this.thread_id}; aborting the held run`);
|
|
19139
|
+
this.abortController?.abort();
|
|
19140
|
+
}
|
|
19141
|
+
});
|
|
19142
|
+
if (!lease) {
|
|
19143
|
+
return { status: await this.getRunStatus(), settled: false, leaseContended: true };
|
|
19144
|
+
}
|
|
19145
|
+
this.threadRunLease = lease;
|
|
19146
|
+
acquiredLeaseHere = true;
|
|
19147
|
+
this.cancelThreadRunLeaseRetry();
|
|
19148
|
+
}
|
|
19149
|
+
}
|
|
19150
|
+
try {
|
|
19151
|
+
return await this.resumeTaskLocked();
|
|
19152
|
+
} finally {
|
|
19153
|
+
if (acquiredLeaseHere && !this.queueProcessorPromise) await this.releaseThreadRunLease();
|
|
19154
|
+
}
|
|
19155
|
+
}
|
|
19156
|
+
/** Recovery body of {@link resumeTask}, executed while thread ownership is settled. */
|
|
19157
|
+
async resumeTaskLocked() {
|
|
18371
19158
|
const store = this.getQueueStore();
|
|
18372
19159
|
const processingMessages = await store.getProcessingMessages(this.thread_id, this.queueScope());
|
|
18373
19160
|
const preRunState = await this.getCurrentState();
|
|
@@ -18411,7 +19198,7 @@ var Agent = class {
|
|
|
18411
19198
|
}
|
|
18412
19199
|
} else if (resumedStatus === "error" /* ERROR */) {
|
|
18413
19200
|
this.clearRecoveryBlock();
|
|
18414
|
-
const failureReason = "Agent execution ended in an error state";
|
|
19201
|
+
const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
|
|
18415
19202
|
for (const msg of processingMessages) {
|
|
18416
19203
|
this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
|
|
18417
19204
|
this.publish("message:failed", {
|
|
@@ -18447,7 +19234,7 @@ var Agent = class {
|
|
|
18447
19234
|
} else if (runStatus === "error" /* ERROR */) {
|
|
18448
19235
|
this.processingExecutionContext(processingMessages);
|
|
18449
19236
|
this.clearRecoveryBlock();
|
|
18450
|
-
const failureReason = "Agent execution ended in an error state";
|
|
19237
|
+
const failureReason = executionErrorFromSnapshot(preRunState) ?? "Agent execution ended in an error state";
|
|
18451
19238
|
for (const msg of processingMessages) {
|
|
18452
19239
|
this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
|
|
18453
19240
|
this.publish("message:failed", {
|
|
@@ -18483,6 +19270,8 @@ var Agent = class {
|
|
|
18483
19270
|
*/
|
|
18484
19271
|
async abort() {
|
|
18485
19272
|
this.cancelQueueProcessorRetry();
|
|
19273
|
+
this.cancelThreadRunLeaseRetry();
|
|
19274
|
+
await this.releaseThreadRunLease();
|
|
18486
19275
|
this.clearRecoveryBlock();
|
|
18487
19276
|
this.queueProcessorGeneration += 1;
|
|
18488
19277
|
if (this.abortController) {
|
|
@@ -18593,8 +19382,19 @@ var AgentInstanceManager = class _AgentInstanceManager {
|
|
|
18593
19382
|
}
|
|
18594
19383
|
return _AgentInstanceManager._instance;
|
|
18595
19384
|
}
|
|
19385
|
+
/**
|
|
19386
|
+
* A thread's identity is `(tenant_id, assistant_id, thread_id)`.
|
|
19387
|
+
*
|
|
19388
|
+
* Workspace/project are execution scope chosen when the instance is created,
|
|
19389
|
+
* not part of identity: including them let the same thread exist as several
|
|
19390
|
+
* Agents when callers defaulted optional workspace/project headers
|
|
19391
|
+
* differently (e.g. `createRun` passing `undefined` while `abort` defaulted
|
|
19392
|
+
* to `"default"`), so control-plane calls could address a different instance
|
|
19393
|
+
* than the one running. `undefined`/`null` normalize to `""`; ids are assumed
|
|
19394
|
+
* not to contain `:` (UUID-shaped in practice).
|
|
19395
|
+
*/
|
|
18596
19396
|
getKey(params) {
|
|
18597
|
-
return
|
|
19397
|
+
return [params.tenant_id, params.assistant_id, params.thread_id].map((value) => value ?? "").join(":");
|
|
18598
19398
|
}
|
|
18599
19399
|
/**
|
|
18600
19400
|
* Get or create Agent instance for a thread
|
|
@@ -18608,6 +19408,24 @@ var AgentInstanceManager = class _AgentInstanceManager {
|
|
|
18608
19408
|
}
|
|
18609
19409
|
return this.agents.get(key5);
|
|
18610
19410
|
}
|
|
19411
|
+
/**
|
|
19412
|
+
* Get the managed Agent for a thread WITHOUT creating or registering one.
|
|
19413
|
+
*
|
|
19414
|
+
* Read-only control-plane callers (state, memory, inbox) must not be the first
|
|
19415
|
+
* to establish a thread's execution scope: since identity is
|
|
19416
|
+
* `(tenant_id, assistant_id, thread_id)`, whichever caller reaches
|
|
19417
|
+
* {@link getAgent} first fixes the instance's workspace/project for its whole
|
|
19418
|
+
* lifetime, and a later trusted dispatch on that thread would then fail
|
|
19419
|
+
* trusted-scope validation. This returns the existing managed instance when
|
|
19420
|
+
* present, otherwise a transient unregistered Agent that is sufficient for
|
|
19421
|
+
* state reads and disappears with the request.
|
|
19422
|
+
*
|
|
19423
|
+
* @param params - Thread identity; scope is only used for the transient Agent.
|
|
19424
|
+
* @returns The managed instance if any, else an unregistered read-only Agent.
|
|
19425
|
+
*/
|
|
19426
|
+
getAgentForRead(params) {
|
|
19427
|
+
return this.agents.get(this.getKey(params)) ?? new Agent(params);
|
|
19428
|
+
}
|
|
18611
19429
|
/**
|
|
18612
19430
|
* Check if an agent instance exists for the thread
|
|
18613
19431
|
*/
|
|
@@ -18643,55 +19461,6 @@ var AgentInstanceManager = class _AgentInstanceManager {
|
|
|
18643
19461
|
});
|
|
18644
19462
|
this.agents.clear();
|
|
18645
19463
|
}
|
|
18646
|
-
/**
|
|
18647
|
-
* Restore agent instances for threads with pending messages after server restart
|
|
18648
|
-
* Queries the message queue store for threads with pending/processing messages
|
|
18649
|
-
* and recreates agent instances to resume processing
|
|
18650
|
-
*/
|
|
18651
|
-
async restore() {
|
|
18652
|
-
const stats = { restored: 0, errors: 0 };
|
|
18653
|
-
try {
|
|
18654
|
-
const queueStoreLattice = storeLatticeManager.getStoreLattice("default", "threadMessageQueue");
|
|
18655
|
-
const queueStore = queueStoreLattice.store;
|
|
18656
|
-
const threadsWithPending = await queueStore.getThreadsWithPendingMessages();
|
|
18657
|
-
if (threadsWithPending.length === 0) {
|
|
18658
|
-
console.log("[AgentInstanceManager] No threads with pending messages found");
|
|
18659
|
-
return stats;
|
|
18660
|
-
}
|
|
18661
|
-
console.log(`[AgentInstanceManager] Found ${threadsWithPending.length} threads with pending messages, restoring...`);
|
|
18662
|
-
for (const threadInfo of threadsWithPending) {
|
|
18663
|
-
try {
|
|
18664
|
-
await this.restoreThread(threadInfo);
|
|
18665
|
-
stats.restored++;
|
|
18666
|
-
} catch (error) {
|
|
18667
|
-
console.error(`[AgentInstanceManager] Failed to restore thread ${threadInfo.threadId}:`, error);
|
|
18668
|
-
stats.errors++;
|
|
18669
|
-
}
|
|
18670
|
-
}
|
|
18671
|
-
console.log(`[AgentInstanceManager] Restore complete: ${stats.restored} restored, ${stats.errors} errors`);
|
|
18672
|
-
return stats;
|
|
18673
|
-
} catch (error) {
|
|
18674
|
-
console.error("[AgentInstanceManager] Restore failed:", error);
|
|
18675
|
-
throw error;
|
|
18676
|
-
}
|
|
18677
|
-
}
|
|
18678
|
-
/**
|
|
18679
|
-
* Restore a single thread
|
|
18680
|
-
* Delegates actual recovery logic to Agent.resumeTask()
|
|
18681
|
-
*/
|
|
18682
|
-
async restoreThread(threadInfo) {
|
|
18683
|
-
const { tenantId: tenantId2, assistantId, threadId, workspaceId, projectId } = threadInfo;
|
|
18684
|
-
const threadParams = {
|
|
18685
|
-
tenant_id: tenantId2,
|
|
18686
|
-
assistant_id: assistantId,
|
|
18687
|
-
thread_id: threadId,
|
|
18688
|
-
workspace_id: workspaceId,
|
|
18689
|
-
project_id: projectId
|
|
18690
|
-
};
|
|
18691
|
-
const agent = this.getAgent(threadParams);
|
|
18692
|
-
await agent.resumeTask();
|
|
18693
|
-
console.log(`[AgentInstanceManager] Restored thread ${threadId}`);
|
|
18694
|
-
}
|
|
18695
19464
|
};
|
|
18696
19465
|
var agentInstanceManager = AgentInstanceManager.getInstance();
|
|
18697
19466
|
|
|
@@ -19162,27 +19931,27 @@ function createCheckAsyncTaskTool() {
|
|
|
19162
19931
|
if (!mainAgent) {
|
|
19163
19932
|
return "Cannot access main agent state.";
|
|
19164
19933
|
}
|
|
19165
|
-
const
|
|
19166
|
-
if (!
|
|
19934
|
+
const cached2 = mainAgent.getAsyncTask(task_id);
|
|
19935
|
+
if (!cached2) {
|
|
19167
19936
|
return `Task ${task_id} not found. Use list_async_tasks to see all tasks.`;
|
|
19168
19937
|
}
|
|
19169
19938
|
try {
|
|
19170
19939
|
if (!agentInstanceManager.hasAgent({
|
|
19171
|
-
assistant_id:
|
|
19940
|
+
assistant_id: cached2.assistantId,
|
|
19172
19941
|
thread_id: task_id,
|
|
19173
19942
|
tenant_id: mainAgent.tenant_id
|
|
19174
19943
|
})) {
|
|
19175
|
-
return `Task ${task_id}: not found (may have been cleaned up). Status was: ${
|
|
19944
|
+
return `Task ${task_id}: not found (may have been cleaned up). Status was: ${cached2.status}`;
|
|
19176
19945
|
}
|
|
19177
19946
|
const subAgent = agentInstanceManager.getAgent({
|
|
19178
|
-
assistant_id:
|
|
19947
|
+
assistant_id: cached2.assistantId,
|
|
19179
19948
|
thread_id: task_id,
|
|
19180
19949
|
tenant_id: mainAgent.tenant_id
|
|
19181
19950
|
});
|
|
19182
19951
|
const status = await subAgent.getRunStatus();
|
|
19183
19952
|
if (status === "busy") {
|
|
19184
19953
|
return `Task ${task_id}: still running.
|
|
19185
|
-
Description: ${
|
|
19954
|
+
Description: ${cached2.description}`;
|
|
19186
19955
|
}
|
|
19187
19956
|
if (status === "idle") {
|
|
19188
19957
|
const state = await subAgent.getCurrentState();
|
|
@@ -19193,21 +19962,21 @@ Description: ${cached.description}`;
|
|
|
19193
19962
|
mainAgent.updateAsyncTaskStatus(task_id, "completed");
|
|
19194
19963
|
const result = lastAI?.content ?? "(completed, no output)";
|
|
19195
19964
|
return `Task ${task_id}: COMPLETED.
|
|
19196
|
-
Description: ${
|
|
19965
|
+
Description: ${cached2.description}
|
|
19197
19966
|
Result:
|
|
19198
19967
|
${result}`;
|
|
19199
19968
|
}
|
|
19200
19969
|
if (status === "error") {
|
|
19201
19970
|
mainAgent.updateAsyncTaskStatus(task_id, "failed");
|
|
19202
19971
|
return `Task ${task_id}: failed.
|
|
19203
|
-
Description: ${
|
|
19972
|
+
Description: ${cached2.description}`;
|
|
19204
19973
|
}
|
|
19205
19974
|
if (status === "interrupted") {
|
|
19206
19975
|
return `Task ${task_id}: interrupted (waiting for input).
|
|
19207
|
-
Description: ${
|
|
19976
|
+
Description: ${cached2.description}`;
|
|
19208
19977
|
}
|
|
19209
19978
|
return `Task ${task_id}: ${status}.
|
|
19210
|
-
Description: ${
|
|
19979
|
+
Description: ${cached2.description}`;
|
|
19211
19980
|
} catch (err) {
|
|
19212
19981
|
return `Task ${task_id}: error checking status: ${err instanceof Error ? err.message : String(err)}`;
|
|
19213
19982
|
}
|
|
@@ -19280,25 +20049,25 @@ function createCancelAsyncTaskTool() {
|
|
|
19280
20049
|
if (!mainAgent) {
|
|
19281
20050
|
return "Cannot access main agent state.";
|
|
19282
20051
|
}
|
|
19283
|
-
const
|
|
19284
|
-
if (!
|
|
20052
|
+
const cached2 = mainAgent.getAsyncTask(task_id);
|
|
20053
|
+
if (!cached2) {
|
|
19285
20054
|
return `Task ${task_id} not found.`;
|
|
19286
20055
|
}
|
|
19287
20056
|
try {
|
|
19288
20057
|
const subAgentExists = agentInstanceManager.hasAgent({
|
|
19289
|
-
assistant_id:
|
|
20058
|
+
assistant_id: cached2.assistantId,
|
|
19290
20059
|
thread_id: task_id,
|
|
19291
20060
|
tenant_id: mainAgent.tenant_id
|
|
19292
20061
|
});
|
|
19293
20062
|
if (subAgentExists) {
|
|
19294
20063
|
const subAgent = agentInstanceManager.getAgent({
|
|
19295
|
-
assistant_id:
|
|
20064
|
+
assistant_id: cached2.assistantId,
|
|
19296
20065
|
thread_id: task_id,
|
|
19297
20066
|
tenant_id: mainAgent.tenant_id
|
|
19298
20067
|
});
|
|
19299
20068
|
await subAgent.abort();
|
|
19300
20069
|
agentInstanceManager.removeAgent({
|
|
19301
|
-
assistant_id:
|
|
20070
|
+
assistant_id: cached2.assistantId,
|
|
19302
20071
|
thread_id: task_id,
|
|
19303
20072
|
tenant_id: mainAgent.tenant_id
|
|
19304
20073
|
});
|
|
@@ -19547,6 +20316,48 @@ var MemoryScheduleStorage = class {
|
|
|
19547
20316
|
});
|
|
19548
20317
|
}
|
|
19549
20318
|
}
|
|
20319
|
+
/**
|
|
20320
|
+
* Atomically claims one due fire by transitioning the task `pending -> running`.
|
|
20321
|
+
*
|
|
20322
|
+
* @param taskId Task to claim.
|
|
20323
|
+
* @returns True when this caller won the claim (task was `pending`); false if
|
|
20324
|
+
* another replica already claimed it or it is not pending.
|
|
20325
|
+
*/
|
|
20326
|
+
async claimScheduledRun(taskId) {
|
|
20327
|
+
const task = this.tasks.get(taskId);
|
|
20328
|
+
if (!task || task.status !== ScheduledTaskStatus.PENDING) {
|
|
20329
|
+
return false;
|
|
20330
|
+
}
|
|
20331
|
+
this.tasks.set(taskId, {
|
|
20332
|
+
...task,
|
|
20333
|
+
status: ScheduledTaskStatus.RUNNING,
|
|
20334
|
+
updatedAt: Date.now()
|
|
20335
|
+
});
|
|
20336
|
+
return true;
|
|
20337
|
+
}
|
|
20338
|
+
/**
|
|
20339
|
+
* Requeues `running` tasks whose `updatedAt` is older than `olderThanMs` back
|
|
20340
|
+
* to `pending` (recovery after a crash that left a claim unsettled).
|
|
20341
|
+
*
|
|
20342
|
+
* @param olderThanMs Age threshold in milliseconds.
|
|
20343
|
+
* @returns The number of tasks requeued.
|
|
20344
|
+
*/
|
|
20345
|
+
async requeueStaleRunning(olderThanMs) {
|
|
20346
|
+
const now = Date.now();
|
|
20347
|
+
const cutoff = now - olderThanMs;
|
|
20348
|
+
let requeued = 0;
|
|
20349
|
+
for (const [taskId, task] of this.tasks.entries()) {
|
|
20350
|
+
if (task.status === ScheduledTaskStatus.RUNNING && task.updatedAt < cutoff) {
|
|
20351
|
+
this.tasks.set(taskId, {
|
|
20352
|
+
...task,
|
|
20353
|
+
status: ScheduledTaskStatus.PENDING,
|
|
20354
|
+
updatedAt: now
|
|
20355
|
+
});
|
|
20356
|
+
requeued++;
|
|
20357
|
+
}
|
|
20358
|
+
}
|
|
20359
|
+
return requeued;
|
|
20360
|
+
}
|
|
19550
20361
|
/**
|
|
19551
20362
|
* Delete task
|
|
19552
20363
|
*/
|
|
@@ -19911,6 +20722,7 @@ function describeCronExpression(expression) {
|
|
|
19911
20722
|
}
|
|
19912
20723
|
|
|
19913
20724
|
// src/schedule_lattice/DefaultScheduleClient.ts
|
|
20725
|
+
var STALE_RUNNING_MS = 30 * 6e4;
|
|
19914
20726
|
var _DefaultScheduleClient = class _DefaultScheduleClient {
|
|
19915
20727
|
constructor(storage) {
|
|
19916
20728
|
this.handlers = /* @__PURE__ */ new Map();
|
|
@@ -20151,6 +20963,19 @@ var _DefaultScheduleClient = class _DefaultScheduleClient {
|
|
|
20151
20963
|
}
|
|
20152
20964
|
// ===== Recovery =====
|
|
20153
20965
|
async restore() {
|
|
20966
|
+
try {
|
|
20967
|
+
const requeued = await this.storage.requeueStaleRunning(STALE_RUNNING_MS);
|
|
20968
|
+
if (requeued > 0) {
|
|
20969
|
+
console.log(
|
|
20970
|
+
`[Scheduler] Requeued ${requeued} stale running task(s)`
|
|
20971
|
+
);
|
|
20972
|
+
}
|
|
20973
|
+
} catch (error) {
|
|
20974
|
+
console.error(
|
|
20975
|
+
"[Scheduler] Failed to requeue stale running tasks:",
|
|
20976
|
+
error
|
|
20977
|
+
);
|
|
20978
|
+
}
|
|
20154
20979
|
const activeTasks = await this.storage.getActiveTasks();
|
|
20155
20980
|
let restored = 0;
|
|
20156
20981
|
for (const task of activeTasks) {
|
|
@@ -20211,6 +21036,16 @@ var _DefaultScheduleClient = class _DefaultScheduleClient {
|
|
|
20211
21036
|
});
|
|
20212
21037
|
}
|
|
20213
21038
|
async executeTask(task) {
|
|
21039
|
+
let claimed = false;
|
|
21040
|
+
try {
|
|
21041
|
+
claimed = await this.storage.claimScheduledRun(task.taskId);
|
|
21042
|
+
} catch (error) {
|
|
21043
|
+
console.error(`[Scheduler] Failed to claim task ${task.taskId}:`, error);
|
|
21044
|
+
return;
|
|
21045
|
+
}
|
|
21046
|
+
if (!claimed) {
|
|
21047
|
+
return;
|
|
21048
|
+
}
|
|
20214
21049
|
const handler = this.handlers.get(task.taskType);
|
|
20215
21050
|
if (!handler) {
|
|
20216
21051
|
console.error(
|
|
@@ -20222,9 +21057,6 @@ var _DefaultScheduleClient = class _DefaultScheduleClient {
|
|
|
20222
21057
|
});
|
|
20223
21058
|
return;
|
|
20224
21059
|
}
|
|
20225
|
-
await this.storage.update(task.taskId, {
|
|
20226
|
-
status: ScheduledTaskStatus2.RUNNING
|
|
20227
|
-
});
|
|
20228
21060
|
console.log(`[Scheduler] Executing task: ${task.taskId}`);
|
|
20229
21061
|
try {
|
|
20230
21062
|
const latestTask = await this.storage.get(task.taskId);
|
|
@@ -24938,8 +25770,8 @@ var VectorStoreProviderManager = class _VectorStoreProviderManager extends BaseL
|
|
|
24938
25770
|
* @param key Provider key name
|
|
24939
25771
|
* @param provider VectorStoreProvider implementation
|
|
24940
25772
|
*/
|
|
24941
|
-
registerProvider(key5,
|
|
24942
|
-
const lattice = { key: key5, provider };
|
|
25773
|
+
registerProvider(key5, provider2) {
|
|
25774
|
+
const lattice = { key: key5, provider: provider2 };
|
|
24943
25775
|
this.registerWithTenant("default", key5, lattice);
|
|
24944
25776
|
}
|
|
24945
25777
|
/**
|
|
@@ -24975,7 +25807,7 @@ var VectorStoreProviderManager = class _VectorStoreProviderManager extends BaseL
|
|
|
24975
25807
|
};
|
|
24976
25808
|
var vectorStoreProviderManager = VectorStoreProviderManager.getInstance();
|
|
24977
25809
|
vectorStoreProviderManager.registerProvider("default", new MemoryVectorStoreProvider());
|
|
24978
|
-
var registerVectorStoreProvider = (key5,
|
|
25810
|
+
var registerVectorStoreProvider = (key5, provider2) => vectorStoreProviderManager.registerProvider(key5, provider2);
|
|
24979
25811
|
var getVectorStoreProvider = (key5) => vectorStoreProviderManager.getProvider(key5);
|
|
24980
25812
|
|
|
24981
25813
|
// src/store_lattice/configureStores.ts
|
|
@@ -27677,7 +28509,110 @@ independently before the workflow's integration eval.
|
|
|
27677
28509
|
|
|
27678
28510
|
An unsupported architecture conversion interrupts the flow and requests a new
|
|
27679
28511
|
user decision. Do not route backward to the Charter or to [[agent-build]], and do
|
|
27680
|
-
not create a replacement
|
|
28512
|
+
not create a replacement.`,
|
|
28513
|
+
"ptc": `---
|
|
28514
|
+
name: ptc
|
|
28515
|
+
description: Programmatic Tool Calling (PTC) \u2014 write sandbox code that discovers and calls platform Open capabilities (MCP tools) through the gateway. Use when orchestration is multi-step, data-heavy, or needs loops/branches across platform tools instead of one-at-a-time model tool calls.
|
|
28516
|
+
metadata:
|
|
28517
|
+
role: workflow
|
|
28518
|
+
domain: orchestration
|
|
28519
|
+
verified: unverified
|
|
28520
|
+
---
|
|
28521
|
+
|
|
28522
|
+
# Programmatic Tool Calling (PTC)
|
|
28523
|
+
|
|
28524
|
+
PTC means the model writes and runs code that calls platform tools itself, instead
|
|
28525
|
+
of calling tools one at a time. Reach for it when orchestration is multi-step,
|
|
28526
|
+
data-heavy, or needs a loop/branch that would be wasteful as a chain of model tool
|
|
28527
|
+
calls.
|
|
28528
|
+
|
|
28529
|
+
## Where the code runs
|
|
28530
|
+
|
|
28531
|
+
Run the code with \`code_eval\` (backed by \`shell_exec\`). Each execution process is
|
|
28532
|
+
injected with two environment variables:
|
|
28533
|
+
|
|
28534
|
+
- \`API_GATEWAY_URL\` \u2014 the gateway base URL.
|
|
28535
|
+
- \`OPEN_API_TOKEN\` \u2014 a short-lived bearer token **self-bound to this agent**. It is
|
|
28536
|
+
not reusable elsewhere.
|
|
28537
|
+
|
|
28538
|
+
The token already encodes this agent's authority: the platform reflects the agent's
|
|
28539
|
+
own configured middleware into Open grants, plus a small always-on baseline
|
|
28540
|
+
(\`kb\` read-only and \`sandbox:self\`). So the callable set = that baseline \u222A the
|
|
28541
|
+
domains your configured middleware exposes \u2014 and nothing beyond it.
|
|
28542
|
+
|
|
28543
|
+
## Client
|
|
28544
|
+
|
|
28545
|
+
The sandbox must have the zero-dependency \`@axiom-lattice/open-mcp-client\` package.
|
|
28546
|
+
Get it one of two ways:
|
|
28547
|
+
|
|
28548
|
+
- **Preinstalled in the sandbox image** (recommended): \`open-mcp\` is on \`PATH\`; for
|
|
28549
|
+
\`require("@axiom-lattice/open-mcp-client")\` to resolve, install it into the working
|
|
28550
|
+
directory or point \`NODE_PATH\` at the global \`node_modules\`.
|
|
28551
|
+
- **Install it in this run** when the sandbox has network + npm:
|
|
28552
|
+
|
|
28553
|
+
\`\`\`bash
|
|
28554
|
+
npm install @axiom-lattice/open-mcp-client
|
|
28555
|
+
# or use without installing:
|
|
28556
|
+
npx @axiom-lattice/open-mcp-client tools list --json
|
|
28557
|
+
\`\`\`
|
|
28558
|
+
|
|
28559
|
+
\`\`\`js
|
|
28560
|
+
const { OpenMcpClient } = require("@axiom-lattice/open-mcp-client");
|
|
28561
|
+
const client = OpenMcpClient.fromEnv(); // reads API_GATEWAY_URL + OPEN_API_TOKEN
|
|
28562
|
+
\`\`\`
|
|
28563
|
+
|
|
28564
|
+
CLI equivalents (config comes from the same env vars):
|
|
28565
|
+
|
|
28566
|
+
\`\`\`bash
|
|
28567
|
+
open-mcp tools list --json
|
|
28568
|
+
open-mcp tools call kb_search --json '{"query":"refund policy"}'
|
|
28569
|
+
\`\`\`
|
|
28570
|
+
|
|
28571
|
+
## Discover, then call
|
|
28572
|
+
|
|
28573
|
+
1. **Discover first.** Call \`await client.listTools()\`. This returns exactly the
|
|
28574
|
+
tools this agent is authorized to call (the server filters by the token's grants
|
|
28575
|
+
on every request, so it is the source of truth).
|
|
28576
|
+
2. **Only call discovered tools.** Pick a tool from that list and call
|
|
28577
|
+
\`await client.callTool(name, args)\` with args matching the tool's \`inputSchema\`.
|
|
28578
|
+
3. **Print the final result as JSON to stdout** so the calling agent can consume it.
|
|
28579
|
+
Keep intermediate logs minimal.
|
|
28580
|
+
|
|
28581
|
+
An unconfigured domain isn't registered, so calling it returns an \`isError\`
|
|
28582
|
+
tool-not-found result; a registered tool refused by the token's grants surfaces
|
|
28583
|
+
\`GRANT_DENIED\`. Either way the capability is **not configured for this agent**.
|
|
28584
|
+
Do not retry or work around it \u2014 drop that step or tell the user which
|
|
28585
|
+
middleware/domain must be enabled. A denied call is expected behavior, not a
|
|
28586
|
+
transient failure.
|
|
28587
|
+
|
|
28588
|
+
## Tips
|
|
28589
|
+
|
|
28590
|
+
- Fan out with \`Promise.all\` over many items instead of many sequential model turns;
|
|
28591
|
+
that is the main win of PTC.
|
|
28592
|
+
- Inspect \`tool.inputSchema\` before calling to avoid schema-validation errors.
|
|
28593
|
+
- Reduce large results in code and return only the fields the agent needs.
|
|
28594
|
+
- The token is short-lived; for very long jobs re-read the env per \`code_eval\` run
|
|
28595
|
+
rather than caching the token in a file.
|
|
28596
|
+
|
|
28597
|
+
## Worked example
|
|
28598
|
+
|
|
28599
|
+
\`\`\`js
|
|
28600
|
+
const { OpenMcpClient } = require("@axiom-lattice/open-mcp-client");
|
|
28601
|
+
|
|
28602
|
+
async function main() {
|
|
28603
|
+
const client = OpenMcpClient.fromEnv(); // API_GATEWAY_URL + OPEN_API_TOKEN
|
|
28604
|
+
const tools = await client.listTools(); // exactly what this agent may call
|
|
28605
|
+
const pick = tools.find((t) => t.name === "kb_search") ?? tools[0];
|
|
28606
|
+
const out = await client.callTool(pick.name, { query: "refund policy" });
|
|
28607
|
+
console.log(JSON.stringify({ called: pick.name, result: out.json() }));
|
|
28608
|
+
}
|
|
28609
|
+
|
|
28610
|
+
main().catch((err) => { console.error(String(err)); process.exit(1); });
|
|
28611
|
+
\`\`\`
|
|
28612
|
+
|
|
28613
|
+
Run this in \`code_eval\`. The first run proves env + client wiring; then extend it
|
|
28614
|
+
into the real fan-out/aggregation the task needs.
|
|
28615
|
+
`
|
|
27681
28616
|
};
|
|
27682
28617
|
function getBuiltInSkillMeta(name) {
|
|
27683
28618
|
const content = BUILTIN_SKILLS[name];
|
|
@@ -28274,7 +29209,7 @@ ${body}` : `${frontmatter}
|
|
|
28274
29209
|
};
|
|
28275
29210
|
|
|
28276
29211
|
// src/store_lattice/InMemoryMenuStore.ts
|
|
28277
|
-
import { randomUUID as
|
|
29212
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
28278
29213
|
var InMemoryMenuStore = class {
|
|
28279
29214
|
constructor() {
|
|
28280
29215
|
this.items = /* @__PURE__ */ new Map();
|
|
@@ -28295,7 +29230,7 @@ var InMemoryMenuStore = class {
|
|
|
28295
29230
|
async create(input) {
|
|
28296
29231
|
const now = /* @__PURE__ */ new Date();
|
|
28297
29232
|
const item = {
|
|
28298
|
-
id:
|
|
29233
|
+
id: randomUUID7(),
|
|
28299
29234
|
tenantId: input.tenantId,
|
|
28300
29235
|
menuTarget: input.menuTarget,
|
|
28301
29236
|
group: input.group,
|
|
@@ -30807,9 +31742,9 @@ async function getOrCreateCollectionVectorStore(name, embeddingKey, tenantId2, p
|
|
|
30807
31742
|
const pendingInitialization = pendingVectorStoreInitializations.get(storeKey);
|
|
30808
31743
|
if (pendingInitialization) return pendingInitialization;
|
|
30809
31744
|
const initialization = (async () => {
|
|
30810
|
-
const
|
|
31745
|
+
const provider2 = vectorStoreProviderManager.getProvider(providerKey);
|
|
30811
31746
|
const tableName = buildTableName(tenantId2, name);
|
|
30812
|
-
const vectorStore = await
|
|
31747
|
+
const vectorStore = await provider2.create({ tableName, embeddingKey });
|
|
30813
31748
|
vectorStoreLatticeManager.registerLattice(storeKey, vectorStore);
|
|
30814
31749
|
return vectorStore;
|
|
30815
31750
|
})();
|
|
@@ -30827,9 +31762,9 @@ async function getCollectionEntryCount(name, embeddingKey, tenantId2) {
|
|
|
30827
31762
|
return vs.getDocumentCount();
|
|
30828
31763
|
}
|
|
30829
31764
|
try {
|
|
30830
|
-
const
|
|
30831
|
-
if (
|
|
30832
|
-
return
|
|
31765
|
+
const provider2 = vectorStoreProviderManager.getProvider("default");
|
|
31766
|
+
if (provider2.getEntryCount) {
|
|
31767
|
+
return provider2.getEntryCount(buildTableName(tenantId2, name));
|
|
30833
31768
|
}
|
|
30834
31769
|
} catch {
|
|
30835
31770
|
}
|
|
@@ -30841,9 +31776,9 @@ async function listCollectionEntries(name, embeddingKey, tenantId2) {
|
|
|
30841
31776
|
return vs.getAllDocuments();
|
|
30842
31777
|
}
|
|
30843
31778
|
try {
|
|
30844
|
-
const
|
|
30845
|
-
if (
|
|
30846
|
-
return
|
|
31779
|
+
const provider2 = vectorStoreProviderManager.getProvider("default");
|
|
31780
|
+
if (provider2.listEntries) {
|
|
31781
|
+
return provider2.listEntries(buildTableName(tenantId2, name));
|
|
30847
31782
|
}
|
|
30848
31783
|
} catch {
|
|
30849
31784
|
}
|
|
@@ -30853,9 +31788,9 @@ async function removeCollectionVectorStore(name, tenantId2) {
|
|
|
30853
31788
|
const storeKey = buildKey(tenantId2, name);
|
|
30854
31789
|
const tableName = buildTableName(tenantId2, name);
|
|
30855
31790
|
try {
|
|
30856
|
-
const
|
|
30857
|
-
if (
|
|
30858
|
-
await
|
|
31791
|
+
const provider2 = vectorStoreProviderManager.getProvider("default");
|
|
31792
|
+
if (provider2.dropTable) {
|
|
31793
|
+
await provider2.dropTable(tableName);
|
|
30859
31794
|
}
|
|
30860
31795
|
} catch {
|
|
30861
31796
|
}
|
|
@@ -33170,7 +34105,7 @@ var DaytonaProvider = class {
|
|
|
33170
34105
|
|
|
33171
34106
|
// src/sandbox_lattice/providers/LocalSandboxProvider.ts
|
|
33172
34107
|
import * as path6 from "path";
|
|
33173
|
-
import * as
|
|
34108
|
+
import * as os2 from "os";
|
|
33174
34109
|
import * as fs4 from "fs/promises";
|
|
33175
34110
|
|
|
33176
34111
|
// src/sandbox_lattice/LocalSandboxInstance.ts
|
|
@@ -33197,6 +34132,32 @@ function assertRegularDeleteTarget(file, stat4) {
|
|
|
33197
34132
|
function quoteShellArgument(value) {
|
|
33198
34133
|
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
33199
34134
|
}
|
|
34135
|
+
var PLATFORM_SECRET_ENV_VARS = [
|
|
34136
|
+
"OPEN_TOKEN_SECRET",
|
|
34137
|
+
"AUTH_TOKEN_SECRET",
|
|
34138
|
+
"JWT_SECRET",
|
|
34139
|
+
"WEB_APP_ATTACHMENT_SECRET",
|
|
34140
|
+
"LATTICE_ENCRYPTION_KEY",
|
|
34141
|
+
"DATABASE_URL",
|
|
34142
|
+
"REDIS_PASSWORD",
|
|
34143
|
+
"MICROSANDBOX_API_KEY",
|
|
34144
|
+
"DAYTONA_API_KEY",
|
|
34145
|
+
"E2B_API_KEY",
|
|
34146
|
+
"OPENAI_API_KEY",
|
|
34147
|
+
"AZURE_OPENAI_API_KEY",
|
|
34148
|
+
"ANTHROPIC_API_KEY",
|
|
34149
|
+
"TAVILY_API_KEY",
|
|
34150
|
+
"VAPID_PRIVATE_KEY",
|
|
34151
|
+
"SUPABASE_KEY",
|
|
34152
|
+
"A2A_API_KEYS"
|
|
34153
|
+
];
|
|
34154
|
+
function stripPlatformSecrets(env) {
|
|
34155
|
+
const rest = { ...env };
|
|
34156
|
+
for (const name of PLATFORM_SECRET_ENV_VARS) {
|
|
34157
|
+
delete rest[name];
|
|
34158
|
+
}
|
|
34159
|
+
return rest;
|
|
34160
|
+
}
|
|
33200
34161
|
function validatePackEntryName(name) {
|
|
33201
34162
|
if (!name || name === "." || name === ".." || name.includes("\\") || name.includes("/")) {
|
|
33202
34163
|
throw new Error(`Cannot pack: unsafe entry name '${name}'`);
|
|
@@ -33369,7 +34330,7 @@ var LocalSandboxInstance = class {
|
|
|
33369
34330
|
timeout: timeoutMs,
|
|
33370
34331
|
maxBuffer: 10 * 1024 * 1024,
|
|
33371
34332
|
// 10MB
|
|
33372
|
-
env: { ...process.env, HOME: this.rootDir }
|
|
34333
|
+
env: stripPlatformSecrets({ ...process.env, HOME: this.rootDir })
|
|
33373
34334
|
}
|
|
33374
34335
|
);
|
|
33375
34336
|
const output = stderr ? `${stdout}
|
|
@@ -33634,7 +34595,7 @@ var LocalSandboxProvider = class {
|
|
|
33634
34595
|
this.instances = /* @__PURE__ */ new Map();
|
|
33635
34596
|
this.creating = /* @__PURE__ */ new Map();
|
|
33636
34597
|
this.createResourceAddress = createResourceAddress;
|
|
33637
|
-
this.basePath = config.basePath ?? path6.join(
|
|
34598
|
+
this.basePath = config.basePath ?? path6.join(os2.homedir(), ".axiom-local-sandbox");
|
|
33638
34599
|
}
|
|
33639
34600
|
async createSandbox(name, _config) {
|
|
33640
34601
|
const existing = this.instances.get(name);
|
|
@@ -35010,6 +35971,10 @@ var TaskLifecycleNotifier = class {
|
|
|
35010
35971
|
this.listeners = /* @__PURE__ */ new Set();
|
|
35011
35972
|
this.tails = /* @__PURE__ */ new Map();
|
|
35012
35973
|
}
|
|
35974
|
+
/** Installs (or clears) the durable outbox used to fan notifications to other replicas. */
|
|
35975
|
+
setOutbox(outbox2) {
|
|
35976
|
+
this.outbox = outbox2;
|
|
35977
|
+
}
|
|
35013
35978
|
/**
|
|
35014
35979
|
* Registers an async lifecycle listener.
|
|
35015
35980
|
*
|
|
@@ -35030,6 +35995,25 @@ var TaskLifecycleNotifier = class {
|
|
|
35030
35995
|
* @throws Error when the event is malformed or one or more listeners reject.
|
|
35031
35996
|
*/
|
|
35032
35997
|
async publish(event) {
|
|
35998
|
+
const snapshot = snapshotNotification(event);
|
|
35999
|
+
const key5 = `${snapshot.tenantId}:${snapshot.taskId}`;
|
|
36000
|
+
const previous = this.tails.get(key5) ?? Promise.resolve();
|
|
36001
|
+
const delivery = previous.catch(() => void 0).then(() => this.deliver(snapshot));
|
|
36002
|
+
this.tails.set(key5, delivery);
|
|
36003
|
+
if (this.outbox) {
|
|
36004
|
+
try {
|
|
36005
|
+
await this.outbox.append({ topic: "task-lifecycle", payload: snapshot, originReplicaId: getReplicaId() });
|
|
36006
|
+
} catch {
|
|
36007
|
+
}
|
|
36008
|
+
}
|
|
36009
|
+
try {
|
|
36010
|
+
await delivery;
|
|
36011
|
+
} finally {
|
|
36012
|
+
if (this.tails.get(key5) === delivery) this.tails.delete(key5);
|
|
36013
|
+
}
|
|
36014
|
+
}
|
|
36015
|
+
/** Delivers one outbox payload to local listeners without re-appending (poller path). */
|
|
36016
|
+
async deliverFromOutbox(event) {
|
|
35033
36017
|
const snapshot = snapshotNotification(event);
|
|
35034
36018
|
const key5 = `${snapshot.tenantId}:${snapshot.taskId}`;
|
|
35035
36019
|
const previous = this.tails.get(key5) ?? Promise.resolve();
|
|
@@ -35094,6 +36078,10 @@ var ProjectTaskAdmissionNotifier = class {
|
|
|
35094
36078
|
if (!Number.isSafeInteger(timeout) || timeout <= 0) throw new Error("Invalid admission listener timeout");
|
|
35095
36079
|
this.listenerTimeoutMs = timeout;
|
|
35096
36080
|
}
|
|
36081
|
+
/** Installs (or clears) the durable outbox used to fan notifications to other replicas. */
|
|
36082
|
+
setOutbox(outbox2) {
|
|
36083
|
+
this.outbox = outbox2;
|
|
36084
|
+
}
|
|
35097
36085
|
/**
|
|
35098
36086
|
* Registers a Project task admission listener.
|
|
35099
36087
|
*
|
|
@@ -35113,6 +36101,30 @@ var ProjectTaskAdmissionNotifier = class {
|
|
|
35113
36101
|
* @returns A promise settled after every snapshotted listener settles.
|
|
35114
36102
|
*/
|
|
35115
36103
|
async publish(event) {
|
|
36104
|
+
const snapshot = snapshotNotification2(event);
|
|
36105
|
+
const listeners = [...this.listeners];
|
|
36106
|
+
const key5 = `${snapshot.tenantId}\0${snapshot.taskId}`;
|
|
36107
|
+
const previous = this.tails.get(key5) ?? Promise.resolve();
|
|
36108
|
+
const delivery = previous.catch(() => void 0).then(() => this.deliver(snapshot, listeners));
|
|
36109
|
+
this.tails.set(key5, delivery);
|
|
36110
|
+
if (this.outbox) {
|
|
36111
|
+
try {
|
|
36112
|
+
await this.outbox.append({
|
|
36113
|
+
topic: "project-task-admission",
|
|
36114
|
+
payload: snapshot,
|
|
36115
|
+
originReplicaId: getReplicaId()
|
|
36116
|
+
});
|
|
36117
|
+
} catch {
|
|
36118
|
+
}
|
|
36119
|
+
}
|
|
36120
|
+
try {
|
|
36121
|
+
await delivery;
|
|
36122
|
+
} finally {
|
|
36123
|
+
if (this.tails.get(key5) === delivery) this.tails.delete(key5);
|
|
36124
|
+
}
|
|
36125
|
+
}
|
|
36126
|
+
/** Delivers one outbox payload to local listeners without re-appending (poller path). */
|
|
36127
|
+
async deliverFromOutbox(event) {
|
|
35116
36128
|
const snapshot = snapshotNotification2(event);
|
|
35117
36129
|
const listeners = [...this.listeners];
|
|
35118
36130
|
const key5 = `${snapshot.tenantId}\0${snapshot.taskId}`;
|
|
@@ -35182,8 +36194,137 @@ function canonicalTimestamp(value) {
|
|
|
35182
36194
|
return Number.isFinite(parsed.getTime()) && parsed.toISOString() === value;
|
|
35183
36195
|
}
|
|
35184
36196
|
|
|
36197
|
+
// src/services/OutboxPoller.ts
|
|
36198
|
+
var OutboxPoller = class {
|
|
36199
|
+
/**
|
|
36200
|
+
* Creates a poller bound to one durable outbox.
|
|
36201
|
+
*
|
|
36202
|
+
* @param deps Store, owner replica id, topic handlers, and optional tuning.
|
|
36203
|
+
*/
|
|
36204
|
+
constructor(deps) {
|
|
36205
|
+
this.deps = deps;
|
|
36206
|
+
this.cursor = null;
|
|
36207
|
+
this.polling = false;
|
|
36208
|
+
}
|
|
36209
|
+
/** Captures the starting cursor and begins polling. */
|
|
36210
|
+
async start() {
|
|
36211
|
+
this.cursor = await this.deps.store.latestId();
|
|
36212
|
+
this.timer = setInterval(() => {
|
|
36213
|
+
void this.pollOnce();
|
|
36214
|
+
}, this.deps.intervalMs ?? 1e3);
|
|
36215
|
+
this.timer.unref?.();
|
|
36216
|
+
}
|
|
36217
|
+
/** Stops polling. */
|
|
36218
|
+
stop() {
|
|
36219
|
+
if (this.timer) clearInterval(this.timer);
|
|
36220
|
+
this.timer = void 0;
|
|
36221
|
+
}
|
|
36222
|
+
/** Runs one drain pass (exported for tests). */
|
|
36223
|
+
async pollOnce() {
|
|
36224
|
+
if (this.polling) return;
|
|
36225
|
+
this.polling = true;
|
|
36226
|
+
try {
|
|
36227
|
+
const batchSize = this.deps.batchSize ?? 100;
|
|
36228
|
+
for (; ; ) {
|
|
36229
|
+
const events = await this.deps.store.listAfter(this.cursor, batchSize);
|
|
36230
|
+
if (events.length === 0) break;
|
|
36231
|
+
for (const event of events) {
|
|
36232
|
+
this.cursor = event.id;
|
|
36233
|
+
if (event.originReplicaId === this.deps.owner) continue;
|
|
36234
|
+
const handler = this.deps.handlers[event.topic];
|
|
36235
|
+
if (!handler) continue;
|
|
36236
|
+
try {
|
|
36237
|
+
await this.deliverWithTimeout(handler, event.payload);
|
|
36238
|
+
} catch {
|
|
36239
|
+
this.deps.log?.warn("Outbox delivery failed", { topic: event.topic, id: event.id });
|
|
36240
|
+
}
|
|
36241
|
+
}
|
|
36242
|
+
if (events.length < batchSize) break;
|
|
36243
|
+
}
|
|
36244
|
+
} catch (error) {
|
|
36245
|
+
this.deps.log?.warn("Outbox poll failed", { error: error instanceof Error ? error.message : String(error) });
|
|
36246
|
+
} finally {
|
|
36247
|
+
this.polling = false;
|
|
36248
|
+
}
|
|
36249
|
+
}
|
|
36250
|
+
/**
|
|
36251
|
+
* Runs one handler bounded by `handlerTimeoutMs` so a hung listener cannot
|
|
36252
|
+
* stall cross-replica delivery for this replica.
|
|
36253
|
+
*/
|
|
36254
|
+
async deliverWithTimeout(handler, payload) {
|
|
36255
|
+
const timeoutMs = this.deps.handlerTimeoutMs ?? 5e3;
|
|
36256
|
+
let timer;
|
|
36257
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
36258
|
+
timer = setTimeout(() => reject(new Error("Outbox handler timed out")), timeoutMs);
|
|
36259
|
+
timer.unref?.();
|
|
36260
|
+
});
|
|
36261
|
+
try {
|
|
36262
|
+
await Promise.race([Promise.resolve().then(() => handler(payload)), timeout]);
|
|
36263
|
+
} finally {
|
|
36264
|
+
if (timer) clearTimeout(timer);
|
|
36265
|
+
}
|
|
36266
|
+
}
|
|
36267
|
+
};
|
|
36268
|
+
|
|
35185
36269
|
// src/services/ProjectMutationMutex.ts
|
|
35186
36270
|
import { snapshotExactRecord as snapshotExactRecord4 } from "@axiom-lattice/protocols";
|
|
36271
|
+
|
|
36272
|
+
// src/services/coordinationLease.ts
|
|
36273
|
+
var configured;
|
|
36274
|
+
function configureCoordinationLeaseStore(store) {
|
|
36275
|
+
configured = store;
|
|
36276
|
+
}
|
|
36277
|
+
function getCoordinationLeaseStore() {
|
|
36278
|
+
return configured;
|
|
36279
|
+
}
|
|
36280
|
+
|
|
36281
|
+
// src/services/withLease.ts
|
|
36282
|
+
import { randomUUID as randomUUID8 } from "crypto";
|
|
36283
|
+
var LeaseAcquisitionTimeoutError = class extends Error {
|
|
36284
|
+
/**
|
|
36285
|
+
* @param key Lease key that could not be acquired.
|
|
36286
|
+
* @param holder Unique holder that attempted acquisition.
|
|
36287
|
+
* @param timeoutMs How long the caller waited before giving up.
|
|
36288
|
+
*/
|
|
36289
|
+
constructor(key5, holder, timeoutMs) {
|
|
36290
|
+
super(`Could not acquire lease '${key5}' for '${holder}' within ${timeoutMs}ms`);
|
|
36291
|
+
this.key = key5;
|
|
36292
|
+
this.holder = holder;
|
|
36293
|
+
this.timeoutMs = timeoutMs;
|
|
36294
|
+
/** Stable machine-readable code. */
|
|
36295
|
+
this.code = "LEASE_ACQUISITION_TIMEOUT";
|
|
36296
|
+
this.name = "LeaseAcquisitionTimeoutError";
|
|
36297
|
+
}
|
|
36298
|
+
};
|
|
36299
|
+
function sleep(ms) {
|
|
36300
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
36301
|
+
}
|
|
36302
|
+
async function withLease(store, key5, ownerLabel, fn, options = {}) {
|
|
36303
|
+
const ttlMs = options.ttlMs ?? 3e4;
|
|
36304
|
+
const acquireTimeoutMs = options.acquireTimeoutMs ?? 1e4;
|
|
36305
|
+
const retryDelayMs = options.retryDelayMs ?? 50;
|
|
36306
|
+
const heartbeatMs = options.heartbeatMs ?? Math.max(1e3, Math.floor(ttlMs / 3));
|
|
36307
|
+
const holder = `${ownerLabel}#${randomUUID8()}`;
|
|
36308
|
+
const deadline = Date.now() + acquireTimeoutMs;
|
|
36309
|
+
for (; ; ) {
|
|
36310
|
+
if (await store.tryAcquire(key5, holder, ttlMs)) break;
|
|
36311
|
+
if (Date.now() >= deadline) throw new LeaseAcquisitionTimeoutError(key5, holder, acquireTimeoutMs);
|
|
36312
|
+
await sleep(retryDelayMs);
|
|
36313
|
+
}
|
|
36314
|
+
const heartbeat = setInterval(() => {
|
|
36315
|
+
void store.renew(key5, holder, ttlMs).catch(() => void 0);
|
|
36316
|
+
}, heartbeatMs);
|
|
36317
|
+
heartbeat.unref?.();
|
|
36318
|
+
try {
|
|
36319
|
+
return await fn();
|
|
36320
|
+
} finally {
|
|
36321
|
+
clearInterval(heartbeat);
|
|
36322
|
+
await store.release(key5, holder).catch(() => void 0);
|
|
36323
|
+
}
|
|
36324
|
+
}
|
|
36325
|
+
|
|
36326
|
+
// src/services/ProjectMutationMutex.ts
|
|
36327
|
+
var MUTATION_LEASE_OPTIONS = { ttlMs: 6e4, acquireTimeoutMs: 9e4, retryDelayMs: 100 };
|
|
35187
36328
|
function projectKey(scope) {
|
|
35188
36329
|
const row = snapshotExactRecord4(scope, ["tenantId", "projectId"]);
|
|
35189
36330
|
if (!row || typeof row.tenantId !== "string" || !row.tenantId || row.tenantId.includes("\0") || typeof row.projectId !== "string" || !row.projectId || row.projectId.includes("\0")) {
|
|
@@ -35199,9 +36340,12 @@ var ProjectMutationMutex = class {
|
|
|
35199
36340
|
/** Runs one mutation after all earlier mutations for the same Tenant and Project. */
|
|
35200
36341
|
async runExclusive(scope, operation, signal) {
|
|
35201
36342
|
const key5 = projectKey(scope);
|
|
36343
|
+
const leaseKey = `project-mutation:${encodeURIComponent(scope.tenantId)}:${encodeURIComponent(scope.projectId)}`;
|
|
35202
36344
|
await this.acquire(key5, signal);
|
|
35203
36345
|
try {
|
|
35204
|
-
|
|
36346
|
+
const store = getCoordinationLeaseStore();
|
|
36347
|
+
if (!store) return await operation();
|
|
36348
|
+
return await withLease(store, leaseKey, getReplicaId(), operation, MUTATION_LEASE_OPTIONS);
|
|
35205
36349
|
} finally {
|
|
35206
36350
|
this.release(key5);
|
|
35207
36351
|
}
|
|
@@ -35259,7 +36403,7 @@ function createTrustedAgentMessageDispatcher(resolve4) {
|
|
|
35259
36403
|
}
|
|
35260
36404
|
|
|
35261
36405
|
// src/services/RoomAgentMessageService.ts
|
|
35262
|
-
import { randomUUID as
|
|
36406
|
+
import { randomUUID as randomUUID9 } from "crypto";
|
|
35263
36407
|
import { snapshotExactArray, snapshotExactRecord as snapshotExactRecord5 } from "@axiom-lattice/protocols";
|
|
35264
36408
|
var INPUT_KEYS = [
|
|
35265
36409
|
"tenantId",
|
|
@@ -35347,7 +36491,7 @@ var RoomAgentMessageService = class {
|
|
|
35347
36491
|
throw new Error("Invalid project room membership");
|
|
35348
36492
|
}
|
|
35349
36493
|
const candidate = {
|
|
35350
|
-
id: (this.deps.idFactory ??
|
|
36494
|
+
id: (this.deps.idFactory ?? randomUUID9)(),
|
|
35351
36495
|
tenantId: input.tenantId,
|
|
35352
36496
|
workspaceId: input.workspaceId,
|
|
35353
36497
|
projectId: input.projectId,
|
|
@@ -35687,6 +36831,8 @@ function buildParentBeliefActivity(input) {
|
|
|
35687
36831
|
}
|
|
35688
36832
|
|
|
35689
36833
|
// src/services/TaskLifecycleService.ts
|
|
36834
|
+
var WORK_ITEM_WRITE_ATTEMPTS = 3;
|
|
36835
|
+
var WORK_ITEM_WRITE_RETRY_DELAYS_MS = [20, 50];
|
|
35690
36836
|
var RETRYABLE_LIFECYCLE_CODES = /* @__PURE__ */ new Set([
|
|
35691
36837
|
"TASK_STATUS_CONFLICT",
|
|
35692
36838
|
"TASK_STORE_WRITE_FAILED",
|
|
@@ -35706,9 +36852,9 @@ var BELIEF_OWNER_WRITE_ATTEMPTS = 3;
|
|
|
35706
36852
|
function isWellFormedImpact(impact) {
|
|
35707
36853
|
return /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(impact.key) && Number.isInteger(impact.after) && impact.after >= 0 && impact.after <= 100 && impact.basis.trim().length > 0 && impact.basis.length <= 1e3 && !/[\r\n]/.test(impact.basis);
|
|
35708
36854
|
}
|
|
35709
|
-
async function applyBeliefImpacts(taskStore,
|
|
35710
|
-
if (impacts.length === 0) return { description:
|
|
35711
|
-
let current =
|
|
36855
|
+
async function applyBeliefImpacts(taskStore, owner2, impacts) {
|
|
36856
|
+
if (impacts.length === 0) return { description: owner2.description ?? "" };
|
|
36857
|
+
let current = owner2;
|
|
35712
36858
|
for (let attempt = 0; attempt < BELIEF_OWNER_WRITE_ATTEMPTS; attempt += 1) {
|
|
35713
36859
|
const parsed = parseTaskBeliefState(current.description ?? "");
|
|
35714
36860
|
const existingTable = parsed.success;
|
|
@@ -35837,14 +36983,14 @@ function sameBeliefOwner(left, right) {
|
|
|
35837
36983
|
function sameBeliefOwnerIdentity(left, right) {
|
|
35838
36984
|
return canonicalJson({ ...left, beliefState: void 0 }) === canonicalJson({ ...right, beliefState: void 0 });
|
|
35839
36985
|
}
|
|
35840
|
-
function canonicalBeliefOwner(
|
|
36986
|
+
function canonicalBeliefOwner(owner2) {
|
|
35841
36987
|
const beliefState = {
|
|
35842
|
-
entries:
|
|
36988
|
+
entries: owner2.beliefState.entries.map((entry) => ({
|
|
35843
36989
|
...entry,
|
|
35844
36990
|
basis: entry.basis.trim().replace(/\s+/g, " ")
|
|
35845
36991
|
})).sort((left, right) => left.key < right.key ? -1 : left.key > right.key ? 1 : 0)
|
|
35846
36992
|
};
|
|
35847
|
-
return { ...
|
|
36993
|
+
return { ...owner2, beliefState };
|
|
35848
36994
|
}
|
|
35849
36995
|
function eventKeyFor(taskId, result, impacts, beliefOwner) {
|
|
35850
36996
|
const base = `belief-impact:${taskId}:${buildBeliefCompletionEventKey(taskId, result, impacts)}`;
|
|
@@ -36053,7 +37199,8 @@ var TaskLifecycleService = class {
|
|
|
36053
37199
|
const resumeKey = this.resumeEventKey(task);
|
|
36054
37200
|
const audit = { eventKey: resumeKey, previousInterruption };
|
|
36055
37201
|
const context = withLifecycleAudit(task.context, "lifecycle_resume_audit", audit);
|
|
36056
|
-
if (input.threadId
|
|
37202
|
+
if (input.threadId) context.thread_id = input.threadId;
|
|
37203
|
+
if (input.runId) context.run_id = input.runId;
|
|
36057
37204
|
const updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
36058
37205
|
input.tenantId,
|
|
36059
37206
|
input.taskId,
|
|
@@ -36150,7 +37297,13 @@ var TaskLifecycleService = class {
|
|
|
36150
37297
|
if (task.status !== "pending") {
|
|
36151
37298
|
return { ...failure2("TASK_STATUS_CONFLICT", "Task cannot start."), transitioned: false };
|
|
36152
37299
|
}
|
|
36153
|
-
const context = {
|
|
37300
|
+
const context = {
|
|
37301
|
+
...task.context ?? {},
|
|
37302
|
+
...input.threadId ? { thread_id: input.threadId } : {},
|
|
37303
|
+
...input.runId ? { run_id: input.runId } : {},
|
|
37304
|
+
...input.callerThreadId ? { caller_thread_id: input.callerThreadId } : {},
|
|
37305
|
+
...input.callerAssistantId ? { caller_assistant_id: input.callerAssistantId } : {}
|
|
37306
|
+
};
|
|
36154
37307
|
let updated;
|
|
36155
37308
|
try {
|
|
36156
37309
|
updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
|
|
@@ -36226,7 +37379,9 @@ var TaskLifecycleService = class {
|
|
|
36226
37379
|
expectedStatuses: ["failed"],
|
|
36227
37380
|
updates: { status: "in_progress", failureReason: null },
|
|
36228
37381
|
summary: "Task retried",
|
|
36229
|
-
detail: { previousStatus: "failed" }
|
|
37382
|
+
detail: { previousStatus: "failed" },
|
|
37383
|
+
// A retry dispatches a new run thread; replace a stale persisted link.
|
|
37384
|
+
replaceThread: true
|
|
36230
37385
|
});
|
|
36231
37386
|
}
|
|
36232
37387
|
/**
|
|
@@ -37202,8 +38357,8 @@ var TaskLifecycleService = class {
|
|
|
37202
38357
|
return { task: existing, parent: parentResult, eventKey, evidence, result, impacts };
|
|
37203
38358
|
}
|
|
37204
38359
|
beliefOwnerSnapshot(task, parent) {
|
|
37205
|
-
const
|
|
37206
|
-
const parsed = parseTaskBeliefState(
|
|
38360
|
+
const owner2 = parent?.ownerType === "agent" ? parent : task;
|
|
38361
|
+
const parsed = parseTaskBeliefState(owner2.description ?? "");
|
|
37207
38362
|
const beliefState = parsed.success ? parsed.state : { entries: [] };
|
|
37208
38363
|
if (parent?.ownerType === "agent") {
|
|
37209
38364
|
return {
|
|
@@ -37712,7 +38867,9 @@ var TaskLifecycleService = class {
|
|
|
37712
38867
|
}
|
|
37713
38868
|
if (!input.expectedStatuses.includes(task.status)) return failure2("TASK_STATUS_CONFLICT", "Task status cannot make this transition.");
|
|
37714
38869
|
const clearedContext = clearInterruptionContext(task.context);
|
|
37715
|
-
const
|
|
38870
|
+
const threadInput = input.threadId && (input.replaceThread || task.context?.thread_id === void 0) ? { thread_id: input.threadId } : {};
|
|
38871
|
+
const runInput = input.runId ? { run_id: input.runId } : {};
|
|
38872
|
+
const withThread = Object.keys(threadInput).length > 0 || Object.keys(runInput).length > 0 ? { ...clearedContext ?? {}, ...threadInput, ...runInput } : clearedContext;
|
|
37716
38873
|
const updates = { ...input.updates, context: withThread };
|
|
37717
38874
|
let updated;
|
|
37718
38875
|
try {
|
|
@@ -37750,6 +38907,31 @@ var TaskLifecycleService = class {
|
|
|
37750
38907
|
statusEventKey(task, status, detail) {
|
|
37751
38908
|
return `task-lifecycle:${task.id}:${status}:${task.updatedAt.toISOString()}:${sha256(detail)}`;
|
|
37752
38909
|
}
|
|
38910
|
+
/**
|
|
38911
|
+
* Writes a lifecycle work-item event, retrying transient store failures.
|
|
38912
|
+
*
|
|
38913
|
+
* @param request Event request passed through to the work-item store.
|
|
38914
|
+
* @returns The persisted or pre-existing work item.
|
|
38915
|
+
* @remarks The write is idempotent by `eventKey`
|
|
38916
|
+
* (`createIfAbsentByEventKey`), so retrying after a transient failure (pool
|
|
38917
|
+
* exhaustion, shutdown, statement timeout, disk IO) is safe. The status CAS has
|
|
38918
|
+
* already committed by this point, and the event key embeds `updatedAt`, so a
|
|
38919
|
+
* lost event cannot be reconstructed later — hence the bounded retry.
|
|
38920
|
+
*/
|
|
38921
|
+
async writeWorkItemWithRetry(request) {
|
|
38922
|
+
let lastError;
|
|
38923
|
+
for (let attempt = 0; attempt < WORK_ITEM_WRITE_ATTEMPTS; attempt += 1) {
|
|
38924
|
+
if (attempt > 0) {
|
|
38925
|
+
await new Promise((resolve4) => setTimeout(resolve4, WORK_ITEM_WRITE_RETRY_DELAYS_MS[attempt - 1]));
|
|
38926
|
+
}
|
|
38927
|
+
try {
|
|
38928
|
+
return await this.deps.workItemStore.createIfAbsentByEventKey(request);
|
|
38929
|
+
} catch (error) {
|
|
38930
|
+
lastError = error;
|
|
38931
|
+
}
|
|
38932
|
+
}
|
|
38933
|
+
throw lastError;
|
|
38934
|
+
}
|
|
37753
38935
|
async writeStatusEvent(task, actor, threadId, action, summary, detail, eventKey) {
|
|
37754
38936
|
const warningCode = `${action.toUpperCase()}_WORK_ITEM_WRITE_FAILED`;
|
|
37755
38937
|
const request = {
|
|
@@ -37765,7 +38947,7 @@ var TaskLifecycleService = class {
|
|
|
37765
38947
|
eventKey
|
|
37766
38948
|
};
|
|
37767
38949
|
try {
|
|
37768
|
-
const item = await this.
|
|
38950
|
+
const item = await this.writeWorkItemWithRetry(request);
|
|
37769
38951
|
if (item.eventKey !== request.eventKey) throw new Error("Canonical lifecycle event key mismatch");
|
|
37770
38952
|
return { eventKey: item.eventKey };
|
|
37771
38953
|
} catch {
|
|
@@ -37896,7 +39078,7 @@ function createTaskLifecycleService(deps) {
|
|
|
37896
39078
|
}
|
|
37897
39079
|
|
|
37898
39080
|
// src/services/TaskExecutionService.ts
|
|
37899
|
-
import { randomUUID as
|
|
39081
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
37900
39082
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
37901
39083
|
import { isExecutionResultEventKey as isExecutionResultEventKey2 } from "@axiom-lattice/protocols";
|
|
37902
39084
|
|
|
@@ -37951,7 +39133,7 @@ function createTaskRunBridge(deps) {
|
|
|
37951
39133
|
return { success: true, task: updated };
|
|
37952
39134
|
},
|
|
37953
39135
|
async beginRun(input) {
|
|
37954
|
-
const { tenantId: tenantId2, actor, threadId } = input;
|
|
39136
|
+
const { tenantId: tenantId2, actor, threadId, runId, callerThreadId, callerAssistantId } = input;
|
|
37955
39137
|
let task = input.task;
|
|
37956
39138
|
const warnings = [];
|
|
37957
39139
|
if (task.status === "pending") {
|
|
@@ -37960,7 +39142,10 @@ function createTaskRunBridge(deps) {
|
|
|
37960
39142
|
tenantId: tenantId2,
|
|
37961
39143
|
taskId: task.id,
|
|
37962
39144
|
actor,
|
|
37963
|
-
threadId
|
|
39145
|
+
...threadId !== void 0 ? { threadId } : {},
|
|
39146
|
+
...runId !== void 0 ? { runId } : {},
|
|
39147
|
+
...callerThreadId ? { callerThreadId } : {},
|
|
39148
|
+
...callerAssistantId ? { callerAssistantId } : {}
|
|
37964
39149
|
});
|
|
37965
39150
|
if (!started.success) {
|
|
37966
39151
|
return {
|
|
@@ -38048,7 +39233,19 @@ function createTaskRunBridge(deps) {
|
|
|
38048
39233
|
error: "Lifecycle transitions only support agent tasks."
|
|
38049
39234
|
};
|
|
38050
39235
|
}
|
|
38051
|
-
const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({
|
|
39236
|
+
const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({
|
|
39237
|
+
tenantId: tenantId2,
|
|
39238
|
+
taskId: task.id,
|
|
39239
|
+
actor,
|
|
39240
|
+
...threadId !== void 0 ? { threadId } : {},
|
|
39241
|
+
...runId !== void 0 ? { runId } : {}
|
|
39242
|
+
}) : await deps.lifecycle.retryTask({
|
|
39243
|
+
tenantId: tenantId2,
|
|
39244
|
+
taskId: task.id,
|
|
39245
|
+
actor,
|
|
39246
|
+
...threadId !== void 0 ? { threadId } : {},
|
|
39247
|
+
...runId !== void 0 ? { runId } : {}
|
|
39248
|
+
});
|
|
38052
39249
|
if (!result.success) {
|
|
38053
39250
|
return {
|
|
38054
39251
|
success: false,
|
|
@@ -38113,6 +39310,132 @@ function createTaskRunBridge(deps) {
|
|
|
38113
39310
|
};
|
|
38114
39311
|
}
|
|
38115
39312
|
|
|
39313
|
+
// src/services/TaskRunRegistry.ts
|
|
39314
|
+
var TaskRunRegistry = class {
|
|
39315
|
+
constructor() {
|
|
39316
|
+
this.live = /* @__PURE__ */ new Set();
|
|
39317
|
+
}
|
|
39318
|
+
/** Marks a task as currently held by a live run. */
|
|
39319
|
+
register(taskId) {
|
|
39320
|
+
this.live.add(taskId);
|
|
39321
|
+
}
|
|
39322
|
+
/** Removes a task once its run has ended. */
|
|
39323
|
+
unregister(taskId) {
|
|
39324
|
+
this.live.delete(taskId);
|
|
39325
|
+
}
|
|
39326
|
+
/** Reports whether a task is currently held by a live run. */
|
|
39327
|
+
isLive(taskId) {
|
|
39328
|
+
return this.live.has(taskId);
|
|
39329
|
+
}
|
|
39330
|
+
/** Returns a snapshot of the live task ids (diagnostics/tests). */
|
|
39331
|
+
snapshot() {
|
|
39332
|
+
return [...this.live];
|
|
39333
|
+
}
|
|
39334
|
+
/** Clears all live entries (tests / process teardown). */
|
|
39335
|
+
clear() {
|
|
39336
|
+
this.live.clear();
|
|
39337
|
+
}
|
|
39338
|
+
};
|
|
39339
|
+
var taskRunRegistry = new TaskRunRegistry();
|
|
39340
|
+
async function safelyLive(probe, task) {
|
|
39341
|
+
try {
|
|
39342
|
+
return await probe(task);
|
|
39343
|
+
} catch {
|
|
39344
|
+
return true;
|
|
39345
|
+
}
|
|
39346
|
+
}
|
|
39347
|
+
async function reconcileStaleTaskRuns(input) {
|
|
39348
|
+
const registry4 = input.registry ?? taskRunRegistry;
|
|
39349
|
+
const converged = [];
|
|
39350
|
+
const convergedTasks = [];
|
|
39351
|
+
for (const task of input.tasks) {
|
|
39352
|
+
if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
|
|
39353
|
+
if (input.isTaskLive && await safelyLive(input.isTaskLive, task)) continue;
|
|
39354
|
+
const result = await input.lifecycle.failTask({
|
|
39355
|
+
tenantId: task.tenantId,
|
|
39356
|
+
taskId: task.id,
|
|
39357
|
+
actor: input.actor,
|
|
39358
|
+
failureReason: "Run is no longer executing this task (no_executor)"
|
|
39359
|
+
});
|
|
39360
|
+
if (result.success) {
|
|
39361
|
+
converged.push(task.id);
|
|
39362
|
+
convergedTasks.push(result.task);
|
|
39363
|
+
}
|
|
39364
|
+
}
|
|
39365
|
+
return { converged, convergedTasks };
|
|
39366
|
+
}
|
|
39367
|
+
async function reconcileTenantTaskRuns(input) {
|
|
39368
|
+
const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
|
|
39369
|
+
const candidates = input.include ? tasks.filter(input.include) : tasks;
|
|
39370
|
+
return reconcileStaleTaskRuns({
|
|
39371
|
+
tasks: candidates,
|
|
39372
|
+
actor: input.actor,
|
|
39373
|
+
lifecycle: input.lifecycle,
|
|
39374
|
+
...input.registry ? { registry: input.registry } : {},
|
|
39375
|
+
...input.isTaskLive ? { isTaskLive: input.isTaskLive } : {}
|
|
39376
|
+
});
|
|
39377
|
+
}
|
|
39378
|
+
async function reconcileAllTenantTaskRuns(input) {
|
|
39379
|
+
const tenants = await input.tenantStore.listTenants();
|
|
39380
|
+
const converged = [];
|
|
39381
|
+
const convergedTasks = [];
|
|
39382
|
+
for (const tenant of tenants) {
|
|
39383
|
+
let result;
|
|
39384
|
+
try {
|
|
39385
|
+
result = await reconcileTenantTaskRuns({
|
|
39386
|
+
tenantId: tenant.id,
|
|
39387
|
+
actor: input.actor,
|
|
39388
|
+
taskStore: input.taskStore,
|
|
39389
|
+
lifecycle: input.lifecycle,
|
|
39390
|
+
...input.registry ? { registry: input.registry } : {},
|
|
39391
|
+
...input.include ? { include: input.include } : {},
|
|
39392
|
+
...input.isTaskLive ? { isTaskLive: input.isTaskLive } : {}
|
|
39393
|
+
});
|
|
39394
|
+
} catch {
|
|
39395
|
+
continue;
|
|
39396
|
+
}
|
|
39397
|
+
converged.push(...result.converged);
|
|
39398
|
+
convergedTasks.push(...result.convergedTasks);
|
|
39399
|
+
}
|
|
39400
|
+
return { converged, convergedTasks };
|
|
39401
|
+
}
|
|
39402
|
+
|
|
39403
|
+
// src/services/taskRunLease.ts
|
|
39404
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
39405
|
+
function taskRunLeaseKey(taskId) {
|
|
39406
|
+
return `task-run:${taskId}`;
|
|
39407
|
+
}
|
|
39408
|
+
async function tryAcquireTaskRun(input) {
|
|
39409
|
+
const key5 = taskRunLeaseKey(input.taskId);
|
|
39410
|
+
const holder = `${input.owner}#${randomUUID10()}`;
|
|
39411
|
+
if (!await input.store.tryAcquire(key5, holder, input.ttlMs)) return null;
|
|
39412
|
+
const heartbeatMs = input.heartbeatMs ?? Math.max(1e3, Math.floor(input.ttlMs / 3));
|
|
39413
|
+
let released = false;
|
|
39414
|
+
let lost = false;
|
|
39415
|
+
const heartbeat = setInterval(() => {
|
|
39416
|
+
void input.store.renew(key5, holder, input.ttlMs).then((renewed) => {
|
|
39417
|
+
if (released || renewed || lost) return;
|
|
39418
|
+
lost = true;
|
|
39419
|
+
try {
|
|
39420
|
+
input.onLost?.();
|
|
39421
|
+
} catch {
|
|
39422
|
+
}
|
|
39423
|
+
}).catch(() => void 0);
|
|
39424
|
+
}, heartbeatMs);
|
|
39425
|
+
heartbeat.unref?.();
|
|
39426
|
+
return {
|
|
39427
|
+
get lost() {
|
|
39428
|
+
return lost;
|
|
39429
|
+
},
|
|
39430
|
+
release: async () => {
|
|
39431
|
+
if (released) return;
|
|
39432
|
+
released = true;
|
|
39433
|
+
clearInterval(heartbeat);
|
|
39434
|
+
await input.store.release(key5, holder).catch(() => void 0);
|
|
39435
|
+
}
|
|
39436
|
+
};
|
|
39437
|
+
}
|
|
39438
|
+
|
|
38116
39439
|
// src/services/ExecutionAuthorityRegistry.ts
|
|
38117
39440
|
var ManagedTaskStartError = class extends Error {
|
|
38118
39441
|
/**
|
|
@@ -38374,276 +39697,23 @@ async function prepareTaskDispatch(deps, input) {
|
|
|
38374
39697
|
agentId: input.agentId,
|
|
38375
39698
|
actor: input.actor,
|
|
38376
39699
|
...input.callerThreadId !== void 0 ? { callerThreadId: input.callerThreadId } : {},
|
|
39700
|
+
...input.callerAssistantId !== void 0 ? { callerAssistantId: input.callerAssistantId } : {},
|
|
38377
39701
|
parent,
|
|
38378
39702
|
completedDependencies
|
|
38379
39703
|
}
|
|
38380
39704
|
};
|
|
38381
39705
|
}
|
|
38382
39706
|
|
|
38383
|
-
// src/
|
|
38384
|
-
|
|
38385
|
-
var
|
|
38386
|
-
|
|
38387
|
-
var arrayIsArray = Array.isArray.bind(Array);
|
|
38388
|
-
var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
|
|
38389
|
-
var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
|
|
38390
|
-
var objectCreate = Object.create.bind(Object);
|
|
38391
|
-
var objectDefineProperty = Object.defineProperty.bind(Object);
|
|
38392
|
-
var objectIs = Object.is.bind(Object);
|
|
38393
|
-
var reflectGet = Reflect.get.bind(Reflect);
|
|
38394
|
-
var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
|
|
38395
|
-
var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
|
|
38396
|
-
var stringifyJson = JSON.stringify.bind(JSON);
|
|
38397
|
-
var numberIsFinite = Number.isFinite.bind(Number);
|
|
38398
|
-
var numberIsNaN = Number.isNaN.bind(Number);
|
|
38399
|
-
var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
|
|
38400
|
-
var mathMax = Math.max.bind(Math);
|
|
38401
|
-
var dateConstructor = Date;
|
|
38402
|
-
var datePrototype = dateConstructor.prototype;
|
|
38403
|
-
var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
|
|
38404
|
-
var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
|
|
38405
|
-
var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
|
|
38406
|
-
var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
|
|
38407
|
-
var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
|
|
38408
|
-
var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
|
|
38409
|
-
var WeakMapConstructor = WeakMap;
|
|
38410
|
-
var utf8Encoder = new TextEncoder();
|
|
38411
|
-
var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
|
|
38412
|
-
var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
|
|
38413
|
-
var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
|
|
38414
|
-
if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
|
|
38415
|
-
var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
|
|
38416
|
-
var JSON_SAFE_MAX_DEPTH = 32;
|
|
38417
|
-
var JSON_SAFE_MAX_NODES = 1e4;
|
|
38418
|
-
var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
|
|
38419
|
-
var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
|
|
38420
|
-
var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
|
|
38421
|
-
var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
|
|
38422
|
-
var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
|
|
38423
|
-
var JsonSafeValueError = class extends Error {
|
|
38424
|
-
/**
|
|
38425
|
-
* Create a bounded normalization error.
|
|
38426
|
-
*
|
|
38427
|
-
* @param code Stable normalization failure code.
|
|
38428
|
-
* @param message Human-readable bounded failure description.
|
|
38429
|
-
*/
|
|
38430
|
-
constructor(code, message) {
|
|
38431
|
-
super(message);
|
|
38432
|
-
objectDefineProperty(this, "name", {
|
|
38433
|
-
value: "JsonSafeValueError",
|
|
38434
|
-
writable: true,
|
|
38435
|
-
configurable: true
|
|
38436
|
-
});
|
|
38437
|
-
objectDefineProperty(this, "code", {
|
|
38438
|
-
value: code,
|
|
38439
|
-
writable: true,
|
|
38440
|
-
configurable: true
|
|
38441
|
-
});
|
|
38442
|
-
}
|
|
38443
|
-
};
|
|
38444
|
-
function fail(code, message) {
|
|
38445
|
-
throw new JsonSafeValueError(code, message);
|
|
38446
|
-
}
|
|
38447
|
-
function propertyAccess(operation, path8) {
|
|
39707
|
+
// src/services/TaskExecutionService.ts
|
|
39708
|
+
import { GraphInterrupt as GraphInterrupt2 } from "@langchain/langgraph";
|
|
39709
|
+
var TASK_RUN_LEASE_TTL_MS = 12e4;
|
|
39710
|
+
function getLeaseStore() {
|
|
38448
39711
|
try {
|
|
38449
|
-
return
|
|
39712
|
+
return storeLatticeManager.getStoreLattice("default", "lease").store;
|
|
38450
39713
|
} catch {
|
|
38451
|
-
|
|
38452
|
-
}
|
|
38453
|
-
}
|
|
38454
|
-
function serializedStringBytes(value) {
|
|
38455
|
-
if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
|
|
38456
|
-
fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
|
|
38457
|
-
}
|
|
38458
|
-
return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
|
|
38459
|
-
}
|
|
38460
|
-
function validatePropertyKey(key5) {
|
|
38461
|
-
if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
|
|
38462
|
-
fail(
|
|
38463
|
-
"MAX_STRING_LENGTH",
|
|
38464
|
-
`JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
|
|
38465
|
-
);
|
|
38466
|
-
}
|
|
38467
|
-
}
|
|
38468
|
-
function chargePropertyKey(state, key5) {
|
|
38469
|
-
state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
|
|
38470
|
-
if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
|
|
38471
|
-
fail(
|
|
38472
|
-
"MAX_PROPERTY_KEY_BYTES",
|
|
38473
|
-
`JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
|
|
38474
|
-
);
|
|
38475
|
-
}
|
|
38476
|
-
}
|
|
38477
|
-
function chargeBytes(state, bytes) {
|
|
38478
|
-
state.serializedBytes += bytes;
|
|
38479
|
-
if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
|
|
38480
|
-
fail(
|
|
38481
|
-
"MAX_SERIALIZED_BYTES",
|
|
38482
|
-
`JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
|
|
38483
|
-
);
|
|
38484
|
-
}
|
|
38485
|
-
}
|
|
38486
|
-
function chargeString(state, value) {
|
|
38487
|
-
chargeBytes(state, serializedStringBytes(value));
|
|
38488
|
-
}
|
|
38489
|
-
function objectPropertyPath(path8, key5) {
|
|
38490
|
-
const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
|
|
38491
|
-
return `${path8}[${stringifyJson(boundedKey)}]`;
|
|
38492
|
-
}
|
|
38493
|
-
function convertJsonValue(value, state, depth, inArray, path8) {
|
|
38494
|
-
state.nodes += 1;
|
|
38495
|
-
if (state.nodes > JSON_SAFE_MAX_NODES) {
|
|
38496
|
-
fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
|
|
38497
|
-
}
|
|
38498
|
-
if (typeof value === "string") {
|
|
38499
|
-
chargeString(state, value);
|
|
38500
|
-
return value;
|
|
38501
|
-
}
|
|
38502
|
-
if (value === null) {
|
|
38503
|
-
chargeBytes(state, 4);
|
|
38504
|
-
return value;
|
|
38505
|
-
}
|
|
38506
|
-
if (typeof value === "boolean") {
|
|
38507
|
-
chargeBytes(state, value ? 4 : 5);
|
|
38508
|
-
return value;
|
|
38509
|
-
}
|
|
38510
|
-
if (typeof value === "number") {
|
|
38511
|
-
const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
|
|
38512
|
-
chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
|
|
38513
|
-
return normalized;
|
|
38514
|
-
}
|
|
38515
|
-
if (typeof value === "bigint") {
|
|
38516
|
-
const normalized = bigintToString(value);
|
|
38517
|
-
chargeString(state, normalized);
|
|
38518
|
-
return normalized;
|
|
38519
|
-
}
|
|
38520
|
-
if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
|
|
38521
|
-
if (inArray) chargeBytes(state, 4);
|
|
38522
|
-
return inArray ? null : void 0;
|
|
38523
|
-
}
|
|
38524
|
-
const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
|
|
38525
|
-
if (isDate) {
|
|
38526
|
-
const time = propertyAccess(() => dateGetTime(value), path8);
|
|
38527
|
-
if (numberIsNaN(time)) {
|
|
38528
|
-
chargeBytes(state, 4);
|
|
38529
|
-
return null;
|
|
38530
|
-
}
|
|
38531
|
-
const normalized = propertyAccess(() => dateToISOString(value), path8);
|
|
38532
|
-
chargeString(state, normalized);
|
|
38533
|
-
return normalized;
|
|
38534
|
-
}
|
|
38535
|
-
if (depth > JSON_SAFE_MAX_DEPTH) {
|
|
38536
|
-
fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
|
|
38537
|
-
}
|
|
38538
|
-
const referenceState = weakMapGet(state.references, value);
|
|
38539
|
-
if (referenceState === "visiting") {
|
|
38540
|
-
chargeString(state, CIRCULAR_VALUE);
|
|
38541
|
-
return CIRCULAR_VALUE;
|
|
38542
|
-
}
|
|
38543
|
-
if (referenceState === "visited") {
|
|
38544
|
-
chargeString(state, REPEATED_VALUE);
|
|
38545
|
-
return REPEATED_VALUE;
|
|
38546
|
-
}
|
|
38547
|
-
weakMapSet(state.references, value, "visiting");
|
|
38548
|
-
if (propertyAccess(() => arrayIsArray(value), path8)) {
|
|
38549
|
-
const arrayValue = value;
|
|
38550
|
-
const length = propertyAccess(
|
|
38551
|
-
() => arrayValue.length,
|
|
38552
|
-
path8
|
|
38553
|
-
);
|
|
38554
|
-
if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
|
|
38555
|
-
fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
|
|
38556
|
-
}
|
|
38557
|
-
if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
|
|
38558
|
-
fail(
|
|
38559
|
-
"COLLECTION_TOO_LARGE",
|
|
38560
|
-
`JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
|
|
38561
|
-
);
|
|
38562
|
-
}
|
|
38563
|
-
chargeBytes(state, 2 + mathMax(0, length - 1));
|
|
38564
|
-
const result2 = arrayFrom({ length }, (_, index) => {
|
|
38565
|
-
const entryPath = `${path8}[${index}]`;
|
|
38566
|
-
const hasEntry = propertyAccess(
|
|
38567
|
-
() => hasOwnProperty(arrayValue, index),
|
|
38568
|
-
entryPath
|
|
38569
|
-
);
|
|
38570
|
-
if (!hasEntry) {
|
|
38571
|
-
chargeBytes(state, 4);
|
|
38572
|
-
return null;
|
|
38573
|
-
}
|
|
38574
|
-
const entry = propertyAccess(() => arrayValue[index], entryPath);
|
|
38575
|
-
return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
|
|
38576
|
-
});
|
|
38577
|
-
objectDefineProperty(result2, "toJSON", {
|
|
38578
|
-
value: void 0,
|
|
38579
|
-
configurable: true,
|
|
38580
|
-
writable: true
|
|
38581
|
-
});
|
|
38582
|
-
weakMapSet(state.references, value, "visited");
|
|
38583
|
-
return result2;
|
|
38584
|
-
}
|
|
38585
|
-
const keys = propertyAccess(() => reflectOwnKeys(value), path8);
|
|
38586
|
-
if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
|
|
38587
|
-
fail(
|
|
38588
|
-
"COLLECTION_TOO_LARGE",
|
|
38589
|
-
`JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
|
|
38590
|
-
);
|
|
38591
|
-
}
|
|
38592
|
-
for (let index = 0; index < keys.length; index += 1) {
|
|
38593
|
-
const key5 = keys[index];
|
|
38594
|
-
if (typeof key5 !== "string") continue;
|
|
38595
|
-
validatePropertyKey(key5);
|
|
38596
|
-
chargePropertyKey(state, key5);
|
|
38597
|
-
}
|
|
38598
|
-
chargeBytes(state, 2);
|
|
38599
|
-
const result = objectCreate(null);
|
|
38600
|
-
let emittedProperties = 0;
|
|
38601
|
-
for (let index = 0; index < keys.length; index += 1) {
|
|
38602
|
-
const key5 = keys[index];
|
|
38603
|
-
const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
|
|
38604
|
-
const descriptor = propertyAccess(
|
|
38605
|
-
() => reflectGetOwnPropertyDescriptor(value, key5),
|
|
38606
|
-
entryPath
|
|
38607
|
-
);
|
|
38608
|
-
if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
|
|
38609
|
-
const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
|
|
38610
|
-
const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
|
|
38611
|
-
if (converted !== void 0) {
|
|
38612
|
-
chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
|
|
38613
|
-
propertyAccess(() => objectDefineProperty(result, key5, {
|
|
38614
|
-
value: converted,
|
|
38615
|
-
enumerable: true,
|
|
38616
|
-
configurable: true,
|
|
38617
|
-
writable: true
|
|
38618
|
-
}), entryPath);
|
|
38619
|
-
emittedProperties += 1;
|
|
38620
|
-
}
|
|
38621
|
-
}
|
|
38622
|
-
weakMapSet(state.references, value, "visited");
|
|
38623
|
-
return result;
|
|
38624
|
-
}
|
|
38625
|
-
function toJsonSafeValue(value) {
|
|
38626
|
-
const state = {
|
|
38627
|
-
nodes: 0,
|
|
38628
|
-
propertyKeyBytes: 0,
|
|
38629
|
-
serializedBytes: 0,
|
|
38630
|
-
references: new WeakMapConstructor()
|
|
38631
|
-
};
|
|
38632
|
-
const converted = convertJsonValue(value, state, 0, false, "$");
|
|
38633
|
-
if (converted === void 0) chargeBytes(state, 4);
|
|
38634
|
-
const result = converted ?? null;
|
|
38635
|
-
const serialized = propertyAccess(() => stringifyJson(result), "$");
|
|
38636
|
-
if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
|
|
38637
|
-
fail(
|
|
38638
|
-
"MAX_SERIALIZED_BYTES",
|
|
38639
|
-
`JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
|
|
38640
|
-
);
|
|
39714
|
+
return void 0;
|
|
38641
39715
|
}
|
|
38642
|
-
return result;
|
|
38643
39716
|
}
|
|
38644
|
-
|
|
38645
|
-
// src/services/TaskExecutionService.ts
|
|
38646
|
-
import { GraphInterrupt as GraphInterrupt2 } from "@langchain/langgraph";
|
|
38647
39717
|
function persistedExecutionObservation(item, attempted) {
|
|
38648
39718
|
const detail = item.detail;
|
|
38649
39719
|
const persistedObservation = toJsonSafeValue(detail?.observation);
|
|
@@ -38690,10 +39760,26 @@ function createTaskExecutionService(deps) {
|
|
|
38690
39760
|
const run = async (plan) => {
|
|
38691
39761
|
const { tenantId: tenantId2, agentId, actor, parent, completedDependencies } = plan;
|
|
38692
39762
|
let task = plan.task;
|
|
38693
|
-
const
|
|
39763
|
+
const storedThreadId = (task.status === "interrupted" || task.status === "failed") && typeof task.context?.thread_id === "string" && task.context.thread_id.trim() !== "" ? task.context.thread_id : void 0;
|
|
39764
|
+
const storedRunId = typeof task.context?.run_id === "string" && task.context.run_id.trim() !== "" ? task.context.run_id : void 0;
|
|
39765
|
+
let reuseCurrentRun = false;
|
|
39766
|
+
if (task.status === "interrupted" && storedThreadId) {
|
|
39767
|
+
const currentKey = storedRunId ? `execution-result:${storedThreadId}:${storedRunId}` : `execution-result:${storedThreadId}`;
|
|
39768
|
+
try {
|
|
39769
|
+
reuseCurrentRun = await deps.workItemStore.findByEventKey(tenantId2, task.id, currentKey) === null;
|
|
39770
|
+
} catch {
|
|
39771
|
+
reuseCurrentRun = false;
|
|
39772
|
+
}
|
|
39773
|
+
}
|
|
38694
39774
|
let threadId;
|
|
39775
|
+
let runId;
|
|
38695
39776
|
try {
|
|
38696
|
-
threadId =
|
|
39777
|
+
threadId = storedThreadId ?? (deps.createThreadId ?? randomUUID11)();
|
|
39778
|
+
if (task.status === "interrupted" && reuseCurrentRun) {
|
|
39779
|
+
runId = storedRunId;
|
|
39780
|
+
} else if (task.status === "interrupted" || task.status === "failed") {
|
|
39781
|
+
runId = (deps.createRunId ?? randomUUID11)();
|
|
39782
|
+
}
|
|
38697
39783
|
} catch (error) {
|
|
38698
39784
|
return {
|
|
38699
39785
|
success: false,
|
|
@@ -38703,7 +39789,7 @@ function createTaskExecutionService(deps) {
|
|
|
38703
39789
|
agentId
|
|
38704
39790
|
};
|
|
38705
39791
|
}
|
|
38706
|
-
const eventKey = `execution-result:${threadId}`;
|
|
39792
|
+
const eventKey = runId ? `execution-result:${threadId}:${runId}` : `execution-result:${threadId}`;
|
|
38707
39793
|
if (!isExecutionResultEventKey2(eventKey)) {
|
|
38708
39794
|
return {
|
|
38709
39795
|
success: false,
|
|
@@ -38737,7 +39823,10 @@ function createTaskExecutionService(deps) {
|
|
|
38737
39823
|
tenantId: tenantId2,
|
|
38738
39824
|
task,
|
|
38739
39825
|
actor,
|
|
38740
|
-
threadId
|
|
39826
|
+
threadId,
|
|
39827
|
+
...runId ? { runId } : {},
|
|
39828
|
+
...plan.callerThreadId ? { callerThreadId: plan.callerThreadId } : {},
|
|
39829
|
+
...plan.callerAssistantId ? { callerAssistantId: plan.callerAssistantId } : {}
|
|
38741
39830
|
});
|
|
38742
39831
|
if (!begun.success) return { ...begun, taskId: task.id };
|
|
38743
39832
|
if (!begun.mutated || !begun.transitioned) {
|
|
@@ -38751,38 +39840,134 @@ function createTaskExecutionService(deps) {
|
|
|
38751
39840
|
task = begun.task;
|
|
38752
39841
|
warnings.push(...begun.warnings);
|
|
38753
39842
|
}
|
|
38754
|
-
|
|
38755
|
-
|
|
38756
|
-
workspaceId: task.workspaceId,
|
|
38757
|
-
projectId: task.projectId,
|
|
38758
|
-
taskId: task.id,
|
|
38759
|
-
agentId,
|
|
38760
|
-
threadId,
|
|
38761
|
-
message: buildWorkerMessage(task, parent, completedDependencies),
|
|
38762
|
-
delegatedTaskId: task.id,
|
|
38763
|
-
taskExecutionRole: "worker"
|
|
38764
|
-
};
|
|
38765
|
-
let observation;
|
|
39843
|
+
taskRunRegistry.register(task.id);
|
|
39844
|
+
let taskRunLease = null;
|
|
38766
39845
|
try {
|
|
38767
|
-
|
|
38768
|
-
|
|
38769
|
-
|
|
39846
|
+
const leaseStore = getLeaseStore();
|
|
39847
|
+
if (leaseStore) {
|
|
39848
|
+
try {
|
|
39849
|
+
taskRunLease = await tryAcquireTaskRun({
|
|
39850
|
+
store: leaseStore,
|
|
39851
|
+
taskId: task.id,
|
|
39852
|
+
owner: getReplicaId(),
|
|
39853
|
+
ttlMs: TASK_RUN_LEASE_TTL_MS
|
|
39854
|
+
});
|
|
39855
|
+
} catch {
|
|
39856
|
+
taskRunLease = null;
|
|
39857
|
+
}
|
|
39858
|
+
}
|
|
39859
|
+
const invocation = {
|
|
39860
|
+
tenantId: tenantId2,
|
|
39861
|
+
workspaceId: task.workspaceId,
|
|
39862
|
+
projectId: task.projectId,
|
|
39863
|
+
taskId: task.id,
|
|
39864
|
+
agentId,
|
|
39865
|
+
threadId,
|
|
39866
|
+
message: buildWorkerMessage(task, parent, completedDependencies),
|
|
39867
|
+
delegatedTaskId: task.id,
|
|
39868
|
+
taskExecutionRole: "worker"
|
|
39869
|
+
};
|
|
39870
|
+
let observation;
|
|
39871
|
+
try {
|
|
39872
|
+
observation = toJsonSafeValue(await deps.invokeAgent(invocation));
|
|
39873
|
+
} catch (error) {
|
|
39874
|
+
if (error instanceof GraphInterrupt2) {
|
|
39875
|
+
try {
|
|
39876
|
+
await bridge.settleRun({
|
|
39877
|
+
tenantId: tenantId2,
|
|
39878
|
+
task,
|
|
39879
|
+
actor,
|
|
39880
|
+
threadId,
|
|
39881
|
+
outcome: { kind: "interrupted", summary: "Awaiting user input" }
|
|
39882
|
+
});
|
|
39883
|
+
} catch {
|
|
39884
|
+
}
|
|
39885
|
+
throw error;
|
|
39886
|
+
}
|
|
39887
|
+
const normalizationError = error instanceof JsonSafeValueError;
|
|
39888
|
+
const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
|
|
39889
|
+
const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
|
|
38770
39890
|
try {
|
|
38771
|
-
await bridge.settleRun({
|
|
39891
|
+
const settled = await bridge.settleRun({
|
|
38772
39892
|
tenantId: tenantId2,
|
|
38773
39893
|
task,
|
|
38774
39894
|
actor,
|
|
38775
39895
|
threadId,
|
|
38776
|
-
outcome: {
|
|
39896
|
+
outcome: {
|
|
39897
|
+
kind: "failed",
|
|
39898
|
+
lifecycleHandled: false,
|
|
39899
|
+
error: message.trim() || "Agent invocation failed"
|
|
39900
|
+
}
|
|
38777
39901
|
});
|
|
39902
|
+
if (!settled.success) {
|
|
39903
|
+
warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
|
|
39904
|
+
}
|
|
38778
39905
|
} catch {
|
|
39906
|
+
warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
|
|
39907
|
+
}
|
|
39908
|
+
const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
|
|
39909
|
+
try {
|
|
39910
|
+
const persisted = await deps.workItemStore.createIfAbsentByEventKey({
|
|
39911
|
+
taskId: task.id,
|
|
39912
|
+
tenantId: tenantId2,
|
|
39913
|
+
workspaceId: task.workspaceId,
|
|
39914
|
+
projectId: task.projectId,
|
|
39915
|
+
action: "execution_result",
|
|
39916
|
+
actor,
|
|
39917
|
+
threadId,
|
|
39918
|
+
summary: normalizationError ? `Agent ${agentId} returned an invalid execution observation` : `Agent ${agentId} invocation failed`,
|
|
39919
|
+
detail: {
|
|
39920
|
+
agentId,
|
|
39921
|
+
threadId,
|
|
39922
|
+
observation: failedObservation,
|
|
39923
|
+
success: false
|
|
39924
|
+
},
|
|
39925
|
+
eventKey
|
|
39926
|
+
});
|
|
39927
|
+
const validated = persistedExecutionObservation(persisted, {
|
|
39928
|
+
tenantId: tenantId2,
|
|
39929
|
+
taskId: task.id,
|
|
39930
|
+
agentId,
|
|
39931
|
+
threadId,
|
|
39932
|
+
eventKey,
|
|
39933
|
+
success: false,
|
|
39934
|
+
observation: failedObservation
|
|
39935
|
+
});
|
|
39936
|
+
if (!validated.matches) {
|
|
39937
|
+
return {
|
|
39938
|
+
success: false,
|
|
39939
|
+
code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
|
|
39940
|
+
error: "The execution result identity is already bound to a different execution payload",
|
|
39941
|
+
...!normalizationError ? { invocationError: message } : {},
|
|
39942
|
+
taskId: task.id,
|
|
39943
|
+
agentId,
|
|
39944
|
+
threadId,
|
|
39945
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
39946
|
+
};
|
|
39947
|
+
}
|
|
39948
|
+
return {
|
|
39949
|
+
success: false,
|
|
39950
|
+
code: failureCode,
|
|
39951
|
+
error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
|
|
39952
|
+
taskId: task.id,
|
|
39953
|
+
agentId,
|
|
39954
|
+
threadId,
|
|
39955
|
+
executionResultId: eventKey,
|
|
39956
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
39957
|
+
};
|
|
39958
|
+
} catch (persistenceError) {
|
|
39959
|
+
return {
|
|
39960
|
+
success: false,
|
|
39961
|
+
code: "EXECUTION_RESULT_WRITE_FAILED",
|
|
39962
|
+
error: errorMessage(persistenceError),
|
|
39963
|
+
...!normalizationError ? { invocationError: message } : {},
|
|
39964
|
+
taskId: task.id,
|
|
39965
|
+
agentId,
|
|
39966
|
+
threadId,
|
|
39967
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
39968
|
+
};
|
|
38779
39969
|
}
|
|
38780
|
-
throw error;
|
|
38781
39970
|
}
|
|
38782
|
-
const normalizationError = error instanceof JsonSafeValueError;
|
|
38783
|
-
const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
|
|
38784
|
-
const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
|
|
38785
|
-
const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
|
|
38786
39971
|
try {
|
|
38787
39972
|
const persisted = await deps.workItemStore.createIfAbsentByEventKey({
|
|
38788
39973
|
taskId: task.id,
|
|
@@ -38792,13 +39977,8 @@ function createTaskExecutionService(deps) {
|
|
|
38792
39977
|
action: "execution_result",
|
|
38793
39978
|
actor,
|
|
38794
39979
|
threadId,
|
|
38795
|
-
summary:
|
|
38796
|
-
detail: {
|
|
38797
|
-
agentId,
|
|
38798
|
-
threadId,
|
|
38799
|
-
observation: failedObservation,
|
|
38800
|
-
success: false
|
|
38801
|
-
},
|
|
39980
|
+
summary: `Agent ${agentId} returned an execution observation`,
|
|
39981
|
+
detail: { agentId, threadId, observation, success: true },
|
|
38802
39982
|
eventKey
|
|
38803
39983
|
});
|
|
38804
39984
|
const validated = persistedExecutionObservation(persisted, {
|
|
@@ -38807,15 +39987,14 @@ function createTaskExecutionService(deps) {
|
|
|
38807
39987
|
agentId,
|
|
38808
39988
|
threadId,
|
|
38809
39989
|
eventKey,
|
|
38810
|
-
success:
|
|
38811
|
-
observation
|
|
39990
|
+
success: true,
|
|
39991
|
+
observation
|
|
38812
39992
|
});
|
|
38813
39993
|
if (!validated.matches) {
|
|
38814
39994
|
return {
|
|
38815
39995
|
success: false,
|
|
38816
39996
|
code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
|
|
38817
39997
|
error: "The execution result identity is already bound to a different execution payload",
|
|
38818
|
-
...!normalizationError ? { invocationError: message } : {},
|
|
38819
39998
|
taskId: task.id,
|
|
38820
39999
|
agentId,
|
|
38821
40000
|
threadId,
|
|
@@ -38823,80 +40002,28 @@ function createTaskExecutionService(deps) {
|
|
|
38823
40002
|
};
|
|
38824
40003
|
}
|
|
38825
40004
|
return {
|
|
38826
|
-
success:
|
|
38827
|
-
code: failureCode,
|
|
38828
|
-
error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
|
|
40005
|
+
success: true,
|
|
38829
40006
|
taskId: task.id,
|
|
38830
40007
|
agentId,
|
|
38831
40008
|
threadId,
|
|
40009
|
+
observation: validated.observation,
|
|
38832
40010
|
executionResultId: eventKey,
|
|
38833
40011
|
...warnings.length > 0 ? { warnings } : {}
|
|
38834
40012
|
};
|
|
38835
|
-
} catch (
|
|
40013
|
+
} catch (error) {
|
|
38836
40014
|
return {
|
|
38837
40015
|
success: false,
|
|
38838
40016
|
code: "EXECUTION_RESULT_WRITE_FAILED",
|
|
38839
|
-
error: errorMessage(
|
|
38840
|
-
...!normalizationError ? { invocationError: message } : {},
|
|
38841
|
-
taskId: task.id,
|
|
38842
|
-
agentId,
|
|
38843
|
-
threadId,
|
|
38844
|
-
...warnings.length > 0 ? { warnings } : {}
|
|
38845
|
-
};
|
|
38846
|
-
}
|
|
38847
|
-
}
|
|
38848
|
-
try {
|
|
38849
|
-
const persisted = await deps.workItemStore.createIfAbsentByEventKey({
|
|
38850
|
-
taskId: task.id,
|
|
38851
|
-
tenantId: tenantId2,
|
|
38852
|
-
workspaceId: task.workspaceId,
|
|
38853
|
-
projectId: task.projectId,
|
|
38854
|
-
action: "execution_result",
|
|
38855
|
-
actor,
|
|
38856
|
-
threadId,
|
|
38857
|
-
summary: `Agent ${agentId} returned an execution observation`,
|
|
38858
|
-
detail: { agentId, threadId, observation, success: true },
|
|
38859
|
-
eventKey
|
|
38860
|
-
});
|
|
38861
|
-
const validated = persistedExecutionObservation(persisted, {
|
|
38862
|
-
tenantId: tenantId2,
|
|
38863
|
-
taskId: task.id,
|
|
38864
|
-
agentId,
|
|
38865
|
-
threadId,
|
|
38866
|
-
eventKey,
|
|
38867
|
-
success: true,
|
|
38868
|
-
observation
|
|
38869
|
-
});
|
|
38870
|
-
if (!validated.matches) {
|
|
38871
|
-
return {
|
|
38872
|
-
success: false,
|
|
38873
|
-
code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
|
|
38874
|
-
error: "The execution result identity is already bound to a different execution payload",
|
|
40017
|
+
error: errorMessage(error),
|
|
38875
40018
|
taskId: task.id,
|
|
38876
40019
|
agentId,
|
|
38877
40020
|
threadId,
|
|
38878
40021
|
...warnings.length > 0 ? { warnings } : {}
|
|
38879
40022
|
};
|
|
38880
40023
|
}
|
|
38881
|
-
|
|
38882
|
-
|
|
38883
|
-
|
|
38884
|
-
agentId,
|
|
38885
|
-
threadId,
|
|
38886
|
-
observation: validated.observation,
|
|
38887
|
-
executionResultId: eventKey,
|
|
38888
|
-
...warnings.length > 0 ? { warnings } : {}
|
|
38889
|
-
};
|
|
38890
|
-
} catch (error) {
|
|
38891
|
-
return {
|
|
38892
|
-
success: false,
|
|
38893
|
-
code: "EXECUTION_RESULT_WRITE_FAILED",
|
|
38894
|
-
error: errorMessage(error),
|
|
38895
|
-
taskId: task.id,
|
|
38896
|
-
agentId,
|
|
38897
|
-
threadId,
|
|
38898
|
-
...warnings.length > 0 ? { warnings } : {}
|
|
38899
|
-
};
|
|
40024
|
+
} finally {
|
|
40025
|
+
taskRunRegistry.unregister(task.id);
|
|
40026
|
+
if (taskRunLease) await taskRunLease.release();
|
|
38900
40027
|
}
|
|
38901
40028
|
};
|
|
38902
40029
|
return {
|
|
@@ -38909,74 +40036,41 @@ function createTaskExecutionService(deps) {
|
|
|
38909
40036
|
};
|
|
38910
40037
|
}
|
|
38911
40038
|
|
|
38912
|
-
// src/services/
|
|
38913
|
-
|
|
38914
|
-
|
|
38915
|
-
|
|
38916
|
-
|
|
38917
|
-
|
|
38918
|
-
|
|
38919
|
-
|
|
38920
|
-
|
|
38921
|
-
|
|
38922
|
-
|
|
38923
|
-
|
|
38924
|
-
|
|
38925
|
-
|
|
38926
|
-
|
|
38927
|
-
|
|
38928
|
-
|
|
38929
|
-
|
|
38930
|
-
snapshot() {
|
|
38931
|
-
return [...this.live];
|
|
38932
|
-
}
|
|
38933
|
-
/** Clears all live entries (tests / process teardown). */
|
|
38934
|
-
clear() {
|
|
38935
|
-
this.live.clear();
|
|
38936
|
-
}
|
|
38937
|
-
};
|
|
38938
|
-
var taskRunRegistry = new TaskRunRegistry();
|
|
38939
|
-
async function reconcileStaleTaskRuns(input) {
|
|
38940
|
-
const registry4 = input.registry ?? taskRunRegistry;
|
|
38941
|
-
const converged = [];
|
|
38942
|
-
for (const task of input.tasks) {
|
|
38943
|
-
if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
|
|
38944
|
-
const result = await input.lifecycle.interruptTask({
|
|
38945
|
-
tenantId: task.tenantId,
|
|
38946
|
-
taskId: task.id,
|
|
38947
|
-
actor: input.actor,
|
|
38948
|
-
type: "missing_input",
|
|
38949
|
-
summary: "Run is no longer executing this task (no_executor)"
|
|
38950
|
-
});
|
|
38951
|
-
if (result.success) converged.push(task.id);
|
|
40039
|
+
// src/services/leadership.ts
|
|
40040
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
40041
|
+
async function runAsLeader(store, name, fn, options = {}) {
|
|
40042
|
+
const key5 = `leader:${name}`;
|
|
40043
|
+
const owner2 = options.owner ?? getReplicaId();
|
|
40044
|
+
const holder = `${owner2}#${randomUUID12()}`;
|
|
40045
|
+
const ttlMs = options.ttlMs ?? 6e4;
|
|
40046
|
+
if (!await store.tryAcquire(key5, holder, ttlMs)) return { ran: false };
|
|
40047
|
+
const heartbeat = setInterval(() => {
|
|
40048
|
+
void store.renew(key5, holder, ttlMs).catch(() => void 0);
|
|
40049
|
+
}, Math.max(1e3, Math.floor(ttlMs / 3)));
|
|
40050
|
+
heartbeat.unref?.();
|
|
40051
|
+
try {
|
|
40052
|
+
const result = await fn();
|
|
40053
|
+
return { ran: true, result };
|
|
40054
|
+
} finally {
|
|
40055
|
+
clearInterval(heartbeat);
|
|
40056
|
+
if (!options.hold) await store.release(key5, holder).catch(() => void 0);
|
|
38952
40057
|
}
|
|
38953
|
-
return { converged };
|
|
38954
40058
|
}
|
|
38955
|
-
|
|
38956
|
-
|
|
38957
|
-
|
|
38958
|
-
|
|
38959
|
-
|
|
38960
|
-
|
|
38961
|
-
|
|
38962
|
-
|
|
38963
|
-
});
|
|
40059
|
+
|
|
40060
|
+
// src/services/pluginCatalogSync.ts
|
|
40061
|
+
var PLUGIN_CATALOG_CHANGED_TOPIC = "plugin-catalog-changed";
|
|
40062
|
+
var outbox;
|
|
40063
|
+
var owner = "unknown";
|
|
40064
|
+
function configurePluginCatalogSync(next) {
|
|
40065
|
+
outbox = next?.outbox;
|
|
40066
|
+
owner = next?.owner ?? "unknown";
|
|
38964
40067
|
}
|
|
38965
|
-
async function
|
|
38966
|
-
|
|
38967
|
-
|
|
38968
|
-
|
|
38969
|
-
|
|
38970
|
-
tenantId: tenant.id,
|
|
38971
|
-
actor: input.actor,
|
|
38972
|
-
taskStore: input.taskStore,
|
|
38973
|
-
lifecycle: input.lifecycle,
|
|
38974
|
-
...input.registry ? { registry: input.registry } : {},
|
|
38975
|
-
...input.include ? { include: input.include } : {}
|
|
38976
|
-
});
|
|
38977
|
-
converged.push(...result.converged);
|
|
40068
|
+
async function publishPluginCatalogChanged(tenantId2) {
|
|
40069
|
+
if (!outbox || !tenantId2) return;
|
|
40070
|
+
try {
|
|
40071
|
+
await outbox.append({ topic: PLUGIN_CATALOG_CHANGED_TOPIC, payload: { tenantId: tenantId2 }, originReplicaId: owner });
|
|
40072
|
+
} catch {
|
|
38978
40073
|
}
|
|
38979
|
-
return { converged };
|
|
38980
40074
|
}
|
|
38981
40075
|
|
|
38982
40076
|
// src/index.ts
|
|
@@ -39121,9 +40215,9 @@ var createLoadSkillsTool = ({ skills, readAll, pluginSkills, pluginSkillOwners }
|
|
|
39121
40215
|
if (!skillName) continue;
|
|
39122
40216
|
if (await isPluginSkillManagedInSandbox(sandbox, skillName)) {
|
|
39123
40217
|
const enabledDefinition = pluginSkills?.[skillName];
|
|
39124
|
-
const
|
|
39125
|
-
const registered =
|
|
39126
|
-
if (!registered || registered.definition !== enabledDefinition || !
|
|
40218
|
+
const owner2 = pluginSkillOwners?.[skillName];
|
|
40219
|
+
const registered = owner2 && enabledDefinition ? PluginRegistry.getSkillForPlugin(owner2, skillName) : void 0;
|
|
40220
|
+
if (!registered || registered.definition !== enabledDefinition || !owner2 || !await isPluginSkillAuthorizedInSandbox(sandbox, skillName, owner2) || await getPluginSkillManifestVersion(sandbox, skillName) !== enabledDefinition.version) {
|
|
39127
40221
|
continue;
|
|
39128
40222
|
}
|
|
39129
40223
|
}
|
|
@@ -39149,8 +40243,8 @@ var createLoadSkillsTool = ({ skills, readAll, pluginSkills, pluginSkillOwners }
|
|
|
39149
40243
|
const seenNames = new Set(filteredSkills.map((skill) => skill.name));
|
|
39150
40244
|
try {
|
|
39151
40245
|
for (const [name, definition] of Object.entries(pluginSkills ?? {})) {
|
|
39152
|
-
const
|
|
39153
|
-
const registered =
|
|
40246
|
+
const owner2 = pluginSkillOwners?.[name];
|
|
40247
|
+
const registered = owner2 ? PluginRegistry.getSkillForPlugin(owner2, name) : void 0;
|
|
39154
40248
|
if (!registered || registered.definition !== definition) continue;
|
|
39155
40249
|
const { meta } = parseSkillFrontmatter(definition.content);
|
|
39156
40250
|
if (!meta.name || !meta.description || seenNames.has(meta.name)) continue;
|
|
@@ -39187,24 +40281,24 @@ import z54 from "zod";
|
|
|
39187
40281
|
import { tool as tool48 } from "langchain";
|
|
39188
40282
|
|
|
39189
40283
|
// src/sandbox_plugin/pluginSkillResolution.ts
|
|
39190
|
-
async function resolveTenantPluginSkill(tenantId2,
|
|
40284
|
+
async function resolveTenantPluginSkill(tenantId2, owner2, skillName) {
|
|
39191
40285
|
try {
|
|
39192
40286
|
const { plugins } = await getSandboxPluginCatalog().ensureLoaded(tenantId2);
|
|
39193
|
-
const plugin = plugins.find((candidate) => candidate.meta.type ===
|
|
40287
|
+
const plugin = plugins.find((candidate) => candidate.meta.type === owner2);
|
|
39194
40288
|
return plugin?.skills?.[skillName];
|
|
39195
40289
|
} catch {
|
|
39196
40290
|
return void 0;
|
|
39197
40291
|
}
|
|
39198
40292
|
}
|
|
39199
|
-
async function resolveEnabledPluginSkill(
|
|
39200
|
-
if (!
|
|
39201
|
-
const registered = PluginRegistry.getSkillForPlugin(
|
|
39202
|
-
if (registered && registered.pluginType ===
|
|
39203
|
-
return { pluginType:
|
|
40293
|
+
async function resolveEnabledPluginSkill(owner2, skillName, enabledDefinition, tenantId2) {
|
|
40294
|
+
if (!owner2 || !enabledDefinition) return void 0;
|
|
40295
|
+
const registered = PluginRegistry.getSkillForPlugin(owner2, skillName);
|
|
40296
|
+
if (registered && registered.pluginType === owner2 && registered.definition === enabledDefinition) {
|
|
40297
|
+
return { pluginType: owner2, definition: enabledDefinition };
|
|
39204
40298
|
}
|
|
39205
40299
|
if (!tenantId2) return void 0;
|
|
39206
|
-
const tenantDefinition = await resolveTenantPluginSkill(tenantId2,
|
|
39207
|
-
return tenantDefinition ? { pluginType:
|
|
40300
|
+
const tenantDefinition = await resolveTenantPluginSkill(tenantId2, owner2, skillName);
|
|
40301
|
+
return tenantDefinition ? { pluginType: owner2, definition: tenantDefinition } : void 0;
|
|
39208
40302
|
}
|
|
39209
40303
|
|
|
39210
40304
|
// src/tool_lattice/skill/load_skill_content.ts
|
|
@@ -39266,10 +40360,10 @@ var createLoadSkillContentTool = (pluginSkills, pluginSkillOwnersOrStaticSelecti
|
|
|
39266
40360
|
return result2;
|
|
39267
40361
|
}
|
|
39268
40362
|
const enabledDefinition = pluginSkills?.[input.skill_name];
|
|
39269
|
-
const
|
|
40363
|
+
const owner2 = pluginSkillOwners?.[input.skill_name];
|
|
39270
40364
|
const runConfig = _exe_config?.configurable?.runConfig || {};
|
|
39271
40365
|
const pluginSkill = await resolveEnabledPluginSkill(
|
|
39272
|
-
|
|
40366
|
+
owner2,
|
|
39273
40367
|
input.skill_name,
|
|
39274
40368
|
enabledDefinition,
|
|
39275
40369
|
runConfig.tenantId
|
|
@@ -39376,9 +40470,9 @@ var createLoadSkillResourceTool = (pluginSkills, pluginSkillOwners) => {
|
|
|
39376
40470
|
validateRelativePath(input.resource_path, "resource");
|
|
39377
40471
|
const sandbox = await getSandboxFromExeConfig3(_exe_config);
|
|
39378
40472
|
const definition = pluginSkills?.[input.skill_name];
|
|
39379
|
-
const
|
|
40473
|
+
const owner2 = pluginSkillOwners?.[input.skill_name];
|
|
39380
40474
|
const tenantId2 = _exe_config?.configurable?.runConfig?.tenantId;
|
|
39381
|
-
const resolved = await resolveEnabledPluginSkill(
|
|
40475
|
+
const resolved = await resolveEnabledPluginSkill(owner2, input.skill_name, definition, tenantId2);
|
|
39382
40476
|
if (definition) {
|
|
39383
40477
|
if (!resolved || !resolved.definition.resources?.[input.resource_path]) {
|
|
39384
40478
|
return `Resource "${input.resource_path}" not found for skill "${input.skill_name}".`;
|
|
@@ -41178,61 +42272,28 @@ var widgetPlugin = {
|
|
|
41178
42272
|
import { createMiddleware as createMiddleware23, tool as tool64 } from "langchain";
|
|
41179
42273
|
import { z as z70 } from "zod";
|
|
41180
42274
|
import { GraphInterrupt as GraphInterrupt3, interrupt as interrupt4 } from "@langchain/langgraph";
|
|
42275
|
+
import { resolveRunScope as resolveRunScope2 } from "@axiom-lattice/protocols";
|
|
41181
42276
|
|
|
41182
|
-
// src/
|
|
41183
|
-
|
|
41184
|
-
function
|
|
41185
|
-
|
|
41186
|
-
|
|
41187
|
-
|
|
42277
|
+
// src/services/taskWorkerRunConfig.ts
|
|
42278
|
+
import { firstNonEmptyString, resolveRunScope } from "@axiom-lattice/protocols";
|
|
42279
|
+
function resolveWorkerRunScope(input) {
|
|
42280
|
+
const caller = resolveRunScope(input.runConfig);
|
|
42281
|
+
return {
|
|
42282
|
+
workspaceId: firstNonEmptyString(input.invocation.workspaceId) ?? caller.workspaceId,
|
|
42283
|
+
projectId: firstNonEmptyString(input.invocation.projectId) ?? caller.projectId
|
|
42284
|
+
};
|
|
41188
42285
|
}
|
|
41189
|
-
function
|
|
41190
|
-
|
|
41191
|
-
if (
|
|
41192
|
-
|
|
41193
|
-
|
|
41194
|
-
seen.add(value);
|
|
41195
|
-
try {
|
|
41196
|
-
if (value instanceof Date) return value.toISOString();
|
|
41197
|
-
if (Array.isArray(value)) {
|
|
41198
|
-
const limit2 = Math.min(value.length, maxEntries);
|
|
41199
|
-
const output2 = [];
|
|
41200
|
-
for (let index = 0; index < limit2; index += 1) {
|
|
41201
|
-
output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
|
|
41202
|
-
}
|
|
41203
|
-
if (value.length > limit2) output2.push("[truncated:entries]");
|
|
41204
|
-
return output2;
|
|
41205
|
-
}
|
|
41206
|
-
const record = value;
|
|
41207
|
-
const output = {};
|
|
41208
|
-
const keys = Object.keys(record);
|
|
41209
|
-
const limit = Math.min(keys.length, maxEntries);
|
|
41210
|
-
for (let index = 0; index < limit; index += 1) {
|
|
41211
|
-
const key5 = keys[index];
|
|
41212
|
-
output[truncateString(key5, maxStringLength)] = truncateValue(
|
|
41213
|
-
record[key5],
|
|
41214
|
-
depth + 1,
|
|
41215
|
-
maxDepth,
|
|
41216
|
-
maxEntries,
|
|
41217
|
-
maxStringLength,
|
|
41218
|
-
seen
|
|
41219
|
-
);
|
|
41220
|
-
}
|
|
41221
|
-
if (keys.length > limit) output["[truncated]"] = true;
|
|
41222
|
-
return output;
|
|
41223
|
-
} finally {
|
|
41224
|
-
seen.delete(value);
|
|
42286
|
+
function applyWorkerRunScope(runConfig, scope) {
|
|
42287
|
+
const next = { ...runConfig };
|
|
42288
|
+
if (scope.workspaceId !== void 0) {
|
|
42289
|
+
next.workspaceId = scope.workspaceId;
|
|
42290
|
+
next["x-workspace-id"] = scope.workspaceId;
|
|
41225
42291
|
}
|
|
41226
|
-
|
|
41227
|
-
|
|
41228
|
-
|
|
41229
|
-
|
|
41230
|
-
|
|
41231
|
-
options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
|
|
41232
|
-
options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
|
|
41233
|
-
options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
|
|
41234
|
-
/* @__PURE__ */ new WeakSet()
|
|
41235
|
-
);
|
|
42292
|
+
if (scope.projectId !== void 0) {
|
|
42293
|
+
next.projectId = scope.projectId;
|
|
42294
|
+
next["x-project-id"] = scope.projectId;
|
|
42295
|
+
}
|
|
42296
|
+
return next;
|
|
41236
42297
|
}
|
|
41237
42298
|
|
|
41238
42299
|
// src/middlewares/taskMiddleware.ts
|
|
@@ -41643,9 +42704,9 @@ async function renderAvailableExecutors(rc, tenantId2) {
|
|
|
41643
42704
|
const governed = authority.kind === "projectRoom" || authority.kind === "projectTask";
|
|
41644
42705
|
const projectId = governed ? (authority.trusted.projectTask ?? authority.trusted.projectRoom)?.projectId : void 0;
|
|
41645
42706
|
const cacheKey = `${tenantId2}:${governed ? `project:${projectId ?? ""}` : "ordinary"}`;
|
|
41646
|
-
const
|
|
42707
|
+
const cached2 = executorCache.get(cacheKey);
|
|
41647
42708
|
const now = Date.now();
|
|
41648
|
-
if (
|
|
42709
|
+
if (cached2 && now - cached2.at < EXECUTOR_CACHE_TTL_MS) return cached2.text;
|
|
41649
42710
|
const lines = [];
|
|
41650
42711
|
try {
|
|
41651
42712
|
if (governed && projectId) {
|
|
@@ -42246,8 +43307,9 @@ function createTaskMiddleware(options = {}) {
|
|
|
42246
43307
|
const trustedProject = authority.kind === "projectRoom" || authority.kind === "projectTask" ? authority.trusted : void 0;
|
|
42247
43308
|
const trustedScope = trustedProject?.projectTask ?? trustedProject?.projectRoom;
|
|
42248
43309
|
const tenantId2 = trustedScope?.tenantId ?? (rc.tenantId || "default");
|
|
42249
|
-
const
|
|
42250
|
-
const
|
|
43310
|
+
const runScope = resolveRunScope2(rc);
|
|
43311
|
+
const workspaceId = trustedScope?.workspaceId ?? runScope.workspaceId;
|
|
43312
|
+
const projectId = trustedScope?.projectId ?? runScope.projectId;
|
|
42251
43313
|
const revalidateCaller = async () => {
|
|
42252
43314
|
if (!trustedProject || trustedRosterExempt(trustedProject)) return void 0;
|
|
42253
43315
|
try {
|
|
@@ -43476,15 +44538,16 @@ function createTaskMiddleware(options = {}) {
|
|
|
43476
44538
|
assistant_id: invocation.agentId,
|
|
43477
44539
|
thread_id: invocation.threadId,
|
|
43478
44540
|
input: { message: invocation.message },
|
|
43479
|
-
runConfig:
|
|
43480
|
-
|
|
43481
|
-
|
|
43482
|
-
|
|
43483
|
-
|
|
43484
|
-
|
|
43485
|
-
|
|
43486
|
-
|
|
43487
|
-
|
|
44541
|
+
runConfig: applyWorkerRunScope(
|
|
44542
|
+
{
|
|
44543
|
+
...rc,
|
|
44544
|
+
assistant_id: invocation.agentId,
|
|
44545
|
+
thread_id: invocation.threadId,
|
|
44546
|
+
taskId: invocation.taskId,
|
|
44547
|
+
tenantId: invocation.tenantId
|
|
44548
|
+
},
|
|
44549
|
+
resolveWorkerRunScope({ invocation, runConfig: rc })
|
|
44550
|
+
)
|
|
43488
44551
|
});
|
|
43489
44552
|
const finalState = workerResult?.finalState;
|
|
43490
44553
|
return boundedWorkerObservation(finalState, void 0);
|
|
@@ -43499,7 +44562,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
43499
44562
|
agentId,
|
|
43500
44563
|
actor,
|
|
43501
44564
|
callerThreadId: rc.thread_id,
|
|
43502
|
-
...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
|
|
44565
|
+
...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : rc.assistant_id ? { callerAssistantId: rc.assistant_id } : {}
|
|
43503
44566
|
}));
|
|
43504
44567
|
};
|
|
43505
44568
|
return createMiddleware23({
|
|
@@ -43559,7 +44622,14 @@ function createTaskMiddleware(options = {}) {
|
|
|
43559
44622
|
task,
|
|
43560
44623
|
actor: getRuntimeActor2(rc) ?? "system",
|
|
43561
44624
|
...threadId ? { threadId } : {},
|
|
43562
|
-
|
|
44625
|
+
// A run that ended without its own lifecycle transition is a mechanical
|
|
44626
|
+
// failure, NOT HITL. Human-in-the-loop pauses arrive as GraphInterrupt
|
|
44627
|
+
// and never reach afterAgent.
|
|
44628
|
+
outcome: {
|
|
44629
|
+
kind: "failed",
|
|
44630
|
+
lifecycleHandled: false,
|
|
44631
|
+
error: "Run ended without a task lifecycle transition"
|
|
44632
|
+
}
|
|
43563
44633
|
});
|
|
43564
44634
|
}
|
|
43565
44635
|
taskRunRegistry.unregister(taskId);
|
|
@@ -45922,6 +46992,7 @@ var sandboxPluginsPlugin = {
|
|
|
45922
46992
|
}
|
|
45923
46993
|
case "reload": {
|
|
45924
46994
|
const loaded = await catalog2.reload(tenantId2);
|
|
46995
|
+
void publishPluginCatalogChanged(tenantId2);
|
|
45925
46996
|
return JSON.stringify({ reloaded: true, plugins: loaded.plugins.length, diagnostics: loaded.diagnostics });
|
|
45926
46997
|
}
|
|
45927
46998
|
case "create":
|
|
@@ -45941,12 +47012,14 @@ var sandboxPluginsPlugin = {
|
|
|
45941
47012
|
if (!check.manifest) return JSON.stringify({ written: false, diagnostics: check.diagnostics });
|
|
45942
47013
|
await catalog2.writePlugin(tenantId2, input.type, input.manifest, handlers);
|
|
45943
47014
|
const loaded = await catalog2.reload(tenantId2);
|
|
47015
|
+
void publishPluginCatalogChanged(tenantId2);
|
|
45944
47016
|
return JSON.stringify({ written: true, diagnostics: loaded.diagnostics, hash: loaded.hash });
|
|
45945
47017
|
}
|
|
45946
47018
|
case "delete": {
|
|
45947
47019
|
if (!input.type) return "type is required";
|
|
45948
47020
|
await catalog2.deletePlugin(tenantId2, input.type);
|
|
45949
47021
|
await catalog2.reload(tenantId2);
|
|
47022
|
+
void publishPluginCatalogChanged(tenantId2);
|
|
45950
47023
|
return JSON.stringify({ deleted: true });
|
|
45951
47024
|
}
|
|
45952
47025
|
case "validate": {
|
|
@@ -46058,6 +47131,26 @@ function registerBuiltinPlugins() {
|
|
|
46058
47131
|
}
|
|
46059
47132
|
}
|
|
46060
47133
|
|
|
47134
|
+
// src/sandbox_plugin/provisionOpenClient.ts
|
|
47135
|
+
import { readFileSync } from "fs";
|
|
47136
|
+
var SDK_ROOT = "/root/.agents/sdk";
|
|
47137
|
+
var CLIENT_DIR = `${SDK_ROOT}/open-mcp-client`;
|
|
47138
|
+
var MANIFEST_PATH2 = `${SDK_ROOT}/.open-client-manifest.json`;
|
|
47139
|
+
async function provisionSandboxOpenClient(sandbox, bundle) {
|
|
47140
|
+
await sandbox.file.createDirectory(SDK_ROOT);
|
|
47141
|
+
await sandbox.file.createDirectory(CLIENT_DIR);
|
|
47142
|
+
await sandbox.file.writeFile(`${CLIENT_DIR}/index.js`, bundle.indexJs);
|
|
47143
|
+
await sandbox.file.writeFile(`${CLIENT_DIR}/cli.js`, bundle.cliJs);
|
|
47144
|
+
await sandbox.file.writeFile(MANIFEST_PATH2, JSON.stringify({ version: bundle.version }));
|
|
47145
|
+
}
|
|
47146
|
+
function buildBundleFromDist(distDir, version) {
|
|
47147
|
+
return {
|
|
47148
|
+
indexJs: readFileSync(`${distDir}/index.js`, "utf8"),
|
|
47149
|
+
cliJs: readFileSync(`${distDir}/cli.js`, "utf8"),
|
|
47150
|
+
version
|
|
47151
|
+
};
|
|
47152
|
+
}
|
|
47153
|
+
|
|
46061
47154
|
// src/personal_assistant/PersonalAssistantConfig.ts
|
|
46062
47155
|
function deepClone(obj) {
|
|
46063
47156
|
return JSON.parse(JSON.stringify(obj));
|
|
@@ -46519,10 +47612,12 @@ export {
|
|
|
46519
47612
|
InMemoryChunkBuffer,
|
|
46520
47613
|
InMemoryCollectionStore,
|
|
46521
47614
|
InMemoryDatabaseConfigStore,
|
|
47615
|
+
InMemoryLeaseStore,
|
|
46522
47616
|
InMemoryMailboxStore,
|
|
46523
47617
|
InMemoryMenuStore,
|
|
46524
47618
|
InMemoryModelProviderStore,
|
|
46525
47619
|
InMemoryOpenAuditStore,
|
|
47620
|
+
InMemoryOutboxStore,
|
|
46526
47621
|
InMemoryProjectBotMembershipStore,
|
|
46527
47622
|
InMemoryProjectMembershipStore,
|
|
46528
47623
|
InMemoryProjectRoomCoordinator,
|
|
@@ -46542,6 +47637,7 @@ export {
|
|
|
46542
47637
|
LatticeEval,
|
|
46543
47638
|
LatticeEvalProject,
|
|
46544
47639
|
LatticeEvalSuite,
|
|
47640
|
+
LeaseAcquisitionTimeoutError,
|
|
46545
47641
|
LocalSandboxInstance,
|
|
46546
47642
|
LocalSandboxProvider,
|
|
46547
47643
|
LoggerLatticeManager,
|
|
@@ -46564,7 +47660,10 @@ export {
|
|
|
46564
47660
|
MicrosandboxServiceClient,
|
|
46565
47661
|
ModelLatticeManager,
|
|
46566
47662
|
MysqlDatabase,
|
|
47663
|
+
OutboxPoller,
|
|
46567
47664
|
PACK_DIRECTORY_TIMEOUT_SECONDS,
|
|
47665
|
+
PLATFORM_SECRET_ENV_VARS,
|
|
47666
|
+
PLUGIN_CATALOG_CHANGED_TOPIC,
|
|
46568
47667
|
PersonalAssistantConfig,
|
|
46569
47668
|
PinoLoggerClient,
|
|
46570
47669
|
PluginRegistry,
|
|
@@ -46585,6 +47684,8 @@ export {
|
|
|
46585
47684
|
RepeatedToolCallError,
|
|
46586
47685
|
RoomAgentMessageService,
|
|
46587
47686
|
SAFE_PATH_COMPONENT,
|
|
47687
|
+
SANDBOX_OPEN_GATEWAY_URL_ENV,
|
|
47688
|
+
SANDBOX_OPEN_TOKEN_ENV,
|
|
46588
47689
|
STTModelLattice,
|
|
46589
47690
|
STTModelLatticeManager,
|
|
46590
47691
|
SandboxFilesystem,
|
|
@@ -46625,11 +47726,13 @@ export {
|
|
|
46625
47726
|
appendReconciliationWarning,
|
|
46626
47727
|
appendUiFence,
|
|
46627
47728
|
assertSafeUpstreamUrl,
|
|
47729
|
+
buildBundleFromDist,
|
|
46628
47730
|
buildGrepResultsDict,
|
|
46629
47731
|
buildInput,
|
|
46630
47732
|
buildNamedVolumeName,
|
|
46631
47733
|
buildRemotePackDirectoryCommand,
|
|
46632
47734
|
buildSandboxMetadataEnv,
|
|
47735
|
+
buildSandboxOpenEnv,
|
|
46633
47736
|
buildSkillFile,
|
|
46634
47737
|
buildStateAnnotation,
|
|
46635
47738
|
buildTableName,
|
|
@@ -46638,11 +47741,14 @@ export {
|
|
|
46638
47741
|
checkEmptyContent,
|
|
46639
47742
|
clearEncryptionKeyCache,
|
|
46640
47743
|
clearEvalRunService,
|
|
47744
|
+
clearSandboxOpenCredentialProviderForTests,
|
|
46641
47745
|
collectionLatticeManager,
|
|
46642
47746
|
compileInternal,
|
|
46643
47747
|
compileSandboxPlugin,
|
|
46644
47748
|
compileWorkflow,
|
|
46645
47749
|
computeSandboxName,
|
|
47750
|
+
configureCoordinationLeaseStore,
|
|
47751
|
+
configurePluginCatalogSync,
|
|
46646
47752
|
configureStores,
|
|
46647
47753
|
connectAllChannels,
|
|
46648
47754
|
convertToConnection,
|
|
@@ -46674,6 +47780,7 @@ export {
|
|
|
46674
47780
|
createSandboxResolver,
|
|
46675
47781
|
createSchedulerMiddleware,
|
|
46676
47782
|
createSharePayload,
|
|
47783
|
+
createShellExecTool,
|
|
46677
47784
|
createTaskExecutionService,
|
|
46678
47785
|
createTaskLifecycleService,
|
|
46679
47786
|
createTaskMiddleware,
|
|
@@ -46708,6 +47815,7 @@ export {
|
|
|
46708
47815
|
generateDirectHumanProjectId,
|
|
46709
47816
|
generateToken,
|
|
46710
47817
|
getAgentClient,
|
|
47818
|
+
getAgentClientAsync,
|
|
46711
47819
|
getAgentConfig,
|
|
46712
47820
|
getAllAgentConfigs,
|
|
46713
47821
|
getAllBuiltInSkillMetas,
|
|
@@ -46719,6 +47827,7 @@ export {
|
|
|
46719
47827
|
getCheckpointSaver,
|
|
46720
47828
|
getChunkBuffer,
|
|
46721
47829
|
getCollectionEntryCount,
|
|
47830
|
+
getCoordinationLeaseStore,
|
|
46722
47831
|
getEmbeddingsClient,
|
|
46723
47832
|
getEmbeddingsLattice,
|
|
46724
47833
|
getEncryptionKey,
|
|
@@ -46730,15 +47839,18 @@ export {
|
|
|
46730
47839
|
getOrCreateCollectionVectorStore,
|
|
46731
47840
|
getPluginSkillManifestVersion,
|
|
46732
47841
|
getQueueLattice,
|
|
47842
|
+
getReplicaId,
|
|
46733
47843
|
getRuntimeCapabilityConfig,
|
|
46734
47844
|
getRuntimeSkillSelection,
|
|
46735
47845
|
getSTTClient,
|
|
46736
47846
|
getSTTClientWithTenant,
|
|
46737
47847
|
getSTTModelLattice,
|
|
46738
47848
|
getSandBoxManager,
|
|
47849
|
+
getSandboxOpenCredential,
|
|
46739
47850
|
getSandboxPluginCatalog,
|
|
46740
47851
|
getScheduleLattice,
|
|
46741
47852
|
getStoreLattice,
|
|
47853
|
+
getThreadRunOwner,
|
|
46742
47854
|
getToolClient,
|
|
46743
47855
|
getToolClientWithTenant,
|
|
46744
47856
|
getToolDefinition,
|
|
@@ -46792,6 +47904,8 @@ export {
|
|
|
46792
47904
|
projectMutationMutex,
|
|
46793
47905
|
projectRoomPlugin,
|
|
46794
47906
|
projectTaskAdmissionNotifier,
|
|
47907
|
+
provisionSandboxOpenClient,
|
|
47908
|
+
publishPluginCatalogChanged,
|
|
46795
47909
|
queueLatticeManager,
|
|
46796
47910
|
readLoopBreakerConfig,
|
|
46797
47911
|
reconcileAllTenantTaskRuns,
|
|
@@ -46810,6 +47924,7 @@ export {
|
|
|
46810
47924
|
registerModelLatticeForTenant,
|
|
46811
47925
|
registerQueueLattice,
|
|
46812
47926
|
registerSTTModelLattice,
|
|
47927
|
+
registerSandboxOpenCredentialProvider,
|
|
46813
47928
|
registerSandboxProviderType,
|
|
46814
47929
|
registerScheduleLattice,
|
|
46815
47930
|
registerStoreLattice,
|
|
@@ -46820,6 +47935,7 @@ export {
|
|
|
46820
47935
|
registerWorkflowRun,
|
|
46821
47936
|
removeCollectionVectorStore,
|
|
46822
47937
|
renderTemplate,
|
|
47938
|
+
resetReplicaIdForTests,
|
|
46823
47939
|
resolveEnabledPluginSkill,
|
|
46824
47940
|
resolveJudgeModelKey,
|
|
46825
47941
|
resolvePath,
|
|
@@ -46827,6 +47943,7 @@ export {
|
|
|
46827
47943
|
resolveSandboxPluginConnections,
|
|
46828
47944
|
resolveTenantPluginSkill,
|
|
46829
47945
|
roomCoordinatorConfig,
|
|
47946
|
+
runAsLeader,
|
|
46830
47947
|
runRemotePackDirectory,
|
|
46831
47948
|
safeTaskResponseId,
|
|
46832
47949
|
sandboxLatticeManager,
|
|
@@ -46845,11 +47962,15 @@ export {
|
|
|
46845
47962
|
storeLatticeManager,
|
|
46846
47963
|
sttModelLatticeManager,
|
|
46847
47964
|
taskLifecycleNotifier,
|
|
47965
|
+
taskRunLeaseKey,
|
|
46848
47966
|
taskRunRegistry,
|
|
47967
|
+
threadRunLeaseKey,
|
|
46849
47968
|
toJsonSchema,
|
|
46850
47969
|
toSafeStateExpr,
|
|
46851
47970
|
toolLatticeManager,
|
|
46852
47971
|
truncateIfTooLong,
|
|
47972
|
+
tryAcquireTaskRun,
|
|
47973
|
+
tryAcquireThreadRun,
|
|
46853
47974
|
unregisterTeammateAgent,
|
|
46854
47975
|
unregisterWorkflowRun,
|
|
46855
47976
|
updateFileData,
|
|
@@ -46865,6 +47986,7 @@ export {
|
|
|
46865
47986
|
validateToolInput,
|
|
46866
47987
|
vectorStoreLatticeManager,
|
|
46867
47988
|
vectorStoreProviderManager,
|
|
47989
|
+
withLease,
|
|
46868
47990
|
withTimeout,
|
|
46869
47991
|
wrapMcpToolWithUi
|
|
46870
47992
|
};
|