@trim21/personal-pi-extensions 0.1.678 → 0.1.679
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/README.md +10 -4
- package/package.json +1 -1
- package/src/codemode/declarations.ts +28 -12
- package/src/codemode/prelude.ts +32 -16
- package/src/codemode/protocol.ts +5 -2
- package/src/codemode/tool.ts +10 -3
- package/src/codemode/worker.js +36 -29
- package/src/codemode/worker.ts +2 -10
- package/src/gh/base.ts +62 -12
- package/src/gh/schemas.ts +230 -0
- package/src/gh/tools/download-release-assets.ts +51 -44
- package/src/gh/tools/get-workflow-jobs.ts +29 -18
- package/src/gh/tools/read-ci-logs.ts +37 -23
- package/src/gh/tools/read-issue-comments.ts +31 -24
- package/src/gh/tools/read-issue.ts +30 -22
- package/src/gh/tools/read-pr-comments.ts +62 -58
- package/src/gh/tools/read-pr-status.ts +31 -20
- package/src/gh/tools/read-pr.ts +30 -22
- package/src/gh/tools/wait-commit-checks.ts +35 -31
- package/src/gh/tools/wait-pr-checks.ts +30 -23
- package/src/lib/tool-bus.ts +128 -8
package/src/lib/tool-bus.ts
CHANGED
|
@@ -7,6 +7,15 @@
|
|
|
7
7
|
* - `executeTool`:先用工具自身的参数 schema 校验参数,再调用定义的 `execute`;
|
|
8
8
|
* 参数校验失败与工具抛出的异常都归一化成错误结果返回,不向调用方抛异常。
|
|
9
9
|
*
|
|
10
|
+
* 结构化结果:工具可以在定义上声明 `structuredSchema`(TypeBox),并在结果里带
|
|
11
|
+
* `structuredResult: StructuredResult<Static<typeof structuredSchema>>`。成功支的载荷类型
|
|
12
|
+
* 由 schema 在编译期约束,执行时再由总线 `Value.Parse` 复核;`ok: false` 让工具不必抛异常
|
|
13
|
+
* 也能结构化地报告失败(它不改变结果的 `isError`)。
|
|
14
|
+
*
|
|
15
|
+
* 这两个名字是本仓库自己的约定,刻意不占用宿主字段:pi-agent-core >= 0.99 自带
|
|
16
|
+
* `outputSchema` / `structuredContent`,语义是「裸载荷 + 用 `isError` 表失败」,与本仓库的
|
|
17
|
+
* Result 信封不同,将来接宿主原生管线时需要显式换算。
|
|
18
|
+
*
|
|
10
19
|
* 状态由闭包持有(工厂 + 闭包),不使用模块级可变状态。
|
|
11
20
|
*/
|
|
12
21
|
|
|
@@ -20,8 +29,52 @@ import type { Static, TSchema } from "typebox";
|
|
|
20
29
|
|
|
21
30
|
import { parseWithSchema } from "./parse-with-schema.js";
|
|
22
31
|
|
|
32
|
+
/**
|
|
33
|
+
* 结构化结果:成功带 `value`,失败带可直接展示的错误说明。它只嵌在工具结果的
|
|
34
|
+
* `structuredResult` 一个属性里,结果对象本身保持单一类型(两个互斥字段会让整个
|
|
35
|
+
* 结果类型分配成对象联合)。
|
|
36
|
+
*/
|
|
37
|
+
export type StructuredResult<T> = { ok: true; value: T } | { ok: false; error: string };
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* 声明了输出结构的工具定义:`structuredResult` 成功支的载荷类型由 `structuredSchema` 在编译
|
|
41
|
+
* 期绑定,因此工具无法返回与声明不符的结果。
|
|
42
|
+
*/
|
|
43
|
+
export interface StructuredToolDefinition<
|
|
44
|
+
TParams extends TSchema = TSchema,
|
|
45
|
+
TOutput extends TSchema = TSchema,
|
|
46
|
+
TDetails = unknown,
|
|
47
|
+
> extends Omit<ToolDefinition<TParams, TDetails, unknown>, "execute"> {
|
|
48
|
+
structuredSchema: TOutput;
|
|
49
|
+
execute(
|
|
50
|
+
toolCallId: string,
|
|
51
|
+
params: Static<TParams>,
|
|
52
|
+
signal: AbortSignal | undefined,
|
|
53
|
+
onUpdate: AgentToolUpdateCallback<TDetails> | undefined,
|
|
54
|
+
ctx: ExtensionContext,
|
|
55
|
+
): Promise<AgentToolResult<TDetails> & { structuredResult: StructuredResult<Static<TOutput>> }>;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 结构化工具必须经它定义:`structuredSchema` 与 `execute` 返回类型之间的绑定只有在
|
|
60
|
+
* generic 函数的参数位置才建立得起来(与 pi 的 `defineTool` 同理)。
|
|
61
|
+
*/
|
|
62
|
+
export function defineStructuredTool<
|
|
63
|
+
TParams extends TSchema,
|
|
64
|
+
TOutput extends TSchema,
|
|
65
|
+
TDetails = unknown,
|
|
66
|
+
>(
|
|
67
|
+
definition: StructuredToolDefinition<TParams, TOutput, TDetails>,
|
|
68
|
+
): StructuredToolDefinition<TParams, TOutput, TDetails> {
|
|
69
|
+
return definition;
|
|
70
|
+
}
|
|
71
|
+
|
|
23
72
|
/** 一次工具执行的结果:`isError` 标出失败(工具不存在、参数不合法、工具抛错)。 */
|
|
24
|
-
export type ToolExecutionResult = AgentToolResult<unknown> & {
|
|
73
|
+
export type ToolExecutionResult = AgentToolResult<unknown> & {
|
|
74
|
+
isError: boolean;
|
|
75
|
+
/** 工具声明的结构化结果,原样交给 codemode 脚本。 */
|
|
76
|
+
structuredResult?: StructuredResult<unknown>;
|
|
77
|
+
};
|
|
25
78
|
|
|
26
79
|
export interface ExecuteToolOptions {
|
|
27
80
|
/** 工具 `execute` 需要的宿主上下文:调用方把自己拿到的那个 ctx 传进来。 */
|
|
@@ -32,16 +85,21 @@ export interface ExecuteToolOptions {
|
|
|
32
85
|
toolCallId?: string;
|
|
33
86
|
}
|
|
34
87
|
|
|
88
|
+
/** 注册后的定义:多出的 `structuredSchema` 供 codemode 渲染脚本侧返回类型。 */
|
|
89
|
+
export type RegisteredToolDefinition = ToolDefinition<TSchema, unknown, unknown> & {
|
|
90
|
+
structuredSchema?: TSchema;
|
|
91
|
+
};
|
|
92
|
+
|
|
35
93
|
export interface ToolBus {
|
|
36
94
|
/** 注册一个工具;被配置禁用时跳过并返回 false。 */
|
|
37
95
|
register<TParams extends TSchema, TDetails>(
|
|
38
96
|
definition: ToolDefinition<TParams, TDetails, unknown>,
|
|
39
97
|
): boolean;
|
|
40
98
|
/** 本次实际注册的工具定义。 */
|
|
41
|
-
list(): readonly
|
|
99
|
+
list(): readonly RegisteredToolDefinition[];
|
|
42
100
|
/** 所有尝试注册过的工具名(含被禁用而跳过的),用于校验配置里的模式是否有效。 */
|
|
43
101
|
declaredNames(): readonly string[];
|
|
44
|
-
get(name: string):
|
|
102
|
+
get(name: string): RegisteredToolDefinition | undefined;
|
|
45
103
|
/** 按名执行一个已注册工具;任何失败都以 `isError` 结果返回,不抛异常。 */
|
|
46
104
|
executeTool(
|
|
47
105
|
name: string,
|
|
@@ -55,8 +113,6 @@ export interface ToolBusOptions {
|
|
|
55
113
|
isDisabled?: (name: string) => boolean;
|
|
56
114
|
}
|
|
57
115
|
|
|
58
|
-
type AnyToolDefinition = ToolDefinition<TSchema, unknown, unknown>;
|
|
59
|
-
|
|
60
116
|
function errorResult(text: string): ToolExecutionResult {
|
|
61
117
|
return { content: [{ type: "text", text }], details: { error: text }, isError: true };
|
|
62
118
|
}
|
|
@@ -65,8 +121,64 @@ function errorMessage(error: unknown): string {
|
|
|
65
121
|
return error instanceof Error ? error.message : String(error);
|
|
66
122
|
}
|
|
67
123
|
|
|
124
|
+
type StructuredCheck =
|
|
125
|
+
{ ok: true; result?: StructuredResult<unknown> } | { ok: false; error: string };
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* 复核工具返回的 `structuredResult`:声明了 `structuredSchema` 的工具必须返回它,成功支的
|
|
129
|
+
* 载荷必须过 schema(外部数据用 typebox 校验是本仓库约定),失败支的错误必须是字符串。
|
|
130
|
+
*/
|
|
131
|
+
function checkStructuredResult(
|
|
132
|
+
name: string,
|
|
133
|
+
structuredSchema: TSchema | undefined,
|
|
134
|
+
result: AgentToolResult<unknown>,
|
|
135
|
+
): StructuredCheck {
|
|
136
|
+
const structured = (result as { structuredResult?: unknown }).structuredResult;
|
|
137
|
+
if (structured === undefined) {
|
|
138
|
+
return structuredSchema === undefined
|
|
139
|
+
? { ok: true }
|
|
140
|
+
: {
|
|
141
|
+
ok: false,
|
|
142
|
+
error: `Tool "${name}" declared a structuredSchema but returned no structuredResult.`,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (structuredSchema === undefined) {
|
|
146
|
+
return {
|
|
147
|
+
ok: false,
|
|
148
|
+
error: `Tool "${name}" returned a structuredResult without declaring a structuredSchema.`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
if (typeof structured !== "object" || structured === null) {
|
|
152
|
+
return { ok: false, error: `Tool "${name}" returned a malformed structuredResult.` };
|
|
153
|
+
}
|
|
154
|
+
const candidate = structured as { ok?: unknown; value?: unknown; error?: unknown };
|
|
155
|
+
if (candidate.ok === false) {
|
|
156
|
+
if (typeof candidate.error !== "string") {
|
|
157
|
+
return {
|
|
158
|
+
ok: false,
|
|
159
|
+
error: `Tool "${name}" returned a structuredResult whose error is not a string.`,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return { ok: true, result: { ok: false, error: candidate.error } };
|
|
163
|
+
}
|
|
164
|
+
if (candidate.ok !== true) {
|
|
165
|
+
return { ok: false, error: `Tool "${name}" returned a malformed structuredResult.` };
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
return {
|
|
169
|
+
ok: true,
|
|
170
|
+
result: { ok: true, value: parseWithSchema(structuredSchema, candidate.value) },
|
|
171
|
+
};
|
|
172
|
+
} catch (error) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
error: `Tool "${name}" returned a structuredResult value that does not match its structuredSchema: ${errorMessage(error)}`,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
68
180
|
export function createToolBus(pi: ExtensionAPI, options: ToolBusOptions = {}): ToolBus {
|
|
69
|
-
const registered = new Map<string,
|
|
181
|
+
const registered = new Map<string, RegisteredToolDefinition>();
|
|
70
182
|
const declared = new Set<string>();
|
|
71
183
|
let callCounter = 0;
|
|
72
184
|
|
|
@@ -76,7 +188,7 @@ export function createToolBus(pi: ExtensionAPI, options: ToolBusOptions = {}): T
|
|
|
76
188
|
if (options.isDisabled?.(definition.name) === true) {
|
|
77
189
|
return false;
|
|
78
190
|
}
|
|
79
|
-
const stored = definition as unknown as
|
|
191
|
+
const stored = definition as unknown as RegisteredToolDefinition;
|
|
80
192
|
pi.registerTool(stored);
|
|
81
193
|
registered.set(stored.name, stored);
|
|
82
194
|
return true;
|
|
@@ -117,7 +229,15 @@ export function createToolBus(pi: ExtensionAPI, options: ToolBusOptions = {}): T
|
|
|
117
229
|
options.onUpdate,
|
|
118
230
|
options.ctx,
|
|
119
231
|
);
|
|
120
|
-
|
|
232
|
+
const checked = checkStructuredResult(name, definition.structuredSchema, result);
|
|
233
|
+
if (!checked.ok) {
|
|
234
|
+
return errorResult(checked.error);
|
|
235
|
+
}
|
|
236
|
+
return {
|
|
237
|
+
...result,
|
|
238
|
+
isError: false,
|
|
239
|
+
...(checked.result !== undefined && { structuredResult: checked.result }),
|
|
240
|
+
};
|
|
121
241
|
} catch (error) {
|
|
122
242
|
return errorResult(`Tool "${name}" failed: ${errorMessage(error)}`);
|
|
123
243
|
}
|