@axiom-lattice/core

中文文档
12.1.1发布于 2026/11/03ISCTypeScriptESM + CJS近 30 天下载 4678

Core library for agent-based applications

原始使用文档
文档目录25 节
  1. Store Configuration
  2. configureStores
  3. Supported store keys
  4. Behavior
  5. Options
  6. Custom stores
  7. Consumer pattern
  8. Other Lattice Managers
  9. Model Lattice
  10. ChunkBuffer
  11. Directory Structure
  12. Custom Middleware Registry
  13. Quick start
  14. Database config format
  15. Full example — permission-check middleware
  16. API reference
  17. Important
  18. External Channel Integration
  19. What core provides
  20. Architecture overview
  21. Setup for custom channel development
  22. Binding resolution flow
  23. Agent-side binding management
  24. Key types (from @axiom-lattice/protocols)
  25. Reference implementation

@axiom-lattice/core

Core agent framework providing lattice managers for models, tools, agents, memory, stores, and more.

Store Configuration

configureStores

Unified store registration that replaces the manual new → initialize → remove → register boilerplate. Handles StoreLatticeManager, ScheduleLatticeManager, and MemoryLatticeManager through a single call.

import { configureStores } from "@axiom-lattice/core";
import { createPgStoreConfig } from "@axiom-lattice/pg-stores";
import { PostgresSaver } from "@langchain/langgraph-checkpoint-postgres";

// One connection string creates all PG store instances
const stores = createPgStoreConfig(process.env.DATABASE_URL);

// One call registers all stores across three managers
await configureStores({
  ...stores,
  checkpoint: PostgresSaver.fromConnString(process.env.DATABASE_URL),
}, { autoDisposeStores: true });

Supported store keys

KeyRegistered via
thread, assistant, workspace, project, database, metrics, mcp, user, tenant, userTenantLink, threadMessageQueue, workflowTracking, eval, channelInstallation, channelBinding, skillStoreLatticeManager
scheduleScheduleLatticeManager (auto-configured as POSTGRES)
checkpointMemoryLatticeManager (accepts any CheckpointSaver)

Behavior

For each store entry:

  1. Calls store.initialize() if the method exists (skipped if it requires arguments)
  2. Removes any existing "default" registration
  3. Registers the new store under "default"
  4. Tracks store.dispose for cleanup

Options

interface ConfigureStoresOptions {
  autoDisposeStores?: boolean;     // Register SIGINT/SIGTERM handlers for cleanup
  customStores?: Record<string, object>;  // Register custom store types
}

Returns a dispose function for manual cleanup regardless of autoDisposeStores.

Custom stores

Register custom store implementations that follow the same initialize() / dispose() pattern:

interface MyCustomStore {
  getData(): Promise<string>;
}

class PostgreSQLMyCustomStore implements MyCustomStore {
  async initialize() { /* run migrations */ }
  async dispose() { /* close pool */ }
  async getData() { return "from pg"; }
}
await configureStores({
  thread: new PostgreSQLThreadStore(opts),
}, {
  customStores: {
    myCustom: new PostgreSQLMyCustomStore({ poolConfig }),
  },
});

// Consume via StoreLatticeManager
const { store } = getStoreLattice("default", "myCustom");
const customStore = store as MyCustomStore;

Consumer pattern

Components that need stores read them directly from StoreLatticeManager — no setConfigStore required:

// SqlDatabaseManager reads database configs lazily from the store lattice
const db = await sqlDatabaseManager.getDatabase(tenantId, "main-db");

// MetricsServerManager loads configs on first access
const client = await metricsServerManager.getClient(tenantId, "prometheus");
const servers = await metricsServerManager.getServerKeys(tenantId);

Other Lattice Managers

Model Lattice

import { registerModelLattice } from "@axiom-lattice/core";

registerModelLattice("default", {
  model: "gpt-4o",
  provider: "openai",
  streaming: true,
  apiKeyEnvName: "OPENAI_API_KEY",
});

ChunkBuffer

import { InMemoryChunkBuffer, registerChunkBuffer } from "@axiom-lattice/core";

const buffer = new InMemoryChunkBuffer({ ttl: 30 * 60 * 1000 });
registerChunkBuffer("default", buffer);

Directory Structure

  • src/store_lattice/ — Store lattice manager + configureStores
  • src/model_lattice/ — LLM provider abstractions
  • src/tool_lattice/ — Tool implementations (SQL, metrics, etc.)
  • src/agent_lattice/ — Agent definitions and builders
  • src/memory_lattice/ — Context/memory management
  • src/schedule_lattice/ — Scheduled task management
  • src/sandbox_lattice/ — Code execution sandbox providers

