@dyyz1993/pi-coding-agent 0.69.17 → 0.69.23
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/core/agent-session.d.ts +12 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +208 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/client-channel.d.ts +61 -0
- package/dist/core/extensions/client-channel.d.ts.map +1 -0
- package/dist/core/extensions/client-channel.js +67 -0
- package/dist/core/extensions/client-channel.js.map +1 -0
- package/dist/core/extensions/index.d.ts +3 -2
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -0
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +13 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +8 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +49 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/include-resolver.d.ts +18 -0
- package/dist/core/include-resolver.d.ts.map +1 -0
- package/dist/core/include-resolver.js +304 -0
- package/dist/core/include-resolver.js.map +1 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +17 -4
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +8 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +29 -6
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/storage.d.ts +24 -0
- package/dist/core/storage.d.ts.map +1 -0
- package/dist/core/storage.js +55 -0
- package/dist/core/storage.js.map +1 -0
- package/dist/core/tools/path-security.d.ts +15 -0
- package/dist/core/tools/path-security.d.ts.map +1 -0
- package/dist/core/tools/path-security.js +76 -0
- package/dist/core/tools/path-security.js.map +1 -0
- package/dist/core/tools/strip-markdown.d.ts +2 -0
- package/dist/core/tools/strip-markdown.d.ts.map +1 -0
- package/dist/core/tools/strip-markdown.js +8 -0
- package/dist/core/tools/strip-markdown.js.map +1 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +1 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client-types.d.ts +1 -0
- package/dist/modes/rpc/rpc-client-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client-types.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +1 -0
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +3 -0
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +5 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +9 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +9 -5
- package/dist/rules-engine/cache.d.ts +0 -4
- package/dist/rules-engine/cache.d.ts.map +0 -1
- package/dist/rules-engine/cache.js +0 -32
- package/dist/rules-engine/cache.js.map +0 -1
- package/dist/rules-engine/config.d.ts +0 -8
- package/dist/rules-engine/config.d.ts.map +0 -1
- package/dist/rules-engine/config.js +0 -56
- package/dist/rules-engine/config.js.map +0 -1
- package/dist/rules-engine/index.d.ts +0 -10
- package/dist/rules-engine/index.d.ts.map +0 -1
- package/dist/rules-engine/index.js +0 -393
- package/dist/rules-engine/index.js.map +0 -1
- package/dist/rules-engine/injector.d.ts +0 -5
- package/dist/rules-engine/injector.d.ts.map +0 -1
- package/dist/rules-engine/injector.js +0 -57
- package/dist/rules-engine/injector.js.map +0 -1
- package/dist/rules-engine/loader.d.ts +0 -8
- package/dist/rules-engine/loader.d.ts.map +0 -1
- package/dist/rules-engine/loader.js +0 -190
- package/dist/rules-engine/loader.js.map +0 -1
- package/dist/rules-engine/matcher.d.ts +0 -3
- package/dist/rules-engine/matcher.d.ts.map +0 -1
- package/dist/rules-engine/matcher.js +0 -48
- package/dist/rules-engine/matcher.js.map +0 -1
- package/dist/rules-engine/types.d.ts +0 -150
- package/dist/rules-engine/types.d.ts.map +0 -1
- package/dist/rules-engine/types.js +0 -2
- package/dist/rules-engine/types.js.map +0 -1
- package/examples/extensions/auto-session-title.ts +0 -82
- package/examples/extensions/file-snapshot.ts +0 -417
- package/examples/extensions/subagent/README.md +0 -172
- package/examples/extensions/subagent/agents/planner.md +0 -37
- package/examples/extensions/subagent/agents/reviewer.md +0 -35
- package/examples/extensions/subagent/agents/scout.md +0 -50
- package/examples/extensions/subagent/agents/worker.md +0 -24
- package/examples/extensions/subagent/agents.ts +0 -126
- package/examples/extensions/subagent/index.ts +0 -987
- package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
- package/examples/extensions/subagent/prompts/implement.md +0 -10
- package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
- package/examples/extensions/subagent-v2/index.ts +0 -849
|
@@ -12,10 +12,13 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Modes use this class and add their own I/O layer on top.
|
|
14
14
|
*/
|
|
15
|
+
import { randomUUID } from "node:crypto";
|
|
15
16
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
16
17
|
import { basename, dirname, join, resolve } from "node:path";
|
|
17
18
|
import { Agent, } from "@dyyz1993/pi-agent-core";
|
|
18
19
|
import { complete, isContextOverflow, modelsAreEqual, resetApiProviders, supportsXhigh } from "@dyyz1993/pi-ai";
|
|
20
|
+
import { Compile } from "typebox/compile";
|
|
21
|
+
import { Value } from "typebox/value";
|
|
19
22
|
import { getDocsPath } from "../config.js";
|
|
20
23
|
import { theme } from "../modes/interactive/theme/theme.js";
|
|
21
24
|
import { stripFrontmatter } from "../utils/frontmatter.js";
|
|
@@ -33,6 +36,7 @@ import { createSyntheticSourceInfo } from "./source-info.js";
|
|
|
33
36
|
import { buildSystemPrompt } from "./system-prompt.js";
|
|
34
37
|
import { createLocalBashOperations } from "./tools/bash.js";
|
|
35
38
|
import { createAllToolDefinitions, createTool } from "./tools/index.js";
|
|
39
|
+
import { stripMarkdownCodeBlock } from "./tools/strip-markdown.js";
|
|
36
40
|
import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
|
|
37
41
|
/**
|
|
38
42
|
* Parse a skill block from message text.
|
|
@@ -106,6 +110,8 @@ export class AgentSession {
|
|
|
106
110
|
_extensionErrorListener;
|
|
107
111
|
_extensionErrorUnsubscriber;
|
|
108
112
|
_registerChannel;
|
|
113
|
+
_sessionAbortController = new AbortController();
|
|
114
|
+
_backgroundTasks = new Set();
|
|
109
115
|
// Model registry for API key resolution
|
|
110
116
|
_modelRegistry;
|
|
111
117
|
// Tool registry for extension getTools/setTools
|
|
@@ -494,6 +500,12 @@ export class AgentSession {
|
|
|
494
500
|
*/
|
|
495
501
|
dispose() {
|
|
496
502
|
this._extensionRunner.invalidate("This extension instance is stale after session replacement or reload. Use the provided replacement-session context instead.");
|
|
503
|
+
this._sessionAbortController.abort();
|
|
504
|
+
for (const task of this._backgroundTasks) {
|
|
505
|
+
task.cancel();
|
|
506
|
+
}
|
|
507
|
+
void Promise.allSettled([...this._backgroundTasks].map((t) => t.promise));
|
|
508
|
+
this._backgroundTasks.clear();
|
|
497
509
|
this._disconnectFromAgent();
|
|
498
510
|
this._eventListeners = [];
|
|
499
511
|
}
|
|
@@ -516,6 +528,10 @@ export class AgentSession {
|
|
|
516
528
|
get isStreaming() {
|
|
517
529
|
return this.agent.state.isStreaming;
|
|
518
530
|
}
|
|
531
|
+
/** Signal that aborts on session shutdown */
|
|
532
|
+
get sessionSignal() {
|
|
533
|
+
return this._sessionAbortController.signal;
|
|
534
|
+
}
|
|
519
535
|
/** Current effective system prompt (includes any per-turn extension modifications) */
|
|
520
536
|
get systemPrompt() {
|
|
521
537
|
return this.agent.state.systemPrompt;
|
|
@@ -1774,10 +1790,14 @@ export class AgentSession {
|
|
|
1774
1790
|
throw new Error(`registerChannel("${name}") is only available in RPC mode`);
|
|
1775
1791
|
}),
|
|
1776
1792
|
callLLM: (options) => this.callLLM(options),
|
|
1793
|
+
callLLMStructured: (opts) => this.callLLMStructured(opts),
|
|
1794
|
+
forkAgent: (prompt, options) => this.forkAgent(prompt, options),
|
|
1795
|
+
background: (fn) => this.background(fn),
|
|
1777
1796
|
}, {
|
|
1778
1797
|
getModel: () => this.model,
|
|
1779
1798
|
isIdle: () => !this.isStreaming,
|
|
1780
1799
|
getSignal: () => this.agent.signal,
|
|
1800
|
+
getSessionSignal: () => this._sessionAbortController.signal,
|
|
1781
1801
|
abort: () => this.abort(),
|
|
1782
1802
|
hasPendingMessages: () => this.pendingMessageCount > 0,
|
|
1783
1803
|
shutdown: () => {
|
|
@@ -1912,6 +1932,186 @@ export class AgentSession {
|
|
|
1912
1932
|
}
|
|
1913
1933
|
return resultText;
|
|
1914
1934
|
}
|
|
1935
|
+
async callLLMStructured(options) {
|
|
1936
|
+
const maxRetries = options.maxRetries ?? 0;
|
|
1937
|
+
let lastError;
|
|
1938
|
+
const schemaJson = JSON.stringify(options.schema);
|
|
1939
|
+
const structuredSystemPrompt = (options.systemPrompt ?? "") +
|
|
1940
|
+
`\n\nRespond with valid JSON matching this schema:\n${schemaJson}\n\nRespond with JSON only, no markdown.`;
|
|
1941
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
1942
|
+
const messages = attempt === 0
|
|
1943
|
+
? options.messages
|
|
1944
|
+
: [
|
|
1945
|
+
...options.messages,
|
|
1946
|
+
{ role: "assistant", content: lastError?.raw ?? "" },
|
|
1947
|
+
{
|
|
1948
|
+
role: "user",
|
|
1949
|
+
content: `Your previous response was invalid: ${lastError?.message}. Please respond with valid JSON matching the schema.`,
|
|
1950
|
+
},
|
|
1951
|
+
];
|
|
1952
|
+
const raw = await this.callLLM({
|
|
1953
|
+
...options,
|
|
1954
|
+
systemPrompt: structuredSystemPrompt,
|
|
1955
|
+
messages,
|
|
1956
|
+
});
|
|
1957
|
+
try {
|
|
1958
|
+
const cleaned = stripMarkdownCodeBlock(raw);
|
|
1959
|
+
const parsed = JSON.parse(cleaned);
|
|
1960
|
+
const check = Compile(options.schema);
|
|
1961
|
+
const coerced = Value.Convert(options.schema, parsed);
|
|
1962
|
+
if (!check.Check(coerced)) {
|
|
1963
|
+
const errors = check
|
|
1964
|
+
.Errors(coerced)
|
|
1965
|
+
.map((e) => `${e.instancePath}: ${e.message}`)
|
|
1966
|
+
.join("; ");
|
|
1967
|
+
const err = new Error(`Schema validation failed: ${errors}`);
|
|
1968
|
+
err.raw = raw;
|
|
1969
|
+
err.reason = "schema_validation";
|
|
1970
|
+
lastError = err;
|
|
1971
|
+
if (attempt >= maxRetries)
|
|
1972
|
+
throw err;
|
|
1973
|
+
continue;
|
|
1974
|
+
}
|
|
1975
|
+
return coerced;
|
|
1976
|
+
}
|
|
1977
|
+
catch (e) {
|
|
1978
|
+
if (e instanceof SyntaxError) {
|
|
1979
|
+
const err = new Error(`JSON parse failed: ${e.message}`);
|
|
1980
|
+
err.raw = raw;
|
|
1981
|
+
err.reason = "json_parse";
|
|
1982
|
+
lastError = err;
|
|
1983
|
+
if (attempt >= maxRetries)
|
|
1984
|
+
throw err;
|
|
1985
|
+
continue;
|
|
1986
|
+
}
|
|
1987
|
+
if (e.reason) {
|
|
1988
|
+
lastError = e;
|
|
1989
|
+
if (attempt >= maxRetries)
|
|
1990
|
+
throw lastError;
|
|
1991
|
+
continue;
|
|
1992
|
+
}
|
|
1993
|
+
throw e;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
throw lastError ?? new Error("callLLMStructured failed");
|
|
1997
|
+
}
|
|
1998
|
+
async forkAgent(promptText, options) {
|
|
1999
|
+
const model = this.model;
|
|
2000
|
+
if (!model)
|
|
2001
|
+
throw new Error("No model selected");
|
|
2002
|
+
const auth = await this._modelRegistry.getApiKeyAndHeaders(model);
|
|
2003
|
+
if (!auth?.ok) {
|
|
2004
|
+
throw new Error("error" in auth ? auth.error : `No API key configured for ${model.provider}`);
|
|
2005
|
+
}
|
|
2006
|
+
if (!auth.apiKey) {
|
|
2007
|
+
throw new Error(`No API key configured for ${model.provider}`);
|
|
2008
|
+
}
|
|
2009
|
+
if (options?.signal?.aborted)
|
|
2010
|
+
throw new Error("Aborted");
|
|
2011
|
+
const opts = options ?? {};
|
|
2012
|
+
let toolNames = opts.tools ?? ["read", "grep", "find", "ls"];
|
|
2013
|
+
if (opts.bash === "deny") {
|
|
2014
|
+
toolNames = toolNames.filter((t) => t !== "bash");
|
|
2015
|
+
}
|
|
2016
|
+
const toolInstances = toolNames
|
|
2017
|
+
.map((name) => {
|
|
2018
|
+
try {
|
|
2019
|
+
const registered = this._toolRegistry.get(name);
|
|
2020
|
+
if (registered)
|
|
2021
|
+
return registered;
|
|
2022
|
+
return createTool(name, this._cwd);
|
|
2023
|
+
}
|
|
2024
|
+
catch {
|
|
2025
|
+
return undefined;
|
|
2026
|
+
}
|
|
2027
|
+
})
|
|
2028
|
+
.filter((t) => t !== undefined);
|
|
2029
|
+
const effectiveSystemPrompt = opts.inheritSystemPrompt
|
|
2030
|
+
? (this.agent.state.systemPrompt ?? opts.systemPrompt ?? "")
|
|
2031
|
+
: (opts.systemPrompt ?? "");
|
|
2032
|
+
const messages = opts.shareContext ? [...this.agent.state.messages] : [];
|
|
2033
|
+
const maxTurns = opts.maxTurns ?? 5;
|
|
2034
|
+
let turnCount = 0;
|
|
2035
|
+
const forkedAgent = new Agent({
|
|
2036
|
+
getApiKey: () => auth.apiKey,
|
|
2037
|
+
initialState: {
|
|
2038
|
+
systemPrompt: effectiveSystemPrompt,
|
|
2039
|
+
model,
|
|
2040
|
+
thinkingLevel: "off",
|
|
2041
|
+
tools: toolInstances,
|
|
2042
|
+
messages,
|
|
2043
|
+
},
|
|
2044
|
+
sessionId: opts.shareContext ? this.agent.sessionId : undefined,
|
|
2045
|
+
});
|
|
2046
|
+
let resultText = "";
|
|
2047
|
+
const usage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
|
|
2048
|
+
const abortHandler = opts.signal ? () => forkedAgent.abort() : undefined;
|
|
2049
|
+
if (abortHandler && opts.signal) {
|
|
2050
|
+
opts.signal.addEventListener("abort", abortHandler, { once: true });
|
|
2051
|
+
}
|
|
2052
|
+
const unsub = forkedAgent.subscribe((event) => {
|
|
2053
|
+
if (event.type === "turn_end") {
|
|
2054
|
+
turnCount++;
|
|
2055
|
+
if (turnCount >= maxTurns) {
|
|
2056
|
+
forkedAgent.abort();
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
if (event.type === "message_end") {
|
|
2060
|
+
const msg = event.message;
|
|
2061
|
+
if (msg.role === "assistant") {
|
|
2062
|
+
const asst = msg;
|
|
2063
|
+
const content = asst.content;
|
|
2064
|
+
if (Array.isArray(content)) {
|
|
2065
|
+
resultText = content
|
|
2066
|
+
.filter((c) => c.type === "text")
|
|
2067
|
+
.map((c) => c.text)
|
|
2068
|
+
.join("\n");
|
|
2069
|
+
}
|
|
2070
|
+
if (asst.usage) {
|
|
2071
|
+
usage.input = asst.usage.input ?? 0;
|
|
2072
|
+
usage.output = asst.usage.output ?? 0;
|
|
2073
|
+
usage.cacheRead = asst.usage.cacheRead ?? 0;
|
|
2074
|
+
usage.cacheWrite = asst.usage.cacheWrite ?? 0;
|
|
2075
|
+
if (model.cost) {
|
|
2076
|
+
usage.cost =
|
|
2077
|
+
(usage.input * model.cost.input +
|
|
2078
|
+
usage.output * model.cost.output +
|
|
2079
|
+
usage.cacheRead * model.cost.cacheRead +
|
|
2080
|
+
usage.cacheWrite * model.cost.cacheWrite) /
|
|
2081
|
+
1_000_000;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
});
|
|
2087
|
+
try {
|
|
2088
|
+
await forkedAgent.prompt({
|
|
2089
|
+
role: "user",
|
|
2090
|
+
content: [{ type: "text", text: promptText }],
|
|
2091
|
+
timestamp: Date.now(),
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
finally {
|
|
2095
|
+
unsub();
|
|
2096
|
+
if (abortHandler && opts.signal) {
|
|
2097
|
+
opts.signal.removeEventListener("abort", abortHandler);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
return { text: resultText, usage };
|
|
2101
|
+
}
|
|
2102
|
+
background(fn) {
|
|
2103
|
+
const controller = new AbortController();
|
|
2104
|
+
const promise = fn(controller.signal);
|
|
2105
|
+
const task = {
|
|
2106
|
+
id: randomUUID(),
|
|
2107
|
+
signal: controller.signal,
|
|
2108
|
+
promise: promise,
|
|
2109
|
+
cancel: () => controller.abort(),
|
|
2110
|
+
};
|
|
2111
|
+
this._backgroundTasks.add(task);
|
|
2112
|
+
promise.finally(() => this._backgroundTasks.delete(task));
|
|
2113
|
+
return task;
|
|
2114
|
+
}
|
|
1915
2115
|
_refreshToolRegistry(options) {
|
|
1916
2116
|
const previousRegistryNames = new Set(this._toolRegistry.keys());
|
|
1917
2117
|
const previousActiveToolNames = this.getActiveToolNames();
|
|
@@ -2043,6 +2243,14 @@ export class AgentSession {
|
|
|
2043
2243
|
await this.extendResourcesFromExtensions("reload");
|
|
2044
2244
|
}
|
|
2045
2245
|
}
|
|
2246
|
+
async setCwd(newCwd) {
|
|
2247
|
+
this._cwd = newCwd;
|
|
2248
|
+
this._buildRuntime({
|
|
2249
|
+
activeToolNames: this.getActiveToolNames(),
|
|
2250
|
+
flagValues: this._extensionRunner.getFlagValues(),
|
|
2251
|
+
includeAllExtensionTools: true,
|
|
2252
|
+
});
|
|
2253
|
+
}
|
|
2046
2254
|
// =========================================================================
|
|
2047
2255
|
// Auto-Retry
|
|
2048
2256
|
// =========================================================================
|