thinkwell 0.5.5 → 0.5.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/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +232 -278
- package/dist/agent.js.map +1 -1
- package/dist/build.js +44 -98
- package/dist/cli/build.js +92 -227
- package/dist/cli/bundle.js +570 -1136
- package/dist/cli/check.js +125 -214
- package/dist/cli/commands.js +63 -177
- package/dist/cli/compiler-host.js +81 -190
- package/dist/cli/dependency-check.js +125 -269
- package/dist/cli/dependency-errors.js +12 -84
- package/dist/cli/fmt.js +1 -13
- package/dist/cli/init-command.js +21 -68
- package/dist/cli/init.js +90 -220
- package/dist/cli/loader.js +95 -361
- package/dist/cli/new-command.js +25 -73
- package/dist/cli/package-manager.js +50 -117
- package/dist/cli/schema.d.ts.map +1 -1
- package/dist/cli/schema.js +91 -245
- package/dist/cli/schema.js.map +1 -1
- package/dist/cli/workspace.js +92 -226
- package/dist/connectors/index.js +1 -7
- package/dist/generated/features.d.ts +6 -0
- package/dist/generated/features.d.ts.map +1 -0
- package/dist/generated/features.js +5 -0
- package/dist/generated/features.js.map +1 -0
- package/dist/index.js +0 -5
- package/dist/schema.js +3 -36
- package/dist/session.js +50 -82
- package/dist/think-builder.d.ts.map +1 -1
- package/dist/think-builder.js +287 -368
- package/dist/think-builder.js.map +1 -1
- package/dist/thought-event.d.ts +1 -0
- package/dist/thought-event.d.ts.map +1 -1
- package/dist/thought-event.js +0 -1
- package/dist/thought-stream.js +60 -96
- package/dist-pkg/acp.cjs +13386 -1876
- package/dist-pkg/cli-build.cjs +264 -446
- package/dist-pkg/cli-bundle.cjs +433 -818
- package/dist-pkg/cli-check.cjs +302 -499
- package/dist-pkg/cli-dependency-check.cjs +39 -82
- package/dist-pkg/cli-dependency-errors.cjs +9 -41
- package/dist-pkg/cli-loader.cjs +91 -173
- package/dist-pkg/protocol.cjs +2 -8
- package/dist-pkg/thinkwell.cjs +927 -1846
- package/package.json +9 -7
package/dist/think-builder.js
CHANGED
|
@@ -1,386 +1,305 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { features } from "./generated/features.js";
|
|
4
|
+
import { mcpServer, createSkillServer, parseSkillMd, validateSkillName, validateSkillDescription } from "@thinkwell/acp";
|
|
4
5
|
import { ThoughtStream } from "./thought-stream.js";
|
|
5
|
-
/**
|
|
6
|
-
* Internal session handler for ThinkBuilder
|
|
7
|
-
*/
|
|
8
6
|
class ThinkSession {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
return this._pendingUpdates.shift();
|
|
42
|
-
}
|
|
43
|
-
if (this._closed) {
|
|
44
|
-
return { type: "stop", reason: "session_closed" };
|
|
45
|
-
}
|
|
46
|
-
return new Promise((resolve) => {
|
|
47
|
-
this._updateResolvers.push(resolve);
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
close() {
|
|
51
|
-
this._closed = true;
|
|
52
|
-
for (const resolver of this._updateResolvers) {
|
|
53
|
-
resolver({ type: "stop", reason: "session_closed" });
|
|
54
|
-
}
|
|
55
|
-
this._updateResolvers = [];
|
|
56
|
-
}
|
|
7
|
+
sessionId;
|
|
8
|
+
_conn;
|
|
9
|
+
_pendingUpdates = [];
|
|
10
|
+
_updateResolvers = [];
|
|
11
|
+
_closed = !1;
|
|
12
|
+
constructor(sessionId, conn) {
|
|
13
|
+
this.sessionId = sessionId, this._conn = conn;
|
|
14
|
+
}
|
|
15
|
+
async sendPrompt(content) {
|
|
16
|
+
const response = await this._conn.connection.prompt({
|
|
17
|
+
sessionId: this.sessionId,
|
|
18
|
+
prompt: [{ type: "text", text: content }]
|
|
19
|
+
});
|
|
20
|
+
response.stopReason && this._pushInternal({ type: "stop", reason: response.stopReason });
|
|
21
|
+
}
|
|
22
|
+
pushUpdate(update) {
|
|
23
|
+
this._pushInternal(update);
|
|
24
|
+
}
|
|
25
|
+
_pushInternal(update) {
|
|
26
|
+
this._updateResolvers.length > 0 ? this._updateResolvers.shift()(update) : this._pendingUpdates.push(update);
|
|
27
|
+
}
|
|
28
|
+
async readUpdate() {
|
|
29
|
+
return this._pendingUpdates.length > 0 ? this._pendingUpdates.shift() : this._closed ? { type: "stop", reason: "session_closed" } : new Promise((resolve) => {
|
|
30
|
+
this._updateResolvers.push(resolve);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
close() {
|
|
34
|
+
this._closed = !0;
|
|
35
|
+
for (const resolver of this._updateResolvers)
|
|
36
|
+
resolver({ type: "stop", reason: "session_closed" });
|
|
37
|
+
this._updateResolvers = [];
|
|
38
|
+
}
|
|
57
39
|
}
|
|
58
40
|
class PlanImpl {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
outputSchema = { toJsonSchema: () => ({ type: "object" }) };
|
|
141
|
-
actualHandler = inputSchemaOrHandler;
|
|
142
|
-
}
|
|
143
|
-
else if (typeof outputSchemaOrHandler === "function") {
|
|
144
|
-
inputSchema = inputSchemaOrHandler;
|
|
145
|
-
outputSchema = { toJsonSchema: () => ({ type: "object" }) };
|
|
146
|
-
actualHandler = outputSchemaOrHandler;
|
|
147
|
-
}
|
|
148
|
-
else {
|
|
149
|
-
inputSchema = inputSchemaOrHandler;
|
|
150
|
-
outputSchema = outputSchemaOrHandler;
|
|
151
|
-
actualHandler = handler;
|
|
152
|
-
}
|
|
153
|
-
const newTools = new Map(this._tools);
|
|
154
|
-
newTools.set(name, {
|
|
155
|
-
name,
|
|
156
|
-
description,
|
|
157
|
-
handler: actualHandler,
|
|
158
|
-
inputSchema,
|
|
159
|
-
outputSchema,
|
|
160
|
-
includeInPrompt: false,
|
|
161
|
-
});
|
|
162
|
-
return this._clone({ tools: newTools });
|
|
163
|
-
}
|
|
164
|
-
skill(pathOrDef) {
|
|
165
|
-
if (typeof pathOrDef === "string") {
|
|
166
|
-
return this._clone({ skills: [...this._skills, { type: "stored", path: pathOrDef }] });
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
validateSkillName(pathOrDef.name);
|
|
170
|
-
validateSkillDescription(pathOrDef.description);
|
|
171
|
-
return this._clone({
|
|
172
|
-
skills: [...this._skills, {
|
|
173
|
-
type: "virtual",
|
|
174
|
-
skill: {
|
|
175
|
-
name: pathOrDef.name,
|
|
176
|
-
description: pathOrDef.description,
|
|
177
|
-
body: pathOrDef.body,
|
|
178
|
-
tools: pathOrDef.tools,
|
|
179
|
-
},
|
|
180
|
-
}],
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
cwd(path) {
|
|
185
|
-
return this._clone({ cwd: path });
|
|
186
|
-
}
|
|
187
|
-
async _resolveSkills() {
|
|
188
|
-
const resolved = [];
|
|
189
|
-
for (const deferred of this._skills) {
|
|
190
|
-
if (deferred.type === "virtual") {
|
|
191
|
-
resolved.push(deferred.skill);
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
const content = await readFile(deferred.path, "utf-8");
|
|
195
|
-
const parsed = parseSkillMd(content);
|
|
196
|
-
const stored = {
|
|
197
|
-
name: parsed.name,
|
|
198
|
-
description: parsed.description,
|
|
199
|
-
body: parsed.body,
|
|
200
|
-
basePath: dirname(deferred.path),
|
|
201
|
-
};
|
|
202
|
-
resolved.push(stored);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
return resolved;
|
|
206
|
-
}
|
|
207
|
-
_buildSkillsPrompt(skills) {
|
|
208
|
-
if (skills.length === 0)
|
|
209
|
-
return "";
|
|
210
|
-
let xml = "<available_skills>\n";
|
|
211
|
-
for (const skill of skills) {
|
|
212
|
-
xml += ` <skill>\n`;
|
|
213
|
-
xml += ` <name>${skill.name}</name>\n`;
|
|
214
|
-
xml += ` <description>${skill.description}</description>\n`;
|
|
215
|
-
xml += ` </skill>\n`;
|
|
41
|
+
_conn;
|
|
42
|
+
_promptParts;
|
|
43
|
+
_tools;
|
|
44
|
+
_skills;
|
|
45
|
+
_schemaProvider;
|
|
46
|
+
_cwd;
|
|
47
|
+
_existingSessionId;
|
|
48
|
+
constructor(state) {
|
|
49
|
+
this._conn = state.conn, this._promptParts = state.promptParts, this._tools = state.tools, this._skills = state.skills, this._schemaProvider = state.schemaProvider, this._cwd = state.cwd, this._existingSessionId = state.existingSessionId;
|
|
50
|
+
}
|
|
51
|
+
_clone(overrides) {
|
|
52
|
+
return new PlanImpl({
|
|
53
|
+
conn: this._conn,
|
|
54
|
+
promptParts: this._promptParts,
|
|
55
|
+
tools: this._tools,
|
|
56
|
+
skills: this._skills,
|
|
57
|
+
schemaProvider: this._schemaProvider,
|
|
58
|
+
cwd: this._cwd,
|
|
59
|
+
existingSessionId: this._existingSessionId,
|
|
60
|
+
...overrides
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
text(content) {
|
|
64
|
+
return this._clone({ promptParts: [...this._promptParts, content] });
|
|
65
|
+
}
|
|
66
|
+
textln(content) {
|
|
67
|
+
return this._clone({ promptParts: [...this._promptParts, content + `
|
|
68
|
+
`] });
|
|
69
|
+
}
|
|
70
|
+
quote(content, tag = "quote") {
|
|
71
|
+
const part = content.includes(`
|
|
72
|
+
`) ? `<${tag}>
|
|
73
|
+
${content}
|
|
74
|
+
</${tag}>
|
|
75
|
+
` : `<${tag}>${content}</${tag}>
|
|
76
|
+
`;
|
|
77
|
+
return this._clone({ promptParts: [...this._promptParts, part] });
|
|
78
|
+
}
|
|
79
|
+
code(content, language = "") {
|
|
80
|
+
return this._clone({
|
|
81
|
+
promptParts: [...this._promptParts, `\`\`\`${language}
|
|
82
|
+
${content}
|
|
83
|
+
\`\`\`
|
|
84
|
+
`]
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
tool(name, description, inputSchemaOrHandler, outputSchemaOrHandler, handler) {
|
|
88
|
+
let inputSchema, outputSchema, actualHandler;
|
|
89
|
+
typeof inputSchemaOrHandler == "function" ? (inputSchema = { toJsonSchema: () => ({ type: "object" }) }, outputSchema = { toJsonSchema: () => ({ type: "object" }) }, actualHandler = inputSchemaOrHandler) : typeof outputSchemaOrHandler == "function" ? (inputSchema = inputSchemaOrHandler, outputSchema = { toJsonSchema: () => ({ type: "object" }) }, actualHandler = outputSchemaOrHandler) : (inputSchema = inputSchemaOrHandler, outputSchema = outputSchemaOrHandler, actualHandler = handler);
|
|
90
|
+
const newTools = new Map(this._tools);
|
|
91
|
+
return newTools.set(name, {
|
|
92
|
+
name,
|
|
93
|
+
description,
|
|
94
|
+
handler: actualHandler,
|
|
95
|
+
inputSchema,
|
|
96
|
+
outputSchema,
|
|
97
|
+
includeInPrompt: !0
|
|
98
|
+
}), this._clone({ tools: newTools });
|
|
99
|
+
}
|
|
100
|
+
defineTool(name, description, inputSchemaOrHandler, outputSchemaOrHandler, handler) {
|
|
101
|
+
let inputSchema, outputSchema, actualHandler;
|
|
102
|
+
typeof inputSchemaOrHandler == "function" ? (inputSchema = { toJsonSchema: () => ({ type: "object" }) }, outputSchema = { toJsonSchema: () => ({ type: "object" }) }, actualHandler = inputSchemaOrHandler) : typeof outputSchemaOrHandler == "function" ? (inputSchema = inputSchemaOrHandler, outputSchema = { toJsonSchema: () => ({ type: "object" }) }, actualHandler = outputSchemaOrHandler) : (inputSchema = inputSchemaOrHandler, outputSchema = outputSchemaOrHandler, actualHandler = handler);
|
|
103
|
+
const newTools = new Map(this._tools);
|
|
104
|
+
return newTools.set(name, {
|
|
105
|
+
name,
|
|
106
|
+
description,
|
|
107
|
+
handler: actualHandler,
|
|
108
|
+
inputSchema,
|
|
109
|
+
outputSchema,
|
|
110
|
+
includeInPrompt: !1
|
|
111
|
+
}), this._clone({ tools: newTools });
|
|
112
|
+
}
|
|
113
|
+
skill(pathOrDef) {
|
|
114
|
+
return typeof pathOrDef == "string" ? this._clone({ skills: [...this._skills, { type: "stored", path: pathOrDef }] }) : (validateSkillName(pathOrDef.name), validateSkillDescription(pathOrDef.description), this._clone({
|
|
115
|
+
skills: [...this._skills, {
|
|
116
|
+
type: "virtual",
|
|
117
|
+
skill: {
|
|
118
|
+
name: pathOrDef.name,
|
|
119
|
+
description: pathOrDef.description,
|
|
120
|
+
body: pathOrDef.body,
|
|
121
|
+
tools: pathOrDef.tools
|
|
216
122
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
123
|
+
}]
|
|
124
|
+
}));
|
|
125
|
+
}
|
|
126
|
+
cwd(path) {
|
|
127
|
+
return this._clone({ cwd: path });
|
|
128
|
+
}
|
|
129
|
+
async _resolveSkills() {
|
|
130
|
+
const resolved = [];
|
|
131
|
+
for (const deferred of this._skills)
|
|
132
|
+
if (deferred.type === "virtual")
|
|
133
|
+
resolved.push(deferred.skill);
|
|
134
|
+
else {
|
|
135
|
+
const content = await readFile(deferred.path, "utf-8"), parsed = parseSkillMd(content), stored = {
|
|
136
|
+
name: parsed.name,
|
|
137
|
+
description: parsed.description,
|
|
138
|
+
body: parsed.body,
|
|
139
|
+
basePath: dirname(deferred.path)
|
|
140
|
+
};
|
|
141
|
+
resolved.push(stored);
|
|
142
|
+
}
|
|
143
|
+
return resolved;
|
|
144
|
+
}
|
|
145
|
+
_buildSkillsPrompt(skills) {
|
|
146
|
+
if (skills.length === 0)
|
|
147
|
+
return "";
|
|
148
|
+
let xml = `<available_skills>
|
|
149
|
+
`;
|
|
150
|
+
for (const skill of skills)
|
|
151
|
+
xml += ` <skill>
|
|
152
|
+
`, xml += ` <name>${skill.name}</name>
|
|
153
|
+
`, xml += ` <description>${skill.description}</description>
|
|
154
|
+
`, xml += ` </skill>
|
|
155
|
+
`;
|
|
156
|
+
return xml += `</available_skills>
|
|
157
|
+
`, xml += `
|
|
158
|
+
`, xml += `The above skills are available to you. When a task matches a skill's description,
|
|
159
|
+
`, xml += "call the `activate_skill` tool with the skill name to load its full instructions.\n", xml += "If the skill provides tools, use `call_skill_tool` to invoke them.\n", xml += "If the skill references files, use `read_skill_file` to access them.\n", xml + `
|
|
160
|
+
`;
|
|
161
|
+
}
|
|
162
|
+
async run() {
|
|
163
|
+
return this.stream().result;
|
|
164
|
+
}
|
|
165
|
+
stream() {
|
|
166
|
+
const stream = new ThoughtStream();
|
|
167
|
+
return this._executeStream(stream).catch((err) => {
|
|
168
|
+
stream.rejectResult(err instanceof Error ? err : new Error(String(err?.message ?? err))), stream.close();
|
|
169
|
+
}), stream;
|
|
170
|
+
}
|
|
171
|
+
async _executeStream(stream) {
|
|
172
|
+
this._conn.initialized || (await this._conn.connection.initialize({
|
|
173
|
+
protocolVersion: 1,
|
|
174
|
+
clientCapabilities: {}
|
|
175
|
+
}), this._conn.initialized = !0);
|
|
176
|
+
const resolvedSkills = await this._resolveSkills();
|
|
177
|
+
let prompt = this._buildSkillsPrompt(resolvedSkills) + this._promptParts.join("");
|
|
178
|
+
const toolsWithPrompt = Array.from(this._tools.values()).filter((t) => t.includeInPrompt);
|
|
179
|
+
if (toolsWithPrompt.length > 0) {
|
|
180
|
+
prompt += `
|
|
181
|
+
|
|
182
|
+
Available tools:
|
|
183
|
+
`;
|
|
184
|
+
for (const tool of toolsWithPrompt)
|
|
185
|
+
prompt += `- ${tool.name}: ${tool.description}
|
|
186
|
+
`;
|
|
224
187
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
});
|
|
243
|
-
this._conn.initialized = true;
|
|
188
|
+
const serverBuilder = mcpServer("thinkwell");
|
|
189
|
+
let resultReceived = !1, result, resultError, resolveResultReady;
|
|
190
|
+
const resultReady = new Promise((r) => {
|
|
191
|
+
resolveResultReady = r;
|
|
192
|
+
}), rawSchema = this._schemaProvider?.toJsonSchema() ?? { type: "object" }, needsWrap = rawSchema.type !== "object", outputSchema = needsWrap ? { type: "object", properties: { result: rawSchema }, required: ["result"] } : rawSchema, acceptResult = (input) => {
|
|
193
|
+
if (resultReceived)
|
|
194
|
+
return;
|
|
195
|
+
const value = needsWrap ? input.result : input, schemaRequired = rawSchema.required;
|
|
196
|
+
let required = Array.isArray(schemaRequired) ? schemaRequired : void 0;
|
|
197
|
+
if (features.FAULT_INJECTION) {
|
|
198
|
+
const injectedField = process.env.THINKWELL_INJECT_REQUIRED_FIELD;
|
|
199
|
+
injectedField && (required = required ? [...required, injectedField] : [injectedField]);
|
|
200
|
+
}
|
|
201
|
+
if (Array.isArray(required)) {
|
|
202
|
+
if (value == null || typeof value != "object") {
|
|
203
|
+
resultError = new TypeError(`Agent result must be an object when schema has required fields, got ${value === null ? "null" : typeof value}`), resultReceived = !0, resolveResultReady();
|
|
204
|
+
return;
|
|
244
205
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
// Add tool references to the prompt
|
|
250
|
-
const toolsWithPrompt = Array.from(this._tools.values()).filter((t) => t.includeInPrompt);
|
|
251
|
-
if (toolsWithPrompt.length > 0) {
|
|
252
|
-
prompt += "\n\nAvailable tools:\n";
|
|
253
|
-
for (const tool of toolsWithPrompt) {
|
|
254
|
-
prompt += `- ${tool.name}: ${tool.description}\n`;
|
|
255
|
-
}
|
|
206
|
+
const obj = value, missing = required.filter((key) => !Object.hasOwn(obj, key));
|
|
207
|
+
if (missing.length > 0) {
|
|
208
|
+
resultError = new TypeError(`Agent result is missing required field(s): ${missing.join(", ")}`), resultReceived = !0, resolveResultReady();
|
|
209
|
+
return;
|
|
256
210
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
211
|
+
}
|
|
212
|
+
result = value, resultReceived = !0, resolveResultReady();
|
|
213
|
+
};
|
|
214
|
+
prompt += "\n\nWhen you have your answer, call the `return_result` MCP tool with the result.", serverBuilder.tool("return_result", "Return the final result", outputSchema, { type: "object", properties: { success: { type: "boolean" } } }, async (input) => (acceptResult(input), { success: !0 }));
|
|
215
|
+
for (const tool of this._tools.values())
|
|
216
|
+
serverBuilder.tool(tool.name, tool.description, tool.inputSchema.toJsonSchema(), tool.outputSchema.toJsonSchema(), async (input, _context) => tool.handler(input));
|
|
217
|
+
const server = serverBuilder.build(), skillServer = resolvedSkills.length > 0 ? createSkillServer(resolvedSkills) : void 0;
|
|
218
|
+
this._conn.mcpHandler.register(server), skillServer && this._conn.mcpHandler.register(skillServer), this._conn.mcpHandler.setSessionId(this._existingSessionId ?? "pending");
|
|
219
|
+
try {
|
|
220
|
+
let sessionId;
|
|
221
|
+
if (this._existingSessionId)
|
|
222
|
+
sessionId = this._existingSessionId;
|
|
223
|
+
else {
|
|
224
|
+
const mcpServers = [{
|
|
225
|
+
type: "http",
|
|
226
|
+
name: server.name,
|
|
227
|
+
url: server.acpUrl,
|
|
228
|
+
headers: []
|
|
229
|
+
}];
|
|
230
|
+
skillServer && mcpServers.push({
|
|
231
|
+
type: "http",
|
|
232
|
+
name: skillServer.name,
|
|
233
|
+
url: skillServer.acpUrl,
|
|
234
|
+
headers: []
|
|
278
235
|
});
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
let sessionId;
|
|
299
|
-
if (this._existingSessionId) {
|
|
300
|
-
// Reuse existing session
|
|
301
|
-
sessionId = this._existingSessionId;
|
|
302
|
-
}
|
|
303
|
-
else {
|
|
304
|
-
// Create new ephemeral session
|
|
305
|
-
const mcpServers = [{
|
|
306
|
-
type: "http",
|
|
307
|
-
name: server.name,
|
|
308
|
-
url: server.acpUrl,
|
|
309
|
-
headers: [],
|
|
310
|
-
}];
|
|
311
|
-
if (skillServer) {
|
|
312
|
-
mcpServers.push({
|
|
313
|
-
type: "http",
|
|
314
|
-
name: skillServer.name,
|
|
315
|
-
url: skillServer.acpUrl,
|
|
316
|
-
headers: [],
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
|
-
const request = {
|
|
320
|
-
cwd: this._cwd ?? process.cwd(),
|
|
321
|
-
mcpServers,
|
|
322
|
-
};
|
|
323
|
-
const response = await this._conn.connection.newSession(request);
|
|
324
|
-
sessionId = response.sessionId;
|
|
236
|
+
const request = {
|
|
237
|
+
cwd: this._cwd ?? process.cwd(),
|
|
238
|
+
mcpServers
|
|
239
|
+
};
|
|
240
|
+
sessionId = (await this._conn.connection.newSession(request)).sessionId;
|
|
241
|
+
}
|
|
242
|
+
this._conn.mcpHandler.setSessionId(sessionId);
|
|
243
|
+
const session = new ThinkSession(sessionId, this._conn);
|
|
244
|
+
this._conn.sessionHandlers.set(sessionId, session), await this._conn.mcpHandler.waitForToolsDiscovery(sessionId, 2e3);
|
|
245
|
+
try {
|
|
246
|
+
const pendingToolCalls = [], sendTurn = async (text) => {
|
|
247
|
+
const promptPromise = session.sendPrompt(text);
|
|
248
|
+
for (; !resultReceived; ) {
|
|
249
|
+
const update = await session.readUpdate();
|
|
250
|
+
if (update.type === "stop")
|
|
251
|
+
break;
|
|
252
|
+
if (update.type === "tool_start") {
|
|
253
|
+
const toolName = update.title;
|
|
254
|
+
(this._tools.has(toolName) || toolName === "return_result") && pendingToolCalls.push({ id: update.id, name: toolName, input: update.input });
|
|
325
255
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
// Read updates, forwarding events to the stream and watching for result
|
|
337
|
-
while (!resultReceived) {
|
|
338
|
-
const update = await session.readUpdate();
|
|
339
|
-
if (update.type === "stop") {
|
|
340
|
-
if (!resultReceived) {
|
|
341
|
-
stream.rejectResult(new Error("Session ended without calling return_result"));
|
|
342
|
-
}
|
|
343
|
-
break;
|
|
344
|
-
}
|
|
345
|
-
// Forward the event to stream consumers
|
|
346
|
-
stream.pushEvent(update);
|
|
347
|
-
}
|
|
348
|
-
// Wait for the prompt to complete (it should already be done since we got a stop)
|
|
349
|
-
await promptPromise;
|
|
350
|
-
if (resultReceived && result !== undefined) {
|
|
351
|
-
stream.resolveResult(result);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
finally {
|
|
355
|
-
stream.close();
|
|
356
|
-
session.close();
|
|
357
|
-
this._conn.sessionHandlers.delete(sessionId);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
finally {
|
|
361
|
-
// Unregister MCP server(s)
|
|
362
|
-
this._conn.mcpHandler.unregister(server);
|
|
363
|
-
if (skillServer) {
|
|
364
|
-
this._conn.mcpHandler.unregister(skillServer);
|
|
256
|
+
stream.pushEvent(update);
|
|
257
|
+
}
|
|
258
|
+
await promptPromise, !resultReceived && pendingToolCalls.some((c) => c.name === "return_result") && await resultReady;
|
|
259
|
+
};
|
|
260
|
+
for (await sendTurn(prompt); !resultReceived && pendingToolCalls.length > 0; ) {
|
|
261
|
+
const calls = pendingToolCalls.splice(0), results = [];
|
|
262
|
+
for (const call of calls) {
|
|
263
|
+
if (call.name === "return_result") {
|
|
264
|
+
acceptResult(call.input);
|
|
265
|
+
break;
|
|
365
266
|
}
|
|
267
|
+
const tool = this._tools.get(call.name);
|
|
268
|
+
if (tool)
|
|
269
|
+
try {
|
|
270
|
+
const output = await tool.handler(call.input), text = typeof output == "string" ? output : JSON.stringify(output);
|
|
271
|
+
results.push(`Tool "${call.name}" (id: ${call.id}) result:
|
|
272
|
+
${text}`);
|
|
273
|
+
} catch (err) {
|
|
274
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
275
|
+
results.push(`Tool "${call.name}" (id: ${call.id}) error:
|
|
276
|
+
${msg}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (resultReceived || results.length === 0)
|
|
280
|
+
break;
|
|
281
|
+
const followUp = results.join(`
|
|
282
|
+
|
|
283
|
+
`) + "\n\nWhen you have your answer, call the `return_result` MCP tool with the result.";
|
|
284
|
+
await sendTurn(followUp);
|
|
366
285
|
}
|
|
286
|
+
resultError ? stream.rejectResult(resultError) : resultReceived && result !== void 0 ? stream.resolveResult(result) : resultReceived ? stream.rejectResult(new TypeError("Agent returned an undefined value")) : stream.rejectResult(new Error("Agent session ended without returning a result"));
|
|
287
|
+
} finally {
|
|
288
|
+
stream.close(), session.close(), this._conn.sessionHandlers.delete(sessionId);
|
|
289
|
+
}
|
|
290
|
+
} finally {
|
|
291
|
+
this._conn.mcpHandler.unregister(server), skillServer && this._conn.mcpHandler.unregister(skillServer);
|
|
367
292
|
}
|
|
293
|
+
}
|
|
368
294
|
}
|
|
369
|
-
/**
|
|
370
|
-
* Create a new Plan for composing a prompt with tools.
|
|
371
|
-
*
|
|
372
|
-
* This is the factory function for creating Plan instances. It is used
|
|
373
|
-
* internally by `Agent.think()` and `Session.think()`.
|
|
374
|
-
*/
|
|
375
295
|
export function createPlan(conn, schema, existingSessionId) {
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
296
|
+
return new PlanImpl({
|
|
297
|
+
conn,
|
|
298
|
+
promptParts: [],
|
|
299
|
+
tools: /* @__PURE__ */ new Map(),
|
|
300
|
+
skills: [],
|
|
301
|
+
schemaProvider: schema,
|
|
302
|
+
cwd: void 0,
|
|
303
|
+
existingSessionId
|
|
304
|
+
});
|
|
385
305
|
}
|
|
386
|
-
//# sourceMappingURL=think-builder.js.map
|