@axiom-lattice/examples-deep_research 1.0.14 → 1.0.17

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.
@@ -0,0 +1,58 @@
1
+ export const sqlQuery = {
2
+ name: "sql-query",
3
+ description:
4
+ "生成和执行 SQL 查询以检索业务数据。适用于需要从数据库获取数据、探索表结构、验证查询正确性的场景。委托给 sql-builder-agent 执行。",
5
+ prompt: `## 委托给 sql-builder-agent
6
+
7
+ 所有 SQL 相关操作都委托给 sql-builder-agent 子代理执行。
8
+
9
+ ## 数据库模式探索
10
+
11
+ **请求模式信息**:
12
+ - "请列出数据库中所有可用的表"
13
+ - "请显示表 [X] 的模式,包括列、数据类型和关系"
14
+
15
+ **检查现有文档**:
16
+ - 先读取 \`/db_schema.md\`(如存在)
17
+ - 仅在需要时请求新的模式探索
18
+
19
+ ## 查询生成与执行
20
+
21
+ **提供清晰的业务需求**:
22
+ 1. **业务问题**:明确要回答的问题
23
+ 2. **指标**:需要计算的业务指标(收入、订单数、转化率等)
24
+ 3. **维度**:分组维度(地区、渠道、产品类别等)
25
+ 4. **筛选条件**:时间范围、状态、类别等
26
+ 5. **比较需求**:同比、环比、目标对比等
27
+
28
+ **请求格式示例**:
29
+ "我需要按地区比较 2024 年第三季度与 2023 年第三季度的收入。请生成并执行 SQL 查询。"
30
+
31
+ "请查询过去 6 个月每个月的订单量和平均订单金额,按渠道分组。"
32
+
33
+ ## 接收与验证结果
34
+
35
+ sql-builder-agent 会返回:
36
+ - **SQL 查询**:格式清晰的完整查询
37
+ - **查询结果**:返回的数据
38
+ - **模式信息**:使用的表结构信息
39
+
40
+ **验证要点**:
41
+ - 查询是否正确回答了业务问题
42
+ - 数据质量(NULL 值、异常值)
43
+ - 结果完整性(行数、时间范围)
44
+ - 列名是否业务友好
45
+
46
+ ## 错误处理
47
+
48
+ 如遇到查询错误:
49
+ - 分析错误信息
50
+ - 检查表名、列名是否正确
51
+ - 验证 JOIN 条件和数据类型
52
+ - 请求 sql-builder-agent 修正并重新执行
53
+
54
+ ## 文档化
55
+
56
+ 将使用的 SQL 查询和结果保存到分析文档中,便于后续参考和复现。
57
+ `,
58
+ };
@@ -0,0 +1,9 @@
1
+ ---
2
+ name: test
3
+ description: test1112222434441111
4
+ metadata:
5
+ a: a
6
+ b: b
7
+ category: TTTT
8
+ ---
9
+ testsetetetete
@@ -1,3 +1,4 @@
1
1
  //import "./todo";
2
2
  import "./research";
3
3
  import "./data_agent";
