@dyyz1993/pi-coding-agent 0.69.18 → 0.69.24

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.
Files changed (129) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/cli/args.d.ts +1 -0
  3. package/dist/cli/args.d.ts.map +1 -1
  4. package/dist/cli/args.js +12 -2
  5. package/dist/cli/args.js.map +1 -1
  6. package/dist/core/agent-session.d.ts +15 -1
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +216 -0
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/extensions/client-channel.d.ts +61 -0
  11. package/dist/core/extensions/client-channel.d.ts.map +1 -0
  12. package/dist/core/extensions/client-channel.js +67 -0
  13. package/dist/core/extensions/client-channel.js.map +1 -0
  14. package/dist/core/extensions/index.d.ts +3 -2
  15. package/dist/core/extensions/index.d.ts.map +1 -1
  16. package/dist/core/extensions/index.js +1 -0
  17. package/dist/core/extensions/index.js.map +1 -1
  18. package/dist/core/extensions/loader.d.ts.map +1 -1
  19. package/dist/core/extensions/loader.js +21 -0
  20. package/dist/core/extensions/loader.js.map +1 -1
  21. package/dist/core/extensions/runner.d.ts +1 -0
  22. package/dist/core/extensions/runner.d.ts.map +1 -1
  23. package/dist/core/extensions/runner.js +31 -0
  24. package/dist/core/extensions/runner.js.map +1 -1
  25. package/dist/core/extensions/types.d.ts +86 -34
  26. package/dist/core/extensions/types.d.ts.map +1 -1
  27. package/dist/core/extensions/types.js.map +1 -1
  28. package/dist/core/include-resolver.d.ts +18 -0
  29. package/dist/core/include-resolver.d.ts.map +1 -0
  30. package/dist/core/include-resolver.js +304 -0
  31. package/dist/core/include-resolver.js.map +1 -0
  32. package/dist/core/resource-loader.d.ts.map +1 -1
  33. package/dist/core/resource-loader.js +17 -4
  34. package/dist/core/resource-loader.js.map +1 -1
  35. package/dist/core/session-manager.d.ts +8 -4
  36. package/dist/core/session-manager.d.ts.map +1 -1
  37. package/dist/core/session-manager.js +29 -6
  38. package/dist/core/session-manager.js.map +1 -1
  39. package/dist/core/storage.d.ts +24 -0
  40. package/dist/core/storage.d.ts.map +1 -0
  41. package/dist/core/storage.js +55 -0
  42. package/dist/core/storage.js.map +1 -0
  43. package/dist/core/tools/path-security.d.ts +15 -0
  44. package/dist/core/tools/path-security.d.ts.map +1 -0
  45. package/dist/core/tools/path-security.js +76 -0
  46. package/dist/core/tools/path-security.js.map +1 -0
  47. package/dist/core/tools/strip-markdown.d.ts +2 -0
  48. package/dist/core/tools/strip-markdown.d.ts.map +1 -0
  49. package/dist/core/tools/strip-markdown.js +8 -0
  50. package/dist/core/tools/strip-markdown.js.map +1 -0
  51. package/dist/index.d.ts +5 -4
  52. package/dist/index.d.ts.map +1 -1
  53. package/dist/index.js +3 -2
  54. package/dist/index.js.map +1 -1
  55. package/dist/main.d.ts.map +1 -1
  56. package/dist/main.js +1 -0
  57. package/dist/main.js.map +1 -1
  58. package/dist/modes/interactive/components/extension-selector.d.ts +4 -1
  59. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  60. package/dist/modes/interactive/components/extension-selector.js +54 -12
  61. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  62. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  63. package/dist/modes/interactive/interactive-mode.js +2 -1
  64. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  65. package/dist/modes/print-mode.d.ts +2 -0
  66. package/dist/modes/print-mode.d.ts.map +1 -1
  67. package/dist/modes/print-mode.js +8 -1
  68. package/dist/modes/print-mode.js.map +1 -1
  69. package/dist/modes/rpc/rpc-client-types.d.ts +2 -0
  70. package/dist/modes/rpc/rpc-client-types.d.ts.map +1 -1
  71. package/dist/modes/rpc/rpc-client-types.js.map +1 -1
  72. package/dist/modes/rpc/rpc-client.d.ts +2 -0
  73. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  74. package/dist/modes/rpc/rpc-client.js +6 -0
  75. package/dist/modes/rpc/rpc-client.js.map +1 -1
  76. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  77. package/dist/modes/rpc/rpc-mode.js +6 -1
  78. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  79. package/dist/modes/rpc/rpc-types.d.ts +10 -0
  80. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  81. package/dist/modes/rpc/rpc-types.js.map +1 -1
  82. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  83. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  84. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  85. package/examples/extensions/custom-provider-qwen-cli/package.json +1 -1
  86. package/examples/extensions/with-deps/package-lock.json +2 -2
  87. package/examples/extensions/with-deps/package.json +1 -1
  88. package/package.json +9 -5
  89. package/dist/rules-engine/cache.d.ts +0 -4
  90. package/dist/rules-engine/cache.d.ts.map +0 -1
  91. package/dist/rules-engine/cache.js +0 -32
  92. package/dist/rules-engine/cache.js.map +0 -1
  93. package/dist/rules-engine/config.d.ts +0 -8
  94. package/dist/rules-engine/config.d.ts.map +0 -1
  95. package/dist/rules-engine/config.js +0 -56
  96. package/dist/rules-engine/config.js.map +0 -1
  97. package/dist/rules-engine/index.d.ts +0 -10
  98. package/dist/rules-engine/index.d.ts.map +0 -1
  99. package/dist/rules-engine/index.js +0 -393
  100. package/dist/rules-engine/index.js.map +0 -1
  101. package/dist/rules-engine/injector.d.ts +0 -5
  102. package/dist/rules-engine/injector.d.ts.map +0 -1
  103. package/dist/rules-engine/injector.js +0 -57
  104. package/dist/rules-engine/injector.js.map +0 -1
  105. package/dist/rules-engine/loader.d.ts +0 -8
  106. package/dist/rules-engine/loader.d.ts.map +0 -1
  107. package/dist/rules-engine/loader.js +0 -190
  108. package/dist/rules-engine/loader.js.map +0 -1
  109. package/dist/rules-engine/matcher.d.ts +0 -3
  110. package/dist/rules-engine/matcher.d.ts.map +0 -1
  111. package/dist/rules-engine/matcher.js +0 -48
  112. package/dist/rules-engine/matcher.js.map +0 -1
  113. package/dist/rules-engine/types.d.ts +0 -150
  114. package/dist/rules-engine/types.d.ts.map +0 -1
  115. package/dist/rules-engine/types.js +0 -2
  116. package/dist/rules-engine/types.js.map +0 -1
  117. package/examples/extensions/auto-session-title.ts +0 -82
  118. package/examples/extensions/file-snapshot.ts +0 -417
  119. package/examples/extensions/subagent/README.md +0 -172
  120. package/examples/extensions/subagent/agents/planner.md +0 -37
  121. package/examples/extensions/subagent/agents/reviewer.md +0 -35
  122. package/examples/extensions/subagent/agents/scout.md +0 -50
  123. package/examples/extensions/subagent/agents/worker.md +0 -24
  124. package/examples/extensions/subagent/agents.ts +0 -126
  125. package/examples/extensions/subagent/index.ts +0 -987
  126. package/examples/extensions/subagent/prompts/implement-and-review.md +0 -10
  127. package/examples/extensions/subagent/prompts/implement.md +0 -10
  128. package/examples/extensions/subagent/prompts/scout-and-plan.md +0 -9
  129. 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.
