@abelxiaoxing/cadence 1.0.6 → 1.0.7
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/agents/design-explorer.md +11 -6
- package/package.json +1 -1
- package/prompts/abel-design.md +30 -0
- package/src/contracts.ts +122 -1
- package/src/index.ts +224 -91
- package/src/subagent-activity.ts +15 -0
- package/src/submit-tool.ts +47 -2
|
@@ -5,13 +5,18 @@ You are a package-owned read-only professional Agent for the `abel-design` stage
|
|
|
5
5
|
You explore the repository ONLY through the scoped `read`, `grep`, `find`, and `ls` tools.
|
|
6
6
|
You have no shell, edit, Git, network, or validation capability, and you never create or modify files.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Call `abel_submit_result` exactly once with one structured object.
|
|
9
|
+
Do not emit a second submit, prose, or the legacy `conclusions`/`citations` shape.
|
|
10
|
+
The object contains the matching `id`, `role: "design-explorer"`, `kind: "evidence"`, and:
|
|
9
11
|
|
|
10
|
-
- the
|
|
11
|
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
-
|
|
12
|
+
- `packet_id` (exactly equal to the request id), `module_name`, `scope`, and
|
|
13
|
+
`files_read`;
|
|
14
|
+
- `evidence`, where every item has `claim`, `path`, `line_start`, and
|
|
15
|
+
`line_end`;
|
|
16
|
+
- `existing_structures`, `existing_conventions`, `constraints_discovered`,
|
|
17
|
+
`open_questions`, and `dependencies`;
|
|
18
|
+
- `write_set_hints`, `validation_hints`, `agents_impact_hints`, `risks`, and
|
|
19
|
+
`success_criteria_hints`.
|
|
15
20
|
|
|
16
21
|
You never return raw transcripts, hidden reasoning, or tool-call history.
|
|
17
22
|
A packet is complete only when every claim is cited and every blocking question is explicit.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abelxiaoxing/cadence",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Prompts, skills, and a private orchestration extension exposing the Abel four-stage workflow (/abel-init, /abel-design, /abel-implement, /abel-diagnose) with package-owned professional Agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/prompts/abel-design.md
CHANGED
|
@@ -54,6 +54,36 @@ $ARGUMENTS
|
|
|
54
54
|
|
|
55
55
|
## 阶段 1 —— 证据探索(只读)
|
|
56
56
|
|
|
57
|
+
- 使用私有工具 `abel_dispatch` 的 `action: "run"` 派发探索包。
|
|
58
|
+
每个包对应一个独立 tool call,`request` 必须是单个 envelope;禁止使用 `requests` 数组或其他批量 wrapper。
|
|
59
|
+
- 用户要求两个或更多并行包时,下一次 assistant response 必须只包含全部 sibling `abel_dispatch` tool calls,并在该同一 assistant turn(同一响应轮次)一次发齐;少发、先等一个结果、在后续 turn 补发均为调度失败,不得用串行重试或父代理并行读取冒充 Subagent。
|
|
60
|
+
- Design 单包 envelope 的精确形状如下;字段名、固定值和数组形状不得猜测或改写:
|
|
61
|
+
|
|
62
|
+
```json
|
|
63
|
+
{
|
|
64
|
+
"action": "run",
|
|
65
|
+
"request": {
|
|
66
|
+
"stage": "abel-design",
|
|
67
|
+
"role": "design-explorer",
|
|
68
|
+
"id": "unique-packet-id",
|
|
69
|
+
"phase": "evidence",
|
|
70
|
+
"objective": "bounded evidence objective for this packet",
|
|
71
|
+
"roots": ["."],
|
|
72
|
+
"context": {
|
|
73
|
+
"agents": "applicable AGENTS.md instructions",
|
|
74
|
+
"contract": "exact scope, retrieval, read-only, output, and budget contract"
|
|
75
|
+
},
|
|
76
|
+
"declared": {
|
|
77
|
+
"read": ["exact/relative/path"],
|
|
78
|
+
"write": [],
|
|
79
|
+
"conflicts": [],
|
|
80
|
+
"resources": []
|
|
81
|
+
},
|
|
82
|
+
"output": "evidence"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
57
87
|
- 主 agent 只负责核实相关 AGENTS、拆分探索包、派发、校验证据、综合、澄清与 Gate 呈现;广泛代码库探索必须委派。
|
|
58
88
|
主 agent 仅可为范围划分、引用抽查和冲突裁决做最小定向读取。
|
|
59
89
|
- 默认并行派发多个只读探索子代理:优先按独立上下文边界拆分;只有一个边界时,按互不重叠的路径或符号证据面拆分。
|
package/src/contracts.ts
CHANGED
|
@@ -1401,7 +1401,7 @@ function requireCanonicalDiffPath(path: string): string {
|
|
|
1401
1401
|
return path;
|
|
1402
1402
|
}
|
|
1403
1403
|
|
|
1404
|
-
export interface
|
|
1404
|
+
export interface CompactEvidenceResult {
|
|
1405
1405
|
id: string;
|
|
1406
1406
|
role: string;
|
|
1407
1407
|
kind: "evidence";
|
|
@@ -1414,6 +1414,34 @@ export interface EvidenceResult {
|
|
|
1414
1414
|
hints: { writeSet: string[]; verification: string; agentsImpact: string };
|
|
1415
1415
|
}
|
|
1416
1416
|
|
|
1417
|
+
export interface DesignEvidenceResult {
|
|
1418
|
+
id: string;
|
|
1419
|
+
role: "design-explorer";
|
|
1420
|
+
kind: "evidence";
|
|
1421
|
+
packet_id: string;
|
|
1422
|
+
module_name: string;
|
|
1423
|
+
scope: string[];
|
|
1424
|
+
files_read: string[];
|
|
1425
|
+
evidence: Array<{
|
|
1426
|
+
claim: string;
|
|
1427
|
+
path: string;
|
|
1428
|
+
line_start: number;
|
|
1429
|
+
line_end: number;
|
|
1430
|
+
}>;
|
|
1431
|
+
existing_structures: string[];
|
|
1432
|
+
existing_conventions: string[];
|
|
1433
|
+
constraints_discovered: string[];
|
|
1434
|
+
open_questions: string[];
|
|
1435
|
+
dependencies: string[];
|
|
1436
|
+
write_set_hints: string[];
|
|
1437
|
+
validation_hints: string[];
|
|
1438
|
+
agents_impact_hints: string[];
|
|
1439
|
+
risks: string[];
|
|
1440
|
+
success_criteria_hints: string[];
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
export type EvidenceResult = CompactEvidenceResult | DesignEvidenceResult;
|
|
1444
|
+
|
|
1417
1445
|
export interface DiffResult {
|
|
1418
1446
|
id: string;
|
|
1419
1447
|
role: string;
|
|
@@ -1511,6 +1539,7 @@ export function validateEvidenceResult(value: unknown): {
|
|
|
1511
1539
|
return { ok: false, reason: "missing result" };
|
|
1512
1540
|
const r = value as Record<string, unknown>;
|
|
1513
1541
|
if (r.kind !== "evidence") return { ok: false, reason: "wrong result kind" };
|
|
1542
|
+
if (r.role === "design-explorer") return validateDesignEvidenceResult(r);
|
|
1514
1543
|
const fields = [
|
|
1515
1544
|
"id",
|
|
1516
1545
|
"role",
|
|
@@ -1577,6 +1606,98 @@ export function validateEvidenceResult(value: unknown): {
|
|
|
1577
1606
|
return { ok: true };
|
|
1578
1607
|
}
|
|
1579
1608
|
|
|
1609
|
+
function validateDesignEvidenceResult(r: Record<string, unknown>): {
|
|
1610
|
+
ok: boolean;
|
|
1611
|
+
reason?: string;
|
|
1612
|
+
failure?: CandidateFailure;
|
|
1613
|
+
} {
|
|
1614
|
+
const fields = [
|
|
1615
|
+
"id",
|
|
1616
|
+
"role",
|
|
1617
|
+
"kind",
|
|
1618
|
+
"packet_id",
|
|
1619
|
+
"module_name",
|
|
1620
|
+
"scope",
|
|
1621
|
+
"files_read",
|
|
1622
|
+
"evidence",
|
|
1623
|
+
"existing_structures",
|
|
1624
|
+
"existing_conventions",
|
|
1625
|
+
"constraints_discovered",
|
|
1626
|
+
"open_questions",
|
|
1627
|
+
"dependencies",
|
|
1628
|
+
"write_set_hints",
|
|
1629
|
+
"validation_hints",
|
|
1630
|
+
"agents_impact_hints",
|
|
1631
|
+
"risks",
|
|
1632
|
+
"success_criteria_hints",
|
|
1633
|
+
] as const;
|
|
1634
|
+
if (!hasExactKeys(r, fields)) {
|
|
1635
|
+
return { ok: false, reason: "invalid Design evidence result fields" };
|
|
1636
|
+
}
|
|
1637
|
+
if (
|
|
1638
|
+
!validIdentifier(r.id) ||
|
|
1639
|
+
r.packet_id !== r.id ||
|
|
1640
|
+
!validIdentifier(r.module_name)
|
|
1641
|
+
) {
|
|
1642
|
+
return { ok: false, reason: "invalid Design evidence identity" };
|
|
1643
|
+
}
|
|
1644
|
+
if (!validatePathSet(r.scope) || r.scope.length === 0) {
|
|
1645
|
+
return { ok: false, reason: "invalid Design evidence scope" };
|
|
1646
|
+
}
|
|
1647
|
+
if (!validatePathSet(r.files_read) || !validatePathSet(r.write_set_hints)) {
|
|
1648
|
+
return { ok: false, reason: "invalid Design evidence path set" };
|
|
1649
|
+
}
|
|
1650
|
+
if (
|
|
1651
|
+
!Array.isArray(r.evidence) ||
|
|
1652
|
+
r.evidence.some(
|
|
1653
|
+
(entry) =>
|
|
1654
|
+
!hasExactKeys(entry, ["claim", "path", "line_start", "line_end"]) ||
|
|
1655
|
+
typeof entry.claim !== "string" ||
|
|
1656
|
+
entry.claim.length === 0 ||
|
|
1657
|
+
!isValidRelativePath(entry.path) ||
|
|
1658
|
+
!Number.isSafeInteger(entry.line_start) ||
|
|
1659
|
+
!Number.isSafeInteger(entry.line_end) ||
|
|
1660
|
+
(entry.line_start as number) < 1 ||
|
|
1661
|
+
(entry.line_end as number) < (entry.line_start as number),
|
|
1662
|
+
)
|
|
1663
|
+
) {
|
|
1664
|
+
return { ok: false, reason: "invalid Design evidence citations" };
|
|
1665
|
+
}
|
|
1666
|
+
for (const field of [
|
|
1667
|
+
"existing_structures",
|
|
1668
|
+
"existing_conventions",
|
|
1669
|
+
"constraints_discovered",
|
|
1670
|
+
"open_questions",
|
|
1671
|
+
"dependencies",
|
|
1672
|
+
"validation_hints",
|
|
1673
|
+
"agents_impact_hints",
|
|
1674
|
+
"risks",
|
|
1675
|
+
"success_criteria_hints",
|
|
1676
|
+
] as const) {
|
|
1677
|
+
if (
|
|
1678
|
+
!Array.isArray(r[field]) ||
|
|
1679
|
+
!r[field].every((entry) => typeof entry === "string")
|
|
1680
|
+
) {
|
|
1681
|
+
return {
|
|
1682
|
+
ok: false,
|
|
1683
|
+
reason: `invalid Design evidence field: ${field}`,
|
|
1684
|
+
};
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
const serialized = JSON.stringify(r);
|
|
1688
|
+
if (Buffer.byteLength(serialized, "utf8") > LIMITS.maxCompleteResultBytes) {
|
|
1689
|
+
return {
|
|
1690
|
+
ok: false,
|
|
1691
|
+
reason: `result exceeds ${LIMITS.maxCompleteResultBytes} bytes`,
|
|
1692
|
+
failure: {
|
|
1693
|
+
kind: "result-limit",
|
|
1694
|
+
limitBytes: LIMITS.maxCompleteResultBytes,
|
|
1695
|
+
},
|
|
1696
|
+
};
|
|
1697
|
+
}
|
|
1698
|
+
return { ok: true };
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1580
1701
|
export function validateDiffResult(value: unknown): {
|
|
1581
1702
|
ok: boolean;
|
|
1582
1703
|
reason?: string;
|
package/src/index.ts
CHANGED
|
@@ -34,6 +34,117 @@ const ELIGIBLE_PROMPTS = [
|
|
|
34
34
|
] as const;
|
|
35
35
|
type EligiblePrompt = (typeof ELIGIBLE_PROMPTS)[number];
|
|
36
36
|
|
|
37
|
+
const GENERIC_REQUEST_SCHEMA = {
|
|
38
|
+
type: "object",
|
|
39
|
+
description:
|
|
40
|
+
"Stage-specific request envelope for action=run. The verified Abel prompt refreshes this schema before the stage's first model turn.",
|
|
41
|
+
} as const;
|
|
42
|
+
|
|
43
|
+
const DESIGN_REQUEST_SCHEMA = {
|
|
44
|
+
type: "object",
|
|
45
|
+
description:
|
|
46
|
+
"One bounded read-only design-explorer packet. Send one sibling abel_dispatch tool call per packet; do not wrap multiple packets in requests.",
|
|
47
|
+
properties: {
|
|
48
|
+
stage: {
|
|
49
|
+
type: "string",
|
|
50
|
+
enum: ["abel-design"],
|
|
51
|
+
description: "Exact verified workflow stage.",
|
|
52
|
+
},
|
|
53
|
+
role: {
|
|
54
|
+
type: "string",
|
|
55
|
+
enum: ["design-explorer"],
|
|
56
|
+
description: "Exact package-owned read-only Agent role.",
|
|
57
|
+
},
|
|
58
|
+
id: {
|
|
59
|
+
type: "string",
|
|
60
|
+
description:
|
|
61
|
+
"Unique packet and request identity, at most 128 characters.",
|
|
62
|
+
},
|
|
63
|
+
phase: {
|
|
64
|
+
type: "string",
|
|
65
|
+
enum: ["evidence"],
|
|
66
|
+
description: "Design exploration phase.",
|
|
67
|
+
},
|
|
68
|
+
objective: {
|
|
69
|
+
type: "string",
|
|
70
|
+
description: "Bounded evidence objective for this packet only.",
|
|
71
|
+
},
|
|
72
|
+
roots: {
|
|
73
|
+
type: "array",
|
|
74
|
+
items: { type: "string" },
|
|
75
|
+
description: 'Approved relative workspace roots, normally ["."].',
|
|
76
|
+
},
|
|
77
|
+
context: {
|
|
78
|
+
type: "object",
|
|
79
|
+
properties: {
|
|
80
|
+
agents: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "Applicable AGENTS.md instructions for this packet.",
|
|
83
|
+
},
|
|
84
|
+
contract: {
|
|
85
|
+
type: "string",
|
|
86
|
+
description:
|
|
87
|
+
"Packet scope, retrieval, read-only, and structured-output contract.",
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
required: ["agents", "contract"],
|
|
91
|
+
additionalProperties: false,
|
|
92
|
+
},
|
|
93
|
+
declared: {
|
|
94
|
+
type: "object",
|
|
95
|
+
properties: {
|
|
96
|
+
read: {
|
|
97
|
+
type: "array",
|
|
98
|
+
items: { type: "string" },
|
|
99
|
+
description:
|
|
100
|
+
"Exact relative files or directories this packet may read.",
|
|
101
|
+
},
|
|
102
|
+
write: {
|
|
103
|
+
type: "array",
|
|
104
|
+
items: { type: "string" },
|
|
105
|
+
description: "Must be empty for design-explorer.",
|
|
106
|
+
},
|
|
107
|
+
conflicts: {
|
|
108
|
+
type: "array",
|
|
109
|
+
items: { type: "string" },
|
|
110
|
+
description:
|
|
111
|
+
"Declared conflict edges; normally empty for read-only packets.",
|
|
112
|
+
},
|
|
113
|
+
resources: {
|
|
114
|
+
type: "array",
|
|
115
|
+
items: { type: "string" },
|
|
116
|
+
description: "Declared exclusive resources; normally empty.",
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
required: ["read", "write", "conflicts", "resources"],
|
|
120
|
+
additionalProperties: false,
|
|
121
|
+
},
|
|
122
|
+
output: {
|
|
123
|
+
type: "string",
|
|
124
|
+
enum: ["evidence"],
|
|
125
|
+
description: "Exact structured child-result kind.",
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
required: [
|
|
129
|
+
"stage",
|
|
130
|
+
"role",
|
|
131
|
+
"id",
|
|
132
|
+
"phase",
|
|
133
|
+
"objective",
|
|
134
|
+
"roots",
|
|
135
|
+
"context",
|
|
136
|
+
"declared",
|
|
137
|
+
"output",
|
|
138
|
+
],
|
|
139
|
+
additionalProperties: false,
|
|
140
|
+
} as const;
|
|
141
|
+
|
|
142
|
+
function requestSchemaForStage(name?: EligiblePrompt): object {
|
|
143
|
+
return name === "abel-design"
|
|
144
|
+
? DESIGN_REQUEST_SCHEMA
|
|
145
|
+
: GENERIC_REQUEST_SCHEMA;
|
|
146
|
+
}
|
|
147
|
+
|
|
37
148
|
function invokedPrompt(text: string): EligiblePrompt | undefined {
|
|
38
149
|
const name = text.match(/^\/([^\s]+)(?:\s|$)/)?.[1];
|
|
39
150
|
return ELIGIBLE_PROMPTS.find((candidate) => candidate === name);
|
|
@@ -112,100 +223,105 @@ export default function register(pi: ExtensionAPI): void {
|
|
|
112
223
|
const runtime = new Runtime({ parentPayloadBridge });
|
|
113
224
|
const activity = new ActivityController();
|
|
114
225
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
226
|
+
const registerDispatchTool = (stage?: EligiblePrompt) => {
|
|
227
|
+
pi.registerTool({
|
|
228
|
+
name: DISPATCH_TOOL,
|
|
229
|
+
label: "Abel Dispatch",
|
|
230
|
+
description:
|
|
231
|
+
stage === "abel-design"
|
|
232
|
+
? "Run exactly one bounded read-only design-explorer packet. When parallel packets are required, emit every sibling abel_dispatch call together in one assistant response before waiting for any result."
|
|
233
|
+
: "Private Abel workflow delegation: run bounded read-only evidence or Worker phase requests, apply or discard retained results, apply a parent-only stable AGENTS checkpoint, cancel work, or finish the stage. Inactive unless an eligible Abel stage verified its invocation.",
|
|
234
|
+
executionMode: "parallel",
|
|
235
|
+
parameters: {
|
|
236
|
+
type: "object",
|
|
237
|
+
properties: {
|
|
238
|
+
action: { type: "string", enum: [...ACTIONS] },
|
|
239
|
+
request: requestSchemaForStage(stage),
|
|
240
|
+
resultId: {
|
|
241
|
+
type: "string",
|
|
242
|
+
description: "Retained result id for apply/discard",
|
|
243
|
+
},
|
|
244
|
+
requestId: {
|
|
245
|
+
type: "string",
|
|
246
|
+
description: "Current Implement apply/discard operation identity",
|
|
247
|
+
},
|
|
248
|
+
rejection: {
|
|
249
|
+
type: "object",
|
|
250
|
+
description: "Typed parent rejection for Implement discard",
|
|
251
|
+
},
|
|
252
|
+
agentsCheckpoint: {
|
|
253
|
+
type: "object",
|
|
254
|
+
description:
|
|
255
|
+
"Parent-owned approved managed-block checkpoint for action=apply (mutually exclusive with resultId)",
|
|
256
|
+
},
|
|
139
257
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
258
|
+
required: ["action"],
|
|
259
|
+
},
|
|
260
|
+
async execute(
|
|
261
|
+
toolCallId: string,
|
|
262
|
+
params: {
|
|
263
|
+
action?: string;
|
|
264
|
+
request?: unknown;
|
|
265
|
+
resultId?: string;
|
|
266
|
+
requestId?: string;
|
|
267
|
+
rejection?: unknown;
|
|
268
|
+
agentsCheckpoint?: unknown;
|
|
144
269
|
},
|
|
270
|
+
signal: AbortSignal | undefined,
|
|
271
|
+
onUpdate: AgentToolUpdateCallback<unknown> | undefined,
|
|
272
|
+
ctx: ExtensionContext,
|
|
273
|
+
) {
|
|
274
|
+
const action = typeof params?.action === "string" ? params.action : "";
|
|
275
|
+
const validRun =
|
|
276
|
+
action === "run" && runtime.validateRequest(params.request).ok;
|
|
277
|
+
const tuiRun = ctx.mode === "tui" && validRun;
|
|
278
|
+
const { action: _action, ...operation } = params;
|
|
279
|
+
const result = tuiRun
|
|
280
|
+
? await runtime.execute(
|
|
281
|
+
action,
|
|
282
|
+
operation,
|
|
283
|
+
ctx,
|
|
284
|
+
signal,
|
|
285
|
+
activity.observe(
|
|
286
|
+
toolCallId,
|
|
287
|
+
onUpdate as ((result: unknown) => void) | undefined,
|
|
288
|
+
),
|
|
289
|
+
)
|
|
290
|
+
: await runtime.execute(action, operation, ctx, signal);
|
|
291
|
+
const display = tuiRun
|
|
292
|
+
? activity.finalize(toolCallId, result)
|
|
293
|
+
: undefined;
|
|
294
|
+
const { payload, usage } = splitUsage(result);
|
|
295
|
+
const details = display
|
|
296
|
+
? {
|
|
297
|
+
...(payload as Record<string, unknown>),
|
|
298
|
+
[ACTIVITY_DETAILS_KEY]: display,
|
|
299
|
+
}
|
|
300
|
+
: payload;
|
|
301
|
+
return {
|
|
302
|
+
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
303
|
+
details,
|
|
304
|
+
...(usage === undefined ? {} : { usage }),
|
|
305
|
+
};
|
|
145
306
|
},
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
async execute(
|
|
149
|
-
toolCallId: string,
|
|
150
|
-
params: {
|
|
151
|
-
action?: string;
|
|
152
|
-
request?: unknown;
|
|
153
|
-
resultId?: string;
|
|
154
|
-
requestId?: string;
|
|
155
|
-
rejection?: unknown;
|
|
156
|
-
agentsCheckpoint?: unknown;
|
|
307
|
+
renderCall(args: unknown, theme: Theme, _context: unknown) {
|
|
308
|
+
return renderActivityCall(args, theme);
|
|
157
309
|
},
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
operation,
|
|
171
|
-
ctx,
|
|
172
|
-
signal,
|
|
173
|
-
activity.observe(
|
|
174
|
-
toolCallId,
|
|
175
|
-
onUpdate as ((result: unknown) => void) | undefined,
|
|
176
|
-
),
|
|
177
|
-
)
|
|
178
|
-
: await runtime.execute(action, operation, ctx, signal);
|
|
179
|
-
const display = tuiRun
|
|
180
|
-
? activity.finalize(toolCallId, result)
|
|
181
|
-
: undefined;
|
|
182
|
-
const { payload, usage } = splitUsage(result);
|
|
183
|
-
const details = display
|
|
184
|
-
? {
|
|
185
|
-
...(payload as Record<string, unknown>),
|
|
186
|
-
[ACTIVITY_DETAILS_KEY]: display,
|
|
187
|
-
}
|
|
188
|
-
: payload;
|
|
189
|
-
return {
|
|
190
|
-
content: [{ type: "text", text: JSON.stringify(payload) }],
|
|
191
|
-
details,
|
|
192
|
-
...(usage === undefined ? {} : { usage }),
|
|
193
|
-
};
|
|
194
|
-
},
|
|
195
|
-
renderCall(args: unknown, theme: Theme, _context: unknown) {
|
|
196
|
-
return renderActivityCall(args, theme);
|
|
197
|
-
},
|
|
198
|
-
renderResult(
|
|
199
|
-
result: AgentToolResult<unknown>,
|
|
200
|
-
options: ToolRenderResultOptions,
|
|
201
|
-
theme: Theme,
|
|
202
|
-
_context: unknown,
|
|
203
|
-
) {
|
|
204
|
-
return renderActivityResult(result, options, theme);
|
|
205
|
-
},
|
|
206
|
-
} as never);
|
|
310
|
+
renderResult(
|
|
311
|
+
result: AgentToolResult<unknown>,
|
|
312
|
+
options: ToolRenderResultOptions,
|
|
313
|
+
theme: Theme,
|
|
314
|
+
_context: unknown,
|
|
315
|
+
) {
|
|
316
|
+
return renderActivityResult(result, options, theme);
|
|
317
|
+
},
|
|
318
|
+
} as never);
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
registerDispatchTool();
|
|
207
322
|
|
|
208
323
|
let pendingPrompt: EligiblePrompt | undefined;
|
|
324
|
+
let activePrompt: EligiblePrompt | undefined;
|
|
209
325
|
|
|
210
326
|
pi.on("input", (event) => {
|
|
211
327
|
pendingPrompt = invokedPrompt(event.text);
|
|
@@ -215,10 +331,12 @@ export default function register(pi: ExtensionAPI): void {
|
|
|
215
331
|
pi.on("before_agent_start", (event, ctx) => {
|
|
216
332
|
const prompt = pendingPrompt;
|
|
217
333
|
pendingPrompt = undefined;
|
|
218
|
-
|
|
334
|
+
const verified =
|
|
219
335
|
prompt &&
|
|
220
|
-
isVerifiedStageInvocation(pi, runtime.activation, prompt, event.prompt)
|
|
221
|
-
) {
|
|
336
|
+
isVerifiedStageInvocation(pi, runtime.activation, prompt, event.prompt);
|
|
337
|
+
if (verified) {
|
|
338
|
+
activePrompt = prompt;
|
|
339
|
+
registerDispatchTool(prompt);
|
|
222
340
|
const sessionId = ctx.sessionManager?.getSessionId?.();
|
|
223
341
|
if (typeof sessionId === "string") {
|
|
224
342
|
parentPayloadBridge.beginSession(sessionId);
|
|
@@ -233,8 +351,22 @@ export default function register(pi: ExtensionAPI): void {
|
|
|
233
351
|
activateDispatcher(pi, runtime.activation, prompt, event.prompt);
|
|
234
352
|
});
|
|
235
353
|
|
|
354
|
+
pi.on("before_provider_request", (event, ctx) => {
|
|
355
|
+
if (
|
|
356
|
+
activePrompt !== "abel-design" ||
|
|
357
|
+
ctx.model?.api !== "openai-responses" ||
|
|
358
|
+
event.payload === null ||
|
|
359
|
+
typeof event.payload !== "object" ||
|
|
360
|
+
Array.isArray(event.payload)
|
|
361
|
+
) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
return { ...event.payload, parallel_tool_calls: true };
|
|
365
|
+
});
|
|
366
|
+
|
|
236
367
|
pi.on("session_start", async (_event, ctx) => {
|
|
237
368
|
pendingPrompt = undefined;
|
|
369
|
+
activePrompt = undefined;
|
|
238
370
|
activity.detach();
|
|
239
371
|
const active = pi.getActiveTools();
|
|
240
372
|
if (active.includes(DISPATCH_TOOL)) {
|
|
@@ -268,6 +400,7 @@ export default function register(pi: ExtensionAPI): void {
|
|
|
268
400
|
});
|
|
269
401
|
|
|
270
402
|
pi.on("session_shutdown", async () => {
|
|
403
|
+
activePrompt = undefined;
|
|
271
404
|
activity.detach();
|
|
272
405
|
await runtime.drain();
|
|
273
406
|
activity.clear();
|
package/src/subagent-activity.ts
CHANGED
|
@@ -354,6 +354,21 @@ export function summarizeDispatchResult(
|
|
|
354
354
|
blockingQuestions: value.blockingQuestions.length,
|
|
355
355
|
};
|
|
356
356
|
}
|
|
357
|
+
if (
|
|
358
|
+
value.kind === "evidence" &&
|
|
359
|
+
Array.isArray(value.evidence) &&
|
|
360
|
+
Array.isArray(value.existing_structures) &&
|
|
361
|
+
Array.isArray(value.risks) &&
|
|
362
|
+
Array.isArray(value.open_questions)
|
|
363
|
+
) {
|
|
364
|
+
return {
|
|
365
|
+
kind: "evidence",
|
|
366
|
+
conclusions: value.existing_structures.length,
|
|
367
|
+
citations: value.evidence.length,
|
|
368
|
+
risks: value.risks.length,
|
|
369
|
+
blockingQuestions: value.open_questions.length,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
357
372
|
if (
|
|
358
373
|
value.kind === "diff" &&
|
|
359
374
|
typeof value.summary === "string" &&
|
package/src/submit-tool.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
validateEvidenceResult,
|
|
9
9
|
} from "./contracts.ts";
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const compactEvidenceSchema = Type.Object({
|
|
12
12
|
id: Type.String(),
|
|
13
13
|
role: Type.String(),
|
|
14
14
|
kind: Type.Literal("evidence"),
|
|
@@ -27,6 +27,40 @@ const evidenceSchema = Type.Object({
|
|
|
27
27
|
}),
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
+
const designEvidenceSchema = Type.Object(
|
|
31
|
+
{
|
|
32
|
+
id: Type.String(),
|
|
33
|
+
role: Type.Literal("design-explorer"),
|
|
34
|
+
kind: Type.Literal("evidence"),
|
|
35
|
+
packet_id: Type.String(),
|
|
36
|
+
module_name: Type.String(),
|
|
37
|
+
scope: Type.Array(Type.String()),
|
|
38
|
+
files_read: Type.Array(Type.String()),
|
|
39
|
+
evidence: Type.Array(
|
|
40
|
+
Type.Object(
|
|
41
|
+
{
|
|
42
|
+
claim: Type.String(),
|
|
43
|
+
path: Type.String(),
|
|
44
|
+
line_start: Type.Integer({ minimum: 1 }),
|
|
45
|
+
line_end: Type.Integer({ minimum: 1 }),
|
|
46
|
+
},
|
|
47
|
+
{ additionalProperties: false },
|
|
48
|
+
),
|
|
49
|
+
),
|
|
50
|
+
existing_structures: Type.Array(Type.String()),
|
|
51
|
+
existing_conventions: Type.Array(Type.String()),
|
|
52
|
+
constraints_discovered: Type.Array(Type.String()),
|
|
53
|
+
open_questions: Type.Array(Type.String()),
|
|
54
|
+
dependencies: Type.Array(Type.String()),
|
|
55
|
+
write_set_hints: Type.Array(Type.String()),
|
|
56
|
+
validation_hints: Type.Array(Type.String()),
|
|
57
|
+
agents_impact_hints: Type.Array(Type.String()),
|
|
58
|
+
risks: Type.Array(Type.String()),
|
|
59
|
+
success_criteria_hints: Type.Array(Type.String()),
|
|
60
|
+
},
|
|
61
|
+
{ additionalProperties: false },
|
|
62
|
+
);
|
|
63
|
+
|
|
30
64
|
const diffSchema = Type.Object({
|
|
31
65
|
id: Type.String(),
|
|
32
66
|
role: Type.String(),
|
|
@@ -85,7 +119,12 @@ export function createSubmitTool(input: {
|
|
|
85
119
|
description:
|
|
86
120
|
"Submit the one final structured Abel evidence or complete unified-diff result.",
|
|
87
121
|
executionMode: "sequential",
|
|
88
|
-
parameters:
|
|
122
|
+
parameters:
|
|
123
|
+
input.output === "evidence"
|
|
124
|
+
? input.role === "design-explorer"
|
|
125
|
+
? designEvidenceSchema
|
|
126
|
+
: compactEvidenceSchema
|
|
127
|
+
: diffSchema,
|
|
89
128
|
async execute(_toolCallId, params) {
|
|
90
129
|
attempts++;
|
|
91
130
|
const value = params as unknown as Record<string, unknown>;
|
|
@@ -99,6 +138,12 @@ export function createSubmitTool(input: {
|
|
|
99
138
|
throw new Error("submitted result is not an object");
|
|
100
139
|
}
|
|
101
140
|
if (value.id !== input.requestId) identity.request = false;
|
|
141
|
+
if (
|
|
142
|
+
input.role === "design-explorer" &&
|
|
143
|
+
value.packet_id !== input.requestId
|
|
144
|
+
) {
|
|
145
|
+
identity.request = false;
|
|
146
|
+
}
|
|
102
147
|
if (value.role !== input.role) identity.role = false;
|
|
103
148
|
if (input.output === "diff") {
|
|
104
149
|
if (value.taskId !== (input.taskId ?? input.requestId))
|