@axiom-lattice/core 6.3.2 → 6.4.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 +883 -8
- package/dist/index.d.ts +883 -8
- package/dist/index.js +1722 -131
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1696 -129
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1621,6 +1621,7 @@ __export(index_exports, {
|
|
|
1621
1621
|
CapabilityBundleValidationError: () => CapabilityBundleValidationError,
|
|
1622
1622
|
CapabilityToolNameConflictError: () => CapabilityToolNameConflictError,
|
|
1623
1623
|
CapabilityToolRegistry: () => CapabilityToolRegistry,
|
|
1624
|
+
ChannelConnectionLeader: () => ChannelConnectionLeader,
|
|
1624
1625
|
ChunkBuffer: () => ChunkBuffer,
|
|
1625
1626
|
ChunkBufferLatticeManager: () => ChunkBufferLatticeManager,
|
|
1626
1627
|
CollectionLatticeManager: () => CollectionLatticeManager,
|
|
@@ -1632,7 +1633,9 @@ __export(index_exports, {
|
|
|
1632
1633
|
DEFAULT_CALIBRATION_PROBES: () => DEFAULT_CALIBRATION_PROBES,
|
|
1633
1634
|
DEFAULT_CONNECT_TIMEOUT_MS: () => DEFAULT_CONNECT_TIMEOUT_MS,
|
|
1634
1635
|
DEFAULT_DELAY_MS: () => DEFAULT_DELAY_MS,
|
|
1636
|
+
DEFAULT_HANDLER_TIMEOUT_MS: () => DEFAULT_HANDLER_TIMEOUT_MS,
|
|
1635
1637
|
DEFAULT_MAX_ATTEMPTS: () => DEFAULT_MAX_ATTEMPTS,
|
|
1638
|
+
DEFAULT_RESIDENT_INVOKE_TIMEOUT_MS: () => DEFAULT_RESIDENT_INVOKE_TIMEOUT_MS,
|
|
1636
1639
|
DaytonaInstance: () => DaytonaInstance,
|
|
1637
1640
|
DaytonaProvider: () => DaytonaProvider,
|
|
1638
1641
|
DefaultScheduleClient: () => DefaultScheduleClient,
|
|
@@ -1650,6 +1653,7 @@ __export(index_exports, {
|
|
|
1650
1653
|
HEALTH_CHECK_INTERVAL_MS: () => HEALTH_CHECK_INTERVAL_MS,
|
|
1651
1654
|
HEALTH_CHECK_TIMEOUT_MS: () => HEALTH_CHECK_TIMEOUT_MS,
|
|
1652
1655
|
HumanMessage: () => import_messages9.HumanMessage,
|
|
1656
|
+
INLINE_INPUT_LIMIT_BYTES: () => INLINE_INPUT_LIMIT_BYTES2,
|
|
1653
1657
|
IdRemapper: () => IdRemapper,
|
|
1654
1658
|
InMemoryA2AApiKeyStore: () => InMemoryA2AApiKeyStore,
|
|
1655
1659
|
InMemoryAgentWebAppStore: () => InMemoryAgentWebAppStore,
|
|
@@ -1690,10 +1694,12 @@ __export(index_exports, {
|
|
|
1690
1694
|
LocalSandboxProvider: () => LocalSandboxProvider,
|
|
1691
1695
|
LoggerLatticeManager: () => LoggerLatticeManager,
|
|
1692
1696
|
MAX_BACKOFF_MS: () => MAX_BACKOFF_MS,
|
|
1697
|
+
MAX_HANDLER_TIMEOUT_MS: () => MAX_HANDLER_TIMEOUT_MS,
|
|
1693
1698
|
MAX_LINE_LENGTH: () => MAX_LINE_LENGTH,
|
|
1694
1699
|
MAX_PACK_ENTRIES: () => MAX_PACK_ENTRIES,
|
|
1695
1700
|
MAX_PACK_FILE_BYTES: () => MAX_PACK_FILE_BYTES,
|
|
1696
1701
|
MAX_PACK_TOTAL_BYTES: () => MAX_PACK_TOTAL_BYTES,
|
|
1702
|
+
MIN_HANDLER_TIMEOUT_MS: () => MIN_HANDLER_TIMEOUT_MS,
|
|
1697
1703
|
ManagedTaskStartError: () => ManagedTaskStartError,
|
|
1698
1704
|
McpLatticeManager: () => McpLatticeManager,
|
|
1699
1705
|
MemoryBackend: () => MemoryBackend,
|
|
@@ -1712,8 +1718,12 @@ __export(index_exports, {
|
|
|
1712
1718
|
PACK_DIRECTORY_TIMEOUT_SECONDS: () => PACK_DIRECTORY_TIMEOUT_SECONDS,
|
|
1713
1719
|
PLATFORM_SECRET_ENV_VARS: () => PLATFORM_SECRET_ENV_VARS,
|
|
1714
1720
|
PLUGIN_CATALOG_CHANGED_TOPIC: () => PLUGIN_CATALOG_CHANGED_TOPIC,
|
|
1721
|
+
PLUGIN_HOST_DIR: () => PLUGIN_HOST_DIR,
|
|
1722
|
+
PLUGIN_HOST_SERVER_SOURCE: () => PLUGIN_HOST_SERVER_SOURCE,
|
|
1723
|
+
PLUGIN_HOST_VERSION: () => PLUGIN_HOST_VERSION,
|
|
1715
1724
|
PersonalAssistantConfig: () => PersonalAssistantConfig,
|
|
1716
1725
|
PinoLoggerClient: () => PinoLoggerClient,
|
|
1726
|
+
PluginDeploymentRuntimeRegistry: () => PluginDeploymentRuntimeRegistry,
|
|
1717
1727
|
PluginRegistry: () => PluginRegistry,
|
|
1718
1728
|
PostgresDatabase: () => PostgresDatabase,
|
|
1719
1729
|
ProjectBotMembershipIdConflictError: () => ProjectBotMembershipIdConflictError,
|
|
@@ -1775,7 +1785,9 @@ __export(index_exports, {
|
|
|
1775
1785
|
appendUiFence: () => appendUiFence,
|
|
1776
1786
|
assertSafeUpstreamUrl: () => assertSafeUpstreamUrl,
|
|
1777
1787
|
buildBundleFromDist: () => buildBundleFromDist,
|
|
1788
|
+
buildConnectionPayload: () => buildConnectionPayload2,
|
|
1778
1789
|
buildGrepResultsDict: () => buildGrepResultsDict,
|
|
1790
|
+
buildHandlerCommand: () => buildHandlerCommand,
|
|
1779
1791
|
buildInput: () => buildInput,
|
|
1780
1792
|
buildNamedVolumeName: () => buildNamedVolumeName,
|
|
1781
1793
|
buildRemotePackDirectoryCommand: () => buildRemotePackDirectoryCommand,
|
|
@@ -1790,6 +1802,7 @@ __export(index_exports, {
|
|
|
1790
1802
|
clearEncryptionKeyCache: () => clearEncryptionKeyCache,
|
|
1791
1803
|
clearEvalRunService: () => clearEvalRunService,
|
|
1792
1804
|
clearSandboxOpenCredentialProviderForTests: () => clearSandboxOpenCredentialProviderForTests,
|
|
1805
|
+
collectPluginSources: () => collectPluginSources,
|
|
1793
1806
|
collectionLatticeManager: () => collectionLatticeManager,
|
|
1794
1807
|
compileInternal: () => compileInternal,
|
|
1795
1808
|
compileSandboxPlugin: () => compileSandboxPlugin,
|
|
@@ -1842,9 +1855,11 @@ __export(index_exports, {
|
|
|
1842
1855
|
decrypt: () => decrypt,
|
|
1843
1856
|
decryptConfigFields: () => decryptConfigFields,
|
|
1844
1857
|
describeCronExpression: () => describeCronExpression,
|
|
1858
|
+
disconnectAllChannels: () => disconnectAllChannels,
|
|
1845
1859
|
documentLearningPlugin: () => documentLearningPlugin,
|
|
1846
1860
|
documentParserPlugin: () => documentParserPlugin,
|
|
1847
1861
|
embeddingsLatticeManager: () => embeddingsLatticeManager,
|
|
1862
|
+
encodeInput: () => encodeInput,
|
|
1848
1863
|
encrypt: () => encrypt,
|
|
1849
1864
|
encryptConfigFields: () => encryptConfigFields,
|
|
1850
1865
|
ensureBuiltinAgentsForTenant: () => ensureBuiltinAgentsForTenant,
|
|
@@ -1888,6 +1903,7 @@ __export(index_exports, {
|
|
|
1888
1903
|
getModelLattice: () => getModelLattice,
|
|
1889
1904
|
getNextCronTime: () => getNextCronTime,
|
|
1890
1905
|
getOrCreateCollectionVectorStore: () => getOrCreateCollectionVectorStore,
|
|
1906
|
+
getPluginDeploymentService: () => getPluginDeploymentService,
|
|
1891
1907
|
getPluginSkillManifestVersion: () => getPluginSkillManifestVersion,
|
|
1892
1908
|
getQueueLattice: () => getQueueLattice,
|
|
1893
1909
|
getReplicaId: () => getReplicaId,
|
|
@@ -1916,6 +1932,8 @@ __export(index_exports, {
|
|
|
1916
1932
|
hasChunkBuffer: () => hasChunkBuffer,
|
|
1917
1933
|
hasDelegatedWorkerToken: () => hasDelegatedWorkerToken,
|
|
1918
1934
|
hasRuntimeCapabilityPolicy: () => hasRuntimeCapabilityPolicy,
|
|
1935
|
+
installPluginHost: () => installPluginHost,
|
|
1936
|
+
invokeResident: () => invokeResident,
|
|
1919
1937
|
invokeWithRetry: () => invokeWithRetry,
|
|
1920
1938
|
isBuiltInSkill: () => isBuiltInSkill,
|
|
1921
1939
|
isDirectRoom: () => isDirectRoom,
|
|
@@ -1929,6 +1947,7 @@ __export(index_exports, {
|
|
|
1929
1947
|
jsonSchemaToZod: () => jsonSchemaToZod,
|
|
1930
1948
|
listCollectionEntries: () => listCollectionEntries,
|
|
1931
1949
|
listSandboxProviderTypes: () => listSandboxProviderTypes,
|
|
1950
|
+
listTenantPlugins: () => listTenantPlugins,
|
|
1932
1951
|
loggerLatticeManager: () => loggerLatticeManager,
|
|
1933
1952
|
mcpManager: () => mcpManager,
|
|
1934
1953
|
mergeCapabilityBundles: () => mergeCapabilityBundles,
|
|
@@ -1942,6 +1961,8 @@ __export(index_exports, {
|
|
|
1942
1961
|
parallelLimit: () => parallelLimit,
|
|
1943
1962
|
parseCronExpression: () => parseCronExpression,
|
|
1944
1963
|
parseDirectRoomType: () => parseDirectRoomType,
|
|
1964
|
+
parseHandlerEnvelope: () => parseHandlerEnvelope,
|
|
1965
|
+
parseHostArgs: () => parseHostArgs,
|
|
1945
1966
|
parseJudgeVerdict: () => parseJudgeVerdict,
|
|
1946
1967
|
parsePackSize: () => parsePackSize,
|
|
1947
1968
|
parseQueuedExecutionMode: () => import_protocols2.parseQueuedExecutionMode,
|
|
@@ -1950,6 +1971,7 @@ __export(index_exports, {
|
|
|
1950
1971
|
parseTrustedRunContext: () => import_protocols2.parseTrustedRunContext,
|
|
1951
1972
|
parseYaml: () => parseYaml,
|
|
1952
1973
|
performStringReplacement: () => performStringReplacement,
|
|
1974
|
+
pluginHostContentHash: () => pluginHostContentHash,
|
|
1953
1975
|
postProcessTaskMutationResponse: () => postProcessTaskMutationResponse,
|
|
1954
1976
|
prepareTaskDispatch: () => prepareTaskDispatch,
|
|
1955
1977
|
projectMutationMutex: () => projectMutationMutex,
|
|
@@ -1988,6 +2010,7 @@ __export(index_exports, {
|
|
|
1988
2010
|
renderTemplate: () => renderTemplate,
|
|
1989
2011
|
resetReplicaIdForTests: () => resetReplicaIdForTests,
|
|
1990
2012
|
resolveEnabledPluginSkill: () => resolveEnabledPluginSkill,
|
|
2013
|
+
resolveHandlerTimeoutMs: () => resolveHandlerTimeoutMs,
|
|
1991
2014
|
resolveJudgeModelKey: () => resolveJudgeModelKey,
|
|
1992
2015
|
resolvePath: () => resolvePath,
|
|
1993
2016
|
resolvePluginConnections: () => resolvePluginConnections,
|
|
@@ -2007,6 +2030,7 @@ __export(index_exports, {
|
|
|
2007
2030
|
setBindingRegistry: () => setBindingRegistry,
|
|
2008
2031
|
setEvalRunService: () => setEvalRunService,
|
|
2009
2032
|
setMenuRegistry: () => setMenuRegistry,
|
|
2033
|
+
setPluginDeploymentService: () => setPluginDeploymentService,
|
|
2010
2034
|
setSandboxPluginCatalog: () => setSandboxPluginCatalog,
|
|
2011
2035
|
skillLatticeManager: () => skillLatticeManager,
|
|
2012
2036
|
sqlDatabaseManager: () => sqlDatabaseManager,
|
|
@@ -3704,6 +3728,9 @@ var InMemoryProjectStore = class {
|
|
|
3704
3728
|
workspaceId,
|
|
3705
3729
|
name: data.name,
|
|
3706
3730
|
description: data.description,
|
|
3731
|
+
// Persist `kind` like the Local/PostgreSQL stores so `public`/`personal`/
|
|
3732
|
+
// `training` project semantics survive in in-memory deployments.
|
|
3733
|
+
...data.kind === void 0 ? {} : { kind: data.kind },
|
|
3707
3734
|
config: data.config === void 0 && Object.keys(capabilityBundleIds).length === 0 ? void 0 : { ...data.config ?? {}, ...capabilityBundleIds },
|
|
3708
3735
|
createdAt: existing?.createdAt ?? now,
|
|
3709
3736
|
updatedAt: now
|
|
@@ -5323,6 +5350,93 @@ var InMemoryOutboxStore = class {
|
|
|
5323
5350
|
}
|
|
5324
5351
|
};
|
|
5325
5352
|
|
|
5353
|
+
// src/store_lattice/InMemoryPluginDeploymentStore.ts
|
|
5354
|
+
var InMemoryPluginDeploymentStore = class {
|
|
5355
|
+
constructor() {
|
|
5356
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
5357
|
+
}
|
|
5358
|
+
/**
|
|
5359
|
+
* Lists every deployment for a tenant.
|
|
5360
|
+
*
|
|
5361
|
+
* @param tenantId - Tenant whose deployments are listed
|
|
5362
|
+
* @returns Defensive copies of the tenant's deployments
|
|
5363
|
+
*/
|
|
5364
|
+
async listByTenant(tenantId2) {
|
|
5365
|
+
return [...this.entries.values()].filter((entry) => entry.tenantId === tenantId2).map((entry) => structuredClone(entry));
|
|
5366
|
+
}
|
|
5367
|
+
/**
|
|
5368
|
+
* Returns the deployment for a tenant + plugin type.
|
|
5369
|
+
*
|
|
5370
|
+
* @param tenantId - Owning tenant
|
|
5371
|
+
* @param pluginType - Plugin type key
|
|
5372
|
+
* @returns Defensive copy of the deployment, or undefined when absent
|
|
5373
|
+
*/
|
|
5374
|
+
async get(tenantId2, pluginType) {
|
|
5375
|
+
const entry = this.entries.get(entryKey2(tenantId2, pluginType));
|
|
5376
|
+
return entry ? structuredClone(entry) : void 0;
|
|
5377
|
+
}
|
|
5378
|
+
/**
|
|
5379
|
+
* Inserts or replaces a deployment keyed by tenant + plugin type.
|
|
5380
|
+
*
|
|
5381
|
+
* On conflict the existing `id` and `createdAt` are preserved while every
|
|
5382
|
+
* other field (including `updatedAt`, when supplied) is updated — mirroring
|
|
5383
|
+
* the PostgreSQL store's `ON CONFLICT` semantics.
|
|
5384
|
+
*
|
|
5385
|
+
* @param deployment - Deployment record to persist
|
|
5386
|
+
* @returns Defensive copy of the stored deployment
|
|
5387
|
+
*/
|
|
5388
|
+
async upsert(deployment) {
|
|
5389
|
+
const key5 = entryKey2(deployment.tenantId, deployment.pluginType);
|
|
5390
|
+
const existing = this.entries.get(key5);
|
|
5391
|
+
const next = {
|
|
5392
|
+
...structuredClone(deployment),
|
|
5393
|
+
id: existing?.id ?? deployment.id,
|
|
5394
|
+
createdAt: existing?.createdAt ?? deployment.createdAt,
|
|
5395
|
+
updatedAt: deployment.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
5396
|
+
};
|
|
5397
|
+
this.entries.set(key5, next);
|
|
5398
|
+
return structuredClone(next);
|
|
5399
|
+
}
|
|
5400
|
+
/**
|
|
5401
|
+
* Applies a partial update to a deployment.
|
|
5402
|
+
*
|
|
5403
|
+
* `patch.createdAt` is ignored (immutable) and `updatedAt` is taken from the
|
|
5404
|
+
* patch when supplied, otherwise set to the current time — matching the
|
|
5405
|
+
* PostgreSQL store.
|
|
5406
|
+
*
|
|
5407
|
+
* @param tenantId - Owning tenant
|
|
5408
|
+
* @param pluginType - Plugin type key
|
|
5409
|
+
* @param patch - Mutable fields to apply
|
|
5410
|
+
* @returns Defensive copy of the updated deployment, or undefined when absent
|
|
5411
|
+
*/
|
|
5412
|
+
async updateStatus(tenantId2, pluginType, patch) {
|
|
5413
|
+
const key5 = entryKey2(tenantId2, pluginType);
|
|
5414
|
+
const existing = this.entries.get(key5);
|
|
5415
|
+
if (!existing) return void 0;
|
|
5416
|
+
const next = {
|
|
5417
|
+
...existing,
|
|
5418
|
+
...patch,
|
|
5419
|
+
createdAt: existing.createdAt,
|
|
5420
|
+
updatedAt: patch.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
5421
|
+
};
|
|
5422
|
+
this.entries.set(key5, next);
|
|
5423
|
+
return structuredClone(next);
|
|
5424
|
+
}
|
|
5425
|
+
/**
|
|
5426
|
+
* Deletes a deployment by tenant + plugin type.
|
|
5427
|
+
*
|
|
5428
|
+
* @param tenantId - Owning tenant
|
|
5429
|
+
* @param pluginType - Plugin type key
|
|
5430
|
+
* @returns Whether a record was removed
|
|
5431
|
+
*/
|
|
5432
|
+
async delete(tenantId2, pluginType) {
|
|
5433
|
+
return this.entries.delete(entryKey2(tenantId2, pluginType));
|
|
5434
|
+
}
|
|
5435
|
+
};
|
|
5436
|
+
function entryKey2(tenantId2, pluginType) {
|
|
5437
|
+
return JSON.stringify([tenantId2, pluginType]);
|
|
5438
|
+
}
|
|
5439
|
+
|
|
5326
5440
|
// src/store_lattice/InMemoryUserStore.ts
|
|
5327
5441
|
var InMemoryUserStore = class {
|
|
5328
5442
|
constructor() {
|
|
@@ -6985,6 +7099,7 @@ var defaultProjectRoomReadStateStore = new InMemoryProjectRoomReadStateStore();
|
|
|
6985
7099
|
var defaultUserPushSubscriptionStore = new InMemoryUserPushSubscriptionStore();
|
|
6986
7100
|
var defaultLeaseStore = new InMemoryLeaseStore();
|
|
6987
7101
|
var defaultOutboxStore = new InMemoryOutboxStore();
|
|
7102
|
+
var defaultPluginDeploymentStore = new InMemoryPluginDeploymentStore();
|
|
6988
7103
|
storeLatticeManager.registerLattice("default", "thread", defaultThreadStore);
|
|
6989
7104
|
storeLatticeManager.registerLattice(
|
|
6990
7105
|
"default",
|
|
@@ -7008,6 +7123,7 @@ storeLatticeManager.registerLattice("default", "projectRoomReadState", defaultPr
|
|
|
7008
7123
|
storeLatticeManager.registerLattice("default", "userPushSubscription", defaultUserPushSubscriptionStore);
|
|
7009
7124
|
storeLatticeManager.registerLattice("default", "lease", defaultLeaseStore);
|
|
7010
7125
|
storeLatticeManager.registerLattice("default", "outbox", defaultOutboxStore);
|
|
7126
|
+
storeLatticeManager.registerLattice("default", "pluginDeployment", defaultPluginDeploymentStore);
|
|
7011
7127
|
var defaultUserStore = new InMemoryUserStore();
|
|
7012
7128
|
var defaultTenantStore = new InMemoryTenantStore();
|
|
7013
7129
|
var defaultUserTenantLinkStore = new InMemoryUserTenantLinkStore();
|
|
@@ -15067,6 +15183,82 @@ var evalPlugin = {
|
|
|
15067
15183
|
})
|
|
15068
15184
|
};
|
|
15069
15185
|
|
|
15186
|
+
// src/sandbox_plugin/residentTransport.ts
|
|
15187
|
+
var DEFAULT_RESIDENT_INVOKE_TIMEOUT_MS = 6e4;
|
|
15188
|
+
function isRecord3(value) {
|
|
15189
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15190
|
+
}
|
|
15191
|
+
function isEnvelope(value) {
|
|
15192
|
+
return isRecord3(value) && typeof value.ok === "boolean";
|
|
15193
|
+
}
|
|
15194
|
+
function errorFromBody(value) {
|
|
15195
|
+
if (isRecord3(value) && typeof value.error === "string" && value.error.length > 0) {
|
|
15196
|
+
return value.error;
|
|
15197
|
+
}
|
|
15198
|
+
return void 0;
|
|
15199
|
+
}
|
|
15200
|
+
async function readJson(response) {
|
|
15201
|
+
try {
|
|
15202
|
+
return await response.json();
|
|
15203
|
+
} catch {
|
|
15204
|
+
return void 0;
|
|
15205
|
+
}
|
|
15206
|
+
}
|
|
15207
|
+
async function invokeResident(args) {
|
|
15208
|
+
const {
|
|
15209
|
+
baseUrl,
|
|
15210
|
+
endpointPath,
|
|
15211
|
+
serviceKey,
|
|
15212
|
+
payload,
|
|
15213
|
+
timeoutMs = DEFAULT_RESIDENT_INVOKE_TIMEOUT_MS
|
|
15214
|
+
} = args;
|
|
15215
|
+
const fetchImpl = args.fetchImpl ?? fetch;
|
|
15216
|
+
const url = `${baseUrl.replace(/\/$/, "")}${endpointPath}/invoke`;
|
|
15217
|
+
const headers = {
|
|
15218
|
+
"Content-Type": "application/json"
|
|
15219
|
+
};
|
|
15220
|
+
if (serviceKey) {
|
|
15221
|
+
headers["Authorization"] = `Bearer ${serviceKey}`;
|
|
15222
|
+
}
|
|
15223
|
+
const controller = new AbortController();
|
|
15224
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
15225
|
+
try {
|
|
15226
|
+
const response = await fetchImpl(url, {
|
|
15227
|
+
method: "POST",
|
|
15228
|
+
headers,
|
|
15229
|
+
body: JSON.stringify({ ...payload, timeoutMs: payload.timeoutMs ?? timeoutMs }),
|
|
15230
|
+
signal: controller.signal
|
|
15231
|
+
});
|
|
15232
|
+
const parsed = await readJson(response);
|
|
15233
|
+
if (!response.ok) {
|
|
15234
|
+
return {
|
|
15235
|
+
ok: false,
|
|
15236
|
+
error: errorFromBody(parsed) ?? `resident service responded with HTTP ${response.status}`,
|
|
15237
|
+
status: response.status
|
|
15238
|
+
};
|
|
15239
|
+
}
|
|
15240
|
+
if (!isEnvelope(parsed)) {
|
|
15241
|
+
return {
|
|
15242
|
+
ok: false,
|
|
15243
|
+
error: "resident service returned an invalid envelope",
|
|
15244
|
+
status: response.status
|
|
15245
|
+
};
|
|
15246
|
+
}
|
|
15247
|
+
if (!parsed.ok) {
|
|
15248
|
+
return {
|
|
15249
|
+
ok: false,
|
|
15250
|
+
error: errorFromBody(parsed) ?? "resident handler reported failure",
|
|
15251
|
+
status: response.status
|
|
15252
|
+
};
|
|
15253
|
+
}
|
|
15254
|
+
return { ok: true, result: parsed.result, status: response.status };
|
|
15255
|
+
} catch (error) {
|
|
15256
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
15257
|
+
} finally {
|
|
15258
|
+
clearTimeout(timer);
|
|
15259
|
+
}
|
|
15260
|
+
}
|
|
15261
|
+
|
|
15070
15262
|
// src/sandbox_plugin/SandboxPluginExecutor.ts
|
|
15071
15263
|
var PLUGINS_ROOT = "/root/.agents/plugins";
|
|
15072
15264
|
var INLINE_INPUT_LIMIT_BYTES = 48 * 1024;
|
|
@@ -15079,11 +15271,11 @@ var MAX_MAX_RESULT_BYTES = 1048576;
|
|
|
15079
15271
|
function encode(value) {
|
|
15080
15272
|
return Buffer.from(JSON.stringify(value ?? null), "utf8").toString("base64");
|
|
15081
15273
|
}
|
|
15082
|
-
function
|
|
15274
|
+
function isRecord4(value) {
|
|
15083
15275
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15084
15276
|
}
|
|
15085
|
-
function
|
|
15086
|
-
return
|
|
15277
|
+
function isEnvelope2(value) {
|
|
15278
|
+
return isRecord4(value) && typeof value.ok === "boolean";
|
|
15087
15279
|
}
|
|
15088
15280
|
function clamp(value, min, max) {
|
|
15089
15281
|
return Math.min(Math.max(value, min), max);
|
|
@@ -15104,7 +15296,7 @@ function parseEnvelope(stdout) {
|
|
|
15104
15296
|
const trimmed = stdout.trim();
|
|
15105
15297
|
try {
|
|
15106
15298
|
const parsed = JSON.parse(trimmed || "null");
|
|
15107
|
-
if (
|
|
15299
|
+
if (isEnvelope2(parsed)) return parsed;
|
|
15108
15300
|
} catch {
|
|
15109
15301
|
}
|
|
15110
15302
|
const lines = stdout.split("\n");
|
|
@@ -15113,7 +15305,7 @@ function parseEnvelope(stdout) {
|
|
|
15113
15305
|
if (!line) continue;
|
|
15114
15306
|
try {
|
|
15115
15307
|
const parsed = JSON.parse(line);
|
|
15116
|
-
if (
|
|
15308
|
+
if (isEnvelope2(parsed)) return parsed;
|
|
15117
15309
|
} catch {
|
|
15118
15310
|
}
|
|
15119
15311
|
}
|
|
@@ -15126,26 +15318,258 @@ function truncate(value, cap) {
|
|
|
15126
15318
|
while (end > 0 && (buf[end] & 192) === 128) end -= 1;
|
|
15127
15319
|
return buf.subarray(0, end).toString("utf8") + "\n...[truncated]";
|
|
15128
15320
|
}
|
|
15321
|
+
function capResult(result, cap) {
|
|
15322
|
+
const serialized = typeof result === "string" ? result : JSON.stringify(result ?? null);
|
|
15323
|
+
return Buffer.byteLength(serialized, "utf8") <= cap ? result : truncate(serialized, cap);
|
|
15324
|
+
}
|
|
15129
15325
|
function errorFromStdout(stdout) {
|
|
15130
15326
|
let text = stdout;
|
|
15131
15327
|
try {
|
|
15132
15328
|
const parsed = JSON.parse(stdout);
|
|
15133
|
-
if (
|
|
15329
|
+
if (isRecord4(parsed)) {
|
|
15134
15330
|
text = JSON.stringify(sanitize(parsed)) ?? stdout;
|
|
15135
15331
|
}
|
|
15136
15332
|
} catch {
|
|
15137
15333
|
}
|
|
15138
15334
|
return text.slice(0, 4096);
|
|
15139
15335
|
}
|
|
15336
|
+
function buildResidentPayload(args, timeoutMs) {
|
|
15337
|
+
return {
|
|
15338
|
+
handler: args.handler,
|
|
15339
|
+
input: args.input,
|
|
15340
|
+
...args.connection === void 0 ? {} : { connection: args.connection },
|
|
15341
|
+
...args.connections === void 0 ? {} : { connections: args.connections },
|
|
15342
|
+
context: args.context,
|
|
15343
|
+
timeoutMs
|
|
15344
|
+
};
|
|
15345
|
+
}
|
|
15140
15346
|
var SandboxPluginExecutor = class {
|
|
15141
15347
|
/**
|
|
15142
|
-
* @param deps - Sandbox resolver and optional
|
|
15348
|
+
* @param deps - Sandbox resolver, optional logger, and optional resident routing
|
|
15143
15349
|
*/
|
|
15144
15350
|
constructor(deps) {
|
|
15145
15351
|
this.deps = deps;
|
|
15146
15352
|
}
|
|
15147
15353
|
/**
|
|
15148
|
-
* Invoke a plugin handler
|
|
15354
|
+
* Invoke a plugin handler.
|
|
15355
|
+
*
|
|
15356
|
+
* Routes to the published plugin's resident service when {@link
|
|
15357
|
+
* SandboxPluginExecutorDeps.resident} is configured and a deployment is
|
|
15358
|
+
* routable (`running` with an endpoint, or a resumed `onDemand` deployment).
|
|
15359
|
+
* Otherwise, or when the resident call fails and degradation is enabled, runs
|
|
15360
|
+
* the handler as a short `node <handler>` process inside the tenant sandbox.
|
|
15361
|
+
*
|
|
15362
|
+
* @param args - Invocation arguments including manifest, handler, and input
|
|
15363
|
+
* @returns The normalized handler result, exit code, timing, and raw stdout
|
|
15364
|
+
* @throws When `args.handler` is not a safe relative path
|
|
15365
|
+
*/
|
|
15366
|
+
async invoke(args) {
|
|
15367
|
+
const started = Date.now();
|
|
15368
|
+
validateRelativePath(args.handler, "handler");
|
|
15369
|
+
if (this.deps.resident) {
|
|
15370
|
+
const resident = await this.tryResident(args, this.deps.resident, started);
|
|
15371
|
+
if (resident) return resident;
|
|
15372
|
+
}
|
|
15373
|
+
return this.invokeShortProcess(args, started);
|
|
15374
|
+
}
|
|
15375
|
+
/**
|
|
15376
|
+
* Attempt to route an invocation to a published plugin's resident service.
|
|
15377
|
+
*
|
|
15378
|
+
* @param args - Invocation arguments
|
|
15379
|
+
* @param resident - Resident routing dependencies
|
|
15380
|
+
* @param started - Invocation start timestamp used for `durationMs`
|
|
15381
|
+
* @returns A terminal result (success, or failure with degradation disabled),
|
|
15382
|
+
* or `undefined` when the caller should fall back to the short-process path
|
|
15383
|
+
*/
|
|
15384
|
+
async tryResident(args, resident, started) {
|
|
15385
|
+
const tenantId2 = args.runConfig?.tenantId ?? args.context.tenantId;
|
|
15386
|
+
const pluginType = args.manifest.type;
|
|
15387
|
+
if (!tenantId2) return void 0;
|
|
15388
|
+
const deployment = await this.lookupDeployment(resident, tenantId2, pluginType);
|
|
15389
|
+
if (!deployment) return void 0;
|
|
15390
|
+
const timeoutMs = clamp(args.timeoutMs ?? DEFAULT_TIMEOUT_MS, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS);
|
|
15391
|
+
const payload = buildResidentPayload(args, timeoutMs);
|
|
15392
|
+
if (deployment.status === "running" && deployment.endpoint) {
|
|
15393
|
+
let outcome = await this.callResident(resident, deployment.endpoint, payload, timeoutMs);
|
|
15394
|
+
if (!outcome.ok && deployment.mode === "onDemand" && resident.ensureRunning) {
|
|
15395
|
+
outcome = await this.ensureRunningAndRetry(
|
|
15396
|
+
resident,
|
|
15397
|
+
tenantId2,
|
|
15398
|
+
pluginType,
|
|
15399
|
+
deployment.endpoint,
|
|
15400
|
+
payload,
|
|
15401
|
+
timeoutMs,
|
|
15402
|
+
outcome
|
|
15403
|
+
);
|
|
15404
|
+
}
|
|
15405
|
+
return this.finalizeResident(outcome, args, resident, pluginType, tenantId2, started);
|
|
15406
|
+
}
|
|
15407
|
+
if (deployment.mode === "onDemand" && resident.ensureRunning) {
|
|
15408
|
+
const outcome = await this.wakeOnDemand(resident, tenantId2, pluginType, payload, timeoutMs);
|
|
15409
|
+
if (outcome) {
|
|
15410
|
+
return this.finalizeResident(outcome, args, resident, pluginType, tenantId2, started);
|
|
15411
|
+
}
|
|
15412
|
+
}
|
|
15413
|
+
return void 0;
|
|
15414
|
+
}
|
|
15415
|
+
/**
|
|
15416
|
+
* Normalize a resident invocation outcome into the caller-facing result.
|
|
15417
|
+
*
|
|
15418
|
+
* @param outcome - Normalized resident transport result
|
|
15419
|
+
* @param args - Invocation arguments (for the result-size cap)
|
|
15420
|
+
* @param resident - Resident routing dependencies (degradation policy)
|
|
15421
|
+
* @param pluginType - Plugin type, for diagnostics
|
|
15422
|
+
* @param tenantId - Tenant owning the plugin, for diagnostics
|
|
15423
|
+
* @param started - Invocation start timestamp used for `durationMs`
|
|
15424
|
+
* @returns The normalized result, or `undefined` when the caller should fall
|
|
15425
|
+
* back to the short-process path
|
|
15426
|
+
*/
|
|
15427
|
+
finalizeResident(outcome, args, resident, pluginType, tenantId2, started) {
|
|
15428
|
+
if (outcome.ok) {
|
|
15429
|
+
const cap = clamp(
|
|
15430
|
+
args.maxResultBytes ?? DEFAULT_MAX_RESULT_BYTES,
|
|
15431
|
+
MIN_MAX_RESULT_BYTES,
|
|
15432
|
+
MAX_MAX_RESULT_BYTES
|
|
15433
|
+
);
|
|
15434
|
+
return {
|
|
15435
|
+
ok: true,
|
|
15436
|
+
result: capResult(outcome.result, cap),
|
|
15437
|
+
exitCode: 0,
|
|
15438
|
+
httpStatus: outcome.status,
|
|
15439
|
+
durationMs: Date.now() - started,
|
|
15440
|
+
stdout: "",
|
|
15441
|
+
stderr: ""
|
|
15442
|
+
};
|
|
15443
|
+
}
|
|
15444
|
+
const error = outcome.error ?? "resident plugin invocation failed";
|
|
15445
|
+
if (resident.degradeToShortProcess ?? true) {
|
|
15446
|
+
this.deps.logger?.info(
|
|
15447
|
+
{ event: "sandbox-plugin.resident.degrade", pluginType, tenantId: tenantId2, error },
|
|
15448
|
+
"resident plugin invocation failed; falling back to short process"
|
|
15449
|
+
);
|
|
15450
|
+
return void 0;
|
|
15451
|
+
}
|
|
15452
|
+
return {
|
|
15453
|
+
ok: false,
|
|
15454
|
+
error,
|
|
15455
|
+
exitCode: 1,
|
|
15456
|
+
httpStatus: outcome.status,
|
|
15457
|
+
durationMs: Date.now() - started,
|
|
15458
|
+
stdout: "",
|
|
15459
|
+
stderr: ""
|
|
15460
|
+
};
|
|
15461
|
+
}
|
|
15462
|
+
/**
|
|
15463
|
+
* Look up a deployment, degrading to `undefined` when the lookup throws.
|
|
15464
|
+
*
|
|
15465
|
+
* @param resident - Resident routing dependencies
|
|
15466
|
+
* @param tenantId - Tenant owning the plugin
|
|
15467
|
+
* @param pluginType - Plugin type addressed by the invocation
|
|
15468
|
+
* @returns The deployment, or `undefined` when absent or lookup failed
|
|
15469
|
+
*/
|
|
15470
|
+
async lookupDeployment(resident, tenantId2, pluginType) {
|
|
15471
|
+
try {
|
|
15472
|
+
return await resident.getDeployment(tenantId2, pluginType);
|
|
15473
|
+
} catch (error) {
|
|
15474
|
+
this.deps.logger?.info(
|
|
15475
|
+
{
|
|
15476
|
+
event: "sandbox-plugin.resident.lookup.failed",
|
|
15477
|
+
pluginType,
|
|
15478
|
+
tenantId: tenantId2,
|
|
15479
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15480
|
+
},
|
|
15481
|
+
"resident deployment lookup failed; falling back to short process"
|
|
15482
|
+
);
|
|
15483
|
+
return void 0;
|
|
15484
|
+
}
|
|
15485
|
+
}
|
|
15486
|
+
/**
|
|
15487
|
+
* Resume a non-running `onDemand` deployment once, then invoke it.
|
|
15488
|
+
*
|
|
15489
|
+
* Re-reads the deployment after the resume so a cold-started endpoint is
|
|
15490
|
+
* picked up. Never throws: a failed resume or a deployment that is still not
|
|
15491
|
+
* `running` with an endpoint resolves to `undefined`, letting the caller use
|
|
15492
|
+
* the short-process path.
|
|
15493
|
+
*
|
|
15494
|
+
* @param resident - Resident routing dependencies
|
|
15495
|
+
* @param tenantId - Tenant owning the plugin
|
|
15496
|
+
* @param pluginType - Plugin type addressed by the invocation
|
|
15497
|
+
* @param payload - Invocation payload
|
|
15498
|
+
* @param timeoutMs - Clamped per-call timeout
|
|
15499
|
+
* @returns The resident outcome when routed, or `undefined` to short-process
|
|
15500
|
+
*/
|
|
15501
|
+
async wakeOnDemand(resident, tenantId2, pluginType, payload, timeoutMs) {
|
|
15502
|
+
try {
|
|
15503
|
+
await resident.ensureRunning?.(tenantId2, pluginType);
|
|
15504
|
+
} catch (error) {
|
|
15505
|
+
this.deps.logger?.info(
|
|
15506
|
+
{
|
|
15507
|
+
event: "sandbox-plugin.resident.ensure.failed",
|
|
15508
|
+
pluginType,
|
|
15509
|
+
tenantId: tenantId2,
|
|
15510
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15511
|
+
},
|
|
15512
|
+
"resident service resume failed; falling back to short process"
|
|
15513
|
+
);
|
|
15514
|
+
return void 0;
|
|
15515
|
+
}
|
|
15516
|
+
const refreshed = await this.lookupDeployment(resident, tenantId2, pluginType);
|
|
15517
|
+
if (!refreshed || refreshed.status !== "running" || !refreshed.endpoint) {
|
|
15518
|
+
return void 0;
|
|
15519
|
+
}
|
|
15520
|
+
return this.callResident(resident, refreshed.endpoint, payload, timeoutMs);
|
|
15521
|
+
}
|
|
15522
|
+
/**
|
|
15523
|
+
* Resume an `onDemand` deployment once and retry the resident call once.
|
|
15524
|
+
*
|
|
15525
|
+
* @param resident - Resident routing dependencies
|
|
15526
|
+
* @param tenantId - Tenant owning the plugin
|
|
15527
|
+
* @param pluginType - Plugin type addressed by the invocation
|
|
15528
|
+
* @param endpoint - Endpoint used by the first attempt
|
|
15529
|
+
* @param payload - Invocation payload
|
|
15530
|
+
* @param timeoutMs - Clamped per-call timeout
|
|
15531
|
+
* @param firstOutcome - Failed first attempt, returned when resume fails
|
|
15532
|
+
* @returns The retry outcome, or `firstOutcome` when resume itself failed
|
|
15533
|
+
*/
|
|
15534
|
+
async ensureRunningAndRetry(resident, tenantId2, pluginType, endpoint, payload, timeoutMs, firstOutcome) {
|
|
15535
|
+
try {
|
|
15536
|
+
await resident.ensureRunning?.(tenantId2, pluginType);
|
|
15537
|
+
} catch (error) {
|
|
15538
|
+
this.deps.logger?.info(
|
|
15539
|
+
{
|
|
15540
|
+
event: "sandbox-plugin.resident.ensure.failed",
|
|
15541
|
+
pluginType,
|
|
15542
|
+
tenantId: tenantId2,
|
|
15543
|
+
error: error instanceof Error ? error.message : String(error)
|
|
15544
|
+
},
|
|
15545
|
+
"resident service resume failed"
|
|
15546
|
+
);
|
|
15547
|
+
return firstOutcome;
|
|
15548
|
+
}
|
|
15549
|
+
const refreshed = await this.lookupDeployment(resident, tenantId2, pluginType);
|
|
15550
|
+
return this.callResident(resident, refreshed?.endpoint ?? endpoint, payload, timeoutMs);
|
|
15551
|
+
}
|
|
15552
|
+
/**
|
|
15553
|
+
* Invoke the resident host over the sandbox-service proxy path.
|
|
15554
|
+
*
|
|
15555
|
+
* @param resident - Resident routing dependencies
|
|
15556
|
+
* @param endpointPath - Relative proxy path
|
|
15557
|
+
* @param payload - Invocation payload matching the host contract
|
|
15558
|
+
* @param timeoutMs - Clamped per-call timeout
|
|
15559
|
+
* @returns The normalized resident invocation result
|
|
15560
|
+
*/
|
|
15561
|
+
callResident(resident, endpointPath, payload, timeoutMs) {
|
|
15562
|
+
return invokeResident({
|
|
15563
|
+
baseUrl: resident.baseUrl,
|
|
15564
|
+
endpointPath,
|
|
15565
|
+
serviceKey: resident.serviceKey,
|
|
15566
|
+
payload,
|
|
15567
|
+
timeoutMs,
|
|
15568
|
+
fetchImpl: resident.fetchImpl
|
|
15569
|
+
});
|
|
15570
|
+
}
|
|
15571
|
+
/**
|
|
15572
|
+
* Invoke a plugin handler as a short `node <handler>` process.
|
|
15149
15573
|
*
|
|
15150
15574
|
* Resolves the sandbox, injects small input as a base64 env var (or writes a
|
|
15151
15575
|
* temp `input.json` for large input), writes connection credentials to a temp
|
|
@@ -15155,12 +15579,10 @@ var SandboxPluginExecutor = class {
|
|
|
15155
15579
|
* in all cases, including setup failures.
|
|
15156
15580
|
*
|
|
15157
15581
|
* @param args - Invocation arguments including manifest, handler, and input
|
|
15582
|
+
* @param started - Invocation start timestamp used for `durationMs`
|
|
15158
15583
|
* @returns The normalized handler result, exit code, timing, and raw stdout
|
|
15159
|
-
* @throws When `args.handler` is not a safe relative path
|
|
15160
15584
|
*/
|
|
15161
|
-
async
|
|
15162
|
-
const started = Date.now();
|
|
15163
|
-
validateRelativePath(args.handler, "handler");
|
|
15585
|
+
async invokeShortProcess(args, started) {
|
|
15164
15586
|
const pluginDir = `${PLUGINS_ROOT}/${args.manifest.type}`;
|
|
15165
15587
|
const handlerAbs = `${pluginDir}/${args.handler}`;
|
|
15166
15588
|
const tenantId2 = args.runConfig?.tenantId ?? args.context.tenantId;
|
|
@@ -15248,11 +15670,9 @@ var SandboxPluginExecutor = class {
|
|
|
15248
15670
|
}
|
|
15249
15671
|
const parsed = parseEnvelope(stdout);
|
|
15250
15672
|
if (parsed) {
|
|
15251
|
-
const result = parsed.ok ? parsed.result : void 0;
|
|
15252
|
-
const serialized = typeof result === "string" ? result : JSON.stringify(result ?? null);
|
|
15253
15673
|
return {
|
|
15254
15674
|
ok: parsed.ok,
|
|
15255
|
-
result:
|
|
15675
|
+
result: capResult(parsed.ok ? parsed.result : void 0, cap),
|
|
15256
15676
|
error: typeof parsed.error === "string" ? parsed.error : void 0,
|
|
15257
15677
|
exitCode,
|
|
15258
15678
|
durationMs,
|
|
@@ -15263,7 +15683,7 @@ var SandboxPluginExecutor = class {
|
|
|
15263
15683
|
const text = stdout.trim();
|
|
15264
15684
|
return {
|
|
15265
15685
|
ok: true,
|
|
15266
|
-
result:
|
|
15686
|
+
result: capResult(text, cap),
|
|
15267
15687
|
exitCode,
|
|
15268
15688
|
durationMs,
|
|
15269
15689
|
stdout,
|
|
@@ -15280,24 +15700,33 @@ var SandboxPluginExecutor = class {
|
|
|
15280
15700
|
}
|
|
15281
15701
|
};
|
|
15282
15702
|
|
|
15703
|
+
// src/sandbox_plugin/pluginDeploymentServiceRuntime.ts
|
|
15704
|
+
var service2 = null;
|
|
15705
|
+
function setPluginDeploymentService(instance) {
|
|
15706
|
+
service2 = instance ?? null;
|
|
15707
|
+
}
|
|
15708
|
+
function getPluginDeploymentService() {
|
|
15709
|
+
return service2;
|
|
15710
|
+
}
|
|
15711
|
+
|
|
15283
15712
|
// src/sandbox_plugin/TenantPluginCatalog.ts
|
|
15284
15713
|
var import_node_crypto3 = require("crypto");
|
|
15285
15714
|
|
|
15286
15715
|
// src/sandbox_plugin/jsonSchemaToZod.ts
|
|
15287
15716
|
var import_zod45 = require("zod");
|
|
15288
|
-
function
|
|
15717
|
+
function isRecord5(value) {
|
|
15289
15718
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15290
15719
|
}
|
|
15291
15720
|
function withDescription(schema6, raw) {
|
|
15292
|
-
const description =
|
|
15721
|
+
const description = isRecord5(raw) ? raw.description : void 0;
|
|
15293
15722
|
return typeof description === "string" ? schema6.describe(description) : schema6;
|
|
15294
15723
|
}
|
|
15295
15724
|
function jsonSchemaToZod(schema6) {
|
|
15296
|
-
if (!
|
|
15725
|
+
if (!isRecord5(schema6)) throw new Error("schema must be an object");
|
|
15297
15726
|
const type = schema6.type;
|
|
15298
15727
|
switch (type) {
|
|
15299
15728
|
case "object": {
|
|
15300
|
-
const props =
|
|
15729
|
+
const props = isRecord5(schema6.properties) ? schema6.properties : {};
|
|
15301
15730
|
const required = Array.isArray(schema6.required) ? schema6.required.filter((x) => typeof x === "string") : [];
|
|
15302
15731
|
const shape = {};
|
|
15303
15732
|
for (const [key5, sub] of Object.entries(props)) {
|
|
@@ -15337,7 +15766,7 @@ var DISPLAY_MODES = ["inline", "fullscreen", "pip"];
|
|
|
15337
15766
|
var MAX_MANIFEST_BYTES = 262144;
|
|
15338
15767
|
var MAX_TOOLS = 32;
|
|
15339
15768
|
var MAX_PLUGINS_PER_TENANT = 50;
|
|
15340
|
-
function
|
|
15769
|
+
function isRecord6(value) {
|
|
15341
15770
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15342
15771
|
}
|
|
15343
15772
|
function isSafeHandler(path8) {
|
|
@@ -15362,7 +15791,7 @@ function validateSandboxPluginManifest(args) {
|
|
|
15362
15791
|
const diagnostics = [];
|
|
15363
15792
|
const error = (code, message, pluginType, tool68) => diagnostics.push({ level: "error", code, message, pluginType, tool: tool68 });
|
|
15364
15793
|
const raw = args.raw;
|
|
15365
|
-
if (!
|
|
15794
|
+
if (!isRecord6(raw)) {
|
|
15366
15795
|
error("MANIFEST_NOT_OBJECT", "manifest must be a JSON object", args.dirName);
|
|
15367
15796
|
return { tools: [], diagnostics };
|
|
15368
15797
|
}
|
|
@@ -15415,7 +15844,7 @@ function validateSandboxPluginManifest(args) {
|
|
|
15415
15844
|
const tools = [];
|
|
15416
15845
|
const seenToolNames = /* @__PURE__ */ new Set();
|
|
15417
15846
|
for (const candidate of toolCandidates.slice(0, MAX_TOOLS)) {
|
|
15418
|
-
if (!
|
|
15847
|
+
if (!isRecord6(candidate)) {
|
|
15419
15848
|
error("TOOL_INVALID", "tool must be an object", type);
|
|
15420
15849
|
continue;
|
|
15421
15850
|
}
|
|
@@ -15432,7 +15861,7 @@ function validateSandboxPluginManifest(args) {
|
|
|
15432
15861
|
error("HANDLER_MISSING", `handler "${String(candidate.handler)}" not found`, type, name);
|
|
15433
15862
|
continue;
|
|
15434
15863
|
}
|
|
15435
|
-
if (!
|
|
15864
|
+
if (!isRecord6(candidate.schema)) {
|
|
15436
15865
|
error("TOOL_SCHEMA", `tool "${name}" schema must be an object`, type, name);
|
|
15437
15866
|
continue;
|
|
15438
15867
|
}
|
|
@@ -15446,17 +15875,17 @@ function validateSandboxPluginManifest(args) {
|
|
|
15446
15875
|
let ui;
|
|
15447
15876
|
if (candidate.ui !== void 0) {
|
|
15448
15877
|
const rawUi = candidate.ui;
|
|
15449
|
-
if (!
|
|
15878
|
+
if (!isRecord6(rawUi) || !isSafeUiPath(rawUi.resource) || !args.handlerExists(rawUi.resource)) {
|
|
15450
15879
|
error("TOOL_UI", `tool "${name}" ui.resource must be an existing .html file within the plugin dir`, type, name);
|
|
15451
15880
|
} else {
|
|
15452
|
-
const csp =
|
|
15881
|
+
const csp = isRecord6(rawUi.csp) ? {
|
|
15453
15882
|
connectDomains: Array.isArray(rawUi.csp.connectDomains) ? rawUi.csp.connectDomains.filter((d) => typeof d === "string") : void 0,
|
|
15454
15883
|
resourceDomains: Array.isArray(rawUi.csp.resourceDomains) ? rawUi.csp.resourceDomains.filter((d) => typeof d === "string") : void 0,
|
|
15455
15884
|
frameDomains: Array.isArray(rawUi.csp.frameDomains) ? rawUi.csp.frameDomains.filter((d) => typeof d === "string") : void 0,
|
|
15456
15885
|
baseUriDomains: Array.isArray(rawUi.csp.baseUriDomains) ? rawUi.csp.baseUriDomains.filter((d) => typeof d === "string") : void 0
|
|
15457
15886
|
} : void 0;
|
|
15458
15887
|
const displayMode = DISPLAY_MODES.includes(rawUi.displayMode) ? rawUi.displayMode : void 0;
|
|
15459
|
-
const permissions =
|
|
15888
|
+
const permissions = isRecord6(rawUi.permissions) ? {
|
|
15460
15889
|
camera: rawUi.permissions.camera === true ? true : void 0,
|
|
15461
15890
|
microphone: rawUi.permissions.microphone === true ? true : void 0,
|
|
15462
15891
|
geolocation: rawUi.permissions.geolocation === true ? true : void 0,
|
|
@@ -15486,7 +15915,7 @@ function validateSandboxPluginManifest(args) {
|
|
|
15486
15915
|
}
|
|
15487
15916
|
const skills = {};
|
|
15488
15917
|
if (raw.skills !== void 0) {
|
|
15489
|
-
if (!
|
|
15918
|
+
if (!isRecord6(raw.skills)) {
|
|
15490
15919
|
error("SKILLS_INVALID", "skills must be an object", type);
|
|
15491
15920
|
} else {
|
|
15492
15921
|
const prefix = `${type}-`;
|
|
@@ -15501,12 +15930,12 @@ function validateSandboxPluginManifest(args) {
|
|
|
15501
15930
|
error("SKILL_NAME", `skill "${name}" must be a safe relative path prefixed with "${prefix}"`, type);
|
|
15502
15931
|
continue;
|
|
15503
15932
|
}
|
|
15504
|
-
if (!
|
|
15933
|
+
if (!isRecord6(definition) || typeof definition.version !== "string" || typeof definition.content !== "string") {
|
|
15505
15934
|
error("SKILL_INVALID", `skill "${name}" requires string version and content`, type);
|
|
15506
15935
|
continue;
|
|
15507
15936
|
}
|
|
15508
15937
|
if (definition.resources !== void 0) {
|
|
15509
|
-
if (!
|
|
15938
|
+
if (!isRecord6(definition.resources)) {
|
|
15510
15939
|
error("SKILL_RESOURCES", `skill "${name}" resources must be an object`, type);
|
|
15511
15940
|
continue;
|
|
15512
15941
|
}
|
|
@@ -15518,7 +15947,7 @@ function validateSandboxPluginManifest(args) {
|
|
|
15518
15947
|
resourcesOk = false;
|
|
15519
15948
|
break;
|
|
15520
15949
|
}
|
|
15521
|
-
if (!
|
|
15950
|
+
if (!isRecord6(resource) || typeof resource.content !== "string") {
|
|
15522
15951
|
resourcesOk = false;
|
|
15523
15952
|
break;
|
|
15524
15953
|
}
|
|
@@ -15534,11 +15963,11 @@ function validateSandboxPluginManifest(args) {
|
|
|
15534
15963
|
}
|
|
15535
15964
|
const agents = {};
|
|
15536
15965
|
if (raw.agents !== void 0) {
|
|
15537
|
-
if (!
|
|
15966
|
+
if (!isRecord6(raw.agents)) {
|
|
15538
15967
|
error("AGENTS_INVALID", "agents must be an object", type);
|
|
15539
15968
|
} else {
|
|
15540
15969
|
for (const [key5, config] of Object.entries(raw.agents)) {
|
|
15541
|
-
if (!
|
|
15970
|
+
if (!isRecord6(config)) {
|
|
15542
15971
|
error("AGENT_INVALID", `agent "${key5}" must be an object`, type);
|
|
15543
15972
|
continue;
|
|
15544
15973
|
}
|
|
@@ -15559,7 +15988,7 @@ function validateSandboxPluginManifest(args) {
|
|
|
15559
15988
|
}
|
|
15560
15989
|
}
|
|
15561
15990
|
let connection;
|
|
15562
|
-
if (
|
|
15991
|
+
if (isRecord6(raw.connection)) {
|
|
15563
15992
|
const fields = raw.connection.fields;
|
|
15564
15993
|
if (!Array.isArray(fields)) {
|
|
15565
15994
|
error("CONNECTION_INVALID", "connection.fields must be an array", type);
|
|
@@ -15573,7 +16002,7 @@ function validateSandboxPluginManifest(args) {
|
|
|
15573
16002
|
for (const key5 of ["test", "discover"]) {
|
|
15574
16003
|
const entry = raw.connection[key5];
|
|
15575
16004
|
if (entry === void 0) continue;
|
|
15576
|
-
const handler =
|
|
16005
|
+
const handler = isRecord6(entry) ? entry.handler : void 0;
|
|
15577
16006
|
if (!isSafeHandler(handler) || !args.handlerExists(handler)) {
|
|
15578
16007
|
error("CONNECTION_HANDLER", `connection.${key5} handler "${String(handler)}" not found`, type);
|
|
15579
16008
|
continue;
|
|
@@ -15591,8 +16020,8 @@ function validateSandboxPluginManifest(args) {
|
|
|
15591
16020
|
version: raw.version,
|
|
15592
16021
|
icon: typeof raw.icon === "string" ? raw.icon : void 0,
|
|
15593
16022
|
category: typeof raw.category === "string" ? raw.category : void 0,
|
|
15594
|
-
configSchema:
|
|
15595
|
-
defaultConfig:
|
|
16023
|
+
configSchema: isRecord6(raw.configSchema) ? raw.configSchema : void 0,
|
|
16024
|
+
defaultConfig: isRecord6(raw.defaultConfig) ? raw.defaultConfig : void 0,
|
|
15596
16025
|
connection,
|
|
15597
16026
|
tools,
|
|
15598
16027
|
skills: Object.keys(skills).length > 0 ? skills : void 0,
|
|
@@ -15772,7 +16201,7 @@ var STANDARD_CONNECTION_DEFAULT_CONFIG = Object.freeze({
|
|
|
15772
16201
|
connectAll: false
|
|
15773
16202
|
});
|
|
15774
16203
|
var EMPTY_DEFAULT_CONFIG = Object.freeze({});
|
|
15775
|
-
function
|
|
16204
|
+
function isRecord7(value) {
|
|
15776
16205
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15777
16206
|
}
|
|
15778
16207
|
function runConfigFrom(exeConfig) {
|
|
@@ -15862,11 +16291,11 @@ async function runConnectionHandler(executor, manifest, handler, config, tenantI
|
|
|
15862
16291
|
return { ok: false, message: result.error ?? "connection test failed" };
|
|
15863
16292
|
}
|
|
15864
16293
|
const value = result.result;
|
|
15865
|
-
if (
|
|
16294
|
+
if (isRecord7(value) && typeof value.ok === "boolean" && typeof value.message === "string") {
|
|
15866
16295
|
return {
|
|
15867
16296
|
ok: value.ok,
|
|
15868
16297
|
message: value.message,
|
|
15869
|
-
details:
|
|
16298
|
+
details: isRecord7(value.details) ? value.details : void 0
|
|
15870
16299
|
};
|
|
15871
16300
|
}
|
|
15872
16301
|
return { ok: false, message: result.error ?? "connection test returned an invalid result" };
|
|
@@ -16219,13 +16648,29 @@ var TenantPluginCatalog = class {
|
|
|
16219
16648
|
|
|
16220
16649
|
// src/sandbox_plugin/sandboxPluginRuntime.ts
|
|
16221
16650
|
var catalog = null;
|
|
16651
|
+
function buildResidentRouting() {
|
|
16652
|
+
const baseUrl = process.env.MICROSANDBOX_SERVICE_URL;
|
|
16653
|
+
if (!baseUrl) return void 0;
|
|
16654
|
+
return {
|
|
16655
|
+
getDeployment: async (tenantId2, pluginType) => await getPluginDeploymentService()?.getDeployment(tenantId2, pluginType) ?? void 0,
|
|
16656
|
+
ensureRunning: async (tenantId2, pluginType) => {
|
|
16657
|
+
await getPluginDeploymentService()?.ensureRunning(tenantId2, pluginType);
|
|
16658
|
+
},
|
|
16659
|
+
baseUrl,
|
|
16660
|
+
serviceKey: process.env.MICROSANDBOX_API_KEY
|
|
16661
|
+
};
|
|
16662
|
+
}
|
|
16663
|
+
function buildExecutor(resolveSandbox) {
|
|
16664
|
+
const resident = buildResidentRouting();
|
|
16665
|
+
return new SandboxPluginExecutor({ resolveSandbox, ...resident ? { resident } : {} });
|
|
16666
|
+
}
|
|
16222
16667
|
function emptyCatalog() {
|
|
16223
16668
|
const resolveSandbox = async () => {
|
|
16224
16669
|
throw new Error("sandbox manager not configured");
|
|
16225
16670
|
};
|
|
16226
16671
|
return new TenantPluginCatalog({
|
|
16227
16672
|
resolveSandbox,
|
|
16228
|
-
executor:
|
|
16673
|
+
executor: buildExecutor(resolveSandbox),
|
|
16229
16674
|
reservedTypes: () => new Set(PluginRegistry.list())
|
|
16230
16675
|
});
|
|
16231
16676
|
}
|
|
@@ -16242,7 +16687,7 @@ function getSandboxPluginCatalog() {
|
|
|
16242
16687
|
const resolveSandbox = createSandboxResolver((config) => manager.getSandboxFromConfig(config));
|
|
16243
16688
|
catalog = new TenantPluginCatalog({
|
|
16244
16689
|
resolveSandbox,
|
|
16245
|
-
executor:
|
|
16690
|
+
executor: buildExecutor(resolveSandbox),
|
|
16246
16691
|
reservedTypes: () => new Set(PluginRegistry.list())
|
|
16247
16692
|
});
|
|
16248
16693
|
return catalog;
|
|
@@ -16251,6 +16696,22 @@ function setSandboxPluginCatalog(instance) {
|
|
|
16251
16696
|
catalog = instance;
|
|
16252
16697
|
}
|
|
16253
16698
|
|
|
16699
|
+
// src/plugin/listTenantPlugins.ts
|
|
16700
|
+
async function collectPluginSources(tenantId2) {
|
|
16701
|
+
const globalPlugins = PluginRegistry.list().map((type) => PluginRegistry.get(type)).filter((plugin) => Boolean(plugin));
|
|
16702
|
+
let tenantPlugins = [];
|
|
16703
|
+
try {
|
|
16704
|
+
tenantPlugins = (await getSandboxPluginCatalog().ensureLoaded(tenantId2)).plugins;
|
|
16705
|
+
} catch {
|
|
16706
|
+
tenantPlugins = [];
|
|
16707
|
+
}
|
|
16708
|
+
return { globalPlugins, tenantPlugins };
|
|
16709
|
+
}
|
|
16710
|
+
async function listTenantPlugins(tenantId2) {
|
|
16711
|
+
const { globalPlugins, tenantPlugins } = await collectPluginSources(tenantId2);
|
|
16712
|
+
return mergePluginSources(globalPlugins, tenantPlugins);
|
|
16713
|
+
}
|
|
16714
|
+
|
|
16254
16715
|
// src/agent_lattice/builders/taskMiddlewareValidation.ts
|
|
16255
16716
|
var REQUIRED_TASK_TOOLS = ["manage_task", "task"];
|
|
16256
16717
|
function validateTaskReviewMode(reviewMode) {
|
|
@@ -16373,23 +16834,23 @@ function toolName(tool68) {
|
|
|
16373
16834
|
return typeof tool68.name === "string" ? tool68.name : void 0;
|
|
16374
16835
|
}
|
|
16375
16836
|
function schemaHasConnectionKey(schema6) {
|
|
16376
|
-
const definition =
|
|
16837
|
+
const definition = isRecord8(schema6._def) ? schema6._def : void 0;
|
|
16377
16838
|
const shape = definition?.shape;
|
|
16378
16839
|
const fields = typeof shape === "function" ? shape() : shape;
|
|
16379
|
-
return
|
|
16840
|
+
return isRecord8(fields) && Object.prototype.hasOwnProperty.call(fields, "connectionKey");
|
|
16380
16841
|
}
|
|
16381
16842
|
function hasConnectionKeySchema(tool68) {
|
|
16382
|
-
if (!
|
|
16843
|
+
if (!isRecord8(tool68) || !isRecord8(tool68.schema)) return false;
|
|
16383
16844
|
if (schemaHasConnectionKey(tool68.schema)) return true;
|
|
16384
|
-
const definition =
|
|
16845
|
+
const definition = isRecord8(tool68.schema._def) ? tool68.schema._def : void 0;
|
|
16385
16846
|
if (Array.isArray(definition?.options) && definition.options.length > 0) {
|
|
16386
16847
|
return definition.options.every(
|
|
16387
|
-
(option) =>
|
|
16848
|
+
(option) => isRecord8(option) && schemaHasConnectionKey(option)
|
|
16388
16849
|
);
|
|
16389
16850
|
}
|
|
16390
16851
|
return false;
|
|
16391
16852
|
}
|
|
16392
|
-
function
|
|
16853
|
+
function isRecord8(value) {
|
|
16393
16854
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16394
16855
|
}
|
|
16395
16856
|
var CapabilityToolRegistry = class {
|
|
@@ -16481,17 +16942,17 @@ var CapabilityToolRegistry = class {
|
|
|
16481
16942
|
// src/middlewares/capabilityGuardMiddleware.ts
|
|
16482
16943
|
var import_messages4 = require("@langchain/core/messages");
|
|
16483
16944
|
var import_langchain49 = require("langchain");
|
|
16484
|
-
function
|
|
16945
|
+
function isRecord9(value) {
|
|
16485
16946
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16486
16947
|
}
|
|
16487
16948
|
function capabilityRuntimeFromRequest(request) {
|
|
16488
|
-
if (!
|
|
16949
|
+
if (!isRecord9(request) || !isRecord9(request.runtime)) return void 0;
|
|
16489
16950
|
const configurable = request.runtime.configurable;
|
|
16490
16951
|
const context = request.runtime.context;
|
|
16491
|
-
const runConfig =
|
|
16952
|
+
const runConfig = isRecord9(configurable) && isRecord9(configurable.runConfig) ? configurable.runConfig : isRecord9(context) && isRecord9(context.runConfig) ? context.runConfig : void 0;
|
|
16492
16953
|
if (!runConfig) return void 0;
|
|
16493
16954
|
const value = runConfig.capabilityRuntime;
|
|
16494
|
-
if (!
|
|
16955
|
+
if (!isRecord9(value) || typeof value.revision !== "string" || !isRecord9(value.middleware)) {
|
|
16495
16956
|
return void 0;
|
|
16496
16957
|
}
|
|
16497
16958
|
return value;
|
|
@@ -16503,10 +16964,10 @@ function hasActiveRuntimePolicy(runtime) {
|
|
|
16503
16964
|
return Object.keys(runtime.middleware).length > 0;
|
|
16504
16965
|
}
|
|
16505
16966
|
function tenantIdFromRequest(request) {
|
|
16506
|
-
if (!
|
|
16967
|
+
if (!isRecord9(request) || !isRecord9(request.runtime)) return void 0;
|
|
16507
16968
|
const configurable = request.runtime.configurable;
|
|
16508
16969
|
const context = request.runtime.context;
|
|
16509
|
-
const runConfig =
|
|
16970
|
+
const runConfig = isRecord9(configurable) && isRecord9(configurable.runConfig) ? configurable.runConfig : isRecord9(context) && isRecord9(context.runConfig) ? context.runConfig : void 0;
|
|
16510
16971
|
return runConfig && typeof runConfig.tenantId === "string" ? runConfig.tenantId : void 0;
|
|
16511
16972
|
}
|
|
16512
16973
|
async function standardConnectionAllowed(request, capabilityType, config) {
|
|
@@ -16514,8 +16975,8 @@ async function standardConnectionAllowed(request, capabilityType, config) {
|
|
|
16514
16975
|
const hasConnectAll = Object.prototype.hasOwnProperty.call(config, "connectAll");
|
|
16515
16976
|
if (!hasConnections && (!hasConnectAll || config.connectAll !== true)) return false;
|
|
16516
16977
|
const tenantId2 = tenantIdFromRequest(request);
|
|
16517
|
-
const resource =
|
|
16518
|
-
const hasConnectionKey =
|
|
16978
|
+
const resource = isRecord9(request.toolCall) && isRecord9(request.toolCall.args) ? request.toolCall.args.connectionKey : void 0;
|
|
16979
|
+
const hasConnectionKey = isRecord9(request.toolCall) && isRecord9(request.toolCall.args) && Object.prototype.hasOwnProperty.call(
|
|
16519
16980
|
request.toolCall.args,
|
|
16520
16981
|
"connectionKey"
|
|
16521
16982
|
);
|
|
@@ -16581,10 +17042,10 @@ function createCapabilityGuardMiddleware(registry4) {
|
|
|
16581
17042
|
toolName: toolName2
|
|
16582
17043
|
});
|
|
16583
17044
|
}
|
|
16584
|
-
const standardConfig =
|
|
17045
|
+
const standardConfig = isRecord9(policy.config) ? policy.config : {};
|
|
16585
17046
|
if (registry4.isStandardConnectionTool(toolName2) && !await standardConnectionAllowed(request, metadata.capabilityType, standardConfig)) {
|
|
16586
17047
|
const args2 = request.toolCall.args;
|
|
16587
|
-
const resource =
|
|
17048
|
+
const resource = isRecord9(args2) && typeof args2.connectionKey === "string" ? args2.connectionKey : void 0;
|
|
16588
17049
|
return denialMessage(request.toolCall, {
|
|
16589
17050
|
code: "RESOURCE_NOT_ALLOWED",
|
|
16590
17051
|
message: typeof resource === "string" ? `Resource '${resource}' is not allowed by the capability policy` : "Resource selector 'connectionKey' must be a permitted string",
|
|
@@ -16597,8 +17058,8 @@ function createCapabilityGuardMiddleware(registry4) {
|
|
|
16597
17058
|
const selector = metadata.resourceSelector;
|
|
16598
17059
|
const args = request.toolCall.args;
|
|
16599
17060
|
if (selector) {
|
|
16600
|
-
const resource =
|
|
16601
|
-
const config =
|
|
17061
|
+
const resource = isRecord9(args) ? args[selector.argumentField] : void 0;
|
|
17062
|
+
const config = isRecord9(policy.config) ? policy.config : {};
|
|
16602
17063
|
const hasExplicitResources = Object.prototype.hasOwnProperty.call(config, selector.configField);
|
|
16603
17064
|
const allowsAll = !hasExplicitResources && selector.allowAllField !== void 0 && config[selector.allowAllField] === true;
|
|
16604
17065
|
const allowedResources = config[selector.configField];
|
|
@@ -16815,13 +17276,7 @@ async function createCommonMiddlewares(middlewareConfigs, filesystemBackend, fsI
|
|
|
16815
17276
|
));
|
|
16816
17277
|
}
|
|
16817
17278
|
}
|
|
16818
|
-
|
|
16819
|
-
try {
|
|
16820
|
-
tenantPlugins = (await getSandboxPluginCatalog().ensureLoaded(tenantId2 ?? "default")).plugins;
|
|
16821
|
-
} catch {
|
|
16822
|
-
tenantPlugins = [];
|
|
16823
|
-
}
|
|
16824
|
-
const globalPlugins = PluginRegistry.list().map((type) => PluginRegistry.get(type)).filter((p) => Boolean(p));
|
|
17279
|
+
const { globalPlugins, tenantPlugins } = await collectPluginSources(tenantId2 ?? "default");
|
|
16825
17280
|
const mergedPlugins = mergePluginSources(globalPlugins, tenantPlugins);
|
|
16826
17281
|
const mergedByType = new Map(mergedPlugins.map((p) => [p.meta.type, p]));
|
|
16827
17282
|
const enabledPluginTypes = new Set(
|
|
@@ -31317,10 +31772,8 @@ function getAvailableTools(tenantId2) {
|
|
|
31317
31772
|
function getAvailableModels() {
|
|
31318
31773
|
return modelLatticeManager.getAllByTenant("default");
|
|
31319
31774
|
}
|
|
31320
|
-
function getAvailableMiddlewareTypes() {
|
|
31321
|
-
return
|
|
31322
|
-
(type) => typeof PluginRegistry.get(type)?.middleware === "function"
|
|
31323
|
-
);
|
|
31775
|
+
async function getAvailableMiddlewareTypes(tenantId2) {
|
|
31776
|
+
return (await listTenantPlugins(tenantId2)).filter((plugin) => typeof plugin.middleware === "function").map((plugin) => plugin.meta.type);
|
|
31324
31777
|
}
|
|
31325
31778
|
function normalizeProjectScope(projectId) {
|
|
31326
31779
|
return !projectId || projectId === "default" ? "default" : projectId;
|
|
@@ -31359,7 +31812,7 @@ function requireSkillDeclaration(skillLoaded) {
|
|
|
31359
31812
|
}
|
|
31360
31813
|
async function validateAgentReferences(input, tenantId2) {
|
|
31361
31814
|
const availableTools = getAvailableTools(tenantId2).map((tool68) => tool68.key);
|
|
31362
|
-
const availableMiddlewareTypes = getAvailableMiddlewareTypes();
|
|
31815
|
+
const availableMiddlewareTypes = await getAvailableMiddlewareTypes(tenantId2);
|
|
31363
31816
|
const availableCustomMiddlewareKeys = CustomMiddlewareRegistry.list().filter(
|
|
31364
31817
|
(key5) => CustomMiddlewareRegistry.get(key5) !== void 0
|
|
31365
31818
|
);
|
|
@@ -32039,9 +32492,10 @@ registerToolLattice(
|
|
|
32039
32492
|
description: "\u5217\u51FA\u5F53\u524D\u7CFB\u7EDF\u4E2D\u6240\u6709\u53EF\u7528\u7684\u4E2D\u95F4\u4EF6\u7C7B\u578B\uFF08Middlewares\uFF09\uFF0C\u5305\u62EC\u5185\u7F6E\u548C\u81EA\u5B9A\u4E49\u63D2\u4EF6\u3002\u8FD4\u56DE\u6BCF\u4E2A\u4E2D\u95F4\u4EF6\u7684 type\u3001name\u3001description\u3001tools \u6E05\u5355\uFF08\u652F\u6301 allowedTools \u8FC7\u6EE4\uFF09\u3001configSchema\uFF08\u914D\u7F6E\u9762\u677F\u9700\u8981\u54EA\u4E9B\u5B57\u6BB5\uFF09\u548C connectionSchema\uFF08\u662F\u5426\u652F\u6301\u8FDE\u63A5\u6D4B\u8BD5\u548C\u8D44\u6E90\u53D1\u73B0\uFF09\u3002\n\n\u4F7F\u7528\u573A\u666F\uFF1A\n1. \u5728\u521B\u5EFA agent \u524D\uFF0C\u5148\u8C03\u6B64\u5DE5\u5177\u4E86\u89E3\u6709\u54EA\u4E9B\u4E2D\u95F4\u4EF6\u53EF\u914D\u7F6E\n2. \u6839\u636E configSchema \u51B3\u5B9A\u9700\u8981\u63D0\u4F9B\u54EA\u4E9B\u914D\u7F6E\u5B57\u6BB5\uFF1B\u65B0\u8FDE\u63A5\u578B\u63D2\u4EF6\u4F7F\u7528 connections \u548C connectAll\uFF0C\u5185\u7F6E\u65E7\u63D2\u4EF6\u7684 selector \u5B57\u6BB5\u7531 core \u7684 legacy compatibility map \u5B9A\u4E49\n3. \u5982\u679C\u67D0\u4E2A\u4E2D\u95F4\u4EF6\u7684 connectionSchema \u5B58\u5728\uFF0C\u8BF4\u660E\u5B83\u662F\u8FDE\u63A5\u578B\u4E2D\u95F4\u4EF6\uFF0C\u9700\u8981\u518D\u8C03 list_connections \u83B7\u53D6\u53EF\u7528\u8FDE\u63A5\n4. \u7528\u8FD4\u56DE\u7684 type \u5B57\u6BB5\u6784\u5EFA middleware \u6570\u7EC4\u4F20\u7ED9 create_agent / update_agent",
|
|
32040
32493
|
schema: import_zod50.default.object({})
|
|
32041
32494
|
},
|
|
32042
|
-
async () => {
|
|
32043
|
-
const
|
|
32044
|
-
const
|
|
32495
|
+
async (_input, exeConfig) => {
|
|
32496
|
+
const tenantId2 = getTenantId2(exeConfig);
|
|
32497
|
+
const plugins = await listTenantPlugins(tenantId2);
|
|
32498
|
+
const metas = plugins.filter((plugin) => typeof plugin.middleware === "function").map(serializePluginMeta);
|
|
32045
32499
|
return JSON.stringify(metas);
|
|
32046
32500
|
}
|
|
32047
32501
|
);
|
|
@@ -32352,14 +32806,7 @@ function ensureBuiltinAgentsForTenant(tenantId2) {
|
|
|
32352
32806
|
|
|
32353
32807
|
// src/agent_lattice/pluginAgents.ts
|
|
32354
32808
|
async function ensurePluginAgentsForTenant(tenantId2) {
|
|
32355
|
-
const
|
|
32356
|
-
let tenantPlugins = [];
|
|
32357
|
-
try {
|
|
32358
|
-
tenantPlugins = (await getSandboxPluginCatalog().ensureLoaded(tenantId2)).plugins;
|
|
32359
|
-
} catch {
|
|
32360
|
-
tenantPlugins = [];
|
|
32361
|
-
}
|
|
32362
|
-
for (const plugin of mergePluginSources(globalPlugins, tenantPlugins)) {
|
|
32809
|
+
for (const plugin of await listTenantPlugins(tenantId2)) {
|
|
32363
32810
|
if (!plugin.agents) continue;
|
|
32364
32811
|
for (const [key5, config] of Object.entries(plugin.agents)) {
|
|
32365
32812
|
try {
|
|
@@ -32387,6 +32834,7 @@ function assistantToConfig(assistant) {
|
|
|
32387
32834
|
prompt: typeof assistant.graphDefinition === "string" ? assistant.graphDefinition : JSON.stringify(assistant.graphDefinition)
|
|
32388
32835
|
};
|
|
32389
32836
|
Object.assign(config, graphDef);
|
|
32837
|
+
if (assistant.ownerUserId !== void 0) config.ownerUserId = assistant.ownerUserId;
|
|
32390
32838
|
return config;
|
|
32391
32839
|
}
|
|
32392
32840
|
var _AgentLatticeManager = class _AgentLatticeManager extends BaseLatticeManager {
|
|
@@ -34784,6 +35232,9 @@ var MicrosandboxRemoteInstance = class {
|
|
|
34784
35232
|
}
|
|
34785
35233
|
return "unknown";
|
|
34786
35234
|
}
|
|
35235
|
+
async getEndpoint(port) {
|
|
35236
|
+
return this.client.getEndpoint(this.name, port);
|
|
35237
|
+
}
|
|
34787
35238
|
/**
|
|
34788
35239
|
* Pack a sandbox folder into a sibling ZIP through the microsandbox shell.
|
|
34789
35240
|
*
|
|
@@ -34850,6 +35301,19 @@ var MicrosandboxServiceClient = class {
|
|
|
34850
35301
|
method: "GET"
|
|
34851
35302
|
});
|
|
34852
35303
|
}
|
|
35304
|
+
/**
|
|
35305
|
+
* Resolve the endpoint for a published guest port of a sandbox.
|
|
35306
|
+
*
|
|
35307
|
+
* @param name - Sandbox name
|
|
35308
|
+
* @param port - Guest port published via `ensureSandbox({ exposePorts })`
|
|
35309
|
+
* @returns The scheme-less endpoint string and optional headers
|
|
35310
|
+
*/
|
|
35311
|
+
async getEndpoint(name, port) {
|
|
35312
|
+
return this.request(
|
|
35313
|
+
`/api/sandboxes/${encodeURIComponent(name)}/endpoints/${port}`,
|
|
35314
|
+
{ method: "GET" }
|
|
35315
|
+
);
|
|
35316
|
+
}
|
|
34853
35317
|
async readFile(sandboxName, path8) {
|
|
34854
35318
|
return this.request("/api/files/read", {
|
|
34855
35319
|
method: "POST",
|
|
@@ -35114,9 +35578,9 @@ var MicrosandboxRemoteProvider = class {
|
|
|
35114
35578
|
}
|
|
35115
35579
|
buildEnsureInput(config) {
|
|
35116
35580
|
const defaultMicrosandboxRemoteConfig = getDefaultMicrosandboxRemoteConfig();
|
|
35117
|
-
const image = this.config.image ?? defaultMicrosandboxRemoteConfig.image;
|
|
35581
|
+
const image = config.image ?? this.config.image ?? defaultMicrosandboxRemoteConfig.image;
|
|
35118
35582
|
console.log(
|
|
35119
|
-
`[MicrosandboxRemote] buildEnsureInput image=${image} from=${this.config.image ? "providerConfig" : "defaultConfig"}`
|
|
35583
|
+
`[MicrosandboxRemote] buildEnsureInput image=${image} from=${config.image ? "runConfig" : this.config.image ? "providerConfig" : "defaultConfig"}`
|
|
35120
35584
|
);
|
|
35121
35585
|
return {
|
|
35122
35586
|
image,
|
|
@@ -35126,7 +35590,10 @@ var MicrosandboxRemoteProvider = class {
|
|
|
35126
35590
|
...this.config.env,
|
|
35127
35591
|
...buildSandboxMetadataEnv(config)
|
|
35128
35592
|
},
|
|
35129
|
-
volumes: config?.volumes ?? this.buildDefaultVolumes(config)
|
|
35593
|
+
volumes: config?.volumes ?? this.buildDefaultVolumes(config),
|
|
35594
|
+
entrypoint: config.entrypoint,
|
|
35595
|
+
timeoutSeconds: config.timeoutSeconds,
|
|
35596
|
+
exposePorts: config.exposePorts
|
|
35130
35597
|
};
|
|
35131
35598
|
}
|
|
35132
35599
|
buildDefaultVolumes(config) {
|
|
@@ -36852,6 +37319,157 @@ async function connectAllChannels(getAdapter, options = {}) {
|
|
|
36852
37319
|
}
|
|
36853
37320
|
}
|
|
36854
37321
|
}
|
|
37322
|
+
async function disconnectAllChannels(getAdapter) {
|
|
37323
|
+
const store = getStoreLattice("default", "channelInstallation").store;
|
|
37324
|
+
const installations = await store.getAllInstallations();
|
|
37325
|
+
console.log(`[disconnectAllChannels] total=${installations.length} enabled=${installations.filter((i) => i.enabled).length}`);
|
|
37326
|
+
for (const inst of installations) {
|
|
37327
|
+
if (!inst.enabled) continue;
|
|
37328
|
+
const adapter = getAdapter(inst.channel);
|
|
37329
|
+
if (!adapter?.disconnect) continue;
|
|
37330
|
+
try {
|
|
37331
|
+
await adapter.disconnect(inst.id);
|
|
37332
|
+
} catch (error) {
|
|
37333
|
+
console.error(`[disconnectAllChannels] disconnect failed: channel=${inst.channel} tenant=${inst.tenantId} id=${inst.id}`, error);
|
|
37334
|
+
}
|
|
37335
|
+
}
|
|
37336
|
+
}
|
|
37337
|
+
|
|
37338
|
+
// src/channel/ChannelConnectionLeader.ts
|
|
37339
|
+
var import_node_crypto8 = require("crypto");
|
|
37340
|
+
var LEASE_KEY = "leader:channel-connections";
|
|
37341
|
+
var ChannelConnectionLeader = class {
|
|
37342
|
+
constructor(deps) {
|
|
37343
|
+
this.holder = null;
|
|
37344
|
+
this.connected = false;
|
|
37345
|
+
this.attempted = false;
|
|
37346
|
+
this.inFlight = null;
|
|
37347
|
+
this.timer = null;
|
|
37348
|
+
this.running = false;
|
|
37349
|
+
this.stopped = false;
|
|
37350
|
+
this.deps = deps;
|
|
37351
|
+
this.ttlMs = deps.ttlMs ?? 6e4;
|
|
37352
|
+
this.retryMs = deps.retryMs ?? Math.max(5e3, Math.floor(this.ttlMs / 3));
|
|
37353
|
+
}
|
|
37354
|
+
/** Starts the ownership loop (immediate tick, then every `retryMs`). */
|
|
37355
|
+
start() {
|
|
37356
|
+
if (this.timer || this.stopped) return;
|
|
37357
|
+
void this.tickOnce();
|
|
37358
|
+
this.timer = setInterval(() => {
|
|
37359
|
+
void this.tickOnce();
|
|
37360
|
+
}, this.retryMs);
|
|
37361
|
+
this.timer.unref?.();
|
|
37362
|
+
}
|
|
37363
|
+
/**
|
|
37364
|
+
* Releases ownership (if held) and disconnects.
|
|
37365
|
+
*
|
|
37366
|
+
* @returns A promise that settles after teardown completes.
|
|
37367
|
+
* @remarks Terminal: a stopped leader does not restart.
|
|
37368
|
+
*/
|
|
37369
|
+
async stop() {
|
|
37370
|
+
this.stopped = true;
|
|
37371
|
+
if (this.timer) {
|
|
37372
|
+
clearInterval(this.timer);
|
|
37373
|
+
this.timer = null;
|
|
37374
|
+
}
|
|
37375
|
+
if (this.inFlight) await this.inFlight.catch(() => void 0);
|
|
37376
|
+
if (this.holder) {
|
|
37377
|
+
const holder = this.holder;
|
|
37378
|
+
this.holder = null;
|
|
37379
|
+
await this.deps.leaseStore.release(LEASE_KEY, holder).catch((error) => {
|
|
37380
|
+
this.deps.log?.warn("Channel leader lease release failed", {
|
|
37381
|
+
error: error instanceof Error ? error.message : String(error)
|
|
37382
|
+
});
|
|
37383
|
+
});
|
|
37384
|
+
}
|
|
37385
|
+
await this.disconnectChannels();
|
|
37386
|
+
}
|
|
37387
|
+
/**
|
|
37388
|
+
* Runs one ownership/health step. Public for deterministic tests.
|
|
37389
|
+
*
|
|
37390
|
+
* @returns A promise that settles when this step completes.
|
|
37391
|
+
*/
|
|
37392
|
+
async tickOnce() {
|
|
37393
|
+
if (this.running || this.stopped) return;
|
|
37394
|
+
this.running = true;
|
|
37395
|
+
const run = this.runTick();
|
|
37396
|
+
this.inFlight = run;
|
|
37397
|
+
try {
|
|
37398
|
+
await run;
|
|
37399
|
+
} finally {
|
|
37400
|
+
if (this.inFlight === run) this.inFlight = null;
|
|
37401
|
+
this.running = false;
|
|
37402
|
+
}
|
|
37403
|
+
}
|
|
37404
|
+
/**
|
|
37405
|
+
* Performs one acquire/renew/step decision.
|
|
37406
|
+
*
|
|
37407
|
+
* @remarks A transient lease-store error while renewing keeps the current
|
|
37408
|
+
* holder and connections intact (retry next tick); only a confirmed
|
|
37409
|
+
* `renewed === false` triggers teardown.
|
|
37410
|
+
*/
|
|
37411
|
+
async runTick() {
|
|
37412
|
+
if (this.holder) {
|
|
37413
|
+
let renewed = false;
|
|
37414
|
+
let renewFailed = false;
|
|
37415
|
+
try {
|
|
37416
|
+
renewed = await this.deps.leaseStore.renew(LEASE_KEY, this.holder, this.ttlMs);
|
|
37417
|
+
} catch (error) {
|
|
37418
|
+
renewFailed = true;
|
|
37419
|
+
this.deps.log?.warn("Channel leader lease renew failed", {
|
|
37420
|
+
error: error instanceof Error ? error.message : String(error)
|
|
37421
|
+
});
|
|
37422
|
+
}
|
|
37423
|
+
if (renewFailed) return;
|
|
37424
|
+
if (renewed) {
|
|
37425
|
+
if (!this.connected) await this.connectChannels();
|
|
37426
|
+
return;
|
|
37427
|
+
}
|
|
37428
|
+
await this.loseLeadership();
|
|
37429
|
+
}
|
|
37430
|
+
await this.tryAcquire();
|
|
37431
|
+
}
|
|
37432
|
+
async tryAcquire() {
|
|
37433
|
+
const holder = `${this.deps.owner}#${(0, import_node_crypto8.randomUUID)()}`;
|
|
37434
|
+
const acquired = await this.deps.leaseStore.tryAcquire(LEASE_KEY, holder, this.ttlMs).catch((error) => {
|
|
37435
|
+
this.deps.log?.warn("Channel leader lease acquire failed", {
|
|
37436
|
+
error: error instanceof Error ? error.message : String(error)
|
|
37437
|
+
});
|
|
37438
|
+
return false;
|
|
37439
|
+
});
|
|
37440
|
+
if (!acquired) return;
|
|
37441
|
+
this.holder = holder;
|
|
37442
|
+
await this.connectChannels();
|
|
37443
|
+
}
|
|
37444
|
+
async loseLeadership() {
|
|
37445
|
+
this.holder = null;
|
|
37446
|
+
await this.disconnectChannels();
|
|
37447
|
+
}
|
|
37448
|
+
async connectChannels() {
|
|
37449
|
+
this.attempted = true;
|
|
37450
|
+
try {
|
|
37451
|
+
await this.deps.connect();
|
|
37452
|
+
this.connected = true;
|
|
37453
|
+
} catch (error) {
|
|
37454
|
+
this.connected = false;
|
|
37455
|
+
this.deps.log?.warn("Channel leader connect failed", {
|
|
37456
|
+
error: error instanceof Error ? error.message : String(error)
|
|
37457
|
+
});
|
|
37458
|
+
}
|
|
37459
|
+
}
|
|
37460
|
+
async disconnectChannels() {
|
|
37461
|
+
if (!this.attempted) return;
|
|
37462
|
+
this.attempted = false;
|
|
37463
|
+
this.connected = false;
|
|
37464
|
+
try {
|
|
37465
|
+
await this.deps.disconnect();
|
|
37466
|
+
} catch (error) {
|
|
37467
|
+
this.deps.log?.warn("Channel leader disconnect failed", {
|
|
37468
|
+
error: error instanceof Error ? error.message : String(error)
|
|
37469
|
+
});
|
|
37470
|
+
}
|
|
37471
|
+
}
|
|
37472
|
+
};
|
|
36855
37473
|
|
|
36856
37474
|
// src/eval_lattice/LatticeEval.ts
|
|
36857
37475
|
var import_messages7 = require("@langchain/core/messages");
|
|
@@ -38312,7 +38930,7 @@ function getCoordinationLeaseStore() {
|
|
|
38312
38930
|
}
|
|
38313
38931
|
|
|
38314
38932
|
// src/services/withLease.ts
|
|
38315
|
-
var
|
|
38933
|
+
var import_node_crypto9 = require("crypto");
|
|
38316
38934
|
var LeaseAcquisitionTimeoutError = class extends Error {
|
|
38317
38935
|
/**
|
|
38318
38936
|
* @param key Lease key that could not be acquired.
|
|
@@ -38337,7 +38955,7 @@ async function withLease(store, key5, ownerLabel, fn, options = {}) {
|
|
|
38337
38955
|
const acquireTimeoutMs = options.acquireTimeoutMs ?? 1e4;
|
|
38338
38956
|
const retryDelayMs = options.retryDelayMs ?? 50;
|
|
38339
38957
|
const heartbeatMs = options.heartbeatMs ?? Math.max(1e3, Math.floor(ttlMs / 3));
|
|
38340
|
-
const holder = `${ownerLabel}#${(0,
|
|
38958
|
+
const holder = `${ownerLabel}#${(0, import_node_crypto9.randomUUID)()}`;
|
|
38341
38959
|
const deadline = Date.now() + acquireTimeoutMs;
|
|
38342
38960
|
for (; ; ) {
|
|
38343
38961
|
if (await store.tryAcquire(key5, holder, ttlMs)) break;
|
|
@@ -38815,11 +39433,11 @@ function snapshotDate(value) {
|
|
|
38815
39433
|
}
|
|
38816
39434
|
|
|
38817
39435
|
// src/services/TaskLifecycleService.ts
|
|
38818
|
-
var
|
|
39436
|
+
var import_node_crypto11 = require("crypto");
|
|
38819
39437
|
var import_protocols31 = require("@axiom-lattice/protocols");
|
|
38820
39438
|
|
|
38821
39439
|
// src/middlewares/taskBelief.ts
|
|
38822
|
-
var
|
|
39440
|
+
var import_node_crypto10 = require("crypto");
|
|
38823
39441
|
function buildBeliefCompletionEventKey(taskId, result, impacts) {
|
|
38824
39442
|
const canonical = JSON.stringify({
|
|
38825
39443
|
beliefImpact: impacts.map((impact) => ({
|
|
@@ -38830,7 +39448,7 @@ function buildBeliefCompletionEventKey(taskId, result, impacts) {
|
|
|
38830
39448
|
})),
|
|
38831
39449
|
result: result.trim()
|
|
38832
39450
|
});
|
|
38833
|
-
return (0,
|
|
39451
|
+
return (0, import_node_crypto10.createHash)("sha256").update(canonical).digest("hex");
|
|
38834
39452
|
}
|
|
38835
39453
|
function buildCompletionEvidenceDetail(result, impacts, eventKey) {
|
|
38836
39454
|
return { result, beliefImpact: impacts, eventKey };
|
|
@@ -39033,7 +39651,7 @@ function canonicalJson(value) {
|
|
|
39033
39651
|
return JSON.stringify(value);
|
|
39034
39652
|
}
|
|
39035
39653
|
function sha256(value) {
|
|
39036
|
-
return (0,
|
|
39654
|
+
return (0, import_node_crypto11.createHash)("sha256").update(canonicalJson(value)).digest("hex");
|
|
39037
39655
|
}
|
|
39038
39656
|
function sameEvidenceDetail(detail, taskId, result, impacts, eventKey, beliefOwner) {
|
|
39039
39657
|
const storedOwner = detail.beliefOwner;
|
|
@@ -41111,7 +41729,7 @@ function createTaskLifecycleService(deps) {
|
|
|
41111
41729
|
}
|
|
41112
41730
|
|
|
41113
41731
|
// src/services/TaskExecutionService.ts
|
|
41114
|
-
var
|
|
41732
|
+
var import_node_crypto13 = require("crypto");
|
|
41115
41733
|
var import_node_util3 = require("util");
|
|
41116
41734
|
var import_protocols32 = require("@axiom-lattice/protocols");
|
|
41117
41735
|
|
|
@@ -41434,13 +42052,13 @@ async function reconcileAllTenantTaskRuns(input) {
|
|
|
41434
42052
|
}
|
|
41435
42053
|
|
|
41436
42054
|
// src/services/taskRunLease.ts
|
|
41437
|
-
var
|
|
42055
|
+
var import_node_crypto12 = require("crypto");
|
|
41438
42056
|
function taskRunLeaseKey(taskId) {
|
|
41439
42057
|
return `task-run:${taskId}`;
|
|
41440
42058
|
}
|
|
41441
42059
|
async function tryAcquireTaskRun(input) {
|
|
41442
42060
|
const key5 = taskRunLeaseKey(input.taskId);
|
|
41443
|
-
const holder = `${input.owner}#${(0,
|
|
42061
|
+
const holder = `${input.owner}#${(0, import_node_crypto12.randomUUID)()}`;
|
|
41444
42062
|
if (!await input.store.tryAcquire(key5, holder, input.ttlMs)) return null;
|
|
41445
42063
|
const heartbeatMs = input.heartbeatMs ?? Math.max(1e3, Math.floor(input.ttlMs / 3));
|
|
41446
42064
|
let released = false;
|
|
@@ -41807,11 +42425,11 @@ function createTaskExecutionService(deps) {
|
|
|
41807
42425
|
let threadId;
|
|
41808
42426
|
let runId;
|
|
41809
42427
|
try {
|
|
41810
|
-
threadId = storedThreadId ?? (deps.createThreadId ??
|
|
42428
|
+
threadId = storedThreadId ?? (deps.createThreadId ?? import_node_crypto13.randomUUID)();
|
|
41811
42429
|
if (task.status === "interrupted" && reuseCurrentRun) {
|
|
41812
42430
|
runId = storedRunId;
|
|
41813
42431
|
} else if (task.status === "interrupted" || task.status === "failed") {
|
|
41814
|
-
runId = (deps.createRunId ??
|
|
42432
|
+
runId = (deps.createRunId ?? import_node_crypto13.randomUUID)();
|
|
41815
42433
|
}
|
|
41816
42434
|
} catch (error) {
|
|
41817
42435
|
return {
|
|
@@ -42070,11 +42688,11 @@ function createTaskExecutionService(deps) {
|
|
|
42070
42688
|
}
|
|
42071
42689
|
|
|
42072
42690
|
// src/services/leadership.ts
|
|
42073
|
-
var
|
|
42691
|
+
var import_node_crypto14 = require("crypto");
|
|
42074
42692
|
async function runAsLeader(store, name, fn, options = {}) {
|
|
42075
42693
|
const key5 = `leader:${name}`;
|
|
42076
42694
|
const owner2 = options.owner ?? getReplicaId();
|
|
42077
|
-
const holder = `${owner2}#${(0,
|
|
42695
|
+
const holder = `${owner2}#${(0, import_node_crypto14.randomUUID)()}`;
|
|
42078
42696
|
const ttlMs = options.ttlMs ?? 6e4;
|
|
42079
42697
|
if (!await store.tryAcquire(key5, holder, ttlMs)) return { ran: false };
|
|
42080
42698
|
const heartbeat = setInterval(() => {
|
|
@@ -43307,16 +43925,16 @@ function createAskUserToClarifyTool() {
|
|
|
43307
43925
|
}
|
|
43308
43926
|
|
|
43309
43927
|
// src/middlewares/askUserClarifyMiddleware.ts
|
|
43310
|
-
function
|
|
43928
|
+
function isRecord10(value) {
|
|
43311
43929
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43312
43930
|
}
|
|
43313
43931
|
function isProjectRoomRun(request) {
|
|
43314
|
-
if (!
|
|
43932
|
+
if (!isRecord10(request) || !isRecord10(request.runtime)) return false;
|
|
43315
43933
|
const runtime = request.runtime;
|
|
43316
|
-
const configurable =
|
|
43317
|
-
const context =
|
|
43318
|
-
const runConfig =
|
|
43319
|
-
return
|
|
43934
|
+
const configurable = isRecord10(runtime.configurable) ? runtime.configurable.runConfig : void 0;
|
|
43935
|
+
const context = isRecord10(runtime.context) ? runtime.context.runConfig : void 0;
|
|
43936
|
+
const runConfig = isRecord10(configurable) ? configurable : isRecord10(context) ? context : void 0;
|
|
43937
|
+
return isRecord10(runConfig?.projectRoom);
|
|
43320
43938
|
}
|
|
43321
43939
|
function createAskUserClarifyMiddleware() {
|
|
43322
43940
|
return (0, import_langchain79.createMiddleware)({
|
|
@@ -44756,15 +45374,16 @@ function executorString(value) {
|
|
|
44756
45374
|
}
|
|
44757
45375
|
async function renderAvailableExecutors(rc, tenantId2) {
|
|
44758
45376
|
const authority = classifyTaskAuthority(rc);
|
|
44759
|
-
const
|
|
44760
|
-
const
|
|
44761
|
-
const
|
|
45377
|
+
const trusted = authority.kind === "projectRoom" || authority.kind === "projectTask" ? authority.trusted : void 0;
|
|
45378
|
+
const useRoster = trusted !== void 0 && !trustedRosterExempt(trusted);
|
|
45379
|
+
const projectId = trusted ? (trusted.projectTask ?? trusted.projectRoom)?.projectId : void 0;
|
|
45380
|
+
const cacheKey = `${tenantId2}:${useRoster ? `project:${projectId ?? ""}` : "tenant"}`;
|
|
44762
45381
|
const cached2 = executorCache.get(cacheKey);
|
|
44763
45382
|
const now = Date.now();
|
|
44764
45383
|
if (cached2 && now - cached2.at < EXECUTOR_CACHE_TTL_MS) return cached2.text;
|
|
44765
45384
|
const lines = [];
|
|
44766
45385
|
try {
|
|
44767
|
-
if (
|
|
45386
|
+
if (useRoster && projectId) {
|
|
44768
45387
|
const store = getStoreLattice("default", "projectBotMembership").store;
|
|
44769
45388
|
if (typeof store.list === "function") {
|
|
44770
45389
|
const bots = await store.list(tenantId2, projectId);
|
|
@@ -44779,11 +45398,15 @@ async function renderAvailableExecutors(rc, tenantId2) {
|
|
|
44779
45398
|
}
|
|
44780
45399
|
}
|
|
44781
45400
|
} else {
|
|
45401
|
+
const exempt = trusted !== void 0 && trustedRosterExempt(trusted) ? trusted : void 0;
|
|
45402
|
+
const excluded = exempt ? await excludedRosterExecutors(exempt) : /* @__PURE__ */ new Set();
|
|
44782
45403
|
const configs = await agentLatticeManager.getAllAgentConfigsByTenant(tenantId2);
|
|
44783
45404
|
for (const config of configs.slice(0, 40)) {
|
|
44784
45405
|
const row = config;
|
|
44785
45406
|
const id = executorString(row.key);
|
|
44786
45407
|
if (!id) continue;
|
|
45408
|
+
if (row.ownerUserId !== void 0) continue;
|
|
45409
|
+
if (excluded.has(id)) continue;
|
|
44787
45410
|
const name = executorString(row.name);
|
|
44788
45411
|
const description = executorString(row.description);
|
|
44789
45412
|
lines.push(`- ${id}${name ? ` \u2014 ${name}` : ""}${description ? ` (${description.slice(0, 120)})` : ""}`);
|
|
@@ -44795,7 +45418,7 @@ async function renderAvailableExecutors(rc, tenantId2) {
|
|
|
44795
45418
|
executorCache.set(cacheKey, { at: now, text: "" });
|
|
44796
45419
|
return "";
|
|
44797
45420
|
}
|
|
44798
|
-
const header =
|
|
45421
|
+
const header = useRoster ? "## Available task executors (Project roster)" : "## Available task executors";
|
|
44799
45422
|
const text = `
|
|
44800
45423
|
|
|
44801
45424
|
${header}
|
|
@@ -44807,6 +45430,22 @@ ${lines.join("\n")}
|
|
|
44807
45430
|
executorCache.set(cacheKey, { at: now, text });
|
|
44808
45431
|
return text;
|
|
44809
45432
|
}
|
|
45433
|
+
async function excludedRosterExecutors(trusted) {
|
|
45434
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
45435
|
+
const context = trusted.projectTask ?? trusted.projectRoom;
|
|
45436
|
+
if (!context) return excluded;
|
|
45437
|
+
try {
|
|
45438
|
+
const store = getStoreLattice("default", "projectBotMembership").store;
|
|
45439
|
+
if (typeof store.list !== "function") return excluded;
|
|
45440
|
+
const rows = await store.list(context.tenantId, context.projectId);
|
|
45441
|
+
for (const row of Array.isArray(rows) ? rows : []) {
|
|
45442
|
+
const record = row;
|
|
45443
|
+
if (record.status !== "active" && typeof record.assistantId === "string") excluded.add(record.assistantId);
|
|
45444
|
+
}
|
|
45445
|
+
} catch {
|
|
45446
|
+
}
|
|
45447
|
+
return excluded;
|
|
45448
|
+
}
|
|
44810
45449
|
function delegatedTaskScopeError(taskId) {
|
|
44811
45450
|
return JSON.stringify({
|
|
44812
45451
|
success: false,
|
|
@@ -44856,7 +45495,7 @@ function trustedRosterScope(trusted) {
|
|
|
44856
45495
|
};
|
|
44857
45496
|
}
|
|
44858
45497
|
function trustedRosterExempt(trusted) {
|
|
44859
|
-
return trusted.projectTask?.rosterExempt === true;
|
|
45498
|
+
return trusted.projectTask?.rosterExempt === true || trusted.projectRoom?.rosterExempt === true;
|
|
44860
45499
|
}
|
|
44861
45500
|
async function requireTrustedOwner(trusted, targetAssistantId) {
|
|
44862
45501
|
const context = trusted.projectTask ?? trusted.projectRoom;
|
|
@@ -44872,6 +45511,17 @@ async function requireTrustedOwner(trusted, targetAssistantId) {
|
|
|
44872
45511
|
targetAssistantId
|
|
44873
45512
|
});
|
|
44874
45513
|
}
|
|
45514
|
+
async function rosterExemptOwnerError(tenantId2, targetAssistantId) {
|
|
45515
|
+
try {
|
|
45516
|
+
const lattice = await agentLatticeManager.getOrLoadWithTenant(tenantId2, targetAssistantId);
|
|
45517
|
+
if (lattice && lattice.config.ownerUserId === void 0) return void 0;
|
|
45518
|
+
} catch {
|
|
45519
|
+
}
|
|
45520
|
+
return projectPolicyError(new ProjectTaskOwnerPolicyError(
|
|
45521
|
+
"PROJECT_TASK_OWNER_INACTIVE",
|
|
45522
|
+
"Target Project task owner is not a shared agent of this tenant."
|
|
45523
|
+
));
|
|
45524
|
+
}
|
|
44875
45525
|
function trustedTaskContextFailure(task, trusted) {
|
|
44876
45526
|
if (task.tenantId === trusted.tenantId && task.workspaceId === trusted.workspaceId && task.projectId === trusted.projectId) return void 0;
|
|
44877
45527
|
return JSON.stringify({
|
|
@@ -45476,6 +46126,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
45476
46126
|
"Target Project task owner is not active in the exact roster."
|
|
45477
46127
|
));
|
|
45478
46128
|
}
|
|
46129
|
+
} else {
|
|
46130
|
+
const ownerError = await rosterExemptOwnerError(
|
|
46131
|
+
(trustedProject.projectTask ?? trustedProject.projectRoom)?.tenantId ?? tenantId2,
|
|
46132
|
+
ownerId
|
|
46133
|
+
);
|
|
46134
|
+
if (ownerError) return ownerError;
|
|
45479
46135
|
}
|
|
45480
46136
|
}
|
|
45481
46137
|
if (!delegatedTaskId && (typeof effectiveOwnerId !== "string" || effectiveOwnerId.length === 0)) {
|
|
@@ -45537,6 +46193,12 @@ function createTaskMiddleware(options = {}) {
|
|
|
45537
46193
|
} catch (error) {
|
|
45538
46194
|
return projectPolicyError(error);
|
|
45539
46195
|
}
|
|
46196
|
+
} else {
|
|
46197
|
+
const ownerError = await rosterExemptOwnerError(
|
|
46198
|
+
(trustedProject.projectTask ?? trustedProject.projectRoom)?.tenantId ?? tenantId2,
|
|
46199
|
+
ownerId
|
|
46200
|
+
);
|
|
46201
|
+
if (ownerError) return ownerError;
|
|
45540
46202
|
}
|
|
45541
46203
|
}
|
|
45542
46204
|
return store.create({
|
|
@@ -46584,7 +47246,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
46584
47246
|
}
|
|
46585
47247
|
const callerAssistantId = rc.assistant_id;
|
|
46586
47248
|
const agentId = input.agentId === "general-purpose" && callerAssistantId ? `${callerAssistantId}-general-purpose` : input.agentId;
|
|
46587
|
-
const
|
|
47249
|
+
const service3 = createTaskExecutionService({
|
|
46588
47250
|
taskStore: getTaskStore(),
|
|
46589
47251
|
workItemStore: getTaskWorkItemStore(),
|
|
46590
47252
|
resolveAgent: async (targetTenantId, agentId2) => !!await agentLatticeManager.getOrLoadWithTenant(targetTenantId, agentId2),
|
|
@@ -46609,7 +47271,7 @@ function createTaskMiddleware(options = {}) {
|
|
|
46609
47271
|
}
|
|
46610
47272
|
});
|
|
46611
47273
|
const trustedCaller = authority.kind === "projectTask" || authority.kind === "projectRoom" ? authority.trusted.projectTask ?? authority.trusted.projectRoom : void 0;
|
|
46612
|
-
return JSON.stringify(await
|
|
47274
|
+
return JSON.stringify(await service3.start({
|
|
46613
47275
|
tenantId: tenantId2,
|
|
46614
47276
|
workspaceId: rc.workspaceId,
|
|
46615
47277
|
projectId: rc.projectId,
|
|
@@ -48126,6 +48788,24 @@ function snapshotMembership3(value) {
|
|
|
48126
48788
|
function snapshotRows(value) {
|
|
48127
48789
|
return (0, import_protocols37.snapshotExactArray)(value) ?? [];
|
|
48128
48790
|
}
|
|
48791
|
+
async function rosterExemptMembershipProjection(scope) {
|
|
48792
|
+
const excluded = /* @__PURE__ */ new Set();
|
|
48793
|
+
const roles = /* @__PURE__ */ new Map();
|
|
48794
|
+
try {
|
|
48795
|
+
const rows = snapshotRows(await getStoreLattice("default", "projectBotMembership").store.list(scope.tenantId, scope.projectId));
|
|
48796
|
+
for (const row of rows) {
|
|
48797
|
+
const member = snapshotMembership3(row);
|
|
48798
|
+
if (!member) continue;
|
|
48799
|
+
if (member.status !== "active") {
|
|
48800
|
+
excluded.add(member.assistantId);
|
|
48801
|
+
continue;
|
|
48802
|
+
}
|
|
48803
|
+
roles.set(member.assistantId, member.role);
|
|
48804
|
+
}
|
|
48805
|
+
} catch {
|
|
48806
|
+
}
|
|
48807
|
+
return { excluded, roles };
|
|
48808
|
+
}
|
|
48129
48809
|
async function hasActiveCurrentMembership(scope) {
|
|
48130
48810
|
const memberships = getStoreLattice("default", "projectBotMembership").store;
|
|
48131
48811
|
const member = snapshotMembership3(await memberships.findById(scope.tenantId, scope.membershipId));
|
|
@@ -48142,11 +48822,11 @@ function createProjectRoomMiddleware() {
|
|
|
48142
48822
|
if (!scope) return CONTEXT_REQUIRED;
|
|
48143
48823
|
const digest = (0, import_crypto10.createHash)("sha256").update(text).digest("hex");
|
|
48144
48824
|
try {
|
|
48145
|
-
const
|
|
48825
|
+
const service3 = new RoomAgentMessageService({
|
|
48146
48826
|
memberships: getStoreLattice("default", "projectBotMembership").store,
|
|
48147
48827
|
messages: getStoreLattice("default", "projectRoomMessage").store
|
|
48148
48828
|
});
|
|
48149
|
-
await
|
|
48829
|
+
await service3.post({
|
|
48150
48830
|
tenantId: scope.tenantId,
|
|
48151
48831
|
workspaceId: scope.workspaceId,
|
|
48152
48832
|
projectId: scope.projectId,
|
|
@@ -48172,6 +48852,25 @@ function createProjectRoomMiddleware() {
|
|
|
48172
48852
|
if (!scope) return CONTEXT_REQUIRED;
|
|
48173
48853
|
try {
|
|
48174
48854
|
if (!await hasActiveCurrentMembership(scope)) return CONTEXT_REQUIRED;
|
|
48855
|
+
if (scope.rosterExempt === true) {
|
|
48856
|
+
const { excluded, roles } = await rosterExemptMembershipProjection(scope);
|
|
48857
|
+
const configs = await agentLatticeManager.getAllAgentConfigsByTenant(scope.tenantId);
|
|
48858
|
+
const members2 = configs.filter((entry) => entry.ownerUserId === void 0).filter((entry) => {
|
|
48859
|
+
const key5 = entry.key;
|
|
48860
|
+
return typeof key5 === "string" && !excluded.has(key5);
|
|
48861
|
+
}).map((entry) => {
|
|
48862
|
+
const row = entry;
|
|
48863
|
+
const name = typeof row.name === "string" ? row.name : "";
|
|
48864
|
+
const assistantId = typeof row.key === "string" ? row.key : "";
|
|
48865
|
+
return {
|
|
48866
|
+
assistantId,
|
|
48867
|
+
mentionName: name,
|
|
48868
|
+
title: name,
|
|
48869
|
+
role: roles.get(assistantId) ?? "specialist"
|
|
48870
|
+
};
|
|
48871
|
+
}).filter((member) => member.assistantId !== "" && member.mentionName !== "").sort((left, right) => left.assistantId < right.assistantId ? -1 : left.assistantId > right.assistantId ? 1 : 0);
|
|
48872
|
+
return JSON.stringify({ success: true, members: members2 });
|
|
48873
|
+
}
|
|
48175
48874
|
const rows = await getStoreLattice("default", "projectBotMembership").store.list(scope.tenantId, scope.projectId);
|
|
48176
48875
|
const members = snapshotRows(rows).map(snapshotMembership3).filter((member) => member !== void 0 && member.status === "active" && member.tenantId === scope.tenantId && member.workspaceId === scope.workspaceId && member.projectId === scope.projectId && member.roomId === scope.roomId).sort((left, right) => left.joinedAt.getTime() - right.joinedAt.getTime() || (left.id < right.id ? -1 : left.id > right.id ? 1 : 0)).map((member) => ({
|
|
48177
48876
|
assistantId: member.assistantId,
|
|
@@ -48274,13 +48973,13 @@ var TEST_TEMPLATE = `const data = process.env.PLUGIN_CONNECTION_FILE
|
|
|
48274
48973
|
: {};
|
|
48275
48974
|
const conn = data.connection ?? data.connections?.[0]?.config ?? {};
|
|
48276
48975
|
const message = conn.apiKey ? "ok" : "missing apiKey";
|
|
48277
|
-
process.stdout.write(JSON.stringify({ ok: Boolean(conn.apiKey), message }));
|
|
48976
|
+
process.stdout.write(JSON.stringify({ ok: true, result: { ok: Boolean(conn.apiKey), message } }));
|
|
48278
48977
|
`;
|
|
48279
48978
|
var DISCOVER_TEMPLATE = `const data = process.env.PLUGIN_CONNECTION_FILE
|
|
48280
48979
|
? JSON.parse(require("fs").readFileSync(process.env.PLUGIN_CONNECTION_FILE, "utf8"))
|
|
48281
48980
|
: {};
|
|
48282
48981
|
const conn = data.connection ?? data.connections?.[0]?.config ?? {};
|
|
48283
|
-
process.stdout.write(JSON.stringify([{ id: "sample", name: "Sample resource" }]));
|
|
48982
|
+
process.stdout.write(JSON.stringify({ ok: true, result: [{ id: "sample", name: "Sample resource" }] }));
|
|
48284
48983
|
`;
|
|
48285
48984
|
var UI_TEMPLATE = `<!doctype html>
|
|
48286
48985
|
<html>
|
|
@@ -48833,7 +49532,7 @@ captured).
|
|
|
48833
49532
|
}
|
|
48834
49533
|
},
|
|
48835
49534
|
"sandbox-plugins-connection": {
|
|
48836
|
-
version: "1.
|
|
49535
|
+
version: "1.1.0",
|
|
48837
49536
|
content: `---
|
|
48838
49537
|
name: sandbox-plugins-connection
|
|
48839
49538
|
description: Define connection fields and test/discover handlers for a tenant sandbox plugin. Trigger: plugin needs credentials or resource discovery.
|
|
@@ -48849,17 +49548,20 @@ The resolved connection is injected at execution time as an
|
|
|
48849
49548
|
\`PLUGIN_CONNECTION_FILE\` (never inline; credentials stay out of argv). It is never hardcoded.
|
|
48850
49549
|
|
|
48851
49550
|
## test handler
|
|
48852
|
-
Print \`{ ok, message }\`:
|
|
49551
|
+
Print the two-level result envelope \`{ ok, result: { ok, message } }\`: the outer
|
|
49552
|
+
\`ok\` means the handler ran, the inner \`ok\`/\`message\` is the connection verdict.
|
|
49553
|
+
Put extra diagnostics under \`result.details\`. A single-level \`{ ok, message }\`
|
|
49554
|
+
is rejected as an invalid result.
|
|
48853
49555
|
\`\`\`js
|
|
48854
49556
|
const data = JSON.parse(require("fs").readFileSync(process.env.PLUGIN_CONNECTION_FILE, "utf8"));
|
|
48855
49557
|
const conn = data.connection ?? data.connections?.[0]?.config ?? {};
|
|
48856
|
-
process.stdout.write(JSON.stringify({ ok: Boolean(conn.apiKey), message: conn.apiKey ? "ok" : "missing apiKey" }));
|
|
49558
|
+
process.stdout.write(JSON.stringify({ ok: true, result: { ok: Boolean(conn.apiKey), message: conn.apiKey ? "ok" : "missing apiKey" } }));
|
|
48857
49559
|
\`\`\`
|
|
48858
49560
|
|
|
48859
49561
|
## discover handler
|
|
48860
|
-
Print
|
|
49562
|
+
Print \`{ ok: true, result: [ ...resources ] }\`:
|
|
48861
49563
|
\`\`\`js
|
|
48862
|
-
process.stdout.write(JSON.stringify([{ id: "a", name: "A", group: "G" }]));
|
|
49564
|
+
process.stdout.write(JSON.stringify({ ok: true, result: [{ id: "a", name: "A", group: "G" }] }));
|
|
48863
49565
|
\`\`\`
|
|
48864
49566
|
|
|
48865
49567
|
Set \`connection.resourceLabel\` for the selection panel title.
|
|
@@ -48916,6 +49618,70 @@ Fall back to \`execute_code\`/\`shell\` to run \`node handlers/x.js\` manually w
|
|
|
48916
49618
|
\`PLUGIN_INPUT\` and a synthetic \`PLUGIN_CONNECTION_FILE\` to reproduce logic bugs.
|
|
48917
49619
|
A synthetic fixture only verifies plumbing \u2014 a real upstream call requires a real
|
|
48918
49620
|
\`connectionKey\` configured by a human.
|
|
49621
|
+
`,
|
|
49622
|
+
resources: {}
|
|
49623
|
+
},
|
|
49624
|
+
"sandbox-plugins-deploy": {
|
|
49625
|
+
version: "1.0.0",
|
|
49626
|
+
content: `---
|
|
49627
|
+
name: sandbox-plugins-deploy
|
|
49628
|
+
description: Deploy a validated tenant plugin as a resident service (alwaysOn vs onDemand), check its status, and undeploy it. Trigger: after a plugin's tests pass and it should run as a long-lived service, or when inspecting/removing a deployment.
|
|
49629
|
+
---
|
|
49630
|
+
|
|
49631
|
+
# Deploying a Plugin as a Resident Service
|
|
49632
|
+
|
|
49633
|
+
By default a plugin handler runs as a short-lived process on each tool call.
|
|
49634
|
+
Optionally, you can **deploy** the plugin as a **resident service**: one
|
|
49635
|
+
long-lived sandbox per plugin that serves every call. This is faster for
|
|
49636
|
+
frequent or heavy calls, but costs a running sandbox.
|
|
49637
|
+
|
|
49638
|
+
## Precondition: tests must pass first
|
|
49639
|
+
Deploy ONLY after the plugin is validated AND its tests pass:
|
|
49640
|
+
1. \`manage_plugin validate\` \u2014 no diagnostics.
|
|
49641
|
+
2. \`manage_plugin create\`/\`update\` \u2014 written and reloaded.
|
|
49642
|
+
3. \`manage_plugin test\` \u2014 every tool/connection test returns \`ok: true\`
|
|
49643
|
+
(a real \`connectionKey\` test for credentialed tools).
|
|
49644
|
+
Never deploy a plugin you have not tested: a resident service wraps the same
|
|
49645
|
+
handlers, so an untested handler fails identically \u2014 just in a service you now
|
|
49646
|
+
have to undeploy.
|
|
49647
|
+
|
|
49648
|
+
## Choose a mode
|
|
49649
|
+
- \`"onDemand"\` (default) \u2014 the service is paused when idle and resumed on the
|
|
49650
|
+
next call. Best for plugins used occasionally. Lower steady cost.
|
|
49651
|
+
- \`"alwaysOn"\` \u2014 the service stays resident and is restarted if it becomes
|
|
49652
|
+
unhealthy. Best for plugins on a hot path or with expensive startup.
|
|
49653
|
+
|
|
49654
|
+
## Deploy
|
|
49655
|
+
\`\`\`jsonc
|
|
49656
|
+
{ "action": "deploy", "type": "my-plugin", "mode": "alwaysOn" }
|
|
49657
|
+
\`\`\`
|
|
49658
|
+
Returns \`{ deployed, status, endpoint, mode }\`. \`status\` is \`"running"\` when
|
|
49659
|
+
the service answered its health check. On failure you get
|
|
49660
|
+
\`{ deployed: false, error }\` \u2014 report it, do not treat it as success.
|
|
49661
|
+
Deploying again is idempotent: it reuses the same service.
|
|
49662
|
+
|
|
49663
|
+
## Check status
|
|
49664
|
+
\`\`\`jsonc
|
|
49665
|
+
{ "action": "status", "type": "my-plugin" }
|
|
49666
|
+
\`\`\`
|
|
49667
|
+
Returns \`{ status, endpoint?, mode?, lastHealthAt?, lastError? }\`. \`"absent"\`
|
|
49668
|
+
means no deployment exists; \`"failed"\` (with \`lastError\`) means the service is
|
|
49669
|
+
down. Inspect this before reporting the plugin as serving.
|
|
49670
|
+
|
|
49671
|
+
## Undeploy
|
|
49672
|
+
\`\`\`jsonc
|
|
49673
|
+
{ "action": "undeploy", "type": "my-plugin" }
|
|
49674
|
+
\`\`\`
|
|
49675
|
+
Returns \`{ undeployed }\`. Undeploy removes the resident sandbox and its
|
|
49676
|
+
deployment record; the plugin files and manifest are untouched, so tool calls
|
|
49677
|
+
fall back to the short-process path. Use it to stop paying for a service you no
|
|
49678
|
+
longer need.
|
|
49679
|
+
|
|
49680
|
+
## When resident services are unavailable
|
|
49681
|
+
If the environment has no deployment service registered, deploy/undeploy/status
|
|
49682
|
+
return a diagnostic (\`{ deployed: false, error }\` etc.) instead of throwing.
|
|
49683
|
+
That is not a plugin defect: the plugin still works through the default
|
|
49684
|
+
short-process path, so report it as not-deployed rather than broken.
|
|
48919
49685
|
`,
|
|
48920
49686
|
resources: {}
|
|
48921
49687
|
}
|
|
@@ -48952,9 +49718,197 @@ the connector and give you its key. Only after a real \`connectionKey\` test
|
|
|
48952
49718
|
passes may you call the tool verified; without it, report functionality as
|
|
48953
49719
|
unverified (missing credentials), not as passing. Use \`shell_exec\` (the tool
|
|
48954
49720
|
provided by the \`code_eval\` middleware) to run \`node handlers/x.js\` for manual
|
|
48955
|
-
checks when reproducing a failure
|
|
49721
|
+
checks when reproducing a failure.
|
|
49722
|
+
|
|
49723
|
+
After the plugin passes \`validate\` and its tests, deploy it as a resident
|
|
49724
|
+
service: load "sandbox-plugins-deploy" and follow it. Choose \`onDemand\`
|
|
49725
|
+
(default) or \`alwaysOn\` for hot paths, call \`manage_plugin deploy\` with the
|
|
49726
|
+
chosen \`mode\`, then confirm with \`manage_plugin status\` (\`running\`). Only claim
|
|
49727
|
+
the plugin is deployed and serving once \`status\` reports \`running\`; if the
|
|
49728
|
+
environment reports no deployment service, say so and treat deployment as
|
|
49729
|
+
unavailable \u2014 do NOT claim success. \`undeploy\` removes the service without
|
|
49730
|
+
touching the plugin files.`;
|
|
49731
|
+
|
|
49732
|
+
// src/middlewares/sandboxPluginsUi.ts
|
|
49733
|
+
var SANDBOX_PLUGINS_UI_RESOURCE = "ui://sandbox-plugins/app";
|
|
49734
|
+
var SANDBOX_PLUGINS_APP_HTML = `<!doctype html>
|
|
49735
|
+
<html lang="en">
|
|
49736
|
+
<head>
|
|
49737
|
+
<meta charset="utf-8" />
|
|
49738
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
49739
|
+
<title>Plugin Deployments</title>
|
|
49740
|
+
<style>
|
|
49741
|
+
:root { color-scheme: light dark; }
|
|
49742
|
+
* { box-sizing: border-box; }
|
|
49743
|
+
body {
|
|
49744
|
+
margin: 0;
|
|
49745
|
+
padding: 14px 16px;
|
|
49746
|
+
font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
49747
|
+
font-size: 13px;
|
|
49748
|
+
color: #1f2430;
|
|
49749
|
+
background: transparent;
|
|
49750
|
+
}
|
|
49751
|
+
h1 { font-size: 14px; font-weight: 600; margin: 0 0 2px; }
|
|
49752
|
+
.subtitle { color: #6b7280; font-size: 12px; margin: 0 0 12px; }
|
|
49753
|
+
table { width: 100%; border-collapse: collapse; }
|
|
49754
|
+
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid #eceef2; vertical-align: top; }
|
|
49755
|
+
th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: #6b7280; font-weight: 600; }
|
|
49756
|
+
td.type { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; white-space: nowrap; }
|
|
49757
|
+
td.mode { white-space: nowrap; color: #4b5563; }
|
|
49758
|
+
td.detail { color: #4b5563; word-break: break-word; max-width: 280px; }
|
|
49759
|
+
.muted { color: #9ca3af; }
|
|
49760
|
+
.status { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
|
|
49761
|
+
.dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; background: #9ca3af; }
|
|
49762
|
+
.dot.running { background: #22c55e; }
|
|
49763
|
+
.dot.failed { background: #ef4444; }
|
|
49764
|
+
.dot.requested, .dot.provisioning, .dot.stopping { background: #f59e0b; }
|
|
49765
|
+
.dot.paused, .dot.stopped { background: #94a3b8; }
|
|
49766
|
+
.state { color: #6b7280; padding: 14px 2px; }
|
|
49767
|
+
.error { margin: 0 0 10px; padding: 8px 10px; border-radius: 8px; background: #fef2f2; color: #b91c1c; }
|
|
49768
|
+
</style>
|
|
49769
|
+
</head>
|
|
49770
|
+
<body>
|
|
49771
|
+
<h1>Plugin Deployments</h1>
|
|
49772
|
+
<p class="subtitle">Resident services deployed for this tenant. Read-only.</p>
|
|
49773
|
+
<div id="root"><p class="state">Loading\u2026</p></div>
|
|
49774
|
+
<script>
|
|
49775
|
+
(function () {
|
|
49776
|
+
var root = document.getElementById("root");
|
|
49777
|
+
|
|
49778
|
+
function post(message) {
|
|
49779
|
+
window.parent.postMessage(message, "*");
|
|
49780
|
+
}
|
|
49781
|
+
function notify(method, params) {
|
|
49782
|
+
post({ jsonrpc: "2.0", method: method, params: params });
|
|
49783
|
+
}
|
|
49784
|
+
var nextId = 1;
|
|
49785
|
+
function rpc(method, params) {
|
|
49786
|
+
var id = nextId++;
|
|
49787
|
+
return new Promise(function (resolve, reject) {
|
|
49788
|
+
function onMessage(event) {
|
|
49789
|
+
var data = event.data;
|
|
49790
|
+
if (!data || data.id !== id) return;
|
|
49791
|
+
window.removeEventListener("message", onMessage);
|
|
49792
|
+
if (data.error) reject(new Error((data.error && data.error.message) || "rpc error"));
|
|
49793
|
+
else resolve(data.result);
|
|
49794
|
+
}
|
|
49795
|
+
window.addEventListener("message", onMessage);
|
|
49796
|
+
post({ jsonrpc: "2.0", id: id, method: method, params: params });
|
|
49797
|
+
});
|
|
49798
|
+
}
|
|
49799
|
+
|
|
49800
|
+
function sendSize() {
|
|
49801
|
+
var width = Math.ceil(document.documentElement.scrollWidth || document.body.scrollWidth);
|
|
49802
|
+
var height = Math.ceil(document.documentElement.scrollHeight || document.body.scrollHeight);
|
|
49803
|
+
notify("ui/notifications/size-changed", { width: width, height: height });
|
|
49804
|
+
}
|
|
49805
|
+
|
|
49806
|
+
function esc(value) {
|
|
49807
|
+
return String(value === null || value === undefined ? "" : value).replace(/[&<>"']/g, function (ch) {
|
|
49808
|
+
return { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[ch];
|
|
49809
|
+
});
|
|
49810
|
+
}
|
|
49811
|
+
|
|
49812
|
+
function statusClass(status) {
|
|
49813
|
+
switch (status) {
|
|
49814
|
+
case "running": return "running";
|
|
49815
|
+
case "failed": return "failed";
|
|
49816
|
+
case "requested":
|
|
49817
|
+
case "provisioning":
|
|
49818
|
+
case "stopping": return "requested";
|
|
49819
|
+
case "paused":
|
|
49820
|
+
case "stopped": return "paused";
|
|
49821
|
+
default: return "";
|
|
49822
|
+
}
|
|
49823
|
+
}
|
|
49824
|
+
|
|
49825
|
+
function healthCell(item) {
|
|
49826
|
+
if (item.lastError) return '<span style="color:#b91c1c">' + esc(item.lastError) + "</span>";
|
|
49827
|
+
if (item.lastHealthAt) return '<span class="muted">' + esc(item.lastHealthAt) + "</span>";
|
|
49828
|
+
return '<span class="muted">\u2014</span>';
|
|
49829
|
+
}
|
|
49830
|
+
|
|
49831
|
+
function render(payload) {
|
|
49832
|
+
var deployments = payload && Array.isArray(payload.deployments) ? payload.deployments : [];
|
|
49833
|
+
var error = payload && payload.error ? String(payload.error) : "";
|
|
49834
|
+
var html = "";
|
|
49835
|
+
if (error) html += '<div class="error">' + esc(error) + "</div>";
|
|
49836
|
+
if (deployments.length === 0) {
|
|
49837
|
+
html += '<p class="state">' + (error ? "No deployments available." : "No resident plugin deployments.") + "</p>";
|
|
49838
|
+
root.innerHTML = html;
|
|
49839
|
+
sendSize();
|
|
49840
|
+
return;
|
|
49841
|
+
}
|
|
49842
|
+
html += "<table><thead><tr><th>Plugin</th><th>Status</th><th>Mode</th><th>Endpoint</th><th>Health</th></tr></thead><tbody>";
|
|
49843
|
+
deployments.forEach(function (item) {
|
|
49844
|
+
var status = item && item.status ? String(item.status) : "unknown";
|
|
49845
|
+
html += "<tr>";
|
|
49846
|
+
html += '<td class="type">' + esc(item && item.pluginType) + "</td>";
|
|
49847
|
+
html += '<td><span class="status"><span class="dot ' + statusClass(status) + '"></span>' + esc(status) + "</span></td>";
|
|
49848
|
+
html += '<td class="mode">' + esc(item && item.mode) + "</td>";
|
|
49849
|
+
html += '<td class="detail">' + (item && item.endpoint ? esc(item.endpoint) : '<span class="muted">\u2014</span>') + "</td>";
|
|
49850
|
+
html += '<td class="detail">' + healthCell(item || {}) + "</td>";
|
|
49851
|
+
html += "</tr>";
|
|
49852
|
+
});
|
|
49853
|
+
html += "</tbody></table>";
|
|
49854
|
+
root.innerHTML = html;
|
|
49855
|
+
sendSize();
|
|
49856
|
+
}
|
|
49857
|
+
|
|
49858
|
+
function readResult(params) {
|
|
49859
|
+
if (!params || typeof params !== "object") return null;
|
|
49860
|
+
if (params.structuredContent && typeof params.structuredContent === "object") {
|
|
49861
|
+
return params.structuredContent;
|
|
49862
|
+
}
|
|
49863
|
+
var content = params.content;
|
|
49864
|
+
var text = content && content[0] && typeof content[0].text === "string" ? content[0].text : "";
|
|
49865
|
+
if (!text) return null;
|
|
49866
|
+
try { return JSON.parse(text); } catch (err) { return null; }
|
|
49867
|
+
}
|
|
49868
|
+
|
|
49869
|
+
// 1) Register the tool-result listener BEFORE initializing so the data
|
|
49870
|
+
// the host pushes right after the handshake is never missed.
|
|
49871
|
+
window.addEventListener("message", function (event) {
|
|
49872
|
+
var data = event.data;
|
|
49873
|
+
if (!data || typeof data !== "object" || typeof data.method !== "string") return;
|
|
49874
|
+
if (data.method === "ui/notifications/tool-result") {
|
|
49875
|
+
render(readResult(data.params));
|
|
49876
|
+
}
|
|
49877
|
+
});
|
|
49878
|
+
|
|
49879
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
49880
|
+
new ResizeObserver(sendSize).observe(document.documentElement);
|
|
49881
|
+
} else {
|
|
49882
|
+
window.addEventListener("resize", sendSize);
|
|
49883
|
+
}
|
|
49884
|
+
|
|
49885
|
+
// 2) MCP Apps lifecycle: initialize, then signal readiness. The host
|
|
49886
|
+
// pushes tool data only after this completes.
|
|
49887
|
+
rpc("ui/initialize", {
|
|
49888
|
+
protocolVersion: "2025-06-18",
|
|
49889
|
+
capabilities: {},
|
|
49890
|
+
clientInfo: { name: "sandbox-plugins-ui", version: "1.0.0" },
|
|
49891
|
+
appCapabilities: { availableDisplayModes: ["inline"] }
|
|
49892
|
+
}).then(function () {
|
|
49893
|
+
notify("ui/notifications/initialized", {});
|
|
49894
|
+
sendSize();
|
|
49895
|
+
}).catch(function (err) {
|
|
49896
|
+
root.innerHTML = '<p class="state">Failed to initialize: ' + esc((err && err.message) || err) + "</p>";
|
|
49897
|
+
sendSize();
|
|
49898
|
+
});
|
|
49899
|
+
})();
|
|
49900
|
+
</script>
|
|
49901
|
+
</body>
|
|
49902
|
+
</html>
|
|
49903
|
+
`;
|
|
48956
49904
|
|
|
48957
49905
|
// src/middlewares/sandboxPluginsMiddleware.ts
|
|
49906
|
+
var SANDBOX_PLUGINS_UI_REF = {
|
|
49907
|
+
kind: "plugin",
|
|
49908
|
+
pluginType: "sandbox-plugins",
|
|
49909
|
+
resource: SANDBOX_PLUGINS_UI_RESOURCE,
|
|
49910
|
+
displayMode: "inline"
|
|
49911
|
+
};
|
|
48958
49912
|
var PLUGIN_BUILDER_SKILLS = [...Object.keys(SANDBOX_PLUGIN_SKILLS), "task-tracking"];
|
|
48959
49913
|
function tenantIdFrom(exeConfig) {
|
|
48960
49914
|
const c = exeConfig;
|
|
@@ -48972,6 +49926,15 @@ function collectSecretValues(connection, fields) {
|
|
|
48972
49926
|
function errorText(err) {
|
|
48973
49927
|
return err instanceof Error ? err.message : String(err);
|
|
48974
49928
|
}
|
|
49929
|
+
function deploymentUnavailable(action) {
|
|
49930
|
+
const error = `plugin deployment service is not configured; cannot ${action}. Resident plugin services are unavailable in this environment.`;
|
|
49931
|
+
if (action === "undeploy") return JSON.stringify({ undeployed: false, error });
|
|
49932
|
+
if (action === "status") return JSON.stringify({ status: "unavailable", error });
|
|
49933
|
+
return JSON.stringify({ deployed: false, error });
|
|
49934
|
+
}
|
|
49935
|
+
function deploymentsResult(payload) {
|
|
49936
|
+
return appendUiFence(JSON.stringify(payload), SANDBOX_PLUGINS_UI_REF);
|
|
49937
|
+
}
|
|
48975
49938
|
function redactString(value, secrets) {
|
|
48976
49939
|
let out = value;
|
|
48977
49940
|
for (const secret of secrets) out = out.split(secret).join("[redacted]");
|
|
@@ -48992,10 +49955,24 @@ function redactSecretValues(payload, secrets) {
|
|
|
48992
49955
|
return walk(payload);
|
|
48993
49956
|
}
|
|
48994
49957
|
var managePluginSchema = import_zod71.z.object({
|
|
48995
|
-
action: import_zod71.z.enum([
|
|
49958
|
+
action: import_zod71.z.enum([
|
|
49959
|
+
"list",
|
|
49960
|
+
"get",
|
|
49961
|
+
"validate",
|
|
49962
|
+
"create",
|
|
49963
|
+
"update",
|
|
49964
|
+
"delete",
|
|
49965
|
+
"reload",
|
|
49966
|
+
"test",
|
|
49967
|
+
"deploy",
|
|
49968
|
+
"undeploy",
|
|
49969
|
+
"status",
|
|
49970
|
+
"deployments"
|
|
49971
|
+
]),
|
|
48996
49972
|
type: import_zod71.z.string().optional(),
|
|
48997
49973
|
manifest: import_zod71.z.record(import_zod71.z.unknown()).optional(),
|
|
48998
49974
|
handlers: import_zod71.z.record(import_zod71.z.string()).optional(),
|
|
49975
|
+
mode: import_zod71.z.enum(["onDemand", "alwaysOn"]).optional(),
|
|
48999
49976
|
target: import_zod71.z.object({
|
|
49000
49977
|
kind: import_zod71.z.enum(["tool", "connection-test", "connection-discover"]),
|
|
49001
49978
|
name: import_zod71.z.string().optional(),
|
|
@@ -49008,9 +49985,18 @@ var sandboxPluginsPlugin = {
|
|
|
49008
49985
|
type: "sandbox-plugins",
|
|
49009
49986
|
category: "execution",
|
|
49010
49987
|
name: "Sandbox Plugins",
|
|
49011
|
-
description: "Author and manage tenant plugins stored in the sandbox: list/validate/create/update/delete/reload/test. Tools are agent-callable JS handlers and may declare an optional interactive HTML UI (rendered as a sandboxed MCP App). Pairs with the Skill plugin for authoring guidance.",
|
|
49988
|
+
description: "Author and manage tenant plugins stored in the sandbox: list/validate/create/update/delete/reload/test, and deploy/undeploy/status/deployments to run a plugin as a resident service. Tools are agent-callable JS handlers and may declare an optional interactive HTML UI (rendered as a sandboxed MCP App). Pairs with the Skill plugin for authoring guidance.",
|
|
49012
49989
|
recommends: ["skill"],
|
|
49013
|
-
tools: [
|
|
49990
|
+
tools: [
|
|
49991
|
+
{
|
|
49992
|
+
name: "manage_plugin",
|
|
49993
|
+
description: "Author and manage tenant sandbox plugins (tools, optional per-tool HTML UI, connections, Open/MCP exposure, and resident deployment). Actions: list/get/validate/create/update/delete/reload/test, deploy/undeploy/status, and `deployments` to list every resident deployment for the tenant.",
|
|
49994
|
+
ui: { resource: SANDBOX_PLUGINS_UI_RESOURCE, displayMode: "inline" }
|
|
49995
|
+
}
|
|
49996
|
+
],
|
|
49997
|
+
uiResources: {
|
|
49998
|
+
[SANDBOX_PLUGINS_UI_RESOURCE]: { html: SANDBOX_PLUGINS_APP_HTML }
|
|
49999
|
+
},
|
|
49014
50000
|
configSchema: { type: "object", properties: {} },
|
|
49015
50001
|
defaultConfig: {}
|
|
49016
50002
|
},
|
|
@@ -49031,7 +50017,7 @@ var sandboxPluginsPlugin = {
|
|
|
49031
50017
|
id: "sandbox-plugins",
|
|
49032
50018
|
type: "sandbox-plugins",
|
|
49033
50019
|
name: "Sandbox Plugins",
|
|
49034
|
-
description: "Author and manage tenant plugins (list/validate/create/update/delete/reload/test)",
|
|
50020
|
+
description: "Author and manage tenant plugins (list/validate/create/update/delete/reload/test/deploy/undeploy/status)",
|
|
49035
50021
|
enabled: true,
|
|
49036
50022
|
config: {}
|
|
49037
50023
|
},
|
|
@@ -49227,13 +50213,74 @@ var sandboxPluginsPlugin = {
|
|
|
49227
50213
|
return JSON.stringify(redactSecretValues({ ok: false, error: errorText(err) }, secrets));
|
|
49228
50214
|
}
|
|
49229
50215
|
}
|
|
50216
|
+
case "deploy": {
|
|
50217
|
+
if (!input.type) return "type is required";
|
|
50218
|
+
const service3 = getPluginDeploymentService();
|
|
50219
|
+
if (!service3) return deploymentUnavailable("deploy");
|
|
50220
|
+
try {
|
|
50221
|
+
const result = await service3.deploy(tenantId2, input.type, {
|
|
50222
|
+
...input.mode === void 0 ? {} : { mode: input.mode }
|
|
50223
|
+
});
|
|
50224
|
+
return JSON.stringify({
|
|
50225
|
+
deployed: true,
|
|
50226
|
+
status: result.status,
|
|
50227
|
+
endpoint: result.endpoint,
|
|
50228
|
+
mode: result.mode
|
|
50229
|
+
});
|
|
50230
|
+
} catch (err) {
|
|
50231
|
+
return JSON.stringify({ deployed: false, error: errorText(err) });
|
|
50232
|
+
}
|
|
50233
|
+
}
|
|
50234
|
+
case "undeploy": {
|
|
50235
|
+
if (!input.type) return "type is required";
|
|
50236
|
+
const service3 = getPluginDeploymentService();
|
|
50237
|
+
if (!service3) return deploymentUnavailable("undeploy");
|
|
50238
|
+
try {
|
|
50239
|
+
const result = await service3.undeploy(tenantId2, input.type);
|
|
50240
|
+
return JSON.stringify({ undeployed: result.undeployed });
|
|
50241
|
+
} catch (err) {
|
|
50242
|
+
return JSON.stringify({ undeployed: false, error: errorText(err) });
|
|
50243
|
+
}
|
|
50244
|
+
}
|
|
50245
|
+
case "status": {
|
|
50246
|
+
if (!input.type) return "type is required";
|
|
50247
|
+
const service3 = getPluginDeploymentService();
|
|
50248
|
+
if (!service3) return deploymentUnavailable("status");
|
|
50249
|
+
try {
|
|
50250
|
+
const result = await service3.status(tenantId2, input.type);
|
|
50251
|
+
return JSON.stringify({
|
|
50252
|
+
status: result.status,
|
|
50253
|
+
endpoint: result.endpoint,
|
|
50254
|
+
mode: result.mode,
|
|
50255
|
+
lastHealthAt: result.lastHealthAt,
|
|
50256
|
+
lastError: result.lastError
|
|
50257
|
+
});
|
|
50258
|
+
} catch (err) {
|
|
50259
|
+
return JSON.stringify({ status: "unavailable", error: errorText(err) });
|
|
50260
|
+
}
|
|
50261
|
+
}
|
|
50262
|
+
case "deployments": {
|
|
50263
|
+
const service3 = getPluginDeploymentService();
|
|
50264
|
+
if (!service3) {
|
|
50265
|
+
return deploymentsResult({
|
|
50266
|
+
deployments: [],
|
|
50267
|
+
error: "plugin deployment service is not configured; cannot list deployments. Resident plugin services are unavailable in this environment."
|
|
50268
|
+
});
|
|
50269
|
+
}
|
|
50270
|
+
try {
|
|
50271
|
+
const deployments = await service3.list(tenantId2);
|
|
50272
|
+
return deploymentsResult({ deployments });
|
|
50273
|
+
} catch (err) {
|
|
50274
|
+
return deploymentsResult({ deployments: [], error: errorText(err) });
|
|
50275
|
+
}
|
|
50276
|
+
}
|
|
49230
50277
|
default:
|
|
49231
50278
|
return `unsupported action: ${input.action}`;
|
|
49232
50279
|
}
|
|
49233
50280
|
},
|
|
49234
50281
|
{
|
|
49235
50282
|
name: "manage_plugin",
|
|
49236
|
-
description: "Author and manage tenant sandbox plugins (list/get/validate/create/update/delete/reload/test).",
|
|
50283
|
+
description: "Author and manage tenant sandbox plugins (list/get/validate/create/update/delete/reload/test) and deploy/undeploy/status a plugin as a resident service.",
|
|
49237
50284
|
schema: managePluginSchema
|
|
49238
50285
|
}
|
|
49239
50286
|
)
|
|
@@ -49288,6 +50335,526 @@ function buildBundleFromDist(distDir, version) {
|
|
|
49288
50335
|
};
|
|
49289
50336
|
}
|
|
49290
50337
|
|
|
50338
|
+
// src/sandbox_plugin/PluginDeploymentRuntimeRegistry.ts
|
|
50339
|
+
var PluginDeploymentRuntimeRegistry = class {
|
|
50340
|
+
/**
|
|
50341
|
+
* @param options - Optional injectable clock for deterministic health timestamps.
|
|
50342
|
+
*/
|
|
50343
|
+
constructor(options = {}) {
|
|
50344
|
+
this.entries = /* @__PURE__ */ new Map();
|
|
50345
|
+
this.inFlight = /* @__PURE__ */ new Map();
|
|
50346
|
+
this.now = options.now ?? Date.now;
|
|
50347
|
+
}
|
|
50348
|
+
/**
|
|
50349
|
+
* Cache the resolved proxy endpoint for a deployment.
|
|
50350
|
+
*
|
|
50351
|
+
* @param id - Composed key `${tenantId}:${pluginType}`.
|
|
50352
|
+
* @param endpoint - Relative proxy path, e.g. `/api/sandboxes/plugin-abc/proxy/8080`.
|
|
50353
|
+
*/
|
|
50354
|
+
setEndpoint(id, endpoint) {
|
|
50355
|
+
this.entry(id).endpoint = endpoint;
|
|
50356
|
+
}
|
|
50357
|
+
/**
|
|
50358
|
+
* Read the cached endpoint for a deployment.
|
|
50359
|
+
*
|
|
50360
|
+
* @param id - Composed key `${tenantId}:${pluginType}`.
|
|
50361
|
+
* @returns The cached endpoint, or `undefined` when none is known.
|
|
50362
|
+
*/
|
|
50363
|
+
getEndpoint(id) {
|
|
50364
|
+
return this.entries.get(id)?.endpoint;
|
|
50365
|
+
}
|
|
50366
|
+
/**
|
|
50367
|
+
* Record a successful health observation and clear any prior error.
|
|
50368
|
+
*
|
|
50369
|
+
* @param id - Composed key `${tenantId}:${pluginType}`.
|
|
50370
|
+
*/
|
|
50371
|
+
markHealthy(id) {
|
|
50372
|
+
const entry = this.entry(id);
|
|
50373
|
+
entry.lastHealthAt = this.now();
|
|
50374
|
+
delete entry.lastError;
|
|
50375
|
+
}
|
|
50376
|
+
/**
|
|
50377
|
+
* Record a failed health observation.
|
|
50378
|
+
*
|
|
50379
|
+
* @param id - Composed key `${tenantId}:${pluginType}`.
|
|
50380
|
+
* @param error - Human-readable failure description.
|
|
50381
|
+
*/
|
|
50382
|
+
markUnhealthy(id, error) {
|
|
50383
|
+
const entry = this.entry(id);
|
|
50384
|
+
entry.lastHealthAt = this.now();
|
|
50385
|
+
entry.lastError = error;
|
|
50386
|
+
}
|
|
50387
|
+
/**
|
|
50388
|
+
* Read the last observed health for a deployment.
|
|
50389
|
+
*
|
|
50390
|
+
* @param id - Composed key `${tenantId}:${pluginType}`.
|
|
50391
|
+
* @returns The cached health, or `undefined` when the id is unknown.
|
|
50392
|
+
*/
|
|
50393
|
+
getHealth(id) {
|
|
50394
|
+
const entry = this.entries.get(id);
|
|
50395
|
+
if (!entry) return void 0;
|
|
50396
|
+
const health = {};
|
|
50397
|
+
if (entry.lastHealthAt !== void 0) health.lastHealthAt = entry.lastHealthAt;
|
|
50398
|
+
if (entry.lastError !== void 0) health.lastError = entry.lastError;
|
|
50399
|
+
return health;
|
|
50400
|
+
}
|
|
50401
|
+
/**
|
|
50402
|
+
* Run a cold start/resume factory at most once per id at a time.
|
|
50403
|
+
*
|
|
50404
|
+
* Concurrent calls for the same id return the same in-flight promise and run
|
|
50405
|
+
* `factory` exactly once. The in-flight entry is cleared when the factory
|
|
50406
|
+
* settles, so a later call runs it again (retry after failure is allowed).
|
|
50407
|
+
*
|
|
50408
|
+
* @param id - Composed key `${tenantId}:${pluginType}`.
|
|
50409
|
+
* @param factory - Idempotent start/resume operation for the resident service.
|
|
50410
|
+
* @returns A promise that settles with the factory outcome.
|
|
50411
|
+
*/
|
|
50412
|
+
ensureRunning(id, factory) {
|
|
50413
|
+
const existing = this.inFlight.get(id);
|
|
50414
|
+
if (existing) return existing;
|
|
50415
|
+
let started;
|
|
50416
|
+
try {
|
|
50417
|
+
started = factory();
|
|
50418
|
+
} catch (error) {
|
|
50419
|
+
started = Promise.reject(error);
|
|
50420
|
+
}
|
|
50421
|
+
const tracked = started.finally(() => {
|
|
50422
|
+
if (this.inFlight.get(id) === tracked) {
|
|
50423
|
+
this.inFlight.delete(id);
|
|
50424
|
+
}
|
|
50425
|
+
});
|
|
50426
|
+
this.inFlight.set(id, tracked);
|
|
50427
|
+
return tracked;
|
|
50428
|
+
}
|
|
50429
|
+
/**
|
|
50430
|
+
* Drop cached endpoint and health for one deployment.
|
|
50431
|
+
*
|
|
50432
|
+
* @param id - Composed key `${tenantId}:${pluginType}`.
|
|
50433
|
+
*/
|
|
50434
|
+
clear(id) {
|
|
50435
|
+
this.entries.delete(id);
|
|
50436
|
+
}
|
|
50437
|
+
/** Drop all cached endpoints, health, and in-flight coordination entries. */
|
|
50438
|
+
reset() {
|
|
50439
|
+
this.entries.clear();
|
|
50440
|
+
this.inFlight.clear();
|
|
50441
|
+
}
|
|
50442
|
+
entry(id) {
|
|
50443
|
+
const existing = this.entries.get(id);
|
|
50444
|
+
if (existing) return existing;
|
|
50445
|
+
const created = {};
|
|
50446
|
+
this.entries.set(id, created);
|
|
50447
|
+
return created;
|
|
50448
|
+
}
|
|
50449
|
+
};
|
|
50450
|
+
|
|
50451
|
+
// src/sandbox_plugin/host/pluginHostProtocol.ts
|
|
50452
|
+
var INLINE_INPUT_LIMIT_BYTES2 = 48 * 1024;
|
|
50453
|
+
var DEFAULT_HANDLER_TIMEOUT_MS = 6e4;
|
|
50454
|
+
var MIN_HANDLER_TIMEOUT_MS = 1e3;
|
|
50455
|
+
var MAX_HANDLER_TIMEOUT_MS = 3e5;
|
|
50456
|
+
function isRecord11(value) {
|
|
50457
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
50458
|
+
}
|
|
50459
|
+
function isEnvelope3(value) {
|
|
50460
|
+
return isRecord11(value) && typeof value.ok === "boolean";
|
|
50461
|
+
}
|
|
50462
|
+
function parseHostArgs(argv) {
|
|
50463
|
+
let type;
|
|
50464
|
+
let port;
|
|
50465
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
50466
|
+
const token = argv[index];
|
|
50467
|
+
if (token === "--type" && index + 1 < argv.length) {
|
|
50468
|
+
type = argv[index + 1];
|
|
50469
|
+
index += 1;
|
|
50470
|
+
} else if (token.startsWith("--type=")) {
|
|
50471
|
+
type = token.slice("--type=".length);
|
|
50472
|
+
} else if (token === "--port" && index + 1 < argv.length) {
|
|
50473
|
+
port = argv[index + 1];
|
|
50474
|
+
index += 1;
|
|
50475
|
+
} else if (token.startsWith("--port=")) {
|
|
50476
|
+
port = token.slice("--port=".length);
|
|
50477
|
+
}
|
|
50478
|
+
}
|
|
50479
|
+
const parsedPort = Number(port);
|
|
50480
|
+
if (typeof type !== "string" || type.length === 0) {
|
|
50481
|
+
throw new Error("parseHostArgs: missing or empty --type");
|
|
50482
|
+
}
|
|
50483
|
+
if (!Number.isInteger(parsedPort) || parsedPort <= 0 || parsedPort > 65535) {
|
|
50484
|
+
throw new Error("parseHostArgs: invalid --port");
|
|
50485
|
+
}
|
|
50486
|
+
return { type, port: parsedPort };
|
|
50487
|
+
}
|
|
50488
|
+
function resolveHandlerTimeoutMs(value) {
|
|
50489
|
+
if (value === null || value === void 0 || value === "") return DEFAULT_HANDLER_TIMEOUT_MS;
|
|
50490
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
50491
|
+
if (!Number.isFinite(numeric)) return DEFAULT_HANDLER_TIMEOUT_MS;
|
|
50492
|
+
return Math.min(Math.max(Math.round(numeric), MIN_HANDLER_TIMEOUT_MS), MAX_HANDLER_TIMEOUT_MS);
|
|
50493
|
+
}
|
|
50494
|
+
function parseHandlerEnvelope(stdout) {
|
|
50495
|
+
const trimmed = stdout.trim();
|
|
50496
|
+
if (!trimmed) return { ok: false, error: "empty handler output" };
|
|
50497
|
+
const whole = tryParse(trimmed);
|
|
50498
|
+
if (isEnvelope3(whole)) return normalizeEnvelope(whole);
|
|
50499
|
+
const lines = stdout.split("\n");
|
|
50500
|
+
for (let index = lines.length - 1; index >= 0; index -= 1) {
|
|
50501
|
+
const line = lines[index]?.trim();
|
|
50502
|
+
if (!line) continue;
|
|
50503
|
+
const candidate = tryParse(line);
|
|
50504
|
+
if (isEnvelope3(candidate)) return normalizeEnvelope(candidate);
|
|
50505
|
+
}
|
|
50506
|
+
return { ok: true, result: trimmed };
|
|
50507
|
+
}
|
|
50508
|
+
function buildHandlerCommand(handlerPath) {
|
|
50509
|
+
return `node ${quotePosixShellArg2(handlerPath)}`;
|
|
50510
|
+
}
|
|
50511
|
+
function encodeInput(input) {
|
|
50512
|
+
return Buffer.from(JSON.stringify(input ?? null), "utf8").toString("base64");
|
|
50513
|
+
}
|
|
50514
|
+
function buildConnectionPayload2(args) {
|
|
50515
|
+
if (Array.isArray(args.connections) && args.connections.length > 0) {
|
|
50516
|
+
return {
|
|
50517
|
+
connection: args.connection ?? args.connections[0]?.config,
|
|
50518
|
+
connections: args.connections
|
|
50519
|
+
};
|
|
50520
|
+
}
|
|
50521
|
+
if (args.connection) {
|
|
50522
|
+
return { connection: args.connection };
|
|
50523
|
+
}
|
|
50524
|
+
return null;
|
|
50525
|
+
}
|
|
50526
|
+
function quotePosixShellArg2(value) {
|
|
50527
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
50528
|
+
}
|
|
50529
|
+
function tryParse(text) {
|
|
50530
|
+
try {
|
|
50531
|
+
return JSON.parse(text);
|
|
50532
|
+
} catch {
|
|
50533
|
+
return void 0;
|
|
50534
|
+
}
|
|
50535
|
+
}
|
|
50536
|
+
function normalizeEnvelope(parsed) {
|
|
50537
|
+
if (parsed.ok) return { ok: true, result: parsed.result };
|
|
50538
|
+
return { ok: false, error: typeof parsed.error === "string" ? parsed.error : void 0 };
|
|
50539
|
+
}
|
|
50540
|
+
|
|
50541
|
+
// src/sandbox_plugin/host/pluginHostSource.ts
|
|
50542
|
+
var import_node_crypto15 = require("crypto");
|
|
50543
|
+
var PLUGIN_HOST_VERSION = "1.1.0";
|
|
50544
|
+
var PLUGIN_HOST_SERVER_SOURCE = String.raw`#!/usr/bin/env node
|
|
50545
|
+
"use strict";
|
|
50546
|
+
|
|
50547
|
+
var http = require("node:http");
|
|
50548
|
+
var fs = require("node:fs");
|
|
50549
|
+
var os = require("node:os");
|
|
50550
|
+
var path = require("node:path");
|
|
50551
|
+
var crypto = require("node:crypto");
|
|
50552
|
+
var execFile = require("node:child_process").execFile;
|
|
50553
|
+
|
|
50554
|
+
var VERSION = "${PLUGIN_HOST_VERSION}";
|
|
50555
|
+
var PLUGINS_ROOT = "/root/.agents/plugins";
|
|
50556
|
+
var INLINE_INPUT_LIMIT_BYTES = 48 * 1024;
|
|
50557
|
+
var MAX_BODY_BYTES = 8 * 1024 * 1024;
|
|
50558
|
+
var MAX_RESULT_BYTES = 16 * 1024 * 1024;
|
|
50559
|
+
var DEFAULT_HANDLER_TIMEOUT_MS = 60000;
|
|
50560
|
+
var MIN_HANDLER_TIMEOUT_MS = 1000;
|
|
50561
|
+
var MAX_HANDLER_TIMEOUT_MS = 300000;
|
|
50562
|
+
|
|
50563
|
+
function resolveHandlerTimeoutMs(value) {
|
|
50564
|
+
if (value === null || value === undefined || value === "") {
|
|
50565
|
+
return DEFAULT_HANDLER_TIMEOUT_MS;
|
|
50566
|
+
}
|
|
50567
|
+
var numeric = typeof value === "number" ? value : Number(value);
|
|
50568
|
+
if (!isFinite(numeric)) {
|
|
50569
|
+
return DEFAULT_HANDLER_TIMEOUT_MS;
|
|
50570
|
+
}
|
|
50571
|
+
return Math.min(Math.max(Math.round(numeric), MIN_HANDLER_TIMEOUT_MS), MAX_HANDLER_TIMEOUT_MS);
|
|
50572
|
+
}
|
|
50573
|
+
|
|
50574
|
+
function isRecord(value) {
|
|
50575
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
50576
|
+
}
|
|
50577
|
+
|
|
50578
|
+
function isEnvelope(value) {
|
|
50579
|
+
return isRecord(value) && typeof value.ok === "boolean";
|
|
50580
|
+
}
|
|
50581
|
+
|
|
50582
|
+
function tryParse(text) {
|
|
50583
|
+
try {
|
|
50584
|
+
return JSON.parse(text);
|
|
50585
|
+
} catch (err) {
|
|
50586
|
+
return undefined;
|
|
50587
|
+
}
|
|
50588
|
+
}
|
|
50589
|
+
|
|
50590
|
+
function normalizeEnvelope(parsed) {
|
|
50591
|
+
if (parsed.ok) {
|
|
50592
|
+
return { ok: true, result: parsed.result };
|
|
50593
|
+
}
|
|
50594
|
+
return { ok: false, error: typeof parsed.error === "string" ? parsed.error : undefined };
|
|
50595
|
+
}
|
|
50596
|
+
|
|
50597
|
+
function parseHandlerEnvelope(stdout) {
|
|
50598
|
+
var text = String(stdout == null ? "" : stdout);
|
|
50599
|
+
var trimmed = text.trim();
|
|
50600
|
+
if (!trimmed) {
|
|
50601
|
+
// Deliberate divergence from SandboxPluginExecutor, which returns
|
|
50602
|
+
// { ok: true, result: "" } for empty stdout; the resident host treats empty
|
|
50603
|
+
// output as a handler failure so a crashed/no-op handler is not a "success".
|
|
50604
|
+
return { ok: false, error: "empty handler output" };
|
|
50605
|
+
}
|
|
50606
|
+
var whole = tryParse(trimmed);
|
|
50607
|
+
if (isEnvelope(whole)) {
|
|
50608
|
+
return normalizeEnvelope(whole);
|
|
50609
|
+
}
|
|
50610
|
+
var lines = text.split("\n");
|
|
50611
|
+
for (var index = lines.length - 1; index >= 0; index -= 1) {
|
|
50612
|
+
var line = lines[index].trim();
|
|
50613
|
+
if (!line) {
|
|
50614
|
+
continue;
|
|
50615
|
+
}
|
|
50616
|
+
var candidate = tryParse(line);
|
|
50617
|
+
if (isEnvelope(candidate)) {
|
|
50618
|
+
return normalizeEnvelope(candidate);
|
|
50619
|
+
}
|
|
50620
|
+
}
|
|
50621
|
+
return { ok: true, result: trimmed };
|
|
50622
|
+
}
|
|
50623
|
+
|
|
50624
|
+
function quotePosixShellArg(value) {
|
|
50625
|
+
return "'" + String(value).replace(/'/g, "'\"'\"'") + "'";
|
|
50626
|
+
}
|
|
50627
|
+
|
|
50628
|
+
function buildHandlerCommand(handlerPath) {
|
|
50629
|
+
return "node " + quotePosixShellArg(handlerPath);
|
|
50630
|
+
}
|
|
50631
|
+
|
|
50632
|
+
function parseHostArgs(argv) {
|
|
50633
|
+
var type;
|
|
50634
|
+
var port;
|
|
50635
|
+
for (var index = 0; index < argv.length; index += 1) {
|
|
50636
|
+
var token = argv[index];
|
|
50637
|
+
if (token === "--type" && index + 1 < argv.length) {
|
|
50638
|
+
type = argv[index + 1];
|
|
50639
|
+
index += 1;
|
|
50640
|
+
} else if (token.indexOf("--type=") === 0) {
|
|
50641
|
+
type = token.slice("--type=".length);
|
|
50642
|
+
} else if (token === "--port" && index + 1 < argv.length) {
|
|
50643
|
+
port = argv[index + 1];
|
|
50644
|
+
index += 1;
|
|
50645
|
+
} else if (token.indexOf("--port=") === 0) {
|
|
50646
|
+
port = token.slice("--port=".length);
|
|
50647
|
+
}
|
|
50648
|
+
}
|
|
50649
|
+
var parsedPort = Number(port);
|
|
50650
|
+
if (typeof type !== "string" || type.length === 0) {
|
|
50651
|
+
throw new Error("parseHostArgs: missing or empty --type");
|
|
50652
|
+
}
|
|
50653
|
+
if (!Number.isInteger(parsedPort) || parsedPort <= 0 || parsedPort > 65535) {
|
|
50654
|
+
throw new Error("parseHostArgs: invalid --port");
|
|
50655
|
+
}
|
|
50656
|
+
return { type: type, port: parsedPort };
|
|
50657
|
+
}
|
|
50658
|
+
|
|
50659
|
+
function encodeInput(input) {
|
|
50660
|
+
return Buffer.from(JSON.stringify(input === undefined ? null : input), "utf8").toString("base64");
|
|
50661
|
+
}
|
|
50662
|
+
|
|
50663
|
+
function buildConnectionPayload(body) {
|
|
50664
|
+
if (Array.isArray(body.connections) && body.connections.length > 0) {
|
|
50665
|
+
return {
|
|
50666
|
+
connection: body.connection !== undefined ? body.connection : body.connections[0].config,
|
|
50667
|
+
connections: body.connections,
|
|
50668
|
+
};
|
|
50669
|
+
}
|
|
50670
|
+
if (body.connection) {
|
|
50671
|
+
return { connection: body.connection };
|
|
50672
|
+
}
|
|
50673
|
+
return null;
|
|
50674
|
+
}
|
|
50675
|
+
|
|
50676
|
+
function resolveHandlerPath(type, handler) {
|
|
50677
|
+
if (typeof handler !== "string" || handler.length === 0) {
|
|
50678
|
+
throw new Error("missing handler");
|
|
50679
|
+
}
|
|
50680
|
+
if (handler.charAt(0) === "/" || handler.split("/").indexOf("..") !== -1) {
|
|
50681
|
+
throw new Error("invalid handler path");
|
|
50682
|
+
}
|
|
50683
|
+
return path.join(PLUGINS_ROOT, type, handler);
|
|
50684
|
+
}
|
|
50685
|
+
|
|
50686
|
+
function readJsonBody(req) {
|
|
50687
|
+
return new Promise(function (resolve, reject) {
|
|
50688
|
+
var chunks = [];
|
|
50689
|
+
var size = 0;
|
|
50690
|
+
req.on("data", function (chunk) {
|
|
50691
|
+
size += chunk.length;
|
|
50692
|
+
if (size > MAX_BODY_BYTES) {
|
|
50693
|
+
reject(new Error("request body too large"));
|
|
50694
|
+
req.destroy();
|
|
50695
|
+
return;
|
|
50696
|
+
}
|
|
50697
|
+
chunks.push(chunk);
|
|
50698
|
+
});
|
|
50699
|
+
req.on("end", function () {
|
|
50700
|
+
try {
|
|
50701
|
+
var text = Buffer.concat(chunks).toString("utf8");
|
|
50702
|
+
resolve(text ? JSON.parse(text) : {});
|
|
50703
|
+
} catch (err) {
|
|
50704
|
+
reject(new Error("invalid JSON body"));
|
|
50705
|
+
}
|
|
50706
|
+
});
|
|
50707
|
+
req.on("error", reject);
|
|
50708
|
+
});
|
|
50709
|
+
}
|
|
50710
|
+
|
|
50711
|
+
function runNode(handlerPath, pluginDir, env, timeoutMs) {
|
|
50712
|
+
return new Promise(function (resolve) {
|
|
50713
|
+
execFile(
|
|
50714
|
+
process.execPath,
|
|
50715
|
+
[handlerPath],
|
|
50716
|
+
{ cwd: pluginDir, env: env, timeout: timeoutMs, maxBuffer: MAX_RESULT_BYTES },
|
|
50717
|
+
function (error, stdout, stderr) {
|
|
50718
|
+
resolve({ error: error, stdout: stdout || "", stderr: stderr || "" });
|
|
50719
|
+
}
|
|
50720
|
+
);
|
|
50721
|
+
});
|
|
50722
|
+
}
|
|
50723
|
+
|
|
50724
|
+
function failureFromExec(exec, command) {
|
|
50725
|
+
var parsed = parseHandlerEnvelope(exec.stdout);
|
|
50726
|
+
if (!parsed.ok) {
|
|
50727
|
+
return parsed;
|
|
50728
|
+
}
|
|
50729
|
+
var code = exec.error && typeof exec.error.code === "number" ? exec.error.code : "n/a";
|
|
50730
|
+
var detail = exec.stdout ? exec.stdout.slice(0, 4096) : exec.error ? String(exec.error.message) : "";
|
|
50731
|
+
return { ok: false, error: "handler failed (exit " + code + "): " + detail + " [" + command + "]" };
|
|
50732
|
+
}
|
|
50733
|
+
|
|
50734
|
+
async function runHandler(body) {
|
|
50735
|
+
var pluginDir = path.join(PLUGINS_ROOT, config.type);
|
|
50736
|
+
var handlerPath = resolveHandlerPath(config.type, body.handler);
|
|
50737
|
+
var command = buildHandlerCommand(handlerPath);
|
|
50738
|
+
var inputJson = JSON.stringify(body.input === undefined ? null : body.input);
|
|
50739
|
+
var connectionPayload = buildConnectionPayload(body);
|
|
50740
|
+
var inputIsLarge = Buffer.byteLength(inputJson, "utf8") > INLINE_INPUT_LIMIT_BYTES;
|
|
50741
|
+
var needsTempDir = inputIsLarge || connectionPayload !== null;
|
|
50742
|
+
var tempDir = null;
|
|
50743
|
+
var env = Object.assign({}, process.env);
|
|
50744
|
+
try {
|
|
50745
|
+
if (needsTempDir) {
|
|
50746
|
+
tempDir = path.join(os.tmpdir(), "plugin-run-" + Date.now() + "-" + Math.random().toString(36).slice(2));
|
|
50747
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
50748
|
+
}
|
|
50749
|
+
if (inputIsLarge) {
|
|
50750
|
+
var inputFile = path.join(tempDir, "input.json");
|
|
50751
|
+
fs.writeFileSync(inputFile, inputJson);
|
|
50752
|
+
env.PLUGIN_INPUT_FILE = inputFile;
|
|
50753
|
+
} else {
|
|
50754
|
+
env.PLUGIN_INPUT = encodeInput(body.input);
|
|
50755
|
+
}
|
|
50756
|
+
if (connectionPayload !== null) {
|
|
50757
|
+
var connectionFile = path.join(tempDir, "connection.json");
|
|
50758
|
+
fs.writeFileSync(connectionFile, JSON.stringify(connectionPayload));
|
|
50759
|
+
env.PLUGIN_CONNECTION_FILE = connectionFile;
|
|
50760
|
+
}
|
|
50761
|
+
env.PLUGIN_CONTEXT = encodeInput(body.context || {});
|
|
50762
|
+
var handlerTimeoutMs = resolveHandlerTimeoutMs(body.timeoutMs);
|
|
50763
|
+
var exec = await runNode(handlerPath, pluginDir, env, handlerTimeoutMs);
|
|
50764
|
+
if (exec.error) {
|
|
50765
|
+
return failureFromExec(exec, command);
|
|
50766
|
+
}
|
|
50767
|
+
return parseHandlerEnvelope(exec.stdout);
|
|
50768
|
+
} finally {
|
|
50769
|
+
if (tempDir) {
|
|
50770
|
+
try {
|
|
50771
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
50772
|
+
} catch (err) {
|
|
50773
|
+
// best-effort cleanup
|
|
50774
|
+
}
|
|
50775
|
+
}
|
|
50776
|
+
}
|
|
50777
|
+
}
|
|
50778
|
+
|
|
50779
|
+
function manifestHash() {
|
|
50780
|
+
try {
|
|
50781
|
+
var content = fs.readFileSync(path.join(PLUGINS_ROOT, config.type, "plugin.json"), "utf8");
|
|
50782
|
+
return crypto.createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
50783
|
+
} catch (err) {
|
|
50784
|
+
return "";
|
|
50785
|
+
}
|
|
50786
|
+
}
|
|
50787
|
+
|
|
50788
|
+
function sendJson(res, status, payload) {
|
|
50789
|
+
var body = JSON.stringify(payload);
|
|
50790
|
+
res.writeHead(status, {
|
|
50791
|
+
"content-type": "application/json",
|
|
50792
|
+
"content-length": Buffer.byteLength(body),
|
|
50793
|
+
});
|
|
50794
|
+
res.end(body);
|
|
50795
|
+
}
|
|
50796
|
+
|
|
50797
|
+
function handleRequest(req, res) {
|
|
50798
|
+
var url = String(req.url || "").split("?")[0];
|
|
50799
|
+
if (req.method === "GET" && url === "/health") {
|
|
50800
|
+
sendJson(res, 200, { ok: true, version: VERSION });
|
|
50801
|
+
return;
|
|
50802
|
+
}
|
|
50803
|
+
if (req.method === "GET" && url === "/meta") {
|
|
50804
|
+
sendJson(res, 200, { type: config.type, manifestHash: manifestHash() });
|
|
50805
|
+
return;
|
|
50806
|
+
}
|
|
50807
|
+
if (req.method === "POST" && url === "/invoke") {
|
|
50808
|
+
readJsonBody(req)
|
|
50809
|
+
.then(function (body) {
|
|
50810
|
+
if (!isRecord(body)) {
|
|
50811
|
+
sendJson(res, 400, { ok: false, error: "invalid body" });
|
|
50812
|
+
return;
|
|
50813
|
+
}
|
|
50814
|
+
return runHandler(body).then(function (result) {
|
|
50815
|
+
sendJson(res, 200, result);
|
|
50816
|
+
});
|
|
50817
|
+
})
|
|
50818
|
+
.catch(function (err) {
|
|
50819
|
+
sendJson(res, 400, { ok: false, error: String(err && err.message ? err.message : err) });
|
|
50820
|
+
});
|
|
50821
|
+
return;
|
|
50822
|
+
}
|
|
50823
|
+
sendJson(res, 404, { ok: false, error: "not found" });
|
|
50824
|
+
}
|
|
50825
|
+
|
|
50826
|
+
var config = parseHostArgs(process.argv);
|
|
50827
|
+
var server = http.createServer(handleRequest);
|
|
50828
|
+
server.listen(config.port, "0.0.0.0", function () {
|
|
50829
|
+
process.stdout.write(
|
|
50830
|
+
"[plugin-host] listening type=" + config.type + " port=" + config.port + " version=" + VERSION + "\n"
|
|
50831
|
+
);
|
|
50832
|
+
});
|
|
50833
|
+
`;
|
|
50834
|
+
function pluginHostContentHash() {
|
|
50835
|
+
return (0, import_node_crypto15.createHash)("sha256").update(`${PLUGIN_HOST_VERSION}:${PLUGIN_HOST_SERVER_SOURCE}`).digest("hex").slice(0, 16);
|
|
50836
|
+
}
|
|
50837
|
+
|
|
50838
|
+
// src/sandbox_plugin/host/pluginHostInstaller.ts
|
|
50839
|
+
var PLUGIN_HOST_DIR = "/root/.agents/.plugin-host";
|
|
50840
|
+
var SERVER_PATH = `${PLUGIN_HOST_DIR}/server.js`;
|
|
50841
|
+
var VERSION_PATH = `${PLUGIN_HOST_DIR}/version.json`;
|
|
50842
|
+
async function installPluginHost(sandbox) {
|
|
50843
|
+
const hash = pluginHostContentHash();
|
|
50844
|
+
try {
|
|
50845
|
+
const existing = await sandbox.file.readFile(VERSION_PATH);
|
|
50846
|
+
const parsed = JSON.parse(existing.content);
|
|
50847
|
+
if (parsed.hash === hash) {
|
|
50848
|
+
return { path: SERVER_PATH, version: PLUGIN_HOST_VERSION, hash, changed: false };
|
|
50849
|
+
}
|
|
50850
|
+
} catch {
|
|
50851
|
+
}
|
|
50852
|
+
await sandbox.file.createDirectory(PLUGIN_HOST_DIR).catch(() => void 0);
|
|
50853
|
+
await sandbox.file.writeFile(SERVER_PATH, PLUGIN_HOST_SERVER_SOURCE);
|
|
50854
|
+
await sandbox.file.writeFile(VERSION_PATH, JSON.stringify({ version: PLUGIN_HOST_VERSION, hash }, null, 2));
|
|
50855
|
+
return { path: SERVER_PATH, version: PLUGIN_HOST_VERSION, hash, changed: true };
|
|
50856
|
+
}
|
|
50857
|
+
|
|
49291
50858
|
// src/workflow/index.ts
|
|
49292
50859
|
init_compile();
|
|
49293
50860
|
init_parse_yaml();
|
|
@@ -49679,16 +51246,16 @@ var IdRemapper = class {
|
|
|
49679
51246
|
};
|
|
49680
51247
|
|
|
49681
51248
|
// src/util/directRoomId.ts
|
|
49682
|
-
var
|
|
51249
|
+
var import_node_crypto16 = require("crypto");
|
|
49683
51250
|
function generateDirectHumanProjectId(tenantId2, workspaceId, userId1, userId2) {
|
|
49684
51251
|
const sortedUserIds = [userId1, userId2].sort();
|
|
49685
51252
|
const parts = [tenantId2, workspaceId, ...sortedUserIds];
|
|
49686
|
-
const hash = (0,
|
|
51253
|
+
const hash = (0, import_node_crypto16.createHash)("sha256").update(parts.join(":")).digest("hex");
|
|
49687
51254
|
return `direct_human_${hash}`;
|
|
49688
51255
|
}
|
|
49689
51256
|
function generateDirectBotProjectId(tenantId2, workspaceId, userId, assistantId) {
|
|
49690
51257
|
const parts = [tenantId2, workspaceId, userId, assistantId];
|
|
49691
|
-
const hash = (0,
|
|
51258
|
+
const hash = (0, import_node_crypto16.createHash)("sha256").update(parts.join(":")).digest("hex");
|
|
49692
51259
|
return `direct_bot_${hash}`;
|
|
49693
51260
|
}
|
|
49694
51261
|
function parseDirectRoomType(projectId) {
|
|
@@ -49718,6 +51285,7 @@ registerBuiltinPlugins();
|
|
|
49718
51285
|
CapabilityBundleValidationError,
|
|
49719
51286
|
CapabilityToolNameConflictError,
|
|
49720
51287
|
CapabilityToolRegistry,
|
|
51288
|
+
ChannelConnectionLeader,
|
|
49721
51289
|
ChunkBuffer,
|
|
49722
51290
|
ChunkBufferLatticeManager,
|
|
49723
51291
|
CollectionLatticeManager,
|
|
@@ -49729,7 +51297,9 @@ registerBuiltinPlugins();
|
|
|
49729
51297
|
DEFAULT_CALIBRATION_PROBES,
|
|
49730
51298
|
DEFAULT_CONNECT_TIMEOUT_MS,
|
|
49731
51299
|
DEFAULT_DELAY_MS,
|
|
51300
|
+
DEFAULT_HANDLER_TIMEOUT_MS,
|
|
49732
51301
|
DEFAULT_MAX_ATTEMPTS,
|
|
51302
|
+
DEFAULT_RESIDENT_INVOKE_TIMEOUT_MS,
|
|
49733
51303
|
DaytonaInstance,
|
|
49734
51304
|
DaytonaProvider,
|
|
49735
51305
|
DefaultScheduleClient,
|
|
@@ -49747,6 +51317,7 @@ registerBuiltinPlugins();
|
|
|
49747
51317
|
HEALTH_CHECK_INTERVAL_MS,
|
|
49748
51318
|
HEALTH_CHECK_TIMEOUT_MS,
|
|
49749
51319
|
HumanMessage,
|
|
51320
|
+
INLINE_INPUT_LIMIT_BYTES,
|
|
49750
51321
|
IdRemapper,
|
|
49751
51322
|
InMemoryA2AApiKeyStore,
|
|
49752
51323
|
InMemoryAgentWebAppStore,
|
|
@@ -49787,10 +51358,12 @@ registerBuiltinPlugins();
|
|
|
49787
51358
|
LocalSandboxProvider,
|
|
49788
51359
|
LoggerLatticeManager,
|
|
49789
51360
|
MAX_BACKOFF_MS,
|
|
51361
|
+
MAX_HANDLER_TIMEOUT_MS,
|
|
49790
51362
|
MAX_LINE_LENGTH,
|
|
49791
51363
|
MAX_PACK_ENTRIES,
|
|
49792
51364
|
MAX_PACK_FILE_BYTES,
|
|
49793
51365
|
MAX_PACK_TOTAL_BYTES,
|
|
51366
|
+
MIN_HANDLER_TIMEOUT_MS,
|
|
49794
51367
|
ManagedTaskStartError,
|
|
49795
51368
|
McpLatticeManager,
|
|
49796
51369
|
MemoryBackend,
|
|
@@ -49809,8 +51382,12 @@ registerBuiltinPlugins();
|
|
|
49809
51382
|
PACK_DIRECTORY_TIMEOUT_SECONDS,
|
|
49810
51383
|
PLATFORM_SECRET_ENV_VARS,
|
|
49811
51384
|
PLUGIN_CATALOG_CHANGED_TOPIC,
|
|
51385
|
+
PLUGIN_HOST_DIR,
|
|
51386
|
+
PLUGIN_HOST_SERVER_SOURCE,
|
|
51387
|
+
PLUGIN_HOST_VERSION,
|
|
49812
51388
|
PersonalAssistantConfig,
|
|
49813
51389
|
PinoLoggerClient,
|
|
51390
|
+
PluginDeploymentRuntimeRegistry,
|
|
49814
51391
|
PluginRegistry,
|
|
49815
51392
|
PostgresDatabase,
|
|
49816
51393
|
ProjectBotMembershipIdConflictError,
|
|
@@ -49872,7 +51449,9 @@ registerBuiltinPlugins();
|
|
|
49872
51449
|
appendUiFence,
|
|
49873
51450
|
assertSafeUpstreamUrl,
|
|
49874
51451
|
buildBundleFromDist,
|
|
51452
|
+
buildConnectionPayload,
|
|
49875
51453
|
buildGrepResultsDict,
|
|
51454
|
+
buildHandlerCommand,
|
|
49876
51455
|
buildInput,
|
|
49877
51456
|
buildNamedVolumeName,
|
|
49878
51457
|
buildRemotePackDirectoryCommand,
|
|
@@ -49887,6 +51466,7 @@ registerBuiltinPlugins();
|
|
|
49887
51466
|
clearEncryptionKeyCache,
|
|
49888
51467
|
clearEvalRunService,
|
|
49889
51468
|
clearSandboxOpenCredentialProviderForTests,
|
|
51469
|
+
collectPluginSources,
|
|
49890
51470
|
collectionLatticeManager,
|
|
49891
51471
|
compileInternal,
|
|
49892
51472
|
compileSandboxPlugin,
|
|
@@ -49939,9 +51519,11 @@ registerBuiltinPlugins();
|
|
|
49939
51519
|
decrypt,
|
|
49940
51520
|
decryptConfigFields,
|
|
49941
51521
|
describeCronExpression,
|
|
51522
|
+
disconnectAllChannels,
|
|
49942
51523
|
documentLearningPlugin,
|
|
49943
51524
|
documentParserPlugin,
|
|
49944
51525
|
embeddingsLatticeManager,
|
|
51526
|
+
encodeInput,
|
|
49945
51527
|
encrypt,
|
|
49946
51528
|
encryptConfigFields,
|
|
49947
51529
|
ensureBuiltinAgentsForTenant,
|
|
@@ -49985,6 +51567,7 @@ registerBuiltinPlugins();
|
|
|
49985
51567
|
getModelLattice,
|
|
49986
51568
|
getNextCronTime,
|
|
49987
51569
|
getOrCreateCollectionVectorStore,
|
|
51570
|
+
getPluginDeploymentService,
|
|
49988
51571
|
getPluginSkillManifestVersion,
|
|
49989
51572
|
getQueueLattice,
|
|
49990
51573
|
getReplicaId,
|
|
@@ -50013,6 +51596,8 @@ registerBuiltinPlugins();
|
|
|
50013
51596
|
hasChunkBuffer,
|
|
50014
51597
|
hasDelegatedWorkerToken,
|
|
50015
51598
|
hasRuntimeCapabilityPolicy,
|
|
51599
|
+
installPluginHost,
|
|
51600
|
+
invokeResident,
|
|
50016
51601
|
invokeWithRetry,
|
|
50017
51602
|
isBuiltInSkill,
|
|
50018
51603
|
isDirectRoom,
|
|
@@ -50026,6 +51611,7 @@ registerBuiltinPlugins();
|
|
|
50026
51611
|
jsonSchemaToZod,
|
|
50027
51612
|
listCollectionEntries,
|
|
50028
51613
|
listSandboxProviderTypes,
|
|
51614
|
+
listTenantPlugins,
|
|
50029
51615
|
loggerLatticeManager,
|
|
50030
51616
|
mcpManager,
|
|
50031
51617
|
mergeCapabilityBundles,
|
|
@@ -50039,6 +51625,8 @@ registerBuiltinPlugins();
|
|
|
50039
51625
|
parallelLimit,
|
|
50040
51626
|
parseCronExpression,
|
|
50041
51627
|
parseDirectRoomType,
|
|
51628
|
+
parseHandlerEnvelope,
|
|
51629
|
+
parseHostArgs,
|
|
50042
51630
|
parseJudgeVerdict,
|
|
50043
51631
|
parsePackSize,
|
|
50044
51632
|
parseQueuedExecutionMode,
|
|
@@ -50047,6 +51635,7 @@ registerBuiltinPlugins();
|
|
|
50047
51635
|
parseTrustedRunContext,
|
|
50048
51636
|
parseYaml,
|
|
50049
51637
|
performStringReplacement,
|
|
51638
|
+
pluginHostContentHash,
|
|
50050
51639
|
postProcessTaskMutationResponse,
|
|
50051
51640
|
prepareTaskDispatch,
|
|
50052
51641
|
projectMutationMutex,
|
|
@@ -50085,6 +51674,7 @@ registerBuiltinPlugins();
|
|
|
50085
51674
|
renderTemplate,
|
|
50086
51675
|
resetReplicaIdForTests,
|
|
50087
51676
|
resolveEnabledPluginSkill,
|
|
51677
|
+
resolveHandlerTimeoutMs,
|
|
50088
51678
|
resolveJudgeModelKey,
|
|
50089
51679
|
resolvePath,
|
|
50090
51680
|
resolvePluginConnections,
|
|
@@ -50104,6 +51694,7 @@ registerBuiltinPlugins();
|
|
|
50104
51694
|
setBindingRegistry,
|
|
50105
51695
|
setEvalRunService,
|
|
50106
51696
|
setMenuRegistry,
|
|
51697
|
+
setPluginDeploymentService,
|
|
50107
51698
|
setSandboxPluginCatalog,
|
|
50108
51699
|
skillLatticeManager,
|
|
50109
51700
|
sqlDatabaseManager,
|