@pencil-agent/nano-pencil 1.11.9 → 1.11.10

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.
@@ -28,6 +28,7 @@ const BUNDLED_SECURITY_AUDIT_EXTENSION = join(__dirname, "extensions", "defaults
28
28
  const BUNDLED_SOUL_EXTENSION = join(__dirname, "extensions", "defaults", "soul", "index.js");
29
29
  const BUNDLED_INTERVIEW_EXTENSION = join(__dirname, "extensions", "defaults", "interview", "index.js");
30
30
  const BUNDLED_LOOP_EXTENSION = join(__dirname, "extensions", "defaults", "loop", "index.js");
31
+ const BUNDLED_TEAM_EXTENSION = join(__dirname, "extensions", "defaults", "team", "index.js");
31
32
  const BUNDLED_MCP_EXTENSION = join(__dirname, "extensions", "defaults", "mcp", "index.js");
32
33
  const BUNDLED_EXPORT_HTML_EXTENSION = join(__dirname, "extensions", "optional", "export-html", "index.js");
33
34
  /** 从当前模块位置向上查找包根(含 package.json 且 name 为 nano-pencil 相关) */
@@ -148,6 +149,16 @@ export function getBuiltinExtensionPaths() {
148
149
  paths.push(loopTs);
149
150
  }
150
151
  // === MCP 扩展(MCP 工具协议适配) ===
152
+ // Built-in team extension
153
+ if (existsSync(BUNDLED_TEAM_EXTENSION)) {
154
+ paths.push(BUNDLED_TEAM_EXTENSION);
155
+ }
156
+ else {
157
+ const teamTs = join(__dirname, "extensions", "defaults", "team", "index.ts");
158
+ if (existsSync(teamTs))
159
+ paths.push(teamTs);
160
+ }
161
+ // Built-in MCP extension
151
162
  if (existsSync(BUNDLED_MCP_EXTENSION)) {
152
163
  paths.push(BUNDLED_MCP_EXTENSION);
153
164
  }
@@ -61,6 +61,15 @@ function truncateForPrompt(str, maxChars) {
61
61
  return str;
62
62
  return str.slice(0, maxChars);
63
63
  }
64
+ const LOOP_PROMPT_PREFIX = "[LOOP:";
65
+ function isLoopManagedPrompt(prompt) {
66
+ const trimmed = prompt.trim();
67
+ if (!trimmed)
68
+ return false;
69
+ return (trimmed.startsWith(LOOP_PROMPT_PREFIX) ||
70
+ trimmed.includes("Autonomous loop goal:") ||
71
+ trimmed.includes("You are inside a managed loop."));
72
+ }
64
73
  /**
65
74
  * Check if interview should be triggered based on prompt content and context.
66
75
  * Only triggers for:
@@ -121,6 +130,10 @@ function shouldRunInterview(prompt) {
121
130
  if (process.env.PI_JUST_SWITCHED_PERSONA === "true") {
122
131
  return false;
123
132
  }
133
+ // Loop-generated follow-up turns should stay autonomous and never re-open interview.
134
+ if (isLoopManagedPrompt(prompt)) {
135
+ return false;
136
+ }
124
137
  // Avoid triggering interview for greetings/small-talk/memory questions.
125
138
  if (isNonTaskPrompt(prompt))
126
139
  return false;
@@ -335,6 +348,18 @@ export default async function interviewExtension(pi) {
335
348
  // Start from provided answers (if any) then allow extra clarifications.
336
349
  const referenceSystemPrompt = ctx.getSystemPrompt();
337
350
  let answers = { ...answersFromModel };
351
+ if (isLoopManagedPrompt(query)) {
352
+ return {
353
+ content: [{ type: "text", text: query }],
354
+ details: {
355
+ original_intent: query,
356
+ refined_intent: query,
357
+ completion_score: 1,
358
+ answers,
359
+ missing_slots: [],
360
+ },
361
+ };
362
+ }
338
363
  // UI mode guard: prevent the model from triggering interactive interview for non-task prompts.
339
364
  if (ctx.hasUI && !isTaskLikePrompt(query)) {
340
365
  return {
@@ -0,0 +1,3 @@
1
+ import type { ExtensionAPI } from "../../../core/extensions/types.js";
2
+ export default function teamExtension(pi: ExtensionAPI): Promise<void>;
3
+ //# sourceMappingURL=index.d.ts.map