4
+ import "./inventory_doctor";
@@ -0,0 +1,53 @@
1
+ import {
2
+ registerAgentLattices,
3
+ AgentType,
4
+ AgentConfig,
5
+ } from "@axiom-lattice/core";
6
+ import z from "zod";
7
+ import "./tools";
8
+
9
+ const inventoryDoctorPrompt = `You are the Inventory Doctor Agent handling WMS pick-shortage incidents.
10
+
11
+ ## Mission
12
+ - Scenario: System shows stock=5 for SKU A, picker finds 0 at location.
13
+ - Follow Think-Act-Observe loops to diagnose and either auto-fix or dispatch physical verification.
14
+
15
+
16
+ ## Workflow
17
+ 1) Trigger: on Pick Shortage, freeze concurrent changes for the SKU/location.
18
+ 2) Data Retrieval & Triage:
19
+ - Check in-flight tasks (putaway/move/wave) for middle states or delays.
20
+ - Pull last 24h location logs; highlight unconfirmed moves or cancellations.
21
+ - Form hypotheses: data delay, stuck middleware, physical misplacement.
22
+ 3) Reasoning & Execution:
23
+ - Branch A Auto-fix: if middle-state, call retry_sync then notify picker to retry.
24
+ - Branch B Physical verify: push a cycle-count task to nearby operator; include candidate locations (B/C) for misplaced stock.
25
+ - Record every action in the report body for auditability.
26
+ 4) Reporting: return a concise Markdown case report with diagnosis, actions taken, residual risk, and training/monitoring suggestions.
27
+
28
+ ## Output format
29
+ Use Markdown sections: 诊断概览 / 关键发现 / 处置动作 / 后续建议. Keep facts first, then recommendations.`;
30
+
31
+ const inventoryDoctorAgent: AgentConfig = {
32
+ key: "inventory_doctor_agent",
33
+ name: "Inventory Doctor Agent",
34
+ description:
35
+ "Diagnoses pick-shortage inventory anomalies in WMS, auto-fixes data middle states, or dispatches cycle counts for physical verification, and returns an audit-friendly report.",
36
+ type: AgentType.DEEP_AGENT,
37
+ prompt: inventoryDoctorPrompt,
38
+ tools: [
39
+ "get_wms_movement_tasks",
40
+ "get_location_logs",
41
+ "retry_sync",
42
+ "dispatch_cycle_count",
43
+ "notify_picker",
44
+ "write_case_report",
45
+ ],
46
+ schema: z.object({
47
+ skuId: z.string().optional(),
48
+ locationId: z.string().optional(),
49
+ incidentId: z.string().optional(),
50
+ }),
51
+ };
52
+
53
+ registerAgentLattices([inventoryDoctorAgent]);
@@ -0,0 +1,244 @@
1
+ /**
2
+ * Inventory Doctor Agent Tools
3
+ *
4
+ * Tools for diagnosing and fixing WMS pick-shortage incidents
5
+ */
6
+
7
+ import z from "zod";
8
+ import { registerToolLattice } from "@axiom-lattice/core";
9
+
10
+ /**
11
+ * Get WMS movement tasks for a SKU and location
12
+ * Returns pending tasks that might affect inventory visibility
13
+ */
14
+ registerToolLattice(
15
+ "get_wms_movement_tasks",
16
+ {
17
+ name: "get_wms_movement_tasks",
18
+ description:
19
+ "Retrieve in-flight movement tasks (putaway/move/wave) for a specific SKU and location. Use this to check for tasks in middle states that might cause inventory discrepancies.",
20
+ needUserApprove: false,
21
+ schema: z.object({
22
+ skuId: z.string().describe("SKU identifier"),
23
+ locationId: z.string().describe("Location identifier"),
24
+ }),
25
+ },
26
+ async (input: { skuId: string; locationId: string }) => {
27
+ // Mock data with random values
28
+ const taskTypes = ["putaway", "move", "wave", "replenishment"];
29
+ const statuses = ["in_progress", "pending", "queued", "processing"];
30
+ const hasPendingTasks = Math.random() > 0.3; // 70% chance of having pending tasks
31
+ const taskCount = hasPendingTasks ? Math.floor(Math.random() * 3) + 1 : 0;
32
+
33
+ const tasks = Array.from({ length: taskCount }, (_, i) => ({
34
+ id: `move-${Math.floor(Math.random() * 9000) + 1000}`,
35
+ type: taskTypes[Math.floor(Math.random() * taskTypes.length)],
36
+ status: statuses[Math.floor(Math.random() * statuses.length)],
37
+ etaMin: Math.floor(Math.random() * 60) + 5, // 5-65 minutes
38
+ }));
39
+
40
+ return {
41
+ pending: hasPendingTasks,
42
+ tasks,
43
+ };
44
+ }
45
+ );
46
+
47
+ /**
48
+ * Get location activity logs
49
+ * Returns recent activity logs for a location to identify unconfirmed moves or cancellations
50
+ */
51
+ registerToolLattice(
52
+ "get_location_logs",
53
+ {
54
+ name: "get_location_logs",
55
+ description:
56
+ "Retrieve activity logs for a location within a specified lookback period. Use this to identify unconfirmed moves, cancellations, or other activities that might explain inventory discrepancies.",
57
+ needUserApprove: false,
58
+ schema: z.object({
59
+ locationId: z.string().describe("Location identifier"),
60
+ lookbackHours: z.number().describe("Number of hours to look back"),
61
+ }),
62
+ },
63
+ async (input: { locationId: string; lookbackHours: number }) => {
64
+ // Mock data with random values
65
+ const actions = ["move", "putaway", "pick", "adjustment", "cycle_count"];
66
+ const statuses = [
67
+ "pending_confirm",
68
+ "completed",
69
+ "cancelled",
70
+ "in_progress",
71
+ "failed",
72
+ ];
73
+ const operators = [
74
+ "op_x",
75
+ "op_y",
76
+ "op_z",
77
+ "worker_01",
78
+ "worker_05",
79
+ "worker_12",
80
+ ];
81
+ const locations = ["A-01", "A-02", "B-01", "B-02", "C-03", "D-05"];
82
+
83
+ const logCount = Math.floor(Math.random() * 5) + 1; // 1-5 logs
84
+ const now = new Date();
85
+ const logs = Array.from({ length: logCount }, (_, i) => {
86
+ const hoursAgo = Math.floor(Math.random() * input.lookbackHours);
87
+ const timestamp = new Date(now.getTime() - hoursAgo * 60 * 60 * 1000);
88
+ const fromLoc = locations[Math.floor(Math.random() * locations.length)];
89
+ const toLoc = locations[Math.floor(Math.random() * locations.length)];
90
+
91
+ return {
92
+ ts: timestamp.toISOString(),
93
+ action: actions[Math.floor(Math.random() * actions.length)],
94
+ from: fromLoc,
95
+ to: toLoc !== fromLoc ? toLoc : locations[Math.floor(Math.random() * locations.length)],
96
+ status: statuses[Math.floor(Math.random() * statuses.length)],
97
+ operator: operators[Math.floor(Math.random() * operators.length)],
98
+ };
99
+ });
100
+
101
+ // Sort by timestamp descending
102
+ logs.sort((a, b) => new Date(b.ts).getTime() - new Date(a.ts).getTime());
103
+
104
+ return logs;
105
+ }
106
+ );
107
+
108
+ /**
109
+ * Retry synchronization for a stuck task
110
+ * Attempts to refresh the status of a task that might be in a middle state
111
+ */
112
+ registerToolLattice(
113
+ "retry_sync",
114
+ {
115
+ name: "retry_sync",
116
+ description:
117
+ "Retry synchronization for a task that appears to be stuck in a middle state. This will attempt to refresh the task status and resolve data delays.",
118
+ needUserApprove: false,
119
+ schema: z.object({
120
+ taskId: z.string().describe("Task identifier to retry"),
121
+ }),
122
+ },
123
+ async (input: { taskId: string }) => {
124
+ // Mock data with random outcomes
125
+ const fixed = Math.random() > 0.2; // 80% success rate
126
+ const messages = [
127
+ "status refreshed to completed",
128
+ "task synchronized successfully",
129
+ "sync completed, inventory updated",
130
+ "task status updated to completed",
131
+ "synchronization failed, task still in progress",
132
+ "unable to sync, task may require manual intervention",
133
+ ];
134
+
135
+ return {
136
+ fixed,
137
+ message: fixed
138
+ ? messages[Math.floor(Math.random() * 4)]
139
+ : messages[Math.floor(Math.random() * 2) + 4],
140
+ };
141
+ }
142
+ );
143
+
144
+ /**
145
+ * Dispatch a cycle count task for physical verification
146
+ * Creates a cycle count task and assigns it to an operator
147
+ */
148
+ registerToolLattice(
149
+ "dispatch_cycle_count",
150
+ {
151
+ name: "dispatch_cycle_count",
152
+ description:
153
+ "Dispatch a cycle count task to physically verify inventory at specified locations. Use this when physical verification is needed to resolve inventory discrepancies.",
154
+ needUserApprove: false,
155
+ schema: z.object({
156
+ skuId: z.string().describe("SKU identifier to verify"),
157
+ locations: z.array(z.string()).describe("List of location identifiers to check"),
158
+ priority: z.string().describe("Priority level (e.g., 'high', 'medium', 'low')"),
159
+ }),
160
+ },
161
+ async (input: {
162
+ skuId: string;
163
+ locations: string[];
164
+ priority: string;
165
+ }) => {
166
+ // Mock data with random values
167
+ const workers = [
168
+ "worker_01",
169
+ "worker_05",
170
+ "worker_07",
171
+ "worker_12",
172
+ "worker_15",
173
+ "worker_20",
174
+ ];
175
+ const taskId = `cc-${Math.floor(Math.random() * 9000) + 1000}`;
176
+ const assignee = workers[Math.floor(Math.random() * workers.length)];
177
+ const etaMinutes = Math.floor(Math.random() * 30) + 5; // 5-35 minutes
178
+ const eta = `${etaMinutes}m`;
179
+
180
+ return {
181
+ taskId,
182
+ assignee,
183
+ eta,
184
+ };
185
+ }
186
+ );
187
+
188
+ /**
189
+ * Notify picker about inventory status
190
+ * Sends a notification to the picker about the current status
191
+ */
192
+ registerToolLattice(
193
+ "notify_picker",
194
+ {
195
+ name: "notify_picker",
196
+ description:
197
+ "Send a notification message to the picker about inventory status, retry instructions, or other relevant information.",
198
+ needUserApprove: false,
199
+ schema: z.object({
200
+ message: z.string().describe("Message to send to the picker"),
201
+ }),
202
+ },
203
+ async (input: { message: string }) => {
204
+ // Mock data with random delivery status
205
+ const delivered = Math.random() > 0.1; // 90% success rate
206
+
207
+ return {
208
+ delivered,
209
+ };
210
+ }
211
+ );
212
+
213
+ /**
214
+ * Write case report to file system
215
+ * Saves the diagnostic case report as a markdown file
216
+ */
217
+ registerToolLattice(
218
+ "write_case_report",
219
+ {
220
+ name: "write_case_report",
221
+ description:
222
+ "Save the diagnostic case report as a markdown file. Use this to record the diagnosis, actions taken, and recommendations for audit purposes.",
223
+ needUserApprove: false,
224
+ schema: z.object({
225
+ markdown: z.string().describe("Markdown content of the case report"),
226
+ }),
227
+ },
228
+ async (input: { markdown: string }) => {
229
+ // Mock data with random path and timestamp
230
+ const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, -5);
231
+ const reportId = Math.floor(Math.random() * 10000);
232
+ const paths = [
233
+ `/reports/inventory-case-latest.md`,
234
+ `/reports/inventory-case-${reportId}.md`,
235
+ `/reports/case-${timestamp}.md`,
236
+ `/reports/inventory-diagnosis-${reportId}.md`,
237
+ ];
238
+
239
+ return {
240
+ saved: true,
241
+ path: paths[Math.floor(Math.random() * paths.length)],
242
+ };
243
+ }
244
+ );
package/src/index.ts CHANGED
@@ -6,13 +6,23 @@ import {
6
6
  registerCheckpointSaver,
7
7
  registerModelLattice,
8
8
  registerScheduleLattice,
9
+ FileSystemSkillStore,
10
+ registerStoreLattice,
11
+
12
+ storeLatticeManager,
13
+ skillLatticeManager,
9
14
  } from "@axiom-lattice/core";
