@oh-my-pi/pi-coding-agent 14.1.1 → 14.2.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/CHANGELOG.md +47 -2
- package/package.json +8 -8
- package/scripts/build-binary.ts +61 -0
- package/src/autoresearch/helpers.ts +10 -0
- package/src/autoresearch/index.ts +1 -11
- package/src/autoresearch/tools/init-experiment.ts +1 -10
- package/src/autoresearch/tools/log-experiment.ts +1 -11
- package/src/autoresearch/tools/run-experiment.ts +1 -10
- package/src/bun-imports.d.ts +6 -0
- package/src/cli/plugin-cli.ts +23 -45
- package/src/commit/agentic/tools/propose-commit.ts +1 -14
- package/src/commit/agentic/tools/split-commit.ts +1 -15
- package/src/commit/utils.ts +15 -1
- package/src/config/model-registry.ts +3 -3
- package/src/config/prompt-templates.ts +4 -12
- package/src/config/settings-schema.ts +27 -2
- package/src/config/settings.ts +1 -1
- package/src/discovery/claude-plugins.ts +61 -6
- package/src/discovery/codex.ts +2 -15
- package/src/discovery/gemini.ts +2 -15
- package/src/discovery/helpers.ts +40 -1
- package/src/discovery/opencode.ts +2 -15
- package/src/edit/apply-patch/index.ts +87 -0
- package/src/edit/apply-patch/parser.ts +174 -0
- package/src/edit/diff.ts +3 -14
- package/src/edit/index.ts +65 -2
- package/src/edit/modes/apply-patch.lark +19 -0
- package/src/edit/modes/apply-patch.ts +63 -0
- package/src/edit/modes/hashline.ts +3 -3
- package/src/edit/modes/replace.ts +2 -13
- package/src/edit/read-file.ts +18 -0
- package/src/edit/renderer.ts +61 -33
- package/src/extensibility/extensions/compact-handler.ts +40 -0
- package/src/extensibility/extensions/runner.ts +11 -29
- package/src/extensibility/utils.ts +7 -1
- package/src/internal-urls/docs-index.generated.ts +9 -2
- package/src/lsp/render.ts +14 -2
- package/src/main.ts +1 -0
- package/src/mcp/manager.ts +29 -48
- package/src/memories/index.ts +7 -1
- package/src/modes/acp/acp-agent.ts +3 -16
- package/src/modes/components/model-selector.ts +15 -24
- package/src/modes/components/plugin-settings.ts +16 -5
- package/src/modes/components/read-tool-group.ts +92 -9
- package/src/modes/components/settings-defs.ts +18 -0
- package/src/modes/components/settings-selector.ts +2 -6
- package/src/modes/components/tool-execution.ts +61 -28
- package/src/modes/controllers/event-controller.ts +3 -1
- package/src/modes/controllers/extension-ui-controller.ts +99 -150
- package/src/modes/controllers/selector-controller.ts +3 -12
- package/src/modes/interactive-mode.ts +4 -2
- package/src/modes/print-mode.ts +4 -22
- package/src/modes/rpc/rpc-mode.ts +18 -38
- package/src/modes/shared.ts +10 -1
- package/src/modes/utils/ui-helpers.ts +6 -2
- package/src/plan-mode/approved-plan.ts +5 -4
- package/src/prompts/system/subagent-system-prompt.md +4 -4
- package/src/prompts/system/subagent-user-prompt.md +2 -2
- package/src/prompts/system/system-prompt.md +208 -243
- package/src/prompts/tools/apply-patch.md +67 -0
- package/src/prompts/tools/ast-edit.md +18 -23
- package/src/prompts/tools/ast-grep.md +24 -32
- package/src/prompts/tools/bash.md +11 -23
- package/src/prompts/tools/debug.md +8 -22
- package/src/prompts/tools/find.md +0 -4
- package/src/prompts/tools/grep.md +3 -5
- package/src/prompts/tools/hashline.md +16 -10
- package/src/prompts/tools/python.md +10 -14
- package/src/prompts/tools/read.md +17 -24
- package/src/prompts/tools/task.md +57 -21
- package/src/prompts/tools/todo-write.md +45 -67
- package/src/session/agent-session.ts +4 -4
- package/src/session/session-manager.ts +15 -7
- package/src/session/streaming-output.ts +24 -0
- package/src/slash-commands/builtin-registry.ts +3 -14
- package/src/task/executor.ts +13 -34
- package/src/task/index.ts +82 -18
- package/src/task/simple-mode.ts +27 -0
- package/src/task/template.ts +17 -3
- package/src/task/types.ts +77 -30
- package/src/tools/ask.ts +2 -4
- package/src/tools/ast-edit.ts +4 -15
- package/src/tools/ast-grep.ts +8 -27
- package/src/tools/bash-skill-urls.ts +9 -7
- package/src/tools/bash.ts +4 -12
- package/src/tools/browser.ts +1 -1
- package/src/tools/fetch.ts +1 -14
- package/src/tools/file-recorder.ts +35 -0
- package/src/tools/find.ts +6 -3
- package/src/tools/gh-format.ts +12 -0
- package/src/tools/gh-renderer.ts +1 -8
- package/src/tools/gh.ts +6 -13
- package/src/tools/grep.ts +9 -22
- package/src/tools/jtd-to-json-schema.ts +16 -0
- package/src/tools/match-line-format.ts +20 -0
- package/src/tools/path-utils.ts +30 -2
- package/src/tools/plan-mode-guard.ts +6 -5
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +1 -1
- package/src/tools/render-utils.ts +38 -6
- package/src/tools/renderers.ts +1 -0
- package/src/tools/ssh.ts +3 -11
- package/src/tools/submit-result.ts +1 -13
- package/src/tools/todo-write.ts +137 -103
- package/src/tools/write.ts +2 -23
- package/src/tui/code-cell.ts +12 -7
- package/src/utils/edit-mode.ts +3 -2
- package/src/utils/git.ts +1 -1
- package/src/vim/engine.ts +41 -58
- package/src/web/scrapers/crates-io.ts +1 -14
- package/src/web/scrapers/types.ts +13 -0
- package/src/web/search/providers/base.ts +13 -0
- package/src/web/search/providers/brave.ts +2 -5
- package/src/web/search/providers/codex.ts +20 -24
- package/src/web/search/providers/gemini.ts +39 -1
- package/src/web/search/providers/jina.ts +2 -5
- package/src/web/search/providers/kagi.ts +3 -8
- package/src/web/search/providers/kimi.ts +3 -7
- package/src/web/search/providers/parallel.ts +3 -8
- package/src/web/search/providers/synthetic.ts +3 -7
- package/src/web/search/providers/tavily.ts +15 -11
- package/src/web/search/providers/utils.ts +36 -0
- package/src/web/search/providers/zai.ts +3 -7
package/src/task/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import path from "node:path";
|
|
|
18
18
|
import type { AgentTool, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
19
19
|
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
20
20
|
import { $env, prompt, Snowflake } from "@oh-my-pi/pi-utils";
|
|
21
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
21
22
|
import type { ToolSession } from "..";
|
|
22
23
|
import { resolveAgentModelPatterns } from "../config/model-resolver";
|
|
23
24
|
import type { Theme } from "../modes/theme/theme";
|
|
@@ -34,17 +35,16 @@ import { runSubprocess } from "./executor";
|
|
|
34
35
|
import { resolveIsolationBackendForTaskExecution } from "./isolation-backend";
|
|
35
36
|
import { AgentOutputManager } from "./output-manager";
|
|
36
37
|
import { mapWithConcurrencyLimit, Semaphore } from "./parallel";
|
|
37
|
-
import {
|
|
38
|
+
import { renderResult, renderCall as renderTaskCall } from "./render";
|
|
39
|
+
import { getTaskSimpleModeCapabilities, type TaskSimpleMode } from "./simple-mode";
|
|
38
40
|
import { renderTemplate } from "./template";
|
|
39
41
|
import {
|
|
40
42
|
type AgentDefinition,
|
|
41
43
|
type AgentProgress,
|
|
44
|
+
getTaskSchema,
|
|
42
45
|
type SingleResult,
|
|
43
46
|
type TaskParams,
|
|
44
|
-
type TaskSchema,
|
|
45
47
|
type TaskToolDetails,
|
|
46
|
-
taskSchema,
|
|
47
|
-
taskSchemaNoIsolation,
|
|
48
48
|
} from "./types";
|
|
49
49
|
import {
|
|
50
50
|
applyBaseline,
|
|
@@ -133,16 +133,54 @@ function renderDescription(
|
|
|
133
133
|
isolationEnabled: boolean,
|
|
134
134
|
asyncEnabled: boolean,
|
|
135
135
|
disabledAgents: string[],
|
|
136
|
+
simpleMode: TaskSimpleMode,
|
|
136
137
|
): string {
|
|
137
138
|
const filteredAgents = disabledAgents.length > 0 ? agents.filter(a => !disabledAgents.includes(a.name)) : agents;
|
|
139
|
+
const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(simpleMode);
|
|
138
140
|
return prompt.render(taskDescriptionTemplate, {
|
|
139
141
|
agents: filteredAgents,
|
|
140
142
|
MAX_CONCURRENCY: maxConcurrency,
|
|
141
143
|
isolationEnabled,
|
|
142
144
|
asyncEnabled,
|
|
145
|
+
contextEnabled,
|
|
146
|
+
customSchemaEnabled,
|
|
147
|
+
defaultMode: simpleMode === "default",
|
|
148
|
+
schemaFreeMode: simpleMode === "schema-free",
|
|
149
|
+
independentMode: simpleMode === "independent",
|
|
143
150
|
});
|
|
144
151
|
}
|
|
145
152
|
|
|
153
|
+
function createTaskModeError(text: string): AgentToolResult<TaskToolDetails> {
|
|
154
|
+
return {
|
|
155
|
+
content: [{ type: "text", text }],
|
|
156
|
+
details: { projectAgentsDir: null, results: [], totalDurationMs: 0 },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function validateTaskModeParams(simpleMode: TaskSimpleMode, params: TaskParams): string | undefined {
|
|
161
|
+
const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(simpleMode);
|
|
162
|
+
const disallowedFields: string[] = [];
|
|
163
|
+
if (!contextEnabled && params.context !== undefined) {
|
|
164
|
+
disallowedFields.push("context");
|
|
165
|
+
}
|
|
166
|
+
if (!customSchemaEnabled && params.schema !== undefined) {
|
|
167
|
+
disallowedFields.push("schema");
|
|
168
|
+
}
|
|
169
|
+
if (disallowedFields.length === 0) {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (simpleMode === "schema-free") {
|
|
174
|
+
return "task.simple is set to schema-free, so the task tool does not accept `schema`. Remove it and rely on the selected agent definition or inherited session schema.";
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (disallowedFields.length === 1) {
|
|
178
|
+
return `task.simple is set to independent, so the task tool does not accept \`${disallowedFields[0]}\`. Put everything the subagent needs inside each task assignment.`;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return "task.simple is set to independent, so the task tool does not accept `context` or `schema`. Put all required background and output expectations inside each task assignment or the selected agent definition.";
|
|
182
|
+
}
|
|
183
|
+
|
|
146
184
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
147
185
|
// Tool Class
|
|
148
186
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -153,16 +191,23 @@ function renderDescription(
|
|
|
153
191
|
* Requires async initialization to discover available agents.
|
|
154
192
|
* Use `TaskTool.create(session)` to instantiate.
|
|
155
193
|
*/
|
|
156
|
-
export class TaskTool implements AgentTool<
|
|
194
|
+
export class TaskTool implements AgentTool<TSchema, TaskToolDetails, Theme> {
|
|
157
195
|
readonly name = "task";
|
|
158
196
|
readonly label = "Task";
|
|
159
197
|
readonly strict = true;
|
|
160
|
-
readonly parameters: TaskSchema;
|
|
161
|
-
readonly renderCall = renderCall;
|
|
162
198
|
readonly renderResult = renderResult;
|
|
163
199
|
readonly #discoveredAgents: AgentDefinition[];
|
|
164
200
|
readonly #blockedAgent: string | undefined;
|
|
165
201
|
|
|
202
|
+
get parameters(): TSchema {
|
|
203
|
+
const isolationEnabled = this.session.settings.get("task.isolation.mode") !== "none";
|
|
204
|
+
return getTaskSchema({ isolationEnabled, simpleMode: this.#getTaskSimpleMode() });
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
renderCall(args: unknown, options: Parameters<typeof renderTaskCall>[1], theme: Theme) {
|
|
208
|
+
return renderTaskCall(args as TaskParams, options, theme);
|
|
209
|
+
}
|
|
210
|
+
|
|
166
211
|
/** Dynamic description that reflects current disabled-agent settings */
|
|
167
212
|
get description(): string {
|
|
168
213
|
const disabledAgents = this.session.settings.get("task.disabledAgents") as string[];
|
|
@@ -174,33 +219,42 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
174
219
|
isolationMode !== "none",
|
|
175
220
|
this.session.settings.get("async.enabled"),
|
|
176
221
|
disabledAgents,
|
|
222
|
+
this.#getTaskSimpleMode(),
|
|
177
223
|
);
|
|
178
224
|
}
|
|
179
225
|
private constructor(
|
|
180
226
|
private readonly session: ToolSession,
|
|
181
227
|
discoveredAgents: AgentDefinition[],
|
|
182
|
-
isolationEnabled: boolean,
|
|
183
228
|
) {
|
|
184
|
-
this.parameters = isolationEnabled ? taskSchema : taskSchemaNoIsolation;
|
|
185
229
|
this.#blockedAgent = $env.PI_BLOCKED_AGENT;
|
|
186
230
|
this.#discoveredAgents = discoveredAgents;
|
|
187
231
|
}
|
|
188
232
|
|
|
233
|
+
#getTaskSimpleMode(): TaskSimpleMode {
|
|
234
|
+
return this.session.settings.get("task.simple");
|
|
235
|
+
}
|
|
236
|
+
|
|
189
237
|
/**
|
|
190
238
|
* Create a TaskTool instance with async agent discovery.
|
|
191
239
|
*/
|
|
192
240
|
static async create(session: ToolSession): Promise<TaskTool> {
|
|
193
|
-
const isolationMode = session.settings.get("task.isolation.mode");
|
|
194
241
|
const { agents } = await discoverAgents(session.cwd);
|
|
195
|
-
return new TaskTool(session, agents
|
|
242
|
+
return new TaskTool(session, agents);
|
|
196
243
|
}
|
|
197
244
|
|
|
198
245
|
async execute(
|
|
199
246
|
_toolCallId: string,
|
|
200
|
-
|
|
247
|
+
rawParams: unknown,
|
|
201
248
|
signal?: AbortSignal,
|
|
202
249
|
onUpdate?: AgentToolUpdateCallback<TaskToolDetails>,
|
|
203
250
|
): Promise<AgentToolResult<TaskToolDetails>> {
|
|
251
|
+
const params = rawParams as TaskParams;
|
|
252
|
+
const simpleMode = this.#getTaskSimpleMode();
|
|
253
|
+
const validationError = validateTaskModeParams(simpleMode, params);
|
|
254
|
+
if (validationError) {
|
|
255
|
+
return createTaskModeError(validationError);
|
|
256
|
+
}
|
|
257
|
+
|
|
204
258
|
const asyncEnabled = this.session.settings.get("async.enabled");
|
|
205
259
|
const selectedAgent = this.#discoveredAgents.find(agent => agent.name === params.agent);
|
|
206
260
|
if (!asyncEnabled || selectedAgent?.blocking === true) {
|
|
@@ -225,7 +279,9 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
225
279
|
const uniqueIds = await outputManager.allocateBatch(taskItems.map(t => t.id));
|
|
226
280
|
const fallbackAgentSource =
|
|
227
281
|
this.#discoveredAgents.find(agent => agent.name === params.agent)?.source ?? "bundled";
|
|
228
|
-
const
|
|
282
|
+
const { contextEnabled } = getTaskSimpleModeCapabilities(simpleMode);
|
|
283
|
+
const sharedContext = contextEnabled ? params.context : undefined;
|
|
284
|
+
const renderedTasks = taskItems.map(taskItem => renderTemplate(sharedContext, taskItem, simpleMode));
|
|
229
285
|
const progressByTaskId = new Map<string, AgentProgress>();
|
|
230
286
|
for (let index = 0; index < renderedTasks.length; index++) {
|
|
231
287
|
const renderedTask = renderedTasks[index];
|
|
@@ -445,6 +501,9 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
445
501
|
const startTime = Date.now();
|
|
446
502
|
const { agents, projectAgentsDir } = await discoverAgents(this.session.cwd);
|
|
447
503
|
const { agent: agentName, context, schema: outputSchema } = params;
|
|
504
|
+
const simpleMode = this.#getTaskSimpleMode();
|
|
505
|
+
const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(simpleMode);
|
|
506
|
+
const sharedContext = contextEnabled ? context : undefined;
|
|
448
507
|
const isolationMode = this.session.settings.get("task.isolation.mode");
|
|
449
508
|
const isolationRequested = "isolated" in params ? params.isolated === true : false;
|
|
450
509
|
const isIsolated = isolationMode !== "none" && isolationRequested;
|
|
@@ -530,8 +589,11 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
530
589
|
});
|
|
531
590
|
const thinkingLevelOverride = effectiveAgent.thinkingLevel;
|
|
532
591
|
|
|
533
|
-
// Output schema priority:
|
|
534
|
-
|
|
592
|
+
// Output schema priority: task call > agent frontmatter > inherited parent session.
|
|
593
|
+
// task.simple can disable the task-call override while leaving agent/session schemas intact.
|
|
594
|
+
const effectiveOutputSchema = customSchemaEnabled
|
|
595
|
+
? (outputSchema ?? effectiveAgent.output ?? this.session.outputSchema)
|
|
596
|
+
: (effectiveAgent.output ?? this.session.outputSchema);
|
|
535
597
|
|
|
536
598
|
// Handle empty or missing tasks
|
|
537
599
|
if (!params.tasks || params.tasks.length === 0) {
|
|
@@ -539,7 +601,9 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
539
601
|
content: [
|
|
540
602
|
{
|
|
541
603
|
type: "text",
|
|
542
|
-
text:
|
|
604
|
+
text: contextEnabled
|
|
605
|
+
? "No tasks provided. Use: { agent, context?, tasks: [{ id, description, assignment }, ...] }"
|
|
606
|
+
: "No tasks provided. Use: { agent, tasks: [{ id, description, assignment }, ...] }",
|
|
543
607
|
},
|
|
544
608
|
],
|
|
545
609
|
details: {
|
|
@@ -728,8 +792,8 @@ export class TaskTool implements AgentTool<TaskSchema, TaskToolDetails, Theme> {
|
|
|
728
792
|
}
|
|
729
793
|
const tasksWithUniqueIds = tasks.map((t, i) => ({ ...t, id: uniqueIds[i] }));
|
|
730
794
|
|
|
731
|
-
// Build full prompts
|
|
732
|
-
const tasksWithContext = tasksWithUniqueIds.map(t => renderTemplate(
|
|
795
|
+
// Build full prompts using shared context only when the current task mode allows it.
|
|
796
|
+
const tasksWithContext = tasksWithUniqueIds.map(t => renderTemplate(sharedContext, t, simpleMode));
|
|
733
797
|
const availableSkills = [...(this.session.skills ?? [])];
|
|
734
798
|
const contextFiles = this.session.contextFiles?.filter(
|
|
735
799
|
file => path.basename(file.path).toLowerCase() !== "agents.md",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const TASK_SIMPLE_MODES = ["default", "schema-free", "independent"] as const;
|
|
2
|
+
|
|
3
|
+
export type TaskSimpleMode = (typeof TASK_SIMPLE_MODES)[number];
|
|
4
|
+
|
|
5
|
+
interface TaskSimpleModeCapabilities {
|
|
6
|
+
contextEnabled: boolean;
|
|
7
|
+
customSchemaEnabled: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const TASK_SIMPLE_MODE_CAPABILITIES: Record<TaskSimpleMode, TaskSimpleModeCapabilities> = {
|
|
11
|
+
default: {
|
|
12
|
+
contextEnabled: true,
|
|
13
|
+
customSchemaEnabled: true,
|
|
14
|
+
},
|
|
15
|
+
"schema-free": {
|
|
16
|
+
contextEnabled: true,
|
|
17
|
+
customSchemaEnabled: false,
|
|
18
|
+
},
|
|
19
|
+
independent: {
|
|
20
|
+
contextEnabled: false,
|
|
21
|
+
customSchemaEnabled: false,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export function getTaskSimpleModeCapabilities(mode: TaskSimpleMode): TaskSimpleModeCapabilities {
|
|
26
|
+
return TASK_SIMPLE_MODE_CAPABILITIES[mode];
|
|
27
|
+
}
|
package/src/task/template.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import subagentUserPromptTemplate from "../prompts/system/subagent-user-prompt.md" with { type: "text" };
|
|
3
|
+
import { getTaskSimpleModeCapabilities, type TaskSimpleMode } from "./simple-mode";
|
|
3
4
|
import type { TaskItem } from "./types";
|
|
4
5
|
|
|
5
6
|
interface RenderResult {
|
|
@@ -16,16 +17,29 @@ interface RenderResult {
|
|
|
16
17
|
*
|
|
17
18
|
* If context is provided, it is prepended with a separator.
|
|
18
19
|
*/
|
|
19
|
-
export function renderTemplate(
|
|
20
|
+
export function renderTemplate(
|
|
21
|
+
context: string | undefined,
|
|
22
|
+
task: TaskItem,
|
|
23
|
+
simpleMode: TaskSimpleMode = "default",
|
|
24
|
+
): RenderResult {
|
|
20
25
|
let { id, description, assignment } = task;
|
|
21
26
|
assignment = assignment.trim();
|
|
22
|
-
|
|
27
|
+
const { contextEnabled } = getTaskSimpleModeCapabilities(simpleMode);
|
|
28
|
+
context = contextEnabled ? context?.trim() : undefined;
|
|
23
29
|
|
|
24
30
|
if (!context || !assignment) {
|
|
31
|
+
if (simpleMode === "independent" && assignment) {
|
|
32
|
+
return {
|
|
33
|
+
task: prompt.render(subagentUserPromptTemplate, { assignment, independentMode: true }),
|
|
34
|
+
assignment,
|
|
35
|
+
id,
|
|
36
|
+
description,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
25
39
|
return { task: assignment || context!, assignment: assignment || context!, id, description };
|
|
26
40
|
}
|
|
27
41
|
return {
|
|
28
|
-
task: prompt.render(subagentUserPromptTemplate, { context, assignment }),
|
|
42
|
+
task: prompt.render(subagentUserPromptTemplate, { context, assignment, independentMode: false }),
|
|
29
43
|
assignment,
|
|
30
44
|
id,
|
|
31
45
|
description,
|
package/src/task/types.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Usage } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import { $env } from "@oh-my-pi/pi-utils";
|
|
4
|
-
import { type Static, Type } from "@sinclair/typebox";
|
|
4
|
+
import { type Static, type TSchema, Type } from "@sinclair/typebox";
|
|
5
|
+
import { getTaskSimpleModeCapabilities, type TaskSimpleMode } from "./simple-mode";
|
|
5
6
|
import type { NestedRepoPatch } from "./worktree";
|
|
6
7
|
|
|
7
8
|
/** Source of an agent definition */
|
|
@@ -56,42 +57,58 @@ export interface SubagentLifecyclePayload {
|
|
|
56
57
|
index: number;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
})
|
|
60
|
+
const assignmentDescriptionForContextEnabled =
|
|
61
|
+
"Complete per-task instructions the subagent executes. Must follow the Target/Change/Edge Cases/Acceptance structure. Only include per-task deltas — shared background belongs in `context`.";
|
|
62
|
+
const assignmentDescriptionForContextDisabled =
|
|
63
|
+
"Complete per-task instructions the subagent executes. Must follow the Target/Change/Edge Cases/Acceptance structure, and include any background that would otherwise live in `context` since shared context is disabled in this mode.";
|
|
64
|
+
|
|
65
|
+
const createTaskItemSchema = (contextEnabled: boolean) =>
|
|
66
|
+
Type.Object({
|
|
67
|
+
id: Type.String({
|
|
68
|
+
description: "CamelCase identifier, max 48 chars",
|
|
69
|
+
maxLength: 48,
|
|
70
|
+
}),
|
|
71
|
+
description: Type.String({
|
|
72
|
+
description: "Short one-liner for UI display only — not seen by the subagent",
|
|
73
|
+
}),
|
|
74
|
+
assignment: Type.String({
|
|
75
|
+
description: contextEnabled ? assignmentDescriptionForContextEnabled : assignmentDescriptionForContextDisabled,
|
|
76
|
+
}),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/** Single task item for parallel execution (default shape with context enabled). */
|
|
80
|
+
export const taskItemSchema = createTaskItemSchema(true);
|
|
73
81
|
export type TaskItem = Static<typeof taskItemSchema>;
|
|
74
82
|
|
|
75
|
-
const createTaskSchema = (options: { isolationEnabled: boolean }) => {
|
|
76
|
-
const
|
|
83
|
+
const createTaskSchema = (options: { isolationEnabled: boolean; simpleMode: TaskSimpleMode }) => {
|
|
84
|
+
const { contextEnabled, customSchemaEnabled } = getTaskSimpleModeCapabilities(options.simpleMode);
|
|
85
|
+
const itemSchema = createTaskItemSchema(contextEnabled);
|
|
86
|
+
const properties: Record<string, TSchema> = {
|
|
77
87
|
agent: Type.String({ description: "Agent type for all tasks in this batch" }),
|
|
78
|
-
|
|
88
|
+
tasks: Type.Array(itemSchema, {
|
|
89
|
+
description: contextEnabled
|
|
90
|
+
? "Tasks to execute in parallel. Each must be small-scoped (3-5 files max) and self-contained given context + assignment."
|
|
91
|
+
: "Tasks to execute in parallel. Each must be small-scoped (3-5 files max) and fully self-contained inside assignment because shared context is disabled.",
|
|
92
|
+
}),
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
if (contextEnabled) {
|
|
96
|
+
properties.context = Type.Optional(
|
|
79
97
|
Type.String({
|
|
80
98
|
description:
|
|
81
99
|
"Shared background prepended to every task's assignment. Put goal, non-goals, constraints, conventions, reference paths, API contracts, and global acceptance commands here once — instead of duplicating across assignments.",
|
|
82
100
|
}),
|
|
83
|
-
)
|
|
84
|
-
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (customSchemaEnabled) {
|
|
105
|
+
properties.schema = Type.Optional(
|
|
85
106
|
Type.String({
|
|
86
107
|
description:
|
|
87
108
|
"JSON-encoded JTD schema defining expected response structure. Output format belongs here — never in context or assignment.",
|
|
88
109
|
}),
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
description:
|
|
92
|
-
"Tasks to execute in parallel. Each must be small-scoped (3-5 files max) and self-contained given context + assignment.",
|
|
93
|
-
}),
|
|
94
|
-
};
|
|
110
|
+
);
|
|
111
|
+
}
|
|
95
112
|
|
|
96
113
|
if (options.isolationEnabled) {
|
|
97
114
|
return Type.Object({
|
|
@@ -107,12 +124,42 @@ const createTaskSchema = (options: { isolationEnabled: boolean }) => {
|
|
|
107
124
|
return Type.Object(properties);
|
|
108
125
|
};
|
|
109
126
|
|
|
110
|
-
export const taskSchema = createTaskSchema({ isolationEnabled: true });
|
|
111
|
-
export const taskSchemaNoIsolation = createTaskSchema({ isolationEnabled: false });
|
|
127
|
+
export const taskSchema = createTaskSchema({ isolationEnabled: true, simpleMode: "default" });
|
|
128
|
+
export const taskSchemaNoIsolation = createTaskSchema({ isolationEnabled: false, simpleMode: "default" });
|
|
129
|
+
const taskSchemaSchemaFree = createTaskSchema({ isolationEnabled: true, simpleMode: "schema-free" });
|
|
130
|
+
const taskSchemaSchemaFreeNoIsolation = createTaskSchema({ isolationEnabled: false, simpleMode: "schema-free" });
|
|
131
|
+
const taskSchemaIndependent = createTaskSchema({ isolationEnabled: true, simpleMode: "independent" });
|
|
132
|
+
const taskSchemaIndependentNoIsolation = createTaskSchema({ isolationEnabled: false, simpleMode: "independent" });
|
|
133
|
+
const ALL_TASK_SCHEMAS = [
|
|
134
|
+
taskSchema,
|
|
135
|
+
taskSchemaNoIsolation,
|
|
136
|
+
taskSchemaSchemaFree,
|
|
137
|
+
taskSchemaSchemaFreeNoIsolation,
|
|
138
|
+
taskSchemaIndependent,
|
|
139
|
+
taskSchemaIndependentNoIsolation,
|
|
140
|
+
] as const;
|
|
112
141
|
|
|
113
|
-
|
|
142
|
+
type DynamicTaskSchema = (typeof ALL_TASK_SCHEMAS)[number];
|
|
143
|
+
export type TaskSchema = typeof taskSchema;
|
|
114
144
|
|
|
115
|
-
export
|
|
145
|
+
export function getTaskSchema(options: { isolationEnabled: boolean; simpleMode: TaskSimpleMode }): DynamicTaskSchema {
|
|
146
|
+
switch (options.simpleMode) {
|
|
147
|
+
case "schema-free":
|
|
148
|
+
return options.isolationEnabled ? taskSchemaSchemaFree : taskSchemaSchemaFreeNoIsolation;
|
|
149
|
+
case "independent":
|
|
150
|
+
return options.isolationEnabled ? taskSchemaIndependent : taskSchemaIndependentNoIsolation;
|
|
151
|
+
default:
|
|
152
|
+
return options.isolationEnabled ? taskSchema : taskSchemaNoIsolation;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface TaskParams {
|
|
157
|
+
agent: string;
|
|
158
|
+
context?: string;
|
|
159
|
+
schema?: string;
|
|
160
|
+
tasks: TaskItem[];
|
|
161
|
+
isolated?: boolean;
|
|
162
|
+
}
|
|
116
163
|
|
|
117
164
|
/** A code review finding reported by the reviewer agent */
|
|
118
165
|
export interface ReviewFinding {
|
package/src/tools/ask.ts
CHANGED
|
@@ -407,10 +407,8 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
|
|
|
407
407
|
): Promise<AgentToolResult<AskToolDetails>> {
|
|
408
408
|
// Headless fallback
|
|
409
409
|
if (!context?.hasUI || !context.ui) {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
details: {},
|
|
413
|
-
};
|
|
410
|
+
context?.abort();
|
|
411
|
+
throw new ToolAbortError("Ask tool requires interactive mode");
|
|
414
412
|
}
|
|
415
413
|
|
|
416
414
|
const extensionUi = context.ui;
|
package/src/tools/ast-edit.ts
CHANGED
|
@@ -12,6 +12,7 @@ import astEditDescription from "../prompts/tools/ast-edit.md" with { type: "text
|
|
|
12
12
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
13
13
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
14
14
|
import type { ToolSession } from ".";
|
|
15
|
+
import { createFileRecorder, formatResultPath } from "./file-recorder";
|
|
15
16
|
import type { OutputMeta } from "./output-meta";
|
|
16
17
|
import {
|
|
17
18
|
combineSearchGlobs,
|
|
@@ -41,6 +42,7 @@ const astEditOpSchema = Type.Object({
|
|
|
41
42
|
|
|
42
43
|
const astEditSchema = Type.Object({
|
|
43
44
|
ops: Type.Array(astEditOpSchema, {
|
|
45
|
+
minItems: 1,
|
|
44
46
|
description: "Rewrite ops as [{ pat, out }]",
|
|
45
47
|
}),
|
|
46
48
|
lang: Type.Optional(Type.String({ description: "Language override" })),
|
|
@@ -163,24 +165,11 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
163
165
|
});
|
|
164
166
|
|
|
165
167
|
const dedupedParseErrors = dedupeParseErrors(result.parseErrors);
|
|
166
|
-
const formatPath = (filePath: string): string =>
|
|
167
|
-
const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
168
|
-
if (isDirectory) {
|
|
169
|
-
return cleanPath.replace(/\\/g, "/");
|
|
170
|
-
}
|
|
171
|
-
return path.basename(cleanPath);
|
|
172
|
-
};
|
|
168
|
+
const formatPath = (filePath: string): string => formatResultPath(filePath, isDirectory);
|
|
173
169
|
|
|
174
|
-
const
|
|
175
|
-
const fileList: string[] = [];
|
|
170
|
+
const { record: recordFile, list: fileList } = createFileRecorder();
|
|
176
171
|
const fileReplacementCounts = new Map<string, number>();
|
|
177
172
|
const changesByFile = new Map<string, AstReplaceChange[]>();
|
|
178
|
-
const recordFile = (relativePath: string) => {
|
|
179
|
-
if (!files.has(relativePath)) {
|
|
180
|
-
files.add(relativePath);
|
|
181
|
-
fileList.push(relativePath);
|
|
182
|
-
}
|
|
183
|
-
};
|
|
184
173
|
for (const fileChange of result.fileChanges) {
|
|
185
174
|
const relativePath = formatPath(fileChange.path);
|
|
186
175
|
recordFile(relativePath);
|
package/src/tools/ast-grep.ts
CHANGED
|
@@ -5,13 +5,14 @@ import type { Component } from "@oh-my-pi/pi-tui";
|
|
|
5
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
6
6
|
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import { type Static, Type } from "@sinclair/typebox";
|
|
8
|
-
import { computeLineHash } from "../edit/line-hash";
|
|
9
8
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
10
9
|
import type { Theme } from "../modes/theme/theme";
|
|
11
10
|
import astGrepDescription from "../prompts/tools/ast-grep.md" with { type: "text" };
|
|
12
11
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
13
12
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
14
13
|
import type { ToolSession } from ".";
|
|
14
|
+
import { createFileRecorder, formatResultPath } from "./file-recorder";
|
|
15
|
+
import { formatMatchLine } from "./match-line-format";
|
|
15
16
|
import type { OutputMeta } from "./output-meta";
|
|
16
17
|
import {
|
|
17
18
|
combineSearchGlobs,
|
|
@@ -39,8 +40,8 @@ const astGrepSchema = Type.Object({
|
|
|
39
40
|
path: Type.Optional(Type.String({ description: "File, directory, or glob pattern to search (default: cwd)" })),
|
|
40
41
|
glob: Type.Optional(Type.String({ description: "Optional glob filter relative to path" })),
|
|
41
42
|
sel: Type.Optional(Type.String({ description: "Optional selector for contextual pattern mode" })),
|
|
42
|
-
limit: Type.Optional(Type.Number({ description: "Max matches
|
|
43
|
-
offset: Type.Optional(Type.Number({ description: "Skip first N matches
|
|
43
|
+
limit: Type.Optional(Type.Number({ description: "Max matches", default: 50 })),
|
|
44
|
+
offset: Type.Optional(Type.Number({ description: "Skip first N matches", default: 0 })),
|
|
44
45
|
context: Type.Optional(Type.Number({ description: "Context lines around each match" })),
|
|
45
46
|
});
|
|
46
47
|
|
|
@@ -155,24 +156,11 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
155
156
|
return parseError?.[1] ?? error;
|
|
156
157
|
});
|
|
157
158
|
const dedupedParseErrors = dedupeParseErrors(normalizedParseErrors);
|
|
158
|
-
const formatPath = (filePath: string): string =>
|
|
159
|
-
const cleanPath = filePath.startsWith("/") ? filePath.slice(1) : filePath;
|
|
160
|
-
if (isDirectory) {
|
|
161
|
-
return cleanPath.replace(/\\/g, "/");
|
|
162
|
-
}
|
|
163
|
-
return path.basename(cleanPath);
|
|
164
|
-
};
|
|
159
|
+
const formatPath = (filePath: string): string => formatResultPath(filePath, isDirectory);
|
|
165
160
|
|
|
166
|
-
const
|
|
167
|
-
const fileList: string[] = [];
|
|
161
|
+
const { record: recordFile, list: fileList } = createFileRecorder();
|
|
168
162
|
const fileMatchCounts = new Map<string, number>();
|
|
169
163
|
const matchesByFile = new Map<string, AstFindMatch[]>();
|
|
170
|
-
const recordFile = (relativePath: string) => {
|
|
171
|
-
if (!files.has(relativePath)) {
|
|
172
|
-
files.add(relativePath);
|
|
173
|
-
fileList.push(relativePath);
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
164
|
for (const match of result.matches) {
|
|
177
165
|
const relativePath = formatPath(match.path);
|
|
178
166
|
recordFile(relativePath);
|
|
@@ -211,15 +199,8 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
211
199
|
const matchLines = match.text.split("\n");
|
|
212
200
|
const lineNumbers = matchLines.map((_, index) => match.startLine + index);
|
|
213
201
|
const lineWidth = Math.max(...lineNumbers.map(value => value.toString().length));
|
|
214
|
-
const formatLine = (lineNumber: number, line: string, isMatch: boolean): string =>
|
|
215
|
-
|
|
216
|
-
if (useHashLines) {
|
|
217
|
-
const ref = `${lineNumber}#${computeLineHash(lineNumber, line)}`;
|
|
218
|
-
return `${ref}${separator}${line}`;
|
|
219
|
-
}
|
|
220
|
-
const padded = lineNumber.toString().padStart(lineWidth, " ");
|
|
221
|
-
return `${padded}${separator}${line}`;
|
|
222
|
-
};
|
|
202
|
+
const formatLine = (lineNumber: number, line: string, isMatch: boolean): string =>
|
|
203
|
+
formatMatchLine(lineNumber, line, isMatch, { useHashLines, lineWidth });
|
|
223
204
|
for (let index = 0; index < matchLines.length; index++) {
|
|
224
205
|
outputLines.push(formatLine(match.startLine + index, matchLines[index], index === 0));
|
|
225
206
|
}
|
|
@@ -4,14 +4,14 @@ import type { Skill } from "../extensibility/skills";
|
|
|
4
4
|
import { type LocalProtocolOptions, resolveLocalUrlToPath } from "../internal-urls";
|
|
5
5
|
import { validateRelativePath } from "../internal-urls/skill-protocol";
|
|
6
6
|
import type { InternalResource } from "../internal-urls/types";
|
|
7
|
+
import { normalizeLocalScheme } from "./path-utils";
|
|
7
8
|
import { ToolError } from "./tool-errors";
|
|
8
9
|
|
|
9
10
|
/** Regex to find skill:// tokens in command text. */
|
|
10
11
|
const SKILL_URL_PATTERN = /'skill:\/\/[^'\s")`\\]+'|"skill:\/\/[^"\s')`\\]+"|skill:\/\/[^\s'")`\\]+/g;
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/'(?:skill|agent|artifact|plan|memory|rule|local):\/\/[^'\s")`\\]+'|"(?:skill|agent|artifact|plan|memory|rule|local):\/\/[^"\s')`\\]+"|(?:skill|agent|artifact|plan|memory|rule|local):\/\/[^\s'")`\\]+/g;
|
|
13
|
+
const INTERNAL_URL_PATTERN_INCLUDING_NORMALIZED_LOCAL =
|
|
14
|
+
/'(?:skill|agent|artifact|plan|memory|rule|local):\/\/[^'\s")`\\]+'|"(?:skill|agent|artifact|plan|memory|rule|local):\/\/[^"\s')`\\]+"|(?:skill|agent|artifact|plan|memory|rule|local):\/\/[^\s'")`\\]+|'local:\/[^'\s")`\\]+'|"local:\/[^"\s')`\\]+"|(?<![./\\\\\w-])local:\/[^\s'")`\\]+/g;
|
|
15
15
|
|
|
16
16
|
const SUPPORTED_INTERNAL_SCHEMES = ["skill", "agent", "artifact", "plan", "memory", "rule", "local"] as const;
|
|
17
17
|
|
|
@@ -146,12 +146,13 @@ function shellEscape(p: string): string {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
async function resolveInternalUrlToPath(
|
|
149
|
-
|
|
149
|
+
rawUrl: string,
|
|
150
150
|
skills: readonly Skill[],
|
|
151
151
|
internalRouter?: InternalUrlResolver,
|
|
152
152
|
localOptions?: LocalProtocolOptions,
|
|
153
153
|
ensureLocalParentDirs?: boolean,
|
|
154
154
|
): Promise<string> {
|
|
155
|
+
const url = normalizeLocalScheme(rawUrl);
|
|
155
156
|
const scheme = extractScheme(url);
|
|
156
157
|
if (!scheme) {
|
|
157
158
|
throw new ToolError(`Unsupported internal URL in bash command: ${url}`);
|
|
@@ -218,9 +219,9 @@ export function expandSkillUrls(command: string, skills: readonly Skill[]): stri
|
|
|
218
219
|
* Supported schemes: skill://, agent://, artifact://, memory://, rule://, local://
|
|
219
220
|
*/
|
|
220
221
|
export async function expandInternalUrls(command: string, options: InternalUrlExpansionOptions): Promise<string> {
|
|
221
|
-
if (!command.includes("://")) return command;
|
|
222
|
+
if (!command.includes("://") && !command.includes("local:/")) return command;
|
|
222
223
|
|
|
223
|
-
const matches = Array.from(command.matchAll(
|
|
224
|
+
const matches = Array.from(command.matchAll(INTERNAL_URL_PATTERN_INCLUDING_NORMALIZED_LOCAL));
|
|
224
225
|
if (matches.length === 0) return command;
|
|
225
226
|
|
|
226
227
|
let expanded = command;
|
|
@@ -230,7 +231,8 @@ export async function expandInternalUrls(command: string, options: InternalUrlEx
|
|
|
230
231
|
const index = match.index;
|
|
231
232
|
if (index === undefined) continue;
|
|
232
233
|
|
|
233
|
-
const
|
|
234
|
+
const rawUrl = unquoteToken(token);
|
|
235
|
+
const url = normalizeLocalScheme(rawUrl);
|
|
234
236
|
const resolvedPath = await resolveInternalUrlToPath(
|
|
235
237
|
url,
|
|
236
238
|
options.skills,
|
package/src/tools/bash.ts
CHANGED
|
@@ -9,7 +9,7 @@ import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
|
9
9
|
import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
10
10
|
import type { Theme } from "../modes/theme/theme";
|
|
11
11
|
import bashDescription from "../prompts/tools/bash.md" with { type: "text" };
|
|
12
|
-
import { DEFAULT_MAX_BYTES, TailBuffer } from "../session/streaming-output";
|
|
12
|
+
import { DEFAULT_MAX_BYTES, streamTailUpdates, TailBuffer } from "../session/streaming-output";
|
|
13
13
|
import { renderStatusLine } from "../tui";
|
|
14
14
|
import { CachedOutputBlock } from "../tui/output-block";
|
|
15
15
|
import { getSixelLineMask } from "../utils/sixel";
|
|
@@ -38,7 +38,7 @@ const bashSchemaBase = Type.Object({
|
|
|
38
38
|
"Additional environment variables passed to the command and rendered inline as shell assignments; prefer this for multiline or quote-heavy content",
|
|
39
39
|
}),
|
|
40
40
|
),
|
|
41
|
-
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds
|
|
41
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds", default: 300 })),
|
|
42
42
|
cwd: Type.Optional(Type.String({ description: "Working directory (default: cwd)" })),
|
|
43
43
|
head: Type.Optional(Type.Number({ description: "Return only first N lines of output" })),
|
|
44
44
|
tail: Type.Optional(Type.Number({ description: "Return only last N lines of output" })),
|
|
@@ -512,7 +512,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
512
512
|
: undefined;
|
|
513
513
|
|
|
514
514
|
// Resolve protocol URLs (skill://, agent://, etc.) in extracted cwd.
|
|
515
|
-
if (cwd?.includes("://")) {
|
|
515
|
+
if (cwd?.includes("://") || cwd?.includes("local:/")) {
|
|
516
516
|
cwd = await expandInternalUrls(cwd, { ...internalUrlOptions, noEscape: true });
|
|
517
517
|
}
|
|
518
518
|
|
|
@@ -612,15 +612,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
612
612
|
env: resolvedEnv,
|
|
613
613
|
artifactPath,
|
|
614
614
|
artifactId,
|
|
615
|
-
onChunk:
|
|
616
|
-
tailBuffer.append(chunk);
|
|
617
|
-
if (onUpdate) {
|
|
618
|
-
onUpdate({
|
|
619
|
-
content: [{ type: "text", text: tailBuffer.text() }],
|
|
620
|
-
details: {},
|
|
621
|
-
});
|
|
622
|
-
}
|
|
623
|
-
},
|
|
615
|
+
onChunk: streamTailUpdates(tailBuffer, onUpdate),
|
|
624
616
|
});
|
|
625
617
|
if (result.cancelled) {
|
|
626
618
|
if (signal?.aborted) {
|
package/src/tools/browser.ts
CHANGED
|
@@ -411,7 +411,7 @@ const browserSchema = Type.Object({
|
|
|
411
411
|
value: Type.Optional(Type.String({ description: "Value to set (fill)" })),
|
|
412
412
|
attribute: Type.Optional(Type.String({ description: "Attribute name to read (get_attribute)" })),
|
|
413
413
|
key: Type.Optional(Type.String({ description: "Keyboard key to press (press)" })),
|
|
414
|
-
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds
|
|
414
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds", default: 30 })),
|
|
415
415
|
wait_until: Type.Optional(
|
|
416
416
|
StringEnum(["load", "domcontentloaded", "networkidle0", "networkidle2"], {
|
|
417
417
|
description: "Navigation wait condition (goto)",
|