agent-phonon 0.2.11 → 0.3.0
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/cli.js +444 -23
- package/dist/cli.js.map +1 -1
- package/dist/daemon.js +444 -23
- package/dist/daemon.js.map +1 -1
- package/package.json +3 -3
package/dist/daemon.js
CHANGED
|
@@ -939,7 +939,7 @@ var init_project = __esm({
|
|
|
939
939
|
|
|
940
940
|
// ../protocol/dist/schemas/skill.js
|
|
941
941
|
import { z as z10 } from "zod";
|
|
942
|
-
var SkillScope, SkillSource, SkillDescriptor, SkillInstallParams, SkillInstallResult, SkillUninstallParams, SkillUninstallResult, SkillListParams, SkillListResult;
|
|
942
|
+
var SkillScope, SkillSource, SkillDescriptor, SkillInstallParams, SkillInstallResult, SkillUninstallParams, SkillUninstallResult, SkillListParams, SkillListResult, SkillDirsParams, SkillDirectoryDescriptor, SkillDirsResult;
|
|
943
943
|
var init_skill = __esm({
|
|
944
944
|
"../protocol/dist/schemas/skill.js"() {
|
|
945
945
|
"use strict";
|
|
@@ -1027,6 +1027,29 @@ var init_skill = __esm({
|
|
|
1027
1027
|
SkillListResult = z10.object({
|
|
1028
1028
|
skills: z10.array(SkillDescriptor)
|
|
1029
1029
|
});
|
|
1030
|
+
SkillDirsParams = z10.object({
|
|
1031
|
+
/** 可选:global scope 的目标 agent。 */
|
|
1032
|
+
agent: AgentId.optional(),
|
|
1033
|
+
/** 可选:project scope 的目标项目。 */
|
|
1034
|
+
projectId: ProjectId.optional(),
|
|
1035
|
+
/** 可选:只查 global 或 project;不传时按 agent/projectId 返回可查范围。 */
|
|
1036
|
+
scope: SkillScope.optional()
|
|
1037
|
+
});
|
|
1038
|
+
SkillDirectoryDescriptor = z10.object({
|
|
1039
|
+
/** skill 目录名。 */
|
|
1040
|
+
name: z10.string().min(1),
|
|
1041
|
+
scope: SkillScope,
|
|
1042
|
+
agent: AgentId.optional(),
|
|
1043
|
+
projectId: ProjectId.optional(),
|
|
1044
|
+
/** scope 根目录(global skill root 或 <project>/.agent/skills)。 */
|
|
1045
|
+
rootPath: z10.string().min(1),
|
|
1046
|
+
/** skill 目录真实本机路径。 */
|
|
1047
|
+
path: z10.string().min(1),
|
|
1048
|
+
exists: z10.boolean()
|
|
1049
|
+
});
|
|
1050
|
+
SkillDirsResult = z10.object({
|
|
1051
|
+
directories: z10.array(SkillDirectoryDescriptor)
|
|
1052
|
+
});
|
|
1030
1053
|
}
|
|
1031
1054
|
});
|
|
1032
1055
|
|
|
@@ -1310,43 +1333,166 @@ var init_env = __esm({
|
|
|
1310
1333
|
}
|
|
1311
1334
|
});
|
|
1312
1335
|
|
|
1313
|
-
// ../protocol/dist/schemas/
|
|
1336
|
+
// ../protocol/dist/schemas/workflow.js
|
|
1314
1337
|
import { z as z16 } from "zod";
|
|
1338
|
+
var ModelId, TurnId, ClientRequestId, WorkflowId, WorkflowNodeId, WorkflowEdgeId, WorkflowRoleId, WorkflowNode, WorkflowEdge, WorkflowDagPlan, WorkflowCommunicationGraph, WorkflowGraphPlan, WorkflowPlan, WorkflowStatus, WorkflowNodeStatus, WorkflowRunParams, WorkflowRunResult, WorkflowStatusParams, WorkflowNodeRuntime, WorkflowStatusResult, WorkflowCancelParams, WorkflowCancelResult, WorkflowListParams, WorkflowListResult, WorkflowEvent;
|
|
1339
|
+
var init_workflow = __esm({
|
|
1340
|
+
"../protocol/dist/schemas/workflow.js"() {
|
|
1341
|
+
"use strict";
|
|
1342
|
+
init_common();
|
|
1343
|
+
ModelId = z16.string().min(1);
|
|
1344
|
+
TurnId = z16.string().min(1);
|
|
1345
|
+
ClientRequestId = z16.string().min(1);
|
|
1346
|
+
WorkflowId = z16.string().min(1);
|
|
1347
|
+
WorkflowNodeId = z16.string().min(1);
|
|
1348
|
+
WorkflowEdgeId = z16.string().min(1);
|
|
1349
|
+
WorkflowRoleId = z16.string().min(1);
|
|
1350
|
+
WorkflowNode = z16.object({
|
|
1351
|
+
nodeId: WorkflowNodeId,
|
|
1352
|
+
agent: AgentId,
|
|
1353
|
+
model: ModelId,
|
|
1354
|
+
role: WorkflowRoleId.optional(),
|
|
1355
|
+
input: z16.string().optional(),
|
|
1356
|
+
systemPrompt: z16.string().optional(),
|
|
1357
|
+
dependsOn: z16.array(WorkflowNodeId).optional(),
|
|
1358
|
+
sessionId: SessionId.optional(),
|
|
1359
|
+
agentConfig: z16.record(z16.unknown()).optional(),
|
|
1360
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1361
|
+
});
|
|
1362
|
+
WorkflowEdge = z16.object({
|
|
1363
|
+
edgeId: WorkflowEdgeId.optional(),
|
|
1364
|
+
from: WorkflowNodeId,
|
|
1365
|
+
to: WorkflowNodeId,
|
|
1366
|
+
label: z16.string().optional(),
|
|
1367
|
+
condition: z16.string().optional(),
|
|
1368
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1369
|
+
});
|
|
1370
|
+
WorkflowDagPlan = z16.object({
|
|
1371
|
+
mode: z16.literal("dag"),
|
|
1372
|
+
nodes: z16.array(WorkflowNode).min(1),
|
|
1373
|
+
edges: z16.array(WorkflowEdge).optional(),
|
|
1374
|
+
finalNodeId: WorkflowNodeId.optional()
|
|
1375
|
+
});
|
|
1376
|
+
WorkflowCommunicationGraph = z16.object({
|
|
1377
|
+
edges: z16.array(WorkflowEdge).default([]),
|
|
1378
|
+
allowSelfLoop: z16.boolean().default(false),
|
|
1379
|
+
maxIterations: z16.number().int().positive().default(12)
|
|
1380
|
+
});
|
|
1381
|
+
WorkflowGraphPlan = z16.object({
|
|
1382
|
+
mode: z16.literal("graph"),
|
|
1383
|
+
executor: z16.object({
|
|
1384
|
+
nodeId: WorkflowNodeId,
|
|
1385
|
+
agent: AgentId,
|
|
1386
|
+
model: ModelId,
|
|
1387
|
+
role: z16.literal("executor").default("executor"),
|
|
1388
|
+
systemPrompt: z16.string().optional(),
|
|
1389
|
+
agentConfig: z16.record(z16.unknown()).optional()
|
|
1390
|
+
}),
|
|
1391
|
+
workers: z16.array(WorkflowNode).min(1),
|
|
1392
|
+
communicationGraph: WorkflowCommunicationGraph
|
|
1393
|
+
});
|
|
1394
|
+
WorkflowPlan = z16.discriminatedUnion("mode", [WorkflowDagPlan, WorkflowGraphPlan]);
|
|
1395
|
+
WorkflowStatus = z16.enum(["queued", "running", "completed", "failed", "cancelled", "timeout"]);
|
|
1396
|
+
WorkflowNodeStatus = z16.enum(["pending", "ready", "running", "completed", "failed", "skipped", "cancelled"]);
|
|
1397
|
+
WorkflowRunParams = z16.object({
|
|
1398
|
+
project: ProjectId,
|
|
1399
|
+
worktreeId: z16.string().optional(),
|
|
1400
|
+
plan: WorkflowPlan,
|
|
1401
|
+
input: z16.string().optional(),
|
|
1402
|
+
clientRequestId: ClientRequestId.optional(),
|
|
1403
|
+
metadata: z16.record(z16.unknown()).optional()
|
|
1404
|
+
});
|
|
1405
|
+
WorkflowRunResult = z16.object({
|
|
1406
|
+
workflowId: WorkflowId,
|
|
1407
|
+
status: WorkflowStatus,
|
|
1408
|
+
createdAt: Timestamp
|
|
1409
|
+
});
|
|
1410
|
+
WorkflowStatusParams = z16.object({ workflowId: WorkflowId });
|
|
1411
|
+
WorkflowNodeRuntime = z16.object({
|
|
1412
|
+
nodeId: WorkflowNodeId,
|
|
1413
|
+
status: WorkflowNodeStatus,
|
|
1414
|
+
agent: AgentId,
|
|
1415
|
+
model: ModelId,
|
|
1416
|
+
role: WorkflowRoleId.optional(),
|
|
1417
|
+
sessionId: SessionId.optional(),
|
|
1418
|
+
turnId: TurnId.optional(),
|
|
1419
|
+
startedAt: Timestamp.optional(),
|
|
1420
|
+
completedAt: Timestamp.optional(),
|
|
1421
|
+
error: z16.string().optional()
|
|
1422
|
+
});
|
|
1423
|
+
WorkflowStatusResult = z16.object({
|
|
1424
|
+
workflowId: WorkflowId,
|
|
1425
|
+
status: WorkflowStatus,
|
|
1426
|
+
project: ProjectId,
|
|
1427
|
+
mode: z16.enum(["dag", "graph"]),
|
|
1428
|
+
nodes: z16.array(WorkflowNodeRuntime),
|
|
1429
|
+
createdAt: Timestamp,
|
|
1430
|
+
updatedAt: Timestamp,
|
|
1431
|
+
completedAt: Timestamp.optional(),
|
|
1432
|
+
error: z16.string().optional()
|
|
1433
|
+
});
|
|
1434
|
+
WorkflowCancelParams = z16.object({ workflowId: WorkflowId, reason: z16.string().optional() });
|
|
1435
|
+
WorkflowCancelResult = z16.object({ workflowId: WorkflowId, status: z16.literal("cancelled") });
|
|
1436
|
+
WorkflowListParams = z16.object({
|
|
1437
|
+
status: WorkflowStatus.optional(),
|
|
1438
|
+
limit: z16.number().int().positive().max(100).default(50).optional(),
|
|
1439
|
+
cursor: z16.string().optional()
|
|
1440
|
+
});
|
|
1441
|
+
WorkflowListResult = z16.object({ workflows: z16.array(WorkflowStatusResult), nextCursor: z16.string().optional() });
|
|
1442
|
+
WorkflowEvent = z16.object({
|
|
1443
|
+
workflowId: WorkflowId,
|
|
1444
|
+
seq: z16.number().int().nonnegative(),
|
|
1445
|
+
type: z16.enum(["workflow.status", "node.status", "node.stream", "edge.route", "executor.decision"]),
|
|
1446
|
+
nodeId: WorkflowNodeId.optional(),
|
|
1447
|
+
sessionId: SessionId.optional(),
|
|
1448
|
+
turnId: TurnId.optional(),
|
|
1449
|
+
agent: AgentId.optional(),
|
|
1450
|
+
model: ModelId.optional(),
|
|
1451
|
+
role: WorkflowRoleId.optional(),
|
|
1452
|
+
status: z16.union([WorkflowStatus, WorkflowNodeStatus]).optional(),
|
|
1453
|
+
payload: z16.record(z16.unknown()).optional(),
|
|
1454
|
+
timestamp: Timestamp
|
|
1455
|
+
});
|
|
1456
|
+
}
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
// ../protocol/dist/schemas/jsonrpc.js
|
|
1460
|
+
import { z as z17 } from "zod";
|
|
1315
1461
|
var JsonRpcVersion, JsonRpcId, JsonRpcRequest, JsonRpcNotification, JsonRpcSuccess, JsonRpcErrorObject, JsonRpcError, JsonRpcMessage, JSON_RPC_CODES;
|
|
1316
1462
|
var init_jsonrpc = __esm({
|
|
1317
1463
|
"../protocol/dist/schemas/jsonrpc.js"() {
|
|
1318
1464
|
"use strict";
|
|
1319
1465
|
init_common();
|
|
1320
|
-
JsonRpcVersion =
|
|
1321
|
-
JsonRpcId =
|
|
1322
|
-
JsonRpcRequest =
|
|
1466
|
+
JsonRpcVersion = z17.literal("2.0");
|
|
1467
|
+
JsonRpcId = z17.union([z17.string(), z17.number()]);
|
|
1468
|
+
JsonRpcRequest = z17.object({
|
|
1323
1469
|
jsonrpc: JsonRpcVersion,
|
|
1324
1470
|
id: JsonRpcId,
|
|
1325
|
-
method:
|
|
1326
|
-
params:
|
|
1471
|
+
method: z17.string(),
|
|
1472
|
+
params: z17.unknown().optional()
|
|
1327
1473
|
});
|
|
1328
|
-
JsonRpcNotification =
|
|
1474
|
+
JsonRpcNotification = z17.object({
|
|
1329
1475
|
jsonrpc: JsonRpcVersion,
|
|
1330
|
-
method:
|
|
1331
|
-
params:
|
|
1476
|
+
method: z17.string(),
|
|
1477
|
+
params: z17.unknown().optional()
|
|
1332
1478
|
});
|
|
1333
|
-
JsonRpcSuccess =
|
|
1479
|
+
JsonRpcSuccess = z17.object({
|
|
1334
1480
|
jsonrpc: JsonRpcVersion,
|
|
1335
1481
|
id: JsonRpcId,
|
|
1336
|
-
result:
|
|
1482
|
+
result: z17.unknown()
|
|
1337
1483
|
});
|
|
1338
|
-
JsonRpcErrorObject =
|
|
1484
|
+
JsonRpcErrorObject = z17.object({
|
|
1339
1485
|
/** JSON-RPC 传输级 code(-32700..-32600 保留;应用错误用 data.appCode 判别)。 */
|
|
1340
|
-
code:
|
|
1341
|
-
message:
|
|
1486
|
+
code: z17.number().int(),
|
|
1487
|
+
message: z17.string(),
|
|
1342
1488
|
data: PhononErrorData.optional()
|
|
1343
1489
|
});
|
|
1344
|
-
JsonRpcError =
|
|
1490
|
+
JsonRpcError = z17.object({
|
|
1345
1491
|
jsonrpc: JsonRpcVersion,
|
|
1346
1492
|
id: JsonRpcId.nullable(),
|
|
1347
1493
|
error: JsonRpcErrorObject
|
|
1348
1494
|
});
|
|
1349
|
-
JsonRpcMessage =
|
|
1495
|
+
JsonRpcMessage = z17.union([
|
|
1350
1496
|
JsonRpcRequest,
|
|
1351
1497
|
JsonRpcNotification,
|
|
1352
1498
|
JsonRpcSuccess,
|
|
@@ -1365,7 +1511,7 @@ var init_jsonrpc = __esm({
|
|
|
1365
1511
|
});
|
|
1366
1512
|
|
|
1367
1513
|
// ../protocol/dist/schemas/methods.js
|
|
1368
|
-
import { z as
|
|
1514
|
+
import { z as z18 } from "zod";
|
|
1369
1515
|
function parseParams(method, data) {
|
|
1370
1516
|
return METHODS[method].params.parse(data);
|
|
1371
1517
|
}
|
|
@@ -1385,7 +1531,8 @@ var init_methods = __esm({
|
|
|
1385
1531
|
init_device();
|
|
1386
1532
|
init_file();
|
|
1387
1533
|
init_env();
|
|
1388
|
-
|
|
1534
|
+
init_workflow();
|
|
1535
|
+
z_void = z18.undefined();
|
|
1389
1536
|
METHODS = {
|
|
1390
1537
|
// --- 握手(phonon 拨出后先发)---
|
|
1391
1538
|
"connect.hello": {
|
|
@@ -1663,6 +1810,43 @@ var init_methods = __esm({
|
|
|
1663
1810
|
kind: "request",
|
|
1664
1811
|
params: SkillListParams,
|
|
1665
1812
|
result: SkillListResult
|
|
1813
|
+
},
|
|
1814
|
+
"skill.dirs": {
|
|
1815
|
+
direction: "s2p",
|
|
1816
|
+
kind: "request",
|
|
1817
|
+
params: SkillDirsParams,
|
|
1818
|
+
result: SkillDirsResult
|
|
1819
|
+
},
|
|
1820
|
+
// --- L3 workflow orchestration (DAG / executor graph) ---
|
|
1821
|
+
"workflow.run": {
|
|
1822
|
+
direction: "s2p",
|
|
1823
|
+
kind: "request",
|
|
1824
|
+
params: WorkflowRunParams,
|
|
1825
|
+
result: WorkflowRunResult
|
|
1826
|
+
},
|
|
1827
|
+
"workflow.status": {
|
|
1828
|
+
direction: "s2p",
|
|
1829
|
+
kind: "request",
|
|
1830
|
+
params: WorkflowStatusParams,
|
|
1831
|
+
result: WorkflowStatusResult
|
|
1832
|
+
},
|
|
1833
|
+
"workflow.cancel": {
|
|
1834
|
+
direction: "s2p",
|
|
1835
|
+
kind: "request",
|
|
1836
|
+
params: WorkflowCancelParams,
|
|
1837
|
+
result: WorkflowCancelResult
|
|
1838
|
+
},
|
|
1839
|
+
"workflow.list": {
|
|
1840
|
+
direction: "s2p",
|
|
1841
|
+
kind: "request",
|
|
1842
|
+
params: WorkflowListParams,
|
|
1843
|
+
result: WorkflowListResult
|
|
1844
|
+
},
|
|
1845
|
+
"workflow.event": {
|
|
1846
|
+
direction: "p2s",
|
|
1847
|
+
kind: "notification",
|
|
1848
|
+
params: WorkflowEvent,
|
|
1849
|
+
result: z_void
|
|
1666
1850
|
}
|
|
1667
1851
|
};
|
|
1668
1852
|
METHOD_NAMES = Object.keys(METHODS);
|
|
@@ -1688,6 +1872,7 @@ var init_dist = __esm({
|
|
|
1688
1872
|
init_device();
|
|
1689
1873
|
init_file();
|
|
1690
1874
|
init_env();
|
|
1875
|
+
init_workflow();
|
|
1691
1876
|
init_jsonrpc();
|
|
1692
1877
|
init_methods();
|
|
1693
1878
|
}
|
|
@@ -2437,7 +2622,7 @@ var ProjectManager = class {
|
|
|
2437
2622
|
|
|
2438
2623
|
// ../core/dist/skill-manager.js
|
|
2439
2624
|
init_rpc();
|
|
2440
|
-
import { mkdir as mkdir2, rm as rm2, writeFile, readdir as readdir2, stat as stat2, mkdtemp, lstat } from "node:fs/promises";
|
|
2625
|
+
import { mkdir as mkdir2, rm as rm2, writeFile, readdir as readdir2, stat as stat2, mkdtemp, lstat, realpath } from "node:fs/promises";
|
|
2441
2626
|
import { existsSync as existsSync2 } from "node:fs";
|
|
2442
2627
|
import { join as join2, resolve as resolve2, sep } from "node:path";
|
|
2443
2628
|
import { tmpdir } from "node:os";
|
|
@@ -2540,6 +2725,36 @@ var SkillManager = class {
|
|
|
2540
2725
|
return true;
|
|
2541
2726
|
});
|
|
2542
2727
|
}
|
|
2728
|
+
async dirs(filter) {
|
|
2729
|
+
const rows = [];
|
|
2730
|
+
if (filter?.scope !== "project" && filter?.agent) {
|
|
2731
|
+
const adapter = this.registry.resolve(filter.agent);
|
|
2732
|
+
const root = adapter?.globalSkillDir?.(filter.agent);
|
|
2733
|
+
if (root)
|
|
2734
|
+
rows.push(...await this.listDirs(root, { scope: "global", agent: filter.agent }));
|
|
2735
|
+
}
|
|
2736
|
+
if (filter?.scope !== "global" && filter?.projectId) {
|
|
2737
|
+
const projPath = this.resolveProjectPath(filter.projectId);
|
|
2738
|
+
if (!projPath)
|
|
2739
|
+
throw new PhononError("errProjectNotFound", `project ${filter.projectId} not found`);
|
|
2740
|
+
rows.push(...await this.listDirs(join2(projPath, ".agent", "skills"), { scope: "project", projectId: filter.projectId }));
|
|
2741
|
+
}
|
|
2742
|
+
return rows;
|
|
2743
|
+
}
|
|
2744
|
+
async listDirs(root, base) {
|
|
2745
|
+
const rootPath = existsSync2(root) ? await realpath(root) : resolve2(root);
|
|
2746
|
+
if (!existsSync2(root))
|
|
2747
|
+
return [];
|
|
2748
|
+
const entries = await readdir2(root, { withFileTypes: true });
|
|
2749
|
+
const rows = [];
|
|
2750
|
+
for (const e of entries) {
|
|
2751
|
+
if (!e.isDirectory())
|
|
2752
|
+
continue;
|
|
2753
|
+
const full = join2(root, e.name);
|
|
2754
|
+
rows.push({ name: e.name, ...base, rootPath, path: await realpath(full), exists: true });
|
|
2755
|
+
}
|
|
2756
|
+
return rows.sort((a, b) => a.name.localeCompare(b.name));
|
|
2757
|
+
}
|
|
2543
2758
|
async installArchive(source, dest) {
|
|
2544
2759
|
if (source.format !== "tar.gz")
|
|
2545
2760
|
throw new PhononError("errSkillInstallFailed", `unsupported archive format: ${source.format}`);
|
|
@@ -3141,7 +3356,7 @@ var PhononStore = class {
|
|
|
3141
3356
|
|
|
3142
3357
|
// ../core/dist/file-manager.js
|
|
3143
3358
|
init_rpc();
|
|
3144
|
-
import { mkdir as mkdir3, readFile, readdir as readdir3, lstat as lstat2, realpath, writeFile as writeFile2 } from "node:fs/promises";
|
|
3359
|
+
import { mkdir as mkdir3, readFile, readdir as readdir3, lstat as lstat2, realpath as realpath2, writeFile as writeFile2 } from "node:fs/promises";
|
|
3145
3360
|
import { basename as basename2, dirname as dirname3, join as join4, resolve as resolve4, sep as sep2 } from "node:path";
|
|
3146
3361
|
var FileManager = class {
|
|
3147
3362
|
resolver;
|
|
@@ -3158,7 +3373,7 @@ var FileManager = class {
|
|
|
3158
3373
|
let cur = abs;
|
|
3159
3374
|
for (; ; ) {
|
|
3160
3375
|
try {
|
|
3161
|
-
const real = await
|
|
3376
|
+
const real = await realpath2(cur);
|
|
3162
3377
|
return suffix.length ? resolve4(real, ...suffix) : real;
|
|
3163
3378
|
} catch (e) {
|
|
3164
3379
|
if (e?.code !== "ENOENT")
|
|
@@ -3364,6 +3579,190 @@ async function commandExists(cmd) {
|
|
|
3364
3579
|
}
|
|
3365
3580
|
}
|
|
3366
3581
|
|
|
3582
|
+
// ../core/dist/workflow-engine.js
|
|
3583
|
+
init_rpc();
|
|
3584
|
+
var WorkflowEngine = class {
|
|
3585
|
+
opts;
|
|
3586
|
+
runs = /* @__PURE__ */ new Map();
|
|
3587
|
+
sessionToNode = /* @__PURE__ */ new Map();
|
|
3588
|
+
idSeq = 1;
|
|
3589
|
+
constructor(opts) {
|
|
3590
|
+
this.opts = opts;
|
|
3591
|
+
}
|
|
3592
|
+
async run(params) {
|
|
3593
|
+
const workflowId = `wf-${Date.now()}-${this.idSeq++}`;
|
|
3594
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3595
|
+
const nodes = this.initialNodes(params.plan);
|
|
3596
|
+
const run = { workflowId, tenantId: this.opts.tenantId, project: params.project, worktreeId: params.worktreeId, mode: params.plan.mode, plan: params.plan, input: params.input, status: "queued", nodes, createdAt: now, updatedAt: now, seq: 0 };
|
|
3597
|
+
this.runs.set(workflowId, run);
|
|
3598
|
+
this.emit(run, { type: "workflow.status", status: "queued" });
|
|
3599
|
+
void this.execute(run).catch((err) => this.fail(run, err));
|
|
3600
|
+
return { workflowId, status: run.status, createdAt: run.createdAt };
|
|
3601
|
+
}
|
|
3602
|
+
status(workflowId) {
|
|
3603
|
+
const run = this.get(workflowId);
|
|
3604
|
+
return this.toStatus(run);
|
|
3605
|
+
}
|
|
3606
|
+
list(filter) {
|
|
3607
|
+
const limit = filter?.limit ?? 50;
|
|
3608
|
+
const rows = [...this.runs.values()].filter((r) => !filter?.status || r.status === filter.status).slice(-limit).reverse();
|
|
3609
|
+
return { workflows: rows.map((r) => this.toStatus(r)) };
|
|
3610
|
+
}
|
|
3611
|
+
async cancel(workflowId, reason) {
|
|
3612
|
+
const run = this.get(workflowId);
|
|
3613
|
+
run.status = "cancelled";
|
|
3614
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3615
|
+
run.updatedAt = run.completedAt;
|
|
3616
|
+
for (const n of run.nodes) {
|
|
3617
|
+
if (n.sessionId && (n.status === "running" || n.status === "ready" || n.status === "pending")) {
|
|
3618
|
+
n.status = "cancelled";
|
|
3619
|
+
try {
|
|
3620
|
+
await this.opts.engine.terminate(this.opts.tenantId, n.sessionId);
|
|
3621
|
+
} catch {
|
|
3622
|
+
}
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
this.emit(run, { type: "workflow.status", status: "cancelled", payload: { reason } });
|
|
3626
|
+
return { workflowId, status: "cancelled" };
|
|
3627
|
+
}
|
|
3628
|
+
onStreamEvent(ev) {
|
|
3629
|
+
const sessionId = ev.sessionId;
|
|
3630
|
+
if (!sessionId)
|
|
3631
|
+
return;
|
|
3632
|
+
const m = this.sessionToNode.get(sessionId);
|
|
3633
|
+
if (!m)
|
|
3634
|
+
return;
|
|
3635
|
+
const run = this.runs.get(m.workflowId);
|
|
3636
|
+
const node = run?.nodes.find((n) => n.nodeId === m.nodeId);
|
|
3637
|
+
if (!run || !node)
|
|
3638
|
+
return;
|
|
3639
|
+
this.emit(run, {
|
|
3640
|
+
type: "node.stream",
|
|
3641
|
+
nodeId: node.nodeId,
|
|
3642
|
+
sessionId,
|
|
3643
|
+
turnId: ev.turnId,
|
|
3644
|
+
agent: node.agent,
|
|
3645
|
+
model: node.model,
|
|
3646
|
+
role: node.role,
|
|
3647
|
+
payload: ev
|
|
3648
|
+
});
|
|
3649
|
+
}
|
|
3650
|
+
async execute(run) {
|
|
3651
|
+
run.status = "running";
|
|
3652
|
+
run.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3653
|
+
this.emit(run, { type: "workflow.status", status: "running" });
|
|
3654
|
+
if (run.plan.mode === "dag")
|
|
3655
|
+
await this.executeDag(run);
|
|
3656
|
+
else
|
|
3657
|
+
await this.executeGraph(run);
|
|
3658
|
+
if (!["cancelled", "failed"].includes(run.status)) {
|
|
3659
|
+
run.status = "completed";
|
|
3660
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3661
|
+
run.updatedAt = run.completedAt;
|
|
3662
|
+
this.emit(run, { type: "workflow.status", status: "completed" });
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
async executeDag(run) {
|
|
3666
|
+
const plan = run.plan.mode === "dag" ? run.plan : void 0;
|
|
3667
|
+
if (!plan)
|
|
3668
|
+
return;
|
|
3669
|
+
const deps = /* @__PURE__ */ new Map();
|
|
3670
|
+
for (const n of plan.nodes)
|
|
3671
|
+
deps.set(n.nodeId, new Set(n.dependsOn ?? []));
|
|
3672
|
+
for (const e of plan.edges ?? [])
|
|
3673
|
+
deps.get(e.to)?.add(e.from);
|
|
3674
|
+
const done = /* @__PURE__ */ new Set();
|
|
3675
|
+
while (done.size < plan.nodes.length) {
|
|
3676
|
+
const ready = plan.nodes.filter((n) => !done.has(n.nodeId) && [...deps.get(n.nodeId) ?? []].every((d) => done.has(d)));
|
|
3677
|
+
if (ready.length === 0)
|
|
3678
|
+
throw new PhononError("errInvalidParams", "workflow DAG has a cycle or missing dependency");
|
|
3679
|
+
await Promise.all(ready.map((n) => this.executeNode(run, n.nodeId, n.agent, n.model, n.role, n.input ?? run.input ?? "", n.agentConfig)));
|
|
3680
|
+
for (const n of ready)
|
|
3681
|
+
done.add(n.nodeId);
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
async executeGraph(run) {
|
|
3685
|
+
const plan = run.plan.mode === "graph" ? run.plan : void 0;
|
|
3686
|
+
if (!plan)
|
|
3687
|
+
return;
|
|
3688
|
+
const prompt = [
|
|
3689
|
+
"You are the executor for a multi-agent graph workflow.",
|
|
3690
|
+
`Input: ${run.input ?? ""}`,
|
|
3691
|
+
`Workers: ${JSON.stringify(plan.workers.map((w) => ({ nodeId: w.nodeId, role: w.role, agent: w.agent, model: w.model })))}`,
|
|
3692
|
+
`Communication graph: ${JSON.stringify(plan.communicationGraph)}`,
|
|
3693
|
+
"Produce the first routing decision and final summary for this initial implementation."
|
|
3694
|
+
].join("\n\n");
|
|
3695
|
+
await this.executeNode(run, plan.executor.nodeId, plan.executor.agent, plan.executor.model, plan.executor.role, prompt, plan.executor.agentConfig);
|
|
3696
|
+
this.emit(run, { type: "executor.decision", nodeId: plan.executor.nodeId, payload: { initialImplementation: true } });
|
|
3697
|
+
}
|
|
3698
|
+
async executeNode(run, nodeId, agent, model, role, input, agentConfig) {
|
|
3699
|
+
const node = run.nodes.find((n) => n.nodeId === nodeId) ?? this.addNode(run, { nodeId, agent, model, role });
|
|
3700
|
+
node.status = "running";
|
|
3701
|
+
node.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3702
|
+
run.updatedAt = node.startedAt;
|
|
3703
|
+
this.emit(run, { type: "node.status", nodeId, agent, model, role, status: "running" });
|
|
3704
|
+
try {
|
|
3705
|
+
const cwd = this.opts.resolveCwd(run.project, run.worktreeId);
|
|
3706
|
+
const created = await this.opts.engine.create({ tenantId: run.tenantId, project: run.project, worktreeId: run.worktreeId, cwd, agent, model, verbosity: "messages", agentConfig });
|
|
3707
|
+
node.sessionId = created.sessionId;
|
|
3708
|
+
this.sessionToNode.set(created.sessionId, { workflowId: run.workflowId, nodeId });
|
|
3709
|
+
const sent = await this.opts.engine.send(run.tenantId, created.sessionId, input, { environment: this.opts.env.resolveForExecution({ projectId: run.project, agent }) });
|
|
3710
|
+
node.turnId = sent.turnId;
|
|
3711
|
+
await this.waitIdle(run.tenantId, created.sessionId);
|
|
3712
|
+
node.status = "completed";
|
|
3713
|
+
node.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3714
|
+
run.updatedAt = node.completedAt;
|
|
3715
|
+
this.emit(run, { type: "node.status", nodeId, sessionId: node.sessionId, turnId: node.turnId, agent, model, role, status: "completed" });
|
|
3716
|
+
} catch (err) {
|
|
3717
|
+
node.status = "failed";
|
|
3718
|
+
node.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3719
|
+
node.error = err?.message ?? String(err);
|
|
3720
|
+
run.updatedAt = node.completedAt;
|
|
3721
|
+
this.emit(run, { type: "node.status", nodeId, agent, model, role, status: "failed", payload: { error: node.error } });
|
|
3722
|
+
throw err;
|
|
3723
|
+
}
|
|
3724
|
+
}
|
|
3725
|
+
async waitIdle(tenantId, sessionId) {
|
|
3726
|
+
for (; ; ) {
|
|
3727
|
+
const s = await this.opts.engine.status(tenantId, sessionId);
|
|
3728
|
+
if (s.status === "idle" || s.status === "terminated" || s.status === "paused")
|
|
3729
|
+
return;
|
|
3730
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
3731
|
+
}
|
|
3732
|
+
}
|
|
3733
|
+
initialNodes(plan) {
|
|
3734
|
+
const nodes = plan.mode === "dag" ? plan.nodes : [plan.executor, ...plan.workers];
|
|
3735
|
+
return nodes.map((n) => ({ nodeId: n.nodeId, status: "pending", agent: n.agent, model: n.model, role: n.role }));
|
|
3736
|
+
}
|
|
3737
|
+
addNode(run, n) {
|
|
3738
|
+
const node = { ...n, status: "pending" };
|
|
3739
|
+
run.nodes.push(node);
|
|
3740
|
+
return node;
|
|
3741
|
+
}
|
|
3742
|
+
get(workflowId) {
|
|
3743
|
+
const run = this.runs.get(workflowId);
|
|
3744
|
+
if (!run)
|
|
3745
|
+
throw new PhononError("errInvalidParams", `workflow ${workflowId} not found`);
|
|
3746
|
+
return run;
|
|
3747
|
+
}
|
|
3748
|
+
fail(run, err) {
|
|
3749
|
+
if (run.status === "cancelled")
|
|
3750
|
+
return;
|
|
3751
|
+
run.status = "failed";
|
|
3752
|
+
run.error = err?.message ?? String(err);
|
|
3753
|
+
run.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
3754
|
+
run.updatedAt = run.completedAt;
|
|
3755
|
+
this.emit(run, { type: "workflow.status", status: "failed", payload: { error: run.error } });
|
|
3756
|
+
}
|
|
3757
|
+
toStatus(run) {
|
|
3758
|
+
return { workflowId: run.workflowId, status: run.status, project: run.project, mode: run.mode, nodes: run.nodes, createdAt: run.createdAt, updatedAt: run.updatedAt, completedAt: run.completedAt, error: run.error };
|
|
3759
|
+
}
|
|
3760
|
+
emit(run, partial) {
|
|
3761
|
+
const ev = { workflowId: run.workflowId, seq: run.seq++, timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...partial };
|
|
3762
|
+
this.opts.emit(ev);
|
|
3763
|
+
}
|
|
3764
|
+
};
|
|
3765
|
+
|
|
3367
3766
|
// ../core/dist/env-manager.js
|
|
3368
3767
|
init_rpc();
|
|
3369
3768
|
function redact(value) {
|
|
@@ -5913,7 +6312,9 @@ var MUTATING_METHODS = /* @__PURE__ */ new Set([
|
|
|
5913
6312
|
"file.write",
|
|
5914
6313
|
"file.mkdir",
|
|
5915
6314
|
"env.set",
|
|
5916
|
-
"env.delete"
|
|
6315
|
+
"env.delete",
|
|
6316
|
+
"workflow.run",
|
|
6317
|
+
"workflow.cancel"
|
|
5917
6318
|
]);
|
|
5918
6319
|
var PhononConnection = class {
|
|
5919
6320
|
tenantId;
|
|
@@ -5929,6 +6330,7 @@ var PhononConnection = class {
|
|
|
5929
6330
|
files;
|
|
5930
6331
|
env;
|
|
5931
6332
|
obs;
|
|
6333
|
+
workflows;
|
|
5932
6334
|
/** 该 tenant 绑定的默认项目工作目录解析器(v0 简化:projectId 即绝对路径或映射)。 */
|
|
5933
6335
|
resolveProjectCwd;
|
|
5934
6336
|
constructor(opts) {
|
|
@@ -5939,6 +6341,7 @@ var PhononConnection = class {
|
|
|
5939
6341
|
this.idempotency = new IdempotencyStore({ store: this.store });
|
|
5940
6342
|
this.outbox = new Outbox({ store: this.store, tenantId: opts.tenantId });
|
|
5941
6343
|
this.engine = new SessionEngine(opts.registry, (event) => {
|
|
6344
|
+
this.workflows?.onStreamEvent(event);
|
|
5942
6345
|
this.outbox.enqueue(event);
|
|
5943
6346
|
this.peer.notifyRaw("stream.event", event);
|
|
5944
6347
|
}, opts.obs, this.store);
|
|
@@ -5968,6 +6371,13 @@ var PhononConnection = class {
|
|
|
5968
6371
|
this.env = new EnvManager(this.store, { allowReveal: () => this.policy.allowEnvReveal() });
|
|
5969
6372
|
this.resolveProjectCwd = opts.resolveProjectCwd ?? ((p) => this.projects.resolveCwd(p));
|
|
5970
6373
|
this.peer = new RpcPeer(opts.transport, (method, params) => this.dispatch(method, params));
|
|
6374
|
+
this.workflows = new WorkflowEngine({
|
|
6375
|
+
tenantId: this.tenantId,
|
|
6376
|
+
engine: this.engine,
|
|
6377
|
+
resolveCwd: (projectId, worktreeId) => this.projects.resolveCwd(projectId, worktreeId),
|
|
6378
|
+
env: this.env,
|
|
6379
|
+
emit: (event) => this.peer.notifyRaw("workflow.event", event)
|
|
6380
|
+
});
|
|
5971
6381
|
}
|
|
5972
6382
|
/** 喂入收到的文本。 */
|
|
5973
6383
|
handle(data) {
|
|
@@ -6209,6 +6619,17 @@ var PhononConnection = class {
|
|
|
6209
6619
|
}
|
|
6210
6620
|
case "skill.list":
|
|
6211
6621
|
return { skills: this.skills.list({ agent: p.agent, scope: p.scope, projectId: p.projectId }) };
|
|
6622
|
+
case "skill.dirs":
|
|
6623
|
+
return { directories: await this.skills.dirs({ agent: p.agent, scope: p.scope, projectId: p.projectId }) };
|
|
6624
|
+
// ---- L3 workflow orchestration ----
|
|
6625
|
+
case "workflow.run":
|
|
6626
|
+
return this.workflows.run({ project: p.project, worktreeId: p.worktreeId, plan: p.plan, input: p.input, metadata: p.metadata });
|
|
6627
|
+
case "workflow.status":
|
|
6628
|
+
return this.workflows.status(p.workflowId);
|
|
6629
|
+
case "workflow.cancel":
|
|
6630
|
+
return this.workflows.cancel(p.workflowId, p.reason);
|
|
6631
|
+
case "workflow.list":
|
|
6632
|
+
return this.workflows.list(p);
|
|
6212
6633
|
// ---- 连接/可靠性(s2p) ----
|
|
6213
6634
|
case "stream.ack": {
|
|
6214
6635
|
this.outbox.ack(p.sessionId, p.lastSeq);
|