Custom Middleware Registry

Applications can write their own middleware and register it at runtime without modifying core source code. The registered middleware can then be enabled via agent config stored in the database.

Quick start

import { createMiddleware, CustomMiddlewareRegistry } from "@axiom-lattice/core";

CustomMiddlewareRegistry.register("my-logger", (config) =>
  createMiddleware({
    name: "MyLogger",
    wrapModelCall: async (request, handler) => {
      console.log(`[${config.logLevel}] Model call`);
      return handler(request);
    },
  })
);

Database config format

In your agent's graphDefinition.middleware array, add a "custom" type entry:

{
  "id": "mw-001",
  "type": "custom",
  "name": "Audit Logger",
  "description": "Logs model calls for audit",
  "enabled": true,
  "config": {
    "key": "my-logger",
    "logLevel": "debug"
  }
}

The config.key must match the key passed to register(). All other config fields are forwarded to your factory function.

Full example — permission-check middleware

import { createMiddleware, CustomMiddlewareRegistry } from "@axiom-lattice/core";

CustomMiddlewareRegistry.register("permission-check", (config) =>
  createMiddleware({
    name: "PermissionCheck",
    wrapToolCall: async (request, handler) => {
      const toolName = request.toolCall?.name;
      if (toolName && !config.allowedTools.includes(toolName)) {
        return { content: `Tool "${toolName}" is not permitted.` };
      }
      return handler(request);
    },
  })
);

Database config:

{
  "id": "perm-001",
  "type": "custom",
  "name": "Tool Permissions",
  "description": "Restrict tool access",
  "enabled": true,
  "config": {
    "key": "permission-check",
    "allowedTools": ["read_file", "write_file"]
  }
}

API reference

MethodSignatureDescription
register(key: string, factory: (config: Record<string, any>) => AgentMiddleware | Promise<AgentMiddleware>) => voidRegister a factory by key
unregister(key: string) => booleanRemove a registration
get(key: string) => AgentMiddlewareFactory | undefinedLook up a factory
has(key: string) => booleanCheck if key is registered
list() => string[]Get all registered keys

Important

  • Register factories before building agents (typically at app startup)
  • Duplicate keys overwrite previous registrations
  • Unregistered keys are skipped with a console warning at build time
  • Factory functions receive the raw config object (minus key) — validate it yourself

External Channel Integration

core provides the storage infrastructure and binding system that external channel adapters (Lark, Slack, Email, etc.) depend on. The actual HTTP routes and message dispatch live in packages/gateway, but all persistence and sender resolution are handled here.

What core provides

ComponentLocationPurpose
InMemoryChannelInstallationStorestore_lattice/In-memory ChannelInstallationStore implementation
InMemoryBindingStorestore_lattice/In-memory BindingRegistry implementation
BindingRegistryHolderbindings_lattice/Global accessor for the active BindingRegistry
manage_binding tooltool_lattice/manage_binding/Agent tool for CRUD on sender-to-agent bindings

Architecture overview

External Platform (Lark, Slack, Email)
  → Gateway HTTP route (packages/gateway)
  → ChannelAdapter.receive(rawPayload) → InboundMessage
  → MessageRouter.dispatch() (packages/gateway)
    → BindingRegistry.resolve() ←── core
    → Thread creation / reuse ←── core
    → Agent.addMessage() ←── core
  → ChannelAdapter.sendReply() (packages/gateway)

Agents remain channel-agnostic — they only see standard thread/message execution.

Setup for custom channel development

1. Register channel stores

import { configureStores } from "@axiom-lattice/core";
import { PostgreSQLChannelInstallationStore, PostgreSQLBindingStore } from "@axiom-lattice/pg-stores";

await configureStores({
  channelInstallation: new PostgreSQLChannelInstallationStore({ pool }),
  channelBinding: new PostgreSQLBindingStore({ pool }),
  // ... other stores
});

2. Set the global BindingRegistry

import { setBindingRegistry } from "@axiom-lattice/core";

const bindingStore = getStoreLattice("default", "channelBinding").store;
setBindingRegistry(bindingStore);

3. Implement ChannelAdapter (in gateway)

import type { ChannelAdapter, InboundMessage, OutboundMessage, ReplyTarget } from "@axiom-lattice/protocols";
import { z } from "zod";

