@objectstack/service-ai 7.3.0 → 7.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.js CHANGED
@@ -5071,7 +5071,8 @@ var SchemaRetriever = class {
5071
5071
  if (obj.label) parts.push(obj.label);
5072
5072
  if (obj.pluralLabel && obj.pluralLabel !== obj.label) parts.push(`(${obj.pluralLabel})`);
5073
5073
  const header = parts.length > 0 ? ` \u2014 ${parts.join(" ")}` : "";
5074
- lines.push(`### ${obj.name}${header}`);
5074
+ const badge = obj.external !== void 0 ? ` [external, ${obj.external?.writable ? "writable" : "read-only"}, datasource=${obj.datasource ?? "default"}]` : "";
5075
+ lines.push(`### ${obj.name}${header}${badge}`);
5075
5076
  const fields = Object.entries(obj.fields ?? {}).slice(0, maxFieldsPerObject);
5076
5077
  for (const [name, field] of fields) {
5077
5078
  lines.push(` - ${name}: ${describeField(field)}`);
@@ -5215,6 +5216,15 @@ var QUERY_DATA_TOOL = {
5215
5216
  function createQueryDataHandler(ctx) {
5216
5217
  const retriever = new SchemaRetriever(ctx.metadata, {}, ctx.protocol);
5217
5218
  const maxLimit = ctx.maxLimit ?? 100;
5219
+ const externalTimeoutFallback = ctx.externalQueryTimeoutMs ?? 3e4;
5220
+ const resolveExternalTimeout = async (datasource) => {
5221
+ try {
5222
+ const ds = await ctx.metadata.get?.("datasource", datasource);
5223
+ return ds?.external?.queryTimeoutMs ?? externalTimeoutFallback;
5224
+ } catch {
5225
+ return externalTimeoutFallback;
5226
+ }
5227
+ };
5218
5228
  return async (args, execCtx) => {
5219
5229
  const { request } = args;
5220
5230
  if (!request || typeof request !== "string") {
@@ -5277,14 +5287,20 @@ function createQueryDataHandler(ctx) {
5277
5287
  });
5278
5288
  }
5279
5289
  }
5290
+ const isExternal = matchedObject.external !== void 0;
5280
5291
  try {
5281
- const records = await ctx.dataEngine.find(plan.objectName, {
5292
+ const findPromise = ctx.dataEngine.find(plan.objectName, {
5282
5293
  where,
5283
5294
  fields: plan.fields ?? void 0,
5284
5295
  orderBy: plan.orderBy ?? void 0,
5285
5296
  limit,
5286
5297
  context: buildAiEngineContext(execCtx)
5287
5298
  });
5299
+ const records = isExternal ? await withTimeout(
5300
+ findPromise,
5301
+ await resolveExternalTimeout(matchedObject.datasource ?? "default"),
5302
+ plan.objectName
5303
+ ) : await findPromise;
5288
5304
  return JSON.stringify({
5289
5305
  plan: { ...plan, where },
5290
5306
  count: records.length,
@@ -5298,6 +5314,28 @@ function createQueryDataHandler(ctx) {
5298
5314
  }
5299
5315
  };
5300
5316
  }
5317
+ function withTimeout(p, ms, object) {
5318
+ return new Promise((resolve, reject) => {
5319
+ const timer = setTimeout(() => {
5320
+ reject(
5321
+ new Error(
5322
+ `query on external object '${object}' exceeded the ${ms}ms timeout. Narrow the filter or lower the limit.`
5323
+ )
5324
+ );
5325
+ }, ms);
5326
+ timer.unref?.();
5327
+ p.then(
5328
+ (v) => {
5329
+ clearTimeout(timer);
5330
+ resolve(v);
5331
+ },
5332
+ (e) => {
5333
+ clearTimeout(timer);
5334
+ reject(e);
5335
+ }
5336
+ );
5337
+ });
5338
+ }
5301
5339
  function registerQueryDataTool(registry, context) {
5302
5340
  registry.register(QUERY_DATA_TOOL, createQueryDataHandler(context));
5303
5341
  }
@@ -6833,7 +6871,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6833
6871
  async start(ctx) {
6834
6872
  if (!this.service) return;
6835
6873
  let metadataService;
6836
- const withTimeout = (promise, ms = 2e3) => Promise.race([promise, new Promise((resolve) => setTimeout(() => resolve(null), ms))]);
6874
+ const withTimeout2 = (promise, ms = 2e3) => Promise.race([promise, new Promise((resolve) => setTimeout(() => resolve(null), ms))]);
6837
6875
  try {
6838
6876
  metadataService = ctx.getService("metadata");
6839
6877
  console.log("[AI Plugin] Retrieved metadata service:", !!metadataService, "has getRegisteredTypes:", typeof metadataService?.getRegisteredTypes);
@@ -6842,7 +6880,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6842
6880
  ctx.logger.debug("[AI] Metadata service not available");
6843
6881
  }
6844
6882
  if (metadataService && typeof metadataService.exists === "function") {
6845
- const probeResult = await withTimeout(metadataService.exists("tool", "__probe__"), 3e3);
6883
+ const probeResult = await withTimeout2(metadataService.exists("tool", "__probe__"), 3e3);
6846
6884
  if (probeResult === null) {
6847
6885
  ctx.logger.warn("[AI] Metadata service unreachable (timed out) \u2014 AI tools/agents will work but Studio visibility unavailable");
6848
6886
  metadataService = void 0;
@@ -6914,7 +6952,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6914
6952
  if (metadataService) {
6915
6953
  const { DATA_TOOL_DEFINITIONS: DATA_TOOL_DEFINITIONS2 } = await Promise.resolve().then(() => (init_data_tools(), data_tools_exports));
6916
6954
  for (const toolDef of DATA_TOOL_DEFINITIONS2) {
6917
- const toolExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("tool", toolDef.name)) : false;
6955
+ const toolExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("tool", toolDef.name)) : false;
6918
6956
  if (toolExists === null) {
6919
6957
  ctx.logger.warn("[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence");
6920
6958
  break;
@@ -6922,7 +6960,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6922
6960
  if (!toolExists) {
6923
6961
  try {
6924
6962
  const label = toolDef.label ?? toToolLabel(toolDef.name);
6925
- await withTimeout(metadataService.register("tool", toolDef.name, { ...toolDef, label }));
6963
+ await withTimeout2(metadataService.register("tool", toolDef.name, { ...toolDef, label }));
6926
6964
  } catch (err) {
6927
6965
  ctx.logger.warn(
6928
6966
  "[AI] Failed to persist tool metadata (non-fatal)",
@@ -6935,11 +6973,11 @@ var _AIServicePlugin = class _AIServicePlugin {
6935
6973
  }
6936
6974
  if (metadataService) {
6937
6975
  try {
6938
- const agentExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("agent", DATA_CHAT_AGENT.name)) : false;
6976
+ const agentExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("agent", DATA_CHAT_AGENT.name)) : false;
6939
6977
  if (agentExists === null) {
6940
6978
  ctx.logger.warn("[AI] Metadata service timed out checking data_chat agent, skipping");
6941
6979
  } else if (!agentExists) {
6942
- await withTimeout(metadataService.register("agent", DATA_CHAT_AGENT.name, DATA_CHAT_AGENT));
6980
+ await withTimeout2(metadataService.register("agent", DATA_CHAT_AGENT.name, DATA_CHAT_AGENT));
6943
6981
  console.log("[AI] Registered data_chat agent to metadataService");
6944
6982
  ctx.logger.info("[AI] data_chat agent registered");
6945
6983
  } else {
@@ -6950,11 +6988,11 @@ var _AIServicePlugin = class _AIServicePlugin {
6950
6988
  ctx.logger.warn("[AI] Failed to register data_chat agent", err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });
6951
6989
  }
6952
6990
  try {
6953
- const skillExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("skill", DATA_EXPLORER_SKILL.name)) : false;
6991
+ const skillExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("skill", DATA_EXPLORER_SKILL.name)) : false;
6954
6992
  if (skillExists === null) {
6955
6993
  ctx.logger.warn("[AI] Metadata service timed out checking data_explorer skill, skipping");
6956
6994
  } else if (!skillExists) {
6957
- await withTimeout(metadataService.register("skill", DATA_EXPLORER_SKILL.name, DATA_EXPLORER_SKILL));
6995
+ await withTimeout2(metadataService.register("skill", DATA_EXPLORER_SKILL.name, DATA_EXPLORER_SKILL));
6958
6996
  ctx.logger.info("[AI] data_explorer skill registered");
6959
6997
  } else {
6960
6998
  ctx.logger.debug("[AI] data_explorer skill already exists, skipping auto-registration");
@@ -6963,11 +7001,11 @@ var _AIServicePlugin = class _AIServicePlugin {
6963
7001
  ctx.logger.warn("[AI] Failed to register data_explorer skill", err instanceof Error ? { error: err.message } : { error: String(err) });
6964
7002
  }
6965
7003
  try {
6966
- const skillExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("skill", ACTIONS_EXECUTOR_SKILL.name)) : false;
7004
+ const skillExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("skill", ACTIONS_EXECUTOR_SKILL.name)) : false;
6967
7005
  if (skillExists === null) {
6968
7006
  ctx.logger.warn("[AI] Metadata service timed out checking actions_executor skill, skipping");
6969
7007
  } else if (!skillExists) {
6970
- await withTimeout(metadataService.register("skill", ACTIONS_EXECUTOR_SKILL.name, ACTIONS_EXECUTOR_SKILL));
7008
+ await withTimeout2(metadataService.register("skill", ACTIONS_EXECUTOR_SKILL.name, ACTIONS_EXECUTOR_SKILL));
6971
7009
  ctx.logger.info("[AI] actions_executor skill registered");
6972
7010
  } else {
6973
7011
  ctx.logger.debug("[AI] actions_executor skill already exists, skipping auto-registration");
@@ -6986,14 +7024,14 @@ var _AIServicePlugin = class _AIServicePlugin {
6986
7024
  ctx.logger.info("[AI] Built-in metadata tools registered");
6987
7025
  const { METADATA_TOOL_DEFINITIONS: METADATA_TOOL_DEFINITIONS2 } = await Promise.resolve().then(() => (init_metadata_tools(), metadata_tools_exports));
6988
7026
  for (const toolDef of METADATA_TOOL_DEFINITIONS2) {
6989
- const toolExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("tool", toolDef.name)) : false;
7027
+ const toolExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("tool", toolDef.name)) : false;
6990
7028
  if (toolExists === null) {
6991
7029
  ctx.logger.warn("[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence");
6992
7030
  break;
6993
7031
  }
6994
7032
  if (!toolExists) {
6995
7033
  try {
6996
- await withTimeout(metadataService.register("tool", toolDef.name, toolDef));
7034
+ await withTimeout2(metadataService.register("tool", toolDef.name, toolDef));
6997
7035
  } catch (err) {
6998
7036
  ctx.logger.warn(
6999
7037
  "[AI] Failed to persist tool metadata (non-fatal)",
@@ -7004,11 +7042,11 @@ var _AIServicePlugin = class _AIServicePlugin {
7004
7042
  }
7005
7043
  ctx.logger.info(`[AI] ${METADATA_TOOL_DEFINITIONS2.length} metadata tools registered as metadata`);
7006
7044
  try {
7007
- const agentExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("agent", METADATA_ASSISTANT_AGENT.name)) : false;
7045
+ const agentExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("agent", METADATA_ASSISTANT_AGENT.name)) : false;
7008
7046
  if (agentExists === null) {
7009
7047
  ctx.logger.warn("[AI] Metadata service timed out checking metadata_assistant agent, skipping");
7010
7048
  } else if (!agentExists) {
7011
- await withTimeout(metadataService.register("agent", METADATA_ASSISTANT_AGENT.name, METADATA_ASSISTANT_AGENT));
7049
+ await withTimeout2(metadataService.register("agent", METADATA_ASSISTANT_AGENT.name, METADATA_ASSISTANT_AGENT));
7012
7050
  console.log("[AI] Registered metadata_assistant agent to metadataService");
7013
7051
  ctx.logger.info("[AI] metadata_assistant agent registered");
7014
7052
  } else {
@@ -7019,11 +7057,11 @@ var _AIServicePlugin = class _AIServicePlugin {
7019
7057
  ctx.logger.warn("[AI] Failed to register metadata_assistant agent", err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });
7020
7058
  }
7021
7059
  try {
7022
- const skillExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("skill", METADATA_AUTHORING_SKILL.name)) : false;
7060
+ const skillExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("skill", METADATA_AUTHORING_SKILL.name)) : false;
7023
7061
  if (skillExists === null) {
7024
7062
  ctx.logger.warn("[AI] Metadata service timed out checking metadata_authoring skill, skipping");
7025
7063
  } else if (!skillExists) {
7026
- await withTimeout(metadataService.register("skill", METADATA_AUTHORING_SKILL.name, METADATA_AUTHORING_SKILL));
7064
+ await withTimeout2(metadataService.register("skill", METADATA_AUTHORING_SKILL.name, METADATA_AUTHORING_SKILL));
7027
7065
  ctx.logger.info("[AI] metadata_authoring skill registered");
7028
7066
  } else {
7029
7067
  ctx.logger.debug("[AI] metadata_authoring skill already exists, skipping auto-registration");
@@ -7047,10 +7085,10 @@ var _AIServicePlugin = class _AIServicePlugin {
7047
7085
  const agent = entry?.content ?? entry;
7048
7086
  const agentName = agent?.name;
7049
7087
  if (!agentName || typeof agentName !== "string") continue;
7050
- const exists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("agent", agentName)) : false;
7088
+ const exists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("agent", agentName)) : false;
7051
7089
  if (exists === true) continue;
7052
7090
  try {
7053
- await withTimeout(metadataService.register("agent", agentName, agent));
7091
+ await withTimeout2(metadataService.register("agent", agentName, agent));
7054
7092
  bridged++;
7055
7093
  } catch (err) {
7056
7094
  ctx.logger.warn(