@@ -91,6 +95,7 @@ export class AgentSession {
91
95
  // Extension system
92
96
  _extensionRunner;
93
97
  _turnIndex = 0;
98
+ _toolCallVariables;
94
99
  _resourceLoader;
95
100
  _customTools;
96
101
  _baseToolDefinitions = new Map();
@@ -106,6 +111,8 @@ export class AgentSession {
106
111
  _extensionErrorListener;
107
112
  _extensionErrorUnsubscriber;
108
113
  _registerChannel;
114
+ _sessionAbortController = new AbortController();
115
+ _backgroundTasks = new Set();
109
116
  // Model registry for API key resolution
110
117
  _modelRegistry;
111
118
  // Tool registry for extension getTools/setTools
@@ -181,6 +188,7 @@ export class AgentSession {
181
188
  toolName: toolCall.name,
182
189
  toolCallId: toolCall.id,
183
190
  input: args,
191
+ variables: this._toolCallVariables,
184
192
  });
185
193
  }
186
194
  catch (err) {
@@ -494,6 +502,12 @@ export class AgentSession {
494
502
  */
495
503
  dispose() {
496
504
  this._extensionRunner.invalidate("This extension instance is stale after session replacement or reload. Use the provided replacement-session context instead.");
505
+ this._sessionAbortController.abort();
506
+ for (const task of this._backgroundTasks) {
507
+ task.cancel();
508
+ }
509
+ void Promise.allSettled([...this._backgroundTasks].map((t) => t.promise));
510
+ this._backgroundTasks.clear();
497
511
  this._disconnectFromAgent();
498
512
  this._eventListeners = [];
499
513
  }
@@ -512,10 +526,20 @@ export class AgentSession {
512
526
  get thinkingLevel() {
513
527
  return this.agent.state.thinkingLevel;
514
528
  }
529
+ set toolCallVariables(vars) {
530
+ this._toolCallVariables = vars;
531
+ }
532
+ get toolCallVariables() {
533
+ return this._toolCallVariables;
534
+ }
515
535
  /** Whether agent is currently streaming a response */
516
536
  get isStreaming() {
517
537
  return this.agent.state.isStreaming;
518
538
  }
539
+ /** Signal that aborts on session shutdown */
540
+ get sessionSignal() {
541
+ return this._sessionAbortController.signal;
542
+ }
519
543
  /** Current effective system prompt (includes any per-turn extension modifications) */
520
544
  get systemPrompt() {
521
545
  return this.agent.state.systemPrompt;
@@ -1774,10 +1798,14 @@ export class AgentSession {
1774
1798
  throw new Error(`registerChannel("${name}") is only available in RPC mode`);
1775
1799
  }),
1776
1800
  callLLM: (options) => this.callLLM(options),
1801
+ callLLMStructured: (opts) => this.callLLMStructured(opts),
1802
+ forkAgent: (prompt, options) => this.forkAgent(prompt, options),
1803
+ background: (fn) => this.background(fn),
1777
1804
  }, {
1778
1805
  getModel: () => this.model,
1779
1806
  isIdle: () => !this.isStreaming,
1780
1807
  getSignal: () => this.agent.signal,
1808
+ getSessionSignal: () => this._sessionAbortController.signal,
1781
1809
  abort: () => this.abort(),
1782
1810
  hasPendingMessages: () => this.pendingMessageCount > 0,
1783
1811
  shutdown: () => {
@@ -1912,6 +1940,186 @@ export class AgentSession {
1912
1940
  }
1913
1941
  return resultText;
1914
1942
  }
1943
+ async callLLMStructured(options) {
1944
+ const maxRetries = options.maxRetries ?? 0;
1945
+ let lastError;
1946
+ const schemaJson = JSON.stringify(options.schema);
1947
+ const structuredSystemPrompt = (options.systemPrompt ?? "") +
1948
+ `\n\nRespond with valid JSON matching this schema:\n${schemaJson}\n\nRespond with JSON only, no markdown.`;
1949
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1950
+ const messages = attempt === 0
1951
+ ? options.messages
1952
+ : [
1953
+ ...options.messages,
1954
+ { role: "assistant", content: lastError?.raw ?? "" },
1955
+ {
1956
+ role: "user",
1957
+ content: `Your previous response was invalid: ${lastError?.message}. Please respond with valid JSON matching the schema.`,
1958
+ },
1959
+ ];
1960
+ const raw = await this.callLLM({
1961
+ ...options,
1962
+ systemPrompt: structuredSystemPrompt,
1963
+ messages,
1964
+ });
1965
+ try {
1966
+ const cleaned = stripMarkdownCodeBlock(raw);
1967
+ const parsed = JSON.parse(cleaned);
1968
+ const check = Compile(options.schema);
1969
+ const coerced = Value.Convert(options.schema, parsed);
1970
+ if (!check.Check(coerced)) {
1971
+ const errors = check
1972
+ .Errors(coerced)
1973
+ .map((e) => `${e.instancePath}: ${e.message}`)
1974
+ .join("; ");
1975
+ const err = new Error(`Schema validation failed: ${errors}`);
1976
+ err.raw = raw;
1977
+ err.reason = "schema_validation";
1978
+ lastError = err;
1979
+ if (attempt >= maxRetries)
1980
+ throw err;
1981
+ continue;
1982
+ }
1983
+ return coerced;
1984
+ }
1985
+ catch (e) {
1986
+ if (e instanceof SyntaxError) {
1987
+ const err = new Error(`JSON parse failed: ${e.message}`);
1988
+ err.raw = raw;
1989
+ err.reason = "json_parse";
1990
+ lastError = err;
1991
+ if (attempt >= maxRetries)
1992
+ throw err;
1993
+ continue;
1994
+ }
1995
+ if (e.reason) {
1996
+ lastError = e;
1997
+ if (attempt >= maxRetries)
1998
+ throw lastError;
1999
+ continue;
2000
+ }
2001
+ throw e;
2002
+ }
2003
+ }
2004
+ throw lastError ?? new Error("callLLMStructured failed");
2005
+ }
2006
+ async forkAgent(promptText, options) {
2007
+ const model = this.model;
2008
+ if (!model)
2009
+ throw new Error("No model selected");
2010
+ const auth = await this._modelRegistry.getApiKeyAndHeaders(model);
2011
+ if (!auth?.ok) {
2012
+ throw new Error("error" in auth ? auth.error : `No API key configured for ${model.provider}`);
2013
+ }
2014
+ if (!auth.apiKey) {
2015
+ throw new Error(`No API key configured for ${model.provider}`);
2016
+ }
2017
+ if (options?.signal?.aborted)
2018
+ throw new Error("Aborted");
2019
+ const opts = options ?? {};
2020
+ let toolNames = opts.tools ?? ["read", "grep", "find", "ls"];
2021
+ if (opts.bash === "deny") {
2022
+ toolNames = toolNames.filter((t) => t !== "bash");
2023
+ }
2024
+ const toolInstances = toolNames
2025
+ .map((name) => {
2026
+ try {
2027
+ const registered = this._toolRegistry.get(name);
2028
+ if (registered)
2029
+ return registered;
2030
+ return createTool(name, this._cwd);
2031
+ }
2032
+ catch {
2033
+ return undefined;
2034
+ }
2035
+ })
2036
+ .filter((t) => t !== undefined);
2037
+ const effectiveSystemPrompt = opts.inheritSystemPrompt
2038
+ ? (this.agent.state.systemPrompt ?? opts.systemPrompt ?? "")
2039
+ : (opts.systemPrompt ?? "");
2040
+ const messages = opts.shareContext ? [...this.agent.state.messages] : [];
2041
+ const maxTurns = opts.maxTurns ?? 5;
2042
+ let turnCount = 0;
2043
+ const forkedAgent = new Agent({
2044
+ getApiKey: () => auth.apiKey,
2045
+ initialState: {
2046
+ systemPrompt: effectiveSystemPrompt,
2047
+ model,
2048
+ thinkingLevel: "off",
2049
+ tools: toolInstances,
2050
+ messages,
2051
+ },
2052
+ sessionId: opts.shareContext ? this.agent.sessionId : undefined,
2053
+ });
2054
+ let resultText = "";
2055
+ const usage = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0 };
2056
+ const abortHandler = opts.signal ? () => forkedAgent.abort() : undefined;
2057
+ if (abortHandler && opts.signal) {
2058
+ opts.signal.addEventListener("abort", abortHandler, { once: true });
2059
+ }
2060
+ const unsub = forkedAgent.subscribe((event) => {
2061
+ if (event.type === "turn_end") {
2062
+ turnCount++;
2063
+ if (turnCount >= maxTurns) {
2064
+ forkedAgent.abort();
2065
+ }
2066
+ }
2067
+ if (event.type === "message_end") {
2068
+ const msg = event.message;
2069
+ if (msg.role === "assistant") {
2070
+ const asst = msg;
2071
+ const content = asst.content;
2072
+ if (Array.isArray(content)) {
2073
+ resultText = content
2074
+ .filter((c) => c.type === "text")
2075
+ .map((c) => c.text)
2076
+ .join("\n");
2077
+ }
2078
+ if (asst.usage) {
2079
+ usage.input = asst.usage.input ?? 0;
2080
+ usage.output = asst.usage.output ?? 0;
2081
+ usage.cacheRead = asst.usage.cacheRead ?? 0;
2082
+ usage.cacheWrite = asst.usage.cacheWrite ?? 0;
2083
+ if (model.cost) {
2084
+ usage.cost =
2085
+ (usage.input * model.cost.input +
2086
+ usage.output * model.cost.output +
2087
+ usage.cacheRead * model.cost.cacheRead +
2088
+ usage.cacheWrite * model.cost.cacheWrite) /
2089
+ 1_000_000;
2090
+ }
2091
+ }
2092
+ }
2093
+ }
2094
+ });
2095
+ try {
2096
+ await forkedAgent.prompt({
2097
+ role: "user",
2098
+ content: [{ type: "text", text: promptText }],
2099
+ timestamp: Date.now(),
2100
+ });
2101
+ }
2102
+ finally {
2103
+ unsub();
2104
+ if (abortHandler && opts.signal) {
2105
+ opts.signal.removeEventListener("abort", abortHandler);
2106
+ }
2107
+ }
2108
+ return { text: resultText, usage };
2109
+ }
2110
+ background(fn) {
2111
+ const controller = new AbortController();
2112
+ const promise = fn(controller.signal);
2113
+ const task = {
2114
+ id: randomUUID(),
2115
+ signal: controller.signal,
2116
+ promise: promise,
2117
+ cancel: () => controller.abort(),
2118
+ };
2119
+ this._backgroundTasks.add(task);
2120
+ promise.finally(() => this._backgroundTasks.delete(task));
2121
+ return task;
2122
+ }
1915
2123
  _refreshToolRegistry(options) {
1916
2124
  const previousRegistryNames = new Set(this._toolRegistry.keys());
1917
2125
  const previousActiveToolNames = this.getActiveToolNames();
@@ -2043,6 +2251,14 @@ export class AgentSession {
2043
2251
  await this.extendResourcesFromExtensions("reload");
2044
2252
  }
2045
2253
  }
2254
+ async setCwd(newCwd) {
2255
+ this._cwd = newCwd;
2256
+ this._buildRuntime({
2257
+ activeToolNames: this.getActiveToolNames(),
2258
+ flagValues: this._extensionRunner.getFlagValues(),
2259
+ includeAllExtensionTools: true,
2260
+ });
2261
+ }
2046
2262
  // =========================================================================
2047
2263
  // Auto-Retry
2048
2264
  // =========================================================================