@axiom-lattice/core 2.1.72 → 2.1.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +31 -6
- package/dist/index.d.ts +31 -6
- package/dist/index.js +458 -40
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +456 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -3059,6 +3059,168 @@ var PostgresDatabase = class {
|
|
|
3059
3059
|
}
|
|
3060
3060
|
}
|
|
3061
3061
|
};
|
|
3062
|
+
var MysqlDatabase = class {
|
|
3063
|
+
constructor(config) {
|
|
3064
|
+
// mysql2.Pool
|
|
3065
|
+
this.connected = false;
|
|
3066
|
+
this.config = config;
|
|
3067
|
+
}
|
|
3068
|
+
async connect() {
|
|
3069
|
+
if (this.connected && this.pool) return;
|
|
3070
|
+
try {
|
|
3071
|
+
const mysql = await import("mysql2/promise");
|
|
3072
|
+
const poolConfig = this.config.connectionString ? { uri: this.config.connectionString } : {
|
|
3073
|
+
host: this.config.host || "localhost",
|
|
3074
|
+
port: this.config.port || 3306,
|
|
3075
|
+
database: this.config.database,
|
|
3076
|
+
user: this.config.user,
|
|
3077
|
+
password: this.config.password,
|
|
3078
|
+
ssl: this.config.ssl ? { rejectUnauthorized: false } : void 0
|
|
3079
|
+
};
|
|
3080
|
+
this.pool = mysql.createPool({
|
|
3081
|
+
...poolConfig,
|
|
3082
|
+
waitForConnections: true,
|
|
3083
|
+
connectionLimit: 10,
|
|
3084
|
+
maxIdle: 10,
|
|
3085
|
+
idleTimeout: 6e4,
|
|
3086
|
+
queueLimit: 0,
|
|
3087
|
+
enableKeepAlive: true,
|
|
3088
|
+
keepAliveInitialDelay: 0
|
|
3089
|
+
});
|
|
3090
|
+
const connection = await this.pool.getConnection();
|
|
3091
|
+
try {
|
|
3092
|
+
await connection.query("SELECT 1");
|
|
3093
|
+
} finally {
|
|
3094
|
+
connection.release();
|
|
3095
|
+
}
|
|
3096
|
+
this.connected = true;
|
|
3097
|
+
} catch (error) {
|
|
3098
|
+
this.connected = false;
|
|
3099
|
+
throw new Error(`Failed to connect to MySQL: ${error}`);
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
async disconnect() {
|
|
3103
|
+
if (this.pool) {
|
|
3104
|
+
try {
|
|
3105
|
+
await this.pool.end();
|
|
3106
|
+
} catch (error) {
|
|
3107
|
+
console.warn("Warning: Error closing MySQL pool:", error);
|
|
3108
|
+
} finally {
|
|
3109
|
+
this.pool = null;
|
|
3110
|
+
this.connected = false;
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
}
|
|
3114
|
+
async listTables() {
|
|
3115
|
+
await this.ensureConnected();
|
|
3116
|
+
const query = `
|
|
3117
|
+
SELECT TABLE_NAME, TABLE_SCHEMA
|
|
3118
|
+
FROM information_schema.TABLES
|
|
3119
|
+
WHERE TABLE_SCHEMA NOT IN ('mysql', 'information_schema', 'performance_schema', 'sys')
|
|
3120
|
+
AND TABLE_SCHEMA = DATABASE()
|
|
3121
|
+
AND TABLE_TYPE = 'BASE TABLE'
|
|
3122
|
+
ORDER BY TABLE_SCHEMA, TABLE_NAME
|
|
3123
|
+
`;
|
|
3124
|
+
const [rows] = await this.pool.query(query);
|
|
3125
|
+
return rows.map((row) => ({
|
|
3126
|
+
name: row.TABLE_NAME,
|
|
3127
|
+
schema: row.TABLE_SCHEMA
|
|
3128
|
+
}));
|
|
3129
|
+
}
|
|
3130
|
+
async getTableInfo(tables) {
|
|
3131
|
+
await this.ensureConnected();
|
|
3132
|
+
const schemas = [];
|
|
3133
|
+
for (const tableName of tables) {
|
|
3134
|
+
const rawName = tableName.includes(".") ? tableName.split(".").pop() : tableName;
|
|
3135
|
+
const columnQuery = `
|
|
3136
|
+
SELECT
|
|
3137
|
+
c.COLUMN_NAME,
|
|
3138
|
+
c.DATA_TYPE,
|
|
3139
|
+
c.IS_NULLABLE,
|
|
3140
|
+
c.COLUMN_DEFAULT
|
|
3141
|
+
FROM information_schema.COLUMNS c
|
|
3142
|
+
WHERE c.TABLE_NAME = ?
|
|
3143
|
+
AND c.TABLE_SCHEMA = DATABASE()
|
|
3144
|
+
ORDER BY c.ORDINAL_POSITION
|
|
3145
|
+
`;
|
|
3146
|
+
const pkQuery = `
|
|
3147
|
+
SELECT k.COLUMN_NAME
|
|
3148
|
+
FROM information_schema.TABLE_CONSTRAINTS t
|
|
3149
|
+
JOIN information_schema.KEY_COLUMN_USAGE k
|
|
3150
|
+
ON t.CONSTRAINT_NAME = k.CONSTRAINT_NAME
|
|
3151
|
+
AND t.TABLE_SCHEMA = k.TABLE_SCHEMA
|
|
3152
|
+
AND t.TABLE_NAME = k.TABLE_NAME
|
|
3153
|
+
WHERE t.CONSTRAINT_TYPE = 'PRIMARY KEY'
|
|
3154
|
+
AND t.TABLE_NAME = ?
|
|
3155
|
+
AND t.TABLE_SCHEMA = DATABASE()
|
|
3156
|
+
`;
|
|
3157
|
+
const fkQuery = `
|
|
3158
|
+
SELECT
|
|
3159
|
+
k.COLUMN_NAME,
|
|
3160
|
+
k.REFERENCED_TABLE_NAME,
|
|
3161
|
+
k.REFERENCED_COLUMN_NAME
|
|
3162
|
+
FROM information_schema.KEY_COLUMN_USAGE k
|
|
3163
|
+
WHERE k.TABLE_NAME = ?
|
|
3164
|
+
AND k.TABLE_SCHEMA = DATABASE()
|
|
3165
|
+
AND k.REFERENCED_TABLE_NAME IS NOT NULL
|
|
3166
|
+
`;
|
|
3167
|
+
const [columnRows] = await this.pool.query(columnQuery, [rawName]);
|
|
3168
|
+
const [pkRows] = await this.pool.query(pkQuery, [rawName]);
|
|
3169
|
+
const [fkRows] = await this.pool.query(fkQuery, [rawName]);
|
|
3170
|
+
const pkColumns = new Set(pkRows.map((r) => r.COLUMN_NAME));
|
|
3171
|
+
const fkMap = /* @__PURE__ */ new Map();
|
|
3172
|
+
for (const row of fkRows) {
|
|
3173
|
+
fkMap.set(row.COLUMN_NAME, {
|
|
3174
|
+
foreignTable: row.REFERENCED_TABLE_NAME,
|
|
3175
|
+
foreignColumn: row.REFERENCED_COLUMN_NAME
|
|
3176
|
+
});
|
|
3177
|
+
}
|
|
3178
|
+
const columns = columnRows.map((row) => {
|
|
3179
|
+
const fkRef = fkMap.get(row.COLUMN_NAME);
|
|
3180
|
+
return {
|
|
3181
|
+
name: row.COLUMN_NAME,
|
|
3182
|
+
type: row.DATA_TYPE,
|
|
3183
|
+
nullable: row.IS_NULLABLE === "YES",
|
|
3184
|
+
default: row.COLUMN_DEFAULT,
|
|
3185
|
+
isPrimaryKey: pkColumns.has(row.COLUMN_NAME),
|
|
3186
|
+
isForeignKey: fkRef !== void 0,
|
|
3187
|
+
foreignKeyRef: fkRef ? `${fkRef.foreignTable}.${fkRef.foreignColumn}` : void 0
|
|
3188
|
+
};
|
|
3189
|
+
});
|
|
3190
|
+
let sampleRows = [];
|
|
3191
|
+
try {
|
|
3192
|
+
const sampleQuery = `SELECT * FROM \`${rawName}\` LIMIT 3`;
|
|
3193
|
+
const [sampleResult] = await this.pool.query(sampleQuery);
|
|
3194
|
+
sampleRows = sampleResult;
|
|
3195
|
+
} catch {
|
|
3196
|
+
}
|
|
3197
|
+
schemas.push({
|
|
3198
|
+
tableName,
|
|
3199
|
+
columns,
|
|
3200
|
+
sampleRows
|
|
3201
|
+
});
|
|
3202
|
+
}
|
|
3203
|
+
return schemas;
|
|
3204
|
+
}
|
|
3205
|
+
async executeQuery(query) {
|
|
3206
|
+
await this.ensureConnected();
|
|
3207
|
+
const [rows, fields] = await this.pool.query(query);
|
|
3208
|
+
const isSelectResult = Array.isArray(rows);
|
|
3209
|
+
return {
|
|
3210
|
+
rows: isSelectResult ? rows : [],
|
|
3211
|
+
rowCount: isSelectResult ? rows.length : rows.affectedRows || 0,
|
|
3212
|
+
fields: fields?.map((f) => f.name)
|
|
3213
|
+
};
|
|
3214
|
+
}
|
|
3215
|
+
getDatabaseType() {
|
|
3216
|
+
return "mysql";
|
|
3217
|
+
}
|
|
3218
|
+
async ensureConnected() {
|
|
3219
|
+
if (!this.connected) {
|
|
3220
|
+
await this.connect();
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
};
|
|
3062
3224
|
var SqlDatabaseManager = class _SqlDatabaseManager {
|
|
3063
3225
|
constructor() {
|
|
3064
3226
|
this.databases = /* @__PURE__ */ new Map();
|
|
@@ -3098,7 +3260,8 @@ var SqlDatabaseManager = class _SqlDatabaseManager {
|
|
|
3098
3260
|
database = new PostgresDatabase(config);
|
|
3099
3261
|
break;
|
|
3100
3262
|
case "mysql":
|
|
3101
|
-
|
|
3263
|
+
database = new MysqlDatabase(config);
|
|
3264
|
+
break;
|
|
3102
3265
|
case "sqlite":
|
|
3103
3266
|
throw new Error("SQLite support not yet implemented");
|
|
3104
3267
|
default:
|
|
@@ -5633,7 +5796,7 @@ var SandboxLatticeManager = class _SandboxLatticeManager extends BaseLatticeMana
|
|
|
5633
5796
|
const tenantId = config.tenantId ?? "default";
|
|
5634
5797
|
const mapping = this._resolveVolumeForPath(config, tenantId, filePath);
|
|
5635
5798
|
if (!mapping) return null;
|
|
5636
|
-
const client = provider.createVolumeFsClient(mapping.volumeName);
|
|
5799
|
+
const client = provider.createVolumeFsClient(mapping.volumeName, mapping.pathPrefix);
|
|
5637
5800
|
return new VolumeFilesystem(stripPrefixClient(client, mapping.pathPrefix), mapping.pathPrefix);
|
|
5638
5801
|
}
|
|
5639
5802
|
_resolveVolumeForPath(config, tenantId, filePath) {
|
|
@@ -18896,10 +19059,105 @@ Use this when the task follows a standard BPO (Business Process Orchestration) p
|
|
|
18896
19059
|
|
|
18897
19060
|
**Business rule \u2014 Draft-then-confirm pattern:** When a workflow creates business objects that require human approval (e.g., draft orders in SAP B1, purchase requisitions, expense reports), the design MUST include a confirmation step AFTER the creation step. The create step must complete successfully before the confirm step runs. The flow is always: **Create draft \u2192 User confirms \u2192 Finalize**. Reason: systems like SAP B1 only expose drafts to users after they are created \u2014 the user cannot see or approve something that doesn't exist yet. The confirm step MUST use the \`ask_user_to_clarify\` middleware.
|
|
18898
19061
|
|
|
19062
|
+
**Business pattern \u2014 SAP B1 Draft SO Creation:** When designing a sub-agent responsible for creating draft Sales Orders in SAP B1, embed the following standards into its system prompt. These ensure consistent data construction, API usage, and user presentation:
|
|
19063
|
+
|
|
19064
|
+
**Step 1: Construct SO Data Structure**
|
|
19065
|
+
Build the JSON payload. For each DocumentLines item:
|
|
19066
|
+
- Include \`WarehouseCode\` ONLY if sku.json provides a value; if missing or empty, OMIT the field entirely
|
|
19067
|
+
- Generate \`Comments\` dynamically based on context (customer name, PO reference, special instructions)
|
|
19068
|
+
|
|
19069
|
+
\`\`\`json
|
|
19070
|
+
{
|
|
19071
|
+
"DocObjectCode": "17",
|
|
19072
|
+
"DocType": "dDocument_Items",
|
|
19073
|
+
"CardCode": "C001",
|
|
19074
|
+
"DocDate": "current date",
|
|
19075
|
+
"DocDueDate": "delivery date",
|
|
19076
|
+
"TaxDate": "current date",
|
|
19077
|
+
"U_YWLX": "Modern Trade",
|
|
19078
|
+
"Comments": "SO for Kaimay Retail - PO ref: PO-2024-001234",
|
|
19079
|
+
"DocumentLines": [
|
|
19080
|
+
{
|
|
19081
|
+
"ItemCode": "SKU001",
|
|
19082
|
+
"Quantity": 240,
|
|
19083
|
+
"UnitPrice": 15.84
|
|
19084
|
+
}
|
|
19085
|
+
]
|
|
19086
|
+
}
|
|
19087
|
+
\`\`\`
|
|
19088
|
+
|
|
19089
|
+
Field mapping rules:
|
|
19090
|
+
| SAP Field | Data Source |
|
|
19091
|
+
|-----------|-------------|
|
|
19092
|
+
| CardCode | customer.json \u2192 CardCode |
|
|
19093
|
+
| DocDate | Current date (yyyy-MM-dd) |
|
|
19094
|
+
| DocDueDate | extracted.json \u2192 delivery_date |
|
|
19095
|
+
| TaxDate | Current date (yyyy-MM-dd) |
|
|
19096
|
+
| U_YWLX | customer.json \u2192 SalesType |
|
|
19097
|
+
| ItemCode | sku.json \u2192 ItemCode |
|
|
19098
|
+
| Quantity | extracted.json \u2192 Quantity |
|
|
19099
|
+
| WarehouseCode | sku.json \u2192 WarehouseCode (OMIT if missing/empty) |
|
|
19100
|
+
| UnitPrice | price.json \u2192 UnitPrice |
|
|
19101
|
+
| Comments | AI-generated based on customer name, PO reference, and context |
|
|
19102
|
+
|
|
19103
|
+
**Step 2: Call SAP API to Create Draft (MUST EXECUTE)**
|
|
19104
|
+
Use the \`sap_api_call\` tool with EXACTLY these parameters:
|
|
19105
|
+
- **Method**: POST
|
|
19106
|
+
- **Endpoint**: \`Drafts\` (ONLY allowed endpoint; do NOT call SalesOrders or any other endpoint)
|
|
19107
|
+
- **Body**: The JSON constructed in Step 1
|
|
19108
|
+
|
|
19109
|
+
CRITICAL: You MUST call sap_api_call BEFORE proceeding to Step 3. This step is NOT optional.
|
|
19110
|
+
|
|
19111
|
+
If the API call fails:
|
|
19112
|
+
- Log the error details
|
|
19113
|
+
- STOP the process
|
|
19114
|
+
- Report the failure to the user with the error message
|
|
19115
|
+
- Do NOT proceed to Step 3
|
|
19116
|
+
|
|
19117
|
+
**Step 3: Present Draft for User Review (MUST EXECUTE AFTER Step 2)**
|
|
19118
|
+
ONLY after the SAP API call in Step 2 succeeds, use the \`ask_user_to_clarify\` tool to present the complete SO summary.
|
|
19119
|
+
|
|
19120
|
+
Message format (STRICT \u2014 no emoji, no summary, field names match Service Layer):
|
|
19121
|
+
|
|
19122
|
+
=== Sales Order Draft ===
|
|
19123
|
+
|
|
19124
|
+
DocEntry: {DocEntry}
|
|
19125
|
+
DocNum: {DocNum}
|
|
19126
|
+
DocDate: {DocDate}
|
|
19127
|
+
DocDueDate: {DocDueDate}
|
|
19128
|
+
CardCode: {CardCode}
|
|
19129
|
+
CardName: {CardName}
|
|
19130
|
+
U_YWLX: {SalesType}
|
|
19131
|
+
Comments: {Comments}
|
|
19132
|
+
|
|
19133
|
+
DocumentLines:
|
|
19134
|
+
LineNum | ItemCode | Quantity | WarehouseCode | UnitPrice | LineTotal
|
|
19135
|
+
0 | {ItemCode} | {Quantity} | {WarehouseCode} | {UnitPrice} | {LineTotal}
|
|
19136
|
+
1 | {ItemCode} | {Quantity} | {WarehouseCode} | {UnitPrice} | {LineTotal}
|
|
19137
|
+
...
|
|
19138
|
+
|
|
19139
|
+
DocTotal: {DocTotal}
|
|
19140
|
+
|
|
19141
|
+
Warnings:
|
|
19142
|
+
- {warning1}
|
|
19143
|
+
- {warning2}
|
|
19144
|
+
|
|
19145
|
+
Options:
|
|
19146
|
+
[Confirm generating draft]
|
|
19147
|
+
[Cancel, do not generate]
|
|
19148
|
+
|
|
19149
|
+
**Data sharing pattern \u2014 File-based handoff:** Every sub-agent in the pipeline MUST persist its work results as files under a shared project directory, never rely on in-memory data passing between steps. Deep agents have built-in file capabilities, so no middleware is needed.
|
|
19150
|
+
|
|
19151
|
+
Rules:
|
|
19152
|
+
1. The **orchestrator** generates a unique project ID at the start (e.g., timestamp-based) and passes it to each sub-agent in the task context
|
|
19153
|
+
2. Each sub-agent reads input from \`/project/{project-id}/\` and writes output files into the same directory
|
|
19154
|
+
3. Establish clear file naming conventions so downstream steps know exactly which files to read (e.g., \`extracted.json\`, \`sku.json\`, \`customer.json\`, \`so_draft.json\`)
|
|
19155
|
+
4. The orchestrator's system prompt MUST specify for each edge: which files the target sub-agent should read and which files it should produce
|
|
19156
|
+
|
|
18899
19157
|
**Step 2: Topology design.** Design the agent topology and use \`show_widget\` to render an interactive diagram showing the flow: Orchestrator \u2192 Stage 1 \u2192 Stage 2 \u2192 ... \u2192 Output. Each edge should be labeled with its business purpose.
|
|
18900
19158
|
|
|
18901
19159
|
**Step 3: Design each sub-agent** as a **deep_agent** type (one at a time). For each:
|
|
18902
|
-
- Responsibility, system prompt, middleware, input/output contract
|
|
19160
|
+
- Responsibility, system prompt, middleware, file input/output contract (which files from \`/project/{project-id}/\` it reads, which files it writes)
|
|
18903
19161
|
- Deep agents have built-in file capabilities (ls, read, write, edit, glob, grep), so do NOT add filesystem middleware.
|
|
18904
19162
|
- **Ask for confirmation before moving to the next sub-agent.**
|
|
18905
19163
|
|
|
@@ -18918,15 +19176,15 @@ Use this when the task follows a standard BPO (Business Process Orchestration) p
|
|
|
18918
19176
|
| Section | Content |
|
|
18919
19177
|
|---------|---------|
|
|
18920
19178
|
| **Overview** | One-sentence summary of the workflow's purpose and business value |
|
|
18921
|
-
| **Steps** | Numbered list of each stage in the pipeline. For each step: which sub-agent handles it, what it does, what tools it uses, and what it
|
|
18922
|
-
| **Data Flow** | How data moves between steps
|
|
19179
|
+
| **Steps** | Numbered list of each stage in the pipeline. For each step: which sub-agent handles it, what it does, what tools it uses, what files it reads from \`/project/{project-id}/\`, and what files it writes. |
|
|
19180
|
+
| **Data Flow** | How data moves between steps via files under \`/project/{project-id}/\`. For each step: which files it reads as input and which files it writes as output. |
|
|
18923
19181
|
| **Logic & Conditions** | Any conditional branching, decision points, retry logic, or exception handling. When does the workflow take path A vs path B? What happens on failure? |
|
|
18924
19182
|
| **Tools Used** | Summary table or list of all tools used across sub-agents, grouped by sub-agent |
|
|
18925
19183
|
| **Expected Input** | What input does the workflow expect from the user? (format, examples) |
|
|
18926
19184
|
| **Expected Output** | What does the workflow produce at the end? (format, examples) |
|
|
18927
19185
|
|
|
18928
19186
|
**Formatting rules:**
|
|
18929
|
-
|
|
19187
|
+
- Write in **English**
|
|
18930
19188
|
- Use **Markdown** for formatting (headings, lists, tables, code blocks)
|
|
18931
19189
|
- Be detailed but concise \u2014 each section should be 1-5 lines
|
|
18932
19190
|
- Avoid placeholder text like "TODO" or "TBD"
|
|
@@ -18938,13 +19196,14 @@ Use this when the task follows a standard BPO (Business Process Orchestration) p
|
|
|
18938
19196
|
\u672C\u5DE5\u4F5C\u6D41\u81EA\u52A8\u4ECE\u591A\u4E2A\u6570\u636E\u6E90\u91C7\u96C6\u7ADE\u54C1\u4EF7\u683C\uFF0C\u751F\u6210\u5BF9\u6BD4\u5206\u6790\u62A5\u544A\u5E76\u63A8\u9001\u901A\u77E5\u3002
|
|
18939
19197
|
|
|
18940
19198
|
## Steps
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
19199
|
+
1. **\u6570\u636E\u91C7\u96C6 (data-collector)** \u2014 \u4F7F\u7528 browser \u5DE5\u5177\u722C\u53D6\u6307\u5B9AURL\u7684\u7ADE\u54C1\u4EF7\u683C\u6570\u636E\uFF0C\u8C03\u7528 metrics API \u62C9\u53D6\u5386\u53F2\u4EF7\u683C\u3002\u8F93\u51FA \u2192 \`raw_prices.json\`
|
|
19200
|
+
2. **\u6570\u636E\u6E05\u6D17 (data-cleaner)** \u2014 \u8BFB\u53D6 \`raw_prices.json\`\uFF0C\u4F7F\u7528 code_eval \u6267\u884C Python \u811A\u672C\u6E05\u6D17\u5F02\u5E38\u503C\u548C\u7F3A\u5931\u503C\uFF0C\u7EDF\u4E00\u8D27\u5E01\u5355\u4F4D\u3002\u8F93\u51FA \u2192 \`cleaned_prices.json\`
|
|
19201
|
+
3. **\u62A5\u544A\u751F\u6210 (report-generator)** \u2014 \u8BFB\u53D6 \`cleaned_prices.json\` \u548C\u6A21\u677F\u6587\u4EF6\uFF0Ccode_eval \u8BA1\u7B97\u6DA8\u8DCC\u5E45\u548C\u8D8B\u52BF\uFF0C\u751F\u6210 Markdown \u5BF9\u6BD4\u62A5\u544A\u3002\u8F93\u51FA \u2192 \`report.md\`
|
|
19202
|
+
4. **\u901A\u77E5\u63A8\u9001 (notifier)** \u2014 \u8BFB\u53D6 \`report.md\`\uFF0C\u8C03\u7528 scheduler \u5B89\u6392\u5B9A\u65F6\u53D1\u9001\uFF0C\u4F7F\u7528 ask_user_to_clarify \u8BF7\u6C42\u53D1\u9001\u786E\u8BA4\u3002\u8F93\u51FA\u53D1\u9001\u7ED3\u679C\u3002
|
|
18945
19203
|
|
|
18946
19204
|
## Data Flow
|
|
18947
|
-
|
|
19205
|
+
All data is shared via files under \`/project/{project-id}/\`:
|
|
19206
|
+
\`\u7528\u6237\u8F93\u5165\` \u2192 data-collector writes \`raw_prices.json\` \u2192 data-cleaner reads \`raw_prices.json\`, writes \`cleaned_prices.json\` \u2192 report-generator reads \`cleaned_prices.json\`, writes \`report.md\` \u2192 notifier reads \`report.md\`, pushes
|
|
18948
19207
|
|
|
18949
19208
|
## Logic & Conditions
|
|
18950
19209
|
- data-collector \u722C\u53D6\u5931\u8D25\u65F6\u91CD\u8BD5\u6700\u591A3\u6B21\uFF0C\u95F4\u969430\u79D2
|
|
@@ -19105,7 +19364,7 @@ Creates a PROCESSING agent with a business-defined workflow topology. Sub-agents
|
|
|
19105
19364
|
\`\`\`typescript
|
|
19106
19365
|
{
|
|
19107
19366
|
name: string, // Required. Display name for the orchestrator
|
|
19108
|
-
description?: string, // Required for good UX. Comprehensive workflow spec in Markdown (
|
|
19367
|
+
description?: string, // Required for good UX. Comprehensive workflow spec in Markdown (English). Must cover: Overview, Steps (with tools per step), Data Flow, Logic & Conditions, Tools Used, Expected Input, Expected Output. This is the single source of truth displayed in the automation view info popover.
|
|
19109
19368
|
prompt: string, // Required. System prompt \u2014 how to route through the topology
|
|
19110
19369
|
edges: [{ // Required. At least 1 edge defining the serial workflow chain
|
|
19111
19370
|
from: string, // Source agent ID. First edge: use orchestrator name as placeholder (tool auto-replaces). Subsequent edges: previous sub-agent ID
|
|
@@ -21203,7 +21462,7 @@ var MicrosandboxRemoteProvider = class {
|
|
|
21203
21462
|
this.instances.delete(name);
|
|
21204
21463
|
await this.client.deleteSandbox(name);
|
|
21205
21464
|
}
|
|
21206
|
-
createVolumeFsClient(volumeName) {
|
|
21465
|
+
createVolumeFsClient(volumeName, _pathPrefix) {
|
|
21207
21466
|
return {
|
|
21208
21467
|
read: (path3) => this.client.volumeFsRead(volumeName, path3),
|
|
21209
21468
|
write: (path3, content) => this.client.volumeFsWrite(volumeName, path3, content),
|
|
@@ -21260,50 +21519,84 @@ var MicrosandboxRemoteProvider = class {
|
|
|
21260
21519
|
import { SandboxClient as SandboxClient23 } from "@agent-infra/sandbox";
|
|
21261
21520
|
|
|
21262
21521
|
// src/sandbox_lattice/RemoteSandboxInstance.ts
|
|
21522
|
+
function extractFetcherError(error) {
|
|
21523
|
+
if (typeof error === "string") {
|
|
21524
|
+
return error;
|
|
21525
|
+
}
|
|
21526
|
+
if (error && typeof error === "object") {
|
|
21527
|
+
const e = error;
|
|
21528
|
+
if (typeof e.reason === "string") {
|
|
21529
|
+
switch (e.reason) {
|
|
21530
|
+
case "status-code":
|
|
21531
|
+
return `HTTP ${e.statusCode}: ${JSON.stringify(e.body)}`;
|
|
21532
|
+
case "non-json":
|
|
21533
|
+
return `HTTP ${e.statusCode}: ${e.rawBody}`;
|
|
21534
|
+
case "timeout":
|
|
21535
|
+
return "Request timed out";
|
|
21536
|
+
case "unknown":
|
|
21537
|
+
return typeof e.errorMessage === "string" ? e.errorMessage : "Unknown error";
|
|
21538
|
+
}
|
|
21539
|
+
}
|
|
21540
|
+
if (typeof e.message === "string") {
|
|
21541
|
+
return e.message;
|
|
21542
|
+
}
|
|
21543
|
+
if (typeof e.error === "string") {
|
|
21544
|
+
return e.error;
|
|
21545
|
+
}
|
|
21546
|
+
return JSON.stringify(error);
|
|
21547
|
+
}
|
|
21548
|
+
return String(error);
|
|
21549
|
+
}
|
|
21263
21550
|
var RemoteSandboxInstance = class {
|
|
21264
|
-
constructor(name, client) {
|
|
21551
|
+
constructor(name, client, workspace) {
|
|
21265
21552
|
this.client = client;
|
|
21553
|
+
this.workspace = workspace;
|
|
21266
21554
|
this.file = {
|
|
21267
21555
|
readFile: async (file) => {
|
|
21268
|
-
const
|
|
21556
|
+
const resolved = this.resolvePath(file);
|
|
21557
|
+
const result = await this.client.file.readFile({ file: resolved });
|
|
21269
21558
|
if (!result.ok) {
|
|
21270
|
-
throw new Error(
|
|
21559
|
+
throw new Error(`readFile failed: ${extractFetcherError(result.error)}`);
|
|
21271
21560
|
}
|
|
21272
21561
|
return { content: result.body.data?.content ?? "" };
|
|
21273
21562
|
},
|
|
21274
21563
|
writeFile: async (file, content) => {
|
|
21275
|
-
const
|
|
21564
|
+
const resolved = this.resolvePath(file);
|
|
21565
|
+
const result = await this.client.file.writeFile({ file: resolved, content });
|
|
21276
21566
|
if (!result.ok) {
|
|
21277
|
-
throw new Error(
|
|
21567
|
+
throw new Error(`writeFile failed: ${extractFetcherError(result.error)}`);
|
|
21278
21568
|
}
|
|
21279
21569
|
},
|
|
21280
21570
|
listPath: async (path3, options) => {
|
|
21571
|
+
const resolved = this.resolvePath(path3);
|
|
21281
21572
|
const result = await this.client.file.listPath({
|
|
21282
|
-
path:
|
|
21573
|
+
path: resolved,
|
|
21283
21574
|
recursive: options?.recursive ?? false
|
|
21284
21575
|
});
|
|
21285
21576
|
if (!result.ok) {
|
|
21286
|
-
throw new Error(
|
|
21577
|
+
throw new Error(`listPath failed: ${extractFetcherError(result.error)}`);
|
|
21287
21578
|
}
|
|
21288
21579
|
const files = (result.body.data?.files || []).map((f) => ({
|
|
21289
21580
|
path: f.path,
|
|
21290
|
-
is_dir: f.is_dir
|
|
21291
|
-
size: f.size,
|
|
21581
|
+
is_dir: f.is_dir === true || f.size === null,
|
|
21582
|
+
size: f.size ?? void 0,
|
|
21292
21583
|
modified_at: f.modified_at
|
|
21293
21584
|
}));
|
|
21294
21585
|
return { files };
|
|
21295
21586
|
},
|
|
21296
21587
|
findFiles: async (path3, glob) => {
|
|
21297
|
-
const
|
|
21588
|
+
const resolved = this.resolvePath(path3);
|
|
21589
|
+
const result = await this.client.file.findFiles({ path: resolved, glob });
|
|
21298
21590
|
if (!result.ok) {
|
|
21299
|
-
throw new Error(
|
|
21591
|
+
throw new Error(`findFiles failed: ${extractFetcherError(result.error)}`);
|
|
21300
21592
|
}
|
|
21301
21593
|
return { files: result.body.data?.files || [] };
|
|
21302
21594
|
},
|
|
21303
21595
|
searchInFile: async (file, regex) => {
|
|
21304
|
-
const
|
|
21596
|
+
const resolved = this.resolvePath(file);
|
|
21597
|
+
const result = await this.client.file.searchInFile({ file: resolved, regex });
|
|
21305
21598
|
if (!result.ok) {
|
|
21306
|
-
throw new Error(
|
|
21599
|
+
throw new Error(`searchInFile failed: ${extractFetcherError(result.error)}`);
|
|
21307
21600
|
}
|
|
21308
21601
|
return {
|
|
21309
21602
|
matches: result.body.data?.matches || [],
|
|
@@ -21311,30 +21604,33 @@ var RemoteSandboxInstance = class {
|
|
|
21311
21604
|
};
|
|
21312
21605
|
},
|
|
21313
21606
|
strReplaceEditor: async (params) => {
|
|
21607
|
+
const resolved = this.resolvePath(params.path);
|
|
21314
21608
|
const result = await this.client.file.strReplaceEditor({
|
|
21315
21609
|
command: params.command,
|
|
21316
|
-
path:
|
|
21610
|
+
path: resolved,
|
|
21317
21611
|
old_str: params.old_str,
|
|
21318
21612
|
new_str: params.new_str,
|
|
21319
21613
|
replace_mode: params.replace_mode
|
|
21320
21614
|
});
|
|
21321
21615
|
if (!result.ok) {
|
|
21322
|
-
throw new Error(
|
|
21616
|
+
throw new Error(`strReplaceEditor failed: ${extractFetcherError(result.error)}`);
|
|
21323
21617
|
}
|
|
21324
21618
|
},
|
|
21325
21619
|
uploadFile: async (params) => {
|
|
21620
|
+
const resolved = this.resolvePath(params.file);
|
|
21326
21621
|
const result = await this.client.file.uploadFile({
|
|
21327
21622
|
file: params.data,
|
|
21328
|
-
path:
|
|
21623
|
+
path: resolved
|
|
21329
21624
|
});
|
|
21330
21625
|
if (!result.ok) {
|
|
21331
|
-
throw new Error(
|
|
21626
|
+
throw new Error(`uploadFile failed: ${extractFetcherError(result.error)}`);
|
|
21332
21627
|
}
|
|
21333
21628
|
},
|
|
21334
21629
|
downloadFile: async (params) => {
|
|
21335
|
-
const
|
|
21630
|
+
const resolved = this.resolvePath(params.file);
|
|
21631
|
+
const result = await this.client.file.downloadFile({ path: resolved });
|
|
21336
21632
|
if (!result.ok) {
|
|
21337
|
-
throw new Error(
|
|
21633
|
+
throw new Error(`downloadFile failed: ${extractFetcherError(result.error)}`);
|
|
21338
21634
|
}
|
|
21339
21635
|
const buffer2 = await result.body.arrayBuffer();
|
|
21340
21636
|
return Buffer.from(buffer2);
|
|
@@ -21344,11 +21640,11 @@ var RemoteSandboxInstance = class {
|
|
|
21344
21640
|
execCommand: async (params) => {
|
|
21345
21641
|
const result = await this.client.shell.execCommand({
|
|
21346
21642
|
command: params.command,
|
|
21347
|
-
exec_dir: params.exec_dir,
|
|
21643
|
+
exec_dir: params.exec_dir ? this.resolvePath(params.exec_dir) : void 0,
|
|
21348
21644
|
timeout: params.timeout
|
|
21349
21645
|
});
|
|
21350
21646
|
if (!result.ok) {
|
|
21351
|
-
throw new Error(
|
|
21647
|
+
throw new Error(`execCommand failed: ${extractFetcherError(result.error)}`);
|
|
21352
21648
|
}
|
|
21353
21649
|
return {
|
|
21354
21650
|
output: result.body.data?.output ?? "",
|
|
@@ -21358,6 +21654,15 @@ var RemoteSandboxInstance = class {
|
|
|
21358
21654
|
};
|
|
21359
21655
|
this.name = name;
|
|
21360
21656
|
}
|
|
21657
|
+
resolvePath(file) {
|
|
21658
|
+
if (file.startsWith(this.workspace)) {
|
|
21659
|
+
return file;
|
|
21660
|
+
}
|
|
21661
|
+
if (!file.startsWith("/")) {
|
|
21662
|
+
return `${this.workspace}/${file}`;
|
|
21663
|
+
}
|
|
21664
|
+
return `${this.workspace}${file}`;
|
|
21665
|
+
}
|
|
21361
21666
|
async start() {
|
|
21362
21667
|
}
|
|
21363
21668
|
async stop() {
|
|
@@ -21378,23 +21683,58 @@ var RemoteSandboxInstance = class {
|
|
|
21378
21683
|
};
|
|
21379
21684
|
|
|
21380
21685
|
// src/sandbox_lattice/providers/RemoteSandboxProvider.ts
|
|
21686
|
+
var DEFAULT_WORKSPACE = "/home/gem";
|
|
21381
21687
|
var RemoteSandboxProvider = class {
|
|
21382
21688
|
constructor(config) {
|
|
21383
21689
|
this.config = config;
|
|
21384
21690
|
this.instances = /* @__PURE__ */ new Map();
|
|
21691
|
+
this.creating = /* @__PURE__ */ new Map();
|
|
21692
|
+
this.workspace = DEFAULT_WORKSPACE;
|
|
21693
|
+
this.workspaceResolved = false;
|
|
21385
21694
|
this.client = new SandboxClient23({
|
|
21386
21695
|
baseUrl: config.baseURL,
|
|
21387
21696
|
environment: ""
|
|
21388
21697
|
});
|
|
21389
21698
|
}
|
|
21699
|
+
async resolveWorkspace() {
|
|
21700
|
+
if (this.workspaceResolved) {
|
|
21701
|
+
return this.workspace;
|
|
21702
|
+
}
|
|
21703
|
+
try {
|
|
21704
|
+
const result = await this.client.sandbox.getContext();
|
|
21705
|
+
if (result.ok && result.body.home_dir) {
|
|
21706
|
+
this.workspace = result.body.home_dir;
|
|
21707
|
+
}
|
|
21708
|
+
} catch {
|
|
21709
|
+
}
|
|
21710
|
+
this.workspaceResolved = true;
|
|
21711
|
+
return this.workspace;
|
|
21712
|
+
}
|
|
21390
21713
|
async createSandbox(name, _config) {
|
|
21391
21714
|
const existing = this.instances.get(name);
|
|
21392
21715
|
if (existing) {
|
|
21393
21716
|
return existing;
|
|
21394
21717
|
}
|
|
21395
|
-
const
|
|
21396
|
-
|
|
21397
|
-
|
|
21718
|
+
const inFlight = this.creating.get(name);
|
|
21719
|
+
if (inFlight) {
|
|
21720
|
+
return inFlight;
|
|
21721
|
+
}
|
|
21722
|
+
const creation = (async () => {
|
|
21723
|
+
const workspace = await this.resolveWorkspace();
|
|
21724
|
+
const instance = new RemoteSandboxInstance(name, this.client, workspace);
|
|
21725
|
+
this.instances.set(name, instance);
|
|
21726
|
+
return instance;
|
|
21727
|
+
})();
|
|
21728
|
+
this.creating.set(name, creation);
|
|
21729
|
+
creation.then(
|
|
21730
|
+
() => {
|
|
21731
|
+
this.creating.delete(name);
|
|
21732
|
+
},
|
|
21733
|
+
() => {
|
|
21734
|
+
this.creating.delete(name);
|
|
21735
|
+
}
|
|
21736
|
+
);
|
|
21737
|
+
return creation;
|
|
21398
21738
|
}
|
|
21399
21739
|
async getSandbox(name) {
|
|
21400
21740
|
const instance = this.instances.get(name);
|
|
@@ -21404,9 +21744,7 @@ var RemoteSandboxProvider = class {
|
|
|
21404
21744
|
return instance;
|
|
21405
21745
|
}
|
|
21406
21746
|
async stopSandbox(name) {
|
|
21407
|
-
|
|
21408
|
-
if (instance) {
|
|
21409
|
-
}
|
|
21747
|
+
this.instances.delete(name);
|
|
21410
21748
|
}
|
|
21411
21749
|
async deleteSandbox(name) {
|
|
21412
21750
|
this.instances.delete(name);
|
|
@@ -21414,6 +21752,82 @@ var RemoteSandboxProvider = class {
|
|
|
21414
21752
|
async listSandboxes() {
|
|
21415
21753
|
return Array.from(this.instances.values());
|
|
21416
21754
|
}
|
|
21755
|
+
createVolumeFsClient(_volumeName, pathPrefix) {
|
|
21756
|
+
const workspace = this.workspace;
|
|
21757
|
+
const resolve3 = (p) => {
|
|
21758
|
+
if (!p || p === "/") {
|
|
21759
|
+
if (pathPrefix) {
|
|
21760
|
+
return `${workspace}${pathPrefix}`;
|
|
21761
|
+
}
|
|
21762
|
+
return workspace;
|
|
21763
|
+
}
|
|
21764
|
+
if (p.startsWith(workspace)) {
|
|
21765
|
+
return p;
|
|
21766
|
+
}
|
|
21767
|
+
if (p.startsWith("/")) {
|
|
21768
|
+
return `${workspace}${p}`;
|
|
21769
|
+
}
|
|
21770
|
+
if (pathPrefix) {
|
|
21771
|
+
const mountDir = pathPrefix.replace(/^\//, "");
|
|
21772
|
+
return `${workspace}/${mountDir}/${p}`;
|
|
21773
|
+
}
|
|
21774
|
+
return `${workspace}/${p}`;
|
|
21775
|
+
};
|
|
21776
|
+
return {
|
|
21777
|
+
read: async (path3) => {
|
|
21778
|
+
const resolved = resolve3(path3);
|
|
21779
|
+
const result = await this.client.file.readFile({ file: resolved });
|
|
21780
|
+
if (!result.ok) {
|
|
21781
|
+
throw new Error(`Volume read failed: ${extractFetcherError(result.error)}`);
|
|
21782
|
+
}
|
|
21783
|
+
return result.body.data?.content ?? "";
|
|
21784
|
+
},
|
|
21785
|
+
write: async (path3, content) => {
|
|
21786
|
+
const resolved = resolve3(path3);
|
|
21787
|
+
const result = await this.client.file.writeFile({ file: resolved, content });
|
|
21788
|
+
if (!result.ok) {
|
|
21789
|
+
throw new Error(`Volume write failed: ${extractFetcherError(result.error)}`);
|
|
21790
|
+
}
|
|
21791
|
+
},
|
|
21792
|
+
list: async (path3) => {
|
|
21793
|
+
const resolved = resolve3(path3);
|
|
21794
|
+
const result = await this.client.file.listPath({
|
|
21795
|
+
path: resolved,
|
|
21796
|
+
recursive: false
|
|
21797
|
+
});
|
|
21798
|
+
if (!result.ok) {
|
|
21799
|
+
throw new Error(`Volume list failed: ${extractFetcherError(result.error)}`);
|
|
21800
|
+
}
|
|
21801
|
+
const entries = (result.body.data?.files || []).map((f) => ({
|
|
21802
|
+
path: f.path.startsWith(workspace) ? f.path.slice(workspace.length) : f.path,
|
|
21803
|
+
kind: f.is_dir === true || f.size === null ? "directory" : "file",
|
|
21804
|
+
size: f.size ?? 0,
|
|
21805
|
+
mode: 0,
|
|
21806
|
+
modified: f.modified_at ?? null
|
|
21807
|
+
}));
|
|
21808
|
+
return entries;
|
|
21809
|
+
},
|
|
21810
|
+
readRaw: async (path3) => {
|
|
21811
|
+
const resolved = resolve3(path3);
|
|
21812
|
+
const result = await this.client.file.downloadFile({ path: resolved });
|
|
21813
|
+
if (!result.ok) {
|
|
21814
|
+
throw new Error(`Volume download failed: ${extractFetcherError(result.error)}`);
|
|
21815
|
+
}
|
|
21816
|
+
const buffer2 = await result.body.arrayBuffer();
|
|
21817
|
+
return Buffer.from(buffer2);
|
|
21818
|
+
},
|
|
21819
|
+
writeRaw: async (path3, data) => {
|
|
21820
|
+
const resolved = resolve3(path3);
|
|
21821
|
+
const result = await this.client.file.uploadFile({
|
|
21822
|
+
file: data,
|
|
21823
|
+
path: resolved
|
|
21824
|
+
});
|
|
21825
|
+
if (!result.ok) {
|
|
21826
|
+
throw new Error(`Volume upload failed: ${extractFetcherError(result.error)}`);
|
|
21827
|
+
}
|
|
21828
|
+
}
|
|
21829
|
+
};
|
|
21830
|
+
}
|
|
21417
21831
|
};
|
|
21418
21832
|
|
|
21419
21833
|
// src/sandbox_lattice/providers/E2BProvider.ts
|
|
@@ -22054,6 +22468,7 @@ export {
|
|
|
22054
22468
|
MicrosandboxRemoteProvider,
|
|
22055
22469
|
MicrosandboxServiceClient,
|
|
22056
22470
|
ModelLatticeManager,
|
|
22471
|
+
MysqlDatabase,
|
|
22057
22472
|
PinoLoggerClient,
|
|
22058
22473
|
PostgresDatabase,
|
|
22059
22474
|
PrometheusClient,
|
|
@@ -22118,6 +22533,7 @@ export {
|
|
|
22118
22533
|
ensureBuiltinAgentsForTenant,
|
|
22119
22534
|
eventBus,
|
|
22120
22535
|
event_bus_default as eventBusDefault,
|
|
22536
|
+
extractFetcherError,
|
|
22121
22537
|
fileDataToString,
|
|
22122
22538
|
formatContentWithLineNumbers,
|
|
22123
22539
|
formatGrepMatches,
|