10
15
  import "./agents";
11
16
 
12
17
  import path from "path";
13
- import { ScheduleType } from "@axiom-lattice/protocols";
18
+ import {
19
+ LoggerConfig,
20
+ LoggerType,
21
+ ScheduleType,
22
+ } from "@axiom-lattice/protocols";
14
23
  import { PostgreSQLScheduleStorage } from "@axiom-lattice/pg-stores";
15
24
  // 在文件开头添加
25
+ const fs = require("fs");
16
26
  const PACKAGE_VERSION = require("../package.json").version;
17
27
  const BUILD_TIME = new Date().toISOString();
18
28
  const IS_DEV = process.env.NODE_ENV !== "production";
@@ -101,6 +111,81 @@ registerModelLattice(
101
111
  );
102
112
  LatticeGateway.registerLatticeRoutes(LatticeGateway.app);
103
113
 
114
+ // Configure Skill Store with FileSystem storage
115
+ // Point to the skills directory in data_agent
116
+ // Always use source directory (src/) since .md files are not copied to dist/ during build
117
+ // Try multiple path resolution strategies to work in both dev and production
118
+ const possiblePaths = [
119
+ // Production: from dist/ go up to src/
120
+ path.resolve(__dirname, "../src/agents/data_agent/skills"),
121
+ // Development: relative to __dirname (src/)
122
+ path.resolve(__dirname, "./agents/data_agent/skills"),
123
+ // Fallback: from project root
124
+ path.resolve(process.cwd(), "examples/deep_research/src/agents/data_agent/skills"),
125
+ ];
126
+
127
+ // Check which path exists, default to first path
128
+ let skillsRootDir: string = possiblePaths[0];
129
+ for (const possiblePath of possiblePaths) {
130
+ if (fs.existsSync(possiblePath)) {
131
+ skillsRootDir = possiblePath;
132
+ break;
133
+ }
134
+ }
135
+
136
+ if (!fs.existsSync(skillsRootDir)) {
137
+ console.warn(
138
+ `Warning: Skills directory not found at any of the expected paths. Using: ${skillsRootDir}`
139
+ );
140
+ }
141
+
142
+ console.log(`Skill store root directory: ${skillsRootDir}`);
143
+
144
+ const skillStore = new FileSystemSkillStore({
145
+ rootDir: skillsRootDir,
146
+ });
147
+
148
+ // Remove the default skill store and register our custom one
149
+ // This ensures tools like load_skills and load_skill_content can access our skills
150
+ storeLatticeManager.removeLattice("default", "skill");
151
+ registerStoreLattice("default", "skill", skillStore);
152
+
153
+ // Configure SkillLatticeManager to use the store
154
+ skillLatticeManager.configureStore("default");
155
+
156
+ // Test loading skills on startup to verify configuration
157
+ (async () => {
158
+ try {
159
+ const skills = await skillStore.getAllSkills();
160
+ console.log(`Loaded ${skills.length} skills from file system:`);
161
+ if (skills.length === 0) {
162
+ console.warn(
163
+ `Warning: No skills found. Please check if the directory exists: ${skillsRootDir}`
164
+ );
165
+ } else {
166
+ skills.forEach((skill) => {
167
+ console.log(` - ${skill.name}: ${skill.description.substring(0, 50)}...`);
168
+ });
169
+ }
170
+ } catch (error) {
171
+ console.error("Failed to load skills on startup:", error);
172
+ if (error instanceof Error) {
173
+ console.error("Error details:", error.message);
174
+ console.error("Stack:", error.stack);
175
+ }
176
+ }
177
+ })();
178
+
179
+ // // Load skills from the file system asynchronously
180
+ // (async () => {
181
+ // try {
182
+ // await loadSkillsFromStore();
183
+ // console.log("Skills loaded successfully from file system");
184
+ // } catch (error) {
185
+ // console.error("Failed to load skills:", error);
186
+ // }
187
+ // })();
188
+
104
189
  // // 注册 Schedule Lattice(使用 PostgreSQL 持久化)
105
190
  // registerScheduleLattice("default", {
106
191
  // name: "Default Scheduler",
@@ -129,7 +214,23 @@ LatticeGateway.registerLatticeRoutes(LatticeGateway.app);
129
214
  const port = parsePort();
130
215
  console.log(`Starting server on port ${port}`);
131
216
 
217
+ // Default logger configuration
218
+ const DEFAULT_LOGGER_CONFIG: LoggerConfig = {
219
+ name: "default",
220
+ description: "Default logger for lattice-gateway service",
221
+ type: LoggerType.PINO,
222
+ serviceName: "lattice/deep_research",
223
+ loggerName: "lattice/deep_research",
224
+ // file: {
225
+ // file: "./logs/lattice" + "/deep_research",
226
+ // frequency: "daily",
227
+ // mkdir: true,
228
+ // maxFiles: 30,
229
+ // },
230
+ };
231
+
132
232
  LatticeGateway.startAsHttpEndpoint({
133
233
  port,
134
234
  queueServiceConfig: { type: "memory", defaultStartPollingQueue: true },
235
+ loggerConfig: DEFAULT_LOGGER_CONFIG,
135
236
  });