@objectstack/service-ai 7.3.0 → 7.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -5145,7 +5145,8 @@ var SchemaRetriever = class {
5145
5145
  if (obj.label) parts.push(obj.label);
5146
5146
  if (obj.pluralLabel && obj.pluralLabel !== obj.label) parts.push(`(${obj.pluralLabel})`);
5147
5147
  const header = parts.length > 0 ? ` \u2014 ${parts.join(" ")}` : "";
5148
- lines.push(`### ${obj.name}${header}`);
5148
+ const badge = obj.external !== void 0 ? ` [external, ${obj.external?.writable ? "writable" : "read-only"}, datasource=${obj.datasource ?? "default"}]` : "";
5149
+ lines.push(`### ${obj.name}${header}${badge}`);
5149
5150
  const fields = Object.entries(obj.fields ?? {}).slice(0, maxFieldsPerObject);
5150
5151
  for (const [name, field] of fields) {
5151
5152
  lines.push(` - ${name}: ${describeField(field)}`);
@@ -5289,6 +5290,15 @@ var QUERY_DATA_TOOL = {
5289
5290
  function createQueryDataHandler(ctx) {
5290
5291
  const retriever = new SchemaRetriever(ctx.metadata, {}, ctx.protocol);
5291
5292
  const maxLimit = ctx.maxLimit ?? 100;
5293
+ const externalTimeoutFallback = ctx.externalQueryTimeoutMs ?? 3e4;
5294
+ const resolveExternalTimeout = async (datasource) => {
5295
+ try {
5296
+ const ds = await ctx.metadata.get?.("datasource", datasource);
5297
+ return ds?.external?.queryTimeoutMs ?? externalTimeoutFallback;
5298
+ } catch {
5299
+ return externalTimeoutFallback;
5300
+ }
5301
+ };
5292
5302
  return async (args, execCtx) => {
5293
5303
  const { request } = args;
5294
5304
  if (!request || typeof request !== "string") {
@@ -5351,14 +5361,20 @@ function createQueryDataHandler(ctx) {
5351
5361
  });
5352
5362
  }
5353
5363
  }
5364
+ const isExternal = matchedObject.external !== void 0;
5354
5365
  try {
5355
- const records = await ctx.dataEngine.find(plan.objectName, {
5366
+ const findPromise = ctx.dataEngine.find(plan.objectName, {
5356
5367
  where,
5357
5368
  fields: plan.fields ?? void 0,
5358
5369
  orderBy: plan.orderBy ?? void 0,
5359
5370
  limit,
5360
5371
  context: buildAiEngineContext(execCtx)
5361
5372
  });
5373
+ const records = isExternal ? await withTimeout(
5374
+ findPromise,
5375
+ await resolveExternalTimeout(matchedObject.datasource ?? "default"),
5376
+ plan.objectName
5377
+ ) : await findPromise;
5362
5378
  return JSON.stringify({
5363
5379
  plan: { ...plan, where },
5364
5380
  count: records.length,
@@ -5372,6 +5388,28 @@ function createQueryDataHandler(ctx) {
5372
5388
  }
5373
5389
  };
5374
5390
  }
5391
+ function withTimeout(p, ms, object) {
5392
+ return new Promise((resolve, reject) => {
5393
+ const timer = setTimeout(() => {
5394
+ reject(
5395
+ new Error(
5396
+ `query on external object '${object}' exceeded the ${ms}ms timeout. Narrow the filter or lower the limit.`
5397
+ )
5398
+ );
5399
+ }, ms);
5400
+ timer.unref?.();
5401
+ p.then(
5402
+ (v) => {
5403
+ clearTimeout(timer);
5404
+ resolve(v);
5405
+ },
5406
+ (e) => {
5407
+ clearTimeout(timer);
5408
+ reject(e);
5409
+ }
5410
+ );
5411
+ });
5412
+ }
5375
5413
  function registerQueryDataTool(registry, context) {
5376
5414
  registry.register(QUERY_DATA_TOOL, createQueryDataHandler(context));
5377
5415
  }
@@ -6907,7 +6945,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6907
6945
  async start(ctx) {
6908
6946
  if (!this.service) return;
6909
6947
  let metadataService;
6910
- const withTimeout = (promise, ms = 2e3) => Promise.race([promise, new Promise((resolve) => setTimeout(() => resolve(null), ms))]);
6948
+ const withTimeout2 = (promise, ms = 2e3) => Promise.race([promise, new Promise((resolve) => setTimeout(() => resolve(null), ms))]);
6911
6949
  try {
6912
6950
  metadataService = ctx.getService("metadata");
6913
6951
  console.log("[AI Plugin] Retrieved metadata service:", !!metadataService, "has getRegisteredTypes:", typeof metadataService?.getRegisteredTypes);
@@ -6916,7 +6954,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6916
6954
  ctx.logger.debug("[AI] Metadata service not available");
6917
6955
  }
6918
6956
  if (metadataService && typeof metadataService.exists === "function") {
6919
- const probeResult = await withTimeout(metadataService.exists("tool", "__probe__"), 3e3);
6957
+ const probeResult = await withTimeout2(metadataService.exists("tool", "__probe__"), 3e3);
6920
6958
  if (probeResult === null) {
6921
6959
  ctx.logger.warn("[AI] Metadata service unreachable (timed out) \u2014 AI tools/agents will work but Studio visibility unavailable");
6922
6960
  metadataService = void 0;
@@ -6988,7 +7026,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6988
7026
  if (metadataService) {
6989
7027
  const { DATA_TOOL_DEFINITIONS: DATA_TOOL_DEFINITIONS2 } = await Promise.resolve().then(() => (init_data_tools(), data_tools_exports));
6990
7028
  for (const toolDef of DATA_TOOL_DEFINITIONS2) {
6991
- const toolExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("tool", toolDef.name)) : false;
7029
+ const toolExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("tool", toolDef.name)) : false;
6992
7030
  if (toolExists === null) {
6993
7031
  ctx.logger.warn("[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence");
6994
7032
  break;
@@ -6996,7 +7034,7 @@ var _AIServicePlugin = class _AIServicePlugin {
6996
7034
  if (!toolExists) {
6997
7035
  try {
6998
7036
  const label = toolDef.label ?? toToolLabel(toolDef.name);
6999
- await withTimeout(metadataService.register("tool", toolDef.name, { ...toolDef, label }));
7037
+ await withTimeout2(metadataService.register("tool", toolDef.name, { ...toolDef, label }));
7000
7038
  } catch (err) {
7001
7039
  ctx.logger.warn(
7002
7040
  "[AI] Failed to persist tool metadata (non-fatal)",
@@ -7009,11 +7047,11 @@ var _AIServicePlugin = class _AIServicePlugin {
7009
7047
  }
7010
7048
  if (metadataService) {
7011
7049
  try {
7012
- const agentExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("agent", DATA_CHAT_AGENT.name)) : false;
7050
+ const agentExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("agent", DATA_CHAT_AGENT.name)) : false;
7013
7051
  if (agentExists === null) {
7014
7052
  ctx.logger.warn("[AI] Metadata service timed out checking data_chat agent, skipping");
7015
7053
  } else if (!agentExists) {
7016
- await withTimeout(metadataService.register("agent", DATA_CHAT_AGENT.name, DATA_CHAT_AGENT));
7054
+ await withTimeout2(metadataService.register("agent", DATA_CHAT_AGENT.name, DATA_CHAT_AGENT));
7017
7055
  console.log("[AI] Registered data_chat agent to metadataService");
7018
7056
  ctx.logger.info("[AI] data_chat agent registered");
7019
7057
  } else {
@@ -7024,11 +7062,11 @@ var _AIServicePlugin = class _AIServicePlugin {
7024
7062
  ctx.logger.warn("[AI] Failed to register data_chat agent", err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });
7025
7063
  }
7026
7064
  try {
7027
- const skillExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("skill", DATA_EXPLORER_SKILL.name)) : false;
7065
+ const skillExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("skill", DATA_EXPLORER_SKILL.name)) : false;
7028
7066
  if (skillExists === null) {
7029
7067
  ctx.logger.warn("[AI] Metadata service timed out checking data_explorer skill, skipping");
7030
7068
  } else if (!skillExists) {
7031
- await withTimeout(metadataService.register("skill", DATA_EXPLORER_SKILL.name, DATA_EXPLORER_SKILL));
7069
+ await withTimeout2(metadataService.register("skill", DATA_EXPLORER_SKILL.name, DATA_EXPLORER_SKILL));
7032
7070
  ctx.logger.info("[AI] data_explorer skill registered");
7033
7071
  } else {
7034
7072
  ctx.logger.debug("[AI] data_explorer skill already exists, skipping auto-registration");
@@ -7037,11 +7075,11 @@ var _AIServicePlugin = class _AIServicePlugin {
7037
7075
  ctx.logger.warn("[AI] Failed to register data_explorer skill", err instanceof Error ? { error: err.message } : { error: String(err) });
7038
7076
  }
7039
7077
  try {
7040
- const skillExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("skill", ACTIONS_EXECUTOR_SKILL.name)) : false;
7078
+ const skillExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("skill", ACTIONS_EXECUTOR_SKILL.name)) : false;
7041
7079
  if (skillExists === null) {
7042
7080
  ctx.logger.warn("[AI] Metadata service timed out checking actions_executor skill, skipping");
7043
7081
  } else if (!skillExists) {
7044
- await withTimeout(metadataService.register("skill", ACTIONS_EXECUTOR_SKILL.name, ACTIONS_EXECUTOR_SKILL));
7082
+ await withTimeout2(metadataService.register("skill", ACTIONS_EXECUTOR_SKILL.name, ACTIONS_EXECUTOR_SKILL));
7045
7083
  ctx.logger.info("[AI] actions_executor skill registered");
7046
7084
  } else {
7047
7085
  ctx.logger.debug("[AI] actions_executor skill already exists, skipping auto-registration");
@@ -7060,14 +7098,14 @@ var _AIServicePlugin = class _AIServicePlugin {
7060
7098
  ctx.logger.info("[AI] Built-in metadata tools registered");
7061
7099
  const { METADATA_TOOL_DEFINITIONS: METADATA_TOOL_DEFINITIONS2 } = await Promise.resolve().then(() => (init_metadata_tools(), metadata_tools_exports));
7062
7100
  for (const toolDef of METADATA_TOOL_DEFINITIONS2) {
7063
- const toolExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("tool", toolDef.name)) : false;
7101
+ const toolExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("tool", toolDef.name)) : false;
7064
7102
  if (toolExists === null) {
7065
7103
  ctx.logger.warn("[AI] Metadata service timed out checking tool existence (non-fatal), skipping persistence");
7066
7104
  break;
7067
7105
  }
7068
7106
  if (!toolExists) {
7069
7107
  try {
7070
- await withTimeout(metadataService.register("tool", toolDef.name, toolDef));
7108
+ await withTimeout2(metadataService.register("tool", toolDef.name, toolDef));
7071
7109
  } catch (err) {
7072
7110
  ctx.logger.warn(
7073
7111
  "[AI] Failed to persist tool metadata (non-fatal)",
@@ -7078,11 +7116,11 @@ var _AIServicePlugin = class _AIServicePlugin {
7078
7116
  }
7079
7117
  ctx.logger.info(`[AI] ${METADATA_TOOL_DEFINITIONS2.length} metadata tools registered as metadata`);
7080
7118
  try {
7081
- const agentExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("agent", METADATA_ASSISTANT_AGENT.name)) : false;
7119
+ const agentExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("agent", METADATA_ASSISTANT_AGENT.name)) : false;
7082
7120
  if (agentExists === null) {
7083
7121
  ctx.logger.warn("[AI] Metadata service timed out checking metadata_assistant agent, skipping");
7084
7122
  } else if (!agentExists) {
7085
- await withTimeout(metadataService.register("agent", METADATA_ASSISTANT_AGENT.name, METADATA_ASSISTANT_AGENT));
7123
+ await withTimeout2(metadataService.register("agent", METADATA_ASSISTANT_AGENT.name, METADATA_ASSISTANT_AGENT));
7086
7124
  console.log("[AI] Registered metadata_assistant agent to metadataService");
7087
7125
  ctx.logger.info("[AI] metadata_assistant agent registered");
7088
7126
  } else {
@@ -7093,11 +7131,11 @@ var _AIServicePlugin = class _AIServicePlugin {
7093
7131
  ctx.logger.warn("[AI] Failed to register metadata_assistant agent", err instanceof Error ? { error: err.message, stack: err.stack } : { error: String(err) });
7094
7132
  }
7095
7133
  try {
7096
- const skillExists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("skill", METADATA_AUTHORING_SKILL.name)) : false;
7134
+ const skillExists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("skill", METADATA_AUTHORING_SKILL.name)) : false;
7097
7135
  if (skillExists === null) {
7098
7136
  ctx.logger.warn("[AI] Metadata service timed out checking metadata_authoring skill, skipping");
7099
7137
  } else if (!skillExists) {
7100
- await withTimeout(metadataService.register("skill", METADATA_AUTHORING_SKILL.name, METADATA_AUTHORING_SKILL));
7138
+ await withTimeout2(metadataService.register("skill", METADATA_AUTHORING_SKILL.name, METADATA_AUTHORING_SKILL));
7101
7139
  ctx.logger.info("[AI] metadata_authoring skill registered");
7102
7140
  } else {
7103
7141
  ctx.logger.debug("[AI] metadata_authoring skill already exists, skipping auto-registration");
@@ -7121,10 +7159,10 @@ var _AIServicePlugin = class _AIServicePlugin {
7121
7159
  const agent = entry?.content ?? entry;
7122
7160
  const agentName = agent?.name;
7123
7161
  if (!agentName || typeof agentName !== "string") continue;
7124
- const exists = typeof metadataService.exists === "function" ? await withTimeout(metadataService.exists("agent", agentName)) : false;
7162
+ const exists = typeof metadataService.exists === "function" ? await withTimeout2(metadataService.exists("agent", agentName)) : false;
7125
7163
  if (exists === true) continue;
7126
7164
  try {
7127
- await withTimeout(metadataService.register("agent", agentName, agent));
7165
+ await withTimeout2(metadataService.register("agent", agentName, agent));
7128
7166
  bridged++;
7129
7167
  } catch (err) {
7130
7168
  ctx.logger.warn(