@axiom-lattice/core 6.3.0 → 6.3.2

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.mjs CHANGED
@@ -18552,12 +18552,47 @@ var Agent = class {
18552
18552
  id: interruptData.id,
18553
18553
  data: { content: interruptData.value }
18554
18554
  };
18555
+ await this.awaitDurableInterrupt(interruptData.id, signal);
18555
18556
  }
18556
18557
  if (data) {
18557
18558
  this.addChunk(data);
18558
18559
  }
18559
18560
  }
18560
18561
  }
18562
+ /**
18563
+ * Waits until the thread's durable checkpoint reports the given interrupt id.
18564
+ *
18565
+ * Reads {@link getCurrentState} (the checkpoint, i.e. the single source of
18566
+ * truth), never an in-memory status, so a `true` result guarantees a resume
18567
+ * against this thread will find the interrupt. Bounded so a broken
18568
+ * checkpointer cannot strand the stream; on timeout the interrupt is emitted
18569
+ * anyway and a warning is logged.
18570
+ *
18571
+ * @param interruptId - Interrupt id from the streamed `__interrupt__` update.
18572
+ * @param signal - Run abort signal; polling stops when aborted.
18573
+ * @param timeoutMs - Maximum time to wait for durable confirmation.
18574
+ */
18575
+ async awaitDurableInterrupt(interruptId, signal, timeoutMs = 5e3) {
18576
+ if (!interruptId) return;
18577
+ const deadline = Date.now() + timeoutMs;
18578
+ while (!signal?.aborted) {
18579
+ try {
18580
+ const state = await this.getCurrentState();
18581
+ const durable = (state?.tasks ?? []).some(
18582
+ (task) => (task.interrupts ?? []).some((interrupt5) => interrupt5.id === interruptId)
18583
+ );
18584
+ if (durable) return;
18585
+ } catch {
18586
+ }
18587
+ if (Date.now() >= deadline) {
18588
+ console.warn(
18589
+ `[Agent] interrupt ${interruptId} not durable within ${timeoutMs}ms on thread ${this.thread_id}; emitting without durable confirmation`
18590
+ );
18591
+ return;
18592
+ }
18593
+ await new Promise((resolve4) => setTimeout(resolve4, 20));
18594
+ }
18595
+ }
18561
18596
  /**
18562
18597
  * Resume LangGraph execution from the last checkpoint.
18563
18598
  *
@@ -40139,6 +40174,33 @@ function clearEncryptionKeyCache() {
40139
40174
  cachedKey = null;
40140
40175
  keyValidated = false;
40141
40176
  }
40177
+ function encryptConfigFields(config, fields) {
40178
+ if (!fields?.length) return config;
40179
+ const out = { ...config };
40180
+ for (const field of fields) {
40181
+ const value = out[field];
40182
+ if (typeof value === "string" && value.length > 0) {
40183
+ out[field] = encrypt(value);
40184
+ }
40185
+ }
40186
+ return out;
40187
+ }
40188
+ function decryptConfigFields(config, fields) {
40189
+ if (!fields?.length) return config;
40190
+ const out = { ...config };
40191
+ for (const field of fields) {
40192
+ const value = out[field];
40193
+ if (typeof value === "string" && value.length > 0) {
40194
+ try {
40195
+ out[field] = decrypt(value);
40196
+ } catch (error) {
40197
+ console.error(`Failed to decrypt connection field "${field}":`, error);
40198
+ throw new Error("Failed to decrypt connection configuration");
40199
+ }
40200
+ }
40201
+ }
40202
+ return out;
40203
+ }
40142
40204
 
40143
40205
  // src/util/safeUpstreamUrl.ts
40144
40206
  var UnsafeUpstreamUrlError = class extends Error {
@@ -43672,7 +43734,7 @@ function createTaskMiddleware(options = {}) {
43672
43734
  error: "Task changed before activity could be recorded."
43673
43735
  });
43674
43736
  markMutation();
43675
- return JSON.stringify({ success: true, data: activity });
43737
+ return JSON.stringify({ success: true, data: activity, task: existing });
43676
43738
  }
43677
43739
  case "update": {
43678
43740
  taskUpdateDebug("update:enter", {
@@ -46163,6 +46225,12 @@ import { createMiddleware as createMiddleware27, tool as tool67 } from "langchai
46163
46225
  import { z as z73 } from "zod";
46164
46226
  import { AgentType as AgentType10 } from "@axiom-lattice/protocols";
46165
46227
 
46228
+ // src/connection/connectionSecretFields.ts
46229
+ function connectionSecretFields(plugin) {
46230
+ const fields = plugin?.connection?.fields ?? [];
46231
+ return fields.filter((field) => field.type === "password" || field.widget === "password").map((field) => field.key);
46232
+ }
46233
+
46166
46234
  // src/middlewares/sandboxPluginsSkills.ts
46167
46235
  var PLUGIN_JSON_TEMPLATE = `{
46168
46236
  "schemaVersion": 1,
@@ -46826,11 +46894,25 @@ Use the \`manage_plugin\` tool. The loop:
46826
46894
 
46827
46895
  1. \`action: "validate"\` with \`{ type, manifest, handlers }\` \u2014 dry-run, no writes, returns diagnostics.
46828
46896
  2. \`action: "create"\` or \`"update"\` \u2014 writes files, bumps version, reloads.
46829
- 3. \`action: "test"\` to exercise a handler without an LLM:
46897
+ 3. If the plugin has \`connection.fields\` and a tool reads credentials: a **human**
46898
+ must configure a connection of this plugin type. You cannot create credentials.
46899
+ Call \`list_connections { type }\` first \u2014 if none exist, use \`ask_user_to_clarify\`
46900
+ to state explicitly that only the human can configure the connector, ask them to
46901
+ add it (Console \u2192 Connections) and to give you the connection key. Do not claim
46902
+ the tool works until a real \`connectionKey\` test passes.
46903
+ 4. \`action: "test"\` to exercise a handler without an LLM:
46830
46904
  - Tool: \`{ type, target: { kind: "tool", name, input, connectionKey? } }\`
46831
46905
  - Connection: \`{ type, target: { kind: "connection-test" } }\` or \`{ kind: "connection-discover" }\`
46832
46906
  Returns \`{ ok, result, exitCode, durationMs, stdout, stderr }\`.
46833
- 4. \`action: "reload"\` if you edited files directly.
46907
+ For credentialed tools, pass the real \`connectionKey\`. Without one, the handler
46908
+ receives an empty connection \u2014 that only checks plumbing, NOT functional success.
46909
+ 5. \`action: "reload"\` if you edited files directly.
46910
+
46911
+ ## Secrets
46912
+ - \`list_connections\` returns identifiers only (\`key\`/\`name\`/\`description\`), never config or secrets.
46913
+ - \`test\` output is redacted: real connection secret values are replaced with
46914
+ \`[redacted]\`. Never rely on echoing credentials to verify a handler \u2014 assert on
46915
+ functional output instead.
46834
46916
 
46835
46917
  ## Common failures
46836
46918
  | Symptom | Cause |
@@ -46840,9 +46922,12 @@ Use the \`manage_plugin\` tool. The loop:
46840
46922
  | TOOL_SCHEMA | unsupported JSON Schema keyword |
46841
46923
  | non-zero exit | handler threw; read stdout/stderr from \`test\` |
46842
46924
  | old behaviour after edit | version/hash unchanged \u2014 bump \`version\` or call \`reload\` |
46925
+ | empty connection in handler | no \`connectionKey\` passed, or no connection configured for this type |
46843
46926
 
46844
46927
  Fall back to \`execute_code\`/\`shell\` to run \`node handlers/x.js\` manually with
46845
- \`PLUGIN_INPUT\` set if you need to reproduce.
46928
+ \`PLUGIN_INPUT\` and a synthetic \`PLUGIN_CONNECTION_FILE\` to reproduce logic bugs.
46929
+ A synthetic fixture only verifies plumbing \u2014 a real upstream call requires a real
46930
+ \`connectionKey\` configured by a human.
46846
46931
  `,
46847
46932
  resources: {}
46848
46933
  }
@@ -46873,8 +46958,13 @@ implemented", "UI added", "validated/tested via manage_plugin"). As you work,
46873
46958
  update each Task's status to reflect reality. Never use \`write_todos\`.
46874
46959
 
46875
46960
  Author with the \`manage_plugin\` tool: validate, then create/update, then test.
46876
- Use \`shell_exec\` (the tool provided by the \`code_eval\` middleware) to run
46877
- \`node handlers/x.js\` for manual checks when reproducing a failure.`;
46961
+ If a tool needs credentials, a human must configure the connection \u2014 use
46962
+ \`list_connections\` to check, and \`ask_user_to_clarify\` to ask the human to add
46963
+ the connector and give you its key. Only after a real \`connectionKey\` test
46964
+ passes may you call the tool verified; without it, report functionality as
46965
+ unverified (missing credentials), not as passing. Use \`shell_exec\` (the tool
46966
+ provided by the \`code_eval\` middleware) to run \`node handlers/x.js\` for manual
46967
+ checks when reproducing a failure.`;
46878
46968
 
46879
46969
  // src/middlewares/sandboxPluginsMiddleware.ts
46880
46970
  var PLUGIN_BUILDER_SKILLS = [...Object.keys(SANDBOX_PLUGIN_SKILLS), "task-tracking"];
@@ -46882,6 +46972,37 @@ function tenantIdFrom(exeConfig) {
46882
46972
  const c = exeConfig;
46883
46973
  return c?.configurable?.runConfig?.tenantId ?? "default";
46884
46974
  }
46975
+ function collectSecretValues(connection, fields) {
46976
+ if (!connection) return [];
46977
+ const values = [];
46978
+ for (const field of fields) {
46979
+ const value = connection[field];
46980
+ if (typeof value === "string" && value.length > 0) values.push(value);
46981
+ }
46982
+ return values;
46983
+ }
46984
+ function errorText(err) {
46985
+ return err instanceof Error ? err.message : String(err);
46986
+ }
46987
+ function redactString(value, secrets) {
46988
+ let out = value;
46989
+ for (const secret of secrets) out = out.split(secret).join("[redacted]");
46990
+ return out;
46991
+ }
46992
+ function redactSecretValues(payload, secrets) {
46993
+ if (secrets.length === 0) return payload;
46994
+ const walk = (node) => {
46995
+ if (typeof node === "string") return redactString(node, secrets);
46996
+ if (Array.isArray(node)) return node.map(walk);
46997
+ if (node !== null && typeof node === "object") {
46998
+ const out = {};
46999
+ for (const [key5, value] of Object.entries(node)) out[key5] = walk(value);
47000
+ return out;
47001
+ }
47002
+ return node;
47003
+ };
47004
+ return walk(payload);
47005
+ }
46885
47006
  var managePluginSchema = z73.object({
46886
47007
  action: z73.enum(["list", "get", "validate", "create", "update", "delete", "reload", "test"]),
46887
47008
  type: z73.string().optional(),
@@ -46913,6 +47034,10 @@ var sandboxPluginsPlugin = {
46913
47034
  description: "Author and manage tenant plugins in the shared sandbox: clarify goal, inputs/outputs, credentials, and whether a UI is needed; then write the manifest and JS handlers, add an optional HTML MCP App UI, and validate/test with the manage_plugin tool.",
46914
47035
  type: AgentType10.DEEP_AGENT,
46915
47036
  prompt: PLUGIN_BUILDER_PROMPT,
47037
+ // Read-only discovery of connection identifiers (metadata only — never
47038
+ // config/secrets) so the builder can confirm a human configured a
47039
+ // connector and pass its key to `manage_plugin test`.
47040
+ tools: ["list_connections"],
46916
47041
  middleware: [
46917
47042
  {
46918
47043
  id: "sandbox-plugins",
@@ -47048,8 +47173,19 @@ var sandboxPluginsPlugin = {
47048
47173
  input.target.connectionKey ? { connections: [input.target.connectionKey] } : { connectAll: true },
47049
47174
  { tenantId: tenantId2 }
47050
47175
  );
47051
- const result2 = await plugin.connection?.test?.(connection ?? {});
47052
- return JSON.stringify(result2 ?? { ok: false, message: "no test handler" });
47176
+ const secrets2 = collectSecretValues(connection, connectionSecretFields(plugin));
47177
+ try {
47178
+ const result = await plugin.connection?.test?.(connection ?? {});
47179
+ return JSON.stringify(redactSecretValues(
47180
+ result ?? { ok: false, message: "no test handler" },
47181
+ secrets2
47182
+ ));
47183
+ } catch (err) {
47184
+ return JSON.stringify(redactSecretValues(
47185
+ { ok: false, message: errorText(err) },
47186
+ secrets2
47187
+ ));
47188
+ }
47053
47189
  }
47054
47190
  if (input.target.kind === "connection-discover") {
47055
47191
  const { connection } = await resolveSandboxPluginConnections(
@@ -47057,8 +47193,16 @@ var sandboxPluginsPlugin = {
47057
47193
  input.target.connectionKey ? { connections: [input.target.connectionKey] } : { connectAll: true },
47058
47194
  { tenantId: tenantId2 }
47059
47195
  );
47060
- const result2 = await plugin.connection?.discover?.(connection ?? {});
47061
- return JSON.stringify(result2 ?? []);
47196
+ const secrets2 = collectSecretValues(connection, connectionSecretFields(plugin));
47197
+ try {
47198
+ const result = await plugin.connection?.discover?.(connection ?? {});
47199
+ return JSON.stringify(redactSecretValues(result ?? [], secrets2));
47200
+ } catch (err) {
47201
+ return JSON.stringify(redactSecretValues(
47202
+ { error: errorText(err) },
47203
+ secrets2
47204
+ ));
47205
+ }
47062
47206
  }
47063
47207
  const executor = catalog2.getExecutor();
47064
47208
  const manifestContent = await catalog2.readPluginFile(tenantId2, input.type, "plugin.json");
@@ -47076,19 +47220,24 @@ var sandboxPluginsPlugin = {
47076
47220
  { connections: [input.target.connectionKey] },
47077
47221
  { tenantId: tenantId2 }
47078
47222
  ) : {};
47079
- const result = await executor.invoke({
47080
- manifest: parsedManifest,
47081
- handler: toolDef.handler,
47082
- input: input.target.input ?? null,
47083
- connection: resolved.connection,
47084
- connections: resolved.connections,
47085
- context: { tenantId: tenantId2, pluginType: input.type, tool: toolDef.name },
47086
- runConfig: {
47087
- tenantId: tenantId2,
47088
- assistantId: typeof runCfg.assistant_id === "string" ? runCfg.assistant_id : void 0
47089
- }
47090
- });
47091
- return JSON.stringify(result);
47223
+ const secrets = collectSecretValues(resolved.connection, connectionSecretFields(plugin));
47224
+ try {
47225
+ const result = await executor.invoke({
47226
+ manifest: parsedManifest,
47227
+ handler: toolDef.handler,
47228
+ input: input.target.input ?? null,
47229
+ connection: resolved.connection,
47230
+ connections: resolved.connections,
47231
+ context: { tenantId: tenantId2, pluginType: input.type, tool: toolDef.name },
47232
+ runConfig: {
47233
+ tenantId: tenantId2,
47234
+ assistantId: typeof runCfg.assistant_id === "string" ? runCfg.assistant_id : void 0
47235
+ }
47236
+ });
47237
+ return JSON.stringify(redactSecretValues(result, secrets));
47238
+ } catch (err) {
47239
+ return JSON.stringify(redactSecretValues({ ok: false, error: errorText(err) }, secrets));
47240
+ }
47092
47241
  }
47093
47242
  default:
47094
47243
  return `unsupported action: ${input.action}`;
@@ -47751,6 +47900,7 @@ export {
47751
47900
  configurePluginCatalogSync,
47752
47901
  configureStores,
47753
47902
  connectAllChannels,
47903
+ connectionSecretFields,
47754
47904
  convertToConnection,
47755
47905
  createAgentNode,
47756
47906
  createAgentTeam,
@@ -47791,11 +47941,13 @@ export {
47791
47941
  createUnknownToolHandlerMiddleware,
47792
47942
  createWidgetMiddleware,
47793
47943
  decrypt,
47944
+ decryptConfigFields,
47794
47945
  describeCronExpression,
47795
47946
  documentLearningPlugin,
47796
47947
  documentParserPlugin,
47797
47948
  embeddingsLatticeManager,
47798
47949
  encrypt,
47950
+ encryptConfigFields,
47799
47951
  ensureBuiltinAgentsForTenant,
47800
47952
  ensurePluginSkillInSandbox,
47801
47953
  evaluateLatticeCaseWithLogs,