@axiom-lattice/examples-deep_research 1.0.16 → 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,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,6 +6,11 @@ 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
 
@@ -17,6 +22,7 @@ import {
17
22
  } from "@axiom-lattice/protocols";
18
23
  import { PostgreSQLScheduleStorage } from "@axiom-lattice/pg-stores";
19
24
  // 在文件开头添加
25
+ const fs = require("fs");
20
26
  const PACKAGE_VERSION = require("../package.json").version;
21
27
  const BUILD_TIME = new Date().toISOString();
22
28
  const IS_DEV = process.env.NODE_ENV !== "production";
@@ -105,6 +111,81 @@ registerModelLattice(
105
111
  );
106
112
  LatticeGateway.registerLatticeRoutes(LatticeGateway.app);
107
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
+
108
189
  // // 注册 Schedule Lattice(使用 PostgreSQL 持久化)
109
190
  // registerScheduleLattice("default", {
110
191
  // name: "Default Scheduler",
@@ -1,88 +0,0 @@
1
- /**
2
- * Load Skills Tools
3
- * Tools for loading skill metadata and content
4
- */
5
-
6
- import z from "zod";
7
- import { registerToolLattice } from "@axiom-lattice/core";
8
- import * as analystSkill from "../skills/analyst";
9
- import * as dataVisualizationSkill from "../skills/data-visualization";
10
- import * as sqlQuerySkill from "../skills/sql-query";
11
- import * as analysisMethodologySkill from "../skills/analysis-methodology";
12
- import * as notebookReportSkill from "../skills/notebook-report";
13
- import * as infographicCreatorSkill from "../skills/infographic-creator";
14
-
15
- // Type definition for skill structure
16
- interface Skill {
17
- name: string;
18
- description: string;
19
- prompt: string;
20
- }
21
-
22
- // Registry of all available skills
23
- const skillsRegistry: Record<string, Skill> = {
24
- analyst: analystSkill.analyst,
25
- "data-visualization": dataVisualizationSkill.dataVisualization,
26
- "sql-query": sqlQuerySkill.sqlQuery,
27
- "analysis-methodology": analysisMethodologySkill.analysisMethodology,
28
- "notebook-report": notebookReportSkill.notebookReport,
29
- "infographic-creator": infographicCreatorSkill.infographicCreator,
30
- };
31
-
32
- /**
33
- * Load all skills and return their metadata (name and description, without prompt)
34
- */
35
- registerToolLattice(
36
- "load_skills",
37
- {
38
- name: "load_skills",
39
- description:
40
- "Load all available skills and return their metadata (name and description). This tool returns skill information without the prompt content. Use this to discover what skills are available.",
41
- needUserApprove: false,
42
- schema: z.object({}),
43
- },
44
- async (_input: Record<string, never>, _config: any) => {
45
- try {
46
- const skillsMeta = Object.values(skillsRegistry).map((skill) => ({
47
- name: skill.name,
48
- description: skill.description,
49
- }));
50
-
51
- return JSON.stringify(skillsMeta, null, 2);
52
- } catch (error) {
53
- return `Error loading skills: ${error instanceof Error ? error.message : String(error)
54
- }`;
55
- }
56
- }
57
- );
58
-
59
- /**
60
- * Load a specific skill's content and return its prompt
61
- */
62
- registerToolLattice(
63
- "load_skill_content",
64
- {
65
- name: "load_skill_content",
66
- description:
67
- "Load a specific skill's content by name and return its prompt. Use this tool to get the full prompt content for a skill that you want to use.",
68
- needUserApprove: false,
69
- schema: z.object({
70
- skill_name: z.string().describe("The name of the skill to load"),
71
- }),
72
- },
73
- async (input: { skill_name: string }, _config: any) => {
74
- try {
75
- const skill = skillsRegistry[input.skill_name];
76
-
77
- if (!skill) {
78
- const availableSkills = Object.keys(skillsRegistry).join(", ");
79
- return `Skill "${input.skill_name}" not found. Available skills: ${availableSkills}`;
80
- }
81
-
82
- return skill.prompt;
83
- } catch (error) {
84
- return `Error loading skill content: ${error instanceof Error ? error.message : String(error)
85
- }`;
86
- }
87
- }
88
- );