@electric-ax/agents 0.4.0 → 0.4.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.
@@ -625,8 +625,8 @@ function createHortonDocsSupport(workingDirectory, opts = {}) {
625
625
  logPrefix: `[horton-docs]`
626
626
  });
627
627
  function resolveCurrentQuestion(wake, events, inbox) {
628
- if (wake.type === `message_received`) {
629
- const eventQuestion = findLatestQuestion(events.filter((event) => event.type === `message_received`).map((event) => event.value));
628
+ if (wake.type === `inbox`) {
629
+ const eventQuestion = findLatestQuestion(events.filter((event) => event.type === `inbox`).map((event) => event.value));
630
630
  if (eventQuestion) return eventQuestion;
631
631
  }
632
632
  const wakeQuestion = payloadToText(wake.payload).trim();
@@ -885,11 +885,11 @@ function createSpawnWorkerTool(ctx, modelConfig) {
885
885
  return {
886
886
  name: `spawn_worker`,
887
887
  label: `Spawn Worker`,
888
- description: `Dispatch a subagent (worker) to perform an isolated subtask. Provide a system prompt that briefs the worker like a colleague who just walked into the room (file paths, line numbers, what specifically to do, what form of answer you want back) and pick the subset of tools the worker needs.`,
888
+ description: `Dispatch a subagent (worker) to perform an isolated subtask. Provide a brief system prompt to give it its role and then a detailed initialMessage which briefs the worker like a colleague who just walked into the room (file paths, line numbers, what specifically to do, what form of answer you want back) and pick the subset of tools the worker needs.`,
889
889
  parameters: Type.Object({
890
- systemPrompt: Type.String({ description: `System prompt for the worker. Be concrete: include file paths, line numbers, and the form of answer you want back.` }),
890
+ systemPrompt: Type.String({ description: `System prompt for the worker.` }),
891
891
  tools: Type.Array(Type.Union(WORKER_TOOL_NAMES.map((n) => Type.Literal(n))), { description: `Subset of tool names to enable for the worker. Must include at least one.` }),
892
- initialMessage: Type.String({ description: `First user message sent to the worker. This is what kicks off its run — without it the worker will idle. Describe the concrete task to perform.` })
892
+ initialMessage: Type.String({ description: `First user message sent to the worker. Be concrete: include file paths, line numbers, and the form of answer you want back. This is what kicks off its run — without it the worker will idle. Describe the concrete task to perform and what form of message you want back.` })
893
893
  }),
894
894
  execute: async (_toolCallId, params) => {
895
895
  const { systemPrompt, tools, initialMessage } = params;
@@ -1426,7 +1426,8 @@ function registerHorton(registry, options) {
1426
1426
  const { workingDirectory, streamFn, skillsRegistry = null, modelCatalog } = options;
1427
1427
  const docsUrl = options.docsUrl ?? process.env.HORTON_DOCS_URL;
1428
1428
  if (process.env.BRAVE_SEARCH_API_KEY) serverLog.info(`[horton] Web search: using Brave Search API`);
1429
- else serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY not set — web search will fall back to Anthropic built-in search (uses your ANTHROPIC_API_KEY)`);
1429
+ else if (process.env.ANTHROPIC_API_KEY) serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY not set — web search will fall back to Anthropic built-in search`);
1430
+ else serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY and ANTHROPIC_API_KEY not set — web search tool will be unavailable`);
1430
1431
  const docsSupport = createHortonDocsSupport(workingDirectory);
1431
1432
  const docsSearchTool = docsSupport?.createSearchTool();
1432
1433
  docsSupport?.ensureReady().catch((error) => {
@@ -1902,7 +1903,7 @@ function truncate(str, max) {
1902
1903
  //#endregion
1903
1904
  //#region src/bootstrap.ts
1904
1905
  async function createBuiltinAgentHandler(options) {
1905
- const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, createElectricTools, publicUrl, runtimeName, serverHeaders, defaultDispatchPolicyForType } = options;
1906
+ const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType } = options;
1906
1907
  const modelCatalog = await createBuiltinModelCatalog({ allowMockFallback: Boolean(streamFn) });
1907
1908
  if (!modelCatalog) {
1908
1909
  serverLog.warn(`[builtin-agents] no supported model provider API key found — set ANTHROPIC_API_KEY or OPENAI_API_KEY`);
@@ -1910,7 +1911,7 @@ async function createBuiltinAgentHandler(options) {
1910
1911
  }
1911
1912
  const cwd = workingDirectory ?? process.cwd();
1912
1913
  const here = path.dirname(fileURLToPath(import.meta.url));
1913
- const baseSkillsDir = path.resolve(here, `../skills`);
1914
+ const baseSkillsDir = baseSkillsDirOverride ?? path.resolve(here, `../skills`);
1914
1915
  let skillsRegistry = null;
1915
1916
  try {
1916
1917
  skillsRegistry = await createSkillsRegistry({
@@ -1962,6 +1963,19 @@ async function registerBuiltinAgentTypes(bootstrap) {
1962
1963
 
1963
1964
  //#endregion
1964
1965
  //#region src/server.ts
1966
+ const PRINCIPAL_KEY_PREFIXES = new Set([
1967
+ `user`,
1968
+ `agent`,
1969
+ `service`,
1970
+ `system`
1971
+ ]);
1972
+ function normalizeOwnerUserId(ownerUserId) {
1973
+ const trimmed = ownerUserId?.trim();
1974
+ if (!trimmed) return void 0;
1975
+ const colon = trimmed.indexOf(`:`);
1976
+ if (colon > 0 && PRINCIPAL_KEY_PREFIXES.has(trimmed.slice(0, colon))) return trimmed;
1977
+ return `user:${trimmed}`;
1978
+ }
1965
1979
  var BuiltinAgentsServer = class {
1966
1980
  bootstrap = null;
1967
1981
  _mcpRegistry = null;
@@ -2098,6 +2112,7 @@ var BuiltinAgentsServer = class {
2098
2112
  createElectricTools: this.options.createElectricTools,
2099
2113
  publicUrl,
2100
2114
  runtimeName: `builtin-agents`,
2115
+ baseSkillsDir: this.options.baseSkillsDir,
2101
2116
  serverHeaders: pullWake.headers
2102
2117
  });
2103
2118
  if (!this.bootstrap) throw new Error(`ANTHROPIC_API_KEY or OPENAI_API_KEY must be set before starting builtin agents`);
@@ -2165,22 +2180,35 @@ var BuiltinAgentsServer = class {
2165
2180
  async registerPullWakeRunner(pullWake) {
2166
2181
  const headers = new Headers(typeof pullWake.headers === `function` ? await pullWake.headers() : pullWake.headers);
2167
2182
  headers.set(`content-type`, `application/json`);
2183
+ const ownerUserId = normalizeOwnerUserId(pullWake.ownerUserId);
2184
+ const body = {
2185
+ id: pullWake.runnerId,
2186
+ label: pullWake.label ?? `Built-in agents`,
2187
+ kind: `local`,
2188
+ admin_status: `enabled`
2189
+ };
2190
+ if (ownerUserId) body.owner_user_id = ownerUserId;
2168
2191
  const response = await fetch(appendPathToUrl(this.options.agentServerUrl, `/_electric/runners`), {
2169
2192
  method: `POST`,
2170
2193
  headers,
2171
- body: JSON.stringify({
2172
- id: pullWake.runnerId,
2173
- owner_user_id: pullWake.ownerUserId,
2174
- label: pullWake.label ?? `Built-in agents`,
2175
- kind: `local`,
2176
- admin_status: `enabled`
2177
- })
2194
+ body: JSON.stringify(body)
2178
2195
  });
2179
2196
  if (!response.ok) throw new Error(`Failed to register pull-wake runner ${pullWake.runnerId}: ${response.status} ${await response.text()}`);
2180
2197
  return await response.json();
2181
2198
  }
2182
2199
  };
2183
2200
 
2201
+ //#endregion
2202
+ //#region src/server-headers.ts
2203
+ const ELECTRIC_PRINCIPAL_HEADER = `electric-principal`;
2204
+ function mergeElectricPrincipalHeader(headers, principal) {
2205
+ const merged = new Headers(headers);
2206
+ const trimmedPrincipal = principal?.trim();
2207
+ if (trimmedPrincipal !== void 0 && trimmedPrincipal.length > 0) merged.set(ELECTRIC_PRINCIPAL_HEADER, trimmedPrincipal);
2208
+ const normalized = Object.fromEntries(merged.entries());
2209
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
2210
+ }
2211
+
2184
2212
  //#endregion
2185
2213
  //#region src/entrypoint-lib.ts
2186
2214
  function readEnv(env, names) {
@@ -2203,14 +2231,6 @@ function validateUrl(name, value) {
2203
2231
  throw new Error(`Invalid ${name}: "${value}"`);
2204
2232
  }
2205
2233
  }
2206
- function buildAssertedAuthHeaders(env) {
2207
- const headers = {};
2208
- const email = readEnv(env, [`ELECTRIC_ASSERTED_AUTH_EMAIL`]);
2209
- const name = readEnv(env, [`ELECTRIC_ASSERTED_AUTH_NAME`]);
2210
- if (email) headers[`X-Electric-Asserted-Email`] = email;
2211
- if (name) headers[`X-Electric-Asserted-Name`] = name;
2212
- return Object.keys(headers).length > 0 ? headers : void 0;
2213
- }
2214
2234
  function parseAdditionalServerHeaders(env) {
2215
2235
  const raw = readEnv(env, [`ELECTRIC_AGENTS_SERVER_HEADERS`]);
2216
2236
  if (!raw) return void 0;
@@ -2244,7 +2264,7 @@ function hasHeader(headers, name) {
2244
2264
  function resolveBuiltinAgentsEntrypointOptions(env = process.env, cwd = process.cwd()) {
2245
2265
  const agentServerUrl = validateUrl(`agent server URL`, readRequiredEnv(env, [`ELECTRIC_AGENTS_SERVER_URL`, `ELECTRIC_AGENTS_BASE_URL`], `agent server base URL`));
2246
2266
  const runnerId = readRequiredEnv(env, [`ELECTRIC_AGENTS_PULL_WAKE_RUNNER_ID`, `PULL_WAKE_RUNNER_ID`], `pull-wake runner id`);
2247
- const serverHeaders = mergeHeaders(buildAssertedAuthHeaders(env), parseAdditionalServerHeaders(env));
2267
+ const serverHeaders = mergeHeaders(mergeElectricPrincipalHeader(parseAdditionalServerHeaders(env), readEnv(env, [`ELECTRIC_AGENTS_PRINCIPAL`])));
2248
2268
  return {
2249
2269
  agentServerUrl,
2250
2270
  workingDirectory: readEnv(env, [`ELECTRIC_AGENTS_WORKING_DIRECTORY`, `WORKING_DIRECTORY`]) ?? cwd,
package/dist/index.cjs CHANGED
@@ -22,6 +22,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
22
22
  }) : target, mod));
23
23
 
24
24
  //#endregion
25
+ const require_server_headers = require('./server-headers-65vIhxvJ.cjs');
25
26
  const node_path = __toESM(require("node:path"));
26
27
  const node_url = __toESM(require("node:url"));
27
28
  const __electric_ax_agents_runtime = __toESM(require("@electric-ax/agents-runtime"));
@@ -648,8 +649,8 @@ function createHortonDocsSupport(workingDirectory, opts = {}) {
648
649
  logPrefix: `[horton-docs]`
649
650
  });
650
651
  function resolveCurrentQuestion(wake, events, inbox) {
651
- if (wake.type === `message_received`) {
652
- const eventQuestion = findLatestQuestion(events.filter((event) => event.type === `message_received`).map((event) => event.value));
652
+ if (wake.type === `inbox`) {
653
+ const eventQuestion = findLatestQuestion(events.filter((event) => event.type === `inbox`).map((event) => event.value));
653
654
  if (eventQuestion) return eventQuestion;
654
655
  }
655
656
  const wakeQuestion = payloadToText(wake.payload).trim();
@@ -908,11 +909,11 @@ function createSpawnWorkerTool(ctx, modelConfig) {
908
909
  return {
909
910
  name: `spawn_worker`,
910
911
  label: `Spawn Worker`,
911
- description: `Dispatch a subagent (worker) to perform an isolated subtask. Provide a system prompt that briefs the worker like a colleague who just walked into the room (file paths, line numbers, what specifically to do, what form of answer you want back) and pick the subset of tools the worker needs.`,
912
+ description: `Dispatch a subagent (worker) to perform an isolated subtask. Provide a brief system prompt to give it its role and then a detailed initialMessage which briefs the worker like a colleague who just walked into the room (file paths, line numbers, what specifically to do, what form of answer you want back) and pick the subset of tools the worker needs.`,
912
913
  parameters: __sinclair_typebox.Type.Object({
913
- systemPrompt: __sinclair_typebox.Type.String({ description: `System prompt for the worker. Be concrete: include file paths, line numbers, and the form of answer you want back.` }),
914
+ systemPrompt: __sinclair_typebox.Type.String({ description: `System prompt for the worker.` }),
914
915
  tools: __sinclair_typebox.Type.Array(__sinclair_typebox.Type.Union(WORKER_TOOL_NAMES.map((n) => __sinclair_typebox.Type.Literal(n))), { description: `Subset of tool names to enable for the worker. Must include at least one.` }),
915
- initialMessage: __sinclair_typebox.Type.String({ description: `First user message sent to the worker. This is what kicks off its run — without it the worker will idle. Describe the concrete task to perform.` })
916
+ initialMessage: __sinclair_typebox.Type.String({ description: `First user message sent to the worker. Be concrete: include file paths, line numbers, and the form of answer you want back. This is what kicks off its run — without it the worker will idle. Describe the concrete task to perform and what form of message you want back.` })
916
917
  }),
917
918
  execute: async (_toolCallId, params) => {
918
919
  const { systemPrompt, tools, initialMessage } = params;
@@ -1450,7 +1451,8 @@ function registerHorton(registry, options) {
1450
1451
  const { workingDirectory, streamFn, skillsRegistry = null, modelCatalog } = options;
1451
1452
  const docsUrl = options.docsUrl ?? process.env.HORTON_DOCS_URL;
1452
1453
  if (process.env.BRAVE_SEARCH_API_KEY) serverLog.info(`[horton] Web search: using Brave Search API`);
1453
- else serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY not set — web search will fall back to Anthropic built-in search (uses your ANTHROPIC_API_KEY)`);
1454
+ else if (process.env.ANTHROPIC_API_KEY) serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY not set — web search will fall back to Anthropic built-in search`);
1455
+ else serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY and ANTHROPIC_API_KEY not set — web search tool will be unavailable`);
1454
1456
  const docsSupport = createHortonDocsSupport(workingDirectory);
1455
1457
  const docsSearchTool = docsSupport?.createSearchTool();
1456
1458
  docsSupport?.ensureReady().catch((error) => {
@@ -1927,7 +1929,7 @@ function truncate(str, max) {
1927
1929
  //#region src/bootstrap.ts
1928
1930
  const DEFAULT_BUILTIN_AGENT_HANDLER_PATH = `/_electric/builtin-agent-handler`;
1929
1931
  async function createBuiltinAgentHandler(options) {
1930
- const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, createElectricTools, publicUrl, runtimeName, serverHeaders, defaultDispatchPolicyForType } = options;
1932
+ const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType } = options;
1931
1933
  const modelCatalog = await createBuiltinModelCatalog({ allowMockFallback: Boolean(streamFn) });
1932
1934
  if (!modelCatalog) {
1933
1935
  serverLog.warn(`[builtin-agents] no supported model provider API key found — set ANTHROPIC_API_KEY or OPENAI_API_KEY`);
@@ -1935,7 +1937,7 @@ async function createBuiltinAgentHandler(options) {
1935
1937
  }
1936
1938
  const cwd = workingDirectory ?? process.cwd();
1937
1939
  const here = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
1938
- const baseSkillsDir = node_path.default.resolve(here, `../skills`);
1940
+ const baseSkillsDir = baseSkillsDirOverride ?? node_path.default.resolve(here, `../skills`);
1939
1941
  let skillsRegistry = null;
1940
1942
  try {
1941
1943
  skillsRegistry = await createSkillsRegistry({
@@ -1997,6 +1999,19 @@ const registerAgentTypes = registerBuiltinAgentTypes;
1997
1999
 
1998
2000
  //#endregion
1999
2001
  //#region src/server.ts
2002
+ const PRINCIPAL_KEY_PREFIXES = new Set([
2003
+ `user`,
2004
+ `agent`,
2005
+ `service`,
2006
+ `system`
2007
+ ]);
2008
+ function normalizeOwnerUserId(ownerUserId) {
2009
+ const trimmed = ownerUserId?.trim();
2010
+ if (!trimmed) return void 0;
2011
+ const colon = trimmed.indexOf(`:`);
2012
+ if (colon > 0 && PRINCIPAL_KEY_PREFIXES.has(trimmed.slice(0, colon))) return trimmed;
2013
+ return `user:${trimmed}`;
2014
+ }
2000
2015
  var BuiltinAgentsServer = class {
2001
2016
  bootstrap = null;
2002
2017
  _mcpRegistry = null;
@@ -2133,6 +2148,7 @@ var BuiltinAgentsServer = class {
2133
2148
  createElectricTools: this.options.createElectricTools,
2134
2149
  publicUrl,
2135
2150
  runtimeName: `builtin-agents`,
2151
+ baseSkillsDir: this.options.baseSkillsDir,
2136
2152
  serverHeaders: pullWake.headers
2137
2153
  });
2138
2154
  if (!this.bootstrap) throw new Error(`ANTHROPIC_API_KEY or OPENAI_API_KEY must be set before starting builtin agents`);
@@ -2200,16 +2216,18 @@ var BuiltinAgentsServer = class {
2200
2216
  async registerPullWakeRunner(pullWake) {
2201
2217
  const headers = new Headers(typeof pullWake.headers === `function` ? await pullWake.headers() : pullWake.headers);
2202
2218
  headers.set(`content-type`, `application/json`);
2219
+ const ownerUserId = normalizeOwnerUserId(pullWake.ownerUserId);
2220
+ const body = {
2221
+ id: pullWake.runnerId,
2222
+ label: pullWake.label ?? `Built-in agents`,
2223
+ kind: `local`,
2224
+ admin_status: `enabled`
2225
+ };
2226
+ if (ownerUserId) body.owner_user_id = ownerUserId;
2203
2227
  const response = await fetch((0, __electric_ax_agents_runtime.appendPathToUrl)(this.options.agentServerUrl, `/_electric/runners`), {
2204
2228
  method: `POST`,
2205
2229
  headers,
2206
- body: JSON.stringify({
2207
- id: pullWake.runnerId,
2208
- owner_user_id: pullWake.ownerUserId,
2209
- label: pullWake.label ?? `Built-in agents`,
2210
- kind: `local`,
2211
- admin_status: `enabled`
2212
- })
2230
+ body: JSON.stringify(body)
2213
2231
  });
2214
2232
  if (!response.ok) throw new Error(`Failed to register pull-wake runner ${pullWake.runnerId}: ${response.status} ${await response.text()}`);
2215
2233
  return await response.json();
@@ -2238,14 +2256,6 @@ function validateUrl(name, value) {
2238
2256
  throw new Error(`Invalid ${name}: "${value}"`);
2239
2257
  }
2240
2258
  }
2241
- function buildAssertedAuthHeaders(env) {
2242
- const headers = {};
2243
- const email = readEnv(env, [`ELECTRIC_ASSERTED_AUTH_EMAIL`]);
2244
- const name = readEnv(env, [`ELECTRIC_ASSERTED_AUTH_NAME`]);
2245
- if (email) headers[`X-Electric-Asserted-Email`] = email;
2246
- if (name) headers[`X-Electric-Asserted-Name`] = name;
2247
- return Object.keys(headers).length > 0 ? headers : void 0;
2248
- }
2249
2259
  function parseAdditionalServerHeaders(env) {
2250
2260
  const raw = readEnv(env, [`ELECTRIC_AGENTS_SERVER_HEADERS`]);
2251
2261
  if (!raw) return void 0;
@@ -2279,7 +2289,7 @@ function hasHeader(headers, name) {
2279
2289
  function resolveBuiltinAgentsEntrypointOptions(env = process.env, cwd = process.cwd()) {
2280
2290
  const agentServerUrl = validateUrl(`agent server URL`, readRequiredEnv(env, [`ELECTRIC_AGENTS_SERVER_URL`, `ELECTRIC_AGENTS_BASE_URL`], `agent server base URL`));
2281
2291
  const runnerId = readRequiredEnv(env, [`ELECTRIC_AGENTS_PULL_WAKE_RUNNER_ID`, `PULL_WAKE_RUNNER_ID`], `pull-wake runner id`);
2282
- const serverHeaders = mergeHeaders(buildAssertedAuthHeaders(env), parseAdditionalServerHeaders(env));
2292
+ const serverHeaders = mergeHeaders(require_server_headers.mergeElectricPrincipalHeader(parseAdditionalServerHeaders(env), readEnv(env, [`ELECTRIC_AGENTS_PRINCIPAL`])));
2283
2293
  return {
2284
2294
  agentServerUrl,
2285
2295
  workingDirectory: readEnv(env, [`ELECTRIC_AGENTS_WORKING_DIRECTORY`, `WORKING_DIRECTORY`]) ?? cwd,
package/dist/index.d.cts CHANGED
@@ -43,6 +43,8 @@ interface BuiltinAgentHandlerOptions {
43
43
  streamFn?: StreamFn;
44
44
  publicUrl?: string;
45
45
  runtimeName?: string;
46
+ /** Override for the built-in skills directory; required when embedders bundle this package. */
47
+ baseSkillsDir?: string;
46
48
  serverHeaders?: HeadersProvider;
47
49
  defaultDispatchPolicyForType?: (typeName: string) => DispatchPolicy | undefined;
48
50
  createElectricTools?: (context: {
@@ -125,6 +127,8 @@ interface BuiltinAgentsServerOptions {
125
127
  * so the embedder must opt in.
126
128
  */
127
129
  loadProjectMcpConfig?: boolean;
130
+ /** Override for the built-in skills directory; required when embedders bundle this package. */
131
+ baseSkillsDir?: string;
128
132
  createElectricTools?: (context: {
129
133
  entityUrl: string;
130
134
  entityType: string;
package/dist/index.d.ts CHANGED
@@ -43,6 +43,8 @@ interface BuiltinAgentHandlerOptions {
43
43
  streamFn?: StreamFn;
44
44
  publicUrl?: string;
45
45
  runtimeName?: string;
46
+ /** Override for the built-in skills directory; required when embedders bundle this package. */
47
+ baseSkillsDir?: string;
46
48
  serverHeaders?: HeadersProvider;
47
49
  defaultDispatchPolicyForType?: (typeName: string) => DispatchPolicy | undefined;
48
50
  createElectricTools?: (context: {
@@ -125,6 +127,8 @@ interface BuiltinAgentsServerOptions {
125
127
  * so the embedder must opt in.
126
128
  */
127
129
  loadProjectMcpConfig?: boolean;
130
+ /** Override for the built-in skills directory; required when embedders bundle this package. */
131
+ baseSkillsDir?: string;
128
132
  createElectricTools?: (context: {
129
133
  entityUrl: string;
130
134
  entityType: string;
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { mergeElectricPrincipalHeader } from "./server-headers-KD5yHFYT.js";
1
2
  import path from "node:path";
2
3
  import { fileURLToPath } from "node:url";
3
4
  import { appendPathToUrl, completeWithLowCostModel, createEntityRegistry, createPullWakeRunner, createRuntimeHandler, db, detectAvailableProviders, readCodexAccessToken, registerToolProvider, unregisterToolProvider } from "@electric-ax/agents-runtime";
@@ -624,8 +625,8 @@ function createHortonDocsSupport(workingDirectory, opts = {}) {
624
625
  logPrefix: `[horton-docs]`
625
626
  });
626
627
  function resolveCurrentQuestion(wake, events, inbox) {
627
- if (wake.type === `message_received`) {
628
- const eventQuestion = findLatestQuestion(events.filter((event) => event.type === `message_received`).map((event) => event.value));
628
+ if (wake.type === `inbox`) {
629
+ const eventQuestion = findLatestQuestion(events.filter((event) => event.type === `inbox`).map((event) => event.value));
629
630
  if (eventQuestion) return eventQuestion;
630
631
  }
631
632
  const wakeQuestion = payloadToText(wake.payload).trim();
@@ -884,11 +885,11 @@ function createSpawnWorkerTool(ctx, modelConfig) {
884
885
  return {
885
886
  name: `spawn_worker`,
886
887
  label: `Spawn Worker`,
887
- description: `Dispatch a subagent (worker) to perform an isolated subtask. Provide a system prompt that briefs the worker like a colleague who just walked into the room (file paths, line numbers, what specifically to do, what form of answer you want back) and pick the subset of tools the worker needs.`,
888
+ description: `Dispatch a subagent (worker) to perform an isolated subtask. Provide a brief system prompt to give it its role and then a detailed initialMessage which briefs the worker like a colleague who just walked into the room (file paths, line numbers, what specifically to do, what form of answer you want back) and pick the subset of tools the worker needs.`,
888
889
  parameters: Type.Object({
889
- systemPrompt: Type.String({ description: `System prompt for the worker. Be concrete: include file paths, line numbers, and the form of answer you want back.` }),
890
+ systemPrompt: Type.String({ description: `System prompt for the worker.` }),
890
891
  tools: Type.Array(Type.Union(WORKER_TOOL_NAMES.map((n) => Type.Literal(n))), { description: `Subset of tool names to enable for the worker. Must include at least one.` }),
891
- initialMessage: Type.String({ description: `First user message sent to the worker. This is what kicks off its run — without it the worker will idle. Describe the concrete task to perform.` })
892
+ initialMessage: Type.String({ description: `First user message sent to the worker. Be concrete: include file paths, line numbers, and the form of answer you want back. This is what kicks off its run — without it the worker will idle. Describe the concrete task to perform and what form of message you want back.` })
892
893
  }),
893
894
  execute: async (_toolCallId, params) => {
894
895
  const { systemPrompt, tools, initialMessage } = params;
@@ -1426,7 +1427,8 @@ function registerHorton(registry, options) {
1426
1427
  const { workingDirectory, streamFn, skillsRegistry = null, modelCatalog } = options;
1427
1428
  const docsUrl = options.docsUrl ?? process.env.HORTON_DOCS_URL;
1428
1429
  if (process.env.BRAVE_SEARCH_API_KEY) serverLog.info(`[horton] Web search: using Brave Search API`);
1429
- else serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY not set — web search will fall back to Anthropic built-in search (uses your ANTHROPIC_API_KEY)`);
1430
+ else if (process.env.ANTHROPIC_API_KEY) serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY not set — web search will fall back to Anthropic built-in search`);
1431
+ else serverLog.warn(`[horton] BRAVE_SEARCH_API_KEY and ANTHROPIC_API_KEY not set — web search tool will be unavailable`);
1430
1432
  const docsSupport = createHortonDocsSupport(workingDirectory);
1431
1433
  const docsSearchTool = docsSupport?.createSearchTool();
1432
1434
  docsSupport?.ensureReady().catch((error) => {
@@ -1903,7 +1905,7 @@ function truncate(str, max) {
1903
1905
  //#region src/bootstrap.ts
1904
1906
  const DEFAULT_BUILTIN_AGENT_HANDLER_PATH = `/_electric/builtin-agent-handler`;
1905
1907
  async function createBuiltinAgentHandler(options) {
1906
- const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, createElectricTools, publicUrl, runtimeName, serverHeaders, defaultDispatchPolicyForType } = options;
1908
+ const { agentServerUrl, serveEndpoint, workingDirectory, streamFn, createElectricTools, publicUrl, runtimeName, baseSkillsDir: baseSkillsDirOverride, serverHeaders, defaultDispatchPolicyForType } = options;
1907
1909
  const modelCatalog = await createBuiltinModelCatalog({ allowMockFallback: Boolean(streamFn) });
1908
1910
  if (!modelCatalog) {
1909
1911
  serverLog.warn(`[builtin-agents] no supported model provider API key found — set ANTHROPIC_API_KEY or OPENAI_API_KEY`);
@@ -1911,7 +1913,7 @@ async function createBuiltinAgentHandler(options) {
1911
1913
  }
1912
1914
  const cwd = workingDirectory ?? process.cwd();
1913
1915
  const here = path.dirname(fileURLToPath(import.meta.url));
1914
- const baseSkillsDir = path.resolve(here, `../skills`);
1916
+ const baseSkillsDir = baseSkillsDirOverride ?? path.resolve(here, `../skills`);
1915
1917
  let skillsRegistry = null;
1916
1918
  try {
1917
1919
  skillsRegistry = await createSkillsRegistry({
@@ -1973,6 +1975,19 @@ const registerAgentTypes = registerBuiltinAgentTypes;
1973
1975
 
1974
1976
  //#endregion
1975
1977
  //#region src/server.ts
1978
+ const PRINCIPAL_KEY_PREFIXES = new Set([
1979
+ `user`,
1980
+ `agent`,
1981
+ `service`,
1982
+ `system`
1983
+ ]);
1984
+ function normalizeOwnerUserId(ownerUserId) {
1985
+ const trimmed = ownerUserId?.trim();
1986
+ if (!trimmed) return void 0;
1987
+ const colon = trimmed.indexOf(`:`);
1988
+ if (colon > 0 && PRINCIPAL_KEY_PREFIXES.has(trimmed.slice(0, colon))) return trimmed;
1989
+ return `user:${trimmed}`;
1990
+ }
1976
1991
  var BuiltinAgentsServer = class {
1977
1992
  bootstrap = null;
1978
1993
  _mcpRegistry = null;
@@ -2109,6 +2124,7 @@ var BuiltinAgentsServer = class {
2109
2124
  createElectricTools: this.options.createElectricTools,
2110
2125
  publicUrl,
2111
2126
  runtimeName: `builtin-agents`,
2127
+ baseSkillsDir: this.options.baseSkillsDir,
2112
2128
  serverHeaders: pullWake.headers
2113
2129
  });
2114
2130
  if (!this.bootstrap) throw new Error(`ANTHROPIC_API_KEY or OPENAI_API_KEY must be set before starting builtin agents`);
@@ -2176,16 +2192,18 @@ var BuiltinAgentsServer = class {
2176
2192
  async registerPullWakeRunner(pullWake) {
2177
2193
  const headers = new Headers(typeof pullWake.headers === `function` ? await pullWake.headers() : pullWake.headers);
2178
2194
  headers.set(`content-type`, `application/json`);
2195
+ const ownerUserId = normalizeOwnerUserId(pullWake.ownerUserId);
2196
+ const body = {
2197
+ id: pullWake.runnerId,
2198
+ label: pullWake.label ?? `Built-in agents`,
2199
+ kind: `local`,
2200
+ admin_status: `enabled`
2201
+ };
2202
+ if (ownerUserId) body.owner_user_id = ownerUserId;
2179
2203
  const response = await fetch(appendPathToUrl(this.options.agentServerUrl, `/_electric/runners`), {
2180
2204
  method: `POST`,
2181
2205
  headers,
2182
- body: JSON.stringify({
2183
- id: pullWake.runnerId,
2184
- owner_user_id: pullWake.ownerUserId,
2185
- label: pullWake.label ?? `Built-in agents`,
2186
- kind: `local`,
2187
- admin_status: `enabled`
2188
- })
2206
+ body: JSON.stringify(body)
2189
2207
  });
2190
2208
  if (!response.ok) throw new Error(`Failed to register pull-wake runner ${pullWake.runnerId}: ${response.status} ${await response.text()}`);
2191
2209
  return await response.json();
@@ -2214,14 +2232,6 @@ function validateUrl(name, value) {
2214
2232
  throw new Error(`Invalid ${name}: "${value}"`);
2215
2233
  }
2216
2234
  }
2217
- function buildAssertedAuthHeaders(env) {
2218
- const headers = {};
2219
- const email = readEnv(env, [`ELECTRIC_ASSERTED_AUTH_EMAIL`]);
2220
- const name = readEnv(env, [`ELECTRIC_ASSERTED_AUTH_NAME`]);
2221
- if (email) headers[`X-Electric-Asserted-Email`] = email;
2222
- if (name) headers[`X-Electric-Asserted-Name`] = name;
2223
- return Object.keys(headers).length > 0 ? headers : void 0;
2224
- }
2225
2235
  function parseAdditionalServerHeaders(env) {
2226
2236
  const raw = readEnv(env, [`ELECTRIC_AGENTS_SERVER_HEADERS`]);
2227
2237
  if (!raw) return void 0;
@@ -2255,7 +2265,7 @@ function hasHeader(headers, name) {
2255
2265
  function resolveBuiltinAgentsEntrypointOptions(env = process.env, cwd = process.cwd()) {
2256
2266
  const agentServerUrl = validateUrl(`agent server URL`, readRequiredEnv(env, [`ELECTRIC_AGENTS_SERVER_URL`, `ELECTRIC_AGENTS_BASE_URL`], `agent server base URL`));
2257
2267
  const runnerId = readRequiredEnv(env, [`ELECTRIC_AGENTS_PULL_WAKE_RUNNER_ID`, `PULL_WAKE_RUNNER_ID`], `pull-wake runner id`);
2258
- const serverHeaders = mergeHeaders(buildAssertedAuthHeaders(env), parseAdditionalServerHeaders(env));
2268
+ const serverHeaders = mergeHeaders(mergeElectricPrincipalHeader(parseAdditionalServerHeaders(env), readEnv(env, [`ELECTRIC_AGENTS_PRINCIPAL`])));
2259
2269
  return {
2260
2270
  agentServerUrl,
2261
2271
  workingDirectory: readEnv(env, [`ELECTRIC_AGENTS_WORKING_DIRECTORY`, `WORKING_DIRECTORY`]) ?? cwd,
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ //#region src/server-headers.ts
4
+ const ELECTRIC_PRINCIPAL_HEADER = `electric-principal`;
5
+ function mergeElectricPrincipalHeader(headers, principal) {
6
+ const merged = new Headers(headers);
7
+ const trimmedPrincipal = principal?.trim();
8
+ if (trimmedPrincipal !== void 0 && trimmedPrincipal.length > 0) merged.set(ELECTRIC_PRINCIPAL_HEADER, trimmedPrincipal);
9
+ const normalized = Object.fromEntries(merged.entries());
10
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
11
+ }
12
+
13
+ //#endregion
14
+ Object.defineProperty(exports, 'ELECTRIC_PRINCIPAL_HEADER', {
15
+ enumerable: true,
16
+ get: function () {
17
+ return ELECTRIC_PRINCIPAL_HEADER;
18
+ }
19
+ });
20
+ Object.defineProperty(exports, 'mergeElectricPrincipalHeader', {
21
+ enumerable: true,
22
+ get: function () {
23
+ return mergeElectricPrincipalHeader;
24
+ }
25
+ });
@@ -0,0 +1,12 @@
1
+ //#region src/server-headers.ts
2
+ const ELECTRIC_PRINCIPAL_HEADER = `electric-principal`;
3
+ function mergeElectricPrincipalHeader(headers, principal) {
4
+ const merged = new Headers(headers);
5
+ const trimmedPrincipal = principal?.trim();
6
+ if (trimmedPrincipal !== void 0 && trimmedPrincipal.length > 0) merged.set(ELECTRIC_PRINCIPAL_HEADER, trimmedPrincipal);
7
+ const normalized = Object.fromEntries(merged.entries());
8
+ return Object.keys(normalized).length > 0 ? normalized : void 0;
9
+ }
10
+
11
+ //#endregion
12
+ export { ELECTRIC_PRINCIPAL_HEADER, mergeElectricPrincipalHeader };
@@ -0,0 +1,4 @@
1
+ const require_server_headers = require('./server-headers-65vIhxvJ.cjs');
2
+
3
+ exports.ELECTRIC_PRINCIPAL_HEADER = require_server_headers.ELECTRIC_PRINCIPAL_HEADER
4
+ exports.mergeElectricPrincipalHeader = require_server_headers.mergeElectricPrincipalHeader
@@ -0,0 +1,6 @@
1
+ //#region src/server-headers.d.ts
2
+ declare const ELECTRIC_PRINCIPAL_HEADER = "electric-principal";
3
+ declare function mergeElectricPrincipalHeader(headers: HeadersInit | undefined, principal: string | undefined): Record<string, string> | undefined;
4
+
5
+ //#endregion
6
+ export { ELECTRIC_PRINCIPAL_HEADER, mergeElectricPrincipalHeader };
@@ -0,0 +1,6 @@
1
+ //#region src/server-headers.d.ts
2
+ declare const ELECTRIC_PRINCIPAL_HEADER = "electric-principal";
3
+ declare function mergeElectricPrincipalHeader(headers: HeadersInit | undefined, principal: string | undefined): Record<string, string> | undefined;
4
+
5
+ //#endregion
6
+ export { ELECTRIC_PRINCIPAL_HEADER, mergeElectricPrincipalHeader };
@@ -0,0 +1,3 @@
1
+ import { ELECTRIC_PRINCIPAL_HEADER, mergeElectricPrincipalHeader } from "./server-headers-KD5yHFYT.js";
2
+
3
+ export { ELECTRIC_PRINCIPAL_HEADER, mergeElectricPrincipalHeader };
package/docs/index.md CHANGED
@@ -60,7 +60,7 @@ The function that runs when an entity wakes. Receives a [`HandlerContext`](/docs
60
60
  ```ts
61
61
  registry.define("support", {
62
62
  async handler(ctx, wake) {
63
- if (wake.type === "message_received") {
63
+ if (wake.type === "inbox") {
64
64
  ctx.useAgent({
65
65
  systemPrompt: "You are a support agent.",
66
66
  model: "claude-sonnet-4-5-20250929",
@@ -78,11 +78,11 @@ Events that trigger a handler invocation. Wake sources include incoming messages
78
78
 
79
79
  ```ts
80
80
  async handler(ctx, wake) {
81
- // wake.type — "message_received", "wake", etc.
81
+ // wake.type — "inbox", "wake", etc.
82
82
  // wake.source — who triggered the wake
83
83
  // wake.payload — message content or wake data
84
84
 
85
- if (wake.type === "message_received") {
85
+ if (wake.type === "inbox") {
86
86
  const userMessage = wake.payload
87
87
  // handle incoming message
88
88
  }
@@ -23,7 +23,7 @@ Every entity automatically has these 17 collections, populated by the runtime as
23
23
  | `toolCalls` | `tool_call` | `ToolCall` | Tool call lifecycle |
24
24
  | `reasoning` | `reasoning` | `Reasoning` | Reasoning block lifecycle |
25
25
  | `errors` | `error` | `ErrorEvent` | Diagnostic errors |
26
- | `inbox` | `message_received` | `MessageReceived` | Inbound messages |
26
+ | `inbox` | `inbox` | `MessageReceived` | Inbound messages |
27
27
  | `wakes` | `wake` | `WakeEntry` | Wake delivery records |
28
28
  | `entityCreated` | `entity_created` | `EntityCreated` | Entity bootstrap metadata |
29
29
  | `entityStopped` | `entity_stopped` | `EntityStopped` | Entity shutdown signal |
@@ -20,6 +20,8 @@ npm install -g electric-ax
20
20
  | -------------------------------- | ----------------------- | -------------------------------------------- |
21
21
  | `ELECTRIC_AGENTS_URL` | `http://localhost:4437` | Server URL for entity commands and built-ins |
22
22
  | `ELECTRIC_AGENTS_IDENTITY` | `user@hostname` | Sender identity for messages |
23
+ | `ELECTRIC_AGENTS_PRINCIPAL` | - | Optional principal key sent as `Electric-Principal` |
24
+ | `ELECTRIC_AGENTS_SERVER_HEADERS` | - | Optional JSON object of additional server headers |
23
25
  | `ELECTRIC_AGENTS_PORT` | `4437` | Port used by `start` / `quickstart` |
24
26
  | `ELECTRIC_AGENTS_BUILTIN_PORT` | `4448` | Webhook port for `start-builtin` |
25
27
  | `ELECTRIC_AGENTS_COMPOSE_PROJECT` | `electric-agents` | Docker Compose project name |
@@ -30,7 +30,7 @@ type WakeEvent = {
30
30
  | Field | Type | Description |
31
31
  | ------------ | --------- | ------------------------------------------------------------------------ |
32
32
  | `source` | `string` | URL or identifier of the stream that triggered the wake. |
33
- | `type` | `string` | Wake type. Usually `"message_received"` or `"wake"`; fallback webhook events can use `triggerEvent` or `"message"`. See catalog. |
33
+ | `type` | `string` | Wake type. Usually `"inbox"` or `"wake"`; fallback webhook events can use `triggerEvent` or `"message"`. See catalog. |
34
34
  | `fromOffset` | `number` | Start offset of new events in the source stream. |
35
35
  | `toOffset` | `number` | End offset (exclusive) of new events. |
36
36
  | `eventCount` | `number` | Number of new events in this wake. |
@@ -40,9 +40,9 @@ type WakeEvent = {
40
40
 
41
41
  ## Wake-type catalog
42
42
 
43
- Handlers usually see two values for `wake.type`. Direct inbox messages arrive as `"message_received"`. Most non-message triggers are flattened into `"wake"`, with the specifics carried on `wake.payload`. Low-level webhook fallbacks can surface `triggerEvent` directly, or `"message"` when no trigger event is provided.
43
+ Handlers usually see two values for `wake.type`. Direct inbox messages arrive as `"inbox"`. Most non-message triggers are flattened into `"wake"`, with the specifics carried on `wake.payload`. Low-level webhook fallbacks can surface `triggerEvent` directly, or `"message"` when no trigger event is provided.
44
44
 
45
- ### `"message_received"`
45
+ ### `"inbox"`
46
46
 
47
47
  An external message landed in the entity's inbox — from `ctx.send()`, the CLI's `electric agents send`, or any direct `/send` HTTP call.
48
48
 
@@ -89,7 +89,7 @@ Inspect the payload to distinguish the sub-kind:
89
89
  | Observed change | `ctx.observe(..., { wake: { on: 'change' } })` or `observe(db(...))` | `payload.changes` is non-empty |
90
90
  | Shared-state change | `await ctx.observe(db(...), { wake: { on: 'change' } })` | `payload.changes` is non-empty, `payload.source` identifies the shared-state stream |
91
91
  | Cron fired | A cron schedule entry on the entity's manifest | `payload.source` identifies the schedule; `payload.changes` is empty |
92
- | Scheduled send | A `future_send` schedule fires | Arrives as `"message_received"` (not `"wake"`) — the schedule produces a message delivery |
92
+ | Scheduled send | A `future_send` schedule fires | Arrives as `"inbox"` (not `"wake"`) — the schedule produces a message delivery |
93
93
  | Timeout | `timeoutMs` on a `change` wake config elapsed with no changes | `payload.timeout === true`, `payload.changes` is empty |
94
94
 
95
95
  For the narrative on how these are produced, see [Waking entities](../usage/waking-entities).
@@ -168,6 +168,8 @@ Environment variables:
168
168
  | Variable | Description |
169
169
  | -------------------------------- | ----------------------------------------------------- |
170
170
  | `ELECTRIC_AGENTS_SERVER_URL` | Required coordinator server URL. |
171
+ | `ELECTRIC_AGENTS_PRINCIPAL` | Optional principal key sent as `Electric-Principal`. |
172
+ | `ELECTRIC_AGENTS_SERVER_HEADERS` | Optional JSON object of additional server headers. |
171
173
  | `ELECTRIC_AGENTS_BUILTIN_BASE_URL` | Public webhook base URL for the built-in server. |
172
174
  | `ELECTRIC_AGENTS_BUILTIN_HOST` | Bind host. |
173
175
  | `ELECTRIC_AGENTS_BUILTIN_PORT` | Built-in server port. Defaults to `4448`. |
@@ -129,7 +129,7 @@ async handler(ctx) {
129
129
 
130
130
  const analyst = await ctx.observe(entity("/worker/analyst"))
131
131
 
132
- if (wake.type === "message_received") {
132
+ if (wake.type === "inbox") {
133
133
  analyst.send(wake.payload)
134
134
  }
135
135
  }
@@ -31,13 +31,13 @@ There are five things that can wake an entity:
31
31
 
32
32
  ### 1. An incoming message
33
33
 
34
- Any external `/send` (via the CLI, HTTP, or another entity's `ctx.send()`) appends a `message_received` event to the entity's stream, which wakes the handler:
34
+ Any external `/send` (via the CLI, HTTP, or another entity's `ctx.send()`) appends a `inbox` event to the entity's stream, which wakes the handler:
35
35
 
36
36
  ```ts
37
37
  ctx.send("/assistant/peer", { text: "hello" })
38
38
  ```
39
39
 
40
- The receiving handler sees `wake.type === "message_received"` and finds the payload on `wake.payload`.
40
+ The receiving handler sees `wake.type === "inbox"` and finds the payload on `wake.payload`.
41
41
 
42
42
  ### 2. A spawned child
43
43
 
@@ -97,7 +97,7 @@ The minimum useful pattern is to branch on `wake.type`:
97
97
 
98
98
  ```ts
99
99
  async handler(ctx, wake) {
100
- if (wake.type === "message_received") {
100
+ if (wake.type === "inbox") {
101
101
  // external input - reply, dispatch, etc.
102
102
  ctx.useAgent({ ... })
103
103
  await ctx.agent.run()
@@ -112,8 +112,8 @@ async handler(ctx, wake) {
112
112
 
113
113
  Two wake types reach handlers directly:
114
114
 
115
- - `"message_received"` — an external message was delivered to this entity's inbox.
116
- - `"wake"` — a synthesised wake for anything else (child finished, collection change, cron, timeout). The specifics are on `wake.payload`. A future-send schedule delivers a message, so it arrives as `"message_received"`.
115
+ - `"inbox"` — an external message was delivered to this entity's inbox.
116
+ - `"wake"` — a synthesised wake for anything else (child finished, collection change, cron, timeout). The specifics are on `wake.payload`. A future-send schedule delivers a message, so it arrives as `"inbox"`.
117
117
 
118
118
  For the full payload shape (`changes[]`, `finished_child`, `other_children`, `timeout`), see the [wake-type catalog](../reference/wake-event#wake-type-catalog) in the reference.
119
119
 
@@ -120,7 +120,7 @@ type WakeEvent = {
120
120
  | Field | Description |
121
121
  | ------------ | -------------------------------------------------------------- |
122
122
  | `source` | The stream or entity that caused the wake. |
123
- | `type` | The wake type: `"message_received"` for inbox messages or `"wake"` for child completion, observed changes, cron, and timeouts. |
123
+ | `type` | The wake type: `"inbox"` for inbox messages or `"wake"` for child completion, observed changes, cron, and timeouts. |
124
124
  | `fromOffset` | Start offset of the events that triggered this wake. |
125
125
  | `toOffset` | End offset of the events that triggered this wake. |
126
126
  | `eventCount` | Number of new events since last wake. |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@electric-ax/agents",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "Built-in Electric Agents runtimes such as Horton and worker",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,6 +25,16 @@
25
25
  "default": "./dist/index.cjs"
26
26
  }
27
27
  },
28
+ "./server-headers": {
29
+ "import": {
30
+ "types": "./dist/server-headers.d.ts",
31
+ "default": "./dist/server-headers.js"
32
+ },
33
+ "require": {
34
+ "types": "./dist/server-headers.d.cts",
35
+ "default": "./dist/server-headers.cjs"
36
+ }
37
+ },
28
38
  "./package.json": "./package.json"
29
39
  },
30
40
  "dependencies": {
@@ -32,14 +42,14 @@
32
42
  "@mariozechner/pi-agent-core": "^0.70.2",
33
43
  "@mariozechner/pi-ai": "^0.70.2",
34
44
  "@sinclair/typebox": "^0.34.48",
35
- "better-sqlite3": "^11.10.0",
45
+ "better-sqlite3": "^12.9.0",
36
46
  "nanoid": "^3.3.11",
37
47
  "pino": "^10.3.1",
38
48
  "pino-pretty": "^13.0.0",
39
49
  "sqlite-vec": "^0.1.9",
40
50
  "zod": "^4.3.6",
41
- "@electric-ax/agents-mcp": "0.2.1",
42
- "@electric-ax/agents-runtime": "0.2.0"
51
+ "@electric-ax/agents-mcp": "0.2.2",
52
+ "@electric-ax/agents-runtime": "0.2.1"
43
53
  },
44
54
  "devDependencies": {
45
55
  "@types/better-sqlite3": "^7.6.13",