pi-t3-bridge 0.6.0 → 0.7.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/package.json +3 -4
- package/src/amplike/btw.ts +5 -7
- package/src/amplike/handoff.ts +33 -23
- package/src/amplike/package.ts +37 -24
- package/src/amplike/selection.ts +26 -14
- package/src/bridge/accounts.ts +66 -49
- package/src/bridge/ask.ts +73 -93
- package/src/bridge/bash-timeout.ts +15 -8
- package/src/bridge/config.ts +29 -26
- package/src/bridge/plan.ts +19 -11
- package/src/bridge/resume.ts +17 -11
- package/src/bridge/state.ts +54 -34
- package/src/bridge/steer-judge.ts +130 -96
- package/src/bridge/steer-transcript.ts +4 -3
- package/src/bridge/steer.ts +16 -10
- package/src/bridge/t3-json.ts +14 -19
- package/src/bridge/tasks.ts +39 -31
- package/src/bridge/thread.ts +5 -6
- package/src/bridge/transcript.ts +11 -8
- package/src/pstack/brief.ts +4 -3
- package/src/pstack/child.ts +45 -32
- package/src/pstack/models.ts +138 -106
- package/src/pstack/overlay.ts +18 -20
- package/src/pstack/results.ts +4 -7
- package/src/pstack/sandbox.ts +12 -8
- package/pstack/skills/statechart/scripts/node_modules/.package-lock.json +0 -46
- package/pstack/skills/statechart/scripts/node_modules/fast-check/LICENSE +0 -21
- package/pstack/skills/statechart/scripts/node_modules/fast-check/README.md +0 -263
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/fast-check.js +0 -12147
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/package.json +0 -3
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/cjs/types57/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/fast-check.js +0 -12011
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/rolldown-runtime-D7D4PA-g.js +0 -13
- package/pstack/skills/statechart/scripts/node_modules/fast-check/lib/types57/fast-check.d.ts +0 -5165
- package/pstack/skills/statechart/scripts/node_modules/fast-check/package.json +0 -94
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/LICENSE +0 -21
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/README.md +0 -168
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/RandomGenerator-DcXj09Ch.d.ts +0 -14
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformBigInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformBigInt.js +0 -38
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat32.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat32.js +0 -18
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat64.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformFloat64.js +0 -22
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/distribution/uniformInt.js +0 -134
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/RandomGenerator-DcXj09Ch.d.ts +0 -14
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformBigInt.js +0 -37
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat32.js +0 -17
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformFloat64.js +0 -21
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformInt.d.ts +0 -15
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/distribution/uniformInt.js +0 -133
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/congruential32.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/congruential32.js +0 -44
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/mersenne.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/mersenne.js +0 -90
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xoroshiro128plus.js +0 -80
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xorshift128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/generator/xorshift128plus.js +0 -78
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/package.json +0 -3
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.d.ts +0 -16
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/JumpableRandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/RandomGenerator.d.ts +0 -2
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/types/RandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/generateN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/generateN.js +0 -8
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/purify.d.ts +0 -12
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/purify.js +0 -9
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/skipN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/esm/utils/skipN.js +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/congruential32.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/congruential32.js +0 -46
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/mersenne.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/mersenne.js +0 -92
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xoroshiro128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xoroshiro128plus.js +0 -82
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xorshift128plus.d.ts +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/generator/xorshift128plus.js +0 -80
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/JumpableRandomGenerator.d.ts +0 -16
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/JumpableRandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/RandomGenerator.d.ts +0 -2
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/types/RandomGenerator.js +0 -0
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/generateN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/generateN.js +0 -9
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/purify.d.ts +0 -12
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/purify.js +0 -10
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/skipN.d.ts +0 -6
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/lib/utils/skipN.js +0 -7
- package/pstack/skills/statechart/scripts/node_modules/pure-rand/package.json +0 -133
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-t3-bridge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Pi extension adapter for t3-pstack inside T3 Code.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-extension",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
"typecheck": "tsc --project tsconfig.json && tsc --project pstack/skills/poteto-mode/scripts/watch-pr/tsconfig.json && tsc --project pstack/skills/statechart/scripts/tsconfig.json"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
+
"@earendil-works/pi-schema": "1.5.0",
|
|
53
54
|
"commander": "^15.0.0",
|
|
54
55
|
"marked": "18.0.11",
|
|
55
56
|
"pele": "1.13.0"
|
|
@@ -61,14 +62,12 @@
|
|
|
61
62
|
"oxfmt": "^0.74.0",
|
|
62
63
|
"oxlint": "^1.89.0",
|
|
63
64
|
"testcontainers": "^12.2.1",
|
|
64
|
-
"typebox": "1.3.27",
|
|
65
65
|
"typescript": "^7.0.2",
|
|
66
66
|
"ultracite": "^8.0.1"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"@earendil-works/pi-ai": "*",
|
|
70
|
-
"@earendil-works/pi-coding-agent": "*"
|
|
71
|
-
"typebox": "*"
|
|
70
|
+
"@earendil-works/pi-coding-agent": "*"
|
|
72
71
|
},
|
|
73
72
|
"peerDependenciesMeta": {
|
|
74
73
|
"@earendil-works/pi-coding-agent": {
|
package/src/amplike/btw.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import {
|
|
3
|
-
import { Value } from "typebox/value";
|
|
2
|
+
import { compile, nullable, obj, opt, str } from "@earendil-works/pi-schema";
|
|
4
3
|
|
|
5
4
|
import { callT3Tool } from "../bridge/t3-http.ts";
|
|
6
5
|
import type { LoadModeSpec } from "./package.ts";
|
|
@@ -14,10 +13,9 @@ import type { SelectionChange } from "./selection.ts";
|
|
|
14
13
|
|
|
15
14
|
type Command = Parameters<ExtensionAPI["registerCommand"]>[1];
|
|
16
15
|
|
|
17
|
-
const
|
|
18
|
-
link:
|
|
19
|
-
|
|
20
|
-
});
|
|
16
|
+
const isDelegated = compile(
|
|
17
|
+
obj({ link: opt(nullable(str())), taskId: str() }, { open: true })
|
|
18
|
+
).check;
|
|
21
19
|
|
|
22
20
|
const TITLE_LENGTH = 80;
|
|
23
21
|
|
|
@@ -76,7 +74,7 @@ export const btwCommand = (loadModeSpec: LoadModeSpec): Command => ({
|
|
|
76
74
|
target: await targetFor(change),
|
|
77
75
|
});
|
|
78
76
|
|
|
79
|
-
if (!
|
|
77
|
+
if (!isDelegated(delegated)) {
|
|
80
78
|
throw new Error("delegate_task returned no task.");
|
|
81
79
|
}
|
|
82
80
|
|
package/src/amplike/handoff.ts
CHANGED
|
@@ -8,8 +8,8 @@ import type {
|
|
|
8
8
|
ExtensionAPI,
|
|
9
9
|
ExtensionContext,
|
|
10
10
|
} from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { compile, nullable, obj, opt, str } from "@earendil-works/pi-schema";
|
|
12
|
+
import type { Static } from "@earendil-works/pi-schema";
|
|
13
13
|
|
|
14
14
|
import { callT3Tool } from "../bridge/t3-http.ts";
|
|
15
15
|
import type { LoadModeSpec } from "./package.ts";
|
|
@@ -39,10 +39,28 @@ Output only the prompt, with no preamble.`;
|
|
|
39
39
|
|
|
40
40
|
const TITLE_LENGTH = 80;
|
|
41
41
|
|
|
42
|
-
const
|
|
43
|
-
link:
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
const isLaunched = compile(
|
|
43
|
+
obj({ link: opt(nullable(str())), threadId: str() }, { open: true })
|
|
44
|
+
).check;
|
|
45
|
+
|
|
46
|
+
const HandoffSchema = obj(
|
|
47
|
+
{
|
|
48
|
+
goal: str({ description: "The goal/task for the new thread" }),
|
|
49
|
+
mode: opt(
|
|
50
|
+
str({
|
|
51
|
+
description:
|
|
52
|
+
"Amplike mode name to start the new thread with (e.g. 'rush', 'smart', 'deep')",
|
|
53
|
+
})
|
|
54
|
+
),
|
|
55
|
+
model: opt(
|
|
56
|
+
str({
|
|
57
|
+
description:
|
|
58
|
+
"Model to start the new thread with, as provider/modelId (e.g. 'anthropic/claude-haiku-4-5')",
|
|
59
|
+
})
|
|
60
|
+
),
|
|
61
|
+
},
|
|
62
|
+
{ open: true }
|
|
63
|
+
);
|
|
46
64
|
|
|
47
65
|
const summarize = async (
|
|
48
66
|
ctx: ExtensionContext,
|
|
@@ -123,7 +141,7 @@ const handoff = async (
|
|
|
123
141
|
modelSelection: { ...applyChange(await currentSelection(), change) },
|
|
124
142
|
});
|
|
125
143
|
|
|
126
|
-
if (!
|
|
144
|
+
if (!isLaunched(launched)) {
|
|
127
145
|
throw new Error("t3_thread_launch returned no thread.");
|
|
128
146
|
}
|
|
129
147
|
|
|
@@ -134,7 +152,13 @@ export const handoffTool = (loadModeSpec: LoadModeSpec) =>
|
|
|
134
152
|
defineTool({
|
|
135
153
|
description:
|
|
136
154
|
"Transfer context to a new focused T3 thread. ONLY use this when the user explicitly asks for a handoff. Provide a goal describing what the new thread should focus on. The result is the new thread's link, which you show the user verbatim.",
|
|
137
|
-
execute: async (
|
|
155
|
+
execute: async (
|
|
156
|
+
_toolCallId,
|
|
157
|
+
params: Static<typeof HandoffSchema>,
|
|
158
|
+
signal,
|
|
159
|
+
_onUpdate,
|
|
160
|
+
ctx
|
|
161
|
+
) => {
|
|
138
162
|
const link = await handoff(
|
|
139
163
|
ctx,
|
|
140
164
|
params.goal,
|
|
@@ -150,21 +174,7 @@ export const handoffTool = (loadModeSpec: LoadModeSpec) =>
|
|
|
150
174
|
},
|
|
151
175
|
label: "Handoff",
|
|
152
176
|
name: "handoff",
|
|
153
|
-
parameters:
|
|
154
|
-
goal: Type.String({ description: "The goal/task for the new thread" }),
|
|
155
|
-
mode: Type.Optional(
|
|
156
|
-
Type.String({
|
|
157
|
-
description:
|
|
158
|
-
"Amplike mode name to start the new thread with (e.g. 'rush', 'smart', 'deep')",
|
|
159
|
-
})
|
|
160
|
-
),
|
|
161
|
-
model: Type.Optional(
|
|
162
|
-
Type.String({
|
|
163
|
-
description:
|
|
164
|
-
"Model to start the new thread with, as provider/modelId (e.g. 'anthropic/claude-haiku-4-5')",
|
|
165
|
-
})
|
|
166
|
-
),
|
|
167
|
-
}),
|
|
177
|
+
parameters: HandoffSchema,
|
|
168
178
|
});
|
|
169
179
|
|
|
170
180
|
export const handoffCommand = (loadModeSpec: LoadModeSpec): Command => ({
|
package/src/amplike/package.ts
CHANGED
|
@@ -10,27 +10,38 @@ import type {
|
|
|
10
10
|
ExtensionFactory,
|
|
11
11
|
ResolvedResource,
|
|
12
12
|
} from "@earendil-works/pi-coding-agent";
|
|
13
|
-
import {
|
|
14
|
-
import type { Static } from "
|
|
15
|
-
import { Value } from "typebox/value";
|
|
13
|
+
import { compile, obj, opt, str, unknown } from "@earendil-works/pi-schema";
|
|
14
|
+
import type { Static } from "@earendil-works/pi-schema";
|
|
16
15
|
|
|
17
16
|
const PACKAGE_NAME = "pi-amplike";
|
|
18
17
|
|
|
19
|
-
const
|
|
18
|
+
const isManifest = compile(obj({ name: str() }, { open: true })).check;
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
// JSON Schema has no function type, so these check that the export exists and
|
|
21
|
+
// isFunction checks that it is a function. Like TypeBox's Type.Function, the
|
|
22
|
+
// check can't see the function's parameters, so the caller names them.
|
|
23
|
+
const isFunction = <F extends (...args: never[]) => void>(
|
|
24
|
+
value: unknown
|
|
25
|
+
): value is F => typeof value === "function";
|
|
24
26
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
const isFactoryModule = compile(
|
|
28
|
+
obj({ default: unknown() }, { open: true })
|
|
29
|
+
).check;
|
|
28
30
|
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const isModeUtils = compile(
|
|
32
|
+
obj({ loadModeSpec: unknown() }, { open: true })
|
|
33
|
+
).check;
|
|
34
|
+
|
|
35
|
+
const ModeSpecSchema = obj(
|
|
36
|
+
{
|
|
37
|
+
modelId: opt(str()),
|
|
38
|
+
provider: opt(str()),
|
|
39
|
+
thinkingLevel: opt(str()),
|
|
40
|
+
},
|
|
41
|
+
{ open: true }
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const isModeSpec = compile(ModeSpecSchema).check;
|
|
34
45
|
|
|
35
46
|
export type ModeSpec = Static<typeof ModeSpecSchema>;
|
|
36
47
|
|
|
@@ -53,9 +64,7 @@ const isAmplikeRoot = (root: string): boolean => {
|
|
|
53
64
|
readFileSync(path.join(root, "package.json"), "utf-8")
|
|
54
65
|
);
|
|
55
66
|
|
|
56
|
-
return (
|
|
57
|
-
Value.Check(ManifestSchema, manifest) && manifest.name === PACKAGE_NAME
|
|
58
|
-
);
|
|
67
|
+
return isManifest(manifest) && manifest.name === PACKAGE_NAME;
|
|
59
68
|
} catch {
|
|
60
69
|
return false;
|
|
61
70
|
}
|
|
@@ -97,12 +106,14 @@ export const findAmplike = async (
|
|
|
97
106
|
export const loadFactory = async (file: string): Promise<ExtensionFactory> => {
|
|
98
107
|
const module: unknown = await import(file);
|
|
99
108
|
|
|
100
|
-
if (
|
|
109
|
+
if (
|
|
110
|
+
!isFactoryModule(module) ||
|
|
111
|
+
!isFunction<ExtensionFactory>(module.default)
|
|
112
|
+
) {
|
|
101
113
|
throw new TypeError(`${file} has no default extension factory.`);
|
|
102
114
|
}
|
|
103
115
|
|
|
104
|
-
|
|
105
|
-
return module.default as ExtensionFactory;
|
|
116
|
+
return module.default;
|
|
106
117
|
};
|
|
107
118
|
|
|
108
119
|
// amplike's handoff and subagent read -mode through this helper, so the T3
|
|
@@ -111,13 +122,15 @@ export const loadModeSpecFrom = async (root: string): Promise<LoadModeSpec> => {
|
|
|
111
122
|
const file = path.join(root, "extensions", "lib", "mode-utils.ts");
|
|
112
123
|
const module: unknown = await import(file);
|
|
113
124
|
|
|
114
|
-
if (!
|
|
125
|
+
if (!isModeUtils(module) || !isFunction<LoadModeSpec>(module.loadModeSpec)) {
|
|
115
126
|
throw new TypeError(`${file} has no loadModeSpec export.`);
|
|
116
127
|
}
|
|
117
128
|
|
|
129
|
+
const { loadModeSpec } = module;
|
|
130
|
+
|
|
118
131
|
return async (cwd, name) => {
|
|
119
|
-
const spec = await
|
|
132
|
+
const spec: unknown = await loadModeSpec(cwd, name);
|
|
120
133
|
|
|
121
|
-
return
|
|
134
|
+
return isModeSpec(spec) ? spec : undefined;
|
|
122
135
|
};
|
|
123
136
|
};
|
package/src/amplike/selection.ts
CHANGED
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
arr,
|
|
3
|
+
bool,
|
|
4
|
+
compile,
|
|
5
|
+
obj,
|
|
6
|
+
opt,
|
|
7
|
+
str,
|
|
8
|
+
union,
|
|
9
|
+
} from "@earendil-works/pi-schema";
|
|
10
|
+
import type { Static } from "@earendil-works/pi-schema";
|
|
4
11
|
|
|
5
12
|
import { callT3Tool } from "../bridge/t3-http.ts";
|
|
6
13
|
import type { LoadModeSpec } from "./package.ts";
|
|
7
14
|
|
|
8
|
-
const OptionSchema =
|
|
9
|
-
id:
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
const OptionSchema = obj(
|
|
16
|
+
{ id: str(), value: union([str(), bool()]) },
|
|
17
|
+
{ open: true }
|
|
18
|
+
);
|
|
12
19
|
|
|
13
|
-
const SelectionSchema =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
const SelectionSchema = obj(
|
|
21
|
+
{
|
|
22
|
+
instanceId: opt(str()),
|
|
23
|
+
model: str(),
|
|
24
|
+
options: opt(arr(OptionSchema)),
|
|
25
|
+
},
|
|
26
|
+
{ open: true }
|
|
27
|
+
);
|
|
18
28
|
|
|
19
|
-
const
|
|
29
|
+
const isConfigured = compile(
|
|
30
|
+
obj({ modelSelection: SelectionSchema }, { open: true })
|
|
31
|
+
).check;
|
|
20
32
|
|
|
21
33
|
// T3's modelSelection for a Pi thread: model is "provider/modelId", and the
|
|
22
34
|
// thinking level is the "thinking" option.
|
|
@@ -45,7 +57,7 @@ export const isEmptyChange = (change: SelectionChange): boolean =>
|
|
|
45
57
|
export const currentSelection = async (): Promise<Selection> => {
|
|
46
58
|
const result = await callT3Tool("t3_thread_configure", {});
|
|
47
59
|
|
|
48
|
-
if (!
|
|
60
|
+
if (!isConfigured(result)) {
|
|
49
61
|
throw new Error("t3_thread_configure returned no modelSelection.");
|
|
50
62
|
}
|
|
51
63
|
|
package/src/bridge/accounts.ts
CHANGED
|
@@ -3,9 +3,19 @@ import type {
|
|
|
3
3
|
ExtensionContext,
|
|
4
4
|
ExtensionToolContext,
|
|
5
5
|
} from "@earendil-works/pi-coding-agent";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import {
|
|
7
|
+
arr,
|
|
8
|
+
bool,
|
|
9
|
+
compile,
|
|
10
|
+
lit,
|
|
11
|
+
nullable,
|
|
12
|
+
num,
|
|
13
|
+
obj,
|
|
14
|
+
opt,
|
|
15
|
+
str,
|
|
16
|
+
union,
|
|
17
|
+
} from "@earendil-works/pi-schema";
|
|
18
|
+
import type { Static } from "@earendil-works/pi-schema";
|
|
9
19
|
|
|
10
20
|
import { classifyFailure } from "./failures.ts";
|
|
11
21
|
import type { Classified } from "./failures.ts";
|
|
@@ -62,15 +72,16 @@ const NO_RESET_MS = 60 * 60_000;
|
|
|
62
72
|
|
|
63
73
|
const USAGE_LIMIT_TITLE = "Usage limit reached";
|
|
64
74
|
|
|
65
|
-
const AccountEventSchema =
|
|
66
|
-
|
|
67
|
-
childThreadId:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}),
|
|
71
|
-
Type.Object({ childThreadId: Type.String(), kind: Type.Literal("settled") }),
|
|
75
|
+
const AccountEventSchema = union([
|
|
76
|
+
obj(
|
|
77
|
+
{ childThreadId: str(), family: str(), kind: lit("delegated") },
|
|
78
|
+
{ open: true }
|
|
79
|
+
),
|
|
80
|
+
obj({ childThreadId: str(), kind: lit("settled") }, { open: true }),
|
|
72
81
|
]);
|
|
73
82
|
|
|
83
|
+
const isAccountEvent = compile(AccountEventSchema).check;
|
|
84
|
+
|
|
74
85
|
type AccountEvent = Static<typeof AccountEventSchema>;
|
|
75
86
|
|
|
76
87
|
export interface Accounts {
|
|
@@ -100,7 +111,7 @@ export const readAccounts = (ctx: ExtensionContext): Accounts => {
|
|
|
100
111
|
if (
|
|
101
112
|
entry.type === "custom" &&
|
|
102
113
|
entry.customType === ACCOUNT_ENTRY &&
|
|
103
|
-
|
|
114
|
+
isAccountEvent(entry.data)
|
|
104
115
|
) {
|
|
105
116
|
const event: AccountEvent = entry.data;
|
|
106
117
|
|
|
@@ -186,19 +197,23 @@ export const recordFailure = (
|
|
|
186
197
|
updateFamily(modelFamily, record);
|
|
187
198
|
};
|
|
188
199
|
|
|
189
|
-
const ThreadReadSchema =
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
200
|
+
const ThreadReadSchema = obj(
|
|
201
|
+
{
|
|
202
|
+
hasMore: bool(),
|
|
203
|
+
items: arr(
|
|
204
|
+
obj(
|
|
205
|
+
{ text: opt(nullable(str())), title: nullable(str()), type: str() },
|
|
206
|
+
{ open: true }
|
|
207
|
+
)
|
|
208
|
+
),
|
|
209
|
+
nextPosition: nullable(num()),
|
|
210
|
+
recentRuns: opt(arr(obj({ status: str() }, { open: true }))),
|
|
211
|
+
thread: obj({ status: str() }, { open: true }),
|
|
212
|
+
},
|
|
213
|
+
{ open: true }
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
const threadRead = compile(ThreadReadSchema);
|
|
202
217
|
|
|
203
218
|
type ThreadRead = Static<typeof ThreadReadSchema>;
|
|
204
219
|
|
|
@@ -217,16 +232,14 @@ const bridgeReader =
|
|
|
217
232
|
async (params) => {
|
|
218
233
|
const outcome = await ctx.executeTool(toolName, params);
|
|
219
234
|
|
|
220
|
-
return outcome.isError
|
|
221
|
-
? undefined
|
|
222
|
-
: t3Json(ThreadReadSchema, outcome.result);
|
|
235
|
+
return outcome.isError ? undefined : t3Json(threadRead, outcome.result);
|
|
223
236
|
};
|
|
224
237
|
|
|
225
238
|
// A tool_result handler gets no ctx.executeTool, so it reads through T3 directly.
|
|
226
239
|
export const httpReader: PageReader = async (params) => {
|
|
227
240
|
const read = await callT3Tool("t3_thread_read", { ...params });
|
|
228
241
|
|
|
229
|
-
return
|
|
242
|
+
return threadRead.check(read) ? read : undefined;
|
|
230
243
|
};
|
|
231
244
|
|
|
232
245
|
type ChildOutcome =
|
|
@@ -358,27 +371,33 @@ const STATUS_TOOLS: ReadonlySet<string> = new Set([
|
|
|
358
371
|
"mcp__t3__task_status",
|
|
359
372
|
]);
|
|
360
373
|
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
374
|
+
const taskStatus = compile(
|
|
375
|
+
obj(
|
|
376
|
+
{ childThreadId: str(), status: opt(str()), workState: opt(str()) },
|
|
377
|
+
{ open: true }
|
|
378
|
+
)
|
|
379
|
+
);
|
|
366
380
|
|
|
367
|
-
const
|
|
368
|
-
target:
|
|
369
|
-
|
|
381
|
+
const isDelegateInput = compile(
|
|
382
|
+
obj({ target: opt(obj({ model: str() }, { open: true })) }, { open: true })
|
|
383
|
+
).check;
|
|
370
384
|
|
|
371
|
-
const
|
|
385
|
+
const delegateResult = compile(obj({ childThreadId: str() }, { open: true }));
|
|
372
386
|
|
|
373
387
|
const sessionFamily = (ctx: ExtensionContext): string | undefined =>
|
|
374
388
|
ctx.model === undefined ? undefined : family(ctx.model.id);
|
|
375
389
|
|
|
376
|
-
const
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
390
|
+
const isAssistantError = compile(
|
|
391
|
+
obj(
|
|
392
|
+
{
|
|
393
|
+
errorMessage: opt(str()),
|
|
394
|
+
model: str(),
|
|
395
|
+
role: lit("assistant"),
|
|
396
|
+
stopReason: str(),
|
|
397
|
+
},
|
|
398
|
+
{ open: true }
|
|
399
|
+
)
|
|
400
|
+
).check;
|
|
382
401
|
|
|
383
402
|
// Recovery takes any family accounts.json records, such as kimi. Marking one
|
|
384
403
|
// out takes only a family of a model Pi knows, so a typo cannot add one.
|
|
@@ -410,7 +429,7 @@ export const registerAccounts = (pi: ExtensionAPI): void => {
|
|
|
410
429
|
return;
|
|
411
430
|
}
|
|
412
431
|
|
|
413
|
-
const status = t3Json(
|
|
432
|
+
const status = t3Json(taskStatus, event);
|
|
414
433
|
|
|
415
434
|
const childFamily =
|
|
416
435
|
status === undefined
|
|
@@ -437,11 +456,9 @@ export const registerAccounts = (pi: ExtensionAPI): void => {
|
|
|
437
456
|
return;
|
|
438
457
|
}
|
|
439
458
|
|
|
440
|
-
const result = t3Json(
|
|
459
|
+
const result = t3Json(delegateResult, event);
|
|
441
460
|
|
|
442
|
-
const input =
|
|
443
|
-
? event.input
|
|
444
|
-
: undefined;
|
|
461
|
+
const input = isDelegateInput(event.input) ? event.input : undefined;
|
|
445
462
|
|
|
446
463
|
const childFamily =
|
|
447
464
|
input?.target === undefined
|
|
@@ -493,7 +510,7 @@ export const registerAccounts = (pi: ExtensionAPI): void => {
|
|
|
493
510
|
(message) => (message as { role?: string }).role === "assistant"
|
|
494
511
|
);
|
|
495
512
|
|
|
496
|
-
if (!
|
|
513
|
+
if (!isAssistantError(last)) {
|
|
497
514
|
lastRun = undefined;
|
|
498
515
|
} else if (last.stopReason === "error") {
|
|
499
516
|
lastRun = {
|