const slackConfigSchema = z.object({
  botToken: z.string(),
  signingSecret: z.string(),
});

export const slackAdapter: ChannelAdapter = {
  channel: "slack",
  configSchema: slackConfigSchema,

  async receive(rawPayload, installation): Promise<InboundMessage | null> {
    // 1. Parse Slack-specific event
    // 2. Return normalized InboundMessage or null to ignore
    return {
      channel: "slack",
      channelInstallationId: installation.id,
      tenantId: installation.tenantId,
      sender: { id: userId, displayName: userName },
      content: { text: messageText },
      replyTarget: {
        adapterChannel: "slack",
        channelInstallationId: installation.id,
        rawTarget: { channelId, threadTs },
      },
    };
  },

  async sendReply(replyTarget, message, installation): Promise<void> {
    // Use Slack API to send reply
    // replyTarget.rawTarget contains channel-specific context
  },
};

4. Register routes and adapter (in gateway)

// packages/gateway/src/channels/registry.ts
adapterRegistry.register(slackAdapter);

// packages/gateway/src/channels/routes.ts
app.post("/api/channels/slack/installations/:id/events", async (req, reply) => {
  const installation = await installationStore.getInstallationById(req.params.id);
  const message = await slackAdapter.receive(req.body, installation);
  if (message) await messageRouter.dispatch(message);
});

Binding resolution flow

When MessageRouter.dispatch() receives an InboundMessage:

  1. Calls BindingRegistry.resolve({ channel, senderId, channelInstallationId, tenantId })
  2. If no binding found:
    • If installation.rejectWhenNoBinding → throw BindingNotFoundError
    • If installation.fallbackAgentId → create temporary fallback binding
  3. If binding disabled → reject
  4. Thread resolution (based on binding.threadMode):
    • "fixed" → reuse binding.threadId
    • "per_conversation" → always create new thread
  5. Execute agent via agent.addMessage()

Agent-side binding management

Agents can manage bindings dynamically via the manage_binding tool:

// Agent can call this tool to:
// - list_installations: List available channel installations
// - create: Bind a sender to an agent (channel, senderId, agentId)
// - update: Change agent or threadMode for a binding
// - delete: Remove a binding
// - list: List all bindings with optional filters

Key types (from @axiom-lattice/protocols)

interface ChannelAdapter<TConfig = unknown> {
  readonly channel: string;
  readonly configSchema: z.ZodSchema<TConfig>;
  receive(rawPayload: unknown, installation: ChannelInstallation): Promise<InboundMessage | null>;
  sendReply(replyTarget: ReplyTarget, message: OutboundMessage, installation: ChannelInstallation): Promise<void>;
}

interface Binding {
  id: string;
  channel: string;
  channelInstallationId: string;
  tenantId: string;
  senderId: string;
  agentId: string;
  threadMode: "fixed" | "per_conversation";
  enabled: boolean;
}

Reference implementation

See packages/gateway/src/channels/lark/ for a complete production channel adapter including:

  • Webhook verification and decryption
  • Event parsing and normalization
  • Thread mapping (user / group / hybrid modes)
  • Reply delivery via official SDK

版本与发布记录

@axiom-lattice/core 共发布 203 个版本,首次发布于 2025/09/01;过去 12 个月发布了 175 个版本。

版本发布日期距今
12.1.1latest2026/11/034 天前
12.1.02026/11/034 天前
12.0.12026/11/025 天前
12.0.02026/10/317 天前
11.0.02026/10/299 天前
10.1.02026/10/2810 天前

其他发布通道:hotfix → 2.1.15-hotfix.0。

关于 @axiom-lattice/core 的常见问题

@axiom-lattice/core 是什么?

Core library for agent-based applications

如何安装 @axiom-lattice/core?

在项目目录运行 npm install @axiom-lattice/core,或使用 pnpm add / yarn add / bun add。

@axiom-lattice/core 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@axiom-lattice/core 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@axiom-lattice/core 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20.10.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@axiom-lattice/core 可以商用吗?

@axiom-lattice/core 使用 ISC 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@axiom-lattice/core 的下载量有多少?

根据 npm 官方下载统计,@axiom-lattice/core 在 2026/10/08 – 2026/11/06 这 30 天内被下载 4,678 次,日均约 156 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@axiom-lattice/core 还在维护吗?

最新版本 12.1.1 发布于 2026/11/03(4 天前);至今共发布 203 个版本,其中过去 12 个月发布了 175 个;首次发布于 2025/09